Fix #2966

Fix #2966

--- app/lib/LevelSetupManager.coffee
+++ app/lib/LevelSetupManager.coffee
@@ -100,7 +100,6 @@

     @options.parent.openModalView(firstModal)
     #    @inventoryModal.onShown() # replace?
-    @playSound 'game-menu-open'

   #- Modal events


move between panes

move between panes

--- .atom/keymap.cson
+++ .atom/keymap.cson
@@ -29,3 +29,7 @@
     'shift-alt-right': 'editor:select-to-end-of-line'
     'alt-left': 'editor:move-to-beginning-of-line'
     'shift-alt-left': 'editor:select-to-beginning-of-line'
+
+'body':
+  'ctrl-tab': 'pane:show-next-item'
+  'ctrl-shift-tab': 'pane:show-previous-item'


do not store selector on data source

do not store selector on data source

--- bokehjs/src/coffee/common/selection_manager.coffee
+++ bokehjs/src/coffee/common/selection_manager.coffee
@@ -16,7 +16,7 @@
       @selectors = {}

     set_selection: (indices) ->
-      @_save(null, indices)
+      @_save_indices(indices)
       source.trigger('select')

     select: (tool, renderer_view, geometry, final, append=false) ->
@@ -29,7 +29,7 @@
       selector = @_get_selector(tool)
       selector.update(indices, final, append)

-      @_save(selector, selector.get('indices'))
+      @_save_indices(selector.get('indices'))
       source.trigger('select')
       source.trigger('select-' + renderer_view.mget('id'))

@@ -52,14 +52,13 @@
       if tool?
         selector = @_get_selector(tool)
         selector.clear()
-      @_save(null, [])
+      @_save_indices([])

     _get_selector: (tool) ->
       _.setdefault(@selectors, tool.model.id, new Selector())
       return @selectors[tool.model.id]

-    _save: (selector, indices) ->
+    _save_indices: (indices) ->
       @get('source').save({
-        "selector": selector
         "selected": indices
       }, {patch: true})


Use .location for testability

Use .location for testability

--- app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/authentication/login_controller.js.coffee
@@ -1,13 +1,13 @@
-Darkswarm.controller "LoginCtrl", ($scope, $http, AuthenticationService, Redirections, Loading) ->
+Darkswarm.controller "LoginCtrl", ($scope, $http, $window, AuthenticationService, Redirections, Loading) ->
   $scope.path = "/login"

   $scope.submit = ->
     Loading.message = "Hold on a moment, we're logging you in"
     $http.post("/user/spree_user/sign_in", {spree_user: $scope.spree_user}).success (data)->
       if Redirections.after_login
-        location.href = location.origin + Redirections.after_login
+        $window.location.href = $window.location.origin + Redirections.after_login
       else
-        location.href = location.origin + location.pathname  # Strips out hash fragments
+        $window.location.href = $window.location.origin + $window.location.pathname  # Strips out hash fragments
     .error (data) ->
       Loading.clear()
       $scope.errors = data.message


don't refresh if tried query is NOT changed

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -755,6 +755,9 @@
           @withIgnoreChange => @setQuery(@lastQuery) # Recover query

         else
+          if @lastQuery.trim() is @getQuery().trim()
+            return
+
           autoPreview = @autoPreviewOnQueryChange and @isActive()
           refreshDelay = null
           if @provider.useFirstQueryAsSearchTerm


Snippets cleanup

Snippets cleanup

--- snippets/language-haskell.cson
+++ snippets/language-haskell.cson
@@ -1,10 +1,13 @@
 '.source.haskell':
   'Definition':
     'prefix': '='
-    'body': '${1:name} ${2:pattern}${2/.+/ /}= ${0:definition}'
+    'body': '${1:name} ${2:pattern} = ${0:definition}'
   'Function':
     'prefix': 'fun'
-    'body': '${1:name} :: ${2:Type}\n${1} ${3:pattern}${3/.+/ /}${4/.+/= /}${4:definition}'
+    'body': '''
+      ${1:name} :: ${2:Type}
+      ${1} ${3:pattern} = ${4:definition}
+      '''
   '#!/usr/bin/env…':
     'prefix': '#!'
     'body': '#!/usr/bin/env ${1:runhaskell}\n'
@@ -16,7 +19,12 @@
     'body': '${1:name} <- ${0:expression}'
   'Main':
     'prefix': 'main'
-    'body': 'module Main where\n\nmain :: IO ()\nmain = ${0:putStrLn "Hello World"}\n'
+    'body': '''
+      module Main where
+
+      main :: IO ()
+      main = ${0:putStrLn "Hello World"}\n
+      '''
   'Right Arrow':
     'prefix': '>'
     'body': '${1:expression} -> ${0:expression}'
@@ -25,34 +33,54 @@
     'body': '${1:name} :: ${0:Type}'
   'case … of …':
     'prefix': 'case'
-    'body': 'case ${1:expression} of\n\t${2:pattern} -> ${3:expression}\n\t${4:otherwise} -> ${5:expression}'
+    'body': '''
+      case ${1:expression} of
+      \t${2:pattern} -> ${3:expression}
+      \t${4:otherwise} -> ${5:expression}
+      '''
   'class …':
     'prefix': 'cla'
-    'body': 'class ${1:Class} where\n\t${0:definition}'
+    'body': '''
+      class ${1:Class} where
+      \t${0:definition}
+      '''
   'data …':
     'prefix': 'dat'
     'body': 'data ${1:Type} = ${0:Other}'
   'do …':
     'prefix': 'do'
-    'body': 'do\n\t${1:return ${0:expression}}'
+    'body': '''
+      do
+      \t${1:return ${0:expression}}
+      '''
   'if … then … else …':
     'prefix': 'if'
-    'body': 'if ${1:condition}\n\tthen ${2:expression}\n\telse ${3:expression}'
+    'body': '''
+      if ${1:condition}
+      \tthen ${2:expression}
+      \telse ${3:expression}
+      '''
   'import … hiding …':
     'prefix': 'imph'
-    'body': 'import ${1:Module}${2/.+/ hiding (/}${2:function}${2/.+/)/}$0'
+    'body': 'import ${1:Module} hiding (${2:function})'
   'import …':
     'prefix': 'imp'
-    'body': 'import ${1:Module}${2/.+/ (/}${2:function}${2/.+/)/}$0'
+    'body': 'import ${1:Module}'
   'import qualified …':
     'prefix': 'impq'
-    'body': 'import qualified ${1:Module}${2/.+/ as /}${2:Mod}${3/.+/ (/}${3:function}${3/.+/)/}$0'
+    'body': 'import qualified ${1:Module}${2: as ${3:Mod}}'
   'instance …':
     'prefix': 'ins'
-    'body': 'instance ${1:Class} ${2:Type} where\n\t${0:definition}'
+    'body': '''
+      instance ${1:Class} ${2:Type} where
+      \t${0:definition}
+      '''
   'let …':
     'prefix': 'let'
-    'body': 'let\n\t${1:name} = ${2:expression}\n\tin ${0:expression}'
+    'body': '''
+      let
+      \t${1:name} = ${2:expression}\n\tin ${0:expression}
+      '''
   'newtype …':
     'prefix': 'new'
     'body': 'newtype ${1:Type} = ${0:Other}'
@@ -61,7 +89,10 @@
     'body': 'type ${1:Type} = ${0:Other}'
   'where …':
     'prefix': 'where'
-    'body': 'where\n\t${0:definitions}'
+    'body': '''
+      where
+      \t${0:definitions}
+      '''
 '.source.haskell:not(.comment)':
   'Guard':
     'prefix': '|'
@@ -76,7 +107,7 @@
 '.source.haskell .constant.language.nil':
   'List Comprehension':
     'prefix': '['
-    'body': '[ ${1:expression} | ${2:name} <- ${3:expression}${4/.+/, /}${4:condition} '
+    'body': '[ ${1:expression} | ${2:${3:name} <- ${4:expression}}$0]'
 '.source.haskell .meta.function.type':
   'Type Constraint':
     'prefix': '='


Fix mergable blobs to attract each other

--- src/Control.coffee
+++ src/Control.coffee
@@ -8,14 +8,37 @@
   add: (engine) ->
     @engine = engine
     @entities = engine.e 'control', 'blob'
+    @players = engine.e 'player'
   update: (delta) ->
+    # Calculate average value of position
+    groupList = {}
     for entity in @entities
       continue unless entity.c('control').owner?
+      if not groupList[entity.c('control').owner]?
+        groupList[entity.c('control').owner] =
+          x: 0
+          y: 0
+          radius: 0
+      group = groupList[entity.c('control').owner]
+      entPos = entity.c 'pos'
+      group.x += entPos.x * 1
+      group.y += entPos.y * 1
+      group.radius += 1
+    for key, group of groupList
+      group.x /= group.radius
+      group.y /= group.radius
+    for entity in @entities
+      continue unless entity.c('control').owner?
+      group = groupList[entity.c('control').owner]
       player = @engine.e(entity.c('control').owner).c 'player'
+      continue unless group?
       continue unless player?
+      entPos = entity.c 'pos'
       entBlob = entity.c 'blob'
       entBlob.velX += (player.mouseX - entBlob.velX) / 30
       entBlob.velY += (player.mouseY - entBlob.velY) / 30
+      entBlob.velX += (group.x - entPos.x - entBlob.velX) / 30
+      entBlob.velY += (group.y - entPos.y - entBlob.velY) / 30

 ControlRenderSystem =
   add: (engine) ->


Teeny tiny case correction.

Teeny tiny case correction.

I like pretty test output...


Fix navigator link on home page

Fix navigator link on home page

--- app/lib/en.coffee
+++ app/lib/en.coffee
@@ -1173,7 +1173,7 @@

     classroom:
       title: 'Galaxy Zoo in the Classroom'
-      body: 'Are you an educator? Would you like to use Galaxy Zoo with a group of students? The Navigator is an interactive tool that allows groups to classify galaxies together and then investigate galaxy characteristics. Zoo Teach is where educators can share lessons, resources and that compliment the citizen science projects that are part of the Zooniverse.'
+      body: 'Are you an educator? Would you like to use Galaxy Zoo with a group of students? The Navigator is an interactive tool that allows groups to classify galaxies together and then investigate galaxy characteristics. Zoo Teach is where educators can share lessons, resources and that compliment the citizen science projects that are part of the Zooniverse.'
       navigator: 'Navigator'

     recent_images:


Clean up rank history

Clean up rank history

--- source/javascripts/rank-history.js.coffee
+++ source/javascripts/rank-history.js.coffee
@@ -1,26 +1,56 @@
-T.def 'rank-history', ->
+FIRST_YEAR = 2003
+THIS_YEAR  = new Date().getYear() + 1900
+YEARS      = [FIRST_YEAR..THIS_YEAR]
+
+T.def 'rank-history', (fromYear, toYear) ->
   [
     [ 'h2'
       'ATP rank history'
       [ 'span.generated-note'
         ' (generated at '
         [ 'span.generated-at' ]
-        ')'
+        ' )'
       ]
     ]
     ['#rank-history', ['svg']]
     [ '#timespan'
       'Time span: '
-      ['select', name: 'fromYear']
+      [ 'select'
+        name: 'fromYear'
+        #change: ->
+        #  fromYear = $(this).val()
+        #  toYear   = $("[name = toYear]").val()
+        #  $("[name=toYear]").html ""
+        #  year = parseInt(fromYear)
+
+        #  while year <= THIS_YEAR
+        #    $("[name=toYear]").append "<option>" + year + "</option>"
+        #    year++
+
+        #  $("[name=toYear]").val (if toYear then toYear else THIS_YEAR)
+
+        renderComplete: (el) -> $(el).val(fromYear)
+
+        for year in YEARS
+          ['option', year]
+      ]
       ' - '
-      ['select', name: 'toYear']
+      [ 'select'
+        name: 'toYear'
+        renderComplete: (el) -> $(el).val(toYear)
+
+        for year in YEARS
+          ['option', year]
+      ]
       [ 'button.update',
         click: ->
-          players = $("[name=player]:checked").map(-> @value)
+          players = []
+          $("[name=player]:checked").each -> players.push(@value)
+
           if players.length is 0
             alert "No player is selected."
           else
-            window.location.hash = "#/ranking-history/#{players.join(',')}?fromYear=#{$("[name=fromYear]").val()}&toYear=#{$("[name=toYear]").val()}"
+            window.location.hash = "#/rank-history/#{players.join(',')}?fromYear=#{$("[name=fromYear]").val()}&toYear=#{$("[name=toYear]").val()}"

         'Update graph'
       ]
@@ -28,7 +58,24 @@
     ['#players']
   ]

-window.loadAndShowRankHistory = (players, fromYear, toYear) ->
+T.def 'player-field', (player, index) ->
+  return  if index >= 50
+
+  name = player.first + " " + player.last
+  value = (player.first + "_" + player.last).toLowerCase().replace(/[ -]/g, "_")
+  [
+    [ 'div.player'
+      [ 'input'
+        type: 'checkbox'
+        name: 'player'
+        value: value
+      ]
+      ['span', name]
+    ]
+    ['br'] if index % 5 is 4
+  ]
+
+loadAndShowRankHistory = (players, fromYear, toYear) ->
   if players.length is 0
     alert "No player is chosen!"
     return
@@ -38,10 +85,10 @@
     data = $.map(results, (request) -> request[0])
     showRankHistory data, fromYear, toYear

-window.loadRankHistory = (players) ->
+loadRankHistory = (players) ->
   $.when ($.map(players, (player) -> loadData player + "_rank_history"))...

-window.showRankHistory = (data, fromYear, toYear) ->
+showRankHistory = (data, fromYear, toYear) ->
   data = $.map(data, (e) ->
     hist = filterHistoryData(e.history, fromYear, toYear)
     key: e.first + " " + e.last
@@ -54,7 +101,7 @@
       .margin(left: 20, right: 40)
       .color(d3.scale.category10().range())
     chart.xAxis.rotateLabels(30)
-      .tickValues( do -> $.map getYears(), (year) -> Date.parse "1/1/" + year)
+      .tickValues( do -> $.map THIS_YEAR, (year) -> Date.parse "1/1/" + year)
       .tickFormat((d) -> d3.time.format("%x")(new Date(d)))

     chart.yAxis.tickValues([0, 10, 20, 30, 40, 45, 46, 47, 48, 49])
@@ -63,85 +110,28 @@

     d3.select("#rank-history svg").datum(data).transition().duration(500).call chart
     nv.utils.windowResize chart.update
-    window.chart = chart
     chart

-window.getYear = ->
-  new Date().getYear() + 1900
-
-window.getYears = ->
-  years = []
-  year = 2003
-  while year <= getYear()
-    years[year - 2003] = year
-    year++
-  years
-
-window.filterHistoryData = (data, fromYear, toYear) ->
+filterHistoryData = (data, fromYear, toYear) ->
   fromTime = Date.parse(fromYear + "/1/1")
   toTime = Date.parse(parseInt(toYear) + 1 + "/1/1")
   $.map data, (item) ->
     time = Date.parse(item[0])
     [item]  if time >= fromTime and time < toTime

-window.initFromYear = ->
-  $("[name=fromYear]").html ""
-  year = 2003
+router.get '/rank-history/:players', (req) ->
+  players  = req.params.players.split(',')
+  fromYear = req.params.fromYear || FIRST_YEAR
+  toYear   = req.params.toYear   || THIS_YEAR

-  while year <= getYear()
-    $("[name=fromYear]").append "<option>" + year + "</option>"
-    year++
-
-window.initToYear = (fromYear) ->
-  $("[name=toYear]").html ""
-  year = fromYear
-
-  while year <= getYear()
-    $("[name=toYear]").append "<option>" + year + "</option>"
-    year++
-
-window.changeFromYear = ->
-  fromYear = $("[name = fromYear]").val()
-  toYear   = $("[name = toYear]").val()
-  $("[name=toYear]").html ""
-  year = parseInt(fromYear)
-
-  while year <= getYear()
-    $("[name=toYear]").append "<option>" + year + "</option>"
-    year++
-
-  $("[name=toYear]").val (if toYear then toYear else getYear())
-
-router.get '/rank-history/:players', (req) ->
-  T('rank-history').render inside: '.main'
+  T('rank-history', fromYear, toYear).render inside: '.main'

   loadData "rankings", (rankings) ->
     updateGenerationTime rankings.generated_at

-    $("[name=fromYear]").change changeFromYear
+    T.each_with_index('player-field', rankings.data).render inside: '#players'

-    $.each rankings.data, (i, r) ->
-      return  if i >= 50
-      name = r.first + " " + r.last
-      value = (r.first + "_" + r.last).toLowerCase().replace(/[ -]/g, "_")
-      $("#players").append "
<input type=\"checkbox\" name=\"player\" value=\"" + value + "\">" + name + "
"
-      $('#players').append('
') if i % 5 is 4
-
-
-    fromYear = 2003
-    fromYearParam = getQueryVar("fromYear")
-    fromYear = parseInt(fromYearParam)  if fromYearParam
-    initFromYear()
-    $("[name=fromYear]").val fromYear
-
-    toYear = getYear()
-    toYearParam = getQueryVar("toYear")
-    toYear = parseInt(toYearParam)  if toYearParam
-    initToYear fromYear
-    $("[name=toYear]").val toYear
-
-    players = req.params.players.split(',')
-    $.each players, (i, p) ->
-      $("[value=" + p + "]").click()
+    for player in players
+      $("[value=" + player + "]").attr('checked', 'checked')

     loadAndShowRankHistory players, fromYear, toYear


Add `iron-iconset` snippet.

Add `iron-iconset` snippet.

--- snippets/iron-elements.cson
+++ snippets/iron-elements.cson
@@ -29,6 +29,13 @@
     "body": """
     <iron-icon icon="$1"></iron-icon>
     """
+  "iron-iconset":
+    "prefix": "iron-iconset"
+    "body": """
+    <iron-iconset id="${1:my-icons}" src="${2:my-icons.png}" width="${3:96}" iconSize="${4:24}"
+        icons="${5:location place}">
+    </iron-iconset>
+    """
   "iron-image":
     "prefix": "iron-image"
     "body": """


fix bouygues konnector

fix bouygues konnector

--- server/konnectors/bouyguestelecom.coffee
+++ server/konnectors/bouyguestelecom.coffee
@@ -26,6 +26,8 @@
     vendor: String
     amount: Number
     fileId: String
+    binaryId: String
+    pdfUrl: String

 PhoneBill.all = (callback) ->
     PhoneBill.request 'byDate', callback
@@ -87,7 +89,7 @@
 logIn = (requiredFields, bills, data, next) ->

     loginUrl = 'https://www.mon-compte.bouyguestelecom.fr/cas/login'
-    billUrl = 'http://www.bouyguestelecom.fr/mon-compte/suivi-conso/factures'
+    billUrl = 'http://www.bouyguestelecom.fr/mon-compte/mes-factures'
     userAgent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:36.0) ' + \
                 'Gecko/20100101 Firefox/36.0'

@@ -134,6 +136,7 @@
                 headers:
                     'User-Agent': userAgent
             request options, (err, res, body) ->
+                console.log body
                 return next err if err
                 data.html = body
                 next()
@@ -179,5 +182,6 @@
                     date: moment date, 'DD/MM/YYYY'
                     amount: amount.replace ',', '.'
                     pdfurl: url
+                console.log bill
                 bills.fetched.push bill
     next()


Re-render auth view after saving

Re-render auth view after saving

--- scripts/views/workspace/menu/auth.coffee
+++ scripts/views/workspace/menu/auth.coffee
@@ -59,6 +59,7 @@
         success: () =>
           console.log 'end saving progress'
           _hasChanged = false
+          @render()

       ###
       return alert 'You need to Sign In (and make sure you can edit) before you can save changes' if not @model.get 'id'


Add tests for writing/reading custom manifest file

--- spec/ComponentLoader.coffee
+++ spec/ComponentLoader.coffee
@@ -607,3 +607,27 @@
     l.load 'componentloader/Missing', (err, instance) ->
       chai.expect(err).to.be.an 'error'
       done()
+  it 'should fail with missing manifest without discover option', (done) ->
+    l = new noflo.ComponentLoader fixtureRoot,
+      cache: true
+      discover: false
+      manifest: 'fbp2.json'
+    l.listComponents (err) ->
+      chai.expect(err).to.be.an 'error'
+      done()
+  it 'should be able to use a custom manifest file', (done) ->
+    @timeout 8000
+    manifestPath = path.resolve fixtureRoot, 'fbp2.json'
+    l = new noflo.ComponentLoader fixtureRoot,
+      cache: true
+      discover: true
+      manifest: 'fbp2.json'
+    l.listComponents (err, components) ->
+      return done err if err
+      chai.expect(l.processing).to.equal false
+      chai.expect(l.components).not.to.be.empty
+      done()
+  it 'should have saved the new manifest', (done) ->
+    manifestPath = path.resolve fixtureRoot, 'fbp2.json'
+    { unlink } = require 'fs'
+    unlink manifestPath, done


Add failing test

Add failing test

--- spec/powershell-spec.coffee
+++ spec/powershell-spec.coffee
@@ -322,7 +322,15 @@
       {tokens} = grammar.tokenizeLine("`_")
       expect(tokens[0]).toHaveScopes ["source.powershell", "constant.character.escape.powershell"]

-    it "escapes quotes within a string", ->
+    it "escapes single quotes within a string", ->
+      {tokens} = grammar.tokenizeLine("$command = \'.\\myfile.ps1 -param1 `\'$myvar`\' -param2 whatever\'")
+      console.log tokens
+      console.log tokens[7]
+      console.log tokens[8]
+      expect(tokens[7]).toHaveScopes ["source.powershell", "constant.character.escape.powershell", "string.quoted.single.single-line.powershell"]
+      expect(tokens[8]).toHaveScopes ["source.powershell", "string.quoted.single.single-line.powershell"]
+
+    it "escapes double quotes within a string", ->
       {tokens} = grammar.tokenizeLine("$command = \".\\myfile.ps1 -param1 `\"$myvar`\" -param2 whatever\"")
       expect(tokens[10]).toHaveScopes ["source.powershell", "constant.character.escape.powershell", "string.quoted.double.single-line.powershell"]
       expect(tokens[11]).toHaveScopes ["source.powershell", "string.quoted.double.single-line.powershell"]


Use indentation fixtures in the spec

Use indentation fixtures in the spec

--- spec/powershell-spec.coffee
+++ spec/powershell-spec.coffee
@@ -1,3 +1,5 @@
+path = require 'path'
+fs = require 'fs'
 {TextEditor} = require 'atom'

 describe "PowerShell grammar", ->
@@ -381,10 +383,14 @@
       editor.autoIndentBufferRows(0, text.split("\n").length - 1)
       expect(editor.getText()).toBe text

-    it "indents foreach loops with braces", ->
-      expectPreservedIndentation """
-        foreach($foo in $myArray)
-        {
-          Write-Host "Value $foo"
-        }
-      """
+    it "preserves indentation", ->
+      indentFixturesFolder = path.join(__dirname, "fixtures", "indents")
+      console.log(indentFixturesFolder)
+
+      fixtures = for fixture in fs.readdirSync(indentFixturesFolder)
+        fs.readFileSync(path.join(indentFixturesFolder, fixture), 'utf8')
+
+      console.log(fixtures)
+
+      for fixture in fixtures
+        expectPreservedIndentation fixture


RangeValidator :: Expose the problem with model-state dependent min and max functions

--- spec/validators_spec.coffee
+++ spec/validators_spec.coffee
@@ -177,6 +177,30 @@
       fv.validate @model
       expect( @model.addError ).toHaveBeenCalledWith "foo", "not in_range"

+    it "adds a validation that has min and max as functions", ->
+      minFunc = -> 0.5 * @get("bar")
+      maxFunc = -> 2 * @get("bar")
+      foobar = { bar: 10, foo: 15 }
+      fv = new @V.RangeValidator "foo", min: minFunc, max: maxFunc
+      spyOn @model, "addError"
+      spyOn(@model, "get").and.callFake ( attr ) ->
+        foobar[attr]
+      fv.validate @model
+      expect( @model.addError ).not.toHaveBeenCalled()
+
+    it "adds a validation that has min and max as functions and handles attribute dependent functions properly", ->
+      minFunc = -> 0.5 * @get("bar")
+      maxFunc = -> 2 * @get("bar")
+      foobar = { bar: 10, foo: 15 }
+      fv = new @V.RangeValidator "foo", min: minFunc, max: maxFunc
+      spyOn @model, "addError"
+      spyOn(@model, "get").and.callFake ( attr ) ->
+        foobar[attr]
+      fv.validate @model
+      foobar.bar = 2
+      fv.validate @model
+      expect( @model.addError ).toHaveBeenCalledWith "foo", "not in_range"
+
   describe "AcceptanceValidator", ->

     it "adds no errors if the attribute has the acceptance value", ->


array_extensions

--- src/array_extensions.coffee
+++ src/array_extensions.coffee
@@ -147,18 +147,17 @@
 Returns true if the element is present in the array.

-   ["a", "b", "c"].include("c")
-=> true
-
-   [40, "a"].include(700)
-=> false
+["a", "b", "c"].include("c")
+# => true
+
+[40, "a"].include(700)
+# => false

 @name include
 @methodOf Array#
 @param {Object} element The element to check if present.
-@returns true if the element is in the array, false otherwise.
-@type Boolean
+@returns {Boolean} true if the element is in the array, false otherwise.
 ###
 Array::include = (element) ->
   this.indexOf(element) != -1


add tests

add tests

--- karma/flows/test_controllers.coffee
+++ karma/flows/test_controllers.coffee
@@ -240,9 +240,11 @@
       # load a flow
       flowService.fetch(flows.favorites.id)
       flowService.contactFieldSearch = []
+      flowService.updateContactSearch = []
       flowService.language = {iso_code:'base'}
       $http.flush()
       flowService.contactFieldSearch = [{id:'national_id',text:'National ID'}]
+      flowService.updateContactSearch = [{id:'national_id',text:'National ID'}]

       # find an actin to edit
       actionset = flowService.flow.action_sets[0]
@@ -262,6 +264,7 @@

         # should still have one to choose from
         expect(flowService.contactFieldSearch.length).toBe(1)
+        expect(flowService.updateContactSearch.length).toBe(1)
       $timeout.flush()

       # now open our modal and try adding a field
@@ -276,9 +279,14 @@

         # new fields should be tacked on the end
         expect(flowService.contactFieldSearch.length).toBe(2)
+        expect(flowService.updateContactSearch.length).toBe(2)

         # check that the NEW markers are stripped off
         added = flowService.contactFieldSearch[1]
+        expect(added.id).toBe('a_new_field')
+        expect(added.text).toBe('A New Field')
+
+        added = flowService.updateContactSearch[1]
         expect(added.id).toBe('a_new_field')
         expect(added.text).toBe('A New Field')
       $timeout.flush()


Add benchmark for OnigRegExp

Add benchmark for OnigRegExp

--- benchmark/benchmark-suite.coffee
+++ benchmark/benchmark-suite.coffee
@@ -2,6 +2,7 @@
 fs = require 'fs'
 $ = require 'jquery'
 TokenizedBuffer = require 'tokenized-buffer'
+TextMateBundle = require 'text-mate-bundle'

 describe "editor.", ->
   editor = null
@@ -88,6 +89,16 @@
       editSession = benchmarkFixturesProject.buildEditSessionForPath('medium.coffee')
       { languageMode, buffer } = editSession

-    pfbenchmark "construction", 5, ->
+    benchmark "construction", 5, ->
       new TokenizedBuffer(buffer, { languageMode, tabText: '  '})

+describe "OnigRegExp.", ->
+  [regex, line] = []
+
+  beforeEach ->
+    line = "  l.comment_matcher = new RegExp('^\\s*' + l.symbol + '\\s?')"
+    regex = TextMateBundle.grammarForFileName('medium.coffee').initialRule.regex
+
+  pfbenchmark ".getCaptureTree", 1000, ->
+    regex.getCaptureTree(line, 22)
+


Ensure packets sent to addressable ports have index

--- src/lib/Component.coffee
+++ src/lib/Component.coffee
@@ -589,6 +589,9 @@
       ip = packet
     ip.scope = @scope if @scope isnt null and ip.scope is null

+    if @nodeInstance.outPorts[port].isAddressable() and ip.index is null
+      throw new Error 'Sending packets to addressable ports requires specifying index'
+
     if @nodeInstance.isOrdered()
       @nodeInstance.addToResult @result, port, ip
       return


Emit ready event once mq is connected

Emit ready event once mq is connected

--- index.coffee
+++ index.coffee
@@ -267,7 +267,10 @@
       @emit 'ready'

   connectHelper:(callback)->
-    @mq.once 'connected', callback.bind @  if callback?
+    @mq.once 'connected', =>
+      @emit 'ready'
+      callback?()
+
     @channelName = createBongoName @resourceName

     @channel = @mq.subscribe @channelName, {connectDirectly:yes}


update the index

update the index

--- index.coffee
+++ index.coffee
@@ -41,7 +41,7 @@
 # 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.
-do -> module.exports = @collectPackages __dirname
+do => module.exports = @collectPackages __dirname
 module.exports.collectPackages = @collectPackages
 module.exports.collectModules = @collectModules
 module.exports.cachedKernel = @cachedKernel


Show character ID in sample

Show character ID in sample

--- index.coffee
+++ index.coffee
@@ -66,7 +66,7 @@
         for sklID, skl of grp.skills
           flatSkills[sklID] = skl

-      console.log characterSheet.name.content
+      console.log "#{characterSheet.name.content} (ID #{characterSheet.characterID.content})"

       totalSP = 0
       for sklID, skl of characterSheet.skills


init dev

init dev

--- index.coffee
+++ index.coffee
@@ -7,6 +7,8 @@
 {isFunction, isArray, isNull, isObject} = require "core-util-is"

 util = require "util"
+
+##

 noopTransform = (c, e, n) ->
   @push c


Documentation

Documentation

--- src/bounded.coffee
+++ src/bounded.coffee
@@ -74,6 +74,8 @@
       width: 20
       height: 20

+    player.include(Bounded)
+
     player.collides({x: 5, y: 7, width: 20, height: 20})
     => true
   </pre></code>
@@ -100,6 +102,8 @@
       width: 20
       height: 20

+    player.include(Bounded)
+
     player.collisionBounds()
     => {x: 38, y: 36, height: 28, width: 24}


game_object

--- src/bounded.coffee
+++ src/bounded.coffee
@@ -2,6 +2,25 @@
 The Bounded module is used to provide basic data about the
 location and dimensions of the including object. This module is included
 by default in GameObject.
+
+

+
+player = Core
+  x: 10
+  y: 50
+  width: 20
+  height: 20
+  other: "stuff"
+  more: "properties"
+
+player.include(Bounded)
+
+# now player has all the methods provided by this module
+player.position()
+
+=> {x: 10, y: 50}
+
+

 Bounded module
 @name Bounded


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -23,7 +23,7 @@
 # => Sets up a health meter that will be drawn during the player overlay event

 enemy.meter
-  na'health'
+  name: 'health'
 # => Sets up a health meter that will be drawn during the enemy overlay event.
 # Since maxHealth wasn't provided, it is set to the value of I.health (500)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -18,7 +18,7 @@
 # => Sets up a health meter that will be drawn during the player overlay event

 enemy.meter 'health'
-# => Sets up a health meter that will be drawn during the enemy overlay event. Since
+# => Sets up a health meter that will be drawn during the enemy overlay event. Since maxHealth

 # now player has all the methods provided by this module
 player.position()


Remove unecessary calls to observeMutation

--- src/observer.coffee
+++ src/observer.coffee
@@ -32,14 +32,11 @@
               if key.replace(keypath, '').length <= key.length
                 for cb in callbacks[ key ]
                   @observe @obj, key, callback
-                  @observeMutations value, @obj[ @id ], key
                   cb()

       @observeMutations parentValue, @obj[ @id ], key
     else
       @observe @obj, parentKeypath
-
-    undefined

   weakReference: (obj) ->
     unless obj.hasOwnProperty @id


gross

gross

--- src/plugins.coffee
+++ src/plugins.coffee
@@ -1,5 +1,4 @@
 {Chrome, Dir, File} = require 'osx'
-

 _.map Dir.list(Chrome.appRoot() + "/plugins"), (plugin) ->
   try
@@ -7,7 +6,6 @@
   catch e
     name = _.last plugin.split '/'
     console.error "Problem loading plugin #{name}: #{e.message}"
-

 if css = File.read "~/.atomicity/twilight.css"
   head = $('head')[0]


勝抜/誤答時に表示切り替え

勝抜/誤答時に表示切り替え

--- src/models/player.coffee
+++ src/models/player.coffee
@@ -23,10 +23,16 @@
     @numOfWrongs = 0
     @state = PlayerState.Neutral

+  # TODO: 後で見直し
   displayPositive: ->
+    if @state == PlayerState.Win
+      return '勝抜'
     '◯ ' + @numOfRights

+  # TODO: 後で見直し
   displayNegative: ->
+    if @state == PlayerState.Lose
+      return '失格'
     '✕ ' + @numOfWrongs

   doRight: ->


Rename process to split

Rename process to split

--- src/process.coffee
+++ src/process.coffee
@@ -1,27 +0,0 @@
-compile = require './compile.js'
-
-module.exports = (item, items, shift = false, callback) ->
-  toArchive = compile item
-
-  hasItems = items? and items.length > 0
-  length = items.length
-
-  if shift
-    latestItem = items.shift()
-  else
-    latestItem = null
-
-  threshold = Math.ceil length / 2
-
-  locals =
-    title: item.header.title
-    items: items
-    dateString: latestItem.dateString
-    hasItems: hasItems
-    latestItem: latestItem
-    firstColumnItems: items.slice 0, threshold
-    secondColumnItems: items.slice threshold
-
-  html = toArchive locals
-
-  callback null, html


Fix flickering

Fix flickering

--- src/ng-datepicker.coffee
+++ src/ng-datepicker.coffee
@@ -58,5 +58,6 @@
             newDate = new Date newValue
             oldDate = dpElem.datepicker 'getUTCDate'
             if not oldDate? or newDate.getTime() isnt oldDate.getTime()
-              dpElem.datepicker 'setUTCDate', newDate
+              $timeout ->
+                dpElem.datepicker 'setUTCDate', newDate
   ]


Oops -- changed bell char from still-octal to hex

--- src/command.coffee
+++ src/command.coffee
@@ -136,7 +136,7 @@
   catch err
     CoffeeScript.emit 'failure', err, task
     return if CoffeeScript.listeners('failure').length
-    return printLine err.message + '\7' if o.watch
+    return printLine err.message + '\x07' if o.watch
     printWarn err instanceof Error and err.stack or "ERROR: #{err}"
     process.exit 1


I'd rather have a long line than an orphan.

--- src/command.coffee
+++ src/command.coffee
@@ -63,8 +63,7 @@
   loadRequires()                         if opts.require
   return require './repl'                if opts.interactive
   if opts.watch and !fs.watch
-    printWarn "The --watch feature depends on Node v0.6.0+. You are running \
-#{process.version}."
+    printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}."
   return compileStdio()                  if opts.stdio
   return compileScript null, sources[0]  if opts.eval
   return require './repl'                unless sources.length


simplified code for calculating sedra for display at top of page

--- source/javascripts/index/schedule.coffee
+++ source/javascripts/index/schedule.coffee
@@ -9,6 +9,12 @@
   initialDate = if initialDate.length > 0 then moment(initialDate, "YYYYMMDD").toDate() else (new Date())
   moment(initialDate).add(12, 'hours').format("YYYY-MM-DD")

+weekDescription = (shabbat) ->
+  sedra = "#{if shabbat.isRegel() || shabbat.isYomKippur() || shabbat.isYomTob() then "" else "שַׁבַּת פְּרָשָׁת"} #{shabbat.sedra().replace(/-/g, ' - ')}"
+  for event, name of window.ShabbatEvents
+    sedra = "#{sedra} — #{name}" if shabbat["is#{event}"]()
+  sedra
+
 write_schedule = (day_iterator) ->
   $('.start-hidden').addClass('hidden')
   $('.start-shown').removeClass('hidden')
@@ -16,12 +22,8 @@
   window.catching_errors 'Morning', day_iterator.toDate(), ->
     $(".weekly-table").html(tableFactory.generateWeekTable())
   window.catching_errors 'Sedra', day_iterator.toDate(), ->
-    for hebrewDate in tableFactory.hebrewWeek
-      if hebrewDate.isShabbat()
-        sedra = "#{if hebrewDate.isRegel() || hebrewDate.isYomKippur() || hebrewDate.isYomTob() then "" else "שַׁבַּת פְּרָשָׁת"} #{hebrewDate.sedra().replace(/-/g, ' - ')}"
-        for event, name of window.ShabbatEvents
-          sedra = "#{sedra} — #{name}" if hebrewDate["is#{event}"]()
-        $('.sedra').html(sedra)
+    shabbat = tableFactory.hebrewWeek[6]
+    $('.sedra').html(weekDescription(shabbat))
   announcementHtml = ""
   window.catching_errors 'Announcements', day_iterator.toDate(), ->
     for i in [0...(tableFactory.gregorianWeek.length)]


Adjust division default level.

Adjust division default level.

--- src/control.coffee
+++ src/control.coffee
@@ -293,7 +293,7 @@
             context?.query?.level or defaultLevel

         _renderDivisions: (ocdIds, context) ->
-            level = @_getLevel context, defaultLevel='all'
+            level = @_getLevel context, defaultLevel='none'
             sm.withDeferred (deferred) =>
                 @_fetchDivisions ocdIds, =>
                     if level == 'none'


slight optimisation

slight optimisation

--- src/counter.coffee
+++ src/counter.coffee
@@ -102,8 +102,7 @@
       while i < arguments.length
         source = arguments[i]

-        for prop of source
-          obj[prop] = source[prop] unless obj[prop]?
+        obj[prop] ?= source[prop], prop of source

         i++


write up coffeescript test

write up coffeescript test

--- spec/javascripts/feedback_spec.js.coffee
+++ spec/javascripts/feedback_spec.js.coffee
@@ -1,7 +1,25 @@
 #=require feedback_mailer/feedback
 #=require jquery
+#=require jquery_ujs

 describe 'feedback', ->
-  describe 'clicking the feedback link', ->
+  berforeEach ->
+    loadFixtures('feedback_form')
+
+
+  describe "My great feature", ->
+    it "will change the world", ->
+      expect(true).toBe true
+      expect(jQuery).toBeDefined()
+
+  describe 'when clicking the feedback link', ->
+    it 'the feedback form be assigned class open', ->
+      expect( $('.feedback_form_container')).toHaveClass('open')
+
+  describe 'when clicking the feedback link', ->
+    it 'hides the feedback link', ->
+      expect( $('.feedback_link') ).toBeHidden()
+
+  describe 'when clicking the feedback link', ->
     it 'displays the feedback form', ->
-     expect( $('.feedback_form_container')).toHaveClass('open')+      expect( $('.feedback_form_container') ).toBeVisible()


incorporate feedback about finish

incorporate feedback about finish

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -92,7 +92,6 @@

       if !msg.match[2] || msg.match[2] == 'me'
         msg.reply "Please specify a schedule with 'pager me ops 60.'' Use 'pager schedules' to list all schedules."
-        msg.finish
         return

       withScheduleMatching msg, msg.match[2], (matchingSchedule) ->
@@ -253,8 +252,7 @@
       query['editable'] = 'true'

     if !msg.match[5]
-      msg.reply "Please specify a schedule with 'pager schedule <name>.'' Use 'pager schedules' to list all schedules."
-      msg.finish
+      msg.reply "Please specify a schedule with 'pager #{msg.match[3]} <name>.'' Use 'pager schedules' to list all schedules."
       return

     withScheduleMatching msg, msg.match[5], (schedule) ->


Expose TDS version constants.

Expose TDS version constants.

--- src/tedious.coffee
+++ src/tedious.coffee
@@ -5,3 +5,4 @@
 exports.library = require('./library')
 exports.TYPES = require('./data-type').typeByName
 exports.ISOLATION_LEVEL = require('./transaction').ISOLATION_LEVEL
+exports.TDS_VERSION = require('./tds-versions').versions


prepared file split on upload

prepared file split on upload

--- src/FileManager/DropZoneDirective.coffee
+++ src/FileManager/DropZoneDirective.coffee
@@ -24,17 +24,16 @@
         evt.preventDefault()
         files = evt.dataTransfer.files

-        addFile = (tmpFile, arrayBuffer) ->
-          fileManager.fileTree.push tmpFile
+        uploadSlice = (tmpFile, arrayBuffer) ->
           strResult = arrayBuffer2String(arrayBuffer)
           fileManager.addFile(tmpFile.metadata, strResult)
           console.log strResult.length, strResult

-        createThumbnail = (data, mimeType) ->
+        createThumbnail = (file) ->
+          mimeType = file.type
           deferred = $q.defer()
-          blob = new Blob [data], {type: mimeType}
-          blobReader = new FileReader()
-          blobReader.onload = (evt2) =>
+          reader = new FileReader()
+          reader.onload = (evt2) =>
             #thumbDataUrl = evt2.target.result
             img = new Image()
             img.src = evt2.target.result
@@ -47,39 +46,52 @@
               imgContext.drawImage(img, 0, 0)
               deferred.resolve(imgCanvas.toDataURL(mimeType))

-          blobReader.readAsDataURL(blob)
+          reader.readAsDataURL(file)
           return deferred.promise
+
+        createLoadingFile = (file)->
+          tmpFile = {
+            metadata: {
+              name: fileManager.uniqueName(file.name)
+              size: file.size
+            }
+          }
+          if file.type == ""
+            #FIXME: could be an unknown file type
+            tmpFile.metadata.type = File.TYPES.FOLDER
+          else
+            tmpFile.metadata.type = File.TYPES.FILE
+          tmpFile = new File(tmpFile)
+          tmpFile.loading = true
+          return tmpFile
+
+        uploadFile = (file, loadingFile)->
+          fileManager.fileTree.push loadingFile
+          reader = new FileReader()
+          reader.onloadend = (evt) ->
+            if (evt.target.readyState == FileReader.DONE) # DONE == 2
+              uploadSlice loadingFile, evt.target.result
+
+          #SLICE_SIZE = 1024 * 1024 - 1
+          SLICE_SIZE = file.size + 1
+          start = 0
+          while start < file.size
+            blob = file.slice(start, start + SLICE_SIZE - 1)
+            reader.readAsArrayBuffer(blob)
+            start += SLICE_SIZE

         for file in files
           console.log "will load", file
           ( (file) ->
-            reader = new FileReader()
-            reader.onloadend = (evt) ->
-              tmpFile = {
-                metadata: {
-                  name: fileManager.uniqueName(file.name)
-                  size: file.size
-                }
-              }
-              if file.type == ""
-                #FIXME: could be an unknown file type
-                tmpFile.metadata.type = File.TYPES.FOLDER
-              else
-                tmpFile.metadata.type = File.TYPES.FILE
-              tmpFile = new File(tmpFile)
-              tmpFile.loading = true
+            loadingFile = createLoadingFile file

-              console.log length, fileManager.fileTree
-              if (evt.target.readyState == FileReader.DONE) # DONE == 2
-                console.log(file.size)
-                if file.type.match('image.*')
-                  createThumbnail evt.target.result, file.type
-                  .then (thumbDataUrl) =>
-                    tmpFile.metadata.thumb = thumbDataUrl
-                    addFile tmpFile, evt.target.result
-                else
-                  addFile tmpFile, evt.target.result
+            if file.type.match('image.*')
+              createThumbnail file
+              .then (thumbDataUrl) =>
+                loadingFile.metadata.thumb = thumbDataUrl
+                uploadFile file, loadingFile
+            else
+              uploadFile file, loadingFile

-            reader.readAsArrayBuffer(file)
           )(file)
   }


Add comment.

Add comment.

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -37,6 +37,7 @@
   action = if match = unwrap.exec action then match[1] else "(#{action}())"

   # All runtime functions we need are defined on "yy"
+  # Add "yy." in front of some things, so we can use them in actions.
   action = action.replace /\b(?:Block|Literal|Value|extend)\b/g, 'yy.$&'
   # Add "yy." in front of word after "new", if it doesn't already have "yy."
   action = action.replace /\bnew (?!yy\.)/g, '$&yy.'


Mention using bundled version

Mention using bundled version

--- src/install.coffee
+++ src/install.coffee
@@ -442,7 +442,8 @@
           if isBundledPackage
             console.error """
               The #{name} package is bundled with Atom and should not be explicitly installed.
-              You can run `apm uninstall #{name}` to uninstall it.
+              You can run `apm uninstall #{name}` to uninstall it and then the version bundled
+              with Atom will be used.
             """.yellow
           @installPackage({name, version}, options, callback)


Add working Tael functionality

Add working Tael functionality

All that is left to be done with Tael is to make
it an external library, do some refactoring, and,
most importantly, to implement DOM and content
functionality for each `leaf` tile.

--- src/js/tael.coffee
+++ src/js/tael.coffee
@@ -2,41 +2,61 @@
 # Copyright (c) 2015 Carter Hinsley
 # MIT License
 error = require './error.coffee'
+ref = require './lib/ref.js'

 tiles = [
-    type: 'container'
+    new ref
+        type: 'container'
+        child: undefined
 ]

-newTile = (parent) ->
+newTile = (tiles, parent_id) ->
     # Add a new tile to the `tiles` array.
     pushTile = ->
         # Push a new tile to the `tiles` array and return its index.
         (
-            tiles.push
-                type: 'leaf'
+            tiles.push new ref
+                    type: 'leaf'
+                    content:
+                        # To be added to
+                        dom: null
+                        data: 'foo'
         ) - 1
-    switch parent.type
+
+    addLeafToContainer = (parent) ->
+        # Create only one tile and add it as the child of the supplied parent.
+        # As the container tile is the top-level tile, it has only a single
+        # child tile.
+        parent.tile.value.child = do pushTile
+
+    addLeavesToLeaf = (parent) ->
+        # Create two tiles; convert the 'leaf' tile into a 'branch' tile
+        # before inserting the two new 'leaf' tiles into the newly-classified
+        # 'branch' tile.
+        parent.tile.value =
+            type: 'branch'
+            children:
+                left: do pushTile
+                right: do pushTile
+            layout:
+                split: 'horizontal'
+                divider_location: 0.5
+
+    parent =
+        id: parent_id
+        tile: tiles[parent_id]
+
+    switch parent.tile.value.type
         # Modify the parent tile and append one or two new tile(s) to the
         # `tiles` array.
         when 'container'
-            # Create only one tile; 'container' is the top-level tile.
-            parent.child = do pushTile
+            addLeafToContainer parent
         when 'leaf'
-            # Create two tiles; converts the 'leaf' tile into a 'branch' tile
-            # before inserting the two new 'leaf' tiles into the
-            # newly-classified 'branch' tile.
-            parent =
-                type: 'branch'
-                children:
-                    left: do pushTile
-                    right: do pushTile
-                layout:
-                    split: 'horizontal'
-                    divider_location: 1
+            addLeavesToLeaf parent
         when 'branch'
             error.throw "Branch tiles cannot spawn new children post-creation."

-newTile tiles[0]
+newTile tiles, 0

 module.exports = ->
     ($ document).ready ->
@@ -44,5 +64,5 @@
         .append(
             ($ '<div>')
             .addClass 'tael-node-leaf'
-            .text 'Hello, world!'
+            .text tiles[1].value.content.data
         )


bug fix

bug fix

--- src/lib/bot.coffee
+++ src/lib/bot.coffee
@@ -163,7 +163,7 @@
             Config.Auth.CookieRaw
         ]

-        argv.push '--noig' if argv.noig
+        argv.push '--noig true' if argv.noig
         argv = argv.concat parameters

         try


reapplied fc12520

reapplied fc12520

--- src/parser/parser.coffee
+++ src/parser/parser.coffee
@@ -23,17 +23,21 @@

   parse: (commit) ->
     conventions = []
-    commit = JSON.parse commit if 'string' is helpers.extractType commit
-    commit.files.forEach (file) ->
-      ext = path.extname file.filename
-      if isSupportExt(ext) and file.patch?
-        convention = {lang: ext.substr(1)}
-        psr = getParser ext
-        lines = parser.parseAdditionTokens file.patch
-        lines.forEach (line) ->
-          convention = psr.parse line, convention, commit.html_url
-        conventions.push convention if Object.keys(convention).length > 1
-    conventions
+    try
+      commit = JSON.parse commit if 'string' is helpers.extractType commit
+      commit.files.forEach (file) ->
+        ext = path.extname file.filename
+        if isSupportExt(ext) and file.patch?
+          convention = {lang: ext.substr(1)}
+          psr = getParser ext
+          lines = parser.parseAdditionTokens file.patch
+          lines.forEach (line) ->
+            convention = psr.parse line, convention, commit.html_url
+          conventions.push convention if Object.keys(convention).length > 1
+      conventions
+    catch err
+      logger.error 'parsing', {err: err}
+      []

 # private
 supportExts = [


Config: do npm i if the package json is newer than run file

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -604,6 +604,15 @@
             exit 1;
         fi

+        if [ "#{projectRoot}/run" -ot "#{projectRoot}/client/package.json" ]; then
+            echo your run file is older than your client package json. doing npm i.
+            sleep 1
+            cd client && npm i && cd -
+
+            echo -e "\n\nPlease do ./configure and  ./run again\n"
+            exit 1;
+        fi
+
         OLD_COOKIE=$(npm list tough-cookie -s | grep 0.9.15 | wc -l | awk \'{printf "%s", $1}\')
         if [  $OLD_COOKIE -ne 0 ]; then
             echo "You have tough-cookie@0.9.15 installed on your system, please remove node_modules directory and do npm i again";


string_extensions

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -101,8 +101,7 @@

 @name isString
 @methodOf String#
-@type Boolean
-@returns true
+@returns {Boolean} true
 ###
 String::isString = ->
   true


working on packmanager tests

working on packmanager tests

--- services/track-changes/test/unit/coffee/PackManager/PackManagerTests.coffee
+++ services/track-changes/test/unit/coffee/PackManager/PackManagerTests.coffee
@@ -237,3 +237,64 @@
 				it "should call the callback", ->
 					@callback.called.should.equal true

+
+	describe "getOpsByVersionRange", ->
+
+	describe "loadPacksByVersionRange", ->
+
+	describe "fetchPacksIfNeeded", ->
+
+	describe "makeProjectIterator", ->
+
+	describe "getPackById", ->
+
+	describe "increaseTTL", ->
+
+	describe "getIndex", ->
+
+	describe "getPackFromIndex", ->
+# getLastPackFromIndex:
+# getIndexWithKeys
+# initialiseIndex
+# updateIndex
+# findCompletedPacks
+# findUnindexedPacks
+# insertPacksIntoIndexWithLock
+# _insertPacksIntoIndex
+# archivePack
+# checkArchivedPack
+# processOldPack
+# 	updateIndexIfNeeded
+# 	findUnarchivedPacks
+
+	describe "checkArchiveNotInProgress", ->
+
+		describe "when an archive is in progress", ->
+			beforeEach ->
+				@db.docHistoryIndex =
+					findOne: sinon.stub().callsArgWith(2, null, {inS3:false})
+				@PackManager.checkArchiveNotInProgress @project_id, @doc_id, @pack_id, @callback
+			it "should call the callback", ->
+				@callback.called.should.equal true
+			it "should return an error", ->
+				@callback.calledWith(new Error()).should.equal true
+
+		describe "when an archive is completed", ->
+			beforeEach ->
+				@db.docHistoryIndex =
+					findOne: sinon.stub().callsArgWith(2, null, {inS3:true})
+				@PackManager.checkArchiveNotInProgress @project_id, @doc_id, @pack_id, @callback
+			it "should call the callback", ->
+				@callback.called.should.equal true
+			it "should return an error", ->
+				@callback.calledWith(new Error()).should.equal true
+
+		describe "when the archive has not started or completed", ->
+			beforeEach ->
+				@db.docHistoryIndex =
+					findOne: sinon.stub().callsArgWith(2, null, {})
+				@PackManager.checkArchiveNotInProgress @project_id, @doc_id, @pack_id, @callback
+			it "should call the callback", ->
+				@callback.called.should.equal true
+			it "should return with no error", ->
+				@callback.calledWith(undefined).should.equal true


Reset filters on new search bar search.

Reset filters on new search bar search.

--- web/site/search.coffee
+++ web/site/search.coffee
@@ -103,6 +103,16 @@
     clearAllContainers = ->
       $scope.retrievedContainers = {}

+    resetFilters = ->
+      highlightFilter = false
+      sessionFilter = false
+      partyFilter = false
+      volumeFilter = false
+      $scope.selectedFilter = ""
+      $scope.selectedType = ""
+      $scope.selectedVolume = ""
+      $scope.filterDisplay = []
+
     $scope.clearContainers = (vol) ->
       $scope.retrievedContainers[vol.id] = undefined

@@ -126,6 +136,8 @@
         $scope.originalQuery = $scope.searchBoxQuery
       else
         $scope.originalQuery = "*"
+
+      resetFilters()

       $scope.query = $scope.originalQuery
       $scope.offset = 0


More type safety in node names

More type safety in node names

--- src/plugins/noflo.coffee
+++ src/plugins/noflo.coffee
@@ -93,7 +93,7 @@

     node.on 'change:label', (node, newName) ->
       oldName = node.nofloNode.id
-      graph.nofloGraph.renameNode oldName, newName
+      graph.nofloGraph.renameNode oldName, newName + ''
     node.on 'change:x change:y', ->
       node.nofloNode.metadata.x = node.get 'x'
       node.nofloNode.metadata.y = node.get 'y'
@@ -114,10 +114,11 @@
           metadata = iip.metadata
           graph.nofloGraph.removeInitial node.nofloNode.id, port
       graph.nofloGraph.addInitial true, node.nofloNode.id, port, metadata
+
   subscribeDataflowEdge: (edge, graph) ->
     unless edge.nofloEdge
       try
-        edge.nofloEdge = graph.nofloGraph.addEdge edge.source.parentNode.id, edge.source.id, edge.target.parentNode.id, edge.target.id,
+        edge.nofloEdge = graph.nofloGraph.addEdge edge.source.parentNode.nofloNode.id, edge.source.id, edge.target.parentNode.nofloNode.id, edge.target.id,
           route: edge.get 'route'
       catch error
         # Not added, probably multiple w/o array port https://github.com/noflo/noflo/issues/90


Make Mock Data Work Again

Make Mock Data Work Again

--- src/coffee/experimental-controller.coffee
+++ src/coffee/experimental-controller.coffee
@@ -26,8 +26,8 @@

 qbnApp.controller 'QBN', ($scope) ->
   $scope.qualities = [
-    instantiate new Quality 'Punchiness', 7
-    instantiate new Quality 'Thinkyness', 2
+    instantiate new Quality 'Punchiness', '', 7
+    instantiate new Quality 'Thinkyness', '', 2
   ]
   $scope.storylets = [
     new Storylet 'The Thinker\'s Apprentice', 'You do some thinking.'


Working on statements

Working on statements

--- grammars/d.cson
+++ grammars/d.cson
@@ -551,132 +551,281 @@
     },
     'lwr-expression': {
       'patterns': [
-
+        { 'include': '#expression' }
       ]
     },
     'upr-expression': {
       'patterns': [
-
+        { 'include': '#expression' }
       ]
     },
     'switch-statement': {
       'patterns': [
-
+        {
+          'begin': 'switch\\s*\\(',
+          'beginCaptures': { '0': { 'name': 'keyword.control.switch.begin.d' } },
+          'end': '\\)',
+          'endCaptures': { '0': { 'name': 'keyword.control.switch.end.d' } },
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        },
+        { 'include': '#scope-statement' }
       ]
     },
     'case-statement': {
       'patterns': [
-
+        {
+          'match': 'case\\s+',
+          'name': 'keyword.control.case.range.d'
+        },
+        { 'include': '#argument-list' },
+        {
+          'match': ':',
+          'name': 'keyword.control.case.colon.d'
+        },
+        { 'include': '#scope-statement-list' }
       ]
     },
     'case-range-statement': {
       'patterns': [
-
+        {
+          'match': 'case\\s+',
+          'name': 'keyword.control.case.range.d'
+        },
+        { 'include': '#first-exp'},
+        {
+          'match': ':',
+          'name': 'keyword.control.case.colon.d'
+        },
+        {
+          'match': '\\.\\.\\s*case\\s+',
+          'name': 'keyword.control.case.range-2.d'
+        },
+        { 'include': '#last-exp' },
+        { 'include': '#scope-statement-list' }
       ]
     },
     'first-exp': {
       'patterns': [
-
+        { 'include': '#assign-expression' }
       ]
     },
     'last-exp': {
       'patterns': [
-
+        { 'include': '#assign-expression' }
       ]
     },
     'default-statement': {
       'patterns': [
-
+        {
+          'match': 'default\\s+:\\s+',
+          'name': 'keyword.control.default.d'
+        },
+        {
+          'include': '#scope-statement-list'
+        }
       ]
     },
     'scope-statement-list': {
       'patterns': [
-
+        { 'include': '#statement-list-no-case-no-default' }
       ]
     },
     'statement-list-no-case-no-default': {
       'patterns': [
-
+        { 'include': '#statement-no-case-no-default' },
       ]
     },
     'statement-no-case-no-default': {
       'patterns': [
-
+        { 'include': '#non-empty-statement-no-case-no-default' },
+        { 'include': '#scope-block-statement' }
       ]
     },
     'final-switch-statement': {
       'patterns': [
-
+        {
+          'begin': 'final\\s+switch\\s+\\(',
+          'beginCaptures': { '0': { 'name': 'keyword.control.final-switch.begin.d' } },
+          'end': '\\)',
+          'endCaptures': { '0': { 'name': 'keyword.control.final-switch.end.d' } },
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        },
+        { 'include': '#scope-statement' }
       ]
     },
     'continue-statement': {
       'patterns': [
-
+        {
+          'begin': 'continue',
+          'beginCaptures': { '0': { 'name': 'keyword.control.continue.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#identifier' }
+          ]
+        }
       ]
     },
     'break-statement': {
       'patterns': [
-
+        {
+          'begin': 'break',
+          'beginCaptures': { '0': { 'name': 'keyword.control.break.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#identifier' }
+          ]
+        }
       ]
     },
     'return-statement': {
       'patterns': [
-
+        {
+          'begin': 'return\\s*',
+          'beginCaptures': { '0': { 'name': 'keyword.control.return.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        }
       ]
     },
     'goto-statement': {
       'patterns': [
-
+        {
+          'match': 'goto\\s+default',
+          'name': 'keyword.control.goto.d'
+        },
+        {
+          'begin': 'goto\\s+case\\s+',
+          'beginCaptures': { '0': { 'name': 'keyword.control.goto.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        },
+        {
+          'begin': 'goto\\s+',
+          'beginCaptures': { '0': { 'name': 'keyword.control.goto.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#identifier' }
+          ]
+        },
       ]
     },
     'with-statement': {
       'patterns': [
-
+        {
+          'begin': 'with\\s*\\(',
+          'beginCaptures': { '0': { 'name': 'keyword.control.with.begin.d' } },
+          'end': '\\)',
+          'endCaptures': { '0': { 'name': 'keyword.control.with.end.d' } },
+          'patterns': [
+            { 'include': '#symbol' },
+            { 'include': '#template-instance' },
+            { 'include': '#expression' },
+          ]
+        },
+        { 'include': '#scope-statement' }
       ]
     },
     'synchronized-statement': {
       'patterns': [
-
+        {
+          'begin': 'synchronized\\s+\\(',
+          'beginCaptures': { '0': { 'name': 'keyword.control.synchronized.begin.d' } },
+          'end': '\\)',
+          'endCaptures': { '0': { 'name': 'keyword.control.synchronized.end.d' } },
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        },
+        {
+          'match': 'synchronized\\s+(?!\\()',
+          'name': 'keyword.control.synchronized.d'
+        },
+        {  'include': '#scope-statement' }
       ]
     },
     'try-statement': {
       'patterns': [
-
+        {
+          'match': 'try\\s+',
+          'name': 'keyword.control.try.d'
+        },
+        { 'include': '#scope-statement' },
+        { 'include': '#catches' },
+        { 'include': '#finally-statement' }
       ]
     },
     'catches': {
       'patterns': [
-
+        { 'include': '#last-catch' },
+        { 'include': '#catch' },
+        { 'include': '#catches' }
       ]
     },
     'last-catch': {
       'patterns': [
-
+        {
+          'match': 'catch\\s+(?!\\()',
+          'name': 'keyword.control.catch.d'
+        },
+        { 'include': '#no-scope-non-empty-statement' }
       ]
     },
     'catch': {
       'patterns': [
-
+        {
+          'begin': 'catch\\s*\\(',
+          'beginCaptures': { '0': { 'name': 'keyword.control.catch.begin.d' } },
+          'end': '\\)',
+          'endCaptures': { '0': { 'name': 'keyword.control.catch.end.d' } },
+          'patterns': [
+            { 'include': '#catch-parameter' },
+          ]
+        },
+        { 'include': '#no-scope-non-empty-statement' }
       ]
     },
     'catch-parameter': {
       'patterns': [
-
+        { 'include': '#basic-type' },
+        { 'include': '#identifier' }
       ]
     },
     'finally-statement': {
       'patterns': [
-
+        {
+          'match': 'finally\\s+',
+          'name': 'keyword.control.throw.d',
+        },
+        { 'include': '#no-scope-non-empty-statement' }
       ]
     },
     'throw-statement': {
       'patterns': [
-
+        {
+          'begin': 'throw\\s+',
+          'beginCaptures': { '0': { 'name': 'keyword.control.throw.d' } },
+          'end': ';',
+          'patterns': [
+            { 'include': '#expression' }
+          ]
+        }
       ]
     },
     'scope-guard-statement': {
       'patterns': [
-
+        {
+          'match': 'scope\\s*\\((exit|success|failure)\\)\\s+',
+          'name': 'keyword.control.scope.d'
+        },
+        { 'include': '#non-empty-or-scope-block-statement' }
       ]
     },
     'asm-statement': {
@@ -692,17 +841,24 @@
     },
     'asm-instruction-list': {
       'patterns': [
-
+        { 'include': '#asm-instruction' }
       ]
     },
     'pragma-statement': {
       'patterns': [
-
+        { 'include': '#pragma' },
+        { 'include': '#no-scope-statement' }
       ]
     },
     'mixin-statement': {
       'patterns': [
-
+        'begin': 'mixin\\s*\\(',
+        'beginCaptures': { '0': { 'name': 'keyword.control.mixin.begin.d' } },
+        'end': '\\)',
+        'endCaptures': { '0': { 'name': 'keyword.control.mixin.end.d' } }
+        'patterns': [
+          { 'include': '#assign-expression' }
+        ]
       ]
     },
     ###########################################################################


Stringify JSON and parse to copy

Stringify JSON and parse to copy

This is a dirty hack to clone an object without adding dependencies to hubot.

--- src/response.coffee
+++ src/response.coffee
@@ -7,6 +7,11 @@
   # message - A Message instance.
   # match   - A Match object from the successful Regex match.
   constructor: (@robot, @message, @match) ->
+    # Dirty hack to deep clone without a dependency...
+    json = JSON.stringify @message
+    message = JSON.parse json
+    @message = message
+

   # Public: Posts a message back to the chat source
   #


Adjust a condition location

Adjust a condition location

--- src/smc-webapp/billing.cjsx
+++ src/smc-webapp/billing.cjsx
@@ -523,12 +523,10 @@
                 <Space/><Space/>
                 {@props.source.address_zip}
             </Col>
-            {@render_action_buttons()}
+            {@render_action_buttons() if @props.set_as_default? or @props.delete_method?}
         </Row>

     render_action_buttons : ->
-        if not @props.set_as_default? and not @props.delete_method?
-            return
         <Col md=3>
             <ButtonToolbar style={float: "right"}>
                 {<Button


reorganize the help dialog.

reorganize the help dialog.

--- src/smc-webapp/support.cjsx
+++ src/smc-webapp/support.cjsx
@@ -385,7 +385,6 @@
                        Otherwise, please fill out this form.

-            {what}

                     Looking for documentation and help? Go to
@@ -396,21 +395,27 @@
                     "Sign out..." button in account settings.

-                    Requesting that we install software? Include a complete example
-                    that we can easily use to verify that we properly installed the software.
-

-

                     You bought a subscription but it does not work...

                     All your files seem gone or you deleted your project...

-                    Sage will not run...
+                    My Sage worksheet or Jupyter notebook is very slow or will not run...

-
-
+

+                    Requesting that we install software? Fill out the form below and
+                    include a complete example
+                    that we can easily use to verify that we properly installed the software.
+

+

+                    Hit a bug or just need to talk with us?  Fill out the form below...
+

+
+
Create a Support Ticket

+
+            {what}

                 After submitting a ticket, you{"'"}ll receive a link, which you should save until
                 you receive a confirmation email.
@@ -489,7 +494,7 @@
             </Alert>
         else
             <Alert bsStyle='info'>
-                Please make sure the email address is correct.
+                Please make sure your email address is correct.
             </Alert>

         <form>
@@ -531,9 +536,6 @@
                     value       = {@props.body}
                     onChange    = {@data_change} />
             </FormGroup>
-

-                Again: include a link (the URL in your browser) to absolutely anything relevant to your question.
-

         </form>

@@ -587,7 +589,7 @@

         <Modal bsSize={"large"} show={@props.show} onHide={@close} animation={false}>
             <Modal.Header closeButton>
-                <Modal.Title>Support Ticket</Modal.Title>
+                <Modal.Title><Icon name='medkit' /> Help</Modal.Title>
             </Modal.Header>

             <Modal.Body>


JSView update

JSView update

--- JSKit/02_JSView.coffee
+++ JSKit/02_JSView.coffee
@@ -78,6 +78,18 @@
 				$(@_viewSelector).css("overflow", "hidden")

 	setUserInteractionEnabled:(@_userInteractionEnabled)->
+		if (@_userInteractionEnabled == true)
+			$(@_viewSelector).unbind("click").bind "click", (event) =>
+				if (@_tapAction? && @_alpha > 0.0)
+					@_tapAction(@_self, event)
+					event.stopPropagation()
+			$(@_viewSelector).unbind("dblclick").bind "dblclick", (event) =>
+				if (@_tapAction2? && @_alpha > 0.0)
+					@_tapAction2(@_self, event)
+					event.stopPropagation()
+		else
+			$(@_viewSelector).unbind("click")
+			$(@_viewSelector).unbind("dblclick")

 	setDraggable: (@_draggable) ->
 		if (@_parent?)
@@ -195,6 +207,7 @@
 					$(@_viewSelector).unbind("click").bind "click", (event) =>
 						event.stopPropagation()
 				else
+					@_tapAction = null
 					$(@_viewSelector).unbind("click")

 			when 2
@@ -202,6 +215,7 @@
 					$(@_viewSelector).unbind("dblclick").bind "dblclick", (event) =>
 						event.stopPropagation()
 				else
+					@_tapAction2 = null
 					$(@_viewSelector).unbind("dblclick")

 	addTapGesture:(tapAction, tapnum = 1)=>
@@ -216,15 +230,14 @@
 		$(@_viewSelector).css("cursor", "pointer")
 		if (tapnum == 1)
 			$(@_viewSelector).unbind("click").bind "click", (event) =>
-				if (@_tapAction? && @_userInteractionEnabled == true)
+				JSLog("1")
+				if (@_tapAction? && @_userInteractionEnabled == true && @_alpha > 0.0)
 					@_tapAction(@_self, event)
-#				event.stopPropagation()

 		if (tapnum == 2)
 			$(@_viewSelector).unbind("dblclick").bind "dblclick", (event) =>
-				if (@_tapAction2? && @_userInteractionEnabled == true)
+				if (@_tapAction2? && @_userInteractionEnabled == true && @_alpha > 0.0)
 					@_tapAction2(@_self, event)
-#				event.stopPropagation()

 	animateWithDuration:(duration, animations, completion = null)=>
 		duration *= 1000
@@ -235,9 +248,38 @@
 			animobj[key] = value

 		if (completion?)
-			$(@_viewSelector).animate animobj, duration, => completion(@_self)
-		else
-			$(@_viewSelector).animate animobj, duration
+			$(@_viewSelector).animate animobj, duration, =>
+				for key, value of animations
+					switch key
+						when "top"
+							@_frame.origin.y = value
+						when "left"
+							@_frame.origin.x = value
+						when "alpha"
+							@_alpha = value
+						when "background-color"
+							@_bgColor = value
+						when "border-color"
+							@_borderColor = value
+						when "border-width"
+							@_borderWidth = value
+				completion(@_self)
+		else
+			$(@_viewSelector).animate animobj, duration, =>
+				for key, value of animations
+					switch key
+						when "top"
+							@_frame.origin.y = value
+						when "left"
+							@_frame.origin.x = value
+						when "alpha"
+							@_alpha = value
+						when "background-color"
+							@_bgColor = value
+						when "border-color"
+							@_borderColor = value
+						when "border-width"
+							@_borderWidth = value

 	setShadow:(@_shadow)->
 		if (@_shadow == true)
@@ -268,6 +310,5 @@
 				o = @_objlist[i]
 				if (!$(o._viewSelector).length)
 					$(@_viewSelector).append(o._div)
-					o.setDraggable(o._draggable)
 					o.viewDidAppear()


watch games

watch games

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -56,7 +56,7 @@

 # Watch and resync

-all_src = ['src/**/*', './../reactive-coffee/src/*']
+all_src = ['src/**/*', 'games/*', './../reactive-coffee/src/*']
 gulp.task 'watch', ['sync'], ->
   gulp.watch all_src, all_builds


gulp task to toggle karma's default action

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -41,6 +41,7 @@
 useLiveReload  = !!argv.liveReload
 useUglify      = !!argv.uglify
 useMinify      = !!(argv.minify ? yes)
+karmaAction    = 'watch'

 # Build Tasks
@@ -103,7 +104,7 @@
   gulp.src ['./test/kd.*']
     .pipe karma
       configFile : 'karma.conf.js'
-      action     : 'watch'
+      action     : karmaAction

 gulp.task 'play', ->
@@ -133,6 +134,8 @@

 gulp.task 'live', -> useLiveReload = yes
+
+gulp.task 'run', -> karmaAction = 'run'

 # Watch Tasks


rfctr test

rfctr test

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -9,8 +9,8 @@
 processBegin = ->
   nav = require './gulp-nav'  # convenient during development to wait until now
   gulp.src 'test/**/*.jade'
-    .pipe data (file) ->
-      matter String file.contents
+    .pipe data ({ contents }) ->
+      matter String contents
     .pipe nav()

 gulp.task 'build', ->
@@ -27,29 +27,28 @@

 runTest = (label, src) ->
   src.pipe filter '*/latin/b.jade'
-    .pipe through.obj (file) ->
+    .pipe through.obj ({ nav }) ->
       titleMsg = 'Nav should have this title.'
       hrefMsg = 'Nav should have this href.'
       activeMsg = 'Nav should be active.'
       notActiveMsg = 'Nav shouldn\'t be active.'

       test "Self-#{label}", (assert) ->
-        assert.plan 3
-        assert.is file.nav.title, 'B', titleMsg
-        assert.is file.nav.href, 'b.html', hrefMsg
-        assert.ok file.nav.active, activeMsg
+        assert.is nav.title, 'B', titleMsg
+        assert.is nav.href, 'b.html', hrefMsg
+        assert.ok nav.active, activeMsg
+        assert.end()
       test "Parent-#{label}", (assert) ->
-        assert.plan 3
-        assert.is file.nav.parent.title, 'Latin', titleMsg
-        assert.is file.nav.parent.href, '.', hrefMsg
-        assert.notOk file.nav.parent.active, notActiveMsg
+        assert.is nav.parent.title, 'Latin', titleMsg
+        assert.is nav.parent.href, '.', hrefMsg
+        assert.notOk nav.parent.active, notActiveMsg
+        assert.end()
       test "Grandparent-#{label}", (assert) ->
-        assert.plan 3
-        assert.is file.nav.parent.parent.title, 'Home', titleMsg
-        assert.is file.nav.parent.parent.href, '..', hrefMsg
-        assert.notOk file.nav.root.active, notActiveMsg
+        assert.is nav.parent.parent.title, 'Home', titleMsg
+        assert.is nav.parent.parent.href, '..', hrefMsg
+        assert.notOk nav.root.active, notActiveMsg
+        assert.end()
       test "Siblings-#{label}", (assert) ->
-        assert.plan 9
         for item, i in [
           title: 'A'
           href: 'letter-a.html'
@@ -63,16 +62,17 @@
           href: 'c.html'
           active: no
         ]
-          current = file.nav.siblings[i]
+          current = nav.siblings[i]
           assert.is current.title, item.title, titleMsg
           assert.is current.href, item.href, hrefMsg
           assert.is current.active, item.active,
             if item.active then activeMsg else notActiveMsg
+        assert.end()
       test "Children-#{label}", (assert) ->
-        assert.plan 1
-        assert.notOk file.nav.children.length, 'Nav should have no children.'
+        assert.notOk nav.children.length, 'Nav should have no children.'
+        assert.end()
       test "Root-#{label}", (assert) ->
-        assert.plan 3
-        assert.is file.nav.root.title, 'Home', titleMsg
-        assert.is file.nav.root.href, '..', hrefMsg
-        assert.notOk file.nav.root.active, notActiveMsg
+        assert.is nav.root.title, 'Home', titleMsg
+        assert.is nav.root.href, '..', hrefMsg
+        assert.notOk nav.root.active, notActiveMsg
+        assert.end()


To get compile error

To get compile error

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -26,8 +26,7 @@
   del.sync(paths.dest.coffee)

 gulp.task 'coffee', ->
-  gulp.src paths.source.coffee
-    .pipe plumber()
+  gulp.src paths.source.coffee
     .pipe coffee()
     .pipe gulp.dest paths.dest.coffee


positioning issue

positioning issue

--- docs/coffee/vis.coffee
+++ docs/coffee/vis.coffee
@@ -57,7 +57,7 @@
     updateTerms(fullJson)
     allData = setupData(data)

-    zoom = d3.behavior.zoom().translate([width/15, height/8]).scale(0.6).scaleExtent([minScale, maxScale]).on("zoom", redraw)
+    zoom = d3.behavior.zoom().translate([width/4, height/8]).scale(0.6).scaleExtent([minScale, maxScale]).on("zoom", redraw)

     # create our svg and groups
     vis = d3.select(selection).append("svg")


nightlies are bleepblooped?

nightlies are bleepblooped?

--- webpack/release.coffee
+++ webpack/release.coffee
@@ -87,6 +87,7 @@
     })

     branch = process.env.CIRCLE_BRANCH
+    console.log('nightly:', Object.keys(process.env), process.env.NIGHTLY)
     if process.env.NIGHTLY == 'true'
       issue = null
     else if branch.match(/^[0-9]+$/)


invalidate all results on disconnect

invalidate all results on disconnect

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -7,11 +7,13 @@
     @notifications.activate()
     @client.onConnected =>
       @notifications.show("Client Connected")
+    @client.onDisconnected =>
+      @ink?.Result.invalidateAll()

   deactivate: ->
     @spinner.dispose()

-  consumeInk: (ink) ->
-    @views.ink = ink
+  consumeInk: (@ink) ->
+    @views.ink = @ink

-    @spinner = new ink.Spinner @client.loading
+    @spinner = new @ink.Spinner @client.loading


simplified StoreSpec

simplified StoreSpec

--- test/StoreSpec.coffee
+++ test/StoreSpec.coffee
@@ -1,14 +1,15 @@
 define ['Store'], (Store)->
   describe 'Store', ->
     object  =
-    subject = undefined
+    subject =
+    funcOne =
+    funcTwo = undefined

     beforeEach ->
       object = {}
       subject = Store(object)
-
-    it 'should be defined', ->
-      expect(subject).toBeDefined()
+      funcOne = (store)-> store.one = 1
+      funcTwo = (store)-> store.two = store.one + 1

     it 'changing subject should affect object', ->
       subject.one = 1
@@ -17,24 +18,12 @@
       delete subject.one
       subject.two = 3
       expect(object).toBeEqual {two: 3}
-
-    describe 'work with outer functions', ->
-      funcOne =
-      funcTwo = undefined
-
-      beforeEach ->
-        funcOne = (store)->
-          store.one = 1
-
-        funcTwo = (store)->
-          store.two = store.one + 1
-
-      it 'should distribute private store', ->
-        expect(object).toBeEmpty()
-        funcOne(subject)
-        expect(object).toBeEqual {one: 1}
-        funcTwo(subject)
-        expect(object).toBeEqual {one: 1, two: 2}
+      delete subject.two
+      expect(object).toBeEmpty()
+      funcOne(subject)
+      expect(object).toBeEqual {one: 1}
+      funcTwo(subject)
+      expect(object).toBeEqual {one: 1, two: 2}


examples: add geojson example

examples: add geojson example

--- examples/geojson.coffee
+++ examples/geojson.coffee
@@ -1,11 +1,27 @@
 #!/usr/bin/env coffee

 WKTReader = (require "../lib").WKTReader
+GeoJSONWriter = (require "../lib").GeoJSONWriter

 reader = new WKTReader()
+writer = new GeoJSONWriter()

 geom = reader.read "POINT(23 42)"

 console.log geom.toGeoJSON()

 console.log geom.toJSON()
+
+# or use the GeoJSONWriter
+
+console.log writer.write geom
+
+# return a BBox as well on every write
+writer.setBBox true
+
+console.log writer.write geom
+
+# use to decimals
+writer.setRoundingPrecision 2
+
+console.log writer.write reader.read "POINT(0.1234 5.6789)"


Home: Don't show related videos after Koding introduction video.

--- client/landing/Intro/home.coffee
+++ client/landing/Intro/home.coffee
@@ -1,6 +1,6 @@
 class HomePage extends JView

-  iframe = """"""
+  iframe = """"""

   partialData = KD.customPartial?.partial or {}


[grunt] use super elegant way to retrive all, but first arguments of function

--- modules/gettext.coffee
+++ modules/gettext.coffee
@@ -53,8 +53,7 @@
      * @return {string} Translated string into specified locale
     ###
     dgettext: (domain, string) ->
-      args = [arguments...]
-      args.shift()
+      [domain, args...] = arguments
       @gt.dgettext(@resolveDomain(domain), args...)

     ###*
@@ -78,8 +77,7 @@
      * @return {string} Pluralized and translated into specified locale string
     ###
     dngettext: (domain, string, pluralString, count) ->
-      args = [arguments...]
-      args.shift()
+      [domain, args...] = arguments
       @gt.dngettext(@resolveDomain(domain), args...)

     ###*
@@ -101,8 +99,7 @@
      * @return {string} Translated string into specified locale
     ###
     dpgettext: (domain, context, string) ->
-      args = [arguments...]
-      args.shift()
+      [domain, args...] = arguments
       @gt.dpgettext(@resolveDomain(domain), args...)

     ###*
@@ -128,8 +125,7 @@
      * @return {string} Pluralized and translated into specified locale string
     ###
     dnpgettext: (domain, context, string, pluralString, count) ->
-      args = [arguments...]
-      args.shift()
+      [domain, args...] = arguments
       @gt.dnpgettext(@resolveDomain(domain), args...)

     installNunjucksGlobals: (env) ->


Groups.invitations: Added a check if no policy exists.

--- client/Dashboard/views/groupsinvitationview.coffee
+++ client/Dashboard/views/groupsinvitationview.coffee
@@ -12,7 +12,7 @@
         tabHandleContainer
       }, data

-      unless @policy.communications?.inviteApprovedMessage
+      unless @policy?.communications?.inviteApprovedMessage
         @saveInviteMessage 'inviteApprovedMessage', @getDefaultInvitationMessage()

     @on 'SearchInputChanged', (value)=>


make sure git has a user.name and user.email

--- index.coffee
+++ index.coffee
@@ -28,6 +28,8 @@

   if config.git?.enable
     execFileSync '/bin/sh', ['-c', "git init"], {cwd: config.tastesDir}
+    execFileSync '/bin/sh', ['-c', "git config user.name #{config.pkg.name}"], {cwd: config.tastesDir}
+    execFileSync '/bin/sh', ['-c', "git config user.email #{config.pkg.name}@localhost"], {cwd: config.tastesDir}
     if config.git.remoteUrl?
       execFileSync '/bin/sh', ['-c', "git config remote.origin.url #{config.git.remoteUrl}"], {cwd: config.tastesDir}


modified index.coffee

modified index.coffee

--- index.coffee
+++ index.coffee
@@ -33,7 +33,7 @@
 ###

 # Export source
-expr = (gulp,config = {}) ->
+expr = (gulp, config = {}) ->

   # if not require then require = ->

@@ -52,86 +52,159 @@
   markdown   = require 'gulp-markdown'
   minify     = require 'gulp-minify'
   minifyCSS  = require 'gulp-minify-css'
+  mkdirp     = require 'mkdirp'
+  path       = require 'path'
   rename     = require 'gulp-rename'
   sass       = require 'gulp-sass'
   sourcemaps = require 'gulp-sourcemaps'
   stylus     = require 'gulp-stylus'
   watch      = require 'gulp-watch'
-  path       = require 'path'
-  mkdirp     = require 'mkdirp'
+

   #
   # Configuraciones
   #
-  folder_dest           = config.dest || process.env.FOLDER_DEST || 'dest'
-  folder_src            = config.src || process.env.FOLDER_SRC || 'src'
-  script_to_concat      = config.scripts || []
-  styles_to_concat      = config.styles  || []
+  disable_tasks         = config.tasks             || {}
+  externals             = config.externals         || {}
+  folder_dest           = config.dest              || process.env.FOLDER_DEST || 'dest'
+  folder_src            = config.src               || process.env.FOLDER_SRC  || 'src'
   name_script_to_concat = config.nameContactScript || "script.js"
-  name_styles_to_concat = config.nameContactStyle || "style.css"
-  disable_tasks         = config.tasks || {}
-
-  # Rutas y destinos
+  name_styles_to_concat = config.nameContactStyle  || "style.css"
+  script_to_concat      = config.scripts           || []
+  styles_to_concat      = config.styles            || []
+
+  #
+  # Rutas de destino y origen.
+  #
   __base = config.patch || do process.cwd

   dest = path.join "#{__base}", "#{folder_dest}"
   src  = path.join "#{__base}", "#{folder_src}"

+  #
+  # Nombre con los directorios que contengan el origen de los distintos tipos de
+  # archivos.
+  #
   names =
-    coffee   : config.coffee || 'coffee'
-    css      : config.css || 'css'
-    html     : config.html || 'html'
-    jade     : config.jade || 'jade'
+    coffee   : config.coffee   || 'coffee'
+    css      : config.css      || 'css'
+    font     : config.font     || 'font'
+    fonts    : config.fonts    || 'fonts'
+    html     : config.html     || 'html'
+    images   : config.images   || 'images'
+    jade     : config.jade     || 'jade'
+    js       : config.js       || 'js'
     markdown : config.markdown || 'markdown'
-    sass     : config.sass || 'sass'
-    stylus   : config.stylus || 'stylus'
-
+    sass     : config.sass     || 'sass'
+    styles   : config.styles   || 'styles'
+    stylus   : config.stylus   || 'stylus'
+
+  #
+  # Nombre de los directorios de destino.
+  #
   names_dest =
+    coffee   : 'coffee'
     css      : 'css'
+    font     : 'font'
     html     : ''
+    images   : 'images'
     js       : 'js'
-    coffee   : 'coffee'
     markdown : 'html'

+  #
+  # Ruta de los directorios de origen.
+  #
   centralDirectory =
     coffee   : path.join "#{src}", "#{names.coffee}"
+    css      : path.join "#{src}", "#{names.css}"
+    font     : path.join "#{src}", "#{names.font}"
+    images   : path.join "#{src}", "#{names.images}"
+    images   : path.join "#{src}", "#{names.images}"
     jade     : path.join "#{src}", "#{names.jade}"
+    js       : path.join "#{src}", "#{names.js}"
     markdown : path.join "#{src}", "#{names.markdown}"
     sass     : path.join "#{src}", "#{names.sass}"
     stylus   : path.join "#{src}", "#{names.stylus}"

+
+  #
+  # Rutas de búsqueda (Match) para encontrar los archivos que se usaran para
+  # compilar.
+  #
   matchs =
-    coffee    : path.join centralDirectory.coffee, "**", "[a-zA-Z0-9]*.coffee"
-    coffeesrc : path.join "#{dest}", "#{names_dest.coffee}", "**", "[a-zA-Z0-9]*.coffee"
-    jade      : path.join centralDirectory.jade, "**", "[a-zA-Z0-9]*.jade"
-    markdown  : path.join centralDirectory.markdown, "**", "*.{markdown,md,mdown}"
-    sass      : path.join centralDirectory.sass, "**", "[a-zA-Z0-9]*.{scss,sass}"
-    stylus    : path.join centralDirectory.stylus, "**", "[a-zA-Z0-9]*.styl"
-
+    coffee    : [path.join centralDirectory.coffee, "**", "[a-zA-Z0-9]*.coffee"]
+    coffeesrc : [path.join "#{dest}", "#{names_dest.coffee}", "**", "[a-zA-Z0-9]*.coffee"]
+    css       : [path.join centralDirectory.css, "**", "[a-zA-Z0-9]*.css"]
+    font      : [path.join centralDirectory.font, "**", "[a-zA-Z0-9]*.{ttf,woff,woff2,svg,eot}"]
+    images    : [path.join centralDirectory.images, "**", "[a-zA-Z0-9]*.{jpg,jpeg,png,gif,svg}"]
+    jade      : [path.join centralDirectory.jade, "**", "[a-zA-Z0-9]*.jade"]
+    js        : [path.join centralDirectory.js, "**", "[a-zA-Z0-9]*.js"]
+    markdown  : [path.join centralDirectory.markdown, "**", "*.{markdown,md,mdown}"]
+    sass      : [path.join centralDirectory.sass, "**", "[a-zA-Z0-9]*.{scss,sass}"]
+    stylus    : [path.join centralDirectory.stylus, "**", "[a-zA-Z0-9]*.styl"]
+
+    # Actúan como visor
     watch :
       coffee   : path.join "#{src}", "#{names.coffee}", "**", "*.coffee"
+      css      : path.join "#{src}", "#{names.css}", "**", "*.css"
+      images   : path.join "#{src}", "#{names.images}", "**", "*.{jpg,jpeg,png,gif,svg}"
       jade     : path.join "#{src}", "#{names.jade}", "**", "*.jade"
+      js       : path.join "#{src}", "#{names.js}", "**", "*.js"
       markdown : path.join "#{src}", "#{names.markdown}", "**", "*.{markdown,md,mdown}"
       sass     : path.join "#{src}", "#{names.sass}", "**", "*.{scss,sass}"
       stylus   : path.join "#{src}", "#{names.stylus}", "**", "*.styl"

+  if externals.css
+    for indexNamecss, namecss of externals.css
+      matchs.css.push namecss
+
+  if externals.font
+    for indexNamefont, namefont of externals.font
+      matchs.font.push namefont
+
+  if externals.js
+    for indexNamejs, namejs of externals.js
+      matchs.js.push namejs
+
+  if externals.coffee
+    for indexNamecoffee, namecoffee of externals.coffee
+      matchs.coffee.push namecoffee
+
+  if externals.images
+    for indexNameimages, nameimages of externals.images
+      matchs.images.push nameimages
+
+  if externals.sass
+    for indexNamesass, namesass of externals.sass
+      matchs.sass.push namesass
+
+  if externals.stylus
+    for indexNamestylus, namestylus of externals.stylus
+      matchs.stylus.push namestylus
+
+
+
+  #
   # Rutas de destino
+  #
   dests =
+    coffee   : path.join "#{dest}", "#{names_dest.coffee}"
     css      : path.join "#{dest}", "#{names_dest.css}"
+    font     : path.join "#{dest}", "#{names_dest.font}"
     html     : path.join "#{dest}", "#{names_dest.html}"
+    images   : path.join "#{dest}", "#{names_dest.images}"
     js       : path.join "#{dest}", "#{names_dest.js}"
-    coffee   : path.join "#{dest}", "#{names_dest.coffee}"
     markdown : path.join "#{dest}", "#{names_dest.markdown}"

   #
-  # Tareas
+  # Tareas Programadas
   #
   gulp.task 'markdown', ->
-    if !(disable_tasks.markdown is false)
+    if not (disable_tasks["markdown"] is false)
       gulp.src matchs.markdown
         .pipe do markdown
         .pipe gulp.dest dests.markdown
@@ -139,7 +212,7 @@

   gulp.task 'stylus', ->
-    if !(disable_tasks.stylus is false)
+    if not (disable_tasks["stylus"] is false)
       gulp.src matchs.stylus
         .pipe do stylus
         .pipe gulp.dest dests.css
@@ -150,7 +223,7 @@

   gulp.task 'sass', ->
-    if !(disable_tasks.sass is false)
+    if not (disable_tasks["sass"] is false)
       gulp.src matchs.sass
         .pipe do sass
         .pipe gulp.dest dests.css
@@ -161,7 +234,7 @@

   gulp.task 'coffee-include', ->
-    if !(disable_tasks['coffee-include'] is false)
+    if not (disable_tasks['coffee-include'] is false)
       gulp.src matchs.coffee
         .pipe do include
         .pipe gulp.dest dests.coffee
@@ -170,7 +243,7 @@
   gulp.task 'coffee', [
     'coffee-include'
     ], ->
-    if !(disable_tasks.coffee is false)
+    if not (disable_tasks["coffee"] is false)
       gulp.src matchs.coffeesrc
         .pipe do sourcemaps.init
         .pipe do coffee
@@ -181,7 +254,7 @@

   gulp.task 'jade', ->
-    if !(disable_tasks.jade is false)
+    if not (disable_tasks["jade"] is false)
       gulp.src matchs.jade
         .pipe do jade
         .pipe gulp.dest dests.html
@@ -190,7 +263,7 @@
   gulp.task 'concat', [
     'coffee'
     ], ->
-    if !(disable_tasks.concat is false)
+    if not (disable_tasks["concat"] is false)
       gulp.src script_to_concat
         .pipe concat name_script_to_concat
         .pipe do minify
@@ -201,7 +274,7 @@
     'sass'
     'stylus'
     ], ->
-    if !(disable_tasks["concat-css"] is false)
+    if not (disable_tasks["concat-css"] is false)
       gulp.src styles_to_concat
         .pipe concatCss name_styles_to_concat
         .pipe do minify
@@ -210,25 +283,52 @@

   ### Tasks Init ###
   gulp.task 'init', ->
-    if !(disable_tasks.init is false)
+    if not (disable_tasks["init"] is false)

       try
-        console.log "Is create the directory ::", src
-        mkdirp.sync src
+        if not fs.existsSync src
+          console.log "Created the directory \"#{src}\"."
+          mkdirp.sync src

       try
-        console.log "Is create the directory ::", dest
-        mkdirp.sync dest
+        if not fs.existsSync dest
+          console.log "Created the directory \"#{dest}\"."
+          mkdirp.sync dest

       for indexCentralDirectory, nameCentralDirectory of centralDirectory
         try
-          console.log "Is create the directory ::", nameCentralDirectory
-          mkdirp.sync nameCentralDirectory
+          if not fs.existsSync nameCentralDirectory
+            console.log "Created the directory \"#{nameCentralDirectory}\"."
+            mkdirp.sync nameCentralDirectory

       for indexDirectoryDests, nameDirectoryDests of dests
         try
-          console.log "Is create the directory ::", nameDirectoryDests
-          mkdirp.sync nameDirectoryDests
+          if not fs.existsSync nameDirectoryDests
+            console.log "Created the directory \"#{nameDirectoryDests}\"."
+            mkdirp.sync nameDirectoryDests
+
+  gulp.task 'copy-css', ->
+    if not (disable_tasks["copy-css"] is false)
+      gulp.src matchs.css
+        .pipe gulp.dest dests.css
+
+  gulp.task 'copy-js', ->
+    if not (disable_tasks["copy-js"] is false)
+      gulp.src matchs.js
+        .pipe gulp.dest dests.js
+
+
+  gulp.task 'copy-images', ->
+    if not (disable_tasks["copy-images"] is false)
+      gulp.src matchs.images
+        .pipe gulp.dest dests.images
+
+
+  gulp.task 'copy-font', ->
+    if not (disable_tasks["copy-font"] is false)
+      gulp.src matchs.font
+        .pipe gulp.dest dests.font
+

   ### End Tasks Init ###

@@ -241,11 +341,15 @@
     'stylus'
     'concat'
     'concat-css'
+    'copy-css'
+    'copy-js'
+    'copy-images'
+    'copy-font'
     ]

   gulp.task 'connect', ->
-    if !(disable_tasks.connect is false)
+    if not (disable_tasks["connect"] is false)
       connect.server
         root: [
           path.join "#{dest}"
@@ -263,12 +367,20 @@
     # 'debug'
     'connect'
     ] , ->
-    if !(disable_tasks.watch is false)
+    if not (disable_tasks["watch"] is false)
+
       gulp.watch matchs.watch.coffee,   ['coffee'] # old: concat
       gulp.watch matchs.watch.jade,     ['jade']
       gulp.watch matchs.watch.markdown, ['markdown', 'jade']
       gulp.watch matchs.watch.sass,     ['sass'] # concat-css
       gulp.watch matchs.watch.stylus,   ['stylus'] # concat-css
+      gulp.watch script_to_concat,      ['concat']
+      gulp.watch styles_to_concat,      ['concat-css']
+
+      gulp.watch matchs.watch.css,      ['copy-css'] # concat-css
+      gulp.watch matchs.watch.js,       ['copy-js'] # concat-css
+      gulp.watch matchs.watch.images,   ['copy-images'] # concat-css
+
       return


Added warning for non-GitHub repos

Added warning for non-GitHub repos

--- index.coffee
+++ index.coffee
@@ -42,6 +42,8 @@
     atom.workspaceView.command 'github-issues:list', ->
       if isGitHubRepo()
         atom.workspace.open 'github-issues://list'
+      else
+        alert 'The current project does not appear to be a GitHub repo.'
     fetchIssues (err, issues) ->
       if err then console.error err
       atom.workspace.registerOpener (uri) ->


fix(decode): fix a syntax issue

fix(decode): fix a syntax issue

--- index.coffee
+++ index.coffee
@@ -1,6 +1,6 @@
 module.exports =

-  decode = ( str ) ->
+  decode: ( str ) ->
     str = str.replace /%[\d\w]{2}/gi, ( code ) -> charsByCode[ code ] ? code
     window.decodeURIComponent str


Set browser to true on Game class when in browser

--- index.coffee
+++ index.coffee
@@ -12,6 +12,7 @@
   window.canvas = canvas

   game = new Game(canvas)
+  game.browser = true
   game.start()
   setInterval((->
     SynchronizedTime.time += 1


Comment typos

Comment typos

--- index.coffee
+++ index.coffee
@@ -78,7 +78,7 @@
 	inserted: (el, binding) -> addListeners el, binding

 	# If the value changed, re-init scrollbar since scrollMonitor doesn't provide
-	# an API to upadte the offsets.  Doing JSON.stringify to conpare as a quick
+	# an API to update the offsets.  Doing JSON.stringify to compare as a quick
 	# way to deep compare objects
 	componentUpdated: (el, binding) ->
 		return if objIsSame binding.value, binding.oldValue


always npm update.

always npm update.

--- index.coffee
+++ index.coffee
@@ -140,14 +140,10 @@
     nodeModulesDir = path.join @config.tmpPath, 'node_modules'
     fs.mkdirpSync nodeModulesDir
     connectorPath = path.join nodeModulesDir, connector
-    if fs.existsSync connectorPath
-      debug "connector #{connector} already installed. skipping installation"
-      return callback()
-
     prefix = ''
     prefix = 'cmd.exe /c ' if process.platform == 'win32'

-    exec("#{prefix} npm --prefix=. install #{connector}"
+    exec("#{prefix} npm --prefix=. update #{connector}"
       cwd: @config.tmpPath
       (error, stdout, stderr) =>
         if error?


fixed example to wrok

fixed example to wrok

--- examples/restify.coffee
+++ examples/restify.coffee
@@ -5,7 +5,7 @@
 express = require "express"
 app = module.exports = express()

-nedb = require "restify-nedb"
+nedb = require("restify-nedb").mount
 ensure = require "../passport/middleware"

 new nedb {


:bug: Fix issue with event delegation selector matching

--- lib/mixins/events-delegation.coffee
+++ lib/mixins/events-delegation.coffee
@@ -30,12 +30,14 @@
       eventsForObject = @eventsMap.get(object)[event]

       {target} = e
-      @eachSelector eventsForObject, (selector,callback) =>
+      found = @eachSelector eventsForObject, (selector,callback) =>
         if @targetMatch(target, selector)
           callback(e)
           return true

-      eventsForObject[NO_SELECTOR]?(e)
+        return false
+
+      eventsForObject[NO_SELECTOR]?(e) unless found
       return true

     object.addEventListener event, listener
@@ -44,8 +46,13 @@

   eachSelector: (eventsForObject, callback) ->
     keys = Object.keys(eventsForObject)
+    if keys.indexOf(NO_SELECTOR) isnt - 1
+      keys.splice(keys.indexOf(NO_SELECTOR), 1)
     keys.sort (a,b) -> b.split(' ').length - a.split(' ').length
-    keys.forEach (key) -> callback(key, eventsForObject[key])
+
+    for key in keys
+      return true if callback(key, eventsForObject[key])
+    return false

   targetMatch: (target, selector) ->
     return true if target.matches(selector)


bai bai execSync

bai bai execSync

--- src/steroids.coffee
+++ src/steroids.coffee
@@ -47,23 +47,6 @@
       if contents.match('steroids-js.git#0.3.5') or contents.match('steroids-js.git#0.3.6')
         Help.legacy.specificSteroidsJSDetected()
         process.exit(1)
-
-
-  runSteroidsCommandSync: (cmd, options={})->
-    # no merging objects :(
-    options.exitOnFailure ?= true
-
-    fullCmd = "steroids #{cmd}"
-    util.log "Running: #{fullCmd}"
-
-    output = execSync fullCmd, true
-
-    console.log output.stdout
-
-    if output.stderr != ""
-      console.log output.stderr
-      if options.exitOnFailure
-        process.exit 1

   debug: (options = {}) =>
     return unless steroidsCli.options.debug


Use .+ instead of .* in the regex pattern for tweet.coffee

This prevents hubot from responding to a blank query by making sure
that something is said before the word tweet.

--- src/scripts/tweet.coffee
+++ src/scripts/tweet.coffee
@@ -33,7 +33,7 @@

   twit = undefined

-  robot.respond /(.*) tweet/i, (msg) ->
+  robot.respond /(.+) tweet/i, (msg) ->
     unless auth.consumer_key
       msg.send "Please set the HUBOT_TWITTER_CONSUMER_KEY environment variable."
       return


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -130,7 +130,7 @@
   @param {Number} height Height of the meter
   @param {Object} position An x, y object representing the position of the meter
   @param {Number} radius Border radius of the meter
-  @param {Boolean} show Boolean to to
+  @param {Boolean} show Boolean to toggle whether of not to display the meter
   @param {Boolean} showName Boolean to toggle whether or not to show the attribute associated with the meter
   @param {String} text A String to display over the meter. Overrides default name attribute
   @param {Number} width How wide the meter is


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -3,7 +3,7 @@
 meter ui to track arbitrary numeric attributes.

-player = Ca
+player = GameO

 player.position()


don't allow deselecting ppl while editing conv

--- src/ui/views/convadd.coffee
+++ src/ui/views/convadd.coffee
@@ -47,7 +47,7 @@
                   else
                       img src: "images/photo.jpg"
                   p r.properties.display_name
-              , onclick:(e) -> action 'deselectentity', r
+              , onclick:(e) -> if not editing then action 'deselectentity', r

           selected_ids = (unique(c) for c in convsettings.selectedEntities)


Export Editor from core

Export Editor from core

--- exports/atom-api.coffee
+++ exports/atom-api.coffee
@@ -5,6 +5,7 @@
   $: require '../src/jquery-extensions'
   $$: $$
   $$$: $$$
+  Editor: require '../src/editor'
   File: require '../src/file'
   fs: require '../src/fs-utils'
   RootView: require '../src/root-view'


Fix bug when I want save data

Fix bug when I want save data

--- dev/helpers/database.coffee
+++ dev/helpers/database.coffee
@@ -10,7 +10,7 @@
         port = 27017
         database = 'app'

-        @uri = 'mongodb://' + host + ':' + port + ':' + database
+        @uri = 'mongodb://' + host + ':' + port + '/' + database

         return
     run: ->
@@ -23,6 +23,8 @@
         con = mongoose.connect @uri

         connect = con.connection
+
+        @app.set 'database', con

         connect.on 'error', (e) ->
             that.app.get('logger').error 'error connection to database', {


$pos is a number, so avoid truncating to int

--- src/natives.coffee
+++ src/natives.coffee
@@ -956,7 +956,7 @@
             fd_obj = _this.get_field rs, 'Ljava/io/RandomAccessFile;fd'
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
             gLong.fromNumber (stat_fd fd).size
-        o 'seek(J)V', (rs, _this, pos) -> _this.$pos = pos.toInt()
+        o 'seek(J)V', (rs, _this, pos) -> _this.$pos = pos.toNumber()
         o 'readBytes([BII)I', (rs, _this, byte_arr, offset, len) ->
             fd_obj = _this.get_field rs, 'Ljava/io/RandomAccessFile;fd'
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
@@ -1387,10 +1387,10 @@
           o 'position0(Ljava/io/FileDescriptor;J)J', (rs, _this, fd, offset) ->
               parent = _this.get_field rs, 'Lsun/nio/ch/FileChannelImpl;parent'
               if offset.equals gLong.NEG_ONE
-                gLong.fromInt parent.$pos
+                gLong.fromNumber parent.$pos
               else
-                parent.$pos = offset.toInt()
-                gLong.fromInt parent.$pos
+                parent.$pos = offset.toNumber()
+                offset
         ]
         FileDispatcher: [
           o 'init()V', (rs) -> # NOP


Create the generated nix expression in sorted order to minimize churn in nixpkgs

--- src/npm2nix.coffee
+++ src/npm2nix.coffee
@@ -29,7 +29,9 @@
     pkgCount -= 1
     if pkgCount is 0
       strings = [ "[" ]
-      for fullName, pkg of packages
+      keys = (key for key, val of packages).sort()
+      for fullName in keys
+        pkg = packages[fullName]
         if pkg is true
           console.error "Internal error: Package #{fullName} never filled in, "
           process.exit 6