support builder::add

support builder::add

--- src/dt-jquery.coffee
+++ src/dt-jquery.coffee
@@ -65,7 +65,13 @@
                     key
                 else
                     # assume this is allready a jquery object
-                    {_jquery:key}
+                    domel = key[0]
+                    attrs = {}
+                    for attr in domel.attributes
+                        attrs[attr.name] = attr.value
+                    new @builder.Tag domel.nodeName.toLowerCase(), attrs, ->
+                        @_jquery = key
+                        @end()
 #                     $(key).data('dt-jquery') or {_jquery:key}
         # register ready handler
         @template.register 'ready', (tag, next) ->
@@ -86,22 +92,34 @@
     onadd: (parent, el) ->
         # insert into parent
         delay.call parent, =>
-            if parent is @builder
+            if parent is parent.builder and parent._jquery.parent().length is 0
                 parent._jquery = parent._jquery.add(el._jquery)
 #                 parent._jquery.data('dt-jquery', parent)
 #                 console.error "ready!", el.name, el._jquery_ready
                 el._jquery_ready?()
                 el._jquery_ready = yes
             else
-                @animation.push ->
-                    parent._jquery?.append(el._jquery)
+                done = => @animation.push ->
+                    if parent is parent.builder
+                        parent._jquery.parent().append(el._jquery)
+                    else
+                        for e in el._jquery ? []
+                            parent._jquery?.append(e)
                     # FIXME listen on dom insertion event
 #                     console.error "ready!", el.name, el._jquery_ready
                     el._jquery_ready?()
                     el._jquery_ready = yes
+                # delay til end if el is a builder
+                if el is el.builder
+                    el.ready(done)
+                else
+                    done()

     onclose: (el) ->
-        el._jquery ?= $(el.toString())
+        if el is el.builder
+            el._jquery ?= $()
+        else
+            el._jquery ?= $(el.toString())
 #         el._jquery.data('dt-jquery', el)
         release.call el

@@ -153,10 +171,8 @@
             delete el._jquery

     onend: () ->
-        @builder._jquery = $()
 #         @builder._jquery.data('dt-jquery', @template.xml)
-        release.call @builder
-        @template.jquery = @builder._jquery
+        @template.jquery = @template._jquery = @builder._jquery
 #         @template.jquery.data('dt-jquery', tpl)


call setEnconding, cuz could be overloaded

--- src/dt-stream.coffee
+++ src/dt-stream.coffee
@@ -75,7 +75,7 @@
         @builder.apdaters ?= {}
         @builder.apdaters['stream'] = this
         @autoremove = opts.autoremove ? on
-        @encoding = opts.encoding ? 'utf8'
+        @setEncoding opts.encoding ? 'utf8'
         @opened_tags = 0
         @readable = yes
         @paused = no


Add new role, manage-integrations

Add new role, manage-integrations

--- packages/rocketchat-authorization/server/startup.coffee
+++ packages/rocketchat-authorization/server/startup.coffee
@@ -92,6 +92,9 @@

 		{ _id: 'manage-assets',
 		roles : ['admin']}
+
+		{ _id: 'manage-integrations',
+		roles : ['admin']}
 	]

 	#alanning:roles


Include alias and bot values in outgoing webhook. (#3805)

--- packages/rocketchat-integrations/server/triggers.coffee
+++ packages/rocketchat-integrations/server/triggers.coffee
@@ -144,6 +144,14 @@
 		user_name: message.u.username
 		text: message.msg

+	if message.alias?
+		data.alias = message.alias
+
+	if message.bot?
+		data.bot = message.bot
+	else
+		data.bot = false
+
 	if word?
 		data.trigger_word = word


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/expirable.coffee
+++ src/expirable.coffee
@@ -7,7 +7,7 @@

   self.bind "update", ->
     if I.fadeOut
-      I.alpha = startingAlpha
+      I.alpha = startingAlpha - (I.age / I.duration)

     if I.duration != -1 && I.age >= I.duration
       I.active = false


Very imperative dirty buggy FIX but better than freezing editor

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -31,6 +31,7 @@
 class TextObject extends Base
   @extend(false)
   wise: null
+  supportCount: false # FIXME #472, #66

   constructor: ->
     @constructor::inner = @getName().startsWith('Inner')
@@ -42,6 +43,9 @@

   isA: ->
     not @isInner()
+
+  isSuportCount: ->
+    @supportCount

   getWise: ->
     if @wise? and @getOperator().isOccurrence()
@@ -57,9 +61,6 @@

   isBlockwise: ->
     @getWise() is 'blockwise'
-
-  stopSelection: ->
-    @selectionStopped = true

   getNormalizedHeadBufferPosition: (selection) ->
     head = selection.getHeadBufferPosition()
@@ -87,11 +88,15 @@
       throw new Error('in TextObject: Must not happen')

   select: ->
-    @selectionStopped = false
     selectResults = []
-    @countTimes =>
-      for selection in @editor.getSelections() when not @selectionStopped
+    @countTimes ({stop}) =>
+      @stopSelection = stop
+
+      for selection in @editor.getSelections()
         selectResults.push(@selectTextObject(selection))
+        unless @isSuportCount()
+          @stopSelection() # FIXME: quick-fix for #560
+

     if @needToKeepColumn()
       for selection in @editor.getSelections()
@@ -108,12 +113,20 @@

   selectTextObject: (selection) ->
     if range = @getRange(selection)
+      oldRange = selection.getBufferRange()
+
       needToKeepColumn = @needToKeepColumn()
       if needToKeepColumn and not @isMode('visual', 'linewise')
         @vimState.modeManager.activate('visual', 'linewise')
       swrap(selection).setBufferRangeSafely(range, keepGoalColumn: needToKeepColumn)
+
+      newRange = selection.getBufferRange()
+      if newRange.isEqual(oldRange)
+        @stopSelection() # FIXME: quick-fix for #560
+
       true
     else
+      @stopSelection() # FIXME: quick-fix for #560
       false

   getRange: ->
@@ -179,6 +192,7 @@
   adjustInnerRange: true
   pair: null
   wise: 'characterwise'
+  supportCount: true

   getPattern: ->
     [open, close] = @pair
@@ -614,6 +628,7 @@
 class Paragraph extends TextObject
   @extend(false)
   wise: 'linewise'
+  supportCount: true

   findRow: (fromRow, direction, fn) ->
     fn.reset?()
@@ -657,6 +672,7 @@
     predict

   getRange: (selection) ->
+    originalRange = selection.getBufferRange()
     fromRow = @getNormalizedHeadBufferPosition(selection).row

     if @isMode('visual', 'linewise')


Add repo.checkoutFile

Add repo.checkoutFile

--- src/repo.coffee
+++ src/repo.coffee
@@ -73,7 +73,7 @@
   #
   #   # Skip some (for pagination):
   #   repo.commits "master", 30, 30, (err, commits) ->
-  #
+  #
   #   # Do not limit commits amount
   #   repo.commits "master", -1, (err, commits) ->
   #
@@ -93,10 +93,10 @@
     Commit.find_all this, start, options, callback

-  # Internal: Returns current commit id
-  #
+  # Internal: Returns current commit id
+  #
   # callback - Receives `(err, id)`.
-  #
+  #
   current_commit_id: (callback) ->
     @git "rev-parse HEAD", {}, []
     , (err, stdout, stderr) =>
@@ -104,10 +104,10 @@
       return callback null, _.first stdout.split "\n"

-  # Public:
-  #
+  # Public:
+  #
   # callback - Receives `(err, commit)`
-  #
+  #
   current_commit: (callback) ->
     @current_commit_id (err, commit_id) =>
       return callback err if err
@@ -241,7 +241,7 @@
   status: (callback) ->
     return Status(this, callback)

-  # Public: Show information about files in the index and the
+  # Public: Show information about files in the index and the
   #         working tree.
   #
   # options  - An Object of command line arguments to pass to
@@ -333,6 +333,19 @@
   checkout: (treeish, callback) ->
     @git "checkout", {}, treeish, callback

+  # Public: Checkout file(s) to the index
+  #
+  # files    - Array of String paths; or a String path. If you want to
+  #            checkout all files pass '.'.
+  # options  - Object (optional).
+  #            "force" - Boolean
+  # callback - Receives `(err)`.
+  #
+  checkoutFile: (files, options, callback) ->
+    [options, callback] = [callback, options] if !callback
+    options ?= {}
+    files = [files] if _.isString files
+    @git "checkout", options, _.flatten['--', files], callback

   # Public: Commit some code.
   #
@@ -357,13 +370,13 @@
   # options  - Object (optional).
   #            "all"   - Boolean
   # callback - Receives `(err)`.
-  #
+  #
   add: (files, options, callback) ->
     [options, callback] = [callback, options] if !callback
     options ?= {}
     files = [files] if _.isString files
     @git "add", options, files, callback
-
+
   # Public: Remove files from the index.
   #
   # files    - Array of String paths; or a String path.
@@ -411,7 +424,7 @@
                 return callback null
             else
               return callback null
-
+
   # Public: Pull the remotes from the master.
   #
   # Arguments: ([[remote_name, ]branch_name, ]callback)
@@ -432,9 +445,9 @@
       @git "pull", {}, [remote, branch], (err, stdout, stderr) =>
         return callback stderr if err
         return callback null
-
+
   # Internal: Parse the list of files from `git ls-files`
-  #
+  #
   # Return Files[]
   parse_lsFiles: (text,options) ->
     files = []


KDView: default _windowDidResize delegate function removed

we do the necessary check on windowController not necessary to pollute prototype

--- src/core/view.coffee
+++ src/core/view.coffee
@@ -911,8 +911,6 @@

   getTooltip:-> @tooltip

-  _windowDidResize:->
-
   listenWindowResize:(state=yes)->

     if state


Add comment

Add comment

--- scripts/modules/featured-books/featured-books.coffee
+++ scripts/modules/featured-books/featured-books.coffee
@@ -29,6 +29,7 @@
         @stopCarousel()
         @$el.find('.book').show()

+      # Called when the 'Less' link is clicked
       less: () ->
         @startCarousel()
         @$el.find('.book').removeAttr('style')


fix the popup alert when starting a new trial

--- services/web/public/coffee/main/account-upgrade.coffee
+++ services/web/public/coffee/main/account-upgrade.coffee
@@ -6,12 +6,12 @@
 		$scope.buttonClass = "btn-primary"

 		$scope.startFreeTrial = (source, couponCode) ->
+			w = window.open()
 			sixpack.convert "track-changes-discount", ->
-
-				sixpack.participate 'free-trial-plan', ['student', 'collaborator'], (planName, rawResponse)->
-					ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source)
-					url = "/user/subscription/new?planCode=#{planName}_free_trial_7_days&ssp=#{planName == 'collaborator'}"
-					if couponCode?
-						url = "#{url}&cc=#{couponCode}"
-					window.open(url)
-					$scope.startedFreeTrial = true+			sixpack.participate 'free-trial-plan', ['student', 'collaborator'], (planName, rawResponse)->
+				ga?('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source)
+				url = "/user/subscription/new?planCode=#{planName}_free_trial_7_days&ssp=#{planName == 'collaborator'}"
+				if couponCode?
+					url = "#{url}&cc=#{couponCode}"
+				$scope.startedFreeTrial = true
+				w.location = url


widget.inputElement

widget.inputElement

--- app/assets/javascripts/uploadcare/widget/base-widget.js.coffee
+++ app/assets/javascripts/uploadcare/widget/base-widget.js.coffee
@@ -99,4 +99,5 @@
         ]
         @__api.onChange = @onChange
         @__api.onUploadComplete = @onUploadComplete
+        @__api.inputElement = @element.get(0)
       @__api


Remove old bundles directory from include paths

--- src/stdlib/require.coffee
+++ src/stdlib/require.coffee
@@ -8,7 +8,6 @@
   "#{window.resourcePath}/vendor/packages"
   "#{window.resourcePath}/vendor"
   "#{window.resourcePath}/static"
-  "#{window.resourcePath}/bundles"
   "#{window.resourcePath}/themes"
   "#{window.resourcePath}"
 ]


fixing test

fixing test

--- tests/poller.coffee
+++ tests/poller.coffee
@@ -1,21 +1,31 @@
-
 should = require 'should'
 sinon = require 'sinon'
 Konnector = require '../server/models/konnector'
 poller = require '../server/lib/konnector_poller'

+hour = 60 * 60 * 1000
+day = 24 * hour
+week = 7 * day
+
 describe 'Testing konnector poller', ->
+    before ->
+        @sandbox = sinon.sandbox.create useFakeTimers: true
+        @spy = @sandbox.spy poller, 'prepareNextCheck'
+    after ->
+        @sandbox.restore()

     it 'When the cron function is called', ->
         poller.start()
-        @sandbox = sinon.sandbox.create()
-        @clock = @sandbox.useFakeTimers()
-        @stub = @sandbox.stub poller, 'prepareNextCheck'
+        @spy.callCount.should.equal 1

-    it 'Then the cron function should not have been called before one week', ->
-        @clock.tick 1000 * 60 * 60 * 24 * 6
-        @stub.calledOnce.should.be.true
+    it 'Then the cron function should not have been called after 6 days', ->
+        @sandbox.clock.tick 6 * day
+        @spy.callCount.should.equal 1

-    it 'And the cron function should have been called only once after one week', ->
-        @clock.tick 1000 * 60 * 60 * 24 * 7
-        @stub.calledTwice.should.be.true
+    it 'But should be called one day later', ->
+        @sandbox.clock.tick 1 * day
+        @spy.callCount.should.equal 2
+
+    it 'And the cron function should have been called again after one more week', ->
+        @sandbox.clock.tick 1 * week
+        @spy.callCount.should.equal 3


the best javascript color library

the best javascript color library

--- src/color.coffee
+++ src/color.coffee
@@ -116,19 +116,7 @@

       rgba: -> "rgba(#{self.r()}, #{self.g()}, #{self.b()}, #{self.a()})"

-      toHex: ->
-        hexString = (number) ->
-          number.toString(16)
-        padString = (hexString) ->
-          if hexString.length == 1
-            return hexString = "0" + hexString
-
-          return hexString
-
-        hexFromNumber = (number) ->
-          return padString(hexString(number))
-
-        "##{hexFromNumber(channels[0])}#{hexFromNumber(channels[1])}#{hexFromNumber(channels[2])}"
+

       toString: -> self.rgba()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -42,7 +42,7 @@

     if arguments.length == 2
       if arguments[0].length == 3
-      parsedColor = [parseInt(arguments[0][0]), parseInt(arguments[0][1]), parseInt(arguments[0][2]), parseFloat(arguments[1])]
+        parsedColor = [parseInt(arguments[0][0]), parseInt(arguments[0][1]), parseInt(arguments[0][2]), parseFloat(arguments[1])]
     else if arguments.length > 2
       alpha = if arguments[3]? then arguments[3] else 1
       parsedColor = [parseInt(arguments[0]), parseInt(arguments[1]), parseInt(arguments[2]), parseFloat(alpha)]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -55,7 +55,7 @@
       r = g = b = lightness
     else
       hue = (hue % 360) / 60
-      hue_floor = hue.floor
+      hue_floor = hue.floor()
       hue_diff = hue - hue_floor

       p = lightness * (1 - saturation)
@@ -289,29 +289,24 @@

       {min, max} = [r, g, b].extremes()

-      hue = saturation = lightness = (max + min) / 2
-
-      if max == min
-        hue = saturation = 0
-      else
-        chroma = max - min
-
-        saturation =
-          if lightness > 0.5
-            chroma / (1 - lightness)
-          else
-            chroma / lightness
-
-        saturation /= 2
-
-        switch max
-          when r then hue = ((g - b) / chroma) + 0
-          when g then hue = ((b - r) / chroma) + 2
-          when b then hue = ((r - g) / chroma) + 4
-
-        hue *= 60
-
-      return [hue, saturation, lightness, @a]
+      delta = max - min
+      hue = 0
+      lightness = max
+      saturation = (if max == 0 then 0 else delta / max)
+
+      if delta != 0
+        if r == max
+          hue = (g - b) / delta
+        else if g == max
+          hue = 2 + (b - r) / delta
+        else
+          hue = 4 + (r - g) / delta
+
+      hue *= 60
+
+      hue += 360 if hue < 0
+
+      return [hue, saturation, lightness, @a]

     toString: ->
       "rgba(#{@r}, #{@g}, #{@b}, #{@a})"


:memo: Add period

:memo: Add period

--- src/color.coffee
+++ src/color.coffee
@@ -5,7 +5,7 @@
 # at the key path is of type 'color'.
 module.exports =
 class Color
-  # Essential: Parse a {String} or {Object} into a {Color}
+  # Essential: Parse a {String} or {Object} into a {Color}.
   #
   # * `value` - A {String} such as `'white'`, `#ff00ff`, or
   #             `'rgba(255, 15, 60, .75)'` or an {Object} with `red`, `green`,


Use GitHub style when "save as HTML"

Use GitHub style when "save as HTML"

#322

--- lib/markdown-preview-view.coffee
+++ lib/markdown-preview-view.coffee
@@ -277,7 +277,7 @@
                   <title>#{title}</title>

-              #{htmlBody}
+              #{htmlBody}
             """ + "\n" # Ensure trailing newline

           fs.writeFileSync(htmlFilePath, html)


Fix partial helper (path+name instead of name+path)

--- src/swag.coffee
+++ src/swag.coffee
@@ -420,7 +420,7 @@
         if newValue then newValue else defaultValue

     Handlebars.registerHelper 'partial', (name, data) ->
-        partial = name + exports.Config.partialsPath
+        partial = exports.Config.partialsPath + name
         data = if Utils.isUndefined(data) then {} else data
         Handlebars.registerPartial(name, require partial) unless Handlebars.partials[name]?
         Utils.safeString Handlebars.partials[name](data)


use author in line view instead of committer. fixes #25 for real

--- lib/views/blame-line-view.coffee
+++ lib/views/blame-line-view.coffee
@@ -43,7 +43,7 @@
           @props.hash.substring(0, HASH_LENGTH)
         span className: 'date', @props.date
         span className: 'committer text-highlight',
-          @props.committer.split(' ').slice(-1)[0]
+          @props.author.split(' ').slice(-1)[0]

   componentDidMount: ->
     $el = $(@getDOMNode())


Upgrade merge list view

Upgrade merge list view

--- lib/views/merge-list-view.coffee
+++ lib/views/merge-list-view.coffee
@@ -1,5 +1,5 @@
 fs = require 'fs-plus'
-{$$, SelectListView} = require 'atom'
+{$$, SelectListView} = require 'atom-space-pen-views'
 git = require '../git'
 StatusView = require './status-view'

@@ -7,7 +7,7 @@
 class ListView extends SelectListView
   initialize: (@data) ->
     super
-    @addClass 'overlay from-top'
+    @show()
     @parseData()

   parseData: ->
@@ -18,10 +18,18 @@
       unless item is ''
         branches.push {name: item}
     @setItems branches
-    atom.workspaceView.append this
     @focusFilterEditor()

   getFilterKey: -> 'name'
+
+  show: ->
+    @panel ?= atom.workspace.addModalPanel(item: this)
+    @panel.show()
+
+  cancelled: -> @hide()
+
+  hide: ->
+    @panel?.hide()

   viewForItem: ({name}) ->
     current = false


implement POST-like testing for services

--- library/exposure/behavior.coffee
+++ library/exposure/behavior.coffee
@@ -39,6 +39,13 @@
 # is actually implementing something useful, not just a stub one.
 assert module.exports.Behavior = class Behavior extends Embedded

+    # This is a marker that indicates to some internal subsystems
+    # that this class has to be considered abstract and therefore
+    # can not be treated as a complete class implementation. This
+    # mainly is used to exclude or account for abstract classes.
+    # Once inherited from, the inheritee is not abstract anymore.
+    @abstract yes
+
     # These declarations below are implantations of the abstracted
     # components by the means of the dynamic recomposition system.
     # Please take a look at the `Composition` class implementation
@@ -46,9 +53,28 @@
     # Each of these will be dynamicall integrated in class hierarchy.
     @implanting Auxiliaries, Bilateral, Localized, Pinpoint

-    # This is a marker that indicates to some internal subsystems
-    # that this class has to be considered abstract and therefore
-    # can not be treated as a complete class implementation. This
-    # mainly is used to exclude or account for abstract classes.
-    # Once inherited from, the inheritee is not abstract anymore.
-    @abstract yes
+    # This method is part of an internal integrity assurance toolkit.
+    # Once the behavior-enabled service emits a signal that indicate
+    # service has been successfuly booted, this implementation takes
+    # on performing a series of tests to ensure that current service
+    # has been propertly installed, bootloaded and then initialized.
+    powerOnSelfTest: @onetimer "booted", ->
+        noEco = "ecosystem hosted by the root missing"
+        noArch = "tools provided by archetype missing"
+        noRoots = "the root service cannot be located"
+        notSys = "service is not present in ecosystem"
+        noService = "service identification is missing"
+        noIdentic = "missing constructor identity tags"
+        namesIncons = "inconsistent service identities"
+        notInitialize = "improperly booted or initilize"
+        m = "Power-on self-testing OK at the %s".magenta
+        identity = @constructor?.identify?().toString()
+        assert _.isFunction(this.tap or false), noArch
+        assert _.isObject(@root or undefined), noRoots
+        assert _.isObject(@root.ecosystem or 0), noEco
+        assert _.isString(@service or null), noService
+        assert _.isString(identity or null), noIdentic
+        assert @initialized and @booted, notInitialize
+        assert this in (@root.ecosystem or []), notSys
+        assert (try identity is @service), namesIncons
+        logger.debug m, identity.underline.magenta


fix a misnomer in the Policies

fix a misnomer in the Policies

--- library/exposure/policies.coffee
+++ library/exposure/policies.coffee
@@ -57,7 +57,7 @@
     # using POJO notation, as in `qualifier: privilege` style. If
     # one more arg is given, then is treated as conditional func
     # that is run to determine the privilege, once is requested.
-    @allow: (definition, condition) ->
+    @granting: (definition, condition) ->
         isEmpty = "an empty definition has been given"
         noCondition = "got invalid conditional argument"
         notDefined = "the definition has to be an object"


add "...for this section" to enrollment code link

--- src/components/course-settings/cc-enrollment-code.cjsx
+++ src/components/course-settings/cc-enrollment-code.cjsx
@@ -7,7 +7,7 @@
 {TutorInput} = require '../tutor-input'
 CourseGroupingLabel = require '../course-grouping-label'
 Icon = require '../icon'
-TITLE = 'Get Student Enrollment Code'
+TITLE = 'Get Student Enrollment Code for this section'

 module.exports = React.createClass
   displayName: 'PeriodEnrollmentCode'


Fixed incorrect content length of scripts from the service.

--- start.coffee
+++ start.coffee
@@ -121,10 +121,10 @@
     done()

 memorize = (identifier, done) ->
-  read identifier, "UTF8", (error, data) ->
+  read identifier, (error, data) ->
     files.add identifier,
       size:data.length
-      data:data
+      data:data.toString("UTF-8")
     console.info memorized:identifier
     if done then done()


Request confirm for validation delete

Request confirm for validation delete

--- www/coffee/backbone/views/validation_view.coffee
+++ www/coffee/backbone/views/validation_view.coffee
@@ -39,9 +39,10 @@
       @detailsVisible = true

   hideDetails: =>
-    @$el.find('.validation-details').slideUp()
-    @removeHighlightPolygon()
-    @detailsVisible = false
+    if @detailsVisible
+      @$el.find('.validation-details').slideUp()
+      @removeHighlightPolygon()
+      @detailsVisible = false

   showHighlightPolygon: ->
     unless @highlightPolygon?
@@ -58,7 +59,8 @@
       delete @highlightPolygon

   delete: =>
-    @validation.localDestroy()
+    if confirm('are you sure you want to delete this validation?')
+      @validation.localDestroy()

   onClose: ->
     @map.removeLayer(@mapPolygon)


Change regex that determines whether a link is to an image

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

   # Return true if uri string is a URI to an image
   @isImageUri: (uri) ->
-    uri.match(/^https?\:\/\/.*\.(jpeg|jpg|gif|png)$/i)?
+    uri.match(/^https?\:\/\/.*[\.|=](jpeg|jpg|gif|png)$/i)?

   # Merge input objects into one object
   @merge = (xs...) ->
@@ -11,7 +11,7 @@
       tap {}, (m) -> m[k] = v for k, v of x for x in xs

   @parseOptions: ->
-
+
     getOpt = (name, defaultValue) ->
       return defaultValue unless process.env['HUBOT_FLEEP_' + name]?
       return process.env['HUBOT_FLEEP_' + name]


Fix python syntax in statement test.

Fix python syntax in statement test.

--- test/statement_count_spec.coffee
+++ test/statement_count_spec.coffee
@@ -24,7 +24,8 @@
         self.moveRight();
     """
     cs "for sum", "python", 3, """
-      for i in xrange(1,10) self.say(i)
+      for i in xrange(1,10):
+        self.say(i)
     """
     cs "function", "python", 3, """
       def x(a):


Adjusting browser’s matrix

Adjusting browser’s matrix

--- test/tests/utils/browsers.coffee
+++ test/tests/utils/browsers.coffee
@@ -11,37 +11,36 @@

     # phantomjs

-    # # chrome
-    # chrome_linux
+    # -- chrome
+    chrome_linux
     # chrome_win8
     # chrome_mountain

-    # # firefox
+    # -- firefox
     # firefox_win8
-    # firefox_linux
+    firefox_linux
     # firefox_snow

-    # # safari
+    # safari
     # safari5_win7
     # safari5_snow
-    # safari6_mountain
-
-    # # ie
+    safari6_mountain
+
+    # -- ie
     # ie6_winxp
     # ie7_winxp
-    ie8_winxp
-
+    # ie8_winxp
     ie8_win7
     ie9_win7
-
     ie10_win8
-
-    # # ios
-    # ios_iphone
-    # ios_ipad
-
-    # # android
-    # # none - awiting sauce labs to support it
+
+    # -- ios
+    ios_61_iphone
+    ios_61_ipad
+
+    # -- android
+    android_40_phone
+    android_40_tablet
   ]

@@ -218,31 +217,33 @@
 # ios
 # ----------------------------------------------------------------------------

-ios_iphone =
+ios_61_iphone =
   browserName: 'iphone'
   platform: 'OS X 10.8'
-  tags: ['the-router-browser', 'ios', 'iphone']
-  'record-video': true
-
-ios_ipad =
+  tags: ['the-router-browser', 'ios', '6.1', 'iphone']
+  'record-video': true
+
+ios_61_ipad =
   browserName: 'ipad'
   platform: 'OS X 10.8'
-  tags: ['the-router-browser', 'ios', 'ipad']
+  tags: ['the-router-browser', 'ios', '6.1', 'ipad']
   'record-video': true

 # android
 # ----------------------------------------------------------------------------

-android_phone =
+android_40_phone =
   browserName: 'android'
-  platform: 'Linux'
-  tags: ['the-router-browser', 'android', 'phone']
-  'record-video': true
-
-android_tablet =
+  version: '4.0'
+  platform: 'Linux'
+  tags: ['the-router-browser', 'android', '4.0', 'phone']
+  'record-video': true
+
+android_40_tablet =
   browserName: 'android'
+  version: '4.0'
   'device-type': 'tablet'
   platform: 'Linux'
-  tags: ['the-router-browser', 'android', 'tablet']
+  tags: ['the-router-browser', 'android', '4.0', 'tablet']
   'record-video': true


Add some functions

Add some functions

--- lisp.coffee
+++ lisp.coffee
@@ -17,7 +17,8 @@
   constructor: (@funname, @args) ->
   toString: -> "(#{@funname} #{@values.map((v) -> v.toString()).join(' ')})"

-SF_NAMES = ['cond', 'quote', 'lambda', 'defun']
+# TODO: 下の実装と離れてしまっているのをどうにかしたい
+SF_NAMES = ['cond', 'quote', 'lambda', 'defun', 'setq', 'defmacro']
 class SpecialForm
   constructor: (@name, @args) ->
   toString: -> "(#{@name} #{@args.map((v) -> v.toString()).join(' ')})"
@@ -27,8 +28,11 @@

 class Environment
   constructor: (@variables) ->
-  get: (name) -> @variables[name]
+    @macros = {}
+  get: (name)      -> @variables[name]
   set: (name, val) -> @variables[name] = val
+  getMacro: (name)        -> @macros[name]
+  setMacro: (name, macro) -> @macros[name] = macro

 class LispError extends Error
   constructor: (@message) ->
@@ -160,7 +164,7 @@
     envstack.push new Environment(lambda.params.values.reduce(
       ((env, param, index) -> env[param.name] = args[index]; env), {}))
     [name, args...] = lambda.body.values
-    ret = @eval_expr(new CallFun(name, args)) #とりあえず
+    ret = @eval_expr(new CallFun(name, args)) #TODO: とりあえず
     envstack.pop()
     return ret

@@ -180,6 +184,11 @@
             new Lambda(args[0], args[1])
           'defun': ->
             currentEnv().set(args[0].name, new Lambda(args[1], args[2]))
+          'setq': =>
+            value = @eval_expr(args[1])
+            currentEnv().set(args[0].name, value)
+          'defmacro': ->
+            currentEnv().setMacro(args[0].name, new Lambda(args[1], args[2]))
         }[expr.name.name]()

       when 'CallFun'
@@ -190,7 +199,8 @@
             @exec_lambda(funname)
           when 'Symbol'
             funcs = {
-              '+': -> args.reduce(((sum, n) -> sum + n), 0),
+              'list': -> args
+              '+': -> args.reduce(((sum, n) -> sum + n), 0)
               'car': -> args[0].values[0]
               'cdr': -> new List args[0].values[1..]
               'cons': -> new List [args[0], args[1].values...]


Don't hang in failing examples that use jasmine.clock

--- spec_app/spec/javascripts/helpers/reset_up.js.coffee
+++ spec_app/spec/javascripts/helpers/reset_up.js.coffee
@@ -1,4 +1,8 @@
 afterEach (done) ->
+  # If the spec has installed the Jasmine clock, uninstall it so
+  # the timeout below will actually happen.
+  jasmine.clock().uninstall()
+
   # Wait one more frame so pending callbacks have a chance to run.
   # Pending callbacks might change the URL or cause errors that bleed into
   # the next example.


Assume cli files are executable

Assume cli files are executable

--- spec/command-installer-spec.coffee
+++ spec/command-installer-spec.coffee
@@ -10,12 +10,12 @@
   installationFilePath = path.join(installationPath, commandName)

   beforeEach ->
+    fs.chmodSync(commandFilePath, '755')
     spyOn(installer, 'getInstallDirectory').andReturn installationPath

   describe "on #darwin", ->
     it "symlinks the command and makes it executable", ->
       expect(fs.isFileSync(commandFilePath)).toBeTruthy()
-      expect(fs.isExecutableSync(commandFilePath)).toBeFalsy()
       expect(fs.isFileSync(installationFilePath)).toBeFalsy()

       installDone = false


add debug code

add debug code

--- src/dockerhub.coffee
+++ src/dockerhub.coffee
@@ -106,6 +106,9 @@
     if token = triger_tokens[repo]
       res.send "#{repo} の build trigger を発火します"
       robot.http("https://registry.hub.docker.com/u/#{repo}/trigger/#{token}").post({"build":"true"}) (post_err, post_res, post_body) ->
+        robot.logger.debug(post_err)
+        robot.logger.debug(post_res)
+        robot.logger.debug(post_body)
         if post_err
           res.send "エラーが発生しました: #{post_err}"
         else


update specs to include image size

update specs to include image size

--- spec/image-editor-view-spec.coffee
+++ spec/image-editor-view-spec.coffee
@@ -98,7 +98,7 @@
         expect(imageSizeStatus).toExist()

     it "displays the size of the image", ->
-      expect(imageSizeStatus.text()).toBe '10x10'
+      expect(imageSizeStatus.text()).toBe '10x10 392B'

   describe "when special characters are used in the file name", ->
     describe "when '?' exists in the file name", ->


:fire: garbage

:fire: garbage

--- spec/markdown-toc-auto-spec.coffee
+++ spec/markdown-toc-auto-spec.coffee
@@ -46,24 +46,3 @@
       expect(deserializeTocOptions('abc:def')).toEqual({})
       expect(deserializeTocOptions('abc')).toEqual({})
       expect(deserializeTocOptions('')).toEqual({})
-
-  # WIP
-  xdescribe "??", ->
-    [workDir, editor] = []
-
-    beforeEach ->
-      waitsForPromise ->
-        atom.packages.activatePackage('language-gfm')
-
-      waitsForPromise ->
-        temp.mkdirSync('working')
-        workDir = temp.path()
-        filePathDst = path.join(workDir, "sample.md")
-        fs.copySync(atom.project.resolvePath('./'), workDir)
-        atom.workspace.open(filePathDst).then (e) ->
-          editor = e
-
-    # describe "generateToc", ->
-    #   it "create path", ->
-    #     console.log editor.getGrammar().scopeName
-    #     console.log editor.getPath()


Fix test for closing commit pane when commits are rejected

--- spec/models/git-commit-spec.coffee
+++ spec/models/git-commit-spec.coffee
@@ -175,12 +175,12 @@
       waitsForPromise ->
         GitCommit(repo)

-    it "notifies of error and doesn't close commit pane", ->
+    it "notifies of error and closes commit pane", ->
       textEditor.save()
       waitsFor -> notifier.addError.callCount > 0
       runs ->
         expect(notifier.addError).toHaveBeenCalledWith 'commit error'
-        expect(commitPane.destroy).not.toHaveBeenCalled()
+        expect(commitPane.destroy).toHaveBeenCalled()

   describe "when the verbose commit setting is true", ->
     beforeEach ->


:green_heart:

--- spec/workspace-element-spec.coffee
+++ spec/workspace-element-spec.coffee
@@ -47,9 +47,9 @@

     it "updates the font-family based on the 'editor.fontFamily' config value", ->
       initialCharWidth = editor.getDefaultCharWidth()
-      expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily')
+      expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily') + ", 'Apple Color Emoji'"
       atom.config.set('editor.fontFamily', 'sans-serif')
-      expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily')
+      expect(getComputedStyle(editorElement).fontFamily).toBe atom.config.get('editor.fontFamily') + ", 'Apple Color Emoji'"
       expect(editor.getDefaultCharWidth()).not.toBe initialCharWidth

     it "updates the line-height based on the 'editor.lineHeight' config value", ->


Fix IE typeahead address autosuggest.

Fix IE typeahead address autosuggest.

--- src/geocoding.coffee
+++ src/geocoding.coffee
@@ -73,8 +73,11 @@
                     @options.selectionCallback ev, data
                 else
                     @setStreet(data).done =>
-                        @options.$inputEl.val (@options.$inputEl.val() + ' ')
-                        @options.$inputEl.trigger 'input'
+                        # To support IE on typeahead < v11, we need to call internal API
+                        # because typeahead listens to different events on IE compared to
+                        # web browsers.
+                        typeaheadInput = @options.$inputEl.data('ttTypeahead').input
+                        typeaheadInput.setInputValue @options.$inputEl.val() + ' '
             else
                 @setStreet null


simplify landcover topology

simplify landcover topology

--- src/data.coffee
+++ src/data.coffee
@@ -333,10 +333,10 @@
         quantization: 1000000
         'property-transform': (f) -> f.properties
       })
-      land: topojson.topology({land: turf.featurecollection(land)}, {
+      land: topojson.simplify(topojson.topology({land: turf.featurecollection(land)}, {
         quantization: 1000000
         'property-transform': (f) -> f.properties
-      })
+      }), 'minimum-area': 200, 'coordinate-system': 'cartesian')
       dem: dem
       routes: route(obj[id]) for id in routeIds.values()
       bbox: [].concat(project(bbox.slice(0, 2)), project(bbox.slice(2, 4)))


<defs> generation working!

<defs> generation working!

--- svgtiler.coffee
+++ svgtiler.coffee
@@ -65,7 +65,7 @@
     fs.writeFileSync filename, @renderSVG mappings
   renderSVG: (mappings) ->
     doc = domImplementation.createDocument SVGNS, 'svg'
-    doc.appendChild defs = doc.createElementNS SVGNS, 'defs'
+    doc.documentElement.appendChild defs = doc.createElementNS SVGNS, 'defs'
     symbols = {}
     for row, i in @data
       for cell, j in row
@@ -77,7 +77,6 @@
       defs.appendChild node = doc.createElementNS SVGNS, 'symbol'
       node.setAttribute 'id', key
       node.appendChild symbol.xml
-    console.log doc.firstChild
     new XMLSerializer().serializeToString doc

 class Mappings


Optimize for collapsed ranges

Optimize for collapsed ranges

--- src/trix/text_view.coffee
+++ src/trix/text_view.coffee
@@ -99,23 +99,32 @@
     return unless selection.rangeCount > 0

     range = selection.getRangeAt(0)
-    return unless isWithin(@element, range.startContainer) and isWithin(@element, range.endContainer)

-    startPosition = @findPositionFromContainerAtOffset(range.startContainer, range.startOffset)
-    endPosition = @findPositionFromContainerAtOffset(range.endContainer, range.endOffset)
-    [startPosition, endPosition]
+    if range.collapsed
+      if isWithin(@element, range.endContainer)
+        position = @findPositionFromContainerAtOffset(range.endContainer, range.endOffset)
+        [position, position]
+    else
+      if isWithin(@element, range.startContainer) and isWithin(@element, range.endContainer)
+        startPosition = @findPositionFromContainerAtOffset(range.startContainer, range.startOffset)
+        endPosition = @findPositionFromContainerAtOffset(range.endContainer, range.endOffset)
+        [startPosition, endPosition]

   setSelectedRange: ([startPosition, endPosition]) ->
     return if @lockedRange
     return unless startPosition? and endPosition?

+    rangeStart = @findContainerAndOffsetForPosition(startPosition)
+    rangeEnd =
+      if startPosition is endPosition
+        rangeStart
+      else
+        @findContainerAndOffsetForPosition(endPosition)
+
     range = document.createRange()
-    [startContainer, startOffset] = @findContainerAndOffsetForPosition(startPosition)
-    [endContainer, endOffset] = @findContainerAndOffsetForPosition(endPosition)
-
     try
-      range.setStart(startContainer, startOffset)
-      range.setEnd(endContainer, endOffset)
+      range.setStart(rangeStart...)
+      range.setEnd(rangeEnd...)
     catch err
       range.setStart(@element, 0)
       range.setEnd(@element, 0)


Fix redundant state bug.

Fix redundant state bug.

--- src/js/collection-editor.coffee
+++ src/js/collection-editor.coffee
@@ -391,6 +391,9 @@

 # write a Google OAuth access token into a cached cookie that should expire when the access token does
 set_access_token_cookie = (params, callback) ->
+  if params['state']?
+    console.log "Replacing hash with state: #{params['state']}"
+    history.replaceState(null,'',window.location.href.replace("#{location.hash}","##{params['state']}"))
   if params['access_token']?
     # validate the token per https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken
     $.ajax "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=#{params['access_token']}",


Don't submit submit_button to fusion table insert

(cherry picked from commit 9269f01ce15345e950ba2dfdd2e60bf95c8354ba)

--- src/js/collection-editor.coffee
+++ src/js/collection-editor.coffee
@@ -198,7 +198,7 @@
     $('input[data-urn=true]').attr('value',urn)
     update_timestamp_inputs()
     for child in $('#collection_form').children()
-      if $(child).attr('id') && ($(child).attr('type') != 'hidden') && !$(child).attr('id').match(/-clippy$/)
+      if $(child).attr('id') && ($(child).attr('type') != 'hidden') && !$(child).attr('id').match(/-clippy$/) && ($(child).attr('id') != 'submit_button')
         column_names.push fusion_tables_escape($(child).attr('id'))
         row_values.push fusion_tables_escape(get_value_for_form_input(child))
     fusion_tables_query "INSERT INTO #{collection} (#{column_names.join(', ')}) VALUES (#{row_values.join(', ')})", (data) ->


DateTimeInputBlock: Fixed a moment global usage

--- src/elements/DateTime/DateTimeInputBlock.coffee
+++ src/elements/DateTime/DateTimeInputBlock.coffee
@@ -4,6 +4,7 @@
  * MIT Licence
  * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
 ###
+moment = require('moment')

 class CUI.DateTimeInputBlock extends CUI.InputBlock
 	initOpts: ->


game levels

game levels

--- src/game.coffee
+++ src/game.coffee
@@ -37,11 +37,10 @@
   game_cache[name] = result
   result

-create_level = (game_dict, level) ->
-  level_dict = game_dict.levels[level]
+create_level = (game_levels, level) ->
+  level_dict = game_levels[level]
   level_dict.level_index = level
-  level_dict.level_count = game_dict.levels.length
-  level_dict.game = game_dict.name
+  level_dict.level_count = game_levels.length
   level_dict

 exports.game = (rx, query) ->
@@ -50,7 +49,8 @@
   world = god(rx, game_dict)

   level = query.level or 0
-  level_dict = create_level(game_dict, level)
+  level_dict = create_level(game_dict.levels, level)
+  level_dict.game = game_dict.name
   level_world = world.add_child level_dict
   for child in layout
     level_world.add_child child(level_dict)


Fix error when document not found

Fix error when document not found

--- src/index.coffee
+++ src/index.coffee
@@ -60,7 +60,7 @@
         console.log 'Error with fetching document by id: ' + error if error

         @close() if @_closeAfterRequest
-        after if results.length is 1 then results[0] else false
+        after if results and results.length is 1 then results[0] else false

   find: (table, params, options, after) ->
     [params, options, after] = @_normalizeArguments params, options, after


Make sure everyone in a Match is alive.

Make sure everyone in a Match is alive.

--- src/index.coffee
+++ src/index.coffee
@@ -45,6 +45,11 @@
       else
         msg.reply "I don't know anyone named #{username}!
           Notice that they have to speak first, for me to notice them."
+        return
+
+    for challenger in challengers
+      unless challenger.hp() > 0
+        msg.reply "#{challenger.displayName()} is dead!"
         return

     m = theCircle.startMatch(challengers)


testing

testing

--- src/index.coffee
+++ src/index.coffee
@@ -24,6 +24,7 @@
     @meshblu.subscribe({uuid: 'c15a9222-1f4e-4724-927f-a4390654fc57'})

   watchForMeeting: () =>
+    console.log 'watchForMeeting'
     @meshblu.on 'config', (event) => @checkMeeting event

   checkMeeting:(event) =>
@@ -42,7 +43,7 @@
         @validUntil = noShowLimit
         console.log "Initializing valid until for: #{@validUntil}"

-      if (@validUntil.isBefore(moment().utc() && moment().utc().isAfter(noShowLimit)))
+      if (moment(@validUntil).isBefore(moment().utc() && moment().utc().isAfter(noShowLimit)))
         meetingId = _.get currentMeeting, 'meetingId'
         console.log "====================================="
         console.log "meetingStartTime: #{meetingStartTime} and No show limit :#{noShowLimit.toISOString()}"


* forget to add the dest property

* forget to add the dest property

--- src/index.coffee
+++ src/index.coffee
@@ -15,6 +15,10 @@
 module.exports  = class CopyFileTask
   register CopyFileTask, ResourceTask #the real name: '/Resource/CopyFile'
   aliases CopyFileTask, 'Copy', 'copy', 'FileCopy'
+
+  defineProperties @,
+    dest:
+      type: 'String'

   _executeSync: (aFile)->
     if aFile.path? and aFile.dest?


I'm not really using EXP yet.

I'm not really using EXP yet.

--- src/index.coffee
+++ src/index.coffee
@@ -12,7 +12,6 @@
 #   hubot hammer <n> - Choose an attack during a hammersport round.
 #   hubot hammeradmin respawn <user>|everyone - Respawn a chosen user at full health.
 #   hubot hammeradmin kill <user>|everyone - Instakill a chosen user.
-#   hubot hammeradmin setexp <user> +n|-n|n - Set a user's current EXP.
 #   hubot hammeradmin report <user> - Show a summary of hammersport state. Danger: spammy.
 #
 # Author:
@@ -103,8 +102,6 @@
     c.kill() for c in challengers
     msg.reply reportAction challengers.length, 'killed'

-  robot.respond /hammeradmin setexp @?(\w+) ([+-]?\d+)/i, (msg) ->
-
   robot.respond /hammeradmin report(?: @?(\w+))?/i, (msg) ->
     return unless isAdmin(msg)
     challengers = challengersFrom(msg)


Fix command description

Fix command description

--- src/index.coffee
+++ src/index.coffee
@@ -5,8 +5,7 @@
 #   "diceware-generator": "^1.2.2"
 #
 # Commands:
-#   hubot diceware -> black gimpy gp lath blue trudge
-#   hubot diceware sp 10 -> zampar 729 antia Cabo afino fue Sra. 134 pie orden
+#   hubot diceware (en|sp) <len> -> Get a diceware
 #
 # Author:
 #   lgaticaq


Allow less import options

Allow less import options


Improved logging

Improved logging

--- server/synchronization.coffee
+++ server/synchronization.coffee
@@ -24,21 +24,24 @@

 @sync = (callback) ->
   syncWithBaseKey = (baseKey, handler) ->
-    tokenRequest = null
+    reqToken = undefined
     getData = ->
       proj = Settings.findOne().project
       if proj is currentProject # a hack to stop prveious waits; meteor HTTP does not expose the request object, can't abort
         recursiveUrl = "#{baseKey}/#{proj}?recursive=true"
         waitForChange = ->
-          if tokenRequest
-            tokenRequest.abort()
-            console.log "Previous watch request for #{baseKey} aborted: #{tokenRequest.req._multipart.boundary}"
-          tokenRequest = EtcdClient.wait recursiveUrl, (err, result) ->
+          if reqToken and not reqToken.isAborted()
+            reqToken.abort()
+            console.log "Previous watch request for #{baseKey} aborted: #{reqToken.req._multipart.boundary}"
+          reqToken = EtcdClient.wait recursiveUrl, (err, result) ->
             console.error err if err
-            console.log "Etcd changes reported for #{baseKey}:"
-            console.log result
+            if result
+              console.log "Etcd changes reported for #{baseKey}:"
+              console.log result
+            else
+              console.log "Watch request for #{baseKey} timed out: #{reqToken.req._multipart.boundary}"
             getData()
-          console.log "New watch request for #{baseKey}: #{tokenRequest.req._multipart.boundary}"
+          console.log "New watch request for #{baseKey}: #{reqToken.req._multipart.boundary}"
         EtcdClient.discover recursiveUrl, (err, nodes) ->
           console.error err if err
           console.log "Getting data from etcd for #{baseKey}"


switch subscribe button source to podigee CDN

--- src/javascripts/subscribe_button_trigger.coffee
+++ src/javascripts/subscribe_button_trigger.coffee
@@ -11,7 +11,7 @@
   buildTags: () ->
     @scriptTag = document.createElement('script')
     @scriptTag.className = "podlove-subscribe-button"
-    @scriptTag.src = "https://cdn.podlove.org/subscribe-button/javascripts/app.js"
+    @scriptTag.src = "https://cdn.podigee.com/subscribe-button/javascripts/app.js"
     @scriptTag.dataset.language = 'en'
     @scriptTag.dataset.size = 'medium'
     @scriptTag.setAttribute('data-hide', true)


Bug fix: Block delete confirmation message box contains rouge chars #14

https://github.com/bskyb-commerce/faber/issues/14

--- src/js/faber/controllers/BlockController.coffee
+++ src/js/faber/controllers/BlockController.coffee
@@ -76,7 +76,7 @@

   # Remove a child block
   $scope.remove = (block)->
-    if confirm 'Are you sure you want to permanently remove this block?\n\nYou can’t undo this action.'
+    if confirm 'Are you sure you want to permanently remove this block?\n\nYou can\'t undo this action.'
       $scope.block.blocks.splice($scope.block.blocks.indexOf(block), 1)

   # Insert a child block to the given index


Better explanation

Better explanation

--- index.coffee
+++ index.coffee
@@ -31,11 +31,15 @@
 paths = require "path"
 fs = require "fs"

+# This construction loads up the framework loader module and extends
+# the current `this` object with the methods found in the loader for
+# convenient access by the implementation further below. Refer to it.
+_.merge this, require "./library/nucleus/loader"
+
 # Build up the entire module hierarchy of the framework. Please do
 # refer to the `collectModules` method implementation for more
 # information on how this is being done. See the modules in the
 # framework library to see the structure of the built hieararchy.
-_.merge @, require "./library/nucleus/loader"
 module.exports = @collectPackages __dirname
 module.exports.cachedKernel = @cachedKernel
 module.exports.collectModules = @collectModules


Add initial sitemap.xml support

Add initial sitemap.xml support

--- index.coffee
+++ index.coffee
@@ -9,6 +9,9 @@
 sharejs = require("share")
 lactate = require("lactate")
 path = require("path")
+xmlbuilder = require("xmlbuilder")
+es = require("event-stream")
+JSONStream = require("JSONStream")

 pkginfo = require("./package.json")

@@ -31,7 +34,7 @@

 assetOptions =
   src: "#{__dirname}/assets"
-  buildDir: "assets/build"
+  buildDir: "build"
   buildFilenamer: (filename) ->
     dir = path.dirname(filename)
     ext = path.extname(filename)
@@ -131,5 +134,33 @@

 # /////////////////////////////////

+apiUrl = nconf.get("url:api")
+wwwUrl = nconf.get("url:www")
+
+app.get "/sitemap.xml", (req, res) ->
+  outstanding = 0
+
+  urlset = xmlbuilder.create "urlset",
+    version: "1.0"
+    encoding: "UTF-8"
+
+  urlset.attribute "xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"
+
+  finalize = ->
+    res.set('Content-Type', 'application/xml')
+    res.send(urlset.end())
+
+  complete = -> finalize() unless --outstanding > 0
+
+  outstanding++
+  plunks = request("#{apiUrl}/plunks").pipe(JSONStream.parse([true])).pipe es.mapSync (plunk) ->
+    url = urlset.ele("url")
+    url.ele("loc").text("#{wwwUrl}/#{plunk.id}").up()
+    url.ele("lastmod").text(plunk.updated_at).up()
+    url.ele("changefreq").text("daily").up()
+    url.up()
+
+  plunks.on "end", complete
+
 app.get "/*", (req, res) ->
   res.render "landing"


profile: hiding customise button for non-activity views

--- client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
+++ client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
@@ -113,16 +113,18 @@
       @emit 'StaticProfileNavLinkClicked', 'CBlogPostActivity', 'static', =>
         @showWrapper @wrappers['static']
         @staticDefaultItem.show()
+        @staticPageSettingsButton.hide()
         callback()

     @on 'ActivityLinkClicked', (callback=->)=>
       @addLogic 'activity'
-      @showLoadingBar()
+      # @showLoadingBar()
       @emit 'StaticProfileNavLinkClicked', 'CBlogPostActivity', 'activity', =>
         @showWrapper @wrappers['activity']
         @displaySidebar yes
+        @staticPageSettingsButton.show()
         callback()

@@ -130,6 +132,7 @@
       @addLogic 'about', =>
         callback()
       @displaySidebar no
+      @staticPageSettingsButton.hide()

     @on 'CustomizeLinkClicked',=>
@@ -204,6 +207,67 @@
   reviveAdminViews:->

       # reviving ADMIN views (inline edits, feeder checkboxes)
+
+      @profileTitleNameView = new KDView
+        lazyDomId : 'profile-name'
+
+      @profileTitleBioView = new KDView
+        lazyDomId : 'profile-bio'
+
+      profileAdminCustomizeView = new KDView
+        lazyDomId : 'profile-admin-customize'
+
+      profileAdminCustomizeView.addSubView @staticPageSettingsButton = new CustomLinkView
+        title : 'Customize'
+        cssClass : 'static-page-settings-button clean-gray hidden'
+        click :(event)=>
+          @emit 'CustomizeLinkClicked'
+          event.stopPropagation()
+          event.preventDefault()
+
+      profileAdminCustomizeView.show()
+
+      profileAdminMessageView = new KDView
+        lazyDomId : 'profile-admin-message'
+
+      showPage = @profileUser.profile.staticPage?.show
+
+      profileAdminMessageView.addSubView disableLink = new CustomLinkView
+        title     : "#{if showPage is yes then 'Disable' else 'Enable'}"
+        cssClass  : 'message-disable'
+        click     : (event)=>
+          event?.stopPropagation()
+          event?.preventDefault()
+
+          if @profileUser.profile.staticPage?.show is yes
+            modal           = new KDModalView
+              cssClass      : 'disable-static-page-modal'
+              title         : 'Do you really want to disable your Public Page?'
+              content       : """
+

+
Disabling this feature will disable other people
+                  from publicly viewing your profile. You will still be
+                  able to access the page yourself.

+
Do you want to continue?

+

+                """
+              buttons       :
+                "Disable the Public Page" :
+                  cssClass  : 'modal-clean-red'
+                  callback  : =>
+                    modal.destroy()
+                    @profileUser.setStaticPageVisibility no, (err,res)=>
+                      if err then log err
+                      disableLink.updatePartial 'Enable'
+                Cancel      :
+                  cssClass  : 'modal-cancel'
+                  callback  : =>
+                    modal.destroy()
+          else
+            @profileUser.setStaticPageVisibility yes, (err,res)=>
+              if err then log err
+              disableLink.updatePartial 'Disable'
+
       handleLinks = {}

       handleLinks['twitter'] = new KDView
@@ -473,69 +537,9 @@
     @emit 'DecorateStaticNavLinks', @getAllowedTypes(@profileUser), 'CBlogPostActivity'

     unless user.getId() is KD.whoami().getId()
-      @addVisitorViews() if KD.isLoggedIn()
+      @reviveVisitorViews() if KD.isLoggedIn()

     else
-      @profileTitleNameView = new KDView
-        lazyDomId : 'profile-name'
-
-      @profileTitleBioView = new KDView
-        lazyDomId : 'profile-bio'
-
-      profileAdminCustomizeView = new KDView
-        lazyDomId : 'profile-admin-customize'
-
-      profileAdminCustomizeView.addSubView staticPageSettingsButton = new CustomLinkView
-        title : 'Customize'
-        cssClass : 'static-page-settings-button clean-gray'
-        click :(event)=>
-          @emit 'CustomizeLinkClicked'
-          event.stopPropagation()
-          event.preventDefault()
-
-      profileAdminCustomizeView.show()
-
-      profileAdminMessageView = new KDView
-        lazyDomId : 'profile-admin-message'
-
-      showPage = user.profile.staticPage?.show
-
-      profileAdminMessageView.addSubView disableLink = new CustomLinkView
-        title     : "#{if showPage is yes then 'Disable' else 'Enable'}"
-        cssClass  : 'message-disable'
-        click     : (event)=>
-          event?.stopPropagation()
-          event?.preventDefault()
-
-          if user.profile.staticPage?.show is yes
-            modal           = new KDModalView
-              cssClass      : 'disable-static-page-modal'
-              title         : 'Do you really want to disable your Public Page?'
-              content       : """
-

-
Disabling this feature will disable other people
-                  from publicly viewing your profile. You will still be
-                  able to access the page yourself.

-
Do you want to continue?

-

-                """
-              buttons       :
-                "Disable the Public Page" :
-                  cssClass  : 'modal-clean-red'
-                  callback  : =>
-                    modal.destroy()
-                    user.setStaticPageVisibility no, (err,res)=>
-                      if err then log err
-                      disableLink.updatePartial 'Enable'
-                Cancel      :
-                  cssClass  : 'modal-cancel'
-                  callback  : =>
-                    modal.destroy()
-          else
-            user.setStaticPageVisibility yes, (err,res)=>
-              if err then log err
-              disableLink.updatePartial 'Disable'
-
       @reviveAdminViews()

     console.timeEnd 'reviving page elements on userload.'
@@ -581,7 +585,7 @@
     # @profileLoaderView.show()

-  addVisitorViews:->
+  reviveVisitorViews:->

   getAllowedTypes:(@profileUser)->
@@ -691,8 +695,8 @@
     @profileShowMoreView.hide()

     for own name,wrapper of @wrappers
-      log name, wrapper
-      wrapper?.hide()
+      # log name, wrapper
+      wrapper?.hide?()

   showWrapper:(wrapper)->
     @hideWrappers()


[refactor] Disambiguate an if/return pair.

--- src/lists.coffee
+++ src/lists.coffee
@@ -22,7 +22,7 @@

 cons = (a, b = nil) ->
   return nil if (nilp a) and (nilp b)
-  makeAsCell if (not (a?)) then b else [a, b]
+  makeAsCell (if (not (a?)) then b else [a, b])

 car = (a) -> a[0]


Add breadcrumbs for fixing ts-loader/tsconfig issues

--- src/webpack.config.coffee
+++ src/webpack.config.coffee
@@ -553,6 +553,8 @@
             },
             { test: [/node_modules\/prom-client\/.*\.js$/], loader: 'babel-loader' },
             { test: [/latex-editor\/.*\.jsx?$/], loader: 'babel-loader' },
+            # Note: ts-loader is not a very good webpack citizen https://github.com/TypeStrong/ts-loader/issues/552
+            # It just kind of does its own thing. See tsconfig.json for further congiration.
             { test: /\.tsx$/, loader: "babel-loader!ts-loader" },
             { test: /\.ts$/, loader: "ts-loader" },
             { test: /\.less$/,   use: ["style-loader", "css-loader", "less-loader?#{cssConfig}"] },


Add apm list --dev

Add apm list --dev

This will include packages in ~/.atom/dev/packages and defaults
to true.

Closes #267

--- src/list.coffee
+++ src/list.coffee
@@ -35,6 +35,7 @@
       List all the installed packages and also the packages bundled with Atom.
     """
     options.alias('b', 'bare').boolean('bare').describe('bare', 'Print packages one per line with no formatting')
+    options.alias('d', 'dev').boolean('dev').default('dev', true).describe('dev', 'Include dev packages')
     options.alias('h', 'help').describe('help', 'Print this usage message')
     options.alias('i', 'installed').boolean('installed').describe('installed', 'Only list installed packages/themes')
     options.alias('j', 'json').boolean('json').describe('json', 'Output all packages as a JSON object')
@@ -85,6 +86,8 @@
     callback?(null, userPackages)

   listDevPackages: (options, callback) ->
+    return callback?(null, []) unless options.argv.dev
+
     devPackages = @listPackages(@devPackagesDirectory, options)
     if devPackages.length > 0
       unless options.argv.bare or options.argv.json


Make focusing other pane views from workspaceView private

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -303,16 +303,16 @@
   # Focus the next pane by id.
   focusNextPaneView: -> @model.activateNextPane()

-  # Essential: Focus the pane directly above the active pane.
+  # Focus the pane directly above the active pane.
   focusPaneViewAbove: -> @panes.focusPaneViewAbove()

-  # Essential: Focus the pane directly below the active pane.
+  # Focus the pane directly below the active pane.
   focusPaneViewBelow: -> @panes.focusPaneViewBelow()

-  # Essential: Focus the pane directly to the left of the active pane.
+  # Focus the pane directly to the left of the active pane.
   focusPaneViewOnLeft: -> @panes.focusPaneViewOnLeft()

-  # Essential: Focus the pane directly to the right of the active pane.
+  # Focus the pane directly to the right of the active pane.
   focusPaneViewOnRight: -> @panes.focusPaneViewOnRight()

   ###


Add update method.

Add update method.

--- src/model.coffee
+++ src/model.coffee
@@ -51,13 +51,23 @@
       @transform prop
     @

+  # Get property
   get: (prop) ->
     @state[prop]

+  # Set property to `value`
   set: (prop, value) ->
     unless @validate prop, value
       return false
+    @state[prop] = @transform prop, value
+    return true

-    @state[prop] = @transform prop, value
+  # Update several properties at once
+  update: (state) ->
+    ret = true
+    for prop, value of state
+      unless @set prop, value
+        ret = false
+    return ret

 module.exports = Model


fix(attrs): Bug with attributes that are empty strings cause issues, emptystring is now blank.

--- src/main.coffee
+++ src/main.coffee
@@ -8,8 +8,12 @@
 	require: 'ngModel'
 	templateUrl: 'md-date-time.tpl.html'
 	link: (scope, element, attrs, ngModel) ->
-		attrs.$observe 'defaultMode', (val) -> scope._mode = val ? 'date'
-		attrs.$observe 'displayMode', (val) -> scope._displayMode = val
+		attrs.$observe 'defaultMode', (val) ->
+			if val isnt 'time' and val isnt 'date' then val = 'date'
+			scope._mode = val
+		attrs.$observe 'displayMode', (val) ->
+			if val isnt 'full' and val isnt 'time' and val isnt 'date' then val = undefined
+			scope._displayMode = val
 		attrs.$observe 'orientation', (val) -> scope._verticalMode = val is 'true'
 		attrs.$observe 'displayTwentyfour', (val) -> scope._hours24 = val? and val
 		attrs.$observe 'mindate', (val) ->


remove console.log

remove console.log

--- lib/fix.coffee
+++ lib/fix.coffee
@@ -5,7 +5,6 @@

     triggerMeasurements = () ->
       if updates <= 5 #do this a bunch of times and then stop
-        console.log('jep')
         atom.workspaceView.increaseFontSize()
         atom.workspaceView.decreaseFontSize()


Make nslog accept arbitrary arguments.

Make nslog accept arbitrary arguments.

--- src/nslog.coffee
+++ src/nslog.coffee
@@ -1,4 +1,5 @@
 NSLog = require('bindings')('nslog.node')
+util = require('util')

-module.exports = (stringToLog="") ->
-  NSLog.log(stringToLog)
+module.exports = (args...) ->
+  NSLog.log(util.format(args...))


Better, but still not working

Better, but still not working

--- src/molo.coffee
+++ src/molo.coffee
@@ -164,8 +164,26 @@
               root.molo.require dep, updateDeps, context
         else
           loadScriptFile appendScriptPath(i), ->
-
-            root.molo.require i, executeCallback, context
+            root.molo.require i
+
+    # Resolve queue if possible
+    #console.log cache
+    #console.log queue
+
+    resolveDeps = []
+
+    if Object.keys(queue).length > 0
+      for key, value of queue
+        depLength = value.dependencies.length
+        for dep in value.dependencies
+          if cache[dep]
+            resolveDeps.push cache[dep]
+            if depLength is resolveDeps.length
+              cache[key] = value.factory.apply context, resolveDeps
+              delete queue[key]
+
+    #console.log cache
+    #console.log queue

   # Additional export functions


Still not working :(

Still not working :(

--- src/molo.coffee
+++ src/molo.coffee
@@ -123,7 +123,9 @@
     reqArgs = []
     reqArgIndex = 0

-    executeCallback = -> callback.apply @, reqArgs if reqArgIndex is name.length
+    executeCallback = ->
+      if callback
+        callback.apply @, reqArgs if reqArgIndex is name.length

     # Walk through all requires
     for i, num in name
@@ -162,7 +164,8 @@
               root.molo.require dep, updateDeps, context
         else
           loadScriptFile appendScriptPath(i), ->
-            root.molo.require i, callback, context
+
+            root.molo.require i, executeCallback, context

   # Additional export functions


Point copy constructor

Point copy constructor

--- src/point.coffee
+++ src/point.coffee
@@ -27,7 +27,8 @@
   @constructor
   ###
   Point = (x, y) ->
-    if typeof x i
+    if typeof x is "object"
+
     __proto__: Point::

     ###*


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/point.coffee
+++ src/point.coffee
@@ -46,6 +46,7 @@
     ###*
     @name clamp
     @methodOf Point#
+    @pa
     @returns {Point} A new point whose magnitude has been clamped to the given value.
     ###
     clamp: (n) ->


Fixed module generator to call the correct functiion

--- lib/sdk.coffee
+++ lib/sdk.coffee
@@ -29,10 +29,10 @@

         if task.taskType is 'dataLink'
           console.log "Datalink received"
-          @dataLink.process task, @moduleGenerator task, completionCallback
+          @dataLink.process task, @moduleGenerator.generateModules task, completionCallback
         else if task.taskType is 'businessLogic'
           console.log "businessLogic received"
-          @businessLogic.process task, @moduleGenerator task, completionCallback
+          @businessLogic.process task, @moduleGenerator.generateModules task, completionCallback

       receiver.start taskReceivedCallback, (err, result) =>
         if err?


flv: Specify correct values for AAC

flv: Specify correct values for AAC

--- flv.coffee
+++ flv.coffee
@@ -186,13 +186,20 @@
   # }
   # @return array
   createAudioDataTag: (opts) ->
+    soundType = opts.soundType
+    soundRate = opts.soundRate
+    # If AAC, SoundType and SoundRate should be 1 (stereo) and 3 (44 kHz),
+    # respectively. Flash Player ignores these values.
+    if opts.soundFormat is api.SOUND_FORMAT_AAC
+      soundType = 1
+      soundRate = api.SOUND_RATE_44KHZ
+
     # AUDIODATA tag: Adobe's Video File Format Spec v10.1 E.4.2.1 AUDIODATA
-    # TODO: If AAC, SoundType and SoundRate should be 1 and 44 kHz, respectively.
     buf = [
       (opts.soundFormat << 4) \ # SoundFormat (4 bits)
-      | (opts.soundRate << 2) \ # SoundRate (2 bits): ignored by Flash Player if AAC
+      | (soundRate << 2) \      # SoundRate (2 bits): ignored by Flash Player if AAC
       | (opts.soundSize << 1) \ # SoundSize (1 bit)
-      | opts.soundType  # SoundType (1 bit): ignored by Flash Player if AAC
+      | soundType               # SoundType (1 bit): ignored by Flash Player if AAC
     ]
     if opts.soundFormat is api.SOUND_FORMAT_AAC
       buf.push opts.aacPacketType  # AACPacketType (1 bit)


Changed placeholder

Changed placeholder

--- core/app/backbone/views/fact_relations/add_comment_view.coffee
+++ core/app/backbone/views/fact_relations/add_comment_view.coffee
@@ -59,4 +59,4 @@
   _textAreaView: ->
     @__textAreaView ?= new Backbone.Factlink.TextAreaView
       model: @_textModel()
-      placeholder: 'Comment...'
+      placeholder: 'What do you think?'


Re-parameterize roof function.

Re-parameterize roof function.

--- main.coffee
+++ main.coffee
@@ -43,7 +43,12 @@
             .attr("id", "plot")
             .attr("transform", "translate(#{margin.left},#{margin.top})")

-        @draw(@x, @y)
+
+        #x = [-0.5, 0, 0.5]
+        #@p = new Plot x, (g(u) for u in x)
+
+
+        @pwl(@x, @y)
         #@circ([200,100])
         #@circ([100,200])

@@ -72,7 +77,15 @@
         #guide.attr("x2", @xScale $blab.Figure.xMax*cos(phi))
         #guide.attr("y2", @yScale $blab.Figure.xMax*sin(phi))

-    draw: (X, Y)->
+
+    #radialLine: (color) ->
+    #    @plot.append('line')
+    #        .attr("x1", @xScale 0)
+    #        .attr("y1", @yScale 0)
+    #        .style("stroke", color)
+    #        .style("stroke-width","1")
+
+    pwl: (X, Y)-> # piece-wise linear
         lineData = ({ x: x, y:Y[i] } for x,i in X)
         @plot.append("path")
             .attr("d", @lineFunction(lineData))
@@ -123,7 +136,6 @@
             .attr('y1', height)
             .style('stroke-opacity', 1e-6)
             .remove()
-

     initAxes: ->
         @xScale = d3.scale.linear() # sim units -> screen units
@@ -317,15 +329,20 @@
 class Simulation

     constructor: ->
-        g = (u) -> ((u<0)*1.5 + (u>0)/2)*u + 0.275
+
+        xm = 0;
+        ym = 0.275;
+
+        g = (x) ->
+            (x<0)*(-0.5+(x+0.5)*(2*ym+1)/(2*xm+1)) + (x>=0)*(ym+(x-xm)*(1-2*ym)/(1-2*xm))
+
         q = (y) -> Math.floor((y+0.875)/2*20)
+
+        x = [-0.5, 0, 0.5]
+        @p = new Plot x, (g(u) for u in x)
+
         @sun = new Sun g, q
         @h = new Histo
-        x = [-0.5, 0, 0.5]
-        #y = [0.5, -0.25, 0.5, 0.25, -0.5, 0.5]
-        #console.log "y", [g(u) for u in x]
-        @p = new Plot x, (g(u) for u in x)
-        #setTimeout @p.circ([100, 100]),

     start: () ->
         setTimeout (=> @animate 20000), 200


Cleanup

Cleanup

--- main.coffee
+++ main.coffee
@@ -349,11 +349,8 @@

 		canvas = document.getElementById CANVAS_NAME
 		canvas.addEventListener "mousemove", mouse_move
-		canvas = document.getElementById CANVAS_NAME
 		canvas.addEventListener "mousedown", mouse_down
-		canvas = document.getElementById CANVAS_NAME
 		canvas.addEventListener "mouseup", mouse_up
-		canvas = document.getElementById CANVAS_NAME
 		canvas.addEventListener "mouseout", mouse_out


Refactor PlotXY.

Refactor PlotXY.

--- main.coffee
+++ main.coffee
@@ -58,34 +58,20 @@

     constructor: (@spec) ->

-        @X = $blab.sheet[@spec.Xid]
-        @Y = $blab.sheet[@spec.Yid]
-
-        container = $("##{@spec.id}")[0]
+        @spec.data["columns"] = @getCols()

         @chart = c3.generate(
-            bindto: container
-            data:
-                columns: @getData()
-                types:
-                    one: 'area'
-                    two: 'area-spline'
+            bindto: $("##{@spec.id}")[0]
+            data: @spec.data
         )

-        console.log "headers", @X.rowHeaders[0]
-        console.log "data", [@X.labelRows()[0]].concat @Y.labelRows()
-        console.log "@Y", @Y
-
-    getData: ->
-        columns = [@X.labelRows()[0]].concat @Y.labelRows()
-        if c[0] == columns[0][0] for c in columns[1..]
-            console.log "!!! WARNING X and Y row labels clash !!!"
-        x: @X.rowHeaders[0],
-        columns: columns
-
-    update: ->
-        console.log "update XY", @spec.id, @getData()
-        @chart.load(@getData())
+    getCols: ->
+        cols = []
+        cols.push c for c in sheet.labelRows() for sheet in @spec.data.sheets
+        columns: cols
+
+    update: ->
+        @chart.load(@getCols())

     stringify: ->
         JSON.stringify($blab.figure[@spec.id]["spec"])
@@ -218,11 +204,18 @@

 fig = (id) -> new Figure1 {id:id}

-xy = (id) -> new PlotXY {id:id, Xid:"x1", Yid:"q"} #, $blab.sheet["x1"], $blab.sheet["y"]
+xy =  -> new PlotXY
+    id: "fig2"
+    data:
+        sheets: [$blab.sheet["x1"], $blab.sheet["q"]]
+        x: "r0"
+        types:
+            one: 'area'
+            two: 'area-spline'

 $blab.figure =
     q: fig "q"
-    fig2: xy "fig2"
+    fig2: xy()

 #console.log "??stringify??", $blab.sheet["A"].stringify()


Enable multiple users

Enable multiple users

Currently, it is not possible to use atom for multiple users on the same linux machine. The socket file '/tmp/atom.sock' belongs to the first user that starts atom.
With this small change, a socket file will be created for each user.

--- src/browser/atom-application.coffee
+++ src/browser/atom-application.coffee
@@ -18,7 +18,7 @@
   if process.platform is 'win32'
     '\\\\.\\pipe\\atom-sock'
   else
-    path.join(os.tmpdir(), 'atom.sock')
+    path.join(os.tmpdir(), "atom_#{process.env['USER']}.sock")

 # The application's singleton class.
 #


:racehorse: Don't load state when restorePreviousState is false

--- src/browser/atom-application.coffee
+++ src/browser/atom-application.coffee
@@ -516,7 +516,7 @@

   loadState: (options) ->
     restorePreviousState = @config.get('core.restorePreviousWindowsOnStart') ? true
-    if (states = @storageFolder.load('application.json'))?.length > 0 and restorePreviousState
+    if restorePreviousState and (states = @storageFolder.load('application.json'))?.length > 0
       for state in states
         @openWithOptions(_.extend(options, {
           initialPaths: state.initialPaths


:racehorse: Don't emit events for unobserved markers

--- src/marker.coffee
+++ src/marker.coffee
@@ -52,10 +52,10 @@
     @invalidate ?= 'overlap'
     @persistent ?= true
     @properties ?= {}
+    @hasChangeObservers = false
     @rangeWhenDestroyed = null
     Object.freeze(@properties)
     @store.setMarkerHasTail(@id, @tailed)
-    @previousEventState = @getSnapshot(range)

   ###
   Section: Event Subscription
@@ -88,6 +88,9 @@
   #
   # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
   onDidChange: (callback) ->
+    unless @hasChangeObservers
+      @previousEventState = @getSnapshot(@getRange())
+      @hasChangeObservers = true
     @emitter.on 'did-change', callback

   # Public: Returns the current {Range} of the marker. The range is immutable.
@@ -363,6 +366,8 @@
   ###

   emitChangeEvent: (currentRange, textChanged, propertiesChanged) ->
+    @store.markerUpdated(@id) unless textChanged
+    return unless @hasChangeObservers
     oldState = @previousEventState

     return false unless propertiesChanged or
@@ -386,8 +391,6 @@
     else
       newHeadPosition = newState.range.end
       newTailPosition = newState.range.start
-
-    @store.markerUpdated(@id) unless textChanged

     @emitter.emit("did-change", {
       wasValid: oldState.valid, isValid: newState.valid


align bottoms

align bottoms

--- src/layout/inspector.coffee
+++ src/layout/inspector.coffee
@@ -3,7 +3,7 @@
 #
 # Role: display and modify sprite state
 #
-# Responsibility:
+# Responsibility:
 # * create inspector panes for each sprite
 # * load the current inspector

@@ -24,12 +24,12 @@
       behavior(sprite)
     ]
   }
-
+
 make_inspector = (world, sprite) ->
   inspector = world.make_world sprite_inspector(sprite)
   sprite.put 'inspector', inspector
   inspector
-
+
 exports.inspector = () ->
   {
     _LABEL: 'inspector'
@@ -37,13 +37,13 @@
     inspect: (world, sprite) ->
       world.reset_children()
       inspector = sprite.get('inspector') or make_inspector(world, sprite)
-      world.add_child inspector
+      world.add_child inspector

     width: (world) -> world.up.get('width') - 4 * my.margin
     x: (world) -> world.up.get('width')
     y: 0
     position: 'absolute'
-    height: (world) -> world.get('screen').at vector.size.height
+    height: (world) -> world.get('screen').at(vector.size.height) - 2*my.margin
     stroke: my.color.line
     fill: my.color.background


gitlab.coffeeで、tagの追加、削除の機能を追加した。

gitlab.coffeeで、tagの追加、削除の機能を追加した。

--- gitlab.coffee
+++ gitlab.coffee
@@ -181,31 +181,37 @@

       when "web"
         message = []
-        # if the ref before the commit is 00000, this is a new branch
-        if /^0+$/.test(hook.before)
-          branch = hook.ref.split("/")[2..].join("/")
-          message.push("#{@sm.bold(hook.user_name)} pushed a new branch (#{@sm.bold(branch)}) to #{@sm.bold(hook.repository.name)} (#{@sm.underline(hook.repository.homepage)})")
+        if hook.ref
+          value = hook.ref.split("/")[2..].join("/")
+          label = hook.ref.split("/")[1]
+          if /^0+$/.test(hook.before)
+            # this is a new branch or tag.
+            message.push("#{@sm.bold(hook.user_name)} pushed a new #{label} (#{@sm.bold(value)}) to #{@sm.bold(hook.repository.name)}")
+            message.push("#{@sm.underline(hook.repository.homepage + '/commit/' + hook.after)}")
+          else
+            if /^0+$/.test(hook.after)
+              # branch or tag is deleted.
+              message.push("#{@sm.bold(hook.user_name)} deleted #{label} (#{@sm.bold(value)}) to #{@sm.bold(hook.repository.name)}")
+              message.push("#{@sm.underline(hook.repository.homepage + '/commit/' + hook.before)}")
+            else
+              # normal push event.
+              branch     = hook.ref.split("/")[2..].join("/")
+              indent     = "    "
+              compareUrl = "#{hook.repository.homepage}/compare/#{hook.before.substr(0,9)}...#{hook.after.substr(0,9)}"
+
+              message.push("#{@sm.bold(hook.user_name)} pushed #{@sm.bold(hook.total_commits_count)} commits to #{@sm.bold(branch)} in #{@sm.bold(hook.repository.name)}")
+              message.push("#{@sm.url('compare', compareUrl)}")
+
+              for li in @sm.list(hook.commits)
+                message.push(li)
+
+              saveInfo hook
         else
-          if hook.ref
-            # push event
-            branch     = hook.ref.split("/")[2..].join("/")
-            indent     = "    "
-            compareUrl = "#{hook.repository.homepage}/compare/#{hook.before.substr(0,9)}...#{hook.after.substr(0,9)}"
-
-            message.push("#{@sm.bold(hook.user_name)} pushed #{@sm.bold(hook.total_commits_count)} commits to #{@sm.bold(branch)} in #{@sm.bold(hook.repository.name)}")
-            message.push("#{@sm.url('compare', compareUrl)}")
-
-            for li in @sm.list(hook.commits)
-              message.push(li)
-
-            saveInfo hook
-
+          if hook.object_kind
+            message = makeObjectKindMessage(hook)
           else
-            if hook.object_kind
-              message = makeObjectKindMessage(hook)
-            else
-              console.log "Unknown message type."
-              console.log "hook: %j", hook
+            console.log "Unknown message type."
+            console.log "hook: %j", hook

         @sm.send target, message


Removing debug

Removing debug

--- test/integration/single/get-with-array-of-refs.coffee
+++ test/integration/single/get-with-array-of-refs.coffee
@@ -20,11 +20,6 @@
           res.statusCode.should.equal 200
           should.exist body
           Array.isArray(body).should.equal true
-          console.log 'Body'
-          console.log (u._id for u in body)
-          console.log 'User', user._id
-          console.log (z._id for z in user.friends), user.bestFriend
-          console.log ''
           body.length.should.equal user.friends.length
           friendIds = (friend._id for friend in body)
           friendIds.should.include String user.friends[0]._id


workers/social: remove unused reference from kodingkey

--- workers/social/lib/social/models/kodingkey.coffee
+++ workers/social/lib/social/models/kodingkey.coffee
@@ -1,5 +1,4 @@
 jraphical = require 'jraphical'
-CActivity = require './activity'
 JAccount  = require './account'
 KodingError = require '../error'


[grunt] allow preconfiguration of Gettext loader via constructor arguments

--- modules/gettext.coffee
+++ modules/gettext.coffee
@@ -16,15 +16,15 @@
      *       * https://github.com/andris9/node-gettext/issues/22
      *       * https://github.com/LotusTM/Kotsu/issues/45
     ###
-    constructor: (@locales, @localesDir) ->
+    constructor: (@locales, @cwd, @src = '{,**/}*.{po,mo}', @defaultDomain = 'messages') ->
       @gt = new NodeGettext()

       @load = ({
         localeDir
-        cwd = path.join(@localesDir, '/')
-        src = '{,**/}*.{po,mo}'
+        cwd = path.join(@cwd, '/')
+        src = @src
         domain = false
-        defaultDomain = 'messages'
+        defaultDomain = @defaultDomain
       }) ->
         cwd = path.join(cwd, localeDir)

@@ -36,7 +36,7 @@
           @gt.addTextdomain(resolvedDomain, messages)

       @locales.forEach (locale) =>
-        @load({ localeDir: locale})
+        @load({ localeDir: locale })

     resolveDomain: (domain) ->
       if domain.charAt(0) == ':' then @gt.textdomain() + domain else domain


Improve context menu item

Improve context menu item

--- menus/svgo.cson
+++ menus/svgo.cson
@@ -1,12 +1,14 @@
 'context-menu':
-  'atom-workspace': [{
-    label: 'Minify SVG',
-    command: 'svgo:minify'
-  }, {
-    label: 'Prettify SVG',
-    command: 'svgo:prettify'
-  }]
-
+  'atom-text-editor:not([mini])[data-grammar$="svg"]': [
+    label: 'SVGO'
+    submenu: [{
+      label: 'Minify SVG',
+      command: 'svgo:minify'
+    }, {
+      label: 'Prettify SVG',
+      command: 'svgo:prettify'
+    }]
+]
 'menu': [{
   label: 'Packages'
   submenu: [


Fix typo in multicursor module.

Fix typo in multicursor module.

--- src/modules/multi-cursor.coffee
+++ src/modules/multi-cursor.coffee
@@ -62,7 +62,7 @@
   removeCursor: (userId) ->
     cursor = @cursors[userId]
     this.emit(MultiCursor.events.CURSOR_REMOVED, cursor)
-    cursor.elem.parentNode.removeChild(cursor.elem) of cursor?
+    cursor.elem.parentNode.removeChild(cursor.elem) if cursor?
     delete @cursors[userId]

   setCursor: (userId, index, name, color, update = true) ->


Revert "Tests: Disable search test intentionally, I need to test it for other test steps"

This reverts commit c8b571b00111914b17422da9e66cb486f2bac9d2.

--- tests/src/activity/others.coffee
+++ tests/src/activity/others.coffee
@@ -7,22 +7,20 @@

 module.exports =

-  # Disable search test intentionally, I need to test it for other test steps
-  # I will revert this after first test passes ~ GG
-  #
-  # searchActivity: (browser) ->
-  #
-  #   post     = helpers.postActivity(browser)
-  #   selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
-  #   word     = post.split(' ')[0]
-  #
-  #   browser
-  #     .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
-  #     .waitForElementVisible    '.kdtabpaneview.search', 25000
-  #     .waitForElementVisible    selector, 25000
-  #     .pause                    25000
-  #     .assert.containsText      selector, word # Assertion
-  #     .end()
+
+  searchActivity: (browser) ->
+
+    post     = helpers.postActivity(browser)
+    selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
+    word     = post.split(' ')[0]
+
+    browser
+      .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
+      .waitForElementVisible    '.kdtabpaneview.search', 25000
+      .waitForElementVisible    selector, 25000
+      .pause                    25000
+      .assert.containsText      selector, word # Assertion
+      .end()

   showMoreCommentLink: (browser) ->


Tests: Activity: Post: Fixed post comment test.

--- tests/src/helpers/helpers.coffee
+++ tests/src/helpers/helpers.coffee
@@ -169,8 +169,10 @@

   doPostComment: (browser, comment, shouldAssert = yes) ->
     browser
-      .click        '[testpath=ActivityListItemView]:first-child [testpath=CommentInputView]'
-      .setValue     '[testpath=ActivityListItemView]:first-child [testpath=CommentInputView]', comment + '\n'
+      .click                    activitySelector + ' [testpath=CommentInputView]'
+      .setValue                 activitySelector + ' [testpath=CommentInputView]', comment
+      .waitForElementVisible    activitySelector + ' .comment-container .comment-input-wrapper', 20000
+      .click                    activitySelector + ' .comment-container button[testpath=post-activity-button]'

     if shouldAssert
       browser


teamwork: cancel finder vm root path set if there isn't any active panel

--- client/Teamwork/Views/teamworkapp.coffee
+++ client/Teamwork/Views/teamworkapp.coffee
@@ -125,6 +125,8 @@
       targetEl        : t.getActivePanel().headerHint

   setVMRoot: (path) ->
+    panel = @teamwork.getActivePanel()
+    return  unless panel
     {finderController} = @teamwork.getActivePanel().getPaneByName "finder"

     cb = (vmName) ->


admire my balls

admire my balls

--- src/Ball.coffee
+++ src/Ball.coffee
@@ -58,22 +58,22 @@
     if @possessorId?
       possessor = @game.entityManager.entities[@possessorId]
       if possessor?
-        offset = possessor.direction
-        @sprite.position.x = possessor.sprite.position.x + offset.x * 10
-        @sprite.position.y = possessor.sprite.position.y + offset.y
-        if offset.y < 0
-          @sprite.position.y -= 20
+        offset = possessor.direction.clone()
+        offset.setMagnitude(15)
+        @sprite.position.x = possessor.sprite.position.x + offset.x
+        @sprite.position.y = possessor.sprite.position.y + offset.y - 10

         moves = @game.controller.poll()
         if (moves.but1)
-          vector = possessor.sprite.body.acceleration.clone().setMagnitude(KICK_MAGNITUDE)
+          vector = possessor.direction.clone().setMagnitude(KICK_MAGNITUDE)
           @kick(vector)

     else if @catchable
       # get all avatars and see if any are overlapping
       avatars = @game.entityManager.getEntitiesOfType("Avatar")
       _.each(avatars, (avatar)=>
-        if Phaser.Rectangle.intersects(avatar.sprite.getBounds(), @sprite.getBounds())
+        hitbox = new Phaser.Rectangle(avatar.sprite.position.x, avatar.sprite.position.y - 25, 30, 30)
+        if Phaser.Rectangle.intersects(hitbox, @sprite.getBounds())
           @possessorId = avatar.id
           @game.entityManager.grantOwnership(this, avatar.owner)
           @catchable = false


cleanup

cleanup

--- lib/Model.coffee
+++ lib/Model.coffee
@@ -311,8 +311,6 @@
           @[key] = data
           done(err)

-      console.log '@constructor.relations', @constructor.relations
-
       for relname, rels of @constructor.relations
         wrapRelations = for key, opts of rels when @[key]?
           async.apply wrap, key, db.models[opts.model]


Screen Position now measures from the bottom, not the top

--- main/screen-position/leap-screen-position.coffee
+++ main/screen-position/leap-screen-position.coffee
@@ -24,13 +24,13 @@
   # positioning can be one of a series of predefined position identifiers, or a custom method.
   options.positioning ||= 'absolute'
   options.scale ||= 8
-  options.verticalOffset ||= -200
+  options.verticalOffset ||= -100

   positioningMethods = {
     absolute: (positionVec3)->
       [
         (document.body.offsetWidth / 2) + (positionVec3[0] * options.scale),
-        (document.body.offsetHeight / 2) + ((positionVec3[1] + options.verticalOffset) * options.scale * -1),
+        (document.body.offsetHeight / 2) + ((positionVec3[1] + options.verticalOffset) * options.scale),
         0
       ]
   }


Move cache key

Move cache key

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -11,13 +11,14 @@
     @loadOptions.filters ?= {}
     @loadOptions.include = _(@loadOptions.include).map((i) -> _.keys(i)[0]) # pull off the top layer of includes

+    # Build cache key
+    filterKeys = _.map(@loadOptions.filters, (v, k) -> "#{k}:#{v}").join(',')
+    @loadOptions.cacheKey = [@loadOptions.order || "updated_at:desc", filterKeys, @loadOptions.page, @loadOptions.perPage, @loadOptions.limit, @loadOptions.offset].join('|')
+
   load: (loadOptions) ->
     @_parseLoadOptions(loadOptions)

     options = @loadOptions
-    filterKeys = _.map(@loadOptions.filters, (v, k) -> "#{k}:#{v}").join(',')
-    cacheKey = [@loadOptions.order || "updated_at:desc", filterKeys, options.page, options.perPage, options.limit, options.offset].join('|')
-
     cachedCollection = @storageManager.storage @loadOptions.name
     collection = @storageManager.createNewCollection @loadOptions.name, []

@@ -30,8 +31,8 @@
           return collection
       else
         # Check if we have, at some point, requested enough records with this this order and filter(s).
-        if @storageManager.getCollectionDetails(@loadOptions.name).cache[cacheKey]
-          subset = _(@storageManager.getCollectionDetails(@loadOptions.name).cache[cacheKey]).map (result) => @storageManager.storage(result.key).get(result.id)
+        if @storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey]
+          subset = _(@storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey]).map (result) => @storageManager.storage(result.key).get(result.id)
           if (_.all(subset, (model) => model.associationsAreLoaded(@loadOptions.include)))
             @_success options, collection, subset
             return collection
@@ -62,7 +63,7 @@
           @storageManager.storage(underscoredModelName).update _(resp[underscoredModelName]).values()

         unless options.cache == false || @loadOptions.only?
-          @storageManager.getCollectionDetails(@loadOptions.name).cache[cacheKey] = results
+          @storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey] = results

         if @loadOptions.only?
           @_success options, collection, _.map(@loadOptions.only, (id) -> cachedCollection.get(id))


Remove old recursive logic, moving it soon

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -179,37 +179,7 @@
       cl = new Brainstem.CollectionLoader(storageManager: @storageManager)
       cl.loadCollection($.extend({}, options, collection: collection, include: include))

-      # @_loadCollectionWithFirstLayer($.extend({}, options, include: include, success: ((firstLayerCollection) =>
-      #   expectedAdditionalLoads = @_countRequiredServerRequests(include) - 1
-
-      #   if expectedAdditionalLoads > 0
-      #     timesCalled = 0
-      #     @_handleNextLayer collection: firstLayerCollection, include: include, error: options.error, success: =>
-      #       timesCalled += 1
-      #       if timesCalled == expectedAdditionalLoads
-      #         @_success(options, collection, firstLayerCollection)
-      #   else
-      #     @_success(options, collection, firstLayerCollection)
-      # )))
-
     collection
-
-  # _handleNextLayer: (options) =>
-  #   # Collection is a fully populated collection of tasks whose first layer of associations are loaded.
-  #   # include is a hierarchical list of associations on those tasks:
-  #   #   [{ 'time_entries': ['project': [], 'task': [{ 'assignees': []}]] }, { 'project': [] }]
-
-  #   _(options.include).each (hash) => # { 'time_entries': ['project': [], 'task': [{ 'assignees': []}]] }
-  #     association = _.keys(hash)[0] # time_entries
-  #     nextLevelInclude = hash[association] # ['project': [], 'task': [{ 'assignees': []}]]
-  #     if nextLevelInclude.length
-  #       association_ids = _(options.collection.models).chain().
-  #       map((m) -> if (a = m.get(association)) instanceof Backbone.Collection then a.models else a).
-  #       flatten().uniq().compact().pluck("id").sort().value()
-  #       newCollectionName = options.collection.model.associationDetails(association).collectionName
-  #       @_loadCollectionWithFirstLayer name: newCollectionName, only: association_ids, include: nextLevelInclude, error: options.error, success: (loadedAssociationCollection) =>
-  #         @_handleNextLayer(collection: loadedAssociationCollection, include: nextLevelInclude, error: options.error, success: options.success)
-  #         options.success()

   # Helpers


Rejigger placeholder compat to run on load.

--- vendor/assets/javascripts/jquery.placeholder.js.coffee
+++ vendor/assets/javascripts/jquery.placeholder.js.coffee
@@ -1,15 +1,16 @@
 unless Modernizr.input.placeholder
-  $('input[placeholder], textarea[placeholder]')
-    .live(
+  jQuery('input[placeholder], textarea[placeholder]')
+    .live
       blur: ->
-        input = $ this
+        input = jQuery this
         unless input.val()
           input.val(input.attr('placeholder')).addClass('placeholder')
       focus: ->
-        input = $ this
+        input = jQuery this
         placeholder = input.removeClass('placeholder').attr('placeholder')
         if input.val() == placeholder
           input.val("")
-    ).blur()
+  jQuery ->
+    jQuery('input[placeholder], textarea[placeholder]').blur()

 # TODO: Add a jQuery ajax dataFilter to process new HTML?


msg is actually a Response. build one of those so handlers can msg.reply

--- src/robot.coffee
+++ src/robot.coffee
@@ -195,7 +195,8 @@
         results.push listener.call(message)
         break if message.done
       catch error
-        @emit('error', error, message)
+        @emit('error', error, new @Response(@, message, []))
+
         false
     if message not instanceof CatchAllMessage and results.indexOf(true) is -1
       @receive new CatchAllMessage(message)


Allow undefined values in the stream

Allow undefined values in the stream

--- mock.coffee
+++ mock.coffee
@@ -137,10 +137,10 @@
         super { objectMode: true }
         @i = 0
       _read: () =>
+        if @i > (@data.length - 1)
+          @push null
+          return
         data = _.deepClone @data[@i++]
-        if data?
-          @push data
-        else
-          @push null
+        @push data

     admin_sdk


:lipstick:

:lipstick:

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -159,6 +159,17 @@
     else
       callback()

+
+# Create a desktop and start menu shortcut by using the command line API
+# provided by Squirrel's Update.exe
+createShortcut = (callback) ->
+  spawnUpdate(['--createShortcut', exeName], callback)
+
+# Remove the desktop and start menu shortcuts by using the command line API
+# provided by Squirrel's Update.exe
+removeShortcut = (callback) ->
+  spawnUpdate(['--removeShortcut', exeName], callback)
+
 exports.spawn = spawnUpdate

 # Is the Update.exe installed with Atom?
@@ -169,13 +180,13 @@
 exports.handleStartupEvent = ->
   switch process.argv[1]
     when '--squirrel-install', '--squirrel-updated'
-      exports.spawn ['--createShortcut', exeName], ->
+      createShortcut ->
         installContextMenu ->
           addCommandsToPath ->
             app.quit()
       true
     when '--squirrel-uninstall'
-      exports.spawn ['--removeShortcut', exeName], ->
+      removeShortcut ->
         uninstallContextMenu ->
           removeCommandsFromPath ->
             app.quit()


setup error handler for ui-router resolve errors, thank fucking goodness i can see errors now

--- src/node_modules/app/app.coffee
+++ src/node_modules/app/app.coffee
@@ -26,6 +26,12 @@
 .config(require('./http-config'))
 .run((editableOptions) ->
   editableOptions.theme = 'bs3'
+)
+.run(($rootScope) ->
+  # https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#issue-javascript-errors-dont-throw-within-resolve-functions
+  $rootScope.$on '$stateChangeError', (ev) ->
+    console.error("error changing state", [].slice.call(arguments))
+    ev.preventDefault()
 )
 # controllers
 .controller('ApplicationController', require('./controller.js'))


When publishing an update, check if the actor is the original author

Fixes test "Posting an update should not be possible for anyone else".

--- src/local/operations.coffee
+++ src/local/operations.coffee
@@ -519,6 +519,16 @@
                                     cb4 null, null
                                 else
                                     cb4 err, item
+                    , (oldItem, cb4) =>
+                        if oldItem?
+                            # Only the original author can update an item
+                            itemActor = oldItem.getChild("author")?.getChild("uri")?.getText()
+                            if itemActor is "acct:#{@req.actor}"
+                                cb4 null, oldItem
+                            else
+                                cb4 new errors.Forbidden "You're not allowed to update this item"
+                        else
+                            cb4 null, oldItem
                     , (oldItem, cb4) =>
                         normalizeItem @req, oldItem, item, cb4
                     , (newItem, cb4) =>


we now have ssl!

we now have ssl!

--- src/coffee/services/baseurl.coffee
+++ src/coffee/services/baseurl.coffee
@@ -1,2 +1,2 @@
 angular.module 'IdleLands'
-  .factory 'BaseURL', -> 'http://api.idle.land'+  .factory 'BaseURL', -> 'https://api.idle.land'


Renaming variable `i` to `file_index` to improve readability

--- src/polvo/core/optimizer.coffee
+++ src/polvo/core/optimizer.coffee
@@ -156,7 +156,7 @@
       @missing = {}

     # looping through all files
-    for file, i in files
+    for file, file_index in files

       # if theres no dependencies, go to next file
       if !file.dependencies.length && !file.baseclasses.length
@@ -176,7 +176,8 @@
         dependency_index = dependency.index if dependency?

         # continue if the dependency was already initialized
-        continue if dependency_index < i && dependency?
+        if dependency_index < file_index && dependency?
+          continue

         # if it's found
         if dependency?


removed extra

removed extra

--- src/components/learning-guide.cjsx
+++ src/components/learning-guide.cjsx
@@ -62,7 +62,6 @@

   render: ->
     {unit} = @state
-    {overall} = @state
     if unit
       chapter = <div className='chapter'>
         {@sectionFormat(unit.chapter_section, @state.sectionSeparator)}


removed console.log

removed console.log

--- src/components/learning-guide.cjsx
+++ src/components/learning-guide.cjsx
@@ -22,12 +22,10 @@
     unit: false

   navigateToPractice: (unit) ->
-    console.log("Navigate to practice unit ID #{unit.id} (#{unit.title})")
     {courseId} = @props
     @context.router.transitionTo('viewPractice', {courseId})

   displayUnit: (unit) ->
-    console.log("Display unit: ID #{unit.id} (#{unit.title})")
     @setState({unit})

   componentDidMount: ->


Remove semicolon

Remove semicolon

--- lib/emmet.coffee
+++ lib/emmet.coffee
@@ -7,7 +7,7 @@
 resources = emmet.require 'assets/resources'
 caniuse = emmet.require 'assets/caniuse'

-emmet.define('file', require('./file'));
+emmet.define('file', require('./file'))

 editorProxy = require './editor-proxy'

@@ -51,8 +51,8 @@

   # we must set these up here, so that the Node environment is loaded, and snippets work
   setupSnippets: ->
-    defaultSnippets = fs.readFileSync(path.join(__dirname, '../vendor/snippets.json'), {encoding: 'utf8'});
-    resources.setVocabulary(JSON.parse(defaultSnippets), 'system');
+    defaultSnippets = fs.readFileSync(path.join(__dirname, '../vendor/snippets.json'), {encoding: 'utf8'})
+    resources.setVocabulary(JSON.parse(defaultSnippets), 'system')

-    db = fs.readFileSync(path.join(__dirname, '../vendor/caniuse.json'), {encoding: 'utf8'});
+    db = fs.readFileSync(path.join(__dirname, '../vendor/caniuse.json'), {encoding: 'utf8'})
     caniuse.load(db)


whitespace cleanup

whitespace cleanup

--- src/ajax.coffee
+++ src/ajax.coffee
@@ -129,7 +129,7 @@
         parallel: options.parallel
       }
     ).done(@recordsResponse)
-     .fail(@failResponse)
+      .fail(@failResponse)

   all: (params, options = {}) ->
     @ajaxQueue(
@@ -139,7 +139,7 @@
         parallel: options.parallel
       }
     ).done(@recordsResponse)
-     .fail(@failResponse)
+      .fail(@failResponse)

   fetch: (params = {}, options = {}) ->
     if id = params.id
@@ -170,7 +170,7 @@
         parallel: options.parallel
       }, @record
     ).done(@recordResponse(options))
-     .fail(@failResponse(options))
+      .fail(@failResponse(options))

   create: (params, options = {}) ->
     @ajaxQueue(
@@ -182,7 +182,7 @@
         parallel: options.parallel
       }
     ).done(@recordResponse(options))
-     .fail(@failResponse(options))
+      .fail(@failResponse(options))

   update: (params, options = {}) ->
     @ajaxQueue(
@@ -194,7 +194,7 @@
         parallel: options.parallel
       }, @record
     ).done(@recordResponse(options))
-     .fail(@failResponse(options))
+      .fail(@failResponse(options))

   destroy: (params, options = {}) ->
     @ajaxQueue(
@@ -204,7 +204,7 @@
         parallel: options.parallel
       }, @record
     ).done(@recordResponse(options))
-     .fail(@failResponse(options))
+      .fail(@failResponse(options))

   # Private


Fix if-condition

Fix if-condition

--- lib/index.coffee
+++ lib/index.coffee
@@ -14,7 +14,7 @@
       pi.checkImports()

     atom.config.observe 'python-isort.sortOnSave', {callNow: true}, (value) ->
-      if value?
+      if value == true
         atom.workspace.eachEditor (editor) ->
           editor.buffer.on "saved", ->
             pi.sortImports()


export the utils with the library

export the utils with the library

--- lib/index.coffee
+++ lib/index.coffee
@@ -1,5 +1,7 @@
 module.exports =
   Promise: require('promise')
+
+  _: require('./util.coffee')

   ValidationError:       require('./error.coffee')
   AllValidator:          require('./validators/all_validator.coffee')