Removed individual coords for svg paths.

The different arrows aren't similar enough to justify breaking up the
paths like this. Now they are just strings.

--- coffeescripts/xwing.coffee
+++ coffeescripts/xwing.coffee
@@ -849,9 +849,6 @@

         outTable = "

"

-        viewWidth = 200
-        viewHeight = 200
-
         for speed in [maneuvers.length - 1 .. 0]

             haveManeuver = false
@@ -873,117 +870,56 @@
                         when 2 then "green"
                         when 3 then "red"

-                    outTable += """<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 #{viewWidth} #{viewHeight}">"""
+                    outTable += """<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">"""

                     if speed == 0
                         outTable += """<rect x="50" y="50" width="100" height="100" style="fill:#{color}" />"""
                     else

-                        # default values are for a straight line
-                        startx = 100
-                        starty = 180
-                        smoothx = 100
-                        smoothy = 100
-                        endx = 100
-                        endy = 80
-                        turnType = "S" # S = smooth, L = line, C = cubic bezier (for k-turn)
-                        extraPoint = "" # extra inflection point for cubic bezier
-
-                        arrowStartx = 70
-                        arrowStarty = 80
-                        arrowMove = "H130"
-                        arrowEndx = 100
-                        arrowEndy = 30
+                        outlineColor = "black"
+                        if maneuvers[speed][turn] != baseManeuvers[speed][turn]
+                          outlineColor = "gold" # highlight manuevers modified by another card (e.g. R2 Astromech makes all 1 & 2 speed maneuvers green)
+
                         transform = ""
-
                         switch turn
                             when 0
                                 # turn left
-                                startx = 160
-                                smoothx = 160
-                                smoothy = 70
-                                endx = 80
-                                endy = 70
-                                turnType = "L"
-
-                                arrowStartx = 80
-                                arrowStarty = 100
-                                arrowMove = "V40"
-                                arrowEndx = 30
-                                arrowEndy = 70
+                                linePath = "M160,180 L160,70 80,70"
+                                trianglePath = "M80,100 V40 L30,70 Z"

                             when 1
                                 # bank left
-                                startx = 150
-                                smoothx = 150
-                                smoothy = 120
-                                endx = 80
-                                endy = 60
-
-                                arrowStartx = 80
-                                arrowStarty = 100
-                                arrowMove = "V40"
-                                arrowEndx = 30
-                                arrowEndy = 70
+                                linePath = "M150,180 S150,120 80,60"
+                                trianglePath = "M80,100 V40 L30,70 Z"
                                 transform = "transform='translate(-5 -15) rotate(45 70 90)' "

-                            # when 2 # straight - this is the default value, don't need to do anything
+                            when 2
+                                # straight
+                                linePath = "M100,180 L100,100 100,80"
+                                trianglePath = "M70,80 H130 L100,30 Z"

                             when 3
                                 # bank right
-                                startx = 50
-                                smoothx = 50
-                                smoothy = 120
-                                endx = 120
-                                endy = 60
-
-                                arrowStartx = 120
-                                arrowStarty = 100
-                                arrowMove = "V40"
-                                arrowEndx = 170
-                                arrowEndy = 70
+                                linePath = "M50,180 S50,120 120,60"
+                                trianglePath = "M120,100 V40 L170,70 Z"
                                 transform = "transform='translate(5 -15) rotate(-45 130 90)' "

                             when 4
                                 # turn right
-                                startx = 40
-                                smoothx = 40
-                                smoothy = 70
-                                endx = 120
-                                endy = 70
-                                turnType = "L"
-
-                                arrowStartx = 120
-                                arrowStarty = 100
-                                arrowMove = "V40"
-                                arrowEndx = 170
-                                arrowEndy = 70
+                                linePath = "M40,180 L40,70 120,70"
+                                trianglePath = "M120,100 V40 L170,70 Z"

                             when 5
                                 # k-turn/u-turn
-                                startx = 50
-                                smoothx = 50
-                                smoothy = -10
-                                endx = 140
-                                endy = 120
-                                turnType = "C"
-                                extraPoint = "140,-10 "
-
-                                arrowStartx = 170
-                                arrowStarty = 120
-                                arrowMove = "H110"
-                                arrowEndx = 140
-                                arrowEndy = 180
-
-                        outlineColor = "black"
-                        if maneuvers[speed][turn] != baseManeuvers[speed][turn]
-                          outlineColor = "gold" # highlight manuevers modified by another card (e.g. R2 Astromech makes all 1 & 2 speed maneuvers green)
+                                linePath = "M50,180 C50,-10 140,-10 140,120"
+                                trianglePath = "M170,120 H110 L140,180 Z"

                         outTable += $.trim """
-                          <path d='M#{arrowStartx},#{arrowStarty} #{arrowMove} L#{arrowEndx},#{arrowEndy} Z' fill='#{color}' #{transform} stroke-width='5' stroke='#{outlineColor}' />
-                          <path stroke-width='25' fill='none' stroke='#{outlineColor}' d='M#{startx},#{starty} #{turnType}#{smoothx},#{smoothy} #{extraPoint}#{endx},#{endy}' />
-                          <path stroke-width='15' fill='none' stroke='#{color}' d='M#{startx},#{starty} #{turnType}#{smoothx},#{smoothy} #{extraPoint}#{endx},#{endy}' />
+                          <path d='#{trianglePath}' fill='#{color}' stroke-width='5' stroke='#{outlineColor}' #{transform}/>
+                          <path stroke-width='25' fill='none' stroke='#{outlineColor}' d='#{linePath}' />
+                          <path stroke-width='15' fill='none' stroke='#{color}' d='#{linePath}' />
                         """
+
                     outTable += "</svg>"
                 outTable += "	"
             outTable += "
"


Make goPrevious advanced to be consistent with goNext

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -110,7 +110,8 @@
   advancedCommands: [
     "scrollToLeft", "scrollToRight", "moveTabToNewWindow",
     "goUp", "goToRoot", "focusInput", "LinkHints.activateModeWithQueue",
-    "LinkHints.activateModeToOpenIncognito", "goNext", "Marks.activateCreateMode", "Marks.activateGotoMode"]
+    "LinkHints.activateModeToOpenIncognito", "goNext", "goPrevious", "Marks.activateCreateMode",
+    "Marks.activateGotoMode"]

 defaultKeyMappings =
   "?": "showHelp"


Removed part of FactsNewView

Removed part of FactsNewView

--- core/app/backbone/client/facts_new_view.coffee
+++ core/app/backbone/client/facts_new_view.coffee
@@ -1,55 +1,3 @@
-class window.FactsNewView extends Backbone.Marionette.Layout
-  _.extend @prototype, Backbone.Factlink.PopoverMixin
-
-  className: 'fact-new-container'
-
-  ui:
-    'post_factlink': '.js-submit-post-factlink'
-
-  events:
-    'click .js-submit-post-factlink': 'post_factlink',
-
-  regions:
-    learnMoreRegion: '.js-learn-more-region'
-    suggestedTopicsRegion: '.js-region-suggested-topics'
-    shareNewFactRegion: '.js-region-share-new-fact'
-
-  templateHelpers: ->
-    fact_text: @options.fact_text
-
-  initialize: ->
-    @addToCollection = new OwnChannelCollection
-
-  onRender: ->
-    @renderPersistentWheelView()
-
-    if Factlink.Global.signed_in
-      @renderAddToChannel()
-      @renderSuggestedChannels()
-      @renderShareNewFact()
-      @openOpinionHelptext()
-    else
-      @learnMoreRegion.show new LearnMoreView
-
-  onBeforeClose: ->
-    @closeOpinionHelptext()
-
-  renderAddToChannel: ->
-    addToChannelView = new AutoCompleteChannelsView collection: @addToCollection
-    addToChannelView.render()
-    addToChannelView.on 'error', ->
-      FactlinkApp.NotificationCenter.error "Something went wrong when creating a new #{Factlink.Global.t.topic}"
-    @$('.js-add-to-channels').html addToChannelView.el
-
-  renderSuggestedChannels: ->
-    suggested_topics = new SuggestedSiteTopics([], site_url: @options.url)
-    suggested_topics.fetch()
-
-    suggestionView = new FilteredSuggestedTopicsView
-      collection: suggested_topics
-      addToCollection: @addToCollection
-    @suggestedTopicsRegion.show suggestionView
-
   renderPersistentWheelView: ->
     @wheel = new FactVotes {}, fact: null
     persistentWheelView = new PersistentWheelView


render loading div

render loading div

--- core/app/backbone/views/activities_view.coffee
+++ core/app/backbone/views/activities_view.coffee
@@ -10,9 +10,18 @@
     @collection.on('reset', this.reset, this)
     @collection.on('add', this.add, this)
     @itemView = ActivityItemView
+    @collection.on 'startLoading stopLoading', => this.renderLoading()
+
+  renderLoading: ->
+    if this.collection._loading
+      this.$('div.loading').show()
+    else
+      this.$('div.loading').hide()
+

   render: ->
     super arguments
+    this.renderLoading()
     this.renderChildren()

   renderChildren: ->


Add spec for a crash case under Windows.

--- spec/pathwatcher-spec.coffee
+++ spec/pathwatcher-spec.coffee
@@ -108,3 +108,13 @@
         expect(path).toBe ''
         done()
       fs.renameSync(tempFile, newName)
+
+  describe 'when en exception is thrown in the closed watcher\'s callback', ->
+    it 'does not crash', (done) ->
+      watcher = pathWatcher.watch tempFile, (type, path) ->
+        watcher.close()
+        try
+          throw new Error('test')
+        catch e
+          done()
+      fs.writeFileSync(tempFile, '')


Adjust layout

Adjust layout

--- lib/about-view.coffee
+++ lib/about-view.coffee
@@ -6,8 +6,9 @@
     @div class: 'pane-item native-key-bindings about-atom', tabindex: -1, =>
       @div class: 'panel', =>
         @img class: 'atom-icon', src: 'atom://about/assets/atom.png'
-        @div class: 'atom-version', outlet: 'atomVersion'
-        @button outlet: 'copyAtomVersion', class: 'btn icon icon-clippy'
+        @div class: 'inline-block', =>
+          @div class: 'atom-version', outlet: 'atomVersion'
+          @button outlet: 'copyAtomVersion', class: 'btn icon icon-clippy'
         @div class: 'credits', outlet: 'credits', =>
           @span class: 'icon icon-code'
           @span class: 'inline', ' with '


Add APIResults::aggregatedBy.

Add APIResults::aggregatedBy.

Same as APIResults::aggregateBy but with a verb tense consistent with the other methods that return a new APIResults instance. (Past-tense for new instances, present-tense for in-place operations.)

--- compiler/ContentAPI.coffee
+++ compiler/ContentAPI.coffee
@@ -169,7 +169,8 @@
             @[item.id] = item if item.id

-    aggregateBy: (property) ->
+    aggregateBy: -> @aggregatedBy(arguments...)
+    aggregatedBy: (property) ->
         result = {}
         @_items.forEach (item) ->
             if item[property]?


Update constructors and remove used instance methods

--- routes/item.coffee
+++ routes/item.coffee
@@ -5,20 +5,18 @@
   constructor: (@_id, @name, @status, @type, @link, @description, @date, @technologies, @images) ->
     super(@_id, @name, @status, @type, @link, @description)
     @itemType = 'item'
+    @partOfTeam = null
     @collection = []

   setCollection: (collection) ->
     collection.addItem(@_id)
     if !@collection.includes(collection._id) then @collection.push(collection._id)

-  setTeam: (team) ->
-    @team = team._id
-    team.addItem(@_id)
-
 class collection extends baseItem
   constructor: (@_id, @name, @status, @type, @link, @description, @image, @hasItems, @showcase) ->
     super(@_id, @name, @status, @type, @link, @description)
     @itemType = 'collection'
+    @partOfTeam = null
     if !@hasItems
       @hasItems = []

@@ -29,21 +27,13 @@
     team.addCollection(@_id)

 class team
-  constructor: (@_id, @name, @logo, @members, @site, @description) ->
+  constructor: (@_id, @name, @logo, @site, @description, @showcase, @members) ->
     @itemType = 'team'
     @hasItems = []
     @hasCollections = []

-  addMember: (members) ->
-    console.log(members, typeof(members))
-    if typeof(members) == 'object'
-      for member in members
-        @members.push(member)
-    else
-      @members.push(members)
-
-  addItem: (items) ->
-    @hasItems.push(items)
+  addItem: (item) ->
+    @hasItems.push(item)

   addCollection: (collection) ->
     @hasCollections.push(collection)


text shortener simplified

text shortener simplified

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemDiscussion.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemDiscussion.coffee
@@ -59,21 +59,17 @@
     # FIXME: 500 chars is a naive separation, check if it is in a tag ( etc) and
     # make the separation after or before the tag in plain text.

+    @shortenedText str
+
+  shortenedText: (str)->
+
     if str.length > 500
       visiblePart = str.substr 0, 500
-      morePart = "show more...#{str.substr 501}...show less"
-      str = visiblePart + morePart
+      # this breaks the markdown sanitizer
+      # morePart = "show more...#{str.substr 501}...show less"
+      str = visiblePart  + " ..." #+ morePart

     return str
-
-  shortenedText: (text)->
-
-    log text
-
-    if text.length>400
-      return text.substr(0,400)+" ..."
-    else
-      return text

   pistachio:->
     """


Timeline: don't need to reset elapsed time on stop

--- components/Timeline.coffee
+++ components/Timeline.coffee
@@ -64,7 +64,6 @@
     @outPorts.started.disconnect()

   stop: () ->
-    @elapsedTime = 0
     @running = false
     return unless @outPorts.stopped.isAttached()
     @outPorts.stopped.send(true)


redirect browsers to target when showing tags

--- routes/tags.coffee
+++ routes/tags.coffee
@@ -35,4 +35,7 @@
       return res.failed '/', err.message,
         status: Errors.statusFor err
     else
-      return res.reply "tags/tag", {tag}
+      if /^json/.test req.param 'format'
+        return res.reply 'tags/tag', {tag}
+      else
+        return res.redirect "#{tag.targetType}s/#{tag.targetSha1}"


put domain into popup for user info

put domain into popup for user info

--- services/web/public/coffee/UserDetailsUpdater.coffee
+++ services/web/public/coffee/UserDetailsUpdater.coffee
@@ -46,7 +46,8 @@

 		$scope.updateInstitutionsList = (a)->
 			Institutions.search $scope.userInfoForm.institution, (err, response)->
-				$scope.institutions = _.pluck response.hits, "name"
+				$scope.institutions = _.map response.hits, (institution)->
+					"#{institution.name} #{institution.domain}"


IMPROVED: Element.inspectedObjects works with complex prop values

--- source/Art/Engine/Core/Element.coffee
+++ source/Art/Engine/Core/Element.coffee
@@ -52,7 +52,8 @@
   isArray
   formattedInspect
   object
-} = require 'art-standard-lib'
+  toInspectedObjects
+} = require './StandardImport'

 stats = clone zeroedStats =
   stagingBitmapsCreated: 0
@@ -1294,7 +1295,7 @@
     inspectedObjects: ->
       [
         inspectedObjectLiteral @inspectedName
-        @minimalProps
+        toInspectedObjects @minimalProps
       ].concat (child.inspectedObjects for child in @children)

   childrenWithout = (children, child) ->


remove zombie

remove zombie

--- test/config.coffee
+++ test/config.coffee
@@ -8,8 +8,8 @@
 global.test   = it
 global.sinon  = require 'sinon'
 global.async  = require 'async'
-global.Browser  = require 'zombie'
-global.browser  = new Browser
+#global.Browser  = require 'zombie'
+#global.browser  = new Browser

 global.spec =
   startDatabase: ->


Grid lines

Grid lines

--- source/javascripts/win-loss.js.coffee
+++ source/javascripts/win-loss.js.coffee
@@ -17,7 +17,7 @@
       break
   isEmpty

-isGrandSlam = -> false
+isGrandSlam = -> true

 getData = (result) ->
   if isGrandSlam() then result.gs_data else result.data
@@ -33,7 +33,7 @@

 hGridData = ->
   if isGrandSlam()
-    [0, 10, 20, 30, .4, .5, .6, .7, .8, .9, 1]
+    [0, 5, 10, 15, 20, 25, 30, .4, .5, .6, .7, .8, .9, 1]
   else
     [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, .6, .7, .8, .9, 1]

@@ -86,16 +86,17 @@
     .append('g')
     .attr('class', 'h-grid');

+  hGridY = (d) -> y(if d > 1 then d else d * 100)
   hGrid.append('line')
     .attr('x1', (d, i) -> 0)
-    .attr('y1', (d, i) -> y(i * 10))
+    .attr('y1', hGridY)
     .attr('x2', (d, i) -> width)
-    .attr('y2', (d, i) -> y(i * 10))
+    .attr('y2', hGridY)

   hGrid.append('text')
     .text((d, i) -> if 0 < d <= 1 then d3.format('%d')(d) else d)
     .attr('x', (d, i) -> -5)
-    .attr('y', (d, i) -> y(i * 10))
+    .attr('y', hGridY)
     .attr('text-anchor', 'end')

   for result, playerIndex in results


load editors only in browser

load editors only in browser

--- modules/gui/lib/editor/ContentAdapter.coffee
+++ modules/gui/lib/editor/ContentAdapter.coffee
@@ -18,9 +18,9 @@
         ##
         ##
         ##
-        wire: (done)->
+        start: (done)->
             super (err)=>
-                return done(err) if err
+                return done(err) if err || floyd.system.platform isnt 'remote'

                 @_loadUser (err, user)=>
                     @_adapt @parent, user, done


color2

--- test/color2.coffee
+++ test/color2.coffee
@@ -1,408 +0,0 @@
-( ->
-
-equalEnough = (actual, expected, tolerance=3, message) ->
-  message ||= "" + expected + " within " + tolerance + " of " + actual
-  ok(expected + tolerance >= actual && expected - tolerance <= actual, message)
-
-module "Color"
-
-test "r, g, b default to 0, a defaults to 1", ->
-  color = Color()
-
-  equalEnough color.r, 0
-  equalEnough color.g, 0
-  equalEnough color.b, 0
-  equalEnough color.a, 1
-
-test "accepts a single array of length 3", ->
-  color = Color([255, 1, 2])
-
-  equalEnough color.r, 255
-  equalEnough color.g, 1
-  equalEnough color.b, 2
-
-test "accepts a single array of length 4", ->
-  color = Color([255, 4, 3, 0.8])
-
-  equalEnough color.r, 255
-  equalEnough color.g, 4
-  equalEnough color.b, 3
-  equalEnough color.a, 0.8
-
-test "accepts an array of length 3 as the first argument and an alpha value as the second", ->
-  color = Color([100, 5, 3], 0.4)
-
-  equalEnough color.r, 100
-  equalEnough color.g, 5
-  equalEnough color.b, 3
-  equalEnough color.a, 0.4
-
-test "accepts an array of length 4 as the first argument and an alpha value. The alpha value passed as the second argument overrides the alpha in the array", ->
-  color = Color([4, 20, 90, 0.1], 0.6)
-
-  equalEnough color.r, 4
-  equalEnough color.g, 20
-  equalEnough color.b, 90
-  equalEnough color.a, 0.6
-
-test "accepts an rgb string as the first argument and an alpha value as the second", ->
-  color = Color('rgb(255, 40, 30)', 0.4)
-
-  equalEnough color.r, 255
-  equalEnough color.g, 40
-  equalEnough color.b, 30
-  equalEnough color.a, 0.4
-
-test "accepts an rgba string as the first argument and an alpha value as the second. The alpha value takes precedence over the alpha from the rgba string", ->
-  color = Color('rgba(30, 20, 15, 0.8)', 0.35)
-
-  equalEnough color.r, 30
-  equalEnough color.g, 20
-  equalEnough color.b, 15
-  equalEnough color.a, 0.35
-
-test "accepts an hsl string as the first argument and an alpha value as the second", ->
-  color = Color('hsl(63, 0.4, 0.3)', 0.21)
-
-  equalEnough color.r, 104
-  equalEnough color.g, 107
-  equalEnough color.b, 46
-  equalEnough color.a, 0.21
-
-test "accepts an hsla string as the first argument and an alpha value as the second. The alpha value takes precedence over the hsla string alpha value", ->
-  color = Color('hsla(45, 0.3, 0.5, 0.1)', 0.47)
-
-  equalEnough color.r, 166
-  equalEnough color.g, 147
-  equalEnough color.b, 89
-  equalEnough color.a, 0.47
-
-test "accepts hex value of length 3 as first argument and alpha value as second argument", ->
-  color = Color('#ff0', 0.5)
-
-  equalEnough color.r, 255
-  equalEnough color.g, 255
-  equalEnough color.b, 0
-  equalEnough color.a, 0.5
-
-test "accepts hex value of length 4 as first argument and alpha value as second argument. The alpha value takes precedence over the alpha from the hex string.", ->
-  color = Color('#ef3c', 0.3)
-
-  equalEnough color.r, 238
-  equalEnough color.g, 255
-  equalEnough color.b, 51
-  equalEnough color.a, 0.3
-
-test "accepts hex value of length 6 as first argument and alpha value as second argument", ->
-  color = Color('#de34ab', 0.27)
-
-  equalEnough color.r, 222
-  equalEnough color.g, 52
-  equalEnough color.b, 171
-  equalEnough color.a, 0.27
-
-test "accepts hex value of length 8 as first argument and alpha value as second argument. Alpha value takes precedence over hex alpha.", ->
-  color = Color('#ab45cd', 0.59)
-
-  equalEnough color.r, 171
-  equalEnough color.g, 69
-  equalEnough color.b, 205
-  equalEnough color.a, 0.59
-
-test "accepts hex string of length 3", ->
-  color = Color('#df2')
-
-  equalEnough color.r, 221
-  equalEnough color.g, 255
-  equalEnough color.b, 34
-  equalEnough color.a, 1.0
-
-test "accepts hex string of length 4", ->
-  color = Color('#c987')
-
-  equalEnough color.r, 204
-  equalEnough color.g, 153
-  equalEnough color.b, 136
-  equalEnough color.a.toFixed(2), 0.47
-
-test "accepts hex string of length 6", ->
-  color = Color('#cdef12')
-
-  equalEnough color.r, 205
-  equalEnough color.g, 239
-  equalEnough color.b, 18
-  equalEnough color.a, 1.0
-
-test "accepts hex string of length 8", ->
-  color = Color('#ef1234af')
-
-  equalEnough color.r, 239
-  equalEnough color.g, 18
-  equalEnough color.b, 52
-  equalEnough color.a.toFixed(2), 0.69
-
-test "accepts 3 numeric values", ->
-  color = Color(34, 54, 39)
-
-  equalEnough color.r, 34
-  equalEnough color.g, 54
-  equalEnough color.b, 39
-  equalEnough color.a, 1.0
-
-test "accepts 4 numeric values", ->
-  color = Color(23, 43, 100, 0.32)
-
-  equalEnough color.r, 23
-  equalEnough color.g, 43
-  equalEnough color.b, 100
-  equalEnough color.a, 0.32
-
-test "invalid color throws error", ->
-  raises ->
-    Color("A Fake Color")
-
-test "#copy", ->
-  color = Color(123, 231, 2)
-  copiedColor = color.copy()
-
-  ok color.equal(copiedColor)
-  ok color != copiedColor
-
-test "#equal", ->
-  color1 = Color(255, 255, 255, 1)
-  color2 = Color([255, 255, 255])
-
-  ok color1.equal(color2)
-
-test "#toString", ->
-  noAlpha = Color(30, 40, 23)
-  withAlpha = Color(29, 49, 50, 0.45)
-  decimalValues = Color(34.7, 52.2, 50.1, 0.45)
-
-  equal noAlpha.toString(), "rgba(30, 40, 23, 1)"
-  equal withAlpha.toString(), "rgba(29, 49, 50, 0.45)"
-  equal decimalValues.toString(), "rgba(35, 52, 50, 0.45)"
-
-test "#toHex", ->
-  color = Color(23, 45, 100)
-
-  equal color.toHex(), "#172d64"
-
-test "#toHsl", ->
-  color = Color(45, 29, 20)
-
-  hsl = color.toHsl()
-
-  equalEnough hsl[0].round(), 22
-  equalEnough hsl[1].toFixed(2), 0.38
-  equalEnough hsl[2].toFixed(2), 0.13
-  equalEnough hsl[3], 1.0
-
-test "#hue", ->
-  color = Color(34, 54, 239).hue(20)
-
-  equalEnough color.r, 84
-  equalEnough color.g, 37
-  equalEnough color.b, 239
-  equalEnough color.a, 1.0
-
-test "#hue$", ->
-  color = Color(34, 54, 239)
-
-  color.hue$(60)
-
-  equalEnough color.r, 218
-  equalEnough color.g, 37
-  equalEnough color.b, 239
-  equalEnough color.a, 1.0
-
-test "#complement", ->
-  color = Color(10, 30, 50).complement()
-
-  equalEnough color.r, 51
-  equalEnough color.g, 31
-  equalEnough color.b, 10
-  equalEnough color.a, 1.0
-
-test "#complement$", ->
-  color = Color(10, 30, 50)
-
-  color.complement$()
-
-  equalEnough color.r, 51
-  equalEnough color.g, 31
-  equalEnough color.b, 10
-  equalEnough color.a, 1.0
-
-test "#grayscale", ->
-  color = Color(30, 40, 29).grayscale()
-
-  equalEnough color.r, 35
-  equalEnough color.g, 35
-  equalEnough color.b, 35
-  equalEnough color.a, 1.0
-
-test "#grayscale$", ->
-  color = Color(30, 40, 29)
-
-  color.grayscale$()
-
-  equalEnough color.r, 35
-  equalEnough color.g, 35
-  equalEnough color.b, 35
-  equalEnough color.a, 1.0
-
-test "#saturate", ->
-  color = Color(100, 200, 150).saturate(0.3)
-
-  equalEnough color.r, 69
-  equalEnough color.g, 232
-  equalEnough color.b, 150
-  equalEnough color.a, 1.0
-
-test "#saturate$", ->
-  color = Color(100, 200, 150)
-
-  color.saturate$(0.3)
-
-  equalEnough color.r, 69
-  equalEnough color.g, 232
-  equalEnough color.b, 150
-  equalEnough color.a, 1.0
-
-test "#desaturate", ->
-  color = Color(69, 232, 150).desaturate(0.3)
-
-  equalEnough color.r, 100
-  equalEnough color.g, 200
-  equalEnough color.b, 150
-  equalEnough color.a, 1.0
-
-test "#desaturate$", ->
-  color = Color(69, 232, 150)
-
-  color.desaturate$(0.3)
-
-  equalEnough color.r, 100
-  equalEnough color.g, 200
-  equalEnough color.b, 150
-  equalEnough color.a, 1.0
-
-test "#darken", ->
-  color = Color(45, 64, 39).darken(0.1)
-
-  equalEnough color.r, 22
-  equalEnough color.g, 32
-  equalEnough color.b, 19
-  equalEnough color.a, 1.0
-
-test "#darken$", ->
-  color = Color(45, 64, 39)
-
-  color.darken$(0.1)
-
-  equalEnough color.r, 22
-  equalEnough color.g, 32
-  equalEnough color.b, 19
-  equalEnough color.a, 1.0
-
-test "#lighten", ->
-  color = Color(22, 32, 19).lighten(0.1)
-
-  equalEnough color.r, 45
-  equalEnough color.g, 64
-  equalEnough color.b, 39
-  equalEnough color.a, 1.0
-
-test "#lighten$", ->
-  color = Color(22, 32, 19)
-
-  color.lighten$(0.1)
-
-  equalEnough color.r, 45
-  equalEnough color.g, 64
-  equalEnough color.b, 39
-  equalEnough color.a, 1.0
-
-test "#mixWith", ->
-  color1 = Color(50, 40, 60, 0.3)
-  color2 = Color(10, 5, 16, 0.2)
-
-  mixedColor = color1.mixWith(color2)
-
-  equalEnough mixedColor.r, 30
-  equalEnough mixedColor.g, (45 / 2).round()
-  equalEnough mixedColor.b, (76 / 2).round()
-  equalEnough mixedColor.a, 0.5 / 2
-
-  weightedMixedColor = color1.mixWith(color2, 0.1)
-
-  equalEnough weightedMixedColor.r, ((50 * 0.1) + (10 * 0.9)).round()
-  equalEnough weightedMixedColor.g, ((40 * 0.1) + (5 * 0.9)).round()
-  equalEnough weightedMixedColor.b, ((60 * 0.1) + (16 * 0.9)).round()
-  equalEnough weightedMixedColor.a, (0.3 * 0.1) + (0.2 * 0.9)
-
-test "#mixWith$", ->
-  color1 = Color(50, 40, 60, 0.3)
-  color2 = Color(10, 5, 16, 0.2)
-
-  color3 = Color(50, 40, 60, 0.3)
-
-  color1.mixWith$(color2)
-
-  equalEnough color1.r, 30
-  equalEnough color1.g, (45 / 2).round()
-  equalEnough color1.b, (76 / 2).round()
-  equalEnough color1.a, 0.5 / 2
-
-  color3.mixWith$(color2, 0.1)
-
-  equalEnough color3.r, ((50 * 0.1) + (10 * 0.9)).round()
-  equalEnough color3.g, ((40 * 0.1) + (5 * 0.9)).round()
-  equalEnough color3.b, ((60 * 0.1) + (16 * 0.9)).round()
-  equalEnough color3.a, (0.3 * 0.1) + (0.2 * 0.9)
-
-test "Color.random", ->
-  color = Color.random()
-
-  ok 0 <= color.r <= 255
-  ok 0 <= color.g <= 255
-  ok 0 <= color.b <= 255
-  equalEnough color.a, 1.0
-
-test "Color.mix", ->
-  mixedColor = Color.mix(
-    Color("red"),
-    Color("sky blue")
-  )
-
-  equalEnough mixedColor.r, 173
-  equalEnough mixedColor.g, 94
-  equalEnough mixedColor.b, 127
-  equalEnough mixedColor.a, 1
-
-  weightedMixedColor = Color.mix(Color(0, 255, 0, 1), Color(255, 0, 255, 0.6), 0.1)
-
-  equalEnough weightedMixedColor.r, ((0 * 0.1) + (255 * 0.9)).round()
-  equalEnough weightedMixedColor.g, ((255 * 0.1) + (0 * 0.9)).round()
-  equalEnough weightedMixedColor.b, ((0 * 0.1) + (255 * 0.9)).round()
-  equalEnough weightedMixedColor.a, (1 * 0.1) + (0.6 * 0.9)
-
-test "accepts named colors", ->
-  white = Color("white")
-
-  equalEnough white.r, 255
-  equalEnough white.g, 255
-  equalEnough white.b, 255
-  equalEnough white.a, 1.0
-
-  piPink = Color("Paul Irish Pink")
-
-  equalEnough piPink.r, 255
-  equalEnough piPink.g, 94
-  equalEnough piPink.b, 153
-  equalEnough piPink.a, 1.0
-
-module()
-
-)()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine.coffee
+++ test/engine.coffee
@@ -187,7 +187,7 @@

   engine.setState nextState

-  # Test state change event
+  # Test state change events
   engine.bind "stateEntered", ->
     ok true
   engine.bind "stateExited", ->


Fix tests

Fix tests

--- test/google.coffee
+++ test/google.coffee
@@ -34,8 +34,8 @@
     profile =
       sub: 'profile_id'
       email: 'user@example.com'
-      first_name: 'my_first_name'
-      last_name: 'my_last_name'
+      given_name: 'my_first_name'
+      family_name: 'my_last_name'
       birthday: new Date()
       gender: 'male'

@@ -95,7 +95,7 @@
         expect(err).to.not.exist
         expect(found).to.exist
         expect(found.google).to.eql profile.sub
-        expect(found.firstName).to.eql profile.first_name
-        expect(found.lastName).to.eql profile.last_name
+        expect(found.firstName).to.eql profile.given_name
+        expect(found.lastName).to.eql profile.family_name
         expect(found.gender).to.eql profile.gender
         done err


KodingKite: queue up maximum 5 waiting calls

--- client/Main/kite/kodingkite.coffee
+++ client/Main/kite/kodingkite.coffee
@@ -3,6 +3,7 @@
   { @Error } = require 'kite'

   [DISCONNECTED, CONNECTED] = [0, 1]
+  MAX_QUEUE_SIZE = 5

   constructor: (options) ->
     super options
@@ -117,6 +118,7 @@

     new Promise (resolve, reject)=>
       return resolve args if @_state is CONNECTED
+      return reject()  if @waitingCalls.length >= MAX_QUEUE_SIZE

       cid = (@waitingCalls.push args) - 1


client: send a request for collaboration when collab route is hit

--- client/app/lib/routehandler.coffee
+++ client/app/lib/routehandler.coffee
@@ -8,6 +8,7 @@
 lazyrouter     = require './lazyrouter'
 registerRoutes = require './util/registerRoutes'
 isKoding       = require './util/isKoding'
+whoami         = require './util/whoami'

 Machine                 = require 'app/providers/machine'
 EnvironmentsModal       = require 'app/environment/environmentsmodal'
@@ -114,6 +115,10 @@
       { stackId } = info.params
       new EnvironmentsModal selected: stackId

+    when 'request-collaboration' then
+      { nickname, channelId } = info.params
+      requestCollaboration {nickname, channelId}
+
     when 'machine-settings'
       { uid, state } = info.params
       { computeController, router } = kd.singletons
@@ -134,3 +139,18 @@
       { router } = kd.singletons
       router.handleRoute "/Account/Email?unsubscribe=#{opt}"

+
+requestCollaboration = ({nickname, channelId})->
+
+  whoami().pushNotification
+    receiver: nickname
+    channelId: channelId
+    action: 'COLLABORATION_REQUEST'
+  , (err) ->
+    # FIXME: better error message
+    return new kd.NotificationView title: 'There is an error'  if err
+
+    new kd.NotificationView title: 'Collaboration request sent.'
+    kd.singletons.router.back()
+
+


a object

a object

--- test/nodify.coffee
+++ test/nodify.coffee
@@ -8,8 +8,8 @@
   it 'should exist', ->
     should.exist Nodify

-  it 'should be an object', ->
-    Nodify.should.be.an 'object'
+  it 'should be a object', ->
+    Nodify.should.be.a 'object'

   describe 'Nodify.Client', ->


Mentioned artists/artworks

Mentioned artists/artworks

--- client/collections/sections.coffee
+++ client/collections/sections.coffee
@@ -14,8 +14,7 @@
         when 'image_set'
           _.map section.images, (image) ->
             if image.type is 'artwork' and image.artists
-              _.map image.artists, (artist) ->
-                artist.id
+              _.map image.artists, (artist) -> artist.id

   mentionedArtworkSlugs: ->
     _.compact _.flatten @map (section) ->


Add dispose() handling for geyser nodes.

--- client/src/scripts/knockout.coffee
+++ client/src/scripts/knockout.coffee
@@ -55,6 +55,8 @@
         if data.behaviors
           for behavior in data.behaviors
             behavior $element
+          if data.dispose
+            ko.utils.domNodeDisposal.addDisposeCallback element, -> data.dispose()
       else
         $element.html geyser.render data
     else


Get origin remote, not zach

Get origin remote, not zach

This was leftover from testing

--- scripts/git.coffee
+++ scripts/git.coffee
@@ -63,7 +63,7 @@
       callback oid

   push: (repo, ref, callback) ->
-    repo.getRemote 'zach'
+    repo.getRemote 'origin'
     .then (remote) ->
       pushOpts = callbacks: credentials: ssh
       remote.push ["#{ref}:#{ref}"], pushOpts


Set read:true

Set read:true

--- tests/integrated.coffee
+++ tests/integrated.coffee
@@ -44,9 +44,7 @@
     it "The file should be compiled properly", (done) ->
       compilationDefer = q.defer()
       g.src(
-        "./tests/data/single/source.scss", (
-          "read": false
-        )
+        "./tests/data/single/source.scss"
       ).pipe(
         sourcemaps.init()
       ).pipe(
@@ -124,8 +122,6 @@
           "./tests/data/multiple",
           gutil.replaceExtension(file, ".scss")
         ) for file in targetFiles
-      ), (
-        "read": false
       )).pipe(
         sourcemaps.init()
       ).pipe(
@@ -203,9 +199,7 @@
     it "The files should be compiled properly", (done) ->
       defer = q.defer()
       g.src(
-        "./tests/data/glob/**/*.scss", (
-          "read": false
-        )
+        "./tests/data/glob/**/*.scss"
       ).pipe(
         sourcemaps.init()
       ).pipe(
@@ -278,9 +272,7 @@
     it "The code should be compiled properly", (done) ->
       defer = q.defer()
       g.src(
-        "./tests/data/imports/main.scss", (
-          "read": false
-        )
+        "./tests/data/imports/main.scss"
       ).pipe(
         sourcemaps.init()
       ).pipe(


Expand CoffeeScript object example

Expand CoffeeScript object example

--- coffeescript/object_example.coffee
+++ coffeescript/object_example.coffee
@@ -4,3 +4,5 @@
     x: 5
     y: 4
   color: 'green'
+  thickness: 2
+  lineStyle: 'dashed'


handle existing users better

handle existing users better

--- server/rest.coffee
+++ server/rest.coffee
@@ -13,13 +13,14 @@
     post: (data) ->
       @setContentType "application/json"
       data = bufferToJSON(data)
+      data.profile.email = data.email

-      unless @query.authToken and @query.authToken is process.env["REST_SECRET_KEY"]
+      unless @query.authToken and @query.authToken is (process.env["REST_SECRET_KEY"] || "jUOwlepEtiGHudRzcIpZq")
         @setStatusCode 401
         return EJSON.stringify(message: "Unauthorized. Give a valid authToken as a parameter.")

-      if existingUser = Meteor.users.findOne(email: data.email)
-        Users.update(existingUser._id, {$set: data})
+      if existingUser = Meteor.users.findOne(email: data.email) || existingUser = Meteor.users.findOne(username: data.username)
+        Meteor.users.update(existingUser._id, {$set: data})
         return EJSON.stringify existingUser

       id = Accounts.createUser(data)


Small fix with error log in dash.coffee.

--- source/dash.coffee
+++ source/dash.coffee
@@ -112,6 +112,6 @@

             # Handle warnings and errors
             console.warn( res.message )  if res.status is Status.warning
-            console.error( res.message ) if res.statis is Status.error
+            console.error( res.message ) if res.status is Status.error

 module.exports = Dash


Fix JS bug

Fix JS bug

--- app/assets/javascripts/store/variants_prodline.js.coffee
+++ app/assets/javascripts/store/variants_prodline.js.coffee
@@ -1,4 +1,4 @@
 $ ->
   Spree.updateVariantPrice = (variant) ->
     variantPrice = variant.data('price')
-    ($ '.price.selling').first.text(variantPrice) if variantPrice+    ($ '.price.selling')[0].text(variantPrice) if variantPrice


alert screenreader on close discussion reply

fixes CNVS-29499

Test Plan
in Firefox with NVDA on, navigate to a discussion with a reply
Move focus to the Collapse bar at the top of a reply.
Press Enter and note that, while the reply does collapse, the SR
is notified.

Change-Id: I65efaf7c4259b46d7978098ec068cc59ade77913
Reviewed-on: https://gerrit.instructure.com/83246
Reviewed-by: Felix Milea-Ciobanu <9384aa226ac9d3237ed0bc52e18ffcb251ee0bf7@instructure.com>
Tested-by: Jenkins
Product-Review: Steven Burnett <a0b450117c5d20a22d5c4d52bb8ae13adee003d8@instructure.com>
QA-Review: Steven Burnett <a0b450117c5d20a22d5c4d52bb8ae13adee003d8@instructure.com>

--- app/coffeescripts/views/DiscussionTopic/EntryView.coffee
+++ app/coffeescripts/views/DiscussionTopic/EntryView.coffee
@@ -123,6 +123,7 @@
       @addCountsToHeader() unless @addedCountsToHeader
       @$el.toggleClass 'collapsed'
       if @$el.hasClass('collapsed')
+        $.screenReaderFlashMessageExclusive(I18n.t('Subdiscussion collapsed'))
         $el.attr('title', I18n.t('Expand Subdiscussion'))
         $el.find('.screenreader-only').text(I18n.t('Expand Subdiscussion'))
       else


pandoc cayw

pandoc cayw

--- chrome/content/zotero-better-bibtex/web-endpoints.coffee
+++ chrome/content/zotero-better-bibtex/web-endpoints.coffee
@@ -266,7 +266,7 @@
           cite = ''
           cite += "#{item.prefix} " if item.prefix
           cite += '-' if item['suppress-author']
-          cite += "@#{citekey.citekey}
+          cite += "@#{citekey.citekey}"
           cite += ", #{item.locator}" if item.locator
           cite += " #{item.suffix}" if item.suffix
           citation.push(cite)


Parentheses aren't needed

Parentheses aren't needed

--- app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_search_inputs.jsx.coffee
+++ app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_search_inputs.jsx.coffee
@@ -73,7 +73,7 @@
     if @isMultilingual()
       `<button className="btn" style={{marginLeft: 20}} onClick={this.props.handleAddLanguage}>Add language</button>`

-  searchButton: () ->
+  searchButton: ->
     marginLeft = if @isMultilingual() then 80 else 40  # adjust position relative to the language select
     `<button type="button" className="btn btn-success"
         style={{marginLeft: marginLeft}} onClick={this.props.handleSearch}>Search</button>`
@@ -105,7 +105,7 @@
     else
       `<a href="" title={title} onClick={onClick}>{name}</a>`

-  searchInputLinks: () ->
+  searchInputLinks: ->
     `<div className="row-fluid search-input-links">
       {this.searchInput("Simple", "Simple search box", this.showSimple, "simple")} |
       {this.searchInput("Extended", "Search for grammatical categories etc.", this.showMultiword, "multiword")} |


This stuff is just on the user

This stuff is just on the user

--- components/inquiry_questionnaire/views/basic_info.coffee
+++ components/inquiry_questionnaire/views/basic_info.coffee
@@ -15,13 +15,7 @@
     e.preventDefault()
     form.state 'loading'

-    @user.set form.data()
-    @user.related().collectorProfile.setWithValidAttributes @user.attributes
-
-    $.when.apply(null, [
-      @user.save()
-      @user.related().collectorProfile.save()
-    ])
+    @user.save(form.data())
       .always => @next()

   postRender: ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -1,5 +1,5 @@
 ###*
-The TimedEvents module allows
+The TimedEvents module allows arbi

 player = Core


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -19,6 +19,7 @@

 @name overlay
 @methodOf TitleScreen#
+@param
 @event
 ###
 TitleScreen = (I={}) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Title Screen class sets up a simple
+The Title Screen class sets up a simple game title sc

 By default, images are loaded asynchronously. A proxy object is
 returned immediately. Even though it has a draw method it will not


output cell is pure

output cell is pure

--- app/notebook.coffee
+++ app/notebook.coffee
@@ -229,7 +229,7 @@

 OutputCellComponent = React.createIdentityClass
   displayName: 'OutputCellComponent'
-  mixins: [React.ObservableMixin]
+  mixins: [React.ObservableMixin, React.addons.PureRenderMixin]
   get_observable: -> @props.cell.component_model
   render: -> React.DOM.div {className: 'cell output', 'data-cell-number': @props.cell.number}, @state.value
   componentDidMount: ->


Inbounds

Inbounds

--- src/torconnections.iced
+++ src/torconnections.iced
@@ -51,8 +51,8 @@
     @destinationIP = @destination.split(":")[0]
     @destinationPort = @destination.split(":")[1]
     @geo = geoip.lookup(@destinationIP)
-    if @destinationPort in exit_policy and @originIP is myIP
-      @connectionType=connectiontypes[1] #Exit
+    if @destinationIP is myIP
+      @connectionType=connectiontypes[0] #Exit
     else
       @connectionType=connectiontypes[2]

@@ -62,22 +62,22 @@
   pollConnections : (callback) =>
     await
       child = exec fileDescriptorCommand, defer error, stdout, stderr
-    # @parse cmdsample
-    if stdout?
-      console.log stdout
-      @parse stdout
-      callback "OK"
-      return
-    else if error?
-      console.log error
-      resString = "error: " + error
-      callback resString
-      return
-    else if stderr?
-      console.log stderr
-      resString = "stderr: " + stderr
-      callback resString
-      return
+    @parse cmdsample
+    # if stdout?
+    #   # console.log stdout
+    #   @parse stdout
+    #   callback "OK"
+    #   return
+    # else if error?
+    #   # console.log error
+    #   resString = "error: " + error
+    #   callback resString
+    #   return
+    # else if stderr?
+    #   # console.log stderr
+    #   resString = "stderr: " + stderr
+    #   callback resString
+    #   return

   parse : (str) =>
     resArray = str.split("\n")


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -28,6 +28,6 @@
   fastEnemy.include(Follow)
   fastEnemy.follow(player)

-  ok fastEnemy.I.velocity.equal(Point(0, -5)), 'fastEnemy should head up'
+  ok fastEnemy.I.velocity.equal(Point(0, -5)), 'fastEnemy should head toward '

 module()


Replace \r in story with <br/>.

Replace \r in story with <br/>.

--- assets/front.coffee
+++ assets/front.coffee
@@ -262,6 +262,8 @@
 						length = segment.tracks[0].metadata.length
 						if segment.tracks[0].metadata.story
 							story = segment.tracks[0].metadata.story
+							#TODO do this using .split and join
+							story = story.replace(/\r?\n|\r+|\r/g, "<br/>");
 						else
 							story = "This one is still a mystery. Please let us know if you can solve."
 						minutes = Math.floor(length/60)


fix gulp format errors

fix gulp format errors

--- tasks/tests.coffee
+++ tasks/tests.coffee
@@ -85,9 +85,9 @@
     fs.removeSync(options.env.EXITCODE_PATH)
     if code != 0
       if _.contains(process.argv, '--appveyor')
-        return cb('Mocha returned an error, and it\'s not displayed here because process spawning on Windows sucks balls. See if the error is happening on Travis-CI, otherwise run tests on a local windows system. https://travis-ci.org/dustinblackman/Championify/builds')
+        return cb(new Error('Mocha returned an error, and it\'s not displayed here because process spawning on Windows sucks balls. See if the error is happening on Travis-CI, otherwise run tests on a local windows system. https://travis-ci.org/dustinblackman/Championify/builds'))

-      cb("Mocha exited with code: #{code}")
+      cb(new Error("Mocha exited with code: #{code}"))
     else
       cb()

@@ -101,7 +101,7 @@

   em = spawn(electron_mocha, args, options)
   em.on 'close', (code) ->
-    return cb("Mocha exited with code: #{code}") if code != 0
+    return cb(new Error("Mocha exited with code: #{code}")) if code != 0
     cb()


Some proxies insist on a favicon

Some proxies insist on a favicon

--- config/grunt/server.coffee
+++ config/grunt/server.coffee
@@ -4,6 +4,9 @@
 harp = require('harp')
 stylus = require('stylus')
 watchify = require('watchify')
+
+
+FAVICON = new Buffer('iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACf0lEQVR42r2XS2gTURSG04K2VReilorEECVKiJk8EYuurIgPEFddKW4El1J3FbRUEOzKKuhKdy4Uql0H0UVxoYIKkoWCrxaKz1qKTayNYv0O3IEhzNzecSYz8HNnJpPz3XPm3HPuxGIRHNlstqdQKBwul8tDpVLpDprg/BV63hJgPB7vAngU0HX0BtCSh76FCs7n89sBjqJZDfS343whFHCxWNyEsZvojwb8jok9YKw77tUDwzF6CtW8wPw2zwQvMN51+f3jf4MzmcwaDIxpPBb4S8Zd6JHHM9UgIa/q4OgqObFDQq+Z4G3fcLJ77TLwBSZ4gueSACaXmeRZv2FfidGHGo9+MO7N5XJbDOBLRKjoN+Eu69Y0Xu80haO3mGzzAz+I/np4Pk3YMwLnesoALv8ZMIYnk8lOTTLNCNyyrK2mcPQerTKeAA8PenhRQ70+4T95Vbv9rvcZF0MNPD/EmNDBmeB3qYDSF7geAb7fb+KdcTMM/CTjBtXVnMAv6BY6ThfcHLjUYvS1i1ejKjJPm+7PomP8rT2UJiPvygVekXbL+X3Ne37BcwfCaDRXmuCT6XR6vWwqDJdaRVZQkAl8cPZxIrKHe9cM4Z9RX5DwF5qMnlcygY+TpN1Bwz/sMPpEst6rEjqTUBpRKAmIscfK6C/G07LuNfCG5AsrY10ocGr6ahsoPZtxzsPjRcYbUglD3VwSxn12b0efXMBfVWdMtGRbLXs4j7o/Ltttrle07CNCdT57xyNldkSWUyqV6ojiI6YN2D17wyi5EIvyIPTnFHyOUG+LFA60X9a50pGo4ZZ8QCjvL0Ud9m675kvzCK2V+qh4F9Ez+Xqhkm2MRXz8AzAAXszjgRshAAAAAElFTkSuQmCC', 'base64')

 bundle = (w) ->
@@ -25,10 +28,12 @@
         s.include('./src/themes/snow')
         s.define('url', stylus.url())
         s.render((err, css) ->
-          res.write(css)
-          res.end()
+          res.end(css)
         )
       )
+    when '/favicon.ico'
+      res.setHeader('Content-Type', 'image/png')
+      res.end(FAVICON)
     else
       next()


Use native code to set file upload cookies

This fixes problems we had with file uploads on Microsft Edge

--- lib/fileUpload.coffee
+++ lib/fileUpload.coffee
@@ -12,9 +12,8 @@
 	initFileStore = ->
 		cookie = new Cookies()
 		if Meteor.isClient
-			cookie.set 'rc_uid', Meteor.userId();
-			cookie.set 'rc_token', Meteor._localStorage.getItem('Meteor.loginToken')
-			cookie.send()
+			document.cookie = 'rc_uid=' + escape(Meteor.userId()) + '; path=/'
+			document.cookie = 'rc_token=' + escape(Meteor._localStorage.getItem('Meteor.loginToken')) + '; path=/'

 		Meteor.fileStore = new UploadFS.store.GridFS
 			collection: RocketChat.models.Uploads.model


Use Decoration::setProperties

Use Decoration::setProperties

--- lib/find-model.coffee
+++ lib/find-model.coffee
@@ -103,11 +103,11 @@
     return if marker is @currentResultMarker

     if @currentResultMarker?
-      @decorationsByMarkerId[@currentResultMarker.id]?.update(type: 'highlight', class: @constructor.markerClass)
+      @decorationsByMarkerId[@currentResultMarker.id]?.setProperties(type: 'highlight', class: @constructor.markerClass)

     @currentResultMarker = null
     if marker and not marker.isDestroyed()
-      @decorationsByMarkerId[marker.id]?.update(type: 'highlight', class: 'current-result')
+      @decorationsByMarkerId[marker.id]?.setProperties(type: 'highlight', class: 'current-result')
       @currentResultMarker = marker

     @emit 'current-result-changed', @currentResultMarker


Matrix copy constructor

Matrix copy constructor

--- test/matrix.coffee
+++ test/matrix.coffee
@@ -20,7 +20,7 @@

    matrix2 = Matrix(matrix)

-
+   equals(matrix2, )

   test "Matrix() (Identity)", ->
     matrix = Matrix()


errors format

errors format

Signed-off-by: Arnaud Richard <791baf8974538c563f287130527dd623cb0e836d@webshell.io>

--- lib/formatters.coffee
+++ lib/formatters.coffee
@@ -69,7 +69,12 @@
 	'text/html; q=0.1': (req, res, body) ->
 		if body instanceof Error
 			if body instanceof check.Error || body instanceof restify.RestError
-				body = body.message
+				msg = body.message
+				if body.body? && Object.keys(body.body).length
+					msg += "
"
+					for k,v of body.body
+						msg += '' + k.toString() + ": " + v.toString() + "
"
+				body = msg
 			else
 				body = "Internal error"
 		body = body.toString()


configure aloha to use drag/drop blocks

configure aloha to use drag/drop blocks

--- scripts/configs/aloha.coffee
+++ scripts/configs/aloha.coffee
@@ -107,6 +107,8 @@
               console.log 'Updated Image src as a result of upload'

       block:
+        dragdrop: "1"
+        rootTags: ['span', 'div', 'figure']
         defaults:
           '.default-block': {}
           figure:


testing for the /data route's 200 response

--- test/routes.coffee
+++ test/routes.coffee
@@ -14,5 +14,6 @@
       assert.isObject results = JSON.parse body
       assert.isArray results.projects
       )
+  .get("/data").expect(200)

   .export(module)


- small bugfix in paramsEditorView:  * to prevent issues without params, this time in the editor's view itself

--- src/app/editors/paramsEditor/paramsEditorView.coffee
+++ src/app/editors/paramsEditor/paramsEditorView.coffee
@@ -172,72 +172,73 @@
             paramValue = param.default
           return paramValue

-        for param in @project.meta.rawParams
-          console.log "param",param
-          paramValue = getParamValue( param )
-          console.log "paramValue",paramValue
+        if @project.meta.rawParams?
+          for param in @project.meta.rawParams
+            console.log "param",param
+            paramValue = getParamValue( param )
+            console.log "paramValue",paramValue
+
+            container = $('
',{class: "control-group field-#{param.name}"})
+            label = """#{param.name}"""
+            toolTip = """

"""
+
+            switch param.type
+              when "float", "int"
+                control = """
 <input type='number' value='#{paramValue}' id='#{param.name}' class='myParams'/> #{toolTip}
"""
+
+              when "checkbox"
+                control = """
 <input class='myParams' type='checkbox' id='#{param.name}' #{if param.default==true then 'checked' else ''}/> #{toolTip}
"""
+
+              when "select"
+                values = param.values.split(',')
+                vals = ""
+                for val in values
+                  vals += "<option value=#{val}>#{val}</option>"
+                control = """
 <select id='#{param.name}' class='myParams'> #{vals} </select>#{toolTip}
"""
+
+              when "color"
+                if "#" in paramValue
+                  paramValue = @_hexToRgba(paramValue)
+                rgbaValue = "rgba(#{paramValue.r}, #{paramValue.g}, #{paramValue.b}, #{paramValue.a})"
+                control = """
+

+

+                  <input type="text" class="span2" value="#{rgbaValue}" readonly="">
+
+

+                #{toolTip}
"""
+
+              when "slider"
+                control = """
+

+

+                  #{param.min}&nbsp<input id='#{param.name}' type="text" class="span2 slider" value=""
+                    data-slider-min="#{param.min}" data-slider-max="#{param.max}" data-slider-step="#{param.step}" data-slider-value="#{paramValue}"
+                    data-slider-orientation="horizontal" data-slider-selection="after"data-slider-tooltip="show" data-slider-handle="square">&nbsp#{param.max}
+
+                  #{toolTip}
+

+
"""
+
+            container.append(label)
+            container.append(control)
+            rootEl.append(container)

-          container = $('
',{class: "control-group field-#{param.name}"})
-          label = """#{param.name}"""
-          toolTip = """

"""
+          parametrizerSettingsFieldSet = $('
')
+          parametrizerSettingsFieldSet.append("""<legend>Parametrizer settings</legend>""")
+          parametrizerSettings = $('
',{class: "control-group field-parametrizerSettings"})
+          parametrizerSettings.append("""
Auto update
 <input class='autoUpdate' id='autoUpdate' type='checkbox' #{if @autoUpdateBasedOnParams then 'checked' else ''} />

""")
+          parametrizerSettings.append("""
Keep ui
   <input class='preventUiRegen' id='preventUiRegen' type='checkbox' #{if @preventUiRegen then 'checked' else ''} />

""")
+          parametrizerSettings.append("
<button class='applyParams'>Apply Params</button>
")
+          parametrizerSettingsFieldSet.append(parametrizerSettings)

-          switch param.type
-            when "float", "int"
-              control = """
 <input type='number' value='#{paramValue}' id='#{param.name}' class='myParams'/> #{toolTip}
"""
+          rootEl.append( parametrizerSettingsFieldSet )
+
+

-            when "checkbox"
-              control = """
 <input class='myParams' type='checkbox' id='#{param.name}' #{if param.default==true then 'checked' else ''}/> #{toolTip}
"""
-
-            when "select"
-              values = param.values.split(',')
-              vals = ""
-              for val in values
-                vals += "<option value=#{val}>#{val}</option>"
-              control = """
 <select id='#{param.name}' class='myParams'> #{vals} </select>#{toolTip}
"""
-
-            when "color"
-              if "#" in paramValue
-                paramValue = @_hexToRgba(paramValue)
-              rgbaValue = "rgba(#{paramValue.r}, #{paramValue.g}, #{paramValue.b}, #{paramValue.a})"
-              control = """
-

-

-                <input type="text" class="span2" value="#{rgbaValue}" readonly="">
-
-

-              #{toolTip}
"""
-
-            when "slider"
-              control = """
-

-

-                #{param.min}&nbsp<input id='#{param.name}' type="text" class="span2 slider" value=""
-                  data-slider-min="#{param.min}" data-slider-max="#{param.max}" data-slider-step="#{param.step}" data-slider-value="#{paramValue}"
-                  data-slider-orientation="horizontal" data-slider-selection="after"data-slider-tooltip="show" data-slider-handle="square">&nbsp#{param.max}
-
-                #{toolTip}
-

-
"""
-
-          container.append(label)
-          container.append(control)
-          rootEl.append(container)
-
-        parametrizerSettingsFieldSet = $('
')
-        parametrizerSettingsFieldSet.append("""<legend>Parametrizer settings</legend>""")
-        parametrizerSettings = $('
',{class: "control-group field-parametrizerSettings"})
-        parametrizerSettings.append("""
Auto update
 <input class='autoUpdate' id='autoUpdate' type='checkbox' #{if @autoUpdateBasedOnParams then 'checked' else ''} />

""")
-        parametrizerSettings.append("""
Keep ui
   <input class='preventUiRegen' id='preventUiRegen' type='checkbox' #{if @preventUiRegen then 'checked' else ''} />

""")
-        parametrizerSettings.append("
<button class='applyParams'>Apply Params</button>
")
-        parametrizerSettingsFieldSet.append(parametrizerSettings)
-
-        rootEl.append( parametrizerSettingsFieldSet )
-
-
-
-        @_drawnOnce = true
-        @newRootEl = rootEl
-        @render()
+          @_drawnOnce = true
+          @newRootEl = rootEl
+          @render()

   return ParamsEditorView


added eta test cases for amazon logistics shipments

--- test/amazon.coffee
+++ test/amazon.coffee
@@ -28,6 +28,9 @@

       it "has a status of out-for-delivery", ->
         expect(_package.status).to.equal ShipperClient.STATUS_TYPES.OUT_FOR_DELIVERY
+
+      it "has an eta of Oct 3rd at 8pm", ->
+        expect(_package.eta).to.deep.equal new Date '2015-10-03T20:00:00Z'

       describe "has last activity", ->
         _activity = null
@@ -170,3 +173,20 @@

         it "with location US", ->
           expect(_activity.location).to.equal 'US'
+
+
+    describe "package scheduled for delivery on Tuesday", ->
+
+      before (done) ->
+        fs.readFile 'test/stub_data/amazon_last_update_today.html', 'utf8', (err, docs) ->
+          _amazonClient.presentResponse docs, 'request', (err, resp) ->
+            should.not.exist(err)
+            _package = resp
+            done()
+
+      it "has a status of en-route", ->
+        expect(_package.status).to.equal ShipperClient.STATUS_TYPES.EN_ROUTE
+
+      it "has an eta of Oct 6th", ->
+        expect(_package.eta).to.deep.equal new Date '2015-10-06T23:00:00Z'
+


update test

update test

--- test/sentry.coffee
+++ test/sentry.coffee
@@ -80,7 +80,7 @@
   it 'send error correctly', (done) ->
     scope = nock('https://app.getsentry.com')
                 .matchHeader('X-Sentry-Auth'
-                , "Sentry sentry_version=4, sentry_key=#{sentry_settings.key}, sentry_secret=#{sentry_settings.secret}, sentry_client=sentry-node/0.1.0")
+                , "Sentry sentry_version=4, sentry_key=#{sentry_settings.key}, sentry_secret=#{sentry_settings.secret}, sentry_client=sentry-node/0.1.2")
                 .filteringRequestBody (path) ->
                   params = JSON.parse path
                   if _.every(['culprit','message','logger','server_name','platform','level'], (prop) -> _.has(params, prop))
@@ -99,7 +99,7 @@
   it 'send message correctly', (done) ->
     scope = nock('https://app.getsentry.com')
                 .matchHeader('X-Sentry-Auth'
-                , "Sentry sentry_version=4, sentry_key=#{sentry_settings.key}, sentry_secret=#{sentry_settings.secret}, sentry_client=sentry-node/0.1.0")
+                , "Sentry sentry_version=4, sentry_key=#{sentry_settings.key}, sentry_secret=#{sentry_settings.secret}, sentry_client=sentry-node/0.1.2")
                 .filteringRequestBody (path) ->
                   params = JSON.parse path
                   if _.every(['message','logger','level'], (prop) -> _.has(params, prop))


parse store to use in tests

parse store to use in tests

--- test/server.coffee
+++ test/server.coffee
@@ -1,5 +1,9 @@
 require '../index.js'
 File  = require('pathfinder').File
+
+# mocha $(find test -name "*attributesTest.coffee") --store mongodb
+store = require('commander').option('--store [name]', 'Store to run tests against', 'memory').parse(process.argv).store
+Tower.store = Tower.Store[_.camelize(store)]

 global.chai   = require 'chai'
 global.assert = chai.assert


fix nrepl-connect focus toggle

fix nrepl-connect focus toggle

--- lib/proto-repl.coffee
+++ lib/proto-repl.coffee
@@ -760,4 +760,5 @@
                 @stderr("Error trying to open: #{result.error}")

   remoteNreplFocusNext: ->
-    @connectionView ? @connectionView.toggleFocus()
+    if @connectionView?
+      @connectionView.toggleFocus()


Test Array::drop()

Test Array::drop()

--- tests/index.coffee
+++ tests/index.coffee
@@ -16,4 +16,12 @@
       assert.deepEqual zipObject(["age"], [21, on]), { age: 21, additional: [true] }

     it "['obj'] and [{ a: 1 }]\t => {obj: { a: 1 }}", ->
-      assert.deepEqual zipObject(['obj'], [{ a: 1 }]), { obj: { a: 1 } }+      assert.deepEqual zipObject(['obj'], [{ a: 1 }]), { obj: { a: 1 } }
+
+  describe "Array::drop()", ->
+
+    it "[1, 2, 3].drop(1) => [1, 2]", ->
+      assert.deepEqual [1, 2, 3].drop(1), [2, 3]
+
+    it "['name', 'age'].drop('name') => ['age']", ->
+      assert.deepEqual ["name", "age"].drop("name"), ["age"]


script partial increment collection update fix

--- server/lib/collection.coffee
+++ server/lib/collection.coffee
@@ -100,9 +100,12 @@
   return undefined if obj.script? and partial isnt true
   rec = this.get q
   if rec
-    if _.keys(obj).length is 1 and rec[_.keys(obj)[0]]? and (_.values(obj)[0].indexOf('+') is 0 or _.values(obj)[0].indexOf('-') is 0)
-      partial = true
-      obj = {script: "ctx._source." + _.keys(obj)[0] + _.values(obj)[0].replace('+=','+').replace('-=','-').replace('+','+=').replace('-','-=')}
+    if _.keys(obj).length is 1 and typeof _.values(obj)[0] is 'string' and  (_.values(obj)[0].indexOf('+') is 0 or _.values(obj)[0].indexOf('-') is 0)
+      if rec[_.keys(obj)[0]]? and typeof rec[_.keys(obj)[0]] is 'number'
+        partial = true
+        obj = {script: "ctx._source." + _.keys(obj)[0] + _.values(obj)[0].replace('+=','+').replace('-=','-').replace('+','+=').replace('-','-=')}
+      else
+        obj[_.keys(obj)[0]] = 1
     if not partial
       for k of obj
         API.collection._dot(rec,k,obj[k]) if k isnt '_id'


updating users catchup script

updating users catchup script

--- server/scripts/2noddy.coffee
+++ server/scripts/2noddy.coffee
@@ -59,7 +59,7 @@
       #for u in newoab.data.hits.hits
       #  rec = _oab_requests_sherpa u._source
       #  API.es.call 'POST', '/oab/request/' + rec._id, rec, undefined, undefined, undefined, undefined, undefined, false
-      return {users: newusers.data.hits.total, requests: newoab.data.hits.total}
+      return {users: newusers.data.hits.total} #, requests: newoab.data.hits.total}

 API.add 'scripts/2noddy/accounts',
   get:


:lipstick: Refactor columns widths computations

--- lib/table-view.coffee
+++ lib/table-view.coffee
@@ -321,14 +321,15 @@
   hasColumnWithWidth: -> @table.getColumns().some (c) -> c.width?

   getColumnsWidths: ->
-    return @columnsPercentWidths if @columnsPercentWidths?
+    return @columnsWidths if @columnsWidths

     if @hasColumnWithWidth()
       @columnsWidths = @getColumnsWidthsFromModel()
-      @columnsPercentWidths = @columnsWidths.map @floatToPercent
     else
       count = @table.getColumnsCount()
-      (1 / count for n in [0...count]).map @floatToPercent
+      (1 / count for n in [0...count])
+
+  getColumnsWidthPercentages: -> @getColumnsWidths().map @floatToPercent

   getColumnsWidthsFromModel: ->
     count = @table.getColumnsCount()
@@ -338,10 +339,10 @@

   getColumnsScreenWidths: ->
     width = @getRowsContainer().width()
-    @getColumnsWidthsFromModel().map (v) => v * width
+    @getColumnsWidths().map (v) => v * width

   getColumnsScreenMargins: ->
-    widths = @getColumnsWidthsFromModel()
+    widths = @getColumnsWidths()
     pad = 0
     width = @getRowsContainer().width()
     margins = widths.map (v) =>
@@ -353,9 +354,7 @@

   setColumnsWidths: (columnsWidths) ->
     widths = @normalizeColumnsWidths(columnsWidths)
-
     @columnsWidths = widths
-    @columnsPercentWidths = widths.map @floatToPercent

     @requestUpdate()

@@ -999,7 +998,7 @@
       @gutter
       firstRow
       lastRow
-      columnsWidths: @getColumnsWidths()
+      columnsWidths: @getColumnsWidthPercentages()
       columnsAligns: @getColumnsAligns()
       totalRows: @table.getRowsCount()
     }


Teamwork: Implemented preview auto refresh feature.

--- client/app/Applications/Teamwork.kdapplication/Views/teamworkworkspace.coffee
+++ client/app/Applications/Teamwork.kdapplication/Views/teamworkworkspace.coffee
@@ -29,12 +29,28 @@
       if @amIHost()
         # currently only for host.
         # bc of clients need to know host's vmName and active pane's file data etc.
-        {viewerHeader} = @getActivePanel().paneLauncher.previewPane.previewer
+        activePanel    = @getActivePanel()
+        {previewPane}  = activePanel.paneLauncher
+        {viewerHeader} = previewPane.previewer
         viewerHeader.addSubView new KDButtonView
-          cssClass : "clean-gray workspace-previewer-button"
+          cssClass : "clean-gray tw-previewer-button"
           title    : "View active file"
           callback : =>
             @previewFile()
+
+        viewerHeader.addSubView @autoRefreshSwitch = new KDOnOffSwitch
+          defaultValue : off
+          cssClass     : "tw-live-update"
+          title        : "Auto Refresh: "
+          size         : "tiny"
+          tooltip      :
+            title      : "If it's on, preview will be refreshed when you save a file."
+            placement  : "bottom"
+          callback     : (state) =>
+            @autoRefresh previewPane  if state
+
+        activePanel.getPaneByName("editor").on "EditorDidSave", =>
+          @autoRefresh previewPane  if @autoRefreshSwitch.getValue()

   createLoader: ->
     @container.addSubView @loader = new KDCustomHTMLView
@@ -80,6 +96,9 @@
       teamwork                   = new teamworkClass teamworkOptions
       @getDelegate().teamwork    = teamwork
       @addSubView teamwork
+
+  autoRefresh: (previewPane) ->
+    previewPane.previewer.emit "ViewerRefreshed"

   createRunButton: (panel) ->
     # panel.headerButtons.Environments.hide()


Created server side tests.

Created server side tests.

--- tests/tests.coffee
+++ tests/tests.coffee
@@ -920,6 +920,152 @@
       #{FOO_COMPONENT_CONTENT()}
     """

+  TEST_BLOCK_COMPONENT_CONTENT = ->
+    """
+
Names and emails and components (CaptionComponent/CaptionComponent/CaptionComponent)

+
(ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent)

+

+

+

+            Name
+            Email
+            Component (ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent)
+

+

+

+

+            Foo
+            foo@example.com
+            TestBlockComponent/TestBlockComponent/ExtraTableWrapperBlockComponent
+

+

+            Bar
+            bar@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Baz
+            baz@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Works
+            nameFromComponent1@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Bac
+            bac@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Works
+            nameFromComponent2@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Works
+            nameFromComponent3@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Bam
+            bam@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Bav
+            bav@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Bak
+            bak@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+            Bal
+            bal@example.com
+            RowComponent/RowComponent/RowComponent
+

+

+

+

+            Name
+            Email
+            Component (FootComponent/FootComponent/FootComponent)
+

+

+

+    """
+
+  TEST_BLOCK_COMPONENT_STRUCTURE = ->
+    component: 'TestBlockComponent'
+    data: {top: '42'}
+    children: [
+      component: 'ExtraTableWrapperBlockComponent'
+      data: {block: '43'}
+      children: [
+        component: 'CaptionComponent'
+        data: {block: '43'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Bar', email: 'bar@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Baz', email: 'baz@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Works', email: 'nameFromComponent1@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Bac', email: 'bac@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Works', email: 'nameFromComponent2@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Works', email: 'nameFromComponent3@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Bam', email: 'bam@example.com'}
+        children: [{}]
+      ,
+        component: 'RowComponent'
+        data: {name: 'Bav', email: 'bav@example.com'}
+        children: [{}]
+      ,
+        component: 'RenderRowComponent'
+        data: {top: '42'}
+        children: [
+          component: 'RowComponent'
+          data: {name: 'Bak', email: 'bak@example.com'}
+          children: [{}]
+        ,
+          component: 'RowComponent'
+          data: {name: 'Bal', email: 'bal@example.com'}
+          children: [{}]
+        ,
+          {}
+        ]
+      ,
+        component: 'FootComponent'
+        data: {block: '43'}
+        children: [{}]
+      ,
+        {}
+      ]
+    ,
+      {}
+    ]
+
   testComponents: ->
     componentTemplate = BlazeComponent.getComponent('MainComponent').renderComponent()

@@ -1081,7 +1227,7 @@
     ,
       /Template 'TemplateWhichDoesNotExist' cannot be found/

-  testEvents: [
+  testClientEvents: [
     ->
       MainComponent.calls = []
       SubComponent.calls = []
@@ -1121,7 +1267,7 @@
       Blaze.remove @renderedComponent
   ]

-  testAnimation: [
+  testClientAnimation: [
     ->
       AnimatedListComponent.calls = []

@@ -1155,7 +1301,7 @@
       @assertEqual AnimatedListComponent.calls, []
   ]

-  assertArgumentsConstructorStateChanges: (stateChanges, wrappedInComponent=true) ->
+  assertArgumentsConstructorStateChanges: (stateChanges, wrappedInComponent=true, staticRender=false) ->
     firstSteps = (dataContext) =>
       change = stateChanges.shift()
       componentId = change.componentId
@@ -1223,6 +1369,10 @@
     secondComponentId = firstSteps a:"3a", b: "4a"
     thirdComponentId = firstSteps a: "5", b: "6"
     forthComponentId = firstSteps {}
+
+    if staticRender
+      @assertEqual stateChanges, []
+      return

     secondSteps = (componentId, dataContext) =>
       change = stateChanges.shift()
@@ -1370,7 +1520,7 @@

     @assertEqual stateChanges, []

-  assertArgumentsOnCreatedStateChanges: (stateChanges) ->
+  assertArgumentsOnCreatedStateChanges: (stateChanges, staticRender=false) ->
     firstSteps = (dataContext) =>
       change = stateChanges.shift()
       componentId = change.componentId
@@ -1436,6 +1586,10 @@
     thirdComponentId = firstSteps a: "5", b: "6"
     forthComponentId = firstSteps {}

+    if staticRender
+      @assertEqual stateChanges, []
+      return
+
     thirdSteps = (componentId) =>
       change = stateChanges.shift()
       @assertEqual change.componentId, componentId
@@ -1546,21 +1700,19 @@

     @assertEqual stateChanges, []

-  testArguments: [
-    ->
-      ArgumentsComponent.calls = []
-      ArgumentsComponent.constructorStateChanges = []
-      ArgumentsComponent.onCreatedStateChanges = []
-
-      reactiveContext {}
-      reactiveArguments {}
-
-      @renderedComponent = Blaze.renderWithData Template.argumentsTestTemplate, {top: '42'}, $('body').get(0)
-
-      Tracker.afterFlush @expect()
-  ,
-    ->
-      @assertEqual trim($('.argumentsTestTemplate').html()), trim """
+  testArguments: ->
+    ArgumentsComponent.calls = []
+    ArgumentsComponent.constructorStateChanges = []
+    ArgumentsComponent.onCreatedStateChanges = []
+
+    reactiveContext {}
+    reactiveArguments {}
+
+    output = Blaze.toHTMLWithData Template.argumentsTestTemplate,
+      top: '42'
+
+    @assertEqual trim(output), trim """
+

Component data context: {"a":"1","b":"2"}

Current data context: {"a":"1","b":"2"}

Parent data context: {"top":"42"}

@@ -1577,9 +1729,31 @@

Current data context: {}

Parent data context: {"top":"42"}

Arguments: [{},{"hash":{}}]

-      """
-
-      reactiveContext {a: '10', b: '11'}
+

+    """
+
+    @assertEqual ArgumentsComponent.calls.length, 4
+
+    @assertEqual ArgumentsComponent.calls, [
+      undefined
+      undefined
+      '7'
+      {}
+    ]
+
+    @assertArgumentsConstructorStateChanges ArgumentsComponent.constructorStateChanges, true, true
+    @assertArgumentsOnCreatedStateChanges ArgumentsComponent.onCreatedStateChanges, true
+
+  testClientArguments: [
+    ->
+      ArgumentsComponent.calls = []
+      ArgumentsComponent.constructorStateChanges = []
+      ArgumentsComponent.onCreatedStateChanges = []
+
+      reactiveContext {}
+      reactiveArguments {}
+
+      @renderedComponent = Blaze.renderWithData Template.argumentsTestTemplate, {top: '42'}, $('body').get(0)

       Tracker.afterFlush @expect()
   ,
@@ -1597,13 +1771,13 @@

Current data context: {"a":"5","b":"6"}

Parent data context: {"top":"42"}

Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

-
Component data context: {"a":"10","b":"11"}

-
Current data context: {"a":"10","b":"11"}

+
Component data context: {}

+
Current data context: {}

Parent data context: {"top":"42"}

Arguments: [{},{"hash":{}}]

       """

-      reactiveArguments {a: '12', b: '13'}
+      reactiveContext {a: '10', b: '11'}

       Tracker.afterFlush @expect()
   ,
@@ -1624,6 +1798,30 @@

Component data context: {"a":"10","b":"11"}

Current data context: {"a":"10","b":"11"}

Parent data context: {"top":"42"}

+
Arguments: [{},{"hash":{}}]

+      """
+
+      reactiveArguments {a: '12', b: '13'}
+
+      Tracker.afterFlush @expect()
+  ,
+    ->
+      @assertEqual trim($('.argumentsTestTemplate').html()), trim """
+
Component data context: {"a":"1","b":"2"}

+
Current data context: {"a":"1","b":"2"}

+
Parent data context: {"top":"42"}

+
Arguments: []

+
Component data context: {"a":"3a","b":"4a"}

+
Current data context: {"a":"3a","b":"4a"}

+
Parent data context: {"a":"3","b":"4"}

+
Arguments: []

+
Component data context: {"a":"5","b":"6"}

+
Current data context: {"a":"5","b":"6"}

+
Parent data context: {"top":"42"}

+
Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

+
Component data context: {"a":"10","b":"11"}

+
Current data context: {"a":"10","b":"11"}

+
Parent data context: {"top":"42"}

Arguments: [{"a":"12","b":"13"},{"hash":{}}]

       """

@@ -1693,7 +1891,7 @@
       #{COMPONENT_CONTENT 'SubComponent'}
     """

-  testMixinEvents: ->
+  testClientMixinEvents: ->
     FirstMixin.calls = []
     SecondMixin.calls = []
     SubComponent.calls = []
@@ -1759,7 +1957,7 @@

43

     """

-  testPostMessageExample: [
+  testClientPostMessageExample: [
     ->
       @renderedComponent = Blaze.render PostMessageButtonComponent.renderComponent(), $('body').get(0)

@@ -1851,7 +2049,7 @@

     """

-  testComponentParent: [
+  testClientComponentParent: [
     ->
       reactiveChild1 false
       reactiveChild2 false
@@ -1949,7 +2147,7 @@
       ]
   ]

-  testCases: [
+  testClientCases: [
     ->
       @dataContext = new ReactiveField {case: 'left'}

@@ -1986,7 +2184,7 @@
       Blaze.remove @renderedComponent
   ]

-  testMixinsExample: [
+  testClientMixinsExample: [
     ->
       @renderedComponent = Blaze.renderWithData BlazeComponent.getComponent('MyComponent').renderComponent(), {top: '42'}, $('body').get(0)

@@ -2010,7 +2208,7 @@
       Blaze.remove @renderedComponent
   ]

-  testReadmeExample: [
+  testClientReadmeExample: [
     ->
       @renderedComponent = Blaze.render BlazeComponent.getComponent('ExampleComponent').renderComponent(), $('body').get(0)

@@ -2049,7 +2247,7 @@
       Blaze.remove @renderedComponent
   ]

-  testReadmeExampleJS: [
+  testClientReadmeExampleJS: [
     ->
       @renderedComponent = Blaze.render BlazeComponent.getComponent('ExampleComponentJS').renderComponent(), $('body').get(0)

@@ -2088,7 +2286,7 @@
       Blaze.remove @renderedComponent
   ]

-  testMixinsExampleWithJavaScript: [
+  testClientMixinsExampleWithJavaScript: [
     ->
       @renderedComponent = Blaze.renderWithData BlazeComponent.getComponent('OurComponentJS').renderComponent(), {top: '42'}, $('body').get(0)

@@ -2112,7 +2310,7 @@
       Blaze.remove @renderedComponent
   ]

-  testReadmeExampleES2015: [
+  testClientReadmeExampleES2015: [
     ->
       @renderedComponent = Blaze.render BlazeComponent.getComponent('ExampleComponentES2015').renderComponent(), $('body').get(0)

@@ -2151,7 +2349,7 @@
       Blaze.remove @renderedComponent
   ]

-  testMixinsExampleWithES2015: [
+  testClientMixinsExampleWithES2015: [
     ->
       @renderedComponent = Blaze.renderWithData BlazeComponent.getComponent('OurComponentES2015').renderComponent(), {top: '42'}, $('body').get(0)

@@ -2175,7 +2373,7 @@
       Blaze.remove @renderedComponent
   ]

-  testOnDestroyedOrder: [
+  testClientOnDestroyedOrder: [
     ->
       OuterComponent.calls = []

@@ -2220,21 +2418,19 @@
       ]
   ]

-  testNamespacedArguments: [
-    ->
-      MyNamespace.Foo.ArgumentsComponent.calls = []
-      MyNamespace.Foo.ArgumentsComponent.constructorStateChanges = []
-      MyNamespace.Foo.ArgumentsComponent.onCreatedStateChanges = []
-
-      reactiveContext {}
-      reactiveArguments {}
-
-      @renderedComponent = Blaze.renderWithData Template.namespacedArgumentsTestTemplate, {top: '42'}, $('body').get(0)
-
-      Tracker.afterFlush @expect()
-  ,
-    ->
-      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+  testNamespacedArguments: ->
+    MyNamespace.Foo.ArgumentsComponent.calls = []
+    MyNamespace.Foo.ArgumentsComponent.constructorStateChanges = []
+    MyNamespace.Foo.ArgumentsComponent.onCreatedStateChanges = []
+
+    reactiveContext {}
+    reactiveArguments {}
+
+    output = Blaze.toHTMLWithData Template.namespacedArgumentsTestTemplate,
+      top: '42'
+
+    @assertEqual trim(output), trim """
+

Component data context: {"a":"1","b":"2"}

Current data context: {"a":"1","b":"2"}

Parent data context: {"top":"42"}

@@ -2251,14 +2447,33 @@

Current data context: {}

Parent data context: {"top":"42"}

Arguments: [{},{"hash":{}}]

-      """
-
-      reactiveContext {a: '10', b: '11'}
-
-      Tracker.afterFlush @expect()
-  ,
-    ->
-      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+

+    """
+
+    @assertEqual MyNamespace.Foo.ArgumentsComponent.calls.length, 4
+
+    @assertEqual MyNamespace.Foo.ArgumentsComponent.calls, [
+      undefined
+      undefined
+      '7'
+      {}
+    ]
+
+    @assertArgumentsConstructorStateChanges MyNamespace.Foo.ArgumentsComponent.constructorStateChanges, false, true
+    @assertArgumentsOnCreatedStateChanges MyNamespace.Foo.ArgumentsComponent.onCreatedStateChanges, true
+
+    OurNamespace.ArgumentsComponent.calls = []
+    OurNamespace.ArgumentsComponent.constructorStateChanges = []
+    OurNamespace.ArgumentsComponent.onCreatedStateChanges = []
+
+    reactiveContext {}
+    reactiveArguments {}
+
+    output = Blaze.toHTMLWithData Template.ourNamespacedArgumentsTestTemplate,
+      top: '42'
+
+    @assertEqual trim(output), trim """
+

Component data context: {"a":"1","b":"2"}

Current data context: {"a":"1","b":"2"}

Parent data context: {"top":"42"}

@@ -2271,18 +2486,37 @@

Current data context: {"a":"5","b":"6"}

Parent data context: {"top":"42"}

Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

-
Component data context: {"a":"10","b":"11"}

-
Current data context: {"a":"10","b":"11"}

+
Component data context: {}

+
Current data context: {}

Parent data context: {"top":"42"}

Arguments: [{},{"hash":{}}]

-      """
-
-      reactiveArguments {a: '12', b: '13'}
-
-      Tracker.afterFlush @expect()
-  ,
-    ->
-      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+

+    """
+
+    @assertEqual OurNamespace.ArgumentsComponent.calls.length, 4
+
+    @assertEqual OurNamespace.ArgumentsComponent.calls, [
+      undefined
+      undefined
+      '7'
+      {}
+    ]
+
+    @assertArgumentsConstructorStateChanges OurNamespace.ArgumentsComponent.constructorStateChanges, false, true
+    @assertArgumentsOnCreatedStateChanges OurNamespace.ArgumentsComponent.onCreatedStateChanges, true
+
+    OurNamespace.calls = []
+    OurNamespace.constructorStateChanges = []
+    OurNamespace.onCreatedStateChanges = []
+
+    reactiveContext {}
+    reactiveArguments {}
+
+    output = Blaze.toHTMLWithData Template.ourNamespaceComponentArgumentsTestTemplate,
+      top: '42'
+
+    @assertEqual trim(output), trim """
+

Component data context: {"a":"1","b":"2"}

Current data context: {"a":"1","b":"2"}

Parent data context: {"top":"42"}

@@ -2295,6 +2529,100 @@

Current data context: {"a":"5","b":"6"}

Parent data context: {"top":"42"}

Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

+
Component data context: {}

+
Current data context: {}

+
Parent data context: {"top":"42"}

+
Arguments: [{},{"hash":{}}]

+

+    """
+
+    @assertEqual OurNamespace.calls.length, 4
+
+    @assertEqual OurNamespace.calls, [
+      undefined
+      undefined
+      '7'
+      {}
+    ]
+
+    @assertArgumentsConstructorStateChanges OurNamespace.constructorStateChanges, false, true
+    @assertArgumentsOnCreatedStateChanges OurNamespace.onCreatedStateChanges, true
+
+  testClientNamespacedArguments: [
+    ->
+      MyNamespace.Foo.ArgumentsComponent.calls = []
+      MyNamespace.Foo.ArgumentsComponent.constructorStateChanges = []
+      MyNamespace.Foo.ArgumentsComponent.onCreatedStateChanges = []
+
+      reactiveContext {}
+      reactiveArguments {}
+
+      @renderedComponent = Blaze.renderWithData Template.namespacedArgumentsTestTemplate, {top: '42'}, $('body').get(0)
+
+      Tracker.afterFlush @expect()
+  ,
+    ->
+      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+
Component data context: {"a":"1","b":"2"}

+
Current data context: {"a":"1","b":"2"}

+
Parent data context: {"top":"42"}

+
Arguments: []

+
Component data context: {"a":"3a","b":"4a"}

+
Current data context: {"a":"3a","b":"4a"}

+
Parent data context: {"a":"3","b":"4"}

+
Arguments: []

+
Component data context: {"a":"5","b":"6"}

+
Current data context: {"a":"5","b":"6"}

+
Parent data context: {"top":"42"}

+
Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

+
Component data context: {}

+
Current data context: {}

+
Parent data context: {"top":"42"}

+
Arguments: [{},{"hash":{}}]

+      """
+
+      reactiveContext {a: '10', b: '11'}
+
+      Tracker.afterFlush @expect()
+  ,
+    ->
+      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+
Component data context: {"a":"1","b":"2"}

+
Current data context: {"a":"1","b":"2"}

+
Parent data context: {"top":"42"}

+
Arguments: []

+
Component data context: {"a":"3a","b":"4a"}

+
Current data context: {"a":"3a","b":"4a"}

+
Parent data context: {"a":"3","b":"4"}

+
Arguments: []

+
Component data context: {"a":"5","b":"6"}

+
Current data context: {"a":"5","b":"6"}

+
Parent data context: {"top":"42"}

+
Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

+
Component data context: {"a":"10","b":"11"}

+
Current data context: {"a":"10","b":"11"}

+
Parent data context: {"top":"42"}

+
Arguments: [{},{"hash":{}}]

+      """
+
+      reactiveArguments {a: '12', b: '13'}
+
+      Tracker.afterFlush @expect()
+  ,
+    ->
+      @assertEqual trim($('.namespacedArgumentsTestTemplate').html()), trim """
+
Component data context: {"a":"1","b":"2"}

+
Current data context: {"a":"1","b":"2"}

+
Parent data context: {"top":"42"}

+
Arguments: []

+
Component data context: {"a":"3a","b":"4a"}

+
Current data context: {"a":"3a","b":"4a"}

+
Parent data context: {"a":"3","b":"4"}

+
Arguments: []

+
Component data context: {"a":"5","b":"6"}

+
Current data context: {"a":"5","b":"6"}

+
Parent data context: {"top":"42"}

+
Arguments: ["7",{"hash":{"a":"8","b":"9"}}]

Component data context: {"a":"10","b":"11"}

Current data context: {"a":"10","b":"11"}

Parent data context: {"top":"42"}

@@ -2589,7 +2917,7 @@

     @assertEqual trim(output), trim COMPONENT_CONTENT 'SubComponent'

-  testGetComponentForElement: [
+  testClientGetComponentForElement: [
     ->
       @outerComponent = new (BlazeComponent.getComponent('OuterComponent'))()

@@ -2608,160 +2936,33 @@
       Blaze.remove @renderedComponent
   ]

-  testBlockHelpersStructure: [
+  testBlockHelpersStructure: ->
+    component = new (BlazeComponent.getComponent('TestBlockComponent'))()
+
+    @assertTrue component
+
+    componentTemplate = component.renderComponent()
+
+    @assertTrue componentTemplate
+
+    output = Blaze.toHTMLWithData componentTemplate,
+      top: '42'
+
+    @assertEqual trim(output), trim(TEST_BLOCK_COMPONENT_CONTENT())
+
+  testClientBlockHelpersStructure: [
     ->
       @renderedComponent = Blaze.render Template.extraTestBlockComponent, $('body').get(0)

       Tracker.afterFlush @expect()
   ,
     ->
-      @assertEqual trim($('.extraTestBlockComponent').html()), trim """
-
Names and emails and components (CaptionComponent/CaptionComponent/CaptionComponent)

-
(ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent)

-

-

-

-              Name
-              Email
-              Component (ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent/ExtraTableWrapperBlockComponent)
-

-

-

-

-              Foo
-              foo@example.com
-              TestBlockComponent/TestBlockComponent/ExtraTableWrapperBlockComponent
-

-

-              Bar
-              bar@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Baz
-              baz@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Works
-              nameFromComponent1@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Bac
-              bac@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Works
-              nameFromComponent2@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Works
-              nameFromComponent3@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Bam
-              bam@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Bav
-              bav@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Bak
-              bak@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-              Bal
-              bal@example.com
-              RowComponent/RowComponent/RowComponent
-

-

-

-

-              Name
-              Email
-              Component (FootComponent/FootComponent/FootComponent)
-

-

-

-      """
+      @assertEqual trim($('.extraTestBlockComponent').html()), trim(TEST_BLOCK_COMPONENT_CONTENT())

       TestingComponentDebug.structure = {}
       TestingComponentDebug.dumpComponentTree $('.extraTestBlockComponent table').get(0)

-      @assertEqual TestingComponentDebug.structure,
-        component: 'TestBlockComponent'
-        data: {top: '42'}
-        children: [
-          component: 'ExtraTableWrapperBlockComponent'
-          data: {block: '43'}
-          children: [
-            component: 'CaptionComponent'
-            data: {block: '43'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Bar', email: 'bar@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Baz', email: 'baz@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Works', email: 'nameFromComponent1@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Bac', email: 'bac@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Works', email: 'nameFromComponent2@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Works', email: 'nameFromComponent3@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Bam', email: 'bam@example.com'}
-            children: [{}]
-          ,
-            component: 'RowComponent'
-            data: {name: 'Bav', email: 'bav@example.com'}
-            children: [{}]
-          ,
-            component: 'RenderRowComponent'
-            data: {top: '42'}
-            children: [
-              component: 'RowComponent'
-              data: {name: 'Bak', email: 'bak@example.com'}
-              children: [{}]
-            ,
-              component: 'RowComponent'
-              data: {name: 'Bal', email: 'bal@example.com'}
-              children: [{}]
-            ,
-              {}
-            ]
-          ,
-            component: 'FootComponent'
-            data: {block: '43'}
-            children: [{}]
-          ,
-            {}
-          ]
-        ,
-          {}
-        ]
+      @assertEqual TestingComponentDebug.structure, TEST_BLOCK_COMPONENT_STRUCTURE()

       @assertEqual BlazeComponent.getComponentForElement($('.insideContent').get(0)).componentName(), 'TestBlockComponent'
       @assertEqual BlazeComponent.getComponentForElement($('.insideContentComponent').get(0)).componentName(), 'RowComponent'
@@ -2772,7 +2973,7 @@
       Blaze.remove @renderedComponent
   ]

-  testExtendingTemplate: [
+  testClientExtendingTemplate: [
     ->
       mainComponent3Calls = []

@@ -2893,7 +3094,7 @@

     """

-  testInlineEvents: [
+  testClientInlineEvents: [
     ->
       reactiveArguments {z: 1}

@@ -2976,7 +3177,7 @@
       Blaze.remove @renderedComponent
   ]

-  testInvalidInlineEvents: ->
+  testClientInvalidInlineEvents: ->
     @assertThrows =>
       Blaze.render Template.invalidInlineEventsTestTemplate, $('body').get(0)
     ,


Test against correctly upper-cased method names

We upper-case the method name immediately before testing, so the strings we are testing against should be upper-case as well.

--- lib/zombie/xhr.coffee
+++ lib/zombie/xhr.coffee
@@ -69,7 +69,7 @@

     # Check supported HTTP method
     method = method.toUpperCase()
-    if /^(connect|trace|track)$/.test(method)
+    if /^(CONNECT|TRACE|TRACK)$/.test(method)
       throw new HTML.DOMException(HTML.SECURITY_ERR, "Unsupported HTTP method")
     unless /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/.test(method)
       throw new HTML.DOMException(HTML.SYNTAX_ERR, "Unsupported HTTP method")


filetree works with a file registry

filetree works with a file registry

--- core/KDEventEmitter.coffee
+++ core/KDEventEmitter.coffee
@@ -53,9 +53,9 @@
     listenerStack = listenerStack.concat @_e[event].slice(0)

     listenerStack.forEach (listener)=>
-      listener.apply @,args
+      listener.apply @, args

-  on : (event,callback) ->
+  on : (event, callback) ->
     @_e[event] ?= []
     @_e[event].push callback


update protocol

update protocol

--- server/d2mpclient/clientver.coffee
+++ server/d2mpclient/clientver.coffee
@@ -13,4 +13,4 @@
     action: ->
       info = clientParams.findOne({stype: "version"})
       @response.writeHead 200, {'Content-Type': 'text/html'}
-      @response.end 'version:'+info.version+'|url:'+info.url
+      @response.end 'version:'+info.version+'|'+info.url


Make failing tests pass.

Make failing tests pass.

--- test/bundle.coffee
+++ test/bundle.coffee
@@ -3,7 +3,6 @@

 describe 'bundle', ->
   it 'should bundle all dependencies', (done) ->
-    throw new Error 'eep'
     bundle
       entry: './test/assets/entry',
       exclude: /excluded/


doc: add ticks around command

doc: add ticks around command

--- src/apm-cli.coffee
+++ src/apm-cli.coffee
@@ -32,7 +32,7 @@
     where <command> is one of:\n
   """
   usage += wordwrap(4, 80)(Object.keys(commands).sort().join(', '))
-  usage += ".\n\nRun apm help <command> to see the more details about a specific command."
+  usage += ".\n\nRun `apm help <command>` to see the more details about a specific command."
   options.usage(usage)
   options.alias('v', 'version').describe('version', 'Print the apm version')
   options.alias('h', 'help').describe('help', 'Print this usage message')


fix(tap): allow 0 as X or Y coordinate (falsy)

--- modules/directives/tap/index.coffee
+++ modules/directives/tap/index.coffee
@@ -30,7 +30,7 @@
     for key of options
       attr = attrs["bp#{key.charAt(0).toUpperCase()}#{key.slice(1)}"]
       if attr?
-	options[key] = if attr is '' then true else attr
+        options[key] = if attr is '' then true else attr

     # #### Intelligent Defaults
     # * Apply `bp-no-scroll` to  `bp-button` within `bp-navbar`
@@ -48,17 +48,30 @@
     touch = {}

     element.bind 'touchstart', (e) ->
-      touch.y = e.originalEvent.pageY or
-        e.originalEvent.changedTouches[0].pageY
-      touch.x = e.originalEvent.pageX or
-        e.originalEvent.changedTouches[0].pageX
+      touch.y =
+        if e.originalEvent.pageY?
+          e.originalEvent.pageY
+        else
+          e.originalEvent.changedTouches?[0].pageY
+      touch.x =
+        if e.originalEvent.pageX?
+          e.originalEvent.pageX
+        else
+          e.originalEvent.changedTouches?[0].pageX
       touch.ongoing = yes
       element.addClass options.activeClass
+
     element.bind 'touchmove', (e) ->
-      y = e.originalEvent.pageY or
-        e.originalEvent.changedTouches[0].pageY
-      x = e.originalEvent.pageX or
-        e.originalEvent.changedTouches[0].pageX
+      y =
+        if e.originalEvent.pageY?
+          e.originalEvent.pageY
+        else
+          e.originalEvent.changedTouches?[0].pageY
+      x =
+        if e.originalEvent.pageX?
+          e.originalEvent.pageX
+        else
+          e.originalEvent.changedTouches?[0].pageX
       if options.boundMargin and
          (Math.abs(touch.y - y) < options.boundMargin and
          Math.abs(touch.x - x) < options.boundMargin)
@@ -72,8 +85,8 @@

     element.bind 'touchend touchcancel', (e) ->
       if touch.ongoing and e.type is 'touchend'
-	scope.$apply $parse(attrs.bpTap), {$event: e, touch}
-	element.trigger 'tap', angular.extend {type: 'tap', touch}, e
+        scope.$apply $parse(attrs.bpTap), {$event: e, touch}
+        element.trigger 'tap', angular.extend {type: 'tap', touch}, e
       touch = {}
       element.removeClass options.activeClass


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color2.coffee
+++ test/color2.coffee
@@ -227,5 +227,15 @@
   equal color2.b, 150
   equal color2.a, 1.0

+test "#desaturate", ->
+  color = Color2(69, 232, 150)
+
+  color2 = color.desaturate(0.3)
+
+  equal color2.r, 100
+  equal color2.g, 200
+  equal color2.b, 150
+  equal color2.a, 1.0
+
 module()


remove alert on modal file doubleclick

remove alert on modal file doubleclick

--- app/assets/javascripts/fs_browser/modal.js.coffee
+++ app/assets/javascripts/fs_browser/modal.js.coffee
@@ -33,8 +33,6 @@
       if entry.type is FsBrowser.Entry.DIRECTORY
         FsBrowser.Path.update entry.name
         @updatePath()
-      else
-        alert entry.type

   @buildEntryElement: (entry) ->
     $(JST['fs_browser/templates/fs_browser/entry'](entry))


constraint `multipleMax` from 0 to 1000

constraint `multipleMax` from 0 to 1000

--- app/assets/javascripts/uploadcare/settings.coffee
+++ app/assets/javascripts/uploadcare/settings.coffee
@@ -50,6 +50,11 @@
     scriptBase: "//ucarecdn.com/widget/#{uploadcare.version}/uploadcare/"
     debugUploads: false

+  constraints =
+    multipleMax:
+      min: 0
+      max: 1000
+
   presets =
     tabs:
       all: 'file camera url facebook gdrive gphotos dropbox instagram evernote flickr skydrive box vk huddle'
@@ -100,6 +105,11 @@
       settings[key] = parseInt(settings[key])
     settings

+  constrainOptions = (settings, constraints) ->
+    for key, {min, max} of constraints when settings[key]?
+      settings[key] = Math.min(Math.max(settings[key], min), max);
+    settings
+
   parseCrop = (val) ->
     reRatio = /^([0-9]+)([x:])([0-9]+)\s*(|upscale|minimum)$/i
     ratio = reRatio.exec($.trim(val.toLowerCase())) or []
@@ -159,6 +169,7 @@
       'multipartMaxAttempts'
       'parallelDirectUploads'
     ])
+    constrainOptions(settings, constraints)

     if settings.crop != false and not $.isArray(settings.crop)
       if /^(disabled?|false|null)$/i.test(settings.crop)


fixed reset theme value bug

fixed reset theme value bug

--- app/coffeescripts/bundles/account_homepage.coffee
+++ app/coffeescripts/bundles/account_homepage.coffee
@@ -87,7 +87,9 @@
     $(".edit_widget").remove()

   $ ->
-
+
+    $('#jxb_page_theme').prop('defaultSelected', $('#jxb_page_theme').val())
+
     $("#content").css("overflow", "scroll")

     $(".sortable").sortable(
@@ -248,11 +250,11 @@
     $('#jxb_page_theme').bind({
       change: ->
         $('#jxb-message-dialog').easyDialog({
-          confirmButton: '我确定更换主题'
+          confirmButton: '确定'
           confirmButtonClass: 'btn-primary'
-          content: '您确定要更换主页的主题吗？'
+          content: "您确定要更换主页的主题为#{$('#jxb_page_theme').val()}吗？"
           confirmCancelCallback: ->
-             $('#jxb_page_theme').val($('#jxb_page_theme').prop('defauleSelected'))
+            $('#jxb_page_theme').val($('#jxb_page_theme').prop('defaultSelected'))
           confirmCallback: ->
             $.ajaxJSON(
               $('#hidden_update_theme_url').val() + $('#jxb_page_theme').val(),


Fix case-insensitive sort typo

Fix case-insensitive sort typo

--- menus/sort-lines.cson
+++ menus/sort-lines.cson
@@ -7,7 +7,7 @@
         { 'label': 'Sort', 'command': 'sort-lines:sort' }
         { 'label': 'Reverse Sort', 'command': 'sort-lines:reverse-sort' }
         { 'label': 'Unique', 'command': 'sort-lines:unique' }
-        { 'label': 'Sort (Case Insentivive)', 'command': 'sort-lines:case-insensitive-sort' }
+        { 'label': 'Sort (Case Insensitive)', 'command': 'sort-lines:case-insensitive-sort' }
       ]
     ]
   }


Reset form after save.

Reset form after save.

--- app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
+++ app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
@@ -345,7 +345,7 @@
   form_update_execute: (article_type) =>

       # add signature
-      if !@form_state && !@signature_used && @signature && @signature.body
+      if !@form_state && !@signature_used && @signature && @signature.body && article_type.name is 'email'
         @signature_used = true
         body = @el.find('[name="body"]').val() || ''
         body = body + "\n" + @signature.body
@@ -508,6 +508,10 @@
           )
         else
           @fetch( @ticket.id, true )
+
+        # reset form after save
+        App.TaskManager.update( @task_key, { 'state': undefined })
+        @form_state = undefined
     )

 #    errors = article.validate()


update

update

--- Movie2019_20190324.framer/app.coffee
+++ Movie2019_20190324.framer/app.coffee
@@ -858,7 +858,7 @@
 		width: 400*scaleContent
 		height: 600*scaleContent
 		y:0
-		backgroundColor:"Blue"
+		backgroundColor:"White"
 		parent:card
 		image:item["poster"]
 	cardBody=new Layer