Add unit test for unlinked nodes

Add unit test for unlinked nodes

--- test/simulation-test.coffee
+++ test/simulation-test.coffee
@@ -104,28 +104,35 @@
     # node on each step.
     describe "for other scenarios", ->
       scenarios = [
-        # 0: cascade independent and dependent variables (A->B->C)
+        # 0: unlinked nodes should retain their initial values
+        {A: 0, B: 50, C: 100, D: "0+", E: "50+", F: "100+",
+        results: [
+          [0, 50, 100, 0, 50, 100]
+          [0, 50, 100, 0, 50, 100]
+        ]}
+
+        # 1: cascade independent and dependent variables (A->B->C)
         {A: 50, B: 40, C: 30, AB: "1 * in", BC: "0.1 * in",
         results: [
-            [50, 50, 5]
-            [50, 50, 5]
-        ]}
-
-        # 1: cascade independent and dependent variables with negative relationship (A->B->C)
+          [50, 50, 5]
+          [50, 50, 5]
+        ]}
+
+        # 2: cascade independent and dependent variables with negative relationship (A->B->C)
         {A: 50, B: 40, C: 30, AB: "0.1 * in", BC: "-1 * in",
         results: [
-            [50, 5, -5]
-            [50, 5, -5]
-        ]}
-
-        # 2: basic collector (A->[B])
+          [50, 5, -5]
+          [50, 5, -5]
+        ]}
+
+        # 3: basic collector (A->[B])
         {A:5, B:"50+", AB: "1 * in",
         results: [
           [5, 50.05]
           [5, 50.1]
         ]}

-        # 3: basic collector with feedback (A<->[B])
+        # 4: basic collector with feedback (A<->[B])
         {A:10, B:"50+", AB: "1 * in", BA: "1 * in",
         results: [
           [50, 50.5]
@@ -133,46 +140,46 @@
           [51.005, 51.51505]
         ]}

-        # 4: three-node graph (>-) with averaging
+        # 5: three-node graph (>-) with averaging
         {A: 10, B: 20, C: null, AC: "1 * in", BC: "1 * in",
         results: [
-            [10, 20, 15]
-            [10, 20, 15]
-        ]}
-
-        # 5: three-node graph (>-) with non-linear averaging
+          [10, 20, 15]
+          [10, 20, 15]
+        ]}
+
+        # 6: three-node graph (>-) with non-linear averaging
         {A: 10, B: 20, C: null, AC: "1 * in", BC: "0.1 * in",
         results: [
-            [10, 20, 6]
-            [10, 20, 6]
-        ]}
-
-        # 6: three-node graph with collector (>-[C])
+          [10, 20, 6]
+          [10, 20, 6]
+        ]}
+
+        # 7: three-node graph with collector (>-[C])
         {A: 10, B: 20, C: "0+", AC: "1 * in", BC: "0.1 * in",
         results: [
-            [10, 20, 0.12]
-            [10, 20, 0.24]
-        ]}
-
-        # 7: three-node graph with collector (>-[C]) and negative relationship
+          [10, 20, 0.12]
+          [10, 20, 0.24]
+        ]}
+
+        # 8: three-node graph with collector (>-[C]) and negative relationship
         {A: 10, B: 1, C: "0+", AC: "1 * in", BC: "-1 * in",
         results: [
-            [10, 1, 0.09]
-            [10, 1, 0.18]
-            [10, 1, 0.27]
-        ]}
-
-        # 8: four-node graph with collector (>-[D]) and scaled product combination
+          [10, 1, 0.09]
+          [10, 1, 0.18]
+          [10, 1, 0.27]
+        ]}
+
+        # 9: four-node graph with collector (>-[D]) and scaled product combination
         {A: 50, B: 50, C: 0, D: "0+", AC: "1 * in", BC: "1 * in", CD: "1 * in"
         results: [
-            [50, 50, 25, 0.25]
-            [50, 50, 25, 0.5]
+          [50, 50, 25, 0.25]
+          [50, 50, 25, 0.5]
         ]}

         # *** Tests for graphs with bounded ranges ***
         # Note all nodes have min:0 and max:100 by default

-        # 9: basic collector (A->[B])
+        # 10: basic collector (A->[B])
         {A:60, B:"99+", AB: "1 * in",
         cap: true
         results: [
@@ -181,7 +188,7 @@
           [60, 100]
         ]}

-        # 10: basic subtracting collector (A- -1 ->[B])
+        # 11: basic subtracting collector (A- -1 ->[B])
         {A:60, B:"1+", AB: "-1 * in",
         cap: true
         results: [
@@ -190,7 +197,7 @@
           [60, 0]
         ]}

-        # 11: basic independent and dependent nodes (A->B)
+        # 12: basic independent and dependent nodes (A->B)
         {A:120, B:0, AB: "1 * in",
         cap: true
         results: [


Clean up and annotate collection

Clean up and annotate collection

--- collections/connection_blocks.coffee
+++ collections/connection_blocks.coffee
@@ -1,24 +1,27 @@
-#
 # Collection for a group of results in a connection search
-#

-UserBlocks = require("./user_blocks.coffee")
-sd = require("sharify").data
-_ = require 'underscore'
-Block = require("../models/block.coffee")
-params = require 'query-params'
+qs = require 'qs'
+{ API_URL } = require('sharify').data
+UserBlocks = require './user_blocks.coffee'

 module.exports = class ConnectionBlocks extends UserBlocks
   defaultOptions:
     page: 1
     per: 20

-  url: -> "#{sd.API_URL}/search/connection?#{params.encode(@options)}"
+  url: ->
+    "#{sd.API_URL}/search/connection?#{qs.stringify @options}"

   initialize: (models, options) ->
     super
     @slug = options.user_slug

   comparator: (model) ->
-    return 1 if model.get('marked')
-    return model.get('score')+    # For original connect component
+    # TODO: Remove this once component is retired
+    if model.get 'marked'
+      1
+
+    # When searched
+    else
+      model.get 'score'


Removed debugging statement

Removed debugging statement

--- src/myna.coffee
+++ src/myna.coffee
@@ -428,7 +428,6 @@
             if elem[evt.type]
               # If there's a method for this event, call it directly to retrigger the default action:
               myna.log(" - dom method", elem, evt.type)
-              window.elem = elem
               window.setTimeout(
                 () -> elem[evt.type]()
                 0


Styling on builder components

Styling on builder components

--- components/default-components.coffee
+++ components/default-components.coffee
@@ -13,6 +13,7 @@
             """

                 <rich-text>Text Message</rich-text>
+

             """
         popoverTemplate:
@@ -76,17 +77,18 @@
         template:
             """

-                {{label}}
-
-

-                    <input ng-if="!readOnly" type="email" ng-model="inputText" placeholder="Email" class="form-control custom-m-b" id="{{formName+index}}" validator-required="{{required}}" validator-group="{{formName}}">
-                    <input type="email" ng-if="requireConfirmation && !readOnly" ng-model="confirmEmail" placeholder="Confirm email" class="form-control custom-m-b" id="confirmEmail">
-                    <input ng-if="readOnly" type="email" ng-model="inputText" placeholder="Email" class="form-control custom-m-b" id="{{formName+index}}" validator-required="{{required}}" validator-group="{{formName}}" disabled>
-                    <input type="email" ng-if="requireConfirmation && readOnly" ng-model="confirmEmail" placeholder="Confirm email" class="form-control custom-m-b" id="confirmEmail" disabled>
-

+                  {{label}}
+
+

+                        <input ng-if="!readOnly" type="email" ng-model="inputText" placeholder="Email" class="form-control m-b" id="{{formName+index}}" validator-required="{{required}}" validator-group="{{formName}}">
+                        <input type="email" ng-if="requireConfirmation && !readOnly" ng-model="confirmEmail" placeholder="Confirm email" class="form-control m-b" id="confirmEmail">
+                        <input ng-if="readOnly" type="email" ng-model="inputText" placeholder="Email" class="form-control m-b" id="{{formName+index}}" validator-required="{{required}}" validator-group="{{formName}}" disabled>
+                        <input type="email" ng-if="requireConfirmation && readOnly" ng-model="confirmEmail" placeholder="Confirm email" class="form-control m-b" id="confirmEmail" disabled>
+

                   {{description}}

+

             """
         popoverTemplate:
@@ -171,16 +173,16 @@
         # maxDate: '2100-01-01'
         template:
             """
-

-
-                    {{label}}
-
-

+

+                  {{label}}
+
+

                     <ui-date weekends="{{disableWeekends}}"></ui-date>
-

+

                   {{description}}

+

             """
         popoverTemplate:
@@ -286,15 +288,16 @@
         template:
             """

-                    {{label}}
+                {{label}}

-

-                    <input type="text" ng-if="!readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control custom-m-b" placeholder="{{placeholder}}"/>
-                    <input type="text" ng-if="readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control custom-m-b" placeholder="{{placeholder}}" disabled/>
-

-

-                  {{description}}
-

+

+                    <input type="text" ng-if="!readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control m-b" placeholder="{{placeholder}}"/>
+                    <input type="text" ng-if="readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control m-b" placeholder="{{placeholder}}" disabled/>
+

+

+                {{description}}
+

+

             """
         popoverTemplate:
@@ -393,15 +396,16 @@
         template:
             """

-                    {{label}}
+                {{label}}

-

-                    <textarea type="text" ng-if="!readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control custom-m-b" rows='6' placeholder="{{placeholder}}"/>
-                    <textarea type="text" ng-if="readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control custom-m-b" rows='6' placeholder="{{placeholder}}" disabled/>
+

+                    <textarea type="text" ng-if="!readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control m-b" rows='6' placeholder="{{placeholder}}"/>
+                    <textarea type="text" ng-if="readOnly" ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}" class="form-control m-b" rows='6' placeholder="{{placeholder}}" disabled/>

                   {{description}}

+

             """
         popoverTemplate:
@@ -482,8 +486,9 @@
         template:
             """

-                {{label}}
-

+
+                {{label}}
+

                     <input type='hidden' ng-model="inputText" validator-required="{{required}}" validator-group="{{formName}}" id="{{formName+index}}"/>

                         <input ng-if="!readOnly" type='checkbox' ng-model="$parent.inputArray[$index]" value='item'/>
@@ -492,6 +497,7 @@

{{description}}

+

             """
         popoverTemplate:
@@ -572,8 +578,8 @@
         template:
             """

-                {{label}}
-

+                {{label}}
+

                         <input ng-if="!readOnly" name='{{formName+index}}' ng-model="$parent.inputText" validator-group="{{formName}}" value='{{item}}' id="{{formName+index}}" type='radio'/>
@@ -583,6 +589,7 @@

{{description}}

+

             """
         popoverTemplate:
@@ -669,22 +676,23 @@
         template:
             """

-                    {{label}}
+                    {{label}}

-

-                    <select ng-if="!multiple && !readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control custom-m-b"
+

+                    <select ng-if="!multiple && !readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control m-b"
                         ng-model="inputText" ng-init="inputText = options[0]"/>
-                    <select ng-if="!multiple && readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control custom-m-b"
+                    <select ng-if="!multiple && readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control m-b"
                         ng-model="inputText" ng-init="inputText = options[0]" disabled/>
-                    <select ng-if="multiple && !readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control custom-m-b"
+                    <select ng-if="multiple && !readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control m-b"
                         ng-model="inputText" multiple ng-init="inputText = options[0]"/>
-                    <select ng-if="multiple && readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control custom-m-b"
+                    <select ng-if="multiple && readOnly" ng-options="value for value in options" id="{{formName+index}}" class="form-control m-b"
                         ng-model="inputText" multiple ng-init="inputText = options[0]" disabled/>

                   {{description}}

+

             """
         popoverTemplate:
@@ -773,30 +781,31 @@
             template:
                 """

-                        {{label}}
+                        {{label}}

-

-                        <input type="text" ng-model="$parent.inputText.StreetName" class="form-control custom-m-b" placeholder="Street Name"/>
-                        <input type="text" ng-model="$parent.inputText.Number" class="form-control custom-m-b" placeholder="Number"/>
-                        <input type="text" ng-model="$parent.inputText.Letter" class="form-control custom-m-b" placeholder="Letter"/>
-                        <input type="text" ng-model="$parent.inputText.Floor" class="form-control custom-m-b" placeholder="Floor"/>
-                        <input type="text" ng-model="$parent.inputText.PlaceName" class="form-control custom-m-b" placeholder="Place Name"/>
-                        <input type="text" ng-model="$parent.inputText.PostCode" class="form-control custom-m-b" placeholder="Post Code"/>
-                        <input type="text" ng-model="$parent.inputText.City" id="{{formName+index}}" class="form-control custom-m-b" placeholder="City" validator-required={{required}} validator-group={{formName}}/>
-

-

-                        <input type="text" ng-model="$parent.inputText.StreetName" class="form-control custom-m-b" placeholder="Street Name" disabled/>
-                        <input type="text" ng-model="$parent.inputText.Number" class="form-control custom-m-b" placeholder="Number" disabled/>
-                        <input type="text" ng-model="$parent.inputText.Letter" class="form-control custom-m-b" placeholder="Letter" disabled/>
-                        <input type="text" ng-model="$parent.inputText.Floor" class="form-control custom-m-b" placeholder="Floor" disabled/>
-                        <input type="text" ng-model="$parent.inputText.PlaceName" class="form-control custom-m-b" placeholder="Place Name" disabled/>
-                        <input type="text" ng-model="$parent.inputText.PostCode" class="form-control custom-m-b" placeholder="Post Code" disabled/>
-                        <input type="text" ng-model="$parent.inputText.City" id="{{formName+index}}" class="form-control custom-m-b" placeholder="City" validator-required={{required}} validator-group={{formName}} disabled/>
+

+                        <input type="text" ng-model="$parent.inputText.StreetName" class="form-control m-b" placeholder="Street Name"/>
+                        <input type="text" ng-model="$parent.inputText.Number" class="form-control m-b" placeholder="Number"/>
+                        <input type="text" ng-model="$parent.inputText.Letter" class="form-control m-b" placeholder="Letter"/>
+                        <input type="text" ng-model="$parent.inputText.Floor" class="form-control m-b" placeholder="Floor"/>
+                        <input type="text" ng-model="$parent.inputText.PlaceName" class="form-control m-b" placeholder="Place Name"/>
+                        <input type="text" ng-model="$parent.inputText.PostCode" class="form-control m-b" placeholder="Post Code"/>
+                        <input type="text" ng-model="$parent.inputText.City" id="{{formName+index}}" class="form-control m-b" placeholder="City" validator-required={{required}} validator-group={{formName}}/>
+

+

+                        <input type="text" ng-model="$parent.inputText.StreetName" class="form-control m-b" placeholder="Street Name" disabled/>
+                        <input type="text" ng-model="$parent.inputText.Number" class="form-control m-b" placeholder="Number" disabled/>
+                        <input type="text" ng-model="$parent.inputText.Letter" class="form-control m-b" placeholder="Letter" disabled/>
+                        <input type="text" ng-model="$parent.inputText.Floor" class="form-control m-b" placeholder="Floor" disabled/>
+                        <input type="text" ng-model="$parent.inputText.PlaceName" class="form-control m-b" placeholder="Place Name" disabled/>
+                        <input type="text" ng-model="$parent.inputText.PostCode" class="form-control m-b" placeholder="Post Code" disabled/>
+                        <input type="text" ng-model="$parent.inputText.City" id="{{formName+index}}" class="form-control m-b" placeholder="City" validator-required={{required}} validator-group={{formName}} disabled/>

                         {{description}}

+

                 """
             popoverTemplate:
@@ -876,15 +885,16 @@
                 template:
                     """

-                            {{label}}
+                            {{label}}

-

-                            <input ng-if="!readOnly" type="file" class="custom-m-b" accept="image/*" capture="camera" id="{{formName+index}}">
-                            <input ng-if="readOnly" type="file" class="custom-m-b" accept="image/*" capture="camera" id="{{formName+index}}" disabled>
+

+                            <input ng-if="!readOnly" type="file" class="m-b" accept="image/*" capture="camera" id="{{formName+index}}">
+                            <input ng-if="readOnly" type="file" class="m-b" accept="image/*" capture="camera" id="{{formName+index}}" disabled>

                             {{description}}

+

                     """
                 popoverTemplate:
@@ -962,16 +972,17 @@
                 template:
                     """

-                            {{label}}
+                            {{label}}

-

-

+

+

                                 <signature-pad></signature-pad>

+

                     """
                 popoverTemplate:
@@ -1007,7 +1018,7 @@

-                                            <input type='checkbox' ng-model="required" />
+                                            <input type='checkbox' ng-model="required"/>
                                             Required


Reset lasttimestampg

Reset lasttimestampg

--- SingularityUI/app/collections/LogLines.coffee
+++ SingularityUI/app/collections/LogLines.coffee
@@ -174,6 +174,7 @@
             lines = _.initial lines

         # create the objects for LogLine models
+        @lastTimestamp = null
         res = lines.map (data) =>
           # Try builtin ISO 8601 timetamp strings
           tryTimestamp = moment data


fix unclear naming

fix unclear naming

--- src/mkts-table.coffee
+++ src/mkts-table.coffee
@@ -175,7 +175,7 @@
   unless value in [ 'top', 'bottom', 'center', 'spread', ]
     throw new Error "(MKTS/TABLE µ1876) expected one of 'top', 'bottom', 'center', 'spread' for mkts-table/fieldalignvertical, got #{rpr value}"
   #.........................................................................................................
-  for [ fail, field_designation, ] from @_walk_f_field_designations_from_hints me, fieldhints
+  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_hints me, fieldhints
     ### TAINT ad-hoc fail message production, use method ###
     if fail? then _record me, "#{fail} (#{jr {field_designation}})"
     else          me.valigns[ field_designation ] = value
@@ -371,7 +371,7 @@
   designations, and later occurrences of a given field will replace earlier appearances. ###
   R = {}
   for [ fieldhints, stuff..., ] in fieldhints_and_stuff
-    for [ fail, field_designation, ] from @_walk_f_field_designations_from_hints me, fieldhints
+    for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_hints me, fieldhints
       if fail? then _record me, fail
       else          R[ field_designation ]  = stuff
   yield [ field_designation, stuff..., ] for field_designation, stuff of R
@@ -620,7 +620,7 @@
 #===========================================================================================================
 # ITERATORS
 #-----------------------------------------------------------------------------------------------------------
-@_walk_f_field_designations_from_hints = ( me, fieldhints ) ->
+@_walk_fails_and_field_designations_from_hints = ( me, fieldhints ) ->
   ### TAINT this will have to be changed to allow for named fields ###
   count           = 0
   fieldhints_set  = new Set ( _.trim() for _ in fieldhints.split ',' )


fix: :bug: bind variable that is used as storage for transcription to instance of transcription class

--- src/javascripts/extensions/transcript.coffee
+++ src/javascripts/extensions/transcript.coffee
@@ -25,6 +25,9 @@
     return unless @app.episode
     return unless @app.episode.transcript

+    @data =
+      transcript: ""
+
     @transcript = @app.episode.transcript

     @search = new Search(@app)
@@ -41,9 +44,6 @@

   transcriptFileFormat: ->
     _.last(@transcript.split('.'))
-
-  data:
-    transcript: ''

   load: =>
     promise = @app.externalData.get(@transcript)
@@ -122,7 +122,7 @@
     raw.transcription.map (segment) =>
       data =
         time: Utils.secondsToHHMMSS(segment.start)
-        timestamp: segment.start.toString()
+        timestamp: segment.start?.toString()
         speaker: segment.speaker
         text: segment.text
       @renderLine(data)


repo#sync default

repo#sync default

--- src/repo.coffee
+++ src/repo.coffee
@@ -248,6 +248,7 @@
   # callback - Receives `(err)`.
   #
   sync: (branch, callback) ->
+    [callback, branch] = [branch, []] if !callback
     @git "stash", {}, ["save"], (err) =>
       return callback err if err
       @git "pull", {}, branch, (err) =>


Add sanity-checking for load mechanism

Add sanity-checking for load mechanism

--- src/save.coffee
+++ src/save.coffee
@@ -7,6 +7,8 @@
          .onValue((state) -> window.localStorage['WRECK_SAVE'] = JSON.stringify(state))

 Save.load.onValue ->
+  value = window.localStorage['WRECK_SAVE']
+  return unless value?
   GameState.start JSON.parse(window.localStorage['WRECK_SAVE'])

 $ ->


subparse doesn't throw errors, it just returns null if it failed

--- src/babel_bridge/parser.coffee
+++ src/babel_bridge/parser.coffee
@@ -92,11 +92,14 @@
   OUT: a Node with offset and matchLength
   ###
   subParse: (subSource, options = {}) ->
-    if p = @class.parse subSource, options
-      p.offset = options.originalOffset
-      p.matchLength = options.originalMatchLength
-      p._parent = options.parentNode
-      p
+    try
+      if p = @class.parse subSource, options
+        p.offset = options.originalOffset
+        p.matchLength = options.originalMatchLength
+        p._parent = options.parentNode
+        p
+    catch
+      null

   ###
   OUT: on success, root Node of the parse tree, else null


Improve error messages

Improve error messages

--- src/sync.coffee
+++ src/sync.coffee
@@ -139,7 +139,7 @@
         (err) =>
             if err?.code is 'ENOSPC'
                 log.error err
-                callback new Error 'The file system is full!'
+                callback new Error 'The disk space on your computer is full!'
             else if err
                 log.error err
                 change.doc.errors or= 0
@@ -151,7 +151,9 @@
                             else
                                 @remote.couch.whenAvailable callback
                     else if full
-                        callback new Error 'The Cozy is full!'
+                        callback new Error 'Your Cozy is full! ' +
+                            'You can delete some files to be able' +
+                            'to add new ones or upgrade your storage plan.'
                     else
                         @updateErrors change, callback
             else


Fix callback thunking

Fix callback thunking

--- src/teak.coffee
+++ src/teak.coffee
@@ -147,7 +147,7 @@
     if typeof(callback) == "function"
       callback(carrotResonse, fbResponse)
     else if typeof(callback) == "string" && @getSwf()
-      swfCallback(carrotResponse, fbResponse, callback)
+      @swfCallback(carrotResponse, fbResponse, callback)

   canMakeFeedPost: (objectInstanceId, callback) ->
     params = {
@@ -155,7 +155,7 @@
     }
     @postSignedRequest("/me/can_post.json", params, (jqXHR) =>
       carrotResponse = $.parseJSON(jqXHR.responseText)
-      @uiCallbackHandler(carrotResponse.code == 200)
+      @uiCallbackHandler(callback, carrotResponse.code == 200)
     )

   popupFeedPost: (objectInstanceId, objectProperties, callback, postMethod) ->
@@ -183,10 +183,10 @@
             if fbResponse and fbResponse.post_id
               @ajaxPost("#{@scheme}://parsnip.gocarrot.com/feed_dialog_post", {platform_id: carrotResponse.post_id})

-            @uiCallbackHandler(carrotResponse, fbResponse)
+            @uiCallbackHandler(callback, carrotResponse, fbResponse)
         )
       else
-        @uiCallbackHandler(carrotResponse)
+        @uiCallbackHandler(callback, carrotResponse)

   reportNotificationClick: (notifId, callback) ->
     @ajaxPost("#{@scheme}://parsnip.gocarrot.com/notification_click", {user_id: @udid, platform_id: notifId})
@@ -197,7 +197,7 @@
         response = $.parseJSON(jqXHR.responseText).response;
         if response.cascade && response.cascade.method == "sendRequest"
           @sendRequest(response.cascade.arguments.request_id, response.cascade.arguments.opts)
-        @uiCallbackHandler(response)
+        @uiCallbackHandler(callback, response)
     )

   # Available opts: object_type, object_id, object_properties, filters, suggestions, exclude_ids, max_recipients, data
@@ -234,10 +234,10 @@
               for receivingUser in fbResponse.to
                 @ajaxPost("#{@scheme}://parsnip.gocarrot.com/request_send", {platform_id: carrotResponse.request_id, posting_user_id: @udid, user_id: receivingUser})

-            @uiCallbackHandler(carrotResponse, fbResponse)
+            @uiCallbackHandler(callback, carrotResponse, fbResponse)
         )
       else
-        @uiCallbackHandler(carrotResponse)
+        @uiCallbackHandler(callback, carrotResponse)

   acceptRequest: (requestId, callback) ->
@@ -246,7 +246,7 @@
         response = $.parseJSON(jqXHR.responseText).response;
         if response.cascade && response.cascade.method == "sendRequest"
           @sendRequest(response.cascade.arguments.request_id, response.cascade.arguments.opts)
-        @uiCallbackHandler(response)
+        @uiCallbackHandler(callback, response)
     )

   getSignedRequest: (endpoint, query_params, callback) ->


Default windowState to empty hash JSON string

--- src/browser/atom-window.coffee
+++ src/browser/atom-window.coffee
@@ -30,7 +30,7 @@
     @handleEvents()

     loadSettings = _.extend({}, settings)
-    loadSettings.windowState ?= ''
+    loadSettings.windowState ?= '{}'

     # Only send to the first non-spec window created
     if @constructor.includeShellLoadTime and not @isSpec


Prevent GPU throttling for hidden test windows

--- src/browser/atom-window.coffee
+++ src/browser/atom-window.coffee
@@ -29,6 +29,10 @@
       'web-preferences':
         'direct-write': true
         'subpixel-font-scaling': false
+
+    if @isSpec
+      options['web-preferences']['page-visibility'] = true
+
     # Don't set icon on Windows so the exe's ico will be used as window and
     # taskbar's icon. See https://github.com/atom/atom/issues/4811 for more.
     if process.platform is 'linux'


- Added interface functions for communicating with UI.

--- src/coffee/eyejs-chrome.coffee
+++ src/coffee/eyejs-chrome.coffee
@@ -2,3 +2,35 @@
 EyeJS = require '/Users/josh/work/eyejs'

 eyejs = new EyeJS()
+
+getStatus = ->
+  return {
+    enabled: eyejs.enabled
+    size: eyejs.indicator.size
+    opacity: eyejs.indicator.opacity()
+  }
+
+
+if chrome?
+
+  chrome.runtime.onMessage.addListener (request, sender, sendResponse) ->
+
+    switch request.msg
+      when 'eyejs:enable'
+        eyejs.enable()
+
+      when 'eyejs:disable'
+        eyejs.disable()
+
+      when 'eyejs:getstatus' then null
+
+      when 'eyejs:resize'
+        eyejs.indicator.resize +request.val
+
+      when 'eyejs:setopacity'
+        eyejs.indicator.opacity +request.val
+
+      when 'eyejs:calibrate'
+        eyejs.calibrate()
+
+    sendResponse getStatus()


Fix paste and match style keyboard command in Safari

--- src/trix/controllers/input_controller.coffee
+++ src/trix/controllers/input_controller.coffee
@@ -74,6 +74,7 @@
       return if @isMobileInputModeEnabled()
       return if (event.metaKey or event.ctrlKey) and not event.altKey
       return if keypressEventIsWebInspectorShortcut(event)
+      return if keypressEventIsPasteAndMatchStyleShortcut(event)

       if event.which is null
         character = String.fromCharCode event.keyCode
@@ -234,3 +235,6 @@

 keypressEventIsWebInspectorShortcut = (event) ->
   event.metaKey and event.altKey and not event.shiftKey and event.keyCode is 94
+
+keypressEventIsPasteAndMatchStyleShortcut = (event) ->
+  event.metaKey and event.altKey and event.shiftKey and event.keyCode is 9674


Remove "resize board" code

Remove "resize board" code

--- static/script/games/settlers/settlers.coffee
+++ static/script/games/settlers/settlers.coffee
@@ -613,31 +613,12 @@

   $(eid).html ''

-  # experimental - resize to fit to height...
-  resize_ratio = (window.screen.height - 20) / $('body').height()
-  if resize_ratio > 1.0
-    resize_ratio = false
-
-  __resize_piece = (piece_eid) ->
-    if not resize_ratio
-      return
-
-    l = $(piece_eid).css 'left'
-    t = $(piece_eid).css 'top'
-
-    $(piece_eid).css 'left', (parseFloat(l) * resize_ratio) + 'px'
-    $(piece_eid).css 'top', (parseFloat(t) * resize_ratio) + 'px'
-
-    $(piece_eid).css 'max-width', ($(piece_eid).width() * resize_ratio)
-    $(piece_eid).css 'max-height', ($(piece_eid).height() * resize_ratio)
-
   __add_field = (f) ->
     attrs =
       id:		'settlers_board_field_' + f.id
       class:		'settlers-board-piece settlers-board-field settlers-board-field-' + f.id + ' settlers-board-field-' + bs + '-' + map_resource_to_str[f.resource + 2]

     $(eid).append window.settlers.render_board_piece attrs
-    __resize_piece '#settlers_board_field_' + f.id

     if f.thief == true
       attrs =
@@ -645,7 +626,6 @@
         class:		'settlers-board-piece settlers-board-thief settlers-board-thief-' + bs + ' settlers-board-thief-' + f.id

       $(eid).append window.settlers.render_board_piece attrs
-      __resize_piece '#settlers_board_thief'

   __add_number = (f) ->
     attrs =
@@ -656,7 +636,6 @@
       attrs.class += ' settlers-board-number-active'

     $(eid).append window.settlers.render_board_piece attrs
-    __resize_piece '#settlers_board_number_' + f.id

     if (G.state == 13 or G.state == 15 or G.state == 19) and f.thief != true
       $('#' + attrs.id).click () ->
@@ -691,7 +670,6 @@
       attrs.class += ' settlers-board-path-active settlers-board-path-' + bs + '-free-' + map_pathid_to_position[p.id] + '-active'

     $(eid).append window.settlers.render_board_piece attrs
-    __resize_piece '#settlers_board_path_' + p.id

     if G.current_active_paths_map[p.id] == true
       if G.state == 1
@@ -767,7 +745,6 @@

     s = ''
     $(eid).append(s)
-    __resize_piece '#settlers_board_node_' + n.id

     if G.current_active_nodes_map[n.id] == true
       if G.state == 1
@@ -870,13 +847,11 @@
     classes = 'settlers-board-piece settlers-board-sea settlers-board-sea-' + (2 * p.id + 1) + ' settlers-board-port-' + map_resource_to_str[p.resource + 2] + '-' + p.clock + '-' + bs
     s = ''
     $(eid).append(s)
-    __resize_piece '#settlers_board_port_' + p.id

   __add_sea = (i) ->
     classes = 'settlers-board-piece settlers-board-sea settlers-board-sea-' + (2 * i) + ' settlers-board-sea-' + bs
     s = ''
     $(eid).append(s)
-    __resize_piece '#settlers_board_sea_' + i

   __add_field f for f in G.board.fields
   __add_number f for f in G.board.fields


force travisci to rerun

force travisci to rerun

--- test/cases/issues/shared/issue337Test.coffee
+++ test/cases/issues/shared/issue337Test.coffee
@@ -12,4 +12,4 @@
   test 'Tower.constant on global vs. namespaced models', ->
     assert.throws((-> Tower.constant('Issue337GlobalModel')), Error, "Constant 'Issue337GlobalModel' wasn't found")
     assert.equal 'App.Issue337NamespacedModel', Tower.constant('Issue337NamespacedModel').toString()
-###+###


Update sunrise stage 2

Update sunrise stage 2

--- src/lazerscripts/stage2.coffee
+++ src/lazerscripts/stage2.coffee
@@ -2,7 +2,7 @@
 { LazerScript } = require('src/lib/LazerScript')
 { Stage1BossLeaving, Stage1BossPopup, Stage1BossRocketStrike } = require('./stage1/stage1boss')
 { ScraperFlyer, Swirler, Shooter, Stalker } = require('./stage1/army_drone')
-{ Noon } = require('./stage1/sunrise')
+{ Noon, Morning } = require('./stage1/sunrise')
 JumpMine = require('./stage1/jump_mine').default
 PlayerClone = require('./stage1/player_clone').default
 HeliAttack = require('./stage1/heli_attack').default
@@ -128,6 +128,7 @@
         )
         drop: 'pool'
       )
+      @sunRise()
       @parallel(
         @attackWaves(
           @parallel(
@@ -219,7 +220,7 @@
   checkpointMidStage: (scenery, sunSkip) ->
     @sequence(
       @setScenery(scenery)
-      @sunRise(skipTo: sunSkip)
+      @async @runScript(Morning, { speed: 1 })
       @wait 2000
     )


Form: Call setData on constructor to populate form.

--- src/lib/components/Form.coffee
+++ src/lib/components/Form.coffee
@@ -36,6 +36,7 @@
     if buttons
       buttons.forEach (options) => @createButton options

+    @setData data

   createContainers: ->
     @inputsContainer  = new spark.core.View cssClass: 'input-container'


Don't update render attributes on layouts

--- src/lib/models/document.coffee
+++ src/lib/models/document.coffee
@@ -418,7 +418,7 @@
 	renderDocument: (opts,next) ->
 		# Prepare
 		file = @
-		[opts,next] = extractOptsAndCallback(opts,next)
+		[opts,next] = extractOptsAndCallback(opts, next)
 		{content,templateData} = opts
 		extension = @get('extensions')[0]
 		content ?= @get('body')
@@ -441,7 +441,7 @@
 	renderLayouts: (opts,next) ->
 		# Prepare
 		file = @
-		[opts,next] = extractOptsAndCallback(opts,next)
+		[opts,next] = extractOptsAndCallback(opts, next)
 		{content,templateData} = opts
 		content ?= @get('body')
 		templateData ?= {}
@@ -461,12 +461,12 @@
 				# templateData.document.metaMerged = extendr.extend({}, layout.getMeta().toJSON(), file.getMeta().toJSON())

 				# Render the layout with the templateData
-				layout.render {templateData}, (err,result) ->
-					return next(err,result)
+				layout.render {templateData,apply:false}, (err,result) ->
+					return next(err, result)

 			# We don't have a layout, nothing to do here
 			else
-				return next(null,content)
+				return next(null, content)

 	# Render
@@ -475,9 +475,10 @@
 	render: (opts={},next) ->
 		# Prepare
 		file = @
-		[opts,next] = extractOptsAndCallback(opts,next)
+		[opts,next] = extractOptsAndCallback(opts, next)
 		opts = extendr.clone(opts or {})
 		opts.actions ?= ['renderExtensions','renderDocument','renderLayouts']
+		opts.apply ?= true
 		contentRenderedWithoutLayouts = null
 		relativePath = @get('relativePath')

@@ -503,10 +504,15 @@
 				return next(err, opts.content, file)

 			# Apply
-			contentRendered = opts.content
-			contentRenderedWithoutLayouts ?= contentRendered
-			rendered = true
-			file.set({contentRendered, contentRenderedWithoutLayouts, rendered})
+			if opts.apply is true
+				# Attributes
+				contentRendered = opts.content
+				contentRenderedWithoutLayouts ?= contentRendered
+				rendered = true
+				file.set({contentRendered, contentRenderedWithoutLayouts, rendered})
+
+				# Log
+				file.log 'debug', "Rendering applied to: #{relativePath}"

 			# Log
 			file.log 'debug', "Rendering completed for: #{relativePath}"
@@ -520,8 +526,10 @@
 				file.renderExtensions opts, (err,result) ->
 					# Check
 					return complete(err)  if err
+
 					# Apply the result
 					opts.content = result
+
 					# Done
 					return complete()

@@ -531,9 +539,11 @@
 				file.renderDocument opts, (err,result) ->
 					# Check
 					return complete(err)  if err
+
 					# Apply the result
 					opts.content = result
 					contentRenderedWithoutLayouts = result
+
 					# Done
 					return complete()

@@ -543,8 +553,10 @@
 				file.renderLayouts opts, (err,result) ->
 					# Check
 					return complete(err)  if err
+
 					# Apply the result
 					opts.content = result
+
 					# Done
 					return complete()

@@ -566,7 +578,7 @@
 		file = @

 		# Fetch
-		opts.content   or= (@getContent() or '').toString('')
+		opts.content ?= (@getContent() or '').toString('')

 		# Adjust
 		CSON      = require('cson')  unless CSON


Actually, setting it to ERROR makes more sense.

--- src/util.coffee
+++ src/util.coffee
@@ -147,7 +147,7 @@

 root.DEBUG = 10
 root.ERROR = 1
-root.log_level ?= 0 # none at all, by default
+root.log_level ?= root.ERROR

 root.log = (level, msgs...) ->
   if level <= root.log_level


CredentialStoreController: send userInput credentials in a map

--- client/app/lib/providers/resourcestatemodal/controllers/credentialscontroller.coffee
+++ client/app/lib/providers/resourcestatemodal/controllers/credentialscontroller.coffee
@@ -126,13 +126,16 @@

     { provider, selectedItem, newData } = submissionData

-    return callback null, selectedItem  if selectedItem
+    kallback = (identifier) ->
+      callback null, { userInput: [ identifier ] }
+
+    return kallback selectedItem  if selectedItem

     helpers.createNewCredential provider, newData, (err, newCredential) =>
       return callback err.message  if err

       @credentialsPage.selectNewRequirements newCredential
-      callback null, newCredential.identifier
+      kallback newCredential.identifier

   checkVerificationResult: (identifier, response) ->


uniCS open all tabs now actually opens all tabs, not just 3

--- client/landing/app/Applications/Activity.kdapplication/views/codesharetabview.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/codesharetabview.coffee
@@ -8,9 +8,9 @@
   viewAppended:->

     @on "codeShare.openAllFiles",=>
-      for pane in @panes
+      for pane,i in @panes
         data=pane.getData()
-        fileName      = "localfile:/#{data.CodeShareItemTitle}"
+        fileName      = "localfile:/#{data.CodeShareItemTitle}_#{i}"
         file          = FSHelper.createFileFromPath fileName
         file.contents = Encoder.htmlDecode(data.CodeShareItemSource)
         file.syntax   = data.CodeShareItemType.syntax


Include setOwner in view (missing part of earlier commit)

--- src/view.coffee
+++ src/view.coffee
@@ -207,6 +207,9 @@

 		if propagate is true and @owner?.dispatch
 			@owner.dispatch(func, parameters)
+
+	setOwner: (@owner) ->
+		@owner

 	updateOutletFromDom: (name) ->
 		outlet = @outlets[name]


shotgun debugging

shotgun debugging

--- scripts/import_coppermine.coffee
+++ scripts/import_coppermine.coffee
@@ -93,6 +93,8 @@
     work.push convertSubcategories(categoryId, edegalAlbum) if categoryId
     work.push convertAlbums(categoryId, edegalAlbum) if categoryId
     work.push convertPictures(albumId, edegalAlbum) if albumId and not existingAlbum?
+    return null if _.isEmpty work
+
     Q.all(work).then ->
       setThumbnail edegalAlbum

@@ -127,4 +129,4 @@
 if require.main is module
   convertCoppermine().then ->
     process.exit()
-  .done()
+  .done()


remove debug statement

remove debug statement

--- src/coffee/client/text_field_handler.coffee
+++ src/coffee/client/text_field_handler.coffee
@@ -330,7 +330,6 @@
                 # now if it's too high, settle on 0
                 if desired_y < 0
                     desired_y = 0
-                console.log 'desired y', desired_y

                 $(container).scrollTop(nodeTop - desired_y)


Teamwork: Created new buttons container and modal button.

--- client/Teamwork/Views/teamworkworkspace.coffee
+++ client/Teamwork/Views/teamworkworkspace.coffee
@@ -8,6 +8,7 @@
     @avatars = {}

     @on "PanelCreated", (panel) =>
+      @createButtons panel
       @createRunButton panel  if playground

     @on "WorkspaceSyncedWithRemote", =>
@@ -57,6 +58,15 @@
         return unless userStatus
         @manageUserAvatars userStatus

+  createButtons: (panel) ->
+    panel.addSubView @buttonsContainer = new KDCustomHTMLView
+      cssClass : "tw-buttons-container"
+
+    @buttonsContainer.addSubView new KDButtonView
+      iconClass: "tw-cog"
+      iconOnly : yes
+      callback : => @getDelegate().showToolsModal panel, this
+
   displayBroadcastMessage: (options) ->
     super options


workflow : add breadcrump

workflow : add breadcrump

--- client/Main/payment/existingaccountworkflow.coffee
+++ client/Main/payment/existingaccountworkflow.coffee
@@ -37,6 +37,7 @@
   pistachio: ->
     """

+
sign in - payment info - place order

Sign in or create an account to proceed with your checkout

       {{> @loginForm}}
       or


Spectators: Remove team preview when battle starts.

--- client/app/js/collections/battle_collection.coffee
+++ client/app/js/collections/battle_collection.coffee
@@ -25,6 +25,9 @@

   _updateBattle: (battle, actions, wasAtBottom) =>
     view = battle.view
+    # TODO: Kind of hacky
+    $teamPreview = view.$('.battle_teams')
+    $teamPreview.remove()
     if actions.length == 0
       if wasAtBottom then view.chatView.scrollToBottom()
       return


Client: Activity: Updated  SidebarList renderChildren method to show first 10 item

--- client/app/lib/components/sidebarlist/index.coffee
+++ client/app/lib/components/sidebarlist/index.coffee
@@ -14,12 +14,13 @@

   renderChildren: ->

-    { itemComponent: Component, selectedId } = @props
+    { itemComponent: Component, selectedId, threads, previewCount } = @props

-    @props.threads.map (thread) ->
+    threads = threads.slice 0, previewCount
+
+    threads.map (thread) ->
       id = thread.getIn ['channel', 'id']
       <Component key={id} active={id is selectedId} thread={thread} />
-

   render: ->
     <div className={classnames 'SidebarList', @props.className}>


Fix scoreboard display

Fix scoreboard display

--- src/constants/cricket_ordered_points.coffee
+++ src/constants/cricket_ordered_points.coffee
@@ -1,3 +1,3 @@
-CricketOrderedPoints = [20, 19, 18, 17, 16, 15, 25]
+CricketOrderedPoints = ['20', '19', '18', '17', '16', '15', '25']

 module.exports = CricketOrderedPoints


Account for different encodings during submit

--- server/cron/submitSubmits.coffee
+++ server/cron/submitSubmits.coffee
@@ -1,3 +1,5 @@
+iconv = require('iconv-lite')
+
 import SubmitProcess from '../models/SubmitProcess'
 import Submit from '../models/submit'
 import User from '../models/user'
@@ -26,6 +28,20 @@

 TIMEOUT_BY_ATTEMPT = makeTimeouts()

+convert = (source, encoding) ->
+    if not source
+        return ""
+    buf = Buffer.from(source, "latin1")
+    return iconv.decode(buf, encoding)
+
+compareSources = (newSource, oldSource) ->
+    newEncoded = convert(newSource, "utf8")
+    for encoding in ["cp866", "cp1251", "utf8"]
+        oldEncoded = convert(oldSource, encoding)
+        if oldEncoded == newEncoded
+            return true
+    return false
+
 getLanguage = (lang) ->
     for l in LANGUAGES
         if lang == l[1]
@@ -36,7 +52,7 @@
     success = false

     onNewSubmit = (newSubmit) ->
-        if newSubmit.sourceRaw != submit.sourceRaw
+        if not compareSources(newSubmit.sourceRaw, submit.sourceRaw)
             return
         await Submit.remove({_id: submit._id})
         await SubmitProcess.remove({_id: submit._id})


Remove Scott and Robin from APCSP access request emails

--- server/middleware/contact.coffee
+++ server/middleware/contact.coffee
@@ -13,10 +13,6 @@
       email_id: sendwithus.templates.plain_text_email
       recipient:
         address: 'jane@codecombat.com'
-      cc:[
-        {address:'robin@codecombat.com'},
-        {address:'scott@codecombat.com'}
-      ]
       sender:
         address: config.mail.username
         reply_to: email


If received update is array, emit for each device.

--- unipi-update-manager.coffee
+++ unipi-update-manager.coffee
@@ -38,8 +38,15 @@
       return (message) =>
         @_base.debug "received update:", message
         try
-          json = JSON.parse message
-          @emit json.dev + json.circuit, json if json.dev? and json.circuit?
+          if (typeof message) isnt "object"
+            json = JSON.parse message
+          else
+            json = message
+          if Array.isArray(json)
+            for obj in json
+              @emit obj.dev + obj.circuit, obj if obj.dev? and obj.circuit?
+          else
+            @emit json.dev + json.circuit, json if json.dev? and json.circuit?
           @_lastError = ''
         catch error
           @_base.error "exception caught:", error.toString()
@@ -176,4 +183,4 @@
       ).catch((errorResult) =>
         @_base.error 'unable to get device status, exception caught: ',
           errorResult.error.toString()
-      )+      )


Remove type coercion hack

Remove type coercion hack

--- server/components/indicatorator/lib/range_applicator.coffee
+++ server/components/indicatorator/lib/range_applicator.coffee
@@ -18,7 +18,6 @@
   return outputRows

 calculateIndicatorText = (value, ranges) ->
-  value = value.replace(',', '')
   value = parseFloat(value)

   for range in ranges


Redundancy.

Redundancy.

--- services/web/app/coffee/infrastructure/ExpressLocals.coffee
+++ services/web/app/coffee/infrastructure/ExpressLocals.coffee
@@ -307,5 +307,5 @@
 			chatMessageBorderLightness : if isOl then "40%" else "70%"
 			chatMessageBgSaturation    : if isOl then "85%" else "60%"
 			chatMessageBgLightness     : if isOl then "40%" else "97%"
-			renderAnnouncements        : if isOl then false else true
-		next()
+			renderAnnouncements        : !isOl
+		next()


Update editor.js.coffee

Update editor.js.coffee

Make sure that all attributes are protected.

--- app/assets/javascripts/dante/editor.js.coffee
+++ app/assets/javascripts/dante/editor.js.coffee
@@ -1020,6 +1020,7 @@
         '__ALL__': ['class']
         a: ['href', 'title', 'target']
         img: ['src']
+        span: ['data-cid', 'data-userid', 'data-username', 'data-time', 'title']

       protocols:
         a: { href: ['http', 'https', 'mailto'] }


名前から検索でmodalを出さないように修正

名前から検索でmodalを出さないように修正

--- app/assets/javascripts/lib/searcher.js.coffee
+++ app/assets/javascripts/lib/searcher.js.coffee
@@ -15,7 +15,6 @@

   @search: (params, url) ->
     $("#error-area").hide()
-    $("#loading-modal").modal('show')

     params ?= {}
     params.ver = ver
@@ -36,6 +35,7 @@
       QueryLogs.add(query)
       return Bacon.once(QueryResult.create(as, detailCache[key]))

+    $("#loading-modal").modal('show')
     result = @search(query.params(), searchUrl)
     result.flatMap (data) ->
       as = _.map data.result, (d) -> Arcana.build(d)
@@ -65,6 +65,7 @@
       as = _.map targets, (c) -> Arcana.forCode(c)
       return Bacon.once(QueryResult.create(as))

+    $("#loading-modal").modal('show')
     params = {'codes': unknowns.join('/')}
     result = @search(params, codesUrl)
     result.flatMap (data) ->


Fix login prompt button shadows and outlines

--- app/assets/javascripts/login_prompt.js.coffee
+++ app/assets/javascripts/login_prompt.js.coffee
@@ -2,6 +2,7 @@
   if error == 'Unauthorized'
     $.fancybox.open
       href: '#js-login-prompt'
+      scrolling: 'visible' # for button outlines and shadows

 $('.js-login-confirm').click ->
   window.location = '/auth/facebook'


changed easing mode fixes #874

changed easing mode
fixes #874

--- app/assets/javascripts/pirates/game.js.coffee
+++ app/assets/javascripts/pirates/game.js.coffee
@@ -80,8 +80,8 @@

   $.extend($.easing, # just for a nicer visualization, from jQuery UI
     {
-      easeOutCubic: (x, t, b, c, d) ->
-        c*((t=t/d-1)*t*t + 1) + b
+      easeOutQuad: (x, t, b, c, d) ->
+        -c *(t/=d)*(t-2) + b
     }
   )

@@ -116,7 +116,7 @@
           },
           {
             duration: 1500
-            easing: 'easeOutCubic'
+            easing: 'easeOutQuad'
             complete: () ->
               hoveringSelection.remove()
               updateQueueSize()


Fix broken layout in Gradebook (SIS ID column)

Re-add SFU MOD, and adjust settings to make the SIS ID column work with
the new slickgrid/frozen column implementation.

It is now compatible with the 12/28/13 release by Instructure.

--- app/coffeescripts/gradebook2/Gradebook.coffee
+++ app/coffeescripts/gradebook2/Gradebook.coffee
@@ -53,7 +53,7 @@

     DISPLAY_PRECISION = 2

-    numberOfFrozenCols: 2
+    numberOfFrozenCols: 3 # SFU MOD - CANVAS-188 Add extra column for SIS ID

     constructor: (@options) ->
       @chunk_start = 0
@@ -881,8 +881,9 @@
         field: 'sis_id'
         width: 100
         cssClass: "meta-cell secondary_identifier_cell"
-        resizable: false
+        resizable: true
         sortable: true
+        formatter: @htmlContentFormatter
       }]
       # END SFU MOD

@@ -1010,7 +1011,9 @@
           bScore = -99999999999 if not bScore and bScore != 0
           if data.sortAsc then bScore - aScore else aScore - bScore
       @grid.onSort.subscribe (event, data) =>
-        propertyToSortBy = {display_name: 'sortable_name', secondary_identifier: 'secondary_identifier'}[data.sortCol.field]
+        # SFU MOD CANVAS-188 Make SIS ID column sortable
+        propertyToSortBy = {display_name: 'sortable_name', secondary_identifier: 'secondary_identifier', sis_id: 'sis_id'}[data.sortCol.field]
+        # END SFU MOD
         sortRowsBy (a, b) ->
           res = if a[propertyToSortBy] < b[propertyToSortBy] then -1
           else if a[propertyToSortBy] > b[propertyToSortBy] then 1


add missing res param in crawler/index

add missing res param in crawler/index

--- servers/lib/crawler/index.coffee
+++ servers/lib/crawler/index.coffee
@@ -127,7 +127,7 @@
   page   or = 1

-handleError = (err, content) ->
+handleError = (err, res, content) ->
   if err
     console.error err

@@ -159,11 +159,11 @@
     { models } = bongo
     { generateFakeClient }   = require '../server/client'
     generateFakeClient req, res, (err, client) ->
-      return handleError err  if err or not client
+      return handleError err, res  if err or not client

       { query } = req
       page = getPage query
       options = { section, entrySlug, client, page, isProfile, name }
       fetchContent models, options, (err, content) ->
-        return handleError err, content  if err or not content
+        return handleError err, res, content  if err or not content
         return res.status(200).send content


embedding urls when they shouldn't be->  removed.

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemStatusUpdate.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemStatusUpdate.coffee
@@ -78,14 +78,14 @@
     # This will involve heavy load on the embedly servers - every client
     # will need to make a request.
     else
-      urls = @$("span.data > a")
-      for url in urls
-        if $(url).attr("href").match(/([a-zA-Z]+\:\/\/)?(\w+:\w+@)?([a-zA-Z\d.-]+\.[A-Za-z]{2,4})(:\d+)?(\/\S*)?/g)
-          firstUrl = $(url).attr "href"
+      # urls = @$("span.data > a")
+      # for url in urls
+      #   if $(url).attr("href").match(/([a-zA-Z]+\:\/\/)?(\w+:\w+@)?([a-zA-Z\d.-]+\.[A-Za-z]{2,4})(:\d+)?(\/\S*)?/g)
+      #     firstUrl = $(url).attr "href"

-      if firstUrl then @embedBox.embedUrl firstUrl, {}
-      else
-        @embedBox.hide()
+      # if firstUrl and @embedBox? then @embedBox.embedUrl firstUrl, {}
+      # else
+      @embedBox.hide()

     @attachTooltipAndEmbedInteractivity()

@@ -106,13 +106,13 @@
           @embedBox.hide()
         else
           @embedBox.show()
-        @attachTooltipAndEmbedInteractivity()
       , link.link_cache

       @embedBox.setLinkFavicon link.link_url

     else
       @embedBox = new KDView
+    @attachTooltipAndEmbedInteractivity()

   click:(event)->


added question

added question

--- lib/aggregation.coffee
+++ lib/aggregation.coffee
@@ -16,7 +16,7 @@
       if params[key] == 'text'
         params[key] = text.toString()
       else if params[key] == '?'
-        params[key] = 'when was the world created'
+        params[key] = 'when was the world created?'
       else if params[key] == 'url'
         params[key] = 'https://cs-aggregator.herokuapp.com/'


More url handling

More url handling

--- lib/url-handler.coffee
+++ lib/url-handler.coffee
@@ -1,30 +1,52 @@
-#ipc = require 'ipc'
+ipc = require 'ipc'
+url = require 'url'

-#ipc.send 'user-opened-file'
-#{urlToOpen} = JSON.parse(decodeURIComponent(location.search.substr(14)))
+module.exports = ({blobStore}) ->
+  #{urlToOpen} = JSON.parse(decodeURIComponent(location.search.substr(14)))

-#console.log urlToOpen
+  #console.log urlToOpen
+  ipc.send('call-window-method', 'show')
+  ipc.send('call-window-method', 'focus')
+  window.focus()
+  #ipc.send('call-window-method', 'openDevTools')

-#ipc = require 'ipc'
-#ipc.send('call-window-method', 'show')
-#ipc.send('call-window-method', 'focus')
-#window.focus()
+  #parsed = url.parse urlToOpen, true
+  #console.log parsed

-#ipc.send('call-window-method', 'openDevTools')
+  #filePath = "/Users/tclem/github/github/#{parsed.query.filepath}"
+  #console.log filePath

-#url = require 'url'
+  # TODO Once you have the path to open, uncomment this line
+  ipc.send('open', {pathsToOpen: ['/Users/loganhasson/Desktop/ile_open.html']})
+  #path = require 'path'
+  #require './window'
+  #{getWindowLoadSettings} = require './window-load-settings-helpers'

-#parsed = url.parse urlToOpen, true
-#console.log parsed
+  #{resourcePath, isSpec, devMode} = getWindowLoadSettings()

-#filePath = "/Users/tclem/github/github/#{parsed.query.filepath}"
-#console.log filePath
+  # Add application-specific exports to module search path.
+  #exportsPath = path.join(resourcePath, 'exports')
+  #require('module').globalPaths.push(exportsPath)
+  #process.env.NODE_PATH = exportsPath

-# TODO Once you have the path to open, uncomment this line
-#ipc.send('open', {pathsToOpen: ['/Users/loganhasson/Desktop/ile_opeh.html']})
+  # Make React faster
+  #process.env.NODE_ENV ?= 'production' unless devMode

-# TODO Once done, uncomment this to close the window
-# require('remote').getCurrentWindow().close()
-module.exports =
-  activate: (state) ->
-    console.log('here')
+  #AtomEnvironment = require './atom-environment'
+  #ApplicationDelegate = require './application-delegate'
+  #window.atom = new AtomEnvironment({
+    #window, document, blobStore,
+    #applicationDelegate: new ApplicationDelegate,
+    #configDirPath: process.env.ATOM_HOME
+    #enablePersistence: true
+  #})
+
+  #atom.displayWindow()
+  #atom.startEditorWindow()
+
+  # Workaround for focus getting cleared upon window creation
+  #windowFocused = ->
+    #window.removeEventListener('focus', windowFocused)
+    #setTimeout (-> document.querySelector('atom-workspace').focus()), 0
+  #window.addEventListener('focus', windowFocused)
+


Remove old battle switch

Remove old battle switch

--- client/js/collections/battle_collection.coffee
+++ client/js/collections/battle_collection.coffee
@@ -13,7 +13,6 @@
     @socket.addEvents
       'start battle': @startBattle
       'update battle': @updateBattle
-      'battle switch': @battleSwitch

   startBattle: (socket, id, numActive, index, teams) =>
     console.log "BATTLE STARTED."
@@ -49,10 +48,3 @@
           console.log "ACTION REQUESTED:"
           console.log validActions
           view.enableButtons(validActions)
-
-
-  battleSwitch: (socket, battleId, playerIndex, fromSlot, toSlot) =>
-    view = @get(battleId).view
-    team = view.model.getTeam(playerIndex)
-    [team[toSlot], team[fromSlot]] = [team[fromSlot], team[toSlot]]
-    view.renderAll()


removed a console.trace(), added a TODO

removed a console.trace(), added a TODO

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -78,7 +78,8 @@

   openContent:(name, section, state, route)->
     KD.getSingleton("appManager").tell section, 'createContentDisplay', state, (contentDisplay)=>
-      console.trace()
+      # TODO: this callback doesn't fire. We need to get this working again
+      # to regain "spatial" history
       @openRoutes[route] = contentDisplay
       @openRoutesById[contentDisplay.id] = route


use NumberInput on bigdec types

use NumberInput on bigdec types

--- client/lanes/components/grid/EditingMixin.cjsx
+++ client/lanes/components/grid/EditingMixin.cjsx
@@ -18,7 +18,7 @@
             <input type="text" {...props}
                 onChange={_.partial(@onFieldChange, _, props.field)} />
         bigdec: (props) ->
-            <LC.Input onlyNumeric inputOnly {...props} />
+            <LC.NumberInput unstyled {...props} />
         date: (props) ->
             <LC.DateTime {...props} inputOnly step={15}
                 onChange={_.partial(@onDateFieldChange, _, props.field)} />


Added specific asserts for tests with image and link

--- client/test/lib/helpers/messageshelpers.coffee
+++ client/test/lib/helpers/messageshelpers.coffee
@@ -17,6 +17,10 @@
     messageWithCode     = "console.log('123456789')"
     messageWithFullCode = "```console.log('123456789')```"
     textSelector        = '.message-pane.privatemessage .message-pane-scroller .kdscrollview .kdlistview-privatemessage .consequent'
+    imageSelector       = "#{textSelector} .link-embed-box .embed-image-view img"
+    linkSelector        = "[testpath=activity-list] section:nth-of-type(1) [testpath=ActivityListItemView] .link-embed-box .with-image .preview-text a:nth-of-type(2)"
+    messageWithImage    = "https://koding-cdn.s3.amazonaws.com/images/default.avatar.333.png"
+    messageWithLink     = "http://wikipedia.org/"
     sendMessage         = (browser, users, message, purpose) ->
       console.log " ✔ Creating a new message with user #{users[0].username}..."
       browser
@@ -44,14 +48,26 @@
         browser
           .waitForElementVisible   '.reply-input-widget.private',20000
           .click                   textareaSelector
-          .setValue                textareaSelector, message + '\n'
+          .setValue                textareaSelector, message
+          .pause                   2000 #in order for the previews to load
+          .setValue                textareaSelector, browser.Keys.ENTER
           .waitForElementVisible   '.message-pane.privatemessage', 20000
           .waitForElementVisible   '[testpath=activity-list]', 20000
           switch message
             when messageWithFullCode
               browser
-                .waitForElementVisible   textSelector, 20000
                 .assert.containsText     textSelector, messageWithCode
+            when messageWithImage
+              browser
+                .waitForElementVisible   imageSelector, 20000
+
+              browser.getAttribute imageSelector, 'height', (result) ->
+                height = result.value
+                assert.equal('333', height)
+            when messageWithLink
+              browser
+                .waitForElementVisible    linkSelector, 20000
+                .assert.containsText      linkSelector, 'The Free Encyclopedia'
             else
               browser
                 .assert.containsText     '.message-pane.privatemessage', message # Assertion


route caching, for within-page back/forward support without re-executing the search

--- web/js/models/routes.coffee
+++ web/js/models/routes.coffee
@@ -4,7 +4,7 @@

     model: Route

-    @find: (from, to, date, arrivalOrDeparture = 'departure', transportTypes = 'all', callback, errback) ->
+    @find: (from, to, date, arrivalOrDeparture = 'departure', transportTypes = 'all') ->
       params = $.param
         from: from
         to: to
@@ -12,11 +12,25 @@
         time: Utils.formatHSLTime(date)
         arrivalOrDeparture: arrivalOrDeparture
         transportTypes: transportTypes.join('|')
-      $.ajax
-        url: "/routes?#{params}"
-        dataType: 'json'
-        success: (data) -> Reitti.Event.trigger 'routes:change', Routes.make(data.from, data.to, data.routes, date, arrivalOrDeparture)
-        error: (xhr, status) -> Reitti.Event.trigger 'routes:notfound', $.parseJSON(xhr.responseText)
+      successCallback = (data) =>
+        @putCached(params, data)
+        Reitti.Event.trigger 'routes:change', Routes.make(data.from, data.to, data.routes, date, arrivalOrDeparture)
+      errorCallback = (xhr, status) =>
+        Reitti.Event.trigger 'routes:notfound', $.parseJSON(xhr.responseText)
+
+      if data = @getCached(params)
+        successCallback(data)
+      else
+        $.ajax
+          url: "/routes?#{params}"
+          dataType: 'json'
+          success: successCallback
+          error: errorCallback
+
+    @getCached: (params) ->
+      (@_cache ?= {})[params]
+    @putCached: (params,data) ->
+      (@_cache ?= {})[params] = data

     @make: (from, to, data, date, arrivalOrDeparture) ->
       fromName = @_locationString(from)


fixed the filter extracting

fixed the filter extracting

--- vendor/assets/javascripts/brainstem/storage-manager.coffee
+++ vendor/assets/javascripts/brainstem/storage-manager.coffee
@@ -129,7 +129,7 @@
     only = if options.only then _.map((Brainstem.Utils.extractArray "only", options), (id) -> String(id)) else null
     search = options.search
     include = _(options.include).map((i) -> _.keys(i)[0]) # pull off the top layer of includes
-    filters = Brainstem.Utils.extractArray "filters", options
+    filters = options.filters || {}
     order = options.order || "updated_at:desc"
     cacheKey = "#{order}|#{_.chain(filters).pairs().map(([k, v]) -> "#{k}:#{v}" ).value().join(",")}|#{options.page}|#{options.perPage}"


:art:

:art:

--- lib/operators/general-operators.coffee
+++ lib/operators/general-operators.coffee
@@ -59,7 +59,8 @@
 # Public: Generic class for an operator that requires extra input
 class OperatorWithInput extends Operator
   @extend()
-  canComposeWith: (operation) -> operation.characters? or operation.select?
+  canComposeWith: (operation) ->
+    operation.characters? or operation.select?

   compose: (operation) ->
     if operation.select?
@@ -80,8 +81,8 @@
   @extend()
   register: null

-  constructor: (@editor, @vimState) ->
-    @complete = false
+  constructor: ->
+    super
     @register = settings.defaultRegister()

   # Public: Deletes the text selected by the given motion.
@@ -147,9 +148,6 @@
 #
 class UpperCase extends Operator
   @extend()
-  constructor: (@editor, @vimState) ->
-    @complete = false
-
   execute: ->
     # if _.contains(@target.select(@getCount(1)), true)
     if _.contains(@target.select(), true)
@@ -163,9 +161,6 @@
 #
 class LowerCase extends Operator
   @extend()
-  constructor: (@editor, @vimState) ->
-    @complete = false
-
   execute: ->
     if _.contains(@target.select(), true)
       @editor.replaceSelectedText {}, (text) ->
@@ -180,7 +175,8 @@
   @extend()
   register: null

-  constructor: (@editor, @vimState) ->
+  constructor: ->
+    super
     @register = settings.defaultRegister()

   # Public: Copies the text selected by the given motion.
@@ -212,7 +208,9 @@
 #
 class Join extends Operator
   @extend()
-  constructor: (@editor, @vimState) -> @complete = true
+  constructor: ->
+    super
+    @complete = true

   # Public: Combines the current with the following lines
   #
@@ -230,7 +228,9 @@
 #
 class Repeat extends Operator
   @extend()
-  constructor: (@editor, @vimState) -> @complete = true
+  constructor: ->
+    super
+    @complete = true

   isRecordable: -> false

@@ -244,8 +244,8 @@
 #
 class Mark extends OperatorWithInput
   @extend()
-  constructor: (@editor, @vimState) ->
-    super(@editor, @vimState)
+  constructor: ->
+    super
     @viewModel = new ViewModel(this, class: 'mark', singleChar: true, hidden: true)

   # Public: Creates the mark in the specified mark register (from user input)


Fix storageManager error on exceptions.  It was not showing the expected options

--- vendor/assets/javascripts/brainstem/storage-manager.coffee
+++ vendor/assets/javascripts/brainstem/storage-manager.coffee
@@ -109,7 +109,7 @@
       if expectation.optionsMatch(name, loader.originalOptions)
         expectation.recordRequest(loader)
         return
-    throw "No expectation matched #{name} with #{JSON.stringify options}"
+    throw "No expectation matched #{name} with #{JSON.stringify loader.originalOptions}"

   # Helpers
   loadObject: (name, loadOptions, options = {}) ->


don't blow up if parentNode doesn't exist

--- tutor/src/components/book-content-mixin.cjsx
+++ tutor/src/components/book-content-mixin.cjsx
@@ -242,7 +242,7 @@
   figure = dom(@).closest('figure') or dom(@).closest('[data-type=media]')
   # console.log("process", @, figure)
   return unless figure
-  if figure.parentNode.nodeName is 'FIGURE'
+  if figure.parentNode?.nodeName is 'FIGURE'
     figure.parentNode.classList.add('with-child-figures')

   @title = @alt


fix/re-enable links preview feature

fix/re-enable links preview feature

--- tutor/src/components/book-content-mixin.cjsx
+++ tutor/src/components/book-content-mixin.cjsx
@@ -145,6 +145,7 @@
   mixins: [ ScrollToLinkMixin ]

   componentDidMount:  ->
+    @_linkContentIsMounted = true
     @insertOverlays()
     @detectImgAspectRatio()
     @cleanUpAbstracts()


fix issue #8, workaround with special case

--- lib/regex-railroad-diagram-view.coffee
+++ lib/regex-railroad-diagram-view.coffee
@@ -37,6 +37,12 @@
       #console.log text
       text = text.replace(/^\s+/, "").replace(/\s+$/, "")

+      # special case, maybe we get a comment, but it might be already
+      # marked as regex by language grammar, although it might result in
+      # a comment
+      if text.length == 1 and text == "/"
+        return
+
       # python regex
       m = /^r('''|"""|"|')(.*)\1$/.exec(text)
       if m?
@@ -50,6 +56,7 @@
         m = /^\/(.*)\/\w*$/.exec(text)
         if m?
           text = m[1]
+

       if not @isVisible or @currentRegex != text
         @.find('div.error-message').remove()


grouphome: pass group slug as parameter to fetchScripts

--- workers/social/lib/social/render/loggedin/grouphome.coffee
+++ workers/social/lib/social/render/loggedin/grouphome.coffee
@@ -31,5 +31,5 @@

     """

-  fetchScripts {bongoModels, client}, (err, scripts)->
+  fetchScripts {bongoModels, client, slug}, (err, scripts)->
     callback null, prepareHTML scripts


Fix #1067: When delete a project reload nav menu

--- app/coffee/modules/projects/lightboxes.coffee
+++ app/coffee/modules/projects/lightboxes.coffee
@@ -34,10 +34,10 @@
         form = $el.find("form").checksley({"onlyOneErrorElement": true})

         onSuccessSubmit = (response) ->
-            lightboxService.close($el)
+            $rootscope.$broadcast("projects:reload")
             $confirm.notify("success", "Success") #TODO: i18n
             $location.url($projectUrl.get(response))
-            $rootscope.$broadcast("projects:reload")
+            lightboxService.close($el)

         onErrorSubmit = (response) ->
             form.setErrors(response)
@@ -124,7 +124,7 @@
 ## Delete Project Lightbox Directive
 #############################################################################

-DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, lightboxService) ->
+DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, $confirm, lightboxService) ->
     link = ($scope, $el, $attrs) ->
         projectToDelete = null
         $scope.$on "deletelightbox:new", (ctx, project)->
@@ -139,11 +139,14 @@

             promise.then (data) ->
                 lightboxService.close($el)
+                $rootscope.$broadcast("projects:reload")
                 $location.path($navUrls.resolve("home"))
+                $confirm.notify("success")

             # FIXME: error handling?
             promise.then null, ->
-                console.log "FAIL"
+                $confirm.notify("error")
+                lightboxService.close($el)

         $el.on "click", ".button-red", (event) ->
             event.preventDefault()
@@ -156,4 +159,4 @@
     return {link:link}

 module.directive("tgLbDeleteProject", ["$tgRepo", "$rootScope", "$tgAuth", "$tgLocation", "$tgNavUrls",
-                                       "lightboxService", DeleteProjectDirective])
+                                       "$tgConfirm", "lightboxService", DeleteProjectDirective])


TL-300: User cannot select from the suggested dropdown menu options and manually entered information is not recognized

--- app/coffeescripts/widget/TokenSelector.coffee
+++ app/coffeescripts/widget/TokenSelector.coffee
@@ -191,7 +191,7 @@
     blur: ->
       # It seems we can't check focus while it is being changed, so check it later.
       setTimeout =>
-        unless @input.hasFocus() || @$container.find(':focus').length > 0
+        unless @input.hasFocus() || @$container.find(':focus').length > 0 || $(document.activeElement).parents('.autocomplete_menu').length > 0
           @close()
       , 0


Kite: instance method, create added

Kite: instance method, create added

--- workers/social/lib/social/models/kite.coffee
+++ workers/social/lib/social/models/kite.coffee
@@ -37,6 +37,7 @@
           (signature Function)
         removePlan:
           (signature Object, Function)
+
     relationships: ->
       plan          :
         as          : 'kitePlan'
@@ -44,12 +45,13 @@

   @create: permit 'create kite',
     success:(client, formData, callback)->
-      queue = [
-        =>
-          {plans} = formData
-          plans.map (plan)=> console.log  "NOT IMPLEMENTED YET"
-
-      ]
+      kite = new JKite formData
+      kite.save (err)->
+        return  callback new KodingError "kite couldn't saved" if err
+        account = client.connection.delegate
+        account.addKite (err, res)->
+          return  callback new KodingError "kite couldn't added to Account" if err
+          callback null, kite

   @list: permit 'list kites',
     success: (client, selector, options, callback)->


backend behaviour clarification comment added

--- web/source/main.coffee
+++ web/source/main.coffee
@@ -66,6 +66,7 @@
           _vals[Patch.PHONE_UPDATED] = undefined
           delete _vals[Patch.PHONE_UPDATED]

+        # NOTE: Location updates date only if both city and country change
         when Patch.CITY, Patch.COUNTRY
           _vals[Patch.LOCATION_UPDATED] = undefined
           delete _vals[Patch.LOCATION_UPDATED]


Make it so that we're only playing video.

--- web/volume/slot.coffee
+++ web/volume/slot.coffee
@@ -298,7 +298,7 @@

         biggerAssets = _.chain($scope.assets)
-                        .filter (i) -> i.lt.o >= $scope.asset.segment.u
+                        .filter (i) -> i.lt.o >= $scope.asset.segment.u && i.asset.format.type == 'video'
                         .sortBy (i) -> i.lt.o
                         .value()


Simplify(?) the callback

Simplify(?) the callback

--- resources/assets/coffee/react/profile-page/historical.coffee
+++ resources/assets/coffee/react/profile-page/historical.coffee
@@ -25,10 +25,11 @@
     showingPlaycounts: 5
     showingRecent: 5

-  _showMore: (e, key) ->
-    e.preventDefault() if e
+  _showMore: (key) ->
+    (e) =>
+      e.preventDefault() if e

-    @setState "#{key}": (@state[key] + 5)
+      @setState "#{key}": (@state[key] + 5)

   _beatmapRow: (bm, bmset, key, shown, details = []) ->
@@ -95,7 +96,7 @@
         a
           href: '#'
           className: 'beatmapset-row beatmapset-row--more'
-          onClick: (e) => @_showMore(e, 'showingPlaycounts')
+          onClick: @_showMore('showingPlaycounts')
           Lang.get('common.buttons.show_more')

       h3
@@ -114,5 +115,5 @@
         a
           href: '#'
           className: 'beatmapset-row beatmapset-row--more'
-          onClick: (e) => @_showMore(e, 'showingRecent')
+          onClick: @_showMore('showingRecent')
           Lang.get('common.buttons.show_more')


Show mode correctly, make recursive button tiny

--- client/app/MainApp/filetree/itemsubviews/setpermissionsview.coffee
+++ client/app/MainApp/filetree/itemsubviews/setpermissionsview.coffee
@@ -17,11 +17,12 @@
             @displayOldOctalPermissions()

     @recursive = new KDOnOffSwitch
+      size : 'tiny'

   permissionsToOctalString = (permissions)->
     str = permissions.toString 8
     str = "0" + str while str.length < 3
-    return str
+    return str[-3..]

   createSwitches: (permission) ->
     for i in [0...9]


Update code for tests

Update code for tests

--- server/fixtures.coffee
+++ server/fixtures.coffee
@@ -33,7 +33,7 @@
       isAliasedByMixpanel: true
       emails: [
         {
-          address: _id.toLowerCase() + "@foreach.io"
+          address: _id.toLowerCase() + "@fixin.io"
           verified: true
         }
       ]


Text Edit #5

Text Edit #5

Infotext angepasst

--- src/components/Info.coffee
+++ src/components/Info.coffee
@@ -15,31 +15,23 @@

   render: ->
     div className: "info",
-      h3 null,
-        "Die Welt steckt voller Entdecker."
-        br null
-        "Und voller Orte, die darauf warten entdeckt zu werden."
-      p null
-        """
-                      Unsere interaktive Karte zeigt dir Orte in deiner Umgebung,
-                      an denen man sich schon heute für eine Welt von morgen einsetzt.
-                      """
-      p null
-        """
-                      Du hast eine Initiative, für die du Mitstreiter suchst?
-                      Du kennst ein Unternehmen, das nachhaltig wirtschaftet?
-                      """
-      p null
-        """
-                      Auf unserer Website kannst du andere darauf
-                      aufmerksam machen – und dich so für eine Sache
-                      einsetzen, die dir persönlich am Herzen liegt.
-                      """
       h2 null, "Das Projekt"
       p null,
         """
-        von morgen fördert Menschlichkeit, Umweltfreundlichkeit und gemeinsames
-        Handeln – kurz gesagt: Alles was glücklich macht.
+        Unsere interaktive Karte zeigt dir Orte in deiner Umgebung,
+        an denen man sich schon heute für eine Welt von morgen einsetzt.
+        """
+      p null
+        """
+        Du hast eine Initiative, für die du Mitstreiter suchst?
+        Du kennst ein Unternehmen, das nachhaltig wirtschaftet?
+        """
+      p null
+        """
+        Auf unserer Website kannst du andere darauf
+        aufmerksam machen – und dich so für eine Sache
+        einsetzen, die dir persönlich am Herzen liegt.
+        """
         Wir sind auf der Suche nach vielfältigen Projekten, Initiativen und
         Unternehmen, die den aktuellen sozialen, ökologischen und ökonomischen
         Umbrüchen alternativ entgegen wirken.


Fix platform check when rendering logo

Fix platform check when rendering logo

--- src/components/header.cjsx
+++ src/components/header.cjsx
@@ -35,7 +35,7 @@

   _renderLogo: ->
-    if process.platform is not 'win32'
+    if process.platform != 'win32'


stop using the 2D context’s arc method and draw a bunch of lines like Love does

--- coffeescript/love.js/graphics/canvas_2d.coffee
+++ coffeescript/love.js/graphics/canvas_2d.coffee
@@ -46,30 +46,18 @@
   setWrap: (self) ->

   # PRIVATE
-  arc: (mode, x, y, radius, startAngle, endAngle) ->
+  arc: (mode, x, y, radius, startAngle, endAngle, points) ->
+    points ||= if radius > 10 then radius else 10
+    angle_shift = (endAngle - startAngle) / points
+    phi = startAngle - angle_shift
+
     @context.beginPath()
     @context.moveTo(x, y)
-
-    # TODO: Can this be generalized and cleaned up?
-    anticlockwise = false # default value for the arc call
-    if endAngle < 0
-      anticlockwise = true
-      if startAngle < 0
-        anticlockwise = false
-      if radius < 0
-        radius = Math.abs(radius)
-        startAngle += Math.PI
-        endAngle += Math.PI
-    else if radius < 0
-      radius = Math.abs(radius)
-      anticlockwise = true
-      if startAngle < 0
-        startAngle += Math.PI
-        endAngle += Math.PI
-        anticlockwise = false
-
-    @context.arc(x, y, radius, startAngle, endAngle, anticlockwise)
+    for i in [0..points]
+      phi += angle_shift
+      @context.lineTo(x + radius * Math.cos(phi), y + radius * Math.sin(phi))
     @context.closePath()
+
     switch mode
       when "fill" then @context.fill()
       when "line" then @context.stroke()


Update specs

Update specs

--- spec/command-palette-spec.coffee
+++ spec/command-palette-spec.coffee
@@ -61,7 +61,7 @@
           expect(eventLi).not.toExist()

     it "focuses the mini-editor and selects the first command", ->
-      expect(palette.filterEditorView.isFocused).toBeTruthy()
+      expect(palette.filterEditorView.hasFocus()).toBeTruthy()
       expect(palette.find('.event:first')).toHaveClass 'selected'

     it "clears the previous mini editor text", ->
@@ -71,21 +71,21 @@
       expect(palette.filterEditorView.getText()).toBe ''

   describe "when command-palette:toggle is triggered on the open command palette", ->
-    it "focus the root view and detaches the command palette", ->
-      expect(palette.hasParent()).toBeTruthy()
-      palette.trigger 'command-palette:toggle'
-      expect(palette.hasParent()).toBeFalsy()
+    it "focus the root view and hides the command palette", ->
+      expect(palette.isVisible()).toBeTruthy()
+      atom.commands.dispatch palette[0], 'command-palette:toggle'
+      expect(palette.is(':visible')).toBeFalsy()
       expect(atom.workspaceView.getActiveView().isFocused).toBeTruthy()

   describe "when the command palette is cancelled", ->
-    it "focuses the root view and detaches the command palette", ->
-      expect(palette.hasParent()).toBeTruthy()
+    it "focuses the root view and hides the command palette", ->
+      expect(palette.is(':visible')).toBeTruthy()
       palette.cancel()
-      expect(palette.hasParent()).toBeFalsy()
+      expect(palette.is(':visible')).toBeFalsy()
       expect(atom.workspaceView.getActiveView().isFocused).toBeTruthy()

   describe "when an command selection is confirmed", ->
-    it "detaches the palette, then focuses the previously focused element and emits the selected command on it", ->
+    it "hides the palette, then focuses the previously focused element and emits the selected command on it", ->
       eventHandler = jasmine.createSpy('eventHandler').andReturn(false)
       activeEditor = atom.workspaceView.getActiveView()
       eventName = palette.items[3].name
@@ -96,7 +96,7 @@

       expect(activeEditor.isFocused).toBeTruthy()
       expect(eventHandler).toHaveBeenCalled()
-      expect(palette.hasParent()).toBeFalsy()
+      expect(palette.is(':visible')).toBeFalsy()

   describe "when no element has focus", ->
     it "uses the root view as the element to display and trigger events for", ->


converting to given

converting to given

--- spec/jasmine-stealth-spec.coffee
+++ spec/jasmine-stealth-spec.coffee
@@ -117,28 +117,18 @@

   describe "jasmine.createStubObj", ->
     context "used just like createSpyObj", ->
-      beforeEach ->
-        @subject = jasmine.createStubObj('foo',['a','b'])
-        @subject.a()
-        @subject.b()
-
-      it "creates a spy", ->
-        expect(@subject.a).toHaveBeenCalled()
-
-      it "creates b spy", ->
-        expect(@subject.b).toHaveBeenCalled()
+      Given -> @subject = jasmine.createStubObj('foo',['a','b'])
+      Given -> @subject.a()
+      Given -> @subject.b()
+      Then -> expect(@subject.a).toHaveBeenCalled()
+      Then -> expect(@subject.b).toHaveBeenCalled()

     context "passed an obj literal", ->
-      beforeEach ->
-        @subject = jasmine.createStubObj 'foo',
-          a: 5
-          b: -> 8
-
-      it "returns a simple value", ->
-        expect(@subject.a()).toBe(5)
-
-      it "invokes a provided function", ->
-        expect(@subject.b()).toBe(8)
+      Given -> @subject = jasmine.createStubObj 'foo',
+        a: 5
+        b: -> 8
+      Then -> @subject.a() == 5
+      Then -> @subject.b() == 8

   describe "jasmine.argThat (jasmine.Matchers.ArgThat)", ->
     context "with when()", ->
@@ -166,8 +156,8 @@
     Given -> @captor = jasmine.captor()
     Given -> @spy = jasmine.createSpy()
     When -> @spy("foo!")
-    Then( -> expect(@spy).toHaveBeenCalledWith(@captor.capture()))
-    .Then( -> @captor.value == "foo!")
+    Then -> expect(@spy).toHaveBeenCalledWith(@captor.capture())
+    And -> @captor.value == "foo!"

     it "readme example", ->
       captor = jasmine.captor()


:white_check_mark: Add tests for highlight decorations render

--- spec/minimap-element-spec.coffee
+++ spec/minimap-element-spec.coffee
@@ -147,6 +147,19 @@
         expect(minimapElement.drawLineDecorations).toHaveBeenCalled()
         expect(minimapElement.drawLineDecorations.calls.length).toEqual(2)

+      it 'renders the visible highlight decorations', ->
+        spyOn(minimapElement, 'drawHighlightDecoration').andCallThrough()
+
+        minimap.decorateMarker(editor.markBufferRange([[1,0], [1,4]]), type: 'highlight-under', color: '#0000FF')
+        minimap.decorateMarker(editor.markBufferRange([[2,20], [2,30]]), type: 'highlight-over', color: '#0000FF')
+        minimap.decorateMarker(editor.markBufferRange([[100,3], [100,5]]), type: 'highlight-under', color: '#0000FF')
+
+        editor.setScrollTop(0)
+        nextAnimationFrame()
+
+        expect(minimapElement.drawHighlightDecoration).toHaveBeenCalled()
+        expect(minimapElement.drawHighlightDecoration.calls.length).toEqual(2)
+
       describe 'when the editor is scrolled', ->
         beforeEach ->
           editor.setScrollTop(2000)


1.7.3

--- def/settings.coffee
+++ def/settings.coffee
@@ -67,6 +67,12 @@

     pref.find('label[for="core.audioBeep"]').children('.setting-title').html('嗶嗶聲')
     pref.find('label[for="core.audioBeep"]').next('.setting-description').html('當操作無效或無結果可顯示時，以系統嗶嗶聲警告。')
+
+		pref.find('label[for="core.automaticallyUpdate"]').children('.setting-title').html('自動更新')
+		pref.find('label[for="core.automaticallyUpdate"]').next('.setting-description').html('當有新版本的時候，自動更新 Atom。')
+		pref.find('label[for="core.automaticallyUpdate"]').children('.setting-title').html('自動更新')
+		pref.find('label[for="core.automaticallyUpdate"]').next('.setting-description').html('當有新版本的時候，自動更新 Atom。')
+
     pref.find('label[for="core.autoHideMenuBar"]').children('.setting-title').html('自動隱藏主選單')
     pref.find('label[for="core.autoHideMenuBar"]').next('.setting-description').html('自動隱藏主選單後，可以按下 Alt 鍵使其再次浮現。這項設定只有 Windows 和 Linux 作業系統支援。')
     pref.find('label[for="core.destroyEmptyPanes"]').children('.setting-title').html('自動關閉空窗格')


Translate welcome message

Translate welcome message

--- def/th/welcome.cson
+++ def/th/welcome.cson
@@ -1,29 +1,29 @@
 Welcome:
-  tabTitle: "Welcome"
+  tabTitle: "ยินดีต้นรับ"
   subtitle: {
-    text1: "A hackable text editor for the 21"
-    superscript: "st"
-    text2: " Century"
+    text1: "อิดิเตอร์ที่แฮคได้ของศตวรรษที่ 21"
+    superscript: ""
+    text2: ""
   }
   help: {
-    forHelpVisit: "For help, please visit"
+    forHelpVisit: "สำหรับความช่วยเหลือ, โปรดเข้าไปที่ "
     atomDocs: {
-      text1: "The "
-      link: "Atom docs"
-      text2: " for Guides and the API reference."
+      text1: ""
+      link: "เอกสารของ Atom"
+      text2: " สำหรับแนวทางและคู่มือ API"
       _template: "${text1}${link}${text2}"
     }
     atomForum: {
-      text1: "The Atom forum at "
+      text1: "กระทู้ของ Atom ที่ "
       link: "discuss.atom.io"
       text2: ""   # optional
       _template: "${text1}${link}${text2}"
     }
     atomOrg: {
-      text1: "The "
+      text1: ""
       link: "Atom org"
-      text2: ". This is where all GitHub-created Atom packages can be found."
+      text2: " คือที่ที่จะพบแพคเก็จของ Atom ที่สร้างบน Github"
       _template: "${text1}${link}${text2}"
     }
   }
-  showWelcomeGuide: "Show Welcome Guide when opening Atom"
+  showWelcomeGuide: "แสดงข้อความต้อนรับเมื่อเริ่มเปิด Atom"


I think I finally squashed the expand-o click event weirdness.

--- app/assets/javascripts/drops_calculator/dropsView.js.coffee
+++ app/assets/javascripts/drops_calculator/dropsView.js.coffee
@@ -14,8 +14,7 @@
   render: (@context) ->
     @el.html(@template(@context))
     @checkboxes = $('input.check-box', @el)
-    @toggleClickables = $('.drop-expand-btn', @el)
-      .add('.glyphicon-triangle-right', @el)
+    @toggleClickables = $('.drop-data-header', @el)
     @checkboxes.each ->
       el = $(this)
       unless el.attr('name') == 'Capture' || el.attr('name') == 'Virus Reward'
@@ -27,6 +26,8 @@
   bind: ->
     @toggleClickables.click @toggleDropTable
     @checkboxes.change @onCheckboxChange
+    @checkboxes.click (e) ->
+      e.stopPropagation()

   selectedBreaks: ->
     result = []


Do not send a parameter with the current time when requesting refresh feed job states via Ajax.

It was keeping the client from leveraging HTTP caching.

--- app/assets/javascripts/ng-services/ng-JobStateSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-JobStateSvc.js.coffee
@@ -10,8 +10,7 @@
   # PRIVATE FUNCTION: load list of refresh feed job states via AJAX
   #---------------------------------------------
   load_refresh_feed_job_states = ->
-    now = new Date()
-    $http.get("/api/refresh_feed_job_states.json?time=#{now.getTime()}")
+    $http.get("/api/refresh_feed_job_states.json")
     .success (data)->
       $rootScope.refresh_feed_job_states = data.slice()
       for job_state in data


Blacklist the dev route for auction notifications

--- components/auction_reminders/blacklist.coffee
+++ components/auction_reminders/blacklist.coffee
@@ -6,6 +6,7 @@
     '^/user/edit'
     '^/sale/.*'
     '^/auction/.*'
+    '^/dev$'
   ]

   check: ->


KDTokenizedInputView: pass tokenViewClass parameter to super of menuItemClicked

--- components/inputs/KDTokenizedInputView.coffee
+++ components/inputs/KDTokenizedInputView.coffee
@@ -95,6 +95,8 @@
     @menu?.destroy()
     @blur()

+    return  unless data.length
+
     pos       = @tokenInput.getBoundingClientRect()
     options.x = pos.left
     options.y = pos.top + parseInt window.getComputedStyle(@tokenInput).lineHeight, 10
@@ -108,8 +110,8 @@
     @activeRule = null
     @tokenInput = null

-  menuItemClicked: (item) ->
-    @addToken item.data
+  menuItemClicked: (item, tokenViewClass) ->
+    @addToken item.data, tokenViewClass
     @hideMenu()

   addToken: (item, tokenViewClass = @getOptions().tokenViewClass) ->
@@ -140,7 +142,7 @@
     super
     switch event.which
       when 9, 13, 27, 38, 40 # enter, tab, escape, up, down
-      else
+      else if not event.altKey and event.ctrlKey and event.metaKey
         if @activeRule then @matchToken()
         else @matchPrefix()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_selector.coffee
+++ src/engine_selector.coffee
@@ -15,7 +15,7 @@
         item.I[attr] = value

   ###*
-  Get the closest
+  Get the game object closest to the
   ###
   closest: (selector, position) ->


Added source of error

Added source of error

--- core/app/backbone/contrib/raven_capture.coffee
+++ core/app/backbone/contrib/raven_capture.coffee
@@ -1,3 +1,3 @@
 window.ravenCapture = (args...) ->
-  console.error args...
+  console.error 'Factlink ravenCapture: ', args...
   Raven?.captureMessage args...


Bug fix for when no sync is required.

Bug fix for when no sync is required.

--- src/publish/bucket/sync.coffee
+++ src/publish/bucket/sync.coffee
@@ -18,6 +18,7 @@
   async ({dlist, ulist}) ->
     console.log "Syncing S3 bucket."
     total = (cat dlist, ulist).length
+    rl.close() if total == 0
     currentIndex = 0

     printProgress = ->


Fix example JavaScript

Fix example JavaScript

--- lib/assets/javascripts/unpoly/form.coffee
+++ lib/assets/javascripts/unpoly/form.coffee
@@ -930,7 +930,7 @@

   Also note that the function must be declared on the `window` object to work, like so:

-      window.showSuggestions(selectedValue) {
+      window.showSuggestions = function(selectedValue) {
         console.log(`Called showSuggestions() with ${selectedValue}`);
       }


检查是否qdt创建的项目

检查是否qdt创建的项目

--- lib/module/create-module-info-view.coffee
+++ lib/module/create-module-info-view.coffee
@@ -81,11 +81,21 @@
   serialize: ->

   getModuleInfo: ->
+    modulePath = @modulePath.getText()
+    hasModulesFolder = modulePath.lastIndexOf('modules') isnt '-1'
+    if hasModulesFolder
+      projectHome = pathM.dirname modulePath
+    else
+      projectHome = modulePath
+    configPath = pathM.join projectHome,desc.ProjectConfigFileName
+    isProject = Util.isFileExist configPath,'sync'
+
     info =
       mainEntry: @mainEntry.getText()
       moduleId: @moduleId.getText()
       moduleName: @moduleName.getText()
-      modulePath: @modulePath.getText()
+      modulePath: modulePath
+      isChameleonProject:isProject
     info

   openFolder: (e) ->


fix mongo brain undefined data ref #873

fix mongo brain undefined data ref #873

--- src/scripts/mongo-brain.coffee
+++ src/scripts/mongo-brain.coffee
@@ -17,9 +17,9 @@
 #   None
 #
 # Author:
-#   ajacksified
+#   ajacksified, maxbeatty

-
+Util = require "util"
 mongodb = require "mongodb"
 Server = mongodb.Server
 Collection = mongodb.Collection
@@ -35,37 +35,37 @@
   error = (err) ->
     console.log "==MONGO BRAIN UNAVAILABLE==\n==SWITCHING TO MEMORY BRAIN=="
     console.log err
-    robot.brain.emit 'loaded', {}

-  server = new Server(host, port, { })
-  db = new Db(dbname, server, { w: 1, native_parser: true })
+  server = new Server host, port, {}
+  db = new Db dbname, server, { w: 1, native_parser: true }

-  db.open((err, client) ->
-    if err
-      error(err)
-    else
-      db.authenticate(user, pass, (err, success) ->
-        if err
-          error(err)
+  db.open (err, client) ->
+    return error err if err
+
+    robot.logger.debug 'Successfully opened connection to mongo'
+
+    db.authenticate user, pass, (err, success) ->
+      return error err if err
+
+      robot.logger.debug 'Successfully authenticated with mongo'
+
+      collection = new Collection client, 'hubot_storage'
+
+      collection.find().limit(1).toArray (err, results) ->
+        return error err if err
+
+        robot.logger.debug 'Successfully queried mongo'
+        robot.logger.debug Util.inspect(results, false, 4)
+
+        if results.length > 0
+          robot.brain.data = results[0]
+          robot.brain.emit 'loaded', results[0]
         else
-          collection = new Collection(client, 'hubot_storage')
+          robot.logger.debug 'No results found'

-          collection.find().limit(1).toArray((err, results) ->
-            if results
-              robot.brain.data = results[0]
-              robot.brain.emit 'loaded', results[0]
-            else
-              robot.brain.emit 'save', {}
-              robot.brain.emit 'loaded', {}
-          )
+      robot.brain.on 'save', (data) ->
+        robot.logger.debug 'Save event caught by mongo'
+        robot.logger.debug Util.inspect(robot.brain.data, false, 4)

-          robot.brain.on('save', () ->
-            collection.save(robot.brain.data, (err) ->
-              console.warn err if err?
-            )
-          )
-        )
-      )
-
-
-
+        collection.save robot.brain.data, (err) ->
+          console.warn err if err?


Add last command on rsstodolist plugin to fetch lastest links

--- src/scripts/rsstodolist.coffee
+++ src/scripts/rsstodolist.coffee
@@ -10,20 +10,24 @@
 # Commands:
 #   hubot rtdl show <user_name> - Display the <user_name> RssToDoList feed url
 #   hubot rtdl add <user_name> <link> - Send the <link> to <user_name> RssToDoList feed
+#   hubot rtdl last <user_name> <limit> - Display last links for that <user_name> (you can specify an optional <limit>)
 #
 # Author:
 #   athieriot
+#   paulgreg
+
+jsdom = require 'jsdom'

 module.exports = (robot) ->
-  robot.respond /rtdl (add|show) ([^ ]*)( .*)?/i, (msg) ->
+  robot.respond /rtdl (add|show|last) ([^ ]*)( .*)?/i, (msg) ->
    server_url = 'http://rsstodolist.appspot.com'

-   [action, user_name, link] = [msg.match[1], escape(msg.match[2]), msg.match[3]]
+   [action, user_name, arg] = [msg.match[1], escape(msg.match[2]), msg.match[3]]

-   if action == 'add' && link != undefined
+   if action == 'add' && arg != undefined
       msg.http(server_url + '/add')
          .query(n: user_name)
-         .query(url: link.trim())
+         .query(url: arg.trim())
          .get() (err, res, body) ->
             status = res.statusCode

@@ -33,3 +37,18 @@
                msg.reply "An error occured on " + user_name + " feed"
    else if action == 'show'
       msg.reply user_name + ' feed is ' + server_url + '/?n=' + user_name
+   else if action == 'last'
+      msg.http(server_url + '/')
+         .query(n: user_name)
+         .query(l: arg || 10)
+         .get() (err, res, body) ->
+            try
+              xml = jsdom.jsdom(body)
+              for item in xml.getElementsByTagName("rss")[0].getElementsByTagName("channel")[0].getElementsByTagName("item")
+                do (item) ->
+                  link = item.getElementsByTagName("link")[0].childNodes[0].nodeValue
+                  title = item.getElementsByTagName("title")[0].childNodes[0].nodeValue
+                  hubotReply = " - #{title}, [#{link}]"
+                  msg.reply hubotReply
+            catch err
+                  msg.reply err


webapp/get_api_key: normal fullscreen to avoid being locked out in kiosk mode

--- src/smc-webapp/init_app.coffee
+++ src/smc-webapp/init_app.coffee
@@ -489,4 +489,4 @@
 get_api_key_query_value = QueryParams.get('get_api_key')
 if get_api_key_query_value
     redux.getActions('page').set_get_api_key(get_api_key_query_value)
-    redux.getActions('page').set_fullscreen('kiosk')
+    redux.getActions('page').set_fullscreen('default')


Draw pie if not there (even if data is the same)

--- admin/static/coffee/namespaces/namespace.coffee
+++ admin/static/coffee/namespaces/namespace.coffee
@@ -254,8 +254,7 @@
                 if not @json_in_memory[key]? or @json_in_memory[key] != json[key]
                     need_update = true
                     break
-
-            if need_update or force_render is true # Need is true since Machine is passed as an argument
+            if need_update or force_render is true or @.$('.pie_chart-data_in_memory').children().length is 0 # Need is true for force_render since Machine is passed as an argument
                 @json_in_memory = json
                 @.$('.data_in_memory-container').html @data_in_memory_template @json_in_memory

@@ -278,7 +277,7 @@
                     @.$('.pie_chart-data_in_memory > g').remove()
                     @.$('.loading_text-pie_chart').remove()

-                    arc = d3.svg.arc().innerRadius(0).outerRadius(r);
+                    arc = d3.svg.arc().innerRadius(0).outerRadius(r)
                     svg = d3.select('.pie_chart-data_in_memory').attr('width', width).attr('height', height).append('svg:g').attr('transform', 'translate('+width/2+', '+height/2+')')
                     arcs = svg.selectAll('path').data(d3.layout.pie().sort(null)(data_pie)).enter().append('svg:path').attr('fill', (d,i) -> color(i)).attr('d', arc)


nobody uses this file

nobody uses this file

--- src/stdlib/fuzzy-filter.coffee
+++ src/stdlib/fuzzy-filter.coffee
@@ -1,16 +0,0 @@
-stringScore = require 'stringscore'
-
-module.exports = (candidates, query, options) ->
-  if query
-    scoredCandidates = candidates.map (candidate) ->
-      string = if options.key? then candidate[options.key] else candidate
-      { candidate, score: stringScore(string, query) }
-
-    scoredCandidates.sort (a, b) ->
-      if a.score > b.score then -1
-      else if a.score < b.score then 1
-      else 0
-    candidates = (scoredCandidate.candidate for scoredCandidate in scoredCandidates when scoredCandidate.score > 0)
-
-  candidates = candidates[0...options.maxResults] if options.maxResults?
-  candidates


Removed commented-out code.

Removed commented-out code.

--- src/gearsketch_main.coffee
+++ src/gearsketch_main.coffee
@@ -821,12 +821,5 @@
   uploadBoard: ->
     boardJSON = JSON.stringify(@board)
     Util.sendPostRequest(boardJSON, "upload_board.php", ((event) => @boardUploaded(event)))
-#    request = new XMLHttpRequest()
-#    request.open("POST", "upload_board.php", true)
-#    request.setRequestHeader("Content-type", "application/json; charset=UTF-8")
-#    request.onload =
-#    request.send(boardJSON)
-
-

 window.gearsketch.GearSketch = GearSketch


only call forceReflow when has_touch_events

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -117,7 +117,8 @@
         # at the position it was set to at page unload
         header_fix = -> scrollTo(0, 0)

-        $(window).scroll -> forceReflow()
+        if has_touch_events
+            ($ window).scroll -> forceReflow()

         if gon.page is 'stores_show' or gon.page is 'products_index'


Add support for contentType

Add support for contentType

--- app/assets/javascripts/react/ajax_helper.coffee
+++ app/assets/javascripts/react/ajax_helper.coffee
@@ -9,13 +9,15 @@

   @request: (url, method, options={}) ->
     url = url.replace(/([^:]\/)\/+/g, "$1")
+    formattedData = if options['contentType'] then JSON.stringify(options['data']) else options['data']
     $.ajax
       url: url
       method: method
       headers:
         "X-Auth-Token": options['authToken'] if options['authToken']
       dataType: options['dataType'] || 'json'
-      data: options['data']
+      contentType: options['contentType'] || 'application/x-www-form-urlencoded'
+      data: formattedData
       success: options['success']
       error: options['error']
       complete: ( jqXHR, textStatus) ->