Fix error value on scoring page. PP-118

Fix error value on scoring page.
PP-118

--- client/src/scripts/scoring-view.coffee
+++ client/src/scripts/scoring-view.coffee
@@ -844,11 +844,11 @@
           (hyperlink 'Show more', 'toggle-advanced-parameters')
         ]
       ]
-      errorRow = [ th 'Error' ]
       durationRow = [ th 'Time' ]
       aucRow = [ th 'AUC' ]
       thresholdCriterionRow = [ th 'Threshold Criterion' ]
       thresholdRow = [ thIndent 'Threshold' ]
+      errorRow = [ thIndent 'Error' ]
       f1Row = [ thIndent 'F1' ]
       accuracyRow = [ thIndent 'Accuracy' ]
       precisionRow = [ thIndent 'Precision' ]
@@ -884,11 +884,13 @@
         nameRow.push td model.key
         rocCurveRow.push tdId 'Loading...', $id:"roc-#{scoreIndex}"
         inputParametersRow.push td createParameterTable parameters: inputParamsByScoreIndex[scoreIndex]
-        errorRow.push td (format4f metrics.error_measure) + errorBadge #TODO change to bootstrap badge
         durationRow.push td "#{metrics.duration_in_ms} ms"
         aucRow.push td format4f auc.AUC
+        #TODO fix error badge
+        #errorRow.push td (format4f metrics.error_measure) + errorBadge #TODO change to bootstrap badge
         thresholdCriterionRow.push td head auc.threshold_criteria
-        thresholdRow.push td head auc.threshold_for_criteria
+        thresholdRow.push td format4f head auc.threshold_for_criteria
+        errorRow.push td format4f head auc.error_for_criteria
         f1Row.push td format4f head auc.F1_for_criteria
         accuracyRow.push td format4f head auc.accuracy_for_criteria
         precisionRow.push td format4f head auc.precision_for_criteria
@@ -925,11 +927,11 @@
         tr nameRow
         tr rocCurveRow
         tr inputParametersRow
-        tr errorRow
         tr durationRow
         tr aucRow
         tr thresholdCriterionRow
         tr thresholdRow
+        tr errorRow
         tr f1Row
         tr accuracyRow
         tr precisionRow


Pressing alt no longer shows the menu on windows and linux

--- packages/client-app/src/browser/application-menu.coffee
+++ packages/client-app/src/browser/application-menu.coffee
@@ -34,7 +34,12 @@
     @extendTemplateWithWindowMenu(fullTemplate)

     @menu = Menu.buildFromTemplate(fullTemplate)
-    Menu.setApplicationMenu(@menu)
+    Menu.setApplicationMenu(null)
+
+    #
+    if process.platform is 'darwin'
+      Menu.setApplicationMenu(@menu)
+

     @updateFullscreenMenuItem(@lastFocusedWindow?.isFullScreen())
     @updateDevModeItem()


fix selectMyPlan success context

fix selectMyPlan success context

--- coffee/subscriptions.controller.coffee
+++ coffee/subscriptions.controller.coffee
@@ -107,7 +107,7 @@
     _onSuccessChangePaymentsData: (data) ->
         @tgLoader.start()

-        @subscriptionsService.selectMyPlan(data).then(@._onSuccessChangedData)
+        @subscriptionsService.selectMyPlan(data).then(@._onSuccessChangedData.bind(this))

     _onSuccessChangedData: () ->
         message = @translate.instant("SUBSCRIPTIONS.PAYMENT_HISTORY.CHANGE_DATA_SUCCESS")


frontend: performFind was not focusing the next a-element

To reproduce, pre-this-patch:

1 Enter find mode ('/')
2 Search for something that matches multiple a-hrefs on the page
3 'Enter' to indicate that you've found your search term
4 findNext ('n')
  4a Now, the next element get's a highlight but is not focused
5 activate/goto ('enter')
  5a The first found match (3) is triggered

An easy way to reproduce: go to a gitweb page, search for "summary", try
to go to any but the first link's href.

Signed-off-by: Carl Helmertz <d78a787955449ad50f586e5155db5f9260d297a8@gmail.com>

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -698,7 +698,8 @@

   # if we have found an input element via 'n', pressing <esc> immediately afterwards sends us into insert
   # mode
-  elementCanTakeInput = DomUtils.isSelectable(document.activeElement) &&
+  elementCanTakeInput = document.activeElement &&
+    DomUtils.isSelectable(document.activeElement) &&
     isDOMDescendant(findModeAnchorNode, document.activeElement)
   if (elementCanTakeInput)
     handlerStack.push({


Fix options link in help dialog

Fix options link in help dialog

This makes the options link in the help dialog cancel the default event
action, so the link (`href="#"`) isn't followed. The former behaviour
was most obvious when using the `LinkHints.activateModeToOpenInNewTab`
command, amoung others.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -869,8 +869,10 @@

   VimiumHelpDialog.init()

-  container.getElementsByClassName("optionsPage")[0].addEventListener("click",
-    -> chrome.runtime.sendMessage({ handler: "openOptionsPageInNewTab" })
+  container.getElementsByClassName("optionsPage")[0].addEventListener("click", (clickEvent) ->
+      chrome.runtime.sendMessage({handler: "openOptionsPageInNewTab"})
+      if clickEvent
+        clickEvent.preventDefault()
     false)


hubot: fix non-match argument passing to fleet controller

--- hubot/fleet.coffee
+++ hubot/fleet.coffee
@@ -63,7 +63,7 @@
       args.push('matchargs=' + encodeURIComponent(arg)) for arg in msg.match[5].split(" ")

     if msg.match[7]
-      args.push('matchargs=' + encodeURIComponent(arg)) for arg in msg.match[7].split(" ")
+      args.push('args=' + encodeURIComponent(arg)) for arg in msg.match[7].split(" ")

     fleet = new Fleet(scenario, msg)
     url = fleet_url + "/scenarios/" + scenario + "/executions"


env now use "lookup from parent" instead of "populate child".

--- src/4.testing.coffee
+++ src/4.testing.coffee
@@ -4,7 +4,7 @@

 class $mate.testing.Test
     constructor: (@description = "") ->
-        @env = {}
+        @_env = {}
         @_children = []
         @_fun = null
         @_interpretedFunction = null
@@ -13,8 +13,16 @@
         @unitResults = []
         @result = null
     define: (fun) ->
-        fun(@env)
-        @
+        fun(@_env)
+        @
+    getEnv: ->
+        r = $mate.testing.objectClone(@_env)
+        @getAncestors().forEach((ancestor) ->
+            Object.keys(ancestor._env).forEach((key) ->
+                if key not in Object.keys(r) then r[key] = ancestor._env[key]
+            )
+        )
+        r
     set: (fun) ->
         @_fun = fun
         @
@@ -77,8 +85,8 @@
                 args.push(description)
                 "#{testArgName}.#{parsed.type}(#{args.join(', ')})"
             )
-            $mate.testing.parseFunction(funStr, Object.keys(@env)).forEach((m, index) =>
-                insertedString = testArgName + ".env."
+            $mate.testing.parseFunction(funStr, Object.keys(@getEnv())).forEach((m, index) =>
+                insertedString = testArgName + ".getEnv()."
                 pos = m + insertedString.length * index
                 funStr = funStr.substr(0, pos) + insertedString + funStr.substr(pos)
             )
@@ -142,9 +150,6 @@
                         @finish(type: false)
             , 0)
         @getChildren().forEach((m) =>
-            Object.keys(@env).forEach((key) =>
-                if key not in Object.keys(m.env) then m.env[key] = @env[key]
-            )
             m.run(false)
         )
         if showsMessage
@@ -349,6 +354,11 @@
             a == b
     else
         a == b
+$mate.testing.objectClone = (x) ->
+    y = {}
+    for key in Object.keys(x)
+        y[key] = x[key]
+    y
 $mate.testing.valueToMessage = (value) ->
     internal = (value, maxLevel) ->
         if value == undefined


Login: Handle query to show activity related warning in login page.

--- client/landing/Login/AppView.coffee
+++ client/landing/Login/AppView.coffee
@@ -227,6 +227,19 @@

     @setTemplate @pistachio()
     @template.update()
+
+    query = KD.utils.parseQuery document.location.search.replace "?", ""
+
+    if query.warning
+      suffix  = if query.type is "comment" then "post a comment" else "like an activity"
+      message = "You need to be logged in to #{suffix}"
+
+      KD.getSingleton("mainView").createGlobalNotification
+        title      : message
+        type       : "yellow"
+        content    : ""
+        closeTimer : 4000
+        container  : this

   pistachio:->
       # {{> @loginOptions}}


Removed CryptoJS example from app.coffee

--- client/mobile/app/coffee/app.coffee
+++ client/mobile/app/coffee/app.coffee
@@ -27,27 +27,14 @@

 # Modules
 # HomeModule = require './modules/home/router'
-DeviceModule = require './modules/device/router'
+DeviceModule    = require './modules/device/router'
 InterfaceModule = require './modules/interface/router'
+PasswordModule  = require './modules/password/router'

 # # # # #

 $(document).on 'ready', =>
   console.log 'Document Ready'
-
-  # # # # #
-  # CryptoJS - basic example
-
-  # Encrypt
-  ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123')
-
-  # Decrypt
-  bytes  = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123')
-  plaintext = bytes.toString(CryptoJS.enc.Utf8)
-  console.log plaintext
-
-  #
-  # # # # #

   # Backbone.history.start()
   # Invoked inside CordovaApp


Typo in id

Typo in id

--- src/RedisPort.coffee
+++ src/RedisPort.coffee
@@ -388,7 +388,7 @@
 			freeFn: freeFn

 		if role.length - 1 is role.indexOf "*"
-			@getServices role, (error, services) ->
+			@getServices role, (error, services) =>
 				return log.error "#{@id}: Error get services: #{error.message}" if error
 				regFn service for service in services


Remove unused subtract method in point (it did not behave correctly)

--- src/app/point.coffee
+++ src/app/point.coffee
@@ -23,16 +23,6 @@
       column = @column + other.column
     else
       column = other.column
-
-    new Point(row, column)
-
-  subtract: (other) ->
-    other = Point.fromObject(other)
-    row = @row - other.row
-    if @row == other.row
-      column = @column - other.column
-    else
-      column = @column

     new Point(row, column)


Correctly check transaction keys.

Correctly check transaction keys.

--- js/core/test/LocalStore.coffee
+++ js/core/test/LocalStore.coffee
@@ -12,7 +12,7 @@

 			store = new JEFRi.LocalStore
 			runtime.save_new(store).then((transaction)->
-				ok(_.intersect(_.keys(transaction), ["entities", "attributes"]).length == 0, "Transaction has unknown keys.");
+				ok(_.difference(_.keys(transaction), ["entities", "attributes"]).length == 0, "Transaction has unknown keys.");
 				ok(transaction.entities.length == 2, "Transaction should only have 2 entities.");
 				start();
 			)


Fixed classList

Fixed classList

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -349,7 +349,6 @@
       offset = 0
     if thumb + offset < env.w
       offset = env.w - thumb
-    console.log offset

     translate @thumbnails, offset
     @
@@ -543,7 +542,7 @@

 hasClassList = (element, selector) ->
   target = getTarget element, selector
-  if target? and target.hasOwnProperty 'classList'
+  if target? and target.classList?
     return target.classList
   else
     return false


Moved tutorial circle to the field center

--- app/lib/tutorial_steps.coffee
+++ app/lib/tutorial_steps.coffee
@@ -56,7 +56,7 @@
     className: 'arrow-left'
     onEnter: ->
       bounding = document.createElementNS('http://www.w3.org/2000/svg', "circle")
-      bounding.setAttribute("transform", "translate(#{258}, #{324})")
+      bounding.setAttribute("transform", "translate(#{220}, #{220})")
       bounding.setAttribute("class", "outline")
       bounding.setAttribute("stroke", 'white')
       bounding.setAttribute("stroke-width", 2)
@@ -123,4 +123,4 @@
     block: '.annotation, .current .controls a:not(:last)'
     next:
       'click .controls a.last': true
-  +


SA account user et email verification

SA account user et email verification

--- app/scripts/directives.coffee
+++ app/scripts/directives.coffee
@@ -87,7 +87,7 @@
           clearTimeout(toId)
         ctrl.toId = setTimeout(() ->
           Users.getList({search: value}).then((data) ->
-              ctrl.$setValidity('uniqueUserField', !data.length);
+              ctrl.$setValidity('uniqueUserField', data.length==0);
           )
         , 200)
       )


add XYZ white to lab colorspace

add XYZ white to lab colorspace

--- src/color/lab.coffee
+++ src/color/lab.coffee
@@ -1,4 +1,4 @@
-XYZ = (require './xyz').XYZ
+xyz = require './xyz'

 N = 4 / 29 # = 16 / 116
 e3 = 216 / 24389 # = e^3
@@ -23,20 +23,21 @@

 class LabCS
   constructor: (white) ->
-    @white = white.XYZ()
+    @white = white
+    @whiteXYZ = (xyz.xyY @white.x, @white.y, 1).XYZ()

   fromXYZ: (XYZ, T = new Lab) ->
-    l = f(XYZ.Y / @white.Y)
+    l = f(XYZ.Y / @whiteXYZ.Y)
     T.L = 116 * l - 16
-    T.a = 500 * (f(XYZ.X / @white.X) - l)
-    T.b = 200 * (l - f(XYZ.Z / @white.Z))
+    T.a = 500 * (f(XYZ.X / @whiteXYZ.X) - l)
+    T.b = 200 * (l - f(XYZ.Z / @whiteXYZ.Z))
     T

-  toXYZ: (Lab, T = XYZ()) ->
+  toXYZ: (Lab, T = xyz.XYZ()) ->
     fy = (Lab.L + 16) / 116
-    T.X = fInv(fy + Lab.a / 500) * @white.X
-    T.Y = fInv(fy) * @white.Y
-    T.Z = fInv(fy - Lab.b / 200) * @white.Z
+    T.X = fInv(fy + Lab.a / 500) * @whiteXYZ.X
+    T.Y = fInv(fy) * @whiteXYZ.Y
+    T.Z = fInv(fy - Lab.b / 200) * @whiteXYZ.Z
     T

 # public api


Partial calls table header now shows Arguments instead of 1st Arg if there are no calls with arguments yet.

--- coffee/PartialCallsComponent.coffee
+++ coffee/PartialCallsComponent.coffee
@@ -16,7 +16,7 @@
     calls = @props.partial_calls
     highlighted_call_num = @props.num_partial_call_executing

-    max_num_cols = 3
+    max_num_cols = 2
     for call in calls
       if call.length > max_num_cols
         max_num_cols = call.length
@@ -32,11 +32,13 @@
             _.times (max_num_cols - 2), (arg_num) ->
               th { key: "arg#{arg_num}" },
                 switch arg_num
-                  when 0 then '1st Arg'
-                  when 1 then '2nd Arg'
-                  when 2 then '3rd Arg'
-                  else        "#{arg_num + 1}th Arg"
-            th { key: 'extra-space', className: 'extra-space' }
+                  when 0 then '1st Arg.'
+                  when 1 then '2nd Arg.'
+                  when 2 then '3rd Arg.'
+                  else        "#{arg_num + 1}th Arg."
+            th { key: 'extra-space', className: 'extra-space' },
+              if max_num_cols <= 2
+                'Arguments'

         tbody {},
           if calls.length == 0


Initialilzed clock when component receive prop too

If you want restart clock but it is yet mounted it did't work.

--- coffee/react-countdown-clock.coffee
+++ coffee/react-countdown-clock.coffee
@@ -23,13 +23,15 @@
     seconds: @props.seconds

   componentWillReceiveProps: (props) ->
+    @_setScale()
+    @_setupCanvas()
+    @_drawTimer()
+    @_startTimer()
     @setState seconds: props.seconds

-  componentWillMount: ->
+  componentDidMount: ->
     @_setScale()
-
-  componentDidMount: ->
-    @_setupCanvas() if !_canvas
+    @_setupCanvas()
     @_drawTimer()
     @_startTimer()


Fixes a bug that was causing any collection 'sorting' to start at the wrong index within a view_collection

--- coffee/views/collection_view.coffee
+++ coffee/views/collection_view.coffee
@@ -87,9 +87,9 @@

     # When an item is added, create a new view and insert it
     itemAdded: (item, collection, options = {}) =>
-      #console.debug 'CollectionView#itemAdded', this, item.cid, item
-      @renderAndInsertItem item, options.at
-
+      #console.debug 'CollectionView#itemAdded', @, item.cid, item
+      @renderAndInsertItem item, options.index
+
     # When an item is removed, remove the corresponding view from DOM and caches
     itemRemoved: (item) =>
       #console.debug 'CollectionView#itemRemoved', this, item.cid, item


Added Artisan access to LevelComponents.

--- server/levels/components/level_component_handler.coffee
+++ server/levels/components/level_component_handler.coffee
@@ -22,6 +22,9 @@
     props = super(req, document)
     props.push('official') if req.user?.isAdmin()
     props
+
+  hasAccessToDocument: (req, document, method) ->
+    if req.user?.isArtisan() then true else super req, document, method

   get: (req, res) ->
     if req.query.view is 'prop-doc-lookup'


social: add a missing error handler

social: add a missing error handler

--- workers/social/lib/social/models/socialapi/channel.coffee
+++ workers/social/lib/social/models/socialapi/channel.coffee
@@ -222,6 +222,8 @@
     options.channelId = options.id
     # just to create social channels
     ensureGroupChannel client, (err, socialApiChannelId)->
+      return callback err  if err
+
       doRequest 'fetchChannelActivities', client, options, callback

   @fetchActivityCount = (options, callback) ->


Make onerror handler less horific. Still waiting for fixes from airbrake

--- js/app.coffee
+++ js/app.coffee
@@ -291,7 +291,7 @@

     @bind 'error', (e, data) ->
       if data? and data.error? and window.Airbrake?
-        window.Airbrake.captureException data.error
+        window.notifyError data

 $(document).ready () ->


make sammy skip api routes

make sammy skip api routes

--- js/app.coffee
+++ js/app.coffee
@@ -377,6 +377,8 @@
     @get "^/technologies.*", (cx) => VM.technologies.display(cx)
     @get "^/pricing.*", (cx) => VM.pricing.display(cx)

+    @get '^/api/.*', (cx) => true
+
     @get '^(.*)', (cx) => VM.error.display(cx)

     # valid posts, allow to propegate


added control blocks to snippets

added control blocks to snippets

--- snippets/language-sqf.cson
+++ snippets/language-sqf.cson
@@ -21,8 +21,64 @@
     """
     'description': 'Function Header per ACE3 guidelines.'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#3-1-function-definitions'
+  # control blocks
+  'For Loop (ARRAY)':
+    'prefix': 'for_array'
+    'body': """
+    for [{${1:[variable]} = 0},{${1:[variable]} < ${2:[condition]}},{ ${1:[variable]} = ${1:[variable]} + ${3:[step]}}] do {
+        ${4:[code]}
+    };
+    """
+    'description': 'For loop (ARRAY)'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/for'
+  'For loop (VAR)':
+    'prefix': 'for_var'
+    'body': """
+    for "${1:[variable]}" from ${2:[from]} to ${3:[to]} do {
+        ${4:[code]}
+    };
+    """
+    'description': 'For loop (VAR)'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/for'
+  'ForEach Loop':
+    'prefix': 'forEach'
+    'body': """
+    {
+        ${2:[code]}
+    } forEach ${1:[variable]};
+    """
+    'description': 'ForEach loop'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/foreach'
+  'If then':
+    'prefix': 'if_then'
+    'body': """
+    if (${1:[variable]}) then {
+        ${2:[code]}
+    };
+    """
+    'description': 'If then'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/if'
+  'If then else':
+    'prefix': 'if_then_else'
+    'body': """
+    if (${1:[variable]}) then {
+        ${2:[code]}
+    } else {

-
+    };
+    """
+    'description': 'If then else'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/if'
+  'ExitWith statement':
+    'prefix': 'exitWith'
+    'body': """
+    if (${1:[variable]}) exitwith {
+        ${2:[code]}
+    };
+    """
+    'description': 'If exitwith'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/exitwith'
+# Config snippets
 '.source.cpp, .source.hpp':
   'ACE3 Settings Entry':
     'prefix': 'ace_settings_entry'


Added- react props with flow.

Added- react props with flow.

--- snippets/react_native.cson
+++ snippets/react_native.cson
@@ -4,7 +4,7 @@
     prefix: 'rnclass-component'
     leftLabelHTML: 'Ⓢ'
     rightLabelHTML: 'React Native class Component'
-    body: "// @flow\nimport * as React from 'react';\nimport { View, Text, StyleSheet, } from 'react-native';\n\nexport default class ${1:ComponentName} extends React.Component<{}> {\n\trender() {\n\t\treturn (\n\t\t\t<View style={styles.container\\}>\n\t\t\t\t<Text>I'm the ${1:ComponentName} component</Text>\n\t\t\t</View>\n\t\t);$5\n\t}\n}\n\nconst styles = StyleSheet.create({\n\tcontainer: {\n\t\tflex: 1,\n\t},\n});\n"
+    body: "// @flow\nimport * as React from 'react';\nimport { View, Text, StyleSheet, } from 'react-native';\n\ntype Props = {\n  text: string\n};\n\nexport default class ${1:ComponentName} extends React.Component<Props> {\n\trender() {\n\t\treturn (\n\t\t\t<View style={styles.container\\}>\n\t\t\t\t<Text>I'm the ${1:ComponentName} component</Text>\n\t\t\t</View>\n\t\t);$5\n\t}\n}\n\nconst styles = StyleSheet.create({\n\tcontainer: {\n\t\tflex: 1,\n\t},\n});\n"
   'React Native function component':
     prefix: 'rnfunction-component'
     leftLabelHTML: 'Ⓢ'


Polish the things

Polish the things

* Add more comments
* Simplify and cleanup mapped data
* Template DOM change throttling (coalescing)
* Move bindinghandler to remap nodes on drag-drop fail

--- source/coffee/index.coffee
+++ source/coffee/index.coffee
@@ -29,7 +29,7 @@
     @getMappedData = (url, pin, map={}, wrap=true) =>
       @getData url, (data) => @mapData(data, pin, map, wrap)

-    # Parse a flat node list, injecting children arrays for traversal
+    # Parse node array into a flat, keyed boject, injecting children for traversal
     @parseNodes = (data, pin, keyed={}) ->
       root = {}

@@ -66,24 +66,34 @@
         else # Invalid root node!
           delete keyed[id] # Pew Pew!

+      # And run a chillin' parseage
       for id of keyed
         parseChildren keyed[id]

       pin keyed if pin? # Update pin with keyed
-      children: root # Return in format appropriate for mapping
-
+      root # Return root for mapping
+
+    # Process nodes and map to pin
     @updateNodes = (data, pin, keys) =>
       @mapData @parseNodes(data, pin, keys), pin

+    # Get and process nodes from url
     @getNodes = (url, pin, keys) =>
       @getData url, (data) =>
         @updateNodes data, pin, keys

+    # Temp storage for node mapping
     @wsTemp = ko.observableArray()
-    @wsItems = ko.computed(=>
-      @wsTemp()?[0]?.children ? []).extend throttle: 100 # Coalesce node changes
-
+    # Computed wrapper for coalescing changes
+    @wsItems = ko.computed =>
+      @wsTemp()
+    # Enable coalesced node changes (x msec settling period)
+    @wsItems.extend throttle: config?.coalesce ? 500
+
+    # Execution plans
     @wsPlans = ko.observableArray()
+
+    # Flat node list, keyed by id
     @wsKeys = {}

     @poll = (url, cb, timeout=@config?.timeout?.long ? 30000) =>
@@ -211,6 +221,19 @@
           $("#indexInputModal").modal "hide"
           console.log "Error (#{jqXHR.status}): errorThrown"

+    ko.bindingHandlers.sortable.afterMove = (options) =>
+      parent = options.sourceParentNode.attributes["data-id"].value
+      ntrapy.post "/roush/facts/",
+        JSON.stringify
+          key: "parent_id"
+          value: parent
+          node_id: options.item.id()
+      , (data) ->
+        null # TODO: Do something with success?
+      , (jqXHR) =>
+        console.log "Error: ", jqXHR
+        @updateNodes null, @wsTemp, @wsKeys # Remap from keys on fails
+
     @ # Return ourself

   popoverOptions =
@@ -252,17 +275,6 @@
       null
       # TODO: Do something on sort stop?

-  ko.bindingHandlers.sortable.afterMove = (options) ->
-    parent = options.sourceParentNode.attributes["data-id"].value
-    ntrapy.post "/roush/facts/",
-      JSON.stringify
-        key: "parent_id"
-        value: parent
-        node_id: options.item.id()
-    , (data) ->
-      null # TODO: Do something with success?
-    , (jqXHR) ->
-      console.log "Error: ", jqXHR

   ntrapy.indexModel = new IndexModel()
   ko.applyBindings ntrapy.indexModel


Updates navbar link names

Updates navbar link names

--- app/assets/javascripts/backbone/apps/header/list/list_model.js.coffee
+++ app/assets/javascripts/backbone/apps/header/list/list_model.js.coffee
@@ -10,8 +10,8 @@
       new List.Links [
         { name: "Movies" }
         { name: "Watched" }
-        { name: "Queue" }
-        { name: "Trash" }
+        { name: "Queued" }
+        { name: "Trashed" }
         { name: "Shows" }
       ]


conditional drop shadow (only when mark selected)

--- app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
@@ -150,7 +150,7 @@
                   width=\"100%\"
                   height=\"#{@props.mark.yLower-@props.mark.yUpper}\"
                   className=\"#{ if isPriorMark then 'previous-mark'}\"
-                  filter=\"url(#dropShadow)\"
+                  filter=\"#{if @props.selected then 'url(#dropShadow)' else 'none'}\"
                 />
               "
             }


Avoid pane-item deprecation warning in spec

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -581,7 +581,7 @@
           sampleJs.click()

         runs ->
-          atom.workspace.getActivePane().activateItem($$ -> @div('hello'))
+          atom.workspace.getActivePane().activateItem(document.createElement("div"))
           expect(treeView.find('.selected')).not.toExist()

   describe "when a different editor becomes active", ->


Use path.join() instead of fsUtils.join()

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -596,11 +596,11 @@
     beforeEach ->
       atom.deactivatePackage('tree-view')

-      rootDirPath = fsUtils.join(fsUtils.absolute("/tmp"), "atom-tests")
+      rootDirPath = path.join(fsUtils.absolute("/tmp"), "atom-tests")
       fsUtils.remove(rootDirPath) if fsUtils.exists(rootDirPath)

-      dirPath = fsUtils.join(rootDirPath, "test-dir")
-      filePath = fsUtils.join(dirPath, "test-file.txt")
+      dirPath = path.join(rootDirPath, "test-dir")
+      filePath = path.join(dirPath, "test-file.txt")
       fsUtils.makeDirectory(rootDirPath)
       fsUtils.makeDirectory(dirPath)
       fsUtils.write(filePath, "doesn't matter")
@@ -646,7 +646,7 @@
         describe "when the path without a trailing '/' is changed and confirmed", ->
           describe "when no file exists at that location", ->
             it "add a file, closes the dialog and selects the file in the tree-view", ->
-              newPath = fsUtils.join(dirPath, "new-test-file.txt")
+              newPath = path.join(dirPath, "new-test-file.txt")
               addDialog.miniEditor.insertText(path.basename(newPath))
               addDialog.trigger 'core:confirm'
               expect(fsUtils.exists(newPath)).toBeTruthy()
@@ -662,7 +662,7 @@

           describe "when a file already exists at that location", ->
             it "shows an error message and does not close the dialog", ->
-              newPath = fsUtils.join(dirPath, "new-test-file.txt")
+              newPath = path.join(dirPath, "new-test-file.txt")
               fsUtils.write(newPath, '')
               addDialog.miniEditor.insertText(path.basename(newPath))
               addDialog.trigger 'core:confirm'
@@ -676,7 +676,7 @@
           describe "when no file or directory exists at the given path", ->
             it "adds a directory and closes the dialog", ->
               treeView.attachToDom()
-              newPath = fsUtils.join(dirPath, "new/dir")
+              newPath = path.join(dirPath, "new/dir")
               addDialog.miniEditor.insertText("new/dir/")
               addDialog.trigger 'core:confirm'
               expect(fsUtils.exists(newPath)).toBeTruthy()
@@ -689,7 +689,7 @@

             it "selects the created directory", ->
               treeView.attachToDom()
-              newPath = fsUtils.join(dirPath, "new2/")
+              newPath = path.join(dirPath, "new2/")
               addDialog.miniEditor.insertText("new2/")
               addDialog.trigger 'core:confirm'
               expect(fsUtils.exists(newPath)).toBeTruthy()
@@ -702,7 +702,7 @@

           describe "when a file or directory already exists at the given path", ->
             it "shows an error message and does not close the dialog", ->
-              newPath = fsUtils.join(dirPath, "new-dir")
+              newPath = path.join(dirPath, "new-dir")
               fsUtils.makeDirectory(newPath)
               addDialog.miniEditor.insertText("new-dir/")
               addDialog.trigger 'core:confirm'
@@ -784,7 +784,7 @@
         describe "when the path is changed and confirmed", ->
           describe "when all the directories along the new path exist", ->
             it "moves the file, updates the tree view, and closes the dialog", ->
-              newPath = fsUtils.join(rootDirPath, 'renamed-test-file.txt')
+              newPath = path.join(rootDirPath, 'renamed-test-file.txt')
               moveDialog.miniEditor.setText(newPath)

               moveDialog.trigger 'core:confirm'
@@ -803,7 +803,7 @@

           describe "when the directories along the new path don't exist", ->
             it "creates the target directory before moving the file", ->
-              newPath = fsUtils.join(rootDirPath, 'new/directory', 'renamed-test-file.txt')
+              newPath = path.join(rootDirPath, 'new/directory', 'renamed-test-file.txt')
               moveDialog.miniEditor.setText(newPath)

               moveDialog.trigger 'core:confirm'
@@ -818,8 +818,8 @@
           describe "when a file or directory already exists at the target path", ->
             it "shows an error message and does not close the dialog", ->
               runs ->
-                fsUtils.write(fsUtils.join(rootDirPath, 'target.txt'), '')
-                newPath = fsUtils.join(rootDirPath, 'target.txt')
+                fsUtils.write(path.join(rootDirPath, 'target.txt'), '')
+                newPath = path.join(rootDirPath, 'target.txt')
                 moveDialog.miniEditor.setText(newPath)

                 moveDialog.trigger 'core:confirm'
@@ -847,7 +847,7 @@
         [dotFilePath, dotFileView, moveDialog] = []

         beforeEach ->
-          dotFilePath = fsUtils.join(dirPath, ".dotfile")
+          dotFilePath = path.join(dirPath, ".dotfile")
           fsUtils.write(dotFilePath, "dot")
           dirView.collapse()
           dirView.expand()
@@ -878,7 +878,7 @@
     temporaryFilePath = null

     beforeEach ->
-      temporaryFilePath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), 'temporary')
+      temporaryFilePath = path.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), 'temporary')
       if fsUtils.exists(temporaryFilePath)
         fsUtils.remove(temporaryFilePath)
         waits(20)
@@ -910,7 +910,7 @@
     [ignoreFile] = []

     beforeEach ->
-      ignoreFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore')
+      ignoreFile = path.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore')
       fsUtils.write(ignoreFile, 'tree-view.js')
       config.set "core.hideGitIgnoredFiles", false

@@ -933,15 +933,15 @@

     beforeEach ->
       config.set "core.hideGitIgnoredFiles", false
-      ignoreFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore')
+      ignoreFile = path.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore')
       fsUtils.write(ignoreFile, 'tree-view.js')
       git.getPathStatus(ignoreFile)

-      newFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir2'), 'new2')
+      newFile = path.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir2'), 'new2')
       fsUtils.write(newFile, '')
       git.getPathStatus(newFile)

-      modifiedFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir1'), 'file1')
+      modifiedFile = path.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir1'), 'file1')
       originalFileContent = fsUtils.read(modifiedFile)
       fsUtils.write modifiedFile, 'ch ch changes'
       git.getPathStatus(modifiedFile)


Unfocus spec

Unfocus spec

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -1077,7 +1077,7 @@
       it "does not hide git ignored files", ->
         expect(treeView.find('.file:contains(tree-view.js)').length).toBe 1

-  fdescribe "the hideIgnoredNames config option", ->
+  describe "the hideIgnoredNames config option", ->
     beforeEach ->
       dotGitFixture = path.join(__dirname, 'fixtures', 'git', 'working-dir', 'git.git')
       projectPath = temp.mkdirSync('tree-view-project')


Client: Activity: Updated channel participant avatars render method to wrap avatar singleboxes

--- client/activity/lib/components/channelparticipantavatars/index.coffee
+++ client/activity/lib/components/channelparticipantavatars/index.coffee
@@ -297,13 +297,15 @@

   render: ->
-

-      {@renderPreviewAvatars()}
-      {@renderMoreCount()}
-      {@renderNewParticipantButton()}
-      {@renderAddNewParticipantInput()}
-      {@renderAllParticipantsMenu()}
-      {@renderAddNewChannelParticipantsDropdown()}
+

+

+        {@renderPreviewAvatars()}
+        {@renderMoreCount()}
+        {@renderNewParticipantButton()}
+

+        {@renderAddNewParticipantInput()}
+        {@renderAllParticipantsMenu()}
+        {@renderAddNewChannelParticipantsDropdown()}


fixed being unable to use cmd+enter on macs

--- app/assets/javascripts/inbox.coffee
+++ app/assets/javascripts/inbox.coffee
@@ -57,7 +57,7 @@

 $(document).on "keydown", "textarea[name=ib-answer]", (evt) ->
   iid = $(this)[0].dataset.id
-  if evt.keyCode == 13 and evt.ctrlKey
+  if evt.keyCode == 13 and (evt.ctrlKey or evt.metaKey)
     # trigger warning:
     $("button[name=ib-answer][data-ib-id=#{iid}]").trigger 'click'

@@ -120,4 +120,4 @@
         showNotification "An error occurred, a developer should check the console for details", false
       complete: (jqxhr, status) ->
         btn.button "reset"
-        $("textarea[name=ib-answer][data-id=#{iid}]").removeAttr "readonly"+        $("textarea[name=ib-answer][data-id=#{iid}]").removeAttr "readonly"


Un-f fuzzy finder spec

Un-f fuzzy finder spec

--- src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee
+++ src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee
@@ -7,7 +7,7 @@
 fsUtils = require 'fs-utils'
 path = require 'path'

-fdescribe 'FuzzyFinder', ->
+describe 'FuzzyFinder', ->
   [finderView] = []

   beforeEach ->


include empty submitlog

include empty submitlog

--- src/scripts/modules/media/editbar/modals/publish.coffee
+++ src/scripts/modules/media/editbar/modals/publish.coffee
@@ -36,11 +36,17 @@
       e.preventDefault()

       formData = $(e.originalEvent.target).serializeArray()
-      data = []
+      items = []

       _.each formData, (field) ->
         if field.name isnt 'license'
-          data.push(field.name)
+          items.push(field.name)
+
+
+      data =
+        submitlog: 'TEST_SUBMITLOG'
+        items: items
+

       $.ajax
         type: 'POST'


hide mouse after 5 sec of inactivity

hide mouse after 5 sec of inactivity

--- templates/project/assets/javascripts/application.coffee
+++ templates/project/assets/javascripts/application.coffee
@@ -12,6 +12,19 @@
   Dashing.widget_base_dimensions ||= [300, 360]
   Dashing.numColumns ||= 4

+  # hide mouse after 5 sec of inactivity
+  timeout = null
+  $(document).on "mousemove", ->
+    if timeout isnt null
+      $("body").css cursor: ""
+      $(".gs_w").css cursor: ""
+      clearTimeout timeout
+    timeout = setTimeout(->
+      timeout = null
+      $("body").css cursor: "none"
+      $(".gs_w").css cursor: "none"
+    , 5000)
+
   contentWidth = (Dashing.widget_base_dimensions[0] + Dashing.widget_margins[0] * 2) * Dashing.numColumns

   Batman.setImmediate ->


add test for instance hook

add test for instance hook

--- test/hooks.coffee
+++ test/hooks.coffee
@@ -139,3 +139,18 @@
         hinoki.inject container, (a) ->
             test.equals a, 6
             test.done()
+
+    'instance': (test) ->
+        test.expect 3
+
+        container =
+            factories:
+                a: -> 5
+            hooks:
+                instance: (chain, instance) ->
+                    test.deepEqual chain, ['a']
+                    test.equals instance, 5
+
+        hinoki.inject container, (a) ->
+            test.equals a, 5
+            test.done()


DE19904: RPB: Restoring tests for user story/leaf story count.

--- test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
+++ test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
@@ -105,25 +105,25 @@
       expect(@cardboard.getColumns()[2].getColumnHeader().getHeaderValue()).toBe "Q2"
       expect(@cardboard.getColumns()[3].getColumnHeader().getHeaderValue()).toBe "Future Planning Period"

-#  it 'should have user story count on the cards if UserStories is a selected card field', ->
-#    @createCardboard().then =>
-#      _.each @cardboard.getColumns(), (column) =>
-#        _.each column.getCards(), (card) =>
-#          expect(card.record.data.UserStories.Count).toBe 3
-#
-#  it 'should have leaf story count on the cards if UserStories is a selected card field', ->
-#    @createCardboard().then =>
-#      _.each @cardboard.getColumns(), (column) =>
-#        _.each column.getCards(), (card) =>
-#          expect(card.record.data.LeafStoryCount).toBe 42
-#          expect(card.getEl().down('.rui-card-content .UserStories .user-story-count').dom.innerHTML).toBe "(42)"
-#
-#  it 'should have leaf story plan estimate total on the cards', ->
-#    @createCardboard().then =>
-#      _.each @cardboard.getColumns(), (column) =>
-#        _.each column.getCards(), (card) =>
-#          expect(card.record.data.LeafStoryPlanEstimateTotal).toBe 3.14
-#          expect(card.getEl().down('.rui-card-content .UserStories .user-story-points').dom.innerHTML).toContain "3.14"
+  it 'should have user story count on the cards if UserStories is a selected card field', ->
+    @createCardboard(cardConfig: fields: ['UserStories']).then =>
+      _.each @cardboard.getColumns(), (column) =>
+        _.each column.getCards(), (card) =>
+          expect(card.record.data.UserStories.Count).toBe 3
+
+  it 'should have leaf story count on the cards if UserStories is a selected card field', ->
+    @createCardboard(cardConfig: fields: ['UserStories']).then =>
+      _.each @cardboard.getColumns(), (column) =>
+        _.each column.getCards(), (card) =>
+          expect(card.record.data.LeafStoryCount).toBe 42
+          expect(card.getEl().down('.rui-card-content .UserStories .user-story-count').dom.innerHTML).toBe "(42)"
+
+  it 'should have leaf story plan estimate total on the cards if UserStories is a selected card field', ->
+    @createCardboard(cardConfig: fields: ['UserStories']).then =>
+      _.each @cardboard.getColumns(), (column) =>
+        _.each column.getCards(), (card) =>
+          expect(card.record.data.LeafStoryPlanEstimateTotal).toBe 3.14
+          expect(card.getEl().down('.rui-card-content .UserStories .user-story-points').dom.innerHTML).toContain "3.14"

   it 'should have parent on the cards', ->
     @createCardboard().then =>


Remove some logging stuff

Remove some logging stuff

--- assets/javascripts/views/log.coffee
+++ assets/javascripts/views/log.coffee
@@ -11,30 +11,23 @@
     @teardownLogEngine()

   setupLogEngine: ->
-    console.log 'setting up log engine'
     @set 'logEngine', window.Log.create()
     @handleLogUpdates()

   logWillChange: (->
-    console.log 'log will change'
     @teardownLogEngine()
   ).observesBefore 'log'

   logDidChange: (->
-    console.log 'log did change'
     if @get 'log'
       @setupLogEngine()
       @rerender() if @get('_state') == 'inDOM'
-    else
-      console.log 'log is null'
   ).observes 'log'

   teardownLogEngine: ->
     if log = @get('log')
       parts = log.get 'parts'
       parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop')
-    else
-      console.log 'log is null'

   handleLogUpdates: ->
     if log = @get('log')
@@ -42,8 +35,6 @@
       parts.addArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop')
       parts = parts.slice(0)
       @partsDidChange(parts, 0, null, parts.length)
-    else
-      console.log 'log is null'

   partsDidChange: (parts, start, _, added)->
     for part, i in parts.slice(start, start + added)


Remove ng2 templates except for maintained TS version

--- assets/js/directives/toolbar.coffee
+++ assets/js/directives/toolbar.coffee
@@ -81,9 +81,7 @@

1.5.x

1.5.x + Typescript

-
2.0.x (ES6)

-
2.0.x (ES5)

-
2.0.x (TS)

+
2.0.x


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/state.coffee
+++ test/state.coffee
@@ -13,6 +13,8 @@
     initialState: 'run'

   animation.include(StateMachine)
+
+  log animation

   animation.update()
   animation.update()


Re-order tests.

Re-order tests.

--- test/types.coffee
+++ test/types.coffee
@@ -20,242 +20,6 @@

   teardown ->
     types = null
-
-  test 'isUnemptyString function is defined', ->
-    assert.isFunction types.isUnemptyString
-
-  test 'isUnemptyString with string foo returns true', ->
-    assert.isTrue types.isUnemptyString('foo')
-
-  test 'isUnemptyString with null returns false', ->
-    assert.isFalse types.isUnemptyString(null)
-
-  test 'isUnemptyString with empty string returns false', ->
-    assert.isFalse types.isUnemptyString('')
-
-  test 'isUnemptyString with object returns false', ->
-    assert.isFalse types.isUnemptyString({})
-
-  test 'isUnemptyString with string bar returns true', ->
-    assert.isTrue types.isUnemptyString('bar')
-
-  test 'isString function is defined', ->
-    assert.isFunction types.isString
-
-  test 'isString with string foo returns true', ->
-    assert.isTrue types.isString('foo')
-
-  test 'isString with null returns false', ->
-    assert.isFalse types.isString(null)
-
-  test 'isString with empty string returns true', ->
-    assert.isTrue types.isString('')
-
-  test 'isString with object returns false', ->
-    assert.isFalse types.isString({})
-
-  test 'isArray function is defined', ->
-    assert.isFunction types.isArray
-
-  test 'isArray with array returns true', ->
-    assert.isTrue types.isArray([])
-
-  test 'isArray with null returns false', ->
-    assert.isFalse types.isArray(null)
-
-  test 'isArray with string returns false', ->
-    assert.isFalse types.isArray('[]')
-
-  test 'isArray with object returns false', ->
-    assert.isFalse types.isArray({})
-
-  test 'isObject function is defined', ->
-    assert.isFunction types.isObject
-
-  test 'isObject with object returns true', ->
-    assert.isTrue types.isObject({})
-
-  test 'isObject with null returns false', ->
-    assert.isFalse types.isObject(null)
-
-  test 'isObject with string returns false', ->
-    assert.isFalse types.isObject('{}')
-
-  test 'isObject with array returns false', ->
-    assert.isFalse types.isObject([])
-
-  test 'isFunction function is defined', ->
-    assert.isFunction types.isFunction
-
-  test 'isFunction with function returns true', ->
-    assert.isTrue types.isFunction(->)
-
-  test 'isFunction with null returns false', ->
-    assert.isFalse types.isFunction(null)
-
-  test 'isFunction with string returns false', ->
-    assert.isFalse types.isFunction('->')
-
-  test 'isFunction with object returns false', ->
-    assert.isFalse types.isFunction({})
-
-  test 'isFunction with array returns false', ->
-    assert.isFalse types.isFunction([])
-
-  test 'isInstance function is defined', ->
-    assert.isFunction types.isInstance
-
-  test 'isInstance with new Error and Error returns true', ->
-    assert.isTrue types.isInstance(new Error(), Error)
-
-  test 'isInstance with object and Error returns false', ->
-    assert.isFalse types.isInstance({}, Error)
-
-  test 'isInstance with null and null returns false', ->
-    assert.isFalse types.isInstance(null, null)
-
-  test 'isInstance with object and Object returns true', ->
-    assert.isTrue types.isInstance({}, Object)
-
-  test 'isInstance with null and Object returns false', ->
-    assert.isFalse types.isInstance(null, Object)
-
-  test 'isInstance with array and Array returns true', ->
-    assert.isTrue types.isInstance([], Array)
-
-  test 'isInstance with Object and object returns false', ->
-    assert.isFalse types.isInstance(Object, {})
-
-  test 'verifyUnemptyString function is defined', ->
-    assert.isFunction types.verifyUnemptyString
-
-  test 'verifyUnemptyString with string baz does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyUnemptyString 'baz'
-
-  test 'verifyUnemptyString with null throws', ->
-    assert.throws ->
-      types.verifyUnemptyString null
-
-  test 'verifyUnemptyString with empty string throws', ->
-    assert.throws ->
-      types.verifyUnemptyString ''
-
-  test 'verifyUnemptyString with object throws', ->
-    assert.throws ->
-      types.verifyUnemptyString {}
-
-  test 'verifyUnemptyString with string qux does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyUnemptyString 'qux'
-
-  test 'verifyString function is defined', ->
-    assert.isFunction types.verifyString
-
-  test 'verifyString with string baz does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyString 'baz'
-
-  test 'verifyString with null throws', ->
-    assert.throws ->
-      types.verifyString null
-
-  test 'verifyString with empty string does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyString ''
-
-  test 'verifyString with object throws', ->
-    assert.throws ->
-      types.verifyString {}
-
-  test 'verifyArray function is defined', ->
-    assert.isFunction types.verifyArray
-
-  test 'verifyArray with array does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyArray []
-
-  test 'verifyArray with null throws', ->
-    assert.throws ->
-      types.verifyArray null
-
-  test 'verifyArray with string throws', ->
-    assert.throws ->
-      types.verifyArray '[]'
-
-  test 'verifyArray with object throws', ->
-    assert.throws ->
-      types.verifyArray {}
-
-  test 'verifyObject function is defined', ->
-    assert.isFunction types.verifyObject
-
-  test 'verifyObject with object does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyObject {}
-
-  test 'verifyObject with null throws', ->
-    assert.throws ->
-      types.verifyObject null
-
-  test 'verifyObject with string throws', ->
-    assert.throws ->
-      types.verifyObject '[]'
-
-  test 'verifyObject with array throws', ->
-    assert.throws ->
-      types.verifyObject []
-
-  test 'verifyFunction function is defined', ->
-    assert.isFunction types.verifyFunction
-
-  test 'verifyFunction with function does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyFunction ->
-
-  test 'verifyFunction with null throws', ->
-    assert.throws ->
-      types.verifyFunction null
-
-  test 'verifyFunction with string throws', ->
-    assert.throws ->
-      types.verifyFunction '[]'
-
-  test 'verifyFunction with object throws', ->
-    assert.throws ->
-      types.verifyFunction {}
-
-  test 'verifyFunction with array throws', ->
-    assert.throws ->
-      types.verifyFunction []
-
-  test 'verifyInstance with new Error and Error does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyInstance new Error(), Error
-
-  test 'verifyInstance with object and Error throws', ->
-    assert.throws ->
-      types.verifyInstance {}, Error
-
-  test 'verifyInstance with null and null throws', ->
-    assert.throws ->
-      types.verifyInstance null, null
-
-  test 'verifyInstance with object and Object does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyInstance {}, Object
-
-  test 'verifyInstance with null and Object throws', ->
-    assert.throws ->
-      types.verifyInstance null, Object
-
-  test 'verifyInstance with array and Array does not throw', ->
-    assert.doesNotThrow ->
-      types.verifyInstance [], Array
-
-  test 'verifyInstance with Object and object throws', ->
-    assert.throws ->
-      types.verifyInstance Object, {}

   test 'quacksLike function is defined', ->
     assert.isFunction types.quacksLike
@@ -308,3 +72,239 @@
     thirdFunction = ->
     assert.isFalse types.quacksLike({ foo: firstFunction, bar: {} }, { foo: secondFunction, bar: thirdFunction })

+  test 'verifyInstance with new Error and Error does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyInstance new Error(), Error
+
+  test 'verifyInstance with object and Error throws', ->
+    assert.throws ->
+      types.verifyInstance {}, Error
+
+  test 'verifyInstance with null and null throws', ->
+    assert.throws ->
+      types.verifyInstance null, null
+
+  test 'verifyInstance with object and Object does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyInstance {}, Object
+
+  test 'verifyInstance with null and Object throws', ->
+    assert.throws ->
+      types.verifyInstance null, Object
+
+  test 'verifyInstance with array and Array does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyInstance [], Array
+
+  test 'verifyInstance with Object and object throws', ->
+    assert.throws ->
+      types.verifyInstance Object, {}
+
+  test 'isInstance function is defined', ->
+    assert.isFunction types.isInstance
+
+  test 'isInstance with new Error and Error returns true', ->
+    assert.isTrue types.isInstance(new Error(), Error)
+
+  test 'isInstance with object and Error returns false', ->
+    assert.isFalse types.isInstance({}, Error)
+
+  test 'isInstance with null and null returns false', ->
+    assert.isFalse types.isInstance(null, null)
+
+  test 'isInstance with object and Object returns true', ->
+    assert.isTrue types.isInstance({}, Object)
+
+  test 'isInstance with null and Object returns false', ->
+    assert.isFalse types.isInstance(null, Object)
+
+  test 'isInstance with array and Array returns true', ->
+    assert.isTrue types.isInstance([], Array)
+
+  test 'isInstance with Object and object returns false', ->
+    assert.isFalse types.isInstance(Object, {})
+
+  test 'verifyObject function is defined', ->
+    assert.isFunction types.verifyObject
+
+  test 'verifyObject with object does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyObject {}
+
+  test 'verifyObject with null throws', ->
+    assert.throws ->
+      types.verifyObject null
+
+  test 'verifyObject with string throws', ->
+    assert.throws ->
+      types.verifyObject '[]'
+
+  test 'verifyObject with array throws', ->
+    assert.throws ->
+      types.verifyObject []
+
+  test 'isObject function is defined', ->
+    assert.isFunction types.isObject
+
+  test 'isObject with object returns true', ->
+    assert.isTrue types.isObject({})
+
+  test 'isObject with null returns false', ->
+    assert.isFalse types.isObject(null)
+
+  test 'isObject with string returns false', ->
+    assert.isFalse types.isObject('{}')
+
+  test 'isObject with array returns false', ->
+    assert.isFalse types.isObject([])
+
+  test 'verifyArray function is defined', ->
+    assert.isFunction types.verifyArray
+
+  test 'verifyArray with array does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyArray []
+
+  test 'verifyArray with null throws', ->
+    assert.throws ->
+      types.verifyArray null
+
+  test 'verifyArray with string throws', ->
+    assert.throws ->
+      types.verifyArray '[]'
+
+  test 'verifyArray with object throws', ->
+    assert.throws ->
+      types.verifyArray {}
+
+  test 'isArray function is defined', ->
+    assert.isFunction types.isArray
+
+  test 'isArray with array returns true', ->
+    assert.isTrue types.isArray([])
+
+  test 'isArray with null returns false', ->
+    assert.isFalse types.isArray(null)
+
+  test 'isArray with string returns false', ->
+    assert.isFalse types.isArray('[]')
+
+  test 'isArray with object returns false', ->
+    assert.isFalse types.isArray({})
+
+  test 'verifyFunction function is defined', ->
+    assert.isFunction types.verifyFunction
+
+  test 'verifyFunction with function does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyFunction ->
+
+  test 'verifyFunction with null throws', ->
+    assert.throws ->
+      types.verifyFunction null
+
+  test 'verifyFunction with string throws', ->
+    assert.throws ->
+      types.verifyFunction '[]'
+
+  test 'verifyFunction with object throws', ->
+    assert.throws ->
+      types.verifyFunction {}
+
+  test 'verifyFunction with array throws', ->
+    assert.throws ->
+      types.verifyFunction []
+
+  test 'isFunction function is defined', ->
+    assert.isFunction types.isFunction
+
+  test 'isFunction with function returns true', ->
+    assert.isTrue types.isFunction(->)
+
+  test 'isFunction with null returns false', ->
+    assert.isFalse types.isFunction(null)
+
+  test 'isFunction with string returns false', ->
+    assert.isFalse types.isFunction('->')
+
+  test 'isFunction with object returns false', ->
+    assert.isFalse types.isFunction({})
+
+  test 'isFunction with array returns false', ->
+    assert.isFalse types.isFunction([])
+
+  test 'verifyUnemptyString function is defined', ->
+    assert.isFunction types.verifyUnemptyString
+
+  test 'verifyUnemptyString with string baz does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyUnemptyString 'baz'
+
+  test 'verifyUnemptyString with null throws', ->
+    assert.throws ->
+      types.verifyUnemptyString null
+
+  test 'verifyUnemptyString with empty string throws', ->
+    assert.throws ->
+      types.verifyUnemptyString ''
+
+  test 'verifyUnemptyString with object throws', ->
+    assert.throws ->
+      types.verifyUnemptyString {}
+
+  test 'verifyUnemptyString with string qux does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyUnemptyString 'qux'
+
+  test 'isUnemptyString function is defined', ->
+    assert.isFunction types.isUnemptyString
+
+  test 'isUnemptyString with string foo returns true', ->
+    assert.isTrue types.isUnemptyString('foo')
+
+  test 'isUnemptyString with null returns false', ->
+    assert.isFalse types.isUnemptyString(null)
+
+  test 'isUnemptyString with empty string returns false', ->
+    assert.isFalse types.isUnemptyString('')
+
+  test 'isUnemptyString with object returns false', ->
+    assert.isFalse types.isUnemptyString({})
+
+  test 'isUnemptyString with string bar returns true', ->
+    assert.isTrue types.isUnemptyString('bar')
+
+  test 'verifyString function is defined', ->
+    assert.isFunction types.verifyString
+
+  test 'verifyString with string baz does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyString 'baz'
+
+  test 'verifyString with null throws', ->
+    assert.throws ->
+      types.verifyString null
+
+  test 'verifyString with empty string does not throw', ->
+    assert.doesNotThrow ->
+      types.verifyString ''
+
+  test 'verifyString with object throws', ->
+    assert.throws ->
+      types.verifyString {}
+
+  test 'isString function is defined', ->
+    assert.isFunction types.isString
+
+  test 'isString with string foo returns true', ->
+    assert.isTrue types.isString('foo')
+
+  test 'isString with null returns false', ->
+    assert.isFalse types.isString(null)
+
+  test 'isString with empty string returns true', ->
+    assert.isTrue types.isString('')
+
+  test 'isString with object returns false', ->
+    assert.isFalse types.isString({})
+


Update test

Update test

--- test/vigil.coffee
+++ test/vigil.coffee
@@ -3,7 +3,7 @@
 request = require 'request'
 should  = (require 'chai').should()

-vigil   = require '../lib'
+vigil   = require '../'

 describe 'vigil', ->


Cleanup, fix braino

Cleanup, fix braino

--- layout.coffee
+++ layout.coffee
@@ -607,7 +607,7 @@

   # init all views in the DOM recursively
   init = (selector = $('view')) ->
-    for el, i in selector
+    for el in selector
       initFromElement(el) unless el.$defer or el.$view
     # console.log 'caches', compileCache

@@ -865,7 +865,7 @@

     unbind: (ev, callback) ->
       super(ev, callback)
-      if @events['mousemove']?.length is 0 and @events['x']?.length is 0 or @events['y']?.length is 0
+      if @events['mousemove']?.length is 0 and @events['x']?.length is 0 and @events['y']?.length is 0
         @stop()

     handle: (event) =>


Clear any overlap when using Mongo's $unset operator

--- lib/db.coffee
+++ lib/db.coffee
@@ -538,6 +538,9 @@

   return callback() if Object.keys(update).length == 0

+  if (update['$unset']?)
+    optimizeProjection(update['$unset'])
+
   devicesCollection.update({'_id' : deviceId}, update, {upsert: isNew}, (err, result) ->
     if not err and result.result.n != 1
       return callback(new Error("Device #{deviceId} not found in database"))


reverting irc

reverting irc

--- src/hubot/irc.coffee
+++ src/hubot/irc.coffee
@@ -28,7 +28,7 @@
     self = @

     options =
-      nick:     process.env.HUBOT_IRC_NICK
+      nick:     process.env.HUBOT_IRC_NICK or @name
       port:     process.env.HUBOT_IRC_PORT
       rooms:    process.env.HUBOT_IRC_ROOMS.split(",")
       server:   process.env.HUBOT_IRC_SERVER
@@ -42,7 +42,11 @@
           debug: true,
           port: options.port,
           stripColors: true,
+<<<<<<< .merge_file_U8CzlD
           floodProtection: true,
+=======
+          secure: if options.port is "6697" then true else false,
+>>>>>>> .merge_file_6hEur6
         }

     unless options.nickpass
@@ -58,8 +62,13 @@
         if from is 'NickServ' and text.indexOf('registered') isnt -1
           bot.say 'NickServ', "identify #{options.nickpass}"
         else if options.nickpass and from is 'NickServ' and text.indexOf('now identified') isnt -1
+<<<<<<< .merge_file_U8CzlD
             for room in options.rooms
                 @join room
+=======
+          for room in options.rooms
+            @join room
+>>>>>>> .merge_file_6hEur6

     bot.addListener 'message', (from, to, message) ->
       console.log "From #{from} to #{to}: #{message}"


Machine: add more data on Machine object

--- client/Main/providers/computeprovider.coffee
+++ client/Main/providers/computeprovider.coffee
@@ -36,18 +36,16 @@

 class Machine extends KDObject

-  constructor:(options = {}, data)->
+  constructor:(options = {})->

-    unless data?.bongo_?.constructorName is 'JMachine'
+    { machine } = options
+    unless machine?.bongo_?.constructorName is 'JMachine'
       throw new Error 'Data should be a JMachine instance'

-    super options, data
-    { @name, @publicAddress } = @jMachine = @getData()
+    delete options.machine
+    super options, machine

-
-
-
-
+    { @label, @publicAddress, @state } = @jMachine = @getData()


Fixed finder pane to work with new finder.

--- client/ide/workspace/panes/finderpane.coffee
+++ client/ide/workspace/panes/finderpane.coffee
@@ -4,12 +4,13 @@

     super options, data

-    KD.getSingleton('appManager').open 'Finder', (finderApp) =>
-      @createFinderController finderApp
-      @bindListeners()
+    @createFinderController()
+    @bindListeners()

-  createFinderController: (finderApp) ->
+  createFinderController: ->
+    finderApp         = new FinderController
     @finderController = finderApp.create()
+
     @addSubView @finderController.getView()
     @finderController.reset()


bugfix

bugfix

--- lib/jsau.iced
+++ lib/jsau.iced
@@ -88,5 +88,4 @@
   throw err if err?
   target = (path.join process.cwd(), project.project)

-  console.log target
   transform_dir fullpath, project, target


fixed KidsComponent event listener not falling off on unmount

--- urb/zod/pub/tree/src/js/components/KidsComponent.coffee
+++ urb/zod/pub/tree/src/js/components/KidsComponent.coffee
@@ -23,6 +23,9 @@
     (not _keys.isEmpty()) and _keys.every (k) =>
       @state.cont[@state.path+"/"+k]?

+  componentWillUnmount: ->
+    TreeStore.removeChangeListener @_onChangeStore
+
   componentDidMount: ->
     TreeStore.addChangeListener @_onChangeStore
     TreeActions.getPath @state.path,"kids" unless @gotPath()


Update uglify task to use variables and new naming scheme

--- grunt/uglify.coffee
+++ grunt/uglify.coffee
@@ -1,4 +1,4 @@
 module.exports =
   production:
     files:
-      'build/production/all.js': 'build/debug/all.js'
+      '<%= buildRelease %>/all.js': '<%= buildDebug %>/all.js'


added dependency exclusion

added dependency exclusion

--- inject.coffee
+++ inject.coffee
@@ -1,20 +1,28 @@
-path = require 'path'
+path_ = require 'path'
 fs = require 'fs'
-file = path.resolve process.argv[2]
-pathIdMap = {}
+file = path_.resolve process.argv[2]
+filenameIdMap = {}
 id = 0
-pathToId = (path) ->
-  pathIdMap[path] = id+=1 if path not of pathIdMap
-  pathIdMap[path]
+shalow = (from, to) ->
+  to[key] = value for key, value of from
+  to
+filenameToId = (filename) ->
+  filenameIdMap[filename] = id+=1 if filename not of filenameIdMap
+  filenameIdMap[filename]
 toDict = (kvps) ->
   dict = {}
   dict[kvp[0]] = kvp[1] for kvp in kvps
   dict
-boil = (id, aliasIdMap, code, filename) ->
+isExcluded = (config) ->
+  if config.excluded or config.path in config.exclude
+    yes
+  else
+    no
+boil = (id, pathIdMap, code, filename) ->
   """
-  // file: #{path.relative __dirname, filename}
-  register.call(this,#{id},#{JSON.stringify aliasIdMap},
+  register.call(this,#{id},#{JSON.stringify pathIdMap},
   function(require,exports,module){
+  // file: #{path_.relative __dirname, filename}
   #{code}
   });
   """
@@ -23,22 +31,22 @@
   (function(everything){
     window.boiler={main:{}};
     var idModuleMap={};
-    function emulateRequire(aliasIdMap){
-      function require(alias, windowName){
-        var exports = idModuleMap[aliasIdMap[alias]];
-        if(typeof windowName==='function'){
-          return windowName(exports);
-        }else if(typeof windowName==='string'){
-          return window[windowName];
+    function emulateRequire(pathIdMap){
+      function require(path, opt){
+        var exports = idModuleMap[pathIdMap[path]];
+        if(typeof opt==='function'){
+          return opt(exports);
+        }else if(typeof opt==='string'){
+          return window[opt];
         }else{
           return exports;
         }
       }
       return require;
     }
-    function register(id,aliasIdMap,factory){
+    function register(id,pathIdMap,factory){
       var module={exports:{}};
-      factory.call(this,emulateRequire(aliasIdMap),module.exports,module);
+      factory.call(this,emulateRequire(pathIdMap),module.exports,module);
       window.boiler.main=idModuleMap[id]=module.exports;
     }
     everything.call(this,register);
@@ -49,6 +57,7 @@

 everything = ''
 hookedExts = []
+config = exclude:[], path:''

 updateExtensions = ->
   for ext, func of require.extensions when ext not in hookedExts
@@ -56,16 +65,27 @@
       hookedExts.push ext
       require.extensions[ext] = (module, filename) ->
         code = ''
+        deps = {}
         cmp = module._compile
-        module.__required = {}
+        module.__boiler_hook = (resolve, path, opt={}) ->
+          config =
+            parent:config
+            exclude:(x for x in config.exclude)
+            excluded:config.excluded or path in config.exclude
+          config.path = path
+          config.parent.deps = deps
+          deps[path] = resolve path
+          if opt.exclude
+            config.exclude.push path for path in opt.exclude # when (filename=resolve path) not in config.exclude
+          #console.dir config
         module._compile = (content, filename) ->
           code = content
           cmp.call this,
             """
             require = function(req) {
-              var require = function(alias) {
-                module.__required[alias] = req.resolve(alias);
-                return req.apply(this, arguments);
+              var require = function(path, opt) {
+                module.__boiler_hook(req.resolve, path, opt);
+                return req.call(this, path);
               };
               for (var i in req) {
                 require[i] = req[i];
@@ -76,8 +96,17 @@
             """, filename
         try
           func module, filename
-        aliasIdMap = toDict([alias, pathToId path] for alias, path of module.__required)
-        everything += boil pathToId(filename), aliasIdMap, code, filename
+        #  console.log "loaded #{config.path}:#{filename} is loading #{deps}"
+        #catch error
+        #  console.log 'error in '+filename+': '+error
+
+        if not config.excluded
+          #  console.log "boiling #{config.path}:#{filename}"
+          pathIdMap = toDict([path, filenameToId fn] for path, fn of deps)
+          everything += boil filenameToId(filename), pathIdMap, code, filename
+        #else
+        #  console.log 'excluded '+filename
+        config = config.parent if config.parent
         updateExtensions()

 updateExtensions()


Reformatted KiRoutes

Reformatted KiRoutes

--- src/ki-router.coffee
+++ src/ki-router.coffee
@@ -61,14 +61,20 @@
   postExecutionListeners: []
   exceptionListeners: []
   debug: false
+  previous: false
+  paramVerifier: false
+  renderCount: 0
+
   log: =>
     if @debug && window.console && console && console.log
       if JSON.stringify
         console.log("ki-router: " + JSON.stringify(arguments))
       else
         console.log(arguments)
+
   add: (urlPattern, fn, metadata) =>
     @routes.push({route: new SinatraRouteParser(urlPattern), fn: fn, urlPattern: urlPattern, metadata: metadata})
+
   exec: (path) =>
     if matched = @find(path)
       @log("Found route for", path, " Calling function with params ", matched.params)
@@ -84,26 +90,30 @@
         throw error
       @previous = matched
       return matched
+
   find: (path) =>
     for candidate in @routes
       if params = candidate.route.parse(path, @paramVerifier)
         return {params: params, route: candidate.matchedRoute, fn: candidate.fn, urlPattern: candidate.urlPattern, path: path, metadata: candidate.metadata}
+
   addPostExecutionListener: (fn) =>
     @postExecutionListeners.push(fn)
+
   addExceptionListener: (fn) =>
     @exceptionListeners.push(fn)

   pushStateSupport: history && history.pushState
   hashchangeSupport: "onhashchange" of window
   hashBaseUrl: false
-  previous: false
   disableUrlUpdate: false
   fallbackRoute: false
   init: false
   initDone: false
-  paramVerifier: false
-  renderCount: 0
   clickCount: 0
+
+  historyApiRouting: () =>
+    @hashchangeSupport = false
+    @transparentRouting()

   transparentRouting: () =>
     @init = true
@@ -114,13 +124,11 @@
     finally
       @init = false
       @initDone = true
+
   hashbangRouting: () =>
     @pushStateSupport = false
     if !@hashchangeSupport
       throw new Error("No hashchange support!")
-    @transparentRouting()
-  historyApiRouting: () =>
-    @hashchangeSupport = false
     @transparentRouting()

   attachClickListener: =>
@@ -131,11 +139,7 @@
         if target
           @log("Checking if click event should be rendered")
           aTag = @findATag(target)
-          if @blog("- A tag", aTag) &&
-          @blog("- Left mouse button click", @leftMouseButton(event)) &&
-          @blog("- Not meta keys pressed", !@metakeyPressed(event)) &&
-          @blog("- Target attribute is current window", @targetAttributeIsCurrentWindow(aTag)) &&
-          @blog("- Link host same as current window", @targetHostSame(aTag))
+          if @checkIfOkToRender(event, aTag)
             href = aTag.attributes.href.nodeValue
             @log("Click event passed all checks")
             if !@pushStateSupport && @hashchangeSupport && @hashBaseUrl && @hashBaseUrl != window.location.pathname
@@ -151,6 +155,13 @@
               @log("Letting browser render url because no matching route", href)
             return

+  checkIfOkToRender: (event, aTag) =>
+    @blog("- A tag", aTag) &&
+    @blog("- Left mouse button click", @leftMouseButton(event)) &&
+    @blog("- Not meta keys pressed", !@metakeyPressed(event)) &&
+    @blog("- Target attribute is current window", @targetAttributeIsCurrentWindow(aTag)) &&
+    @blog("- Link host same as current window", @targetHostSame(aTag))
+
   disableEventDefault: (ev) =>
     if ev.preventDefault
       ev.preventDefault()
@@ -262,7 +273,7 @@
       throw new Error("addListener can not attach listeners!")

 class SinatraRouteParser
-  constructor: (route) ->
+constructor: (route) ->
     @keys = []
     route = route.substring(1)
     segments = []


remove useless comments

remove useless comments

--- coffee/index.coffee
+++ coffee/index.coffee
@@ -8,7 +8,6 @@
 tray = require 'tray'

 args = require './args'
-# process.chdir args.workdir if args.workdir
 defaultDocPort = args.docport or 33300
 args.docsetdir = args.docsetdir or path.join(process.cwd(), "Docsets")


Don't bundle atom.sh on Windows

Don't bundle atom.sh on Windows

--- build/tasks/build-task.coffee
+++ build/tasks/build-task.coffee
@@ -21,7 +21,9 @@

     mkdir appDir

-    cp 'atom.sh', path.join(appDir, 'atom.sh')
+    if process.platform isnt 'win32'
+      cp 'atom.sh', path.join(appDir, 'atom.sh')
+
     cp 'package.json', path.join(appDir, 'package.json')

     packageDirectories = []


Add chocolatey gui for atom.exe

Add chocolatey gui for atom.exe

--- build/tasks/build-task.coffee
+++ build/tasks/build-task.coffee
@@ -92,6 +92,7 @@

       fs.writeFileSync path.join(appDir, 'apm', 'node_modules', 'atom-package-manager', 'bin', 'node.exe.ignore'), ''
       fs.writeFileSync path.join(appDir, 'node_modules', 'symbols-view', 'vendor', 'ctags-win32.exe.ignore'), ''
+      fs.writeFileSync path.join(shellAppDir, 'atom.exe.gui'), ''

     dependencies = ['compile', "generate-license:save"]
     dependencies.push('copy-info-plist') if process.platform is 'darwin'


Fixed close of MySQL driver.

Fixed close of MySQL driver.

For PostgreSQL we allow the user to send a query prior to closing the
connection, to perform some sort of clean up. I can't recall the
motivation for this option, I can't recall why a PostgreSQL connection
cannot simply be disconnected. Hopefully I'll remember before I set out
to document the API.

The MySQL driver close now has the same signature.

--- src/lib/mysql.coffee
+++ src/lib/mysql.coffee
@@ -51,12 +51,10 @@

   sql: (query, parameters, callback) ->
     try
-      say "HERE"
       @_client.query query, parameters, callback
     catch error
       console.error "CLOSING"
-      @close()
-      callback error
+      @close null, -> callback error

   close: (terminator, callback) ->
     @_client.destroy()


Fix https://github.com/poooi/poi/issues/802

--- views/env.coffee
+++ views/env.coffee
@@ -1,5 +1,5 @@
 require 'coffee-react/register'
-path = require 'path-extra'
+{join} = require 'path-extra'
 fs = require 'fs-extra'
 os = require 'os'
 semver = require 'semver'
@@ -7,23 +7,23 @@

 # Environments
 window.remote = require('electron').remote
-window.ROOT = path.join(__dirname, '..')
+window.ROOT = join(__dirname, '..')
 window.Tray = remote.require('electron').Tray
 window.EXROOT = remote.getGlobal 'EXROOT'
 window.APPDATA_PATH = remote.getGlobal 'APPDATA_PATH'
-window.PLUGIN_PATH = path.join window.APPDATA_PATH, 'plugins'
+window.PLUGIN_PATH = join window.APPDATA_PATH, 'plugins'
 window.POI_VERSION = remote.getGlobal 'POI_VERSION'
 window.SERVER_HOSTNAME = remote.getGlobal 'SERVER_HOSTNAME'
 window.MODULE_PATH = remote.getGlobal 'MODULE_PATH'
 fs.ensureDirSync window.PLUGIN_PATH
-fs.ensureDirSync path.join window.PLUGIN_PATH, 'node_modules'
+fs.ensureDirSync join window.PLUGIN_PATH, 'node_modules'

 # Shortcuts and Components
-(window.dbg = require path.join(ROOT, 'lib', 'debug')).init()
+(window.dbg = require join(ROOT, 'lib', 'debug')).init()
 window._ = require 'underscore'
 window.$ = (param) -> document.querySelector(param)
 window.$$ = (param) -> document.querySelectorAll(param)
-window.jQuery = require path.join(ROOT, 'components/jquery/dist/jquery')
+window.jQuery = require join(ROOT, 'components/jquery/dist/jquery')
 window.React = require 'react'
 window.ReactDOM = require 'react-dom'
 window.ReactBootstrap = require 'react-bootstrap'
@@ -53,7 +53,7 @@

 ## window.notify
 # msg=null: Sound-only notification.
-NOTIFY_DEFAULT_ICON = path.join(ROOT, 'assets', 'icons', 'icon.png')
+NOTIFY_DEFAULT_ICON = join(ROOT, 'assets', 'icons', 'icon.png')
 NOTIFY_NOTIFICATION_API = true
 if process.platform == 'win32' and semver.lt(os.release(), '6.2.0')
   NOTIFY_NOTIFICATION_API = false
@@ -96,7 +96,7 @@
         body: msg
         silent: true
     else
-      appIcon = new Tray(path.join(ROOT, 'assets', 'icons', 'poi.ico'));
+      appIcon = new Tray(join(ROOT, 'assets', 'icons', 'poi.ico'));
       appIcon.displayBalloon
         title: title
         icon: icon
@@ -160,14 +160,14 @@
 window.language = config.get 'poi.language', language
 window.zoomLevel = config.get 'poi.zoomLevel', 1
 window.useSVGIcon = config.get 'poi.useSVGIcon', false
-d = if process.platform == 'darwin' then path.join(path.homedir(), 'Pictures', 'Poi') else path.join(global.APPDATA_PATH, 'screenshots')
+d = if process.platform == 'darwin' then join(path.homedir(), 'Pictures', 'Poi') else join(global.APPDATA_PATH, 'screenshots')
 window.screenshotPath = config.get 'poi.screenshotPath', d
 window.notify.morale = config.get 'poi.notify.morale.value', 49
 window.notify.expedition = config.get 'poi.notify.expedition.value', 60

 # i18n config
 window.i18n = {}
-i18nFiles = glob.sync(path.join(__dirname, '..', 'i18n', '*'))
+i18nFiles = glob.sync(join(__dirname, '..', 'i18n', '*'))
 for i18nFile in i18nFiles
   namespace = path.basename i18nFile
   window.i18n[namespace] = new (require 'i18n-2')


better url

better url

--- js/app.coffee
+++ js/app.coffee
@@ -460,6 +460,19 @@
     VM.loadRootPage(cx)

   @get '^/add-projects', (cx) => VM.loadAddProjects cx
+
+  # before any project pages so that it gets routed first
+  @get '^/gh/organizations/:username/settings(.*)', (cx) ->
+    sel =
+      page: "org_settings"
+      crumbs: false
+      username: cx.params.username
+      favicon_updator: VM.reset_favicon
+
+    VM.selected sel
+
+    VM.loadOrgPage cx.params.username, cx.params.splat
+
   @get '^/gh/:username/:project/edit(.*)',
     (cx) ->
       project_name = "#{cx.params.username}/#{cx.params.project}"
@@ -549,17 +562,6 @@
       VM.selected sel

       VM.loadProject cx.params.username, cx.params.project
-
-  @get '^/gh/:username(.*)', (cx) ->
-    sel =
-      page: "org"
-      crumbs: false
-      username: cx.params.username
-      favicon_updator: VM.reset_favicon
-
-    VM.selected sel
-
-    VM.loadOrgPage cx.params.username, cx.params.splat

   @get '^/logout', (cx) -> VM.logout cx


Skip refresh when serchTerm length was short

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -646,6 +646,7 @@
             selection.destroy()
           @controlBar.show() if selectionDestroyed
           @withIgnoreChange => @setQuery(@lastQuery) # Recover query
+
         else
           autoPreview = @autoPreviewOnQueryChange and @isActive()
           refreshDelay = null
@@ -654,6 +655,8 @@

             if @currentSearchTerm isnt @lastSearchTerm
               @cachedItems = null
+              if @provider.searchUseRegex and @currentSearchTerm.length < @provider.getConfig('minimumLengthToStartRegexSearch')
+                return
               refreshDelay = if @provider.boundToSingleFile then 10 else 500
             else
               refreshDelay = if @provider.boundToSingleFile then 10 else 150


continue cleanup

continue cleanup

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -49,9 +49,6 @@

   # Ui.prototype
   # -------------------------
-  emitDidStopRefreshingOptions: null
-  debouncedPreviewOptions: null
-
   autoPreview: null
   autoPreviewOnQueryChange: null

@@ -397,10 +394,7 @@
   refresh: ({force, selectFirstItem}={}) ->
     @emitWillRefresh()

-    if force
-      @cachedItems = null
-
-    if @cachedItems?
+    if @cachedItems? and not force
       promiseForItems = Promise.resolve(@cachedItems)
     else
       promiseForItems = Promise.resolve(@provider.getItems()).then (items) =>
@@ -643,7 +637,6 @@
     @syncToEditor(editor)

     ignoreColumnChange = not @provider.itemHaveRange
-
     @syncSubcriptions.add editor.onDidChangeCursorPosition (event) =>
       return if event.textChanged
       return if ignoreColumnChange and (event.oldBufferPosition.row is event.newBufferPosition.row)


:fire: blank row

:fire: blank row

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -219,7 +219,6 @@
       else
         @startSyncToEditor(item) if @hasSomeNormalItemForFilePath(item.getPath())

-
   start: ->
     # When initial getItems() take very long time, it means refresh get delayed.
     # In this case, user see modified icon(mark) on tab.


further compact refresh

further compact refresh

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -409,7 +409,13 @@
         items = getItemsWithHeaders(items) unless @provider.boundToSingleFile
         items

-  filterItems: (items, filterSpec) ->
+  filterItems: (items) ->
+    @lastQuery = @getQuery()
+    sensitivity = @provider.getConfig('caseSensitivityForNarrowQuery')
+    filterSpec = getFilterSpecForQuery(@lastQuery, {sensitivity})
+    if @provider.updateGrammarOnQueryChange
+      @grammar.update(filterSpec.include) # No need to highlight excluded items
+
     if @excludedFiles.length
       items = items.filter (item) => item.filePath not in @excludedFiles
     items = @provider.filterItems(items, filterSpec)
@@ -419,16 +425,11 @@
   refresh: ({force, selectFirstItem, filePath}={}) ->
     @emitWillRefresh()

-    @lastQuery = @getQuery()
-    sensitivity = @provider.getConfig('caseSensitivityForNarrowQuery')
-    filterSpec = getFilterSpecForQuery(@lastQuery, {sensitivity})
-    if @provider.updateGrammarOnQueryChange
-      @grammar.update(filterSpec.include) # No need to highlight excluded items
-
     @getItems({force, filePath}).then (items) =>
-      @cachedItems = items if @provider.supportCacheItems
-      items = @filterItems(items, filterSpec)
-
+      if @provider.supportCacheItems
+        @cachedItems = items
+
+      items = @filterItems(items)
       if (not selectFirstItem) and @items.hasSelectedItem()
         selectedItem = findEqualLocationItem(items, @items.getSelectedItem())
         oldColumn = @getCursorColumn()


Fix issue where editor could flash and show label/hint from another cell When we say "wait for next Ajax response", the "next" is important (we don't say "current") When we want to wait, we store the current sequence no When an Ajax response arrive, we check that the current sequence no has been incremented by 1 For performance, anyEditableSelector only returns elements inside a .fr-editable For performance, filter on state before we filter on condition Minor: reorder attributes in the transitions to reflect the order in which operations run

--- src/resources/forms/orbeon/builder/resources/grid/placeholders.coffee
+++ src/resources/forms/orbeon/builder/resources/grid/placeholders.coffee
@@ -10,12 +10,13 @@
 #
 # The full text of the license is available at http://www.gnu.org/copyleft/lesser.html

-YD = YAHOO.util.Dom
-OD = ORBEON.util.Dom
 Builder = ORBEON.Builder
+Controls = ORBEON.xforms.Controls
+Document = ORBEON.xforms.Document
 Event = YAHOO.util.Event
 Events = ORBEON.xforms.Events
-Controls = ORBEON.xforms.Controls
+OD = ORBEON.util.Dom
+YD = YAHOO.util.Dom

 # For the generic label, generic hint, button's label, and link's label:
 #   Show/hide placeholders
@@ -87,7 +88,10 @@
     ]

     # Function dealing with editables
-    anyEditableSelector = (_.pluck editables, 'selector').join ', '                                                     # A CSS selector matching any editable
+    anyEditableSelector = do ->                                                                                # A CSS selector matching any editable
+        selectors = _.pluck editables, 'selector'
+        selectors = _.map selectors, (s) -> '.fr-editable ' + s
+        selectors.join ', '
     editable = (element) -> _.first _.filter editables, (e) -> f$.is '*', f$.findOrIs e.selector, element               # element: editable -> editable info
     editableEditInput = (element) -> $ (editable element).editInputSelector                                             # Input field used for editing
     editablePlaceholderOutput = (element) -> $ (editable element).placeholderOutputSelector                             # Element in which we put the placeholder
@@ -100,6 +104,11 @@
     matchState = (states, element) ->
         state = f$.data 'state', element
         ((_.isUndefined state) and (_.contains states, 'initial')) or (_.contains states, state)
+
+    # Utility
+    currentSeqNo = (element) ->
+        form = f$.closest 'form', element
+        parseInt Document.getFromClientState (f$.attr 'id', form), "sequence"

     # Events
     mouseEntersGridTd = (f) -> Builder.mouseEntersGridTdEvent.subscribe ({gridTd}) -> f $ gridTd
@@ -125,6 +134,9 @@
         Builder.mouseExitsGridTdEvent.subscribe () -> currentCell = null
         (element) -> currentCell? and f$.is '*', f$.closest currentCell, element
     pointerOutsideCell = (element) -> not pointerInsideCell element
+    isNextSeqNo = (element) ->
+        storeSeqNo = parseInt (f$.data 'seqNo', element)
+        (currentSeqNo element) == storeSeqNo + 1

     # Actions
     removeFor = (element) -> f$.removeAttr 'for', element                                                               # So on click on the label, the focus isn't set on the input on click
@@ -137,6 +149,7 @@
         f$.text '', editablePlaceholderContainer element
     createMock = editableDo 'createMock'
     removeMock = editableDo 'removeMock'
+    storeSeqNo = (element) -> f$.data 'seqNo', (currentSeqNo element), element
     startEdit = (element) ->
         f$.removeClass 'fb-label-hint-placeholder', element
         f$.removeClass 'xforms-disabled', element                                                                       # Remove disabled which we have on hint when their value is empty
@@ -154,17 +167,17 @@
     # Finite state machine description
     # Diagram: https://docs.google.com/a/orbeon.com/drawings/d/1cJ0B3Tl7QRTMkVUbtlA55C0TUvRiOt5hzR8-dc-aBrk/edit
     transitions = [
-        { from: [ 'initial' ],                  events: [ mouseEntersGridTd ],      elements: elementsInContainer,  conditions: [ isEmpty ],                        to: 'placeholder',              actions: [ removeFor, createMock, showPlaceholder ]  }
-        { from: [ 'initial' ],                  events: [ mouseEntersGridTd ],      elements: elementsInContainer,  conditions: [ isNonEmpty ],                     to: 'mock',                     actions: [ removeFor, createMock ]                   }
-        { from: [ 'mock' ],                     events: [ mouseExistsGridTd ],      elements: elementsInContainer,                                                  to: 'initial',                  actions: [ removeMock ]                              }
-        { from: [ 'placeholder' ],              events: [ mouseExistsGridTd ],      elements: elementsInContainer,                                                  to: 'initial',                  actions: [ hidePlaceholder, removeMock  ]            }
-        { from: [ 'placeholder', 'mock' ],      events: [ click ],                  elements: elementClosest,                                                       to: 'wait-xhr-to-edit'                                                               }
-        { from: [ 'wait-xhr-to-edit' ],         events: [ ajaxResponse ],           elements: elementsAll,                                                          to: 'edit',                     actions: [ startEdit ]                               }
-        { from: [ 'edit' ],                     events: [ enterKey, lostFocus ],    elements: elementClosest,                                                       to: 'edit-done',                actions: [ endEdit, removeMock, fireEditDone ]       }
-        { from: [ 'edit-done' ],                events: [ editDone ],               elements: elementsAll,          conditions: [ pointerOutsideCell ],             to: 'initial'                                                                        }
-        { from: [ 'edit-done' ],                events: [ editDone ],               elements: elementsAll,          conditions: [ pointerInsideCell, isEmpty ],     to: 'placeholder-after-edit',   actions: [ createMock, showPlaceholder ]             }
-        { from: [ 'edit-done' ],                events: [ editDone ],               elements: elementsAll,          conditions: [ pointerInsideCell, isNonEmpty ],  to: 'mock',                     actions: [ createMock ]                              }
-        { from: [ 'placeholder-after-edit' ],   events: [ ajaxResponse ],           elements: elementsAll,                                                          to: 'placeholder',              actions: [ showPlaceholder ]                         }
+        { events: [ mouseEntersGridTd ],      elements: elementsInContainer,  from: [ 'initial' ],                  conditions: [ isEmpty ],                        to: 'placeholder',              actions: [ removeFor, createMock, showPlaceholder ]  }
+        { events: [ mouseEntersGridTd ],      elements: elementsInContainer,  from: [ 'initial' ],                  conditions: [ isNonEmpty ],                     to: 'mock',                     actions: [ removeFor, createMock ]                   }
+        { events: [ mouseExistsGridTd ],      elements: elementsInContainer,  from: [ 'mock' ],                                                                     to: 'initial',                  actions: [ removeMock ]                              }
+        { events: [ mouseExistsGridTd ],      elements: elementsInContainer,  from: [ 'placeholder' ],                                                              to: 'initial',                  actions: [ hidePlaceholder, removeMock  ]            }
+        { events: [ click ],                  elements: elementClosest,       from: [ 'placeholder', 'mock' ],                                                      to: 'wait-xhr-to-edit',         actions: [ storeSeqNo ]                              }
+        { events: [ ajaxResponse ],           elements: elementsAll,          from: [ 'wait-xhr-to-edit' ],         conditions: [ isNextSeqNo ],                    to: 'edit',                     actions: [ startEdit ]                               }
+        { events: [ enterKey, lostFocus ],    elements: elementClosest,       from: [ 'edit' ],                                                                     to: 'edit-done',                actions: [ endEdit, removeMock, fireEditDone ]       }
+        { events: [ editDone ],               elements: elementsAll,          from: [ 'edit-done' ],                conditions: [ pointerOutsideCell ],             to: 'initial'                                                                        }
+        { events: [ editDone ],               elements: elementsAll,          from: [ 'edit-done' ],                conditions: [ pointerInsideCell, isEmpty ],     to: 'placeholder-after-edit',   actions: [ storeSeqNo, createMock, showPlaceholder ] }
+        { events: [ editDone ],               elements: elementsAll,          from: [ 'edit-done' ],                conditions: [ pointerInsideCell, isNonEmpty ],  to: 'mock',                     actions: [ createMock ]                              }
+        { events: [ ajaxResponse ],           elements: elementsAll,          from: [ 'placeholder-after-edit' ],   conditions: [ isNextSeqNo ],                    to: 'placeholder',              actions: [ showPlaceholder ]                         }
     ]

     # Finite state machine runner
@@ -172,10 +185,10 @@
         _.each transition.events, (event) ->
             event (event) ->
                 elements = transition.elements event                                                                    # Get elements from event (e.g. editable inside cell for mouseover)
+                elements = _.filter elements, (e) -> matchState transition.from, $ e                                    # Filter elements that are in the 'from' state
                 if transition.conditions                                                                                # Filter elements that match all the conditions
                     elements = _.filter elements, (e) ->
                         _.all transition.conditions, (c) -> c $ e
-                elements = _.filter elements, (e) -> matchState transition.from, $ e                                    # Filter elements that are in the 'from' state
                 _.each elements, (element) ->
                     f$.data 'state', transition.to, $ element                                                           # Change state before running action, so if action trigger an event, that event runs against the new state
                     _.each transition.actions, (action) -> action $ element                                             # Run all the actions on the elements


hidden logo fix.

hidden logo fix.

--- client/landing/app/MainApp/maincontroller/mainview.coffee
+++ client/landing/app/MainApp/maincontroller/mainview.coffee
@@ -89,7 +89,7 @@
     @header.addSubView @logo = new KDCustomHTMLView
       tagName   : "a"
       domId     : "koding-logo"
-      cssClass  : "hidden"
+      # cssClass  : "hidden"
       attributes:
         href    : "#"
       click     : (pubInst,event)=>
@@ -155,14 +155,14 @@
       $('body').addClass "loggedIn"
       @mainTabView.showHandleContainer()
       @contentPanel.setClass "social"
-      @logo.show()
+      # @logo.show()
       @buttonHolder.hide()
     else
       $('body').removeClass "loggedIn"
       @contentPanel.unsetClass "social"
       @mainTabView.hideHandleContainer()
       @buttonHolder.show()
-      @logo.hide()
+      # @logo.hide()

     @changeHomeLayout isLoggedIn
     @utils.wait 300, => @notifyResizeListeners()


activity: deprecate `NewCommentForm::otherCommentInputReceivedFocus` method

--- client/Social/Activity/views/comments/newcommentform.coffee
+++ client/Social/Activity/views/comments/newcommentform.coffee
@@ -59,13 +59,6 @@
     (KD.getSingleton "windowController").setKeyView @input

-  otherCommentInputReceivedFocus:(instance) ->
-
-    if instance isnt @input
-      commentForm = @input.getDelegate()
-      commentForm.resetCommentField() if $.trim(@input.getValue()) is ""
-
-
   commentInputReceivedBlur: ->

     @resetCommentField()  if @input.getValue() is ""


Teamwork: Chat item names are separated into a new method.

--- client/landing/CollaborativeWorkspace/panes/chatitem.coffee
+++ client/landing/CollaborativeWorkspace/panes/chatitem.coffee
@@ -16,7 +16,7 @@

     @messageList.addSubView @header = new KDCustomHTMLView
       cssClass   : "username"
-      partial    : if ownMessage then "Me" else "#{user.nickname}"
+      partial    : if ownMessage then "Me" else @getUsername()

     @header.addSubView @timeAgo = new KDTimeAgoView
       cssClass   : "time-ago"
@@ -27,6 +27,9 @@
       partial    : Encoder.XSSEncode @getOptions().body

     @setClass "mine" if ownMessage
+
+  getUsername: ->
+    return "#{@getOptions().user.nickname}"

   createAvatar: ->
     @avatar      = new AvatarView


S88792: Remove toggle: S78545_ENABLE_BUFFERED_RENDERER_FOR_PI_PAGE

--- test/spec/portfolioitemstreegrid/PortfolioItemsTreeGridAppSpec.coffee
+++ test/spec/portfolioitemstreegrid/PortfolioItemsTreeGridAppSpec.coffee
@@ -5,7 +5,7 @@
 describe 'Rally.apps.portfolioitemstreegrid.PortfolioItemsTreeGridApp', ->

   helpers
-    createApp: (enableToggles) ->
+    createApp: () ->
       context = Ext.create 'Rally.app.Context',
         initialValues:
           project: Rally.environment.getContext().getProject()
@@ -13,15 +13,12 @@
           user: Rally.environment.getContext().getUser()
           subscription: Rally.environment.getContext().getSubscription()

-      context.isFeatureEnabled = -> enableToggles
-      Rally.app.GridBoardApp.bufferedRendererEnabled = enableToggles
-
       Ext.create 'Rally.apps.portfolioitemstreegrid.PortfolioItemsTreeGridApp',
         context: context
         renderTo: 'testDiv'

-    renderApp: (enableToggles = true) ->
-      @app = @createApp(enableToggles)
+    renderApp: () ->
+      @app = @createApp()
       @waitForComponentReady @app

   beforeEach ->
@@ -29,7 +26,6 @@
     @piHelper.stubPortfolioItemRequests()

   afterEach ->
-    delete Rally.app.GridBoardApp.bufferedRendererEnabled
     _.invoke Ext.ComponentQuery.query('portfoliotemstreegridapp'), 'destroy'

   it 'should initialize', ->
@@ -48,14 +44,6 @@
       expect(_.intersection(storeTypes, piTypes)).toEqual piTypes

   describe '#getGridConfig', ->
-    it 'should return bufferedRenderer true when feature toggle enabled', ->
-      @renderApp(true).then =>
-        expect(@app.getGridConfig().bufferedRenderer).toBe true
-
-    it 'should return bufferedRenderer false when feature toggle disabled', ->
-      @renderApp(false).then =>
-        expect(@app.getGridConfig().bufferedRenderer).toBe false
-
     it 'should enable inline', ->
       @renderApp().then =>
         expect(@app.getGridConfig().enableInlineAdd).toBe true


[Ban User] Added block user button to admin modal

--- client/landing/app/MainApp/sidebar/modals/adminmodal.coffee
+++ client/landing/app/MainApp/sidebar/modals/adminmodal.coffee
@@ -44,8 +44,22 @@
               Flags           :
                 label         : "Flags"
                 placeholder   : "no flags assigned"
+              BlockUser       :
+                label         : "Block User"
+                itemClass     : KDButtonView
+                title         : "Block"
+                callback      : =>
+                  accounts = @userController.getSelectedItemData()
+                  if accounts.length > 0
+                    console.log accounts[0]
+                    activityController = KD.getSingleton('activityController')
+                    activityController.emit "ActivityItemBlockUserClicked", accounts[0].profile.nickname
+                    console.log "hede"
+                  else
+                    console.log accounts
+
               Impersonate     :
-                label         : "Switch to User"
+                label         : "Switch to User "
                 itemClass     : KDButtonView
                 title         : "Impersonate"
                 callback      : =>
@@ -238,12 +252,14 @@
     fields.Impersonate.hide()
     buttons.Update.hide()
     fields.Flags.hide()
+    fields.Block.hide()
     inputs.Flags.setValue ''

   showConnectedFields:->
     {fields, inputs, buttons} = @modalTabs.forms["User Details"]
     fields.Impersonate.show()
     fields.Flags.show()
+    fields.Block.show()
     buttons.Update.show()

   initIntroductionTab: ->


Moved the hiding of the box to a separate method, call whenever a model is added to the list of evidence

--- core/app/backbone/views/evidence/add_evidence_view.coffee
+++ core/app/backbone/views/evidence/add_evidence_view.coffee
@@ -43,15 +43,18 @@

   collectionEvents:
     'saved_added_model': 'cancel'
+    'add': 'hideBox'

   onRender: ->
     @headingRegion.show new EvidenceishHeadingView model: currentUser
     @cancel()

   cancel: ->
-    @ui.box.hide()
+    @hideBox()
     @buttonsRegion.show new AddEvidenceButtonsView
       parentView: this
+
+  hideBox: -> @ui.box.hide()

   showAdd: (type) ->
     @buttonsRegion.close()


fixes dropdown tests

fixes dropdown tests

--- components/filter2/dropdown/test/view.coffee
+++ components/filter2/dropdown/test/view.coffee
@@ -35,6 +35,6 @@
     @view.$('.filter-nav-main-text').text().should.equal 'Price'
     @view.$('.filter-nav-active-text').text().should.equal ''
     @view.$('.filter-dropdown-nav > a').first().text().should.equal 'All Prices'
-    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-text').text().should.equal 'for Sale'
-    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-count').text().should.equal '(5,647)'
+    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-text').text().should.equal 'Under $1,000'
+    @view.$('.filter-dropdown-nav > a:nth-child(2) .filter-dropdown-count').text().should.equal '(535)'


Books is an array, method to get 'em all

--- src/flux/ecosystems.coffee
+++ src/flux/ecosystems.coffee
@@ -32,8 +32,8 @@
     isLoading: -> @_asyncStatus is LOADING
     isFailed:  -> @_asyncStatus is FAILED

-    all: ->
-      @_ecosystems
+    allBooks: ->
+      _.flatten _.pluck(@_ecosystems, 'books')

     getBook: (attrs) ->
       _.findWhere(@_ecosystems, attrs)


Removed unused function

Removed unused function

--- core/app/backbone/factlink/collection.coffee
+++ core/app/backbone/factlink/collection.coffee
@@ -11,9 +11,3 @@
   loading: -> @_loading

   fetchIfUnloaded: (options) -> @_started_loading_once || @fetch options
-
-Marionette.View.prototype.whenFactlinkCollectionFetched = (model, callback) ->
-  if model.loading()
-    @listenToOnce model, 'sync', callback
-  else
-    callback.call(this)


Simplify tooltip_jq: allow only one target per call

--- core/app/backbone/factlink/tooltip_jq.coffee
+++ core/app/backbone/factlink/tooltip_jq.coffee
@@ -9,51 +9,42 @@
     align: 'center'
     closingtimeout: 300

-    #$el: owner
-    #selector: what to hover over
-    #mkTooltip: $target -> $tooltipEl
-    #rmTooltip: $target, $tooltipEl ->
+    #$target: owner
+    #mkTooltip: $target -> $tooltip
+    #rmTooltip: $target, $tooltip ->

   hoverStateByEvent =
     mouseenter: true
     mouseleave: false

-  # I need to track info per-tooltip, e.g. to avoid
-  # reopening an open tooltip
-  # solution: a page-global tooltip counter providing ids.
-  ttNextId = 0

   Backbone.Factlink.TooltipJQ = (cfg) ->
+    $target = cfg.$target
+    inTarget = inTooltip = showing = false
+    $tooltip = null
+    cfg = $.extend defaults, cfg

-    cfg = $.extend defaults, cfg
-    ttId = ttNextId++
-    ttIdStr = 'tooltipData-' + ttId
+    updateTooltip = ->
+      shouldShow = inTarget || inTooltip
+      if shouldShow && !showing then
+        showing = true
+        $tooltip = cfg.mkTooltip $target
+        $tooltip.hoverIntent
+          timeout: cfg.closingtimeout
+          over: hoverTooltip
+      else if showing && !shouldShow then
+        showing = false
+        $tooltip = null
+        cfg.rmTooltip $target, $tooltip

     hoverTarget = (e) ->
       console.log e
-      target = $(e.currentTarget)
-      ttData = target.data(ttIdStr) || {}
-      ttData.inTarget = hoverStateByEvent[e.type]
-
-      shouldShow = ttData.inTarget || ttData.inTooltip
-
-      if shouldShow && !ttData.showing then
-        ttData.showing = true
-        target.data(ttIdStr, ttData)
-        ttData.$tooltipEl = cfg.mkTooltip $(e.target)
-        cfg.$el.hoverIntent
-          timeout: cfg.closingtimeout
-          over: hoverTooltip
-
-      else if showing && !shouldShow then
-        ttData.showing = false
-        target.removeData(ttIdStr)
-        cfg.rmTooltip
+      inTarget = hoverStateByEvent[e.type]

     hoverTooltip = (e) ->
+      console.log e
+      inTooltip = hoverStateByEvent[e.type]

-
-    cfg.$el.hoverIntent
+    $target.hoverIntent
       timeout: cfg.closingtimeout
-      selector: cfg.selector
       over: hoverTarget