Re-add wesabe.xpath.bind with a deprecation warning.

--- application/chrome/content/wesabe/xpath.coffee
+++ application/chrome/content/wesabe/xpath.coffee
@@ -227,3 +227,20 @@

 module.exports = {Pathset, Pathway}
+
+# DEPRECATIONS
+#
+# We previously allowed:
+#
+#   wesabe.xpath.bind(xpath, binding)
+#
+# to be shorthand for:
+#
+#   wesabe.xpath.Pathway.from(xpath).bind(binding)
+#
+# but now the preferred shorthand is:
+#
+#   wesabe.xpath.Pathway.bind(xpath, binding)
+#
+# We re-add the original here with a deprecation notice.
+wesabe.provide 'xpath.bind', logger.wrapDeprecated('wesabe.xpath.bind', 'wesabe.xpath.Pathway.bind', (args...) -> Pathway.bind args...)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/flickerable.coffee
+++ src/flickerable.coffee
@@ -49,7 +49,8 @@
   @param {Number} [alpha=0.5] The alpha value to flicker to
   ###
   flicker: ({duration: 30, frequency: 3, alpha: 0.5}) ->
-    Object.reverse
+    Object.reverseMerge I,
+      duratio

     I.flickerDuration = duration
     I.flickerFrequency = frequency


make analysis example longer

make analysis example longer

--- app/assets/javascripts/index.coffee
+++ app/assets/javascripts/index.coffee
@@ -36,7 +36,7 @@
     ,1000))
   )
   .controller('AnalyzeCtrl', ($scope, playRoutes) ->
-    $scope.text = "Albert osti"
+    $scope.text = "Albert osti fagotin ja töräytti puhkuvan melodian."
     $scope.locale = "fi"
     $scope.$watchCollection('[text,locale]', _.throttle(() ->
       locale = $scope.locale


typo fix

typo fix

--- spec/BaconSpec.coffee
+++ spec/BaconSpec.coffee
@@ -1738,7 +1738,7 @@
       c = Bacon.constant(1)
       Bacon.combineAsArray([c, c]).delay(1).map(".0")), [1]

-describe "when subscribing within the while dispatching", ->
+describe "when subscribing while dispatching", ->
   describe "single subscriber", ->
     describe "up-to-date values are used (skipped bounce)", ->
       expectStreamEvents(


Get component via ComponentLoader

Get component via ComponentLoader

--- spec/SetupPeer.coffee
+++ spec/SetupPeer.coffee
@@ -1,9 +1,10 @@
 noflo = require 'noflo'
 unless noflo.isBrowser()
-  chai = require 'chai' unless chai
-  SetupPeer = require '../components/SetupPeer.coffee'
+  chai = require 'chai'
+  path = require 'path'
+  baseDir = path.resolve __dirname, '../'
 else
-  SetupPeer = require 'noflo-peer/components/SetupPeer.js'
+  baseDir = 'noflo-peer'

 describe 'Browser check', ->
   it 'should be a compatible browser', ->
@@ -13,12 +14,19 @@

 describe 'SetupPeer component', ->
   c = null
-  beforeEach ->
-    c = SetupPeer.getComponent()
-    # ins = noflo.internalSocket.createSocket()
-    # out = noflo.internalSocket.createSocket()
-    # c.inPorts.in.attach ins
-    # c.outPorts.out.attach out
+  loader = null
+  before ->
+    loader = new noflo.ComponentLoader baseDir
+  beforeEach (done) ->
+    @timeout 4000
+    loader.load 'peer/SetupPeer', (err, instance) ->
+      return done err if err
+      c = instance
+      # ins = noflo.internalSocket.createSocket()
+      # out = noflo.internalSocket.createSocket()
+      # c.inPorts.in.attach ins
+      # c.outPorts.out.attach out
+      done()

   describe 'when instantiated', ->
     it 'should have correct input ports', ->


add todo's for more edge cases

add todo's for more edge cases

--- spec/breakwrap.coffee
+++ spec/breakwrap.coffee
@@ -54,3 +54,11 @@
           it 'modifies the already split string and keeps the existing splits', ->
             expect(result.split('\n').length).to.eq 3

+
+    describe 'when the cursor is not at 0', ->
+      it 'takes into account the current cursor position when deciding to split the string', ->
+        # TODO
+
+    describe 'when special escape strings are used in the string', ->
+      it 'takes into account the escape strings when deciding to split the string', ->
+        # TODO


[CW] [73045828] Clarify How the Specs Run

--- spec/coffee/pinball_spec.coffee
+++ spec/coffee/pinball_spec.coffee
@@ -76,6 +76,5 @@

   describe '#debug', ->

-
-  # Hm, something with require isn't loading jasmine
+  # Jasmine 2.0 Works on window.onload and doesn't play well with requirejs
   jasmine.getEnv().execute()


Use atom-api for requires

Use atom-api for requires

--- spec/link-spec.coffee
+++ spec/link-spec.coffee
@@ -1,4 +1,4 @@
-RootView = require 'root-view'
+{RootView} = require 'atom-api'
 shell = require 'shell'

 describe "link package", ->


Changing the background of pie chart labels

--- app/coffee/directives/graphs.coffee
+++ app/coffee/directives/graphs.coffee
@@ -139,7 +139,7 @@
                             "
#{label}
#{slice.data[0][1]}
"
                         background:
                             opacity: 0.5
-                            color: 'white'
+                            color: 'black'
             legend:
                 show: false
             colors: _.map(_.values(dataToDraw), (d) -> d.color)


Fixing config in navurls

Fixing config in navurls

--- app/coffee/modules/base/urls.coffee
+++ app/coffee/modules/base/urls.coffee
@@ -30,7 +30,7 @@

     constructor: (@config) ->
         @.urls = {}
-        @.mainUrl = config.get("api")
+        @.mainUrl = @config.get("api")

     update: (urls) ->
         @.urls = _.merge(@.urls, urls)


enhance: add new step and tour

enhance: add new step and tour

--- app/components/irene-onboard.coffee
+++ app/components/irene-onboard.coffee
@@ -8,6 +8,7 @@
     tours.createStep 'submit-url', 'Please enter your Android/Windows store URL here and click on `Submit URL`'
     tours.createStep 'upload-app', 'Or, You can also upload an app here'
     tours.createStep 'project', 'You can view your projects here after uploading'
+    tours.createStep 'project-details', 'Here is an overview of your file. Click this area to view your scan details'

     # `sd` is shorthand for `Scan Detail`

@@ -18,6 +19,7 @@

     tours.createTour ENV.TOUR.newScan, ['submit-url', 'upload-app', 'project']
     tours.createTour ENV.TOUR.scanDetail, ['sd-overview', 'sd-action-buttons', 'sd-analyses', 'sd-dynamic']
+    tours.createTour ENV.TOUR.manualTour, ['submit-url', 'upload-app', 'project', 'project-details']
   ).on "init"

 `export default IreneOnboardComponent`


Explicitly rebalance stoppedChangingPatch


& replaced by OR when multiple property filters are selected

--- app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee
@@ -50,7 +50,7 @@
   $scope.appliedPropertiesList = ->
     $scope.activeProperties.map( (property_id) ->
       Properties.properties_by_id[property_id].name
-    ).join(" & ") if $scope.activeProperties?
+    ).join(" OR ") if $scope.activeProperties?

   $scope.clearAll = ->
     $scope.query = ""


Add MapCtrl to build markers grouped by district

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -3,3 +3,16 @@
 angular.module('taarifaWaterpointsApp')
   .controller 'MainCtrl', ($scope, Waterpoint) ->
     $scope.waterpoints = Waterpoint.query()
+  .controller 'MapCtrl', ($scope, Waterpoint) ->
+    $scope.dar =
+      lat: -6.7701973
+      lng: 39.2664484
+      zoom: 6
+    $scope.markers = {}
+    Waterpoint.query (waterpoints) ->
+      for p in waterpoints
+        $scope.markers[p._id] =
+          group: p.district
+          lat: p.latitude
+          lng: p.longitude
+          message: "#{p.wpt_code}\nStatus: #{p.status}"


Move initialization code into a function

--- app/scripts/natdashboardctrl.coffee
+++ app/scripts/natdashboardctrl.coffee
@@ -235,16 +235,16 @@
       if val and plotsDirty
         drawPlots()

-    ##########################################################################
-    # Initialization code
-
-    # Ensure the population data is loaded
-    popData = null
-    populationData.then((data) ->
-      popData = data
-      $scope.getStatus())
-
-    getRegion()
-    getLGA()
-    getWard()
-    getProblems()
+    initView = () ->
+      # Ensure the population data is loaded
+      popData = null
+      populationData.then((data) ->
+        popData = data
+        $scope.getStatus())
+
+      getRegion()
+      getLGA()
+      getWard()
+      getProblems()
+
+    initView()


base-domainify: relative path should begin with '.'

--- src/base-domainify.coffee
+++ src/base-domainify.coffee
@@ -40,6 +40,9 @@
         dir = path.dirname(file)
         @relativePath = path.relative(dir, dirname)

+        if @relativePath.charAt(0) isnt '.'
+            @relativePath = './' + @relativePath
+
         initialCode = @getInitialCode(options.dirname)

         @initialCodeGenerated = true
@@ -77,8 +80,8 @@

         for filename in @getFiles()

-            path = @relativePath + '/' + filename
             name = filename.split('.')[0]
+            path = @relativePath + '/' + name

             coffeeCode += """
                 #{_}@addClass '#{name}', require('#{path}')\n


Fix WebTerm to work correctly with multiple VMs

--- client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
@@ -8,14 +8,15 @@
     behavior     : "application"
     preCondition :
       condition  : (options, cb)->
-        KD.singletons.vmController.info (err, vm, info)=>
+        {params} = options
+        vmName   = params?.vmName or "koding~#{KD.nick()}~0"
+        KD.singletons.vmController.info vmName, (err, vm, info)=>
           cb  if info?.state is 'RUNNING' then yes else no
       failure    : (options, cb)->
         KD.singletons.vmController.askToTurnOn 'Terminal', cb

   constructor:(options = {}, data)->
-    vmName          = options.params?.vmName or \
-                      KD.singletons.vmController.getDefaultVmName()
+    vmName          = options.params?.vmName or "koding~#{KD.nick()}~0"
     options.view    = new WebTermAppView {vmName}
     options.appInfo =
       title         : "Terminal on #{vmName}"


Update spec/protocol.coffee

Update spec/protocol.coffee

more than one game per host player

--- spec/protocol.coffee
+++ spec/protocol.coffee
@@ -88,9 +88,13 @@
           players: [
             {
               player:  "Anyname"
-              game:    "my.game-12345" # regex test
-              joined:  1
-              max:     2
+              games: [
+                {
+                  game: "my.game-12345" # regex test
+                  joined:  1
+                  max:     2
+                } # more games ...
+              ]
             },
             { player: "Lukas" },
             { player: "Ananda"  }
@@ -104,14 +108,6 @@
       @anotherplayer.emit 'join', { game: "my.game-12345" } # regex
       @lukas.emit 'join', { host: "Anyname", game: "my.game" }
       @anyplayer.on 'join', (msg) => this.happens() # expect game instance id
-      setTimeout ( () =>
-        expect(@happens.calledTwice).to.be.ok
-        done() ), 42 # ms responsiveness !!!
-
-    it "should acknowledge to all participants that the game starts", (done) ->
-      @anyplayer.emit 'start', { host: "Anyname", game: "my.game" }
-      @anotherplayer.on 'start', (msg) => this.happens()
-      @lukas.on 'start', (msg) => this.happens()
       setTimeout ( () =>
         expect(@happens.calledTwice).to.be.ok
         done() ), 42 # ms responsiveness !!!


Add missing path require

Add missing path require

--- src/git.coffee
+++ src/git.coffee
@@ -1,4 +1,5 @@
 {spawn} = require 'child_process'
+path = require 'path'
 _ = require 'underscore-plus'
 npm = require 'npm'
 config = require './apm'


Added same link logic as found in react-router

--- src/NavItemLink.cjsx
+++ src/NavItemLink.cjsx
@@ -1,22 +1,62 @@
 React = require 'react'
 Router = require 'react-router'
 NavItem = require 'react-bootstrap/NavItem'
+withoutProperties = require 'react-router/modules/helpers/withoutProperties'
+makeHref = require 'react-router/modules/helpers/makeHref'
+
+isLeftClick = (event) -> event.button == 0
+isModifiedEvent = (event) -> !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey)
+
+RESERVED_PROPS =
+  to: true
+  className: true
+  activeClassName: true
+  query: true
+  children: true # ReactChildren
+  active: true
+  activeHref: true
+  activeKey: true
+  key: true
+  navItem: true
+  onSelect: true
+  ref: true

 NavItemLink = React.createClass
   displayName: 'NavItemLink'
   mixins: [Router.ActiveState]
+  statics:
+    getUnreservedProps: (props) -> withoutProperties(props, RESERVED_PROPS)
+  propTypes:
+    to: React.PropTypes.string.isRequired
+    query: React.PropTypes.object
   getInitialState: ->
-    active: false
+    isActive: false
   updateActiveState: ->
     @setState
-      active: NavItemLink.isActive(@props.to, @props.params, @props.query)
-  handleClick: (e) ->
-    e.preventDefault()
-    Router.transitionTo(@props.to, @props.params, @props.query)
+      isActive: NavItemLink.isActive(@props.to, @props.params, @props.query)
+  getParams: ->
+    NavItemLink.getUnreservedProps(@props)
+  getHref: ->
+    makeHref(@props.to, @getParams(), @props.query)
+  componentWillReceiveProps: (nextProps) ->
+    params = NavItemLink.getUnreservedProps(nextProps)
+
+    @setState
+      isActive: NavItemLink.isActive(nextProps.to, params, nextProps.query)
+  updateActiveState: ->
+    @setState
+      isActive: NavItemLink.isActive(@props.to, @getParams(), @props.query)
+  handleClick: (event) ->
+    if (isModifiedEvent(event) || !isLeftClick(event))
+      return
+
+    event.preventDefault()
+
+    Router.transitionTo(@props.to, @getParams(), @props.query)
   render: ->
     @transferPropsTo(
       <NavItem
-        active={@state.active}
+        active={@state.isActive}
         onClick={@handleClick}>
         {@props.children}
       </NavItem>


node: Add Array::first and Array::last back

--- node_modules_koding/koding-config-manager/config.coffee
+++ node_modules_koding/koding-config-manager/config.coffee
@@ -2,6 +2,15 @@
 traverse = require 'traverse'

 KONFIG = {}
+
+do ->
+  unless 'first' of Array.prototype
+    Object.defineProperty Array.prototype, 'first',
+      get: -> this[0]
+  unless 'last' of Array.prototype
+    Object.defineProperty Array.prototype, 'last',
+      get: -> this[this.length-1]
+

 try
   module.exports = KONFIG = JSON.parse process.env.KONFIG_JSON


Configurable src

Configurable src

--- src/scripts/hubot-zoi.coffee
+++ src/scripts/hubot-zoi.coffee
@@ -4,12 +4,17 @@
 # Commands:
 #   hubot zoi - 今日も一日頑張る
 #
+# Configuration:
+#   HUBOT_ZOI_SOURCE_URL
+#
 # Author:
 #   Uchio KONDO

 request = require 'request'
-uri     = 'http://zoi.herokuapp.com/js/services.js'
+uri     = process.env.HUBOT_ZOI_SOURCE_URL
+
+throw new Error('Please set HUBOT_ZOI_SOURCE_URL env') unless uri?

 getZois = (cb) ->
   request(uri, (err, response, body) ->


Add explanation to when can't find user for that name

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -278,7 +278,7 @@

     pagerDutyGet msg, "/users", {query: email}, (json) ->
       if json.users.length isnt 1
-        msg.send "Sorry, I expected to get 1 user back for #{email}, but got #{json.users.length} :sweat:"
+        msg.send "Sorry, I expected to get 1 user back for #{email}, but got #{json.users.length} :sweat:. Can you make sure that is actually a real user on PagerDuty?"
         return

       cb(json.users[0])


ignores the ?

ignores the ?

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -552,7 +552,7 @@
             msg.send 'No schedules found!'

   # who is on call?
-  robot.respond /who(’s|'s|s| is|se)? (on call|oncall|on-call)( (?:for )?(.+))?/i, (msg) ->
+  robot.respond /who(?:’s|'s|s| is|se)? (?:on call|oncall|on-call)(?: (?:for )?(.*?)(?:\?|$))?/i, (msg) ->
     if pagerduty.missingEnvironmentForApi(msg)
       return


bug fix

bug fix

--- src/simditor-markdown.coffee
+++ src/simditor-markdown.coffee
@@ -125,12 +125,13 @@
   _onKeyPress: (e) ->
     # check the input hooks
     if e.which is 32 or e.which is 13
-      container = @editor.selection.getRange().commonAncestorContainer
-      cmd       = container.textContent
+      range = @editor.selection.getRange()
+      container = range?.commonAncestorContainer
+      return unless range and container and container.nodeType == 3

-      return unless container.nodeName is "#text"
+      cmd = $.trim(container.textContent)
       for name, hook of @markdownConfigs
-        if hook.cmd instanceof RegExp and hook.cmd.test(cmd.trim())
+        if hook.cmd instanceof RegExp and hook.cmd.test(cmd)
           range = document.createRange()
           range.setStart container, 0
           range.setEnd   container, 0


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -136,7 +136,7 @@

 @name startsWith
 @methodOf String#
-@param
+@param {String} s

 @returns {Boolean} True if this string starts with the given string, false otherwise.
 ###


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -130,6 +130,8 @@
     JSON.parse(this.toString())
   catch e
     this.toString()
+
+String::startsWith

 ###*
 Returns a new string in Title Case.


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -26,6 +26,7 @@
   ###*
   @name clampToBounds
   @methodOf Clampable#
+  @param
   ###
   clampToBounds: (bounds) ->
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height


fix bug ref http://bugs.jquery.com/ticket/8283

--- src/urlhandlers/flash.coffee
+++ src/urlhandlers/flash.coffee
@@ -18,6 +18,8 @@
         xdr.timeout = options.timeout or 0
         xdr.withCredentials = options.withCredentials or false
         xdr.send()
+        xdr.onprogress = ->
+
         xdr.onload = ->
              xmlDocument.loadXML(xdr.responseText)
              cb(null, xmlDocument)


implemented rotate (dyadic ⌽ and ⊖)

implemented rotate (dyadic ⌽ and ⊖)

--- src/vocabulary/rotate.coffee
+++ src/vocabulary/rotate.coffee
@@ -1,18 +1,46 @@
 {APLArray} = require '../array'
-{assert, prod} = require '../helpers'
+{assert, prod, repeat} = require '../helpers'

-#
 @['⌽'] = rotate = (omega, alpha, axis) ->
   assert typeof axis is 'undefined' or axis instanceof APLArray
   if alpha
     # Rotate (`⌽`)
     #
-    #!    1 ⌽ 1 2 3 4 5 6                   ⍝ returns 2 3 4 5 6 1
-    #!    3 ⌽ 'ABCDEFGH'                    ⍝ returns 'DEFGHABC'
-    #!    3 ⌽ 2 5 ⍴  1 2 3 4 5  6 7 8 9 0   ⍝ returns 2 5 ⍴ 4 5 1 2 3 9 0 6 7 8
-    #!    ¯2 ⌽ "ABCDEFGH"                   ⍝ returns 'GHABCDEF'
-    #!    1 ⌽ 3 3 ⍴ ⍳ 9                     ⍝ returns 3 3 ⍴ 1 2 0 4 5 3 7 8 6
-    throw Error 'Not implemented'
+    #     1 ⌽ 1 2 3 4 5 6                   ⍝ returns 2 3 4 5 6 1
+    #     3 ⌽ 'ABCDEFGH'                    ⍝ returns 'DEFGHABC'
+    #     3 ⌽ 2 5 ⍴  1 2 3 4 5  6 7 8 9 0   ⍝ returns 2 5 ⍴ 4 5 1 2 3 9 0 6 7 8
+    #     ¯2 ⌽ "ABCDEFGH"                   ⍝ returns 'GHABCDEF'
+    #     1 ⌽ 3 3 ⍴ ⍳ 9                     ⍝ returns 3 3 ⍴ 1 2 0 4 5 3 7 8 6
+    #     0 ⌽ 1 2 3 4                       ⍝ returns 1 2 3 4
+    #     0 ⌽ 1234                          ⍝ returns 1234
+    #     5 ⌽ ⍬                             ⍝ returns ⍬
+    axis = if not axis then omega.shape.length - 1 else axis.unbox()
+    if typeof axis isnt 'number' or axis isnt Math.floor axis
+      throw Error 'DOMAIN ERROR'
+    if omega.shape.length and not (0 <= axis < omega.shape.length)
+      throw Error 'INDEX ERROR'
+    step = alpha.unbox()
+    if typeof step isnt 'number' or step isnt Math.floor step
+      throw Error 'DOMAIN ERROR'
+    if not step
+      return omega
+    n = omega.shape[axis]
+    step = (n + (step % n)) % n # force % to handle negatives properly
+    if omega.empty() or step is 0 then return omega
+    data = []
+    {shape, stride} = omega
+    p = omega.offset
+    indices = repeat [0], shape.length
+    loop
+      data.push omega.data[p + ((indices[axis] + step) % shape[axis] - indices[axis]) * stride[axis]]
+      a = shape.length - 1
+      while a >= 0 and indices[a] + 1 is shape[a]
+        p -= indices[a] * stride[a]
+        indices[a--] = 0
+      if a < 0 then break
+      indices[a]++
+      p += stride[a]
+    new APLArray data, shape
   else
     # Reverse (`⌽`)
     #
@@ -46,6 +74,6 @@
 #
 # 1st axis rotate (`⊖`)
 #
-#!    1 ⊖ 3 3 ⍴ ⍳ 9   ⍝ returns 3 3 ⍴ 3 4 5 6 7 8 0 1 2
+#    1 ⊖ 3 3 ⍴ ⍳ 9   ⍝ returns 3 3 ⍴ 3 4 5 6 7 8 0 1 2
 @['⊖'] = (omega, alpha, axis = APLArray.zero) ->
   rotate omega, alpha, axis


some type casting

some type casting

Signed-off-by: Zach Aller <4787d6de6a760249392703056ca7cdd759317178@hotmail.com>

--- src/data-type.coffee
+++ src/data-type.coffee
@@ -23,7 +23,7 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(1)
-        buffer.writeInt8(parameter.value)
+        buffer.writeInt8(parseInt(parameter.value))
       else
         buffer.writeUInt8(0)
   0x32:
@@ -55,7 +55,7 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(2)
-        buffer.writeInt16LE(parameter.value)
+        buffer.writeInt16LE(parseInt(parameter.value))
       else
         buffer.writeUInt8(0)
   0x38:
@@ -71,7 +71,7 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(4)
-        buffer.writeInt32LE(parameter.value)
+        buffer.writeInt32LE(parseInt(parameter.value))
       else
         buffer.writeUInt8(0)
   0x3A:
@@ -113,7 +113,7 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(4)
-        buffer.writeFloatLE(parameter.value)
+        buffer.writeFloatLE(parseFloat(parameter.value))
       else
         buffer.writeUInt8(0)
       ###
@@ -160,7 +160,7 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(8)
-        buffer.writeDoubleLE(parameter.value)
+        buffer.writeDoubleLE(parseFloat(parameter.value))
       else
         buffer.writeUInt8(0)
   0x7A:
@@ -179,8 +179,10 @@
       # ParamLenData
       if parameter.value?
         buffer.writeUInt8(8)
-        buffer.writeUInt32LE(parameter.value%4294967296)
-        buffer.writeUInt32LE(Math.floor(parameter.value/4294967296))
+        buffer.writeUInt32LE(parseInt(parameter.value) % 0x100000000)
+        buffer.writeUInt32LE(Math.floor(parseInt(parameter.value) / 0x100000000))
+        # might need to sign the high value not sure
+        # buffer.writeInt32LE(Math.floor(parseInt(parameter.value) / 0x100000000))
       else
         buffer.writeUInt8(0)

@@ -268,7 +270,7 @@
       if parameter.length
         length = parameter.length
       else if parameter.value?
-        length = parameter.value.length
+        length = parameter.value.toString().length
       else
         length = @.maximumLength

@@ -280,7 +282,7 @@
       if parameter.length
         length = parameter.length
       else if parameter.value?
-        length = parameter.value.length
+        length = parameter.value.toString().length
       else
         length = @.maximumLength

@@ -296,13 +298,13 @@
       if parameter.value?
         if length <= @maximumLength
           buffer.writeUInt16LE(length)
-          buffer.writeString(parameter.value, 'ascii')
+          buffer.writeString(parameter.value.toString(), 'ascii')
         else
           # Length of all chunks.
           buffer.writeUInt64LE(length)
           # One chunk.
           buffer.writeUInt32LE(length)
-          buffer.writeString(parameter.value, 'ascii')
+          buffer.writeString(parameter.value.toString(), 'ascii')
           # PLP_TERMINATOR (no more chunks).
           buffer.writeUInt32LE(0)
       else
@@ -326,7 +328,7 @@
       if parameter.length
         length = 2 * parameter.length
       else if parameter.value?
-        length = 2 * parameter.value.length
+        length = 2 * parameter.value.toString().length
       else
         length = @maximumLength

@@ -338,7 +340,7 @@
       if parameter.length
         length = 2 * parameter.length
       else if parameter.value?
-        length = 2 * parameter.value.length
+        length = 2 * parameter.value.toString().length
       else
         length = @maximumLength

@@ -354,13 +356,13 @@
       if parameter.value?
         if length <= @maximumLength
           buffer.writeUInt16LE(length)
-          buffer.writeString(parameter.value, 'ucs2')
+          buffer.writeString(parameter.value.toString(), 'ucs2')
         else
           # Length of all chunks.
           buffer.writeUInt64LE(length)
           # One chunk.
           buffer.writeUInt32LE(length)
-          buffer.writeString(parameter.value, 'ucs2')
+          buffer.writeString(parameter.value.toString(), 'ucs2')
           # PLP_TERMINATOR (no more chunks).
           buffer.writeUInt32LE(0)
       else


implement named layouts

implement named layouts


things

things

--- src/instagram.coffee
+++ src/instagram.coffee
@@ -27,7 +27,7 @@
       q: 'kyleinfrontofwalls'
       complete: (data) ->
         index = Math.floor(Math.random() * data.length)
-        imageUrl = data[index]['images']['standard_resolution']['url']
+        imageUrl = data[index]
         msg.send imageUrl

 authenticateUser = (msg) ->


增加$stateChangeStart来获取用户是否登录

增加$stateChangeStart来获取用户是否登录

--- src/js/routes.coffee
+++ src/js/routes.coffee
@@ -22,8 +22,8 @@

   _app.config(['$routeProvider', '$locationProvider', '$stateProvider', '$urlRouterProvider',
   ($routeProvider, $locationProvider, $stateProvider, $urlRouterProvider) ->
+
     $locationProvider.html5Mode enabled: true, requireBase: false
-
     templates =
       issueDetails: require('./issue/views/details.html')
       home: require('./views/home.html')
@@ -510,4 +510,18 @@
       views: issueViews
     )

-  ])+  ])
+
+  _app.run ($rootScope, $timeout, $state, API)->
+    #如果用户没有获取登录信息， 则先获取用户的登录信息，则继续流程
+    $rootScope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams)->
+      #没有获取到用户的信息，阻止用户
+      return if $rootScope.__member
+
+      #阻止流程
+      event.preventDefault()
+      #获取用户信息
+      API.session().retrieve().then (result)->
+        $rootScope.__member = result
+        $state.go(toState, toParams)
+    )


fixed amd define statement

fixed amd define statement

--- src/ki-router.coffee
+++ src/ki-router.coffee
@@ -35,13 +35,14 @@
 # - hashbang urls don't work in a href tags -> won't fix, use /plain/urls
 # - does not resolve situation hashbang url needs to be converted and both window.location.pathname and window.location.hash are defined

+KiRouter = {}
 if module?
-  module.exports = KiRouter = {} # for KiRouter = require 'KiRouterjs'
+  module.exports = KiRouter # for KiRouter = require 'KiRouterjs'
   KiRouter.KiRouter = KiRouter # for {KiRouter} = require 'KiRouterjs'
 else
   if define? and define.amd?
-    define (-> KiRouter)
-  @KiRouter = KiRouter = {} # otherwise for execution context
+    define [], -> KiRouter
+  @KiRouter = KiRouter # otherwise for execution context

 KiRouter.router = -> new KiRoutes()


ComputeProvider: No need for fat-arrows

ComputeProvider: No need for fat-arrows

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -190,7 +190,7 @@
         baseStackId : template._id
         groupSlug   : group.slug
         account
-      }, (err, stack)=>
+      }, (err, stack)->

         return callback err  if err

@@ -203,17 +203,17 @@
           account.addStackTemplate template, (err)->
             if err then callback err else queue.next()

-        machines.forEach (machineInfo) =>
-
-          queue.push =>
+        machines.forEach (machineInfo) ->
+
+          queue.push ->
             machineInfo.stack = stack
-            @create client, machineInfo, (err, machine)->
+            ComputeProvider.create client, machineInfo, (err, machine)->
               results.machines.push { err, machine }
               queue.next()

-        domains.forEach (domainInfo) =>
-
-          queue.push =>
+        domains.forEach (domainInfo) ->
+
+          queue.push ->
             domain = domainInfo.domain.replace "${username}", user.username
             JDomain.createDomain {
               domain, account,


use expectRelation helper in credential.test.coffee

--- workers/social/lib/social/models/computeproviders/credential.test.coffee
+++ workers/social/lib/social/models/computeproviders/credential.test.coffee
@@ -1,8 +1,8 @@
 JCredential      = require './credential'
 JCredentialData  = require './credentialdata'
-{ Relationship } = require 'jraphical'
 { daisy
   expect
+  expectRelation
   withDummyClient
   withConvertedUser
   expectAccessDenied
@@ -93,9 +93,7 @@
               targetName : 'JCredential'
               sourceName : 'JAccount'

-            Relationship.one options, (err, relationship) ->
-              expect(err).to.not.exist
-              expect(relationship).to.exist
+            expectRelation.toExist options, ->
               queue.next()

           ->
@@ -107,9 +105,7 @@
               targetName : 'JCredentialData'
               sourceName : 'JCredential'

-            Relationship.one options, (err, relationship) ->
-              expect(err).to.not.exist
-              expect(relationship).to.exist
+            expectRelation.toExist options, ->
               queue.next()

           -> done()
@@ -297,9 +293,7 @@
             targetName : 'JCredential'
             sourceName : 'JAccount'

-          Relationship.one options, (err, relationship) ->
-            expect(err).to.not.exist
-            expect(relationship).to.exist
+          expectRelation.toExist options, (relationship) ->
             expect(relationship.sourceId).to.be.deep.equal anotherAccount._id
             queue.next()

@@ -348,9 +342,7 @@
             targetName : 'JCredential'
             sourceName : 'JAccount'

-          Relationship.one options, (err, relationship) ->
-            expect(err).to.not.exist
-            expect(relationship).to.exist
+          expectRelation.toExist options, (relationship) ->
             expect(relationship.sourceId).to.be.deep.equal anotherAccount._id
             queue.next()


Fix for new versions of jQuery

Fix for new versions of jQuery

--- lib/assets/javascripts/zui53/tools/zoom_tool.js.coffee
+++ lib/assets/javascripts/zui53/tools/zoom_tool.js.coffee
@@ -109,12 +109,12 @@
       if @disabled
         return

-      delta = e.wheelDelta || (e.detail * -1)
+      delta = e.originalEvent.wheelDelta || (e.originalEvent.detail * -1)
       f = 0.05
       if delta < 0
         f *= -1

-      @vp.zoomBy(f, e.clientX, e.clientY)
+      @vp.zoomBy(f, e.originalEvent.clientX, e.originalEvent.clientY)

       @stopEvent(e)


Implement the 'random-opponent' target.

Implement the 'random-opponent' target.

--- server/battle.coffee
+++ server/battle.coffee
@@ -363,6 +363,9 @@
         pokemon = @getOpponentPokemon(id, @numActive)
         pokemon.push(@getTeam(id).at(0))
         pokemon
+      when 'random-opponent'
+        pokemon = @getOpponentPokemon(id, @numActive)
+        @rng.choice(pokemon)
       when 'users-field'
         @getTeam(id).pokemon
       else


more validation

more validation


Small changes to variable names

Small changes to variable names

--- test/controllers/x3d-controller-test.coffee
+++ test/controllers/x3d-controller-test.coffee
@@ -1,8 +1,8 @@
-X3d = require 'controllers/x3d-controller'
+X3dController = require 'controllers/x3d-controller'

-describe 'X3d', ->
+describe 'X3d Controller', ->
   beforeEach ->
-    @controller = new X3d()
+    @controller = new X3dController()

   afterEach ->
     @controller.dispose()


Don't use an existential operator on a boolean...

--- src/middleware/visualizer.coffee
+++ src/middleware/visualizer.coffee
@@ -87,5 +87,5 @@

 exports.koaMiddleware = (next) ->
   yield next
-  if config.visualizer.enableVisualizer?
+  if config.visualizer.enableVisualizer
     storeVisualizerEvents this, ->


one catch should do it

one catch should do it

--- API/src/scraper.coffee
+++ API/src/scraper.coffee
@@ -64,8 +64,6 @@
                     for url in urls
                         p.push get_details url
                     Promise.all p
-                .catch (err) ->
-                    r err
                 .then (values) ->
                     cache.set('tiere', values, 60*60*24)
                     f values


Fixed --watch on failed first build

Fixed --watch on failed first build

--- cli/tasks/build/server/index.coffee
+++ cli/tasks/build/server/index.coffee
@@ -88,9 +88,9 @@
                     if err
                         res.send 500, utils.errorToObject(err)
                     else
-                        if data.watch
-                            startWatchers data
                         res.send 200
+                    if data.watch
+                        startWatchers data
             unless buildsStack.pending
                 buildsStack.runAll utils.NOP


Parameterizing theoricus path in config file.

--- cli/templates/app_skel/polvo.coffee
+++ cli/templates/app_skel/polvo.coffee
@@ -1,3 +1,5 @@
+theoricus = 'node_modules/theoricus'
+
 setup

   # ----------------------------------------------------------------------------
@@ -49,10 +51,10 @@
     javascript:

       # theoricus
-      'json': ".theoricus/www/vendors/json2.js"
-      'history': ".theoricus/www/vendors/history.js"
-      'inflection': ".theoricus/www/vendors/inflection.js"
-      'jquery': ".theoricus/www/vendors/jquery.js"
+      'json': "#{theoricus}/www/vendors/json2.js"
+      'history': "#{theoricus}/www/vendors/history.js"
+      'inflection': "#{theoricus}/www/vendors/inflection.js"
+      'jquery': "#{theoricus}/www/vendors/jquery.js"

       # app
       # 'app_vendor_name': 'vendors/app_vendor_name.js'


Remove duplicate call to TokenizedBuffer:resetTokenizesLines()

This is already handled in an event listener bound to 'grammar-changed'
which TokenizedBuffer::setGrammar triggers.

--- src/app/tokenized-buffer.coffee
+++ src/app/tokenized-buffer.coffee
@@ -57,7 +57,6 @@
     @grammar = grammar
     @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
     @subscribe @grammar, 'grammar-updated', => @resetTokenizedLines()
-    @resetTokenizedLines()
     @trigger 'grammar-changed', grammar

   reloadGrammar: ->


fix getOriginal import

fix getOriginal import

--- client/js/views/picture_view.coffee
+++ client/js/views/picture_view.coffee
@@ -2,7 +2,8 @@
 require 'hammer-jquery'

 {View} = require './helpers/view_helper.coffee'
-{selectMedia, preloadMedia, getOriginal} = require './helpers/media_helper.coffee'
+{selectMedia, preloadMedia} = require './helpers/media_helper.coffee'
+{getOriginal} = require '../../../shared/helpers/media_helper.coffee'
 {makeBreadcrumb} = require '../../../shared/helpers/path_helper.coffee'

 class PictureView extends View


Go top on clear columns

Go top on clear columns

--- public/javascripts/app/views/app.coffee
+++ public/javascripts/app/views/app.coffee
@@ -538,3 +538,7 @@

   clearColumns: (columns = ['main', 'side1', 'side2'])->
     (@["#{column}ColumnView"] and @["#{column}ColumnView"].remove()) for column in columns
+    @goTop()
+
+  goTop: ()->
+    $("window,html,body").scrollTop(0)


Only work if a model is given

Only work if a model is given

--- client/skr/components/SkuLines.cjsx
+++ client/skr/components/SkuLines.cjsx
@@ -53,6 +53,7 @@
             />

     onSelectionChange:  (model) ->
+        return unless model and @props.commands.isEditing()
         new _.Promise (res, rej) ->
             model.withAssociations([
                 'sku_loc', 'sku', 'uom_choices'


fix in Evaluator

fix in Evaluator

--- src/Evaluator.coffee
+++ src/Evaluator.coffee
@@ -26,7 +26,10 @@
         catcher e

     @flush = (name)->
-      delete properties[name]
-      delete Store.failed[name]
+      try
+        delete properties[name]
+        delete Store.failed[name]
+      catch e
+        catcher e

     this


fix overlooked init->dinit switch for Ticker creation

--- bokehjs/src/coffee/ticking/years_ticker.coffee
+++ bokehjs/src/coffee/ticking/years_ticker.coffee
@@ -12,10 +12,10 @@
   class YearsTicker extends SingleIntervalTicker.Model
     type: 'YearsTicker'

-    initialize: (attrs, options) ->
+    dinitialize: (attrs, options) ->
       super(attrs, options)
       @set('interval', ONE_YEAR)
-      @basic_ticker = new BasicTicker.Model()
+      @basic_ticker = BasicTicker.Collection.create({doc: @get('doc')})

     get_ticks_no_defaults: (data_low, data_high, desired_n_ticks) ->
       start_year = last_year_no_later_than(new Date(data_low)).getUTCFullYear()


Auto-detect fluid video containers

Auto-detect fluid video containers

--- app/assets/javascripts/main.js.coffee
+++ app/assets/javascripts/main.js.coffee
@@ -1,6 +1,5 @@
 class FluidVideos
-  constructor: ->
-  @init: (container="body", $videos=null) ->
+  @init: (container=null, $videos=null) ->
     $videos ||= $("iframe[src*='vimeo.com'], iframe[src*='youtube.com']")

     $videos.each ->
@@ -10,9 +9,10 @@
         .removeAttr('width')

     $(window).resize ->
-      newWidth = $(container).width()
       $videos.each ->
         $elm = $(this)
+        $parent = if container then $(container) else $elm.parent()
+        newWidth = $parent.width()
         $elm
           .width(newWidth)
           .height(newWidth * $elm.data('aspectRatio'))
@@ -20,7 +20,6 @@
     $(window).resize()

 class Viewport
-  constructor: ->
   @getWidth: ->
     size = window
             .getComputedStyle(document.body,':after')
@@ -28,7 +27,6 @@
     size.replace(/\"/g, '')

 class Lightbox
-  constructor: ->
   @init: ->
     $("a[href$='.jpg'],a[href$='.png'],a[href$='.jpeg']").each ->
       $link = $(this)
@@ -45,7 +43,6 @@
         })

 class Calendar
-  constructor: ->
   @init: ->
     $('#fullcalendar').html("").fullCalendar({
       events: {


Fix reintroduced bug in Mark All Read

Fix reintroduced bug in Mark All Read

--- app/assets/javascripts/main.js.coffee
+++ app/assets/javascripts/main.js.coffee
@@ -166,7 +166,7 @@
     document.title = 'CSH WebNews'
     $('#unread_line').text('Marked all posts read. Reloading activity feed...')
     $('#activity_feeds').remove()
-    window.onhashchange()
+    after_func = -> window.onhashchange()
   else
     abort_active_scroll()
     after_func = -> $('#posts_list').scroll()


Confused by parens

Confused by parens

--- app/assets/javascripts/vote.js.coffee
+++ app/assets/javascripts/vote.js.coffee
@@ -35,7 +35,7 @@

     set: (vote) ->
         return false if vote > @v.fav
-        notice(t 'voting' + '...')
+        notice t('voting') + '...'
         Moebooru.request @api.vote_url, {id: @current_post.id, score: vote}

     updateWidget: ->


Customize geojson markers based on dataset styles

--- app/assets/javascripts/welcome.coffee
+++ app/assets/javascripts/welcome.coffee
@@ -6,30 +6,44 @@

   console.log 'Page loaded!'

-  map = L.map('mapid').setView([40.75, -74.00], 12)
+  if $('#mapid').length > 0

-  # OSM Tile layer
-  osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
-    minZoom: 4,
-    maxZoom: 16,
-    attribution: 'Map data © OpenStreetMap contributors'
-  })
-  map.addLayer(osm)
+    map = L.map('mapid').setView([40.75, -74.00], 12)

-  $('.btn-load-dataset').click((event) ->
-    event.preventDefault()
+    # OSM Tile layer
+    osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+      minZoom: 4,
+      maxZoom: 16,
+      attribution: 'Map data © OpenStreetMap contributors'
+    })
+    map.addLayer(osm)

-    button = $(this)
-    datasetId = button.attr('id')
-    console.log "Clicked dataset: #{datasetId}"
+    geojsonMarkerOptions = {
+      radius: 8,
+      fillColor: "#ff7800",
+      weight: 4,
+      opacity: 1,
+      fillOpacity: 0.8
+    }

-    # Load geobjects of dataset
-    $.getJSON("/datasets/#{datasetId}.json", (data) ->
-      console.log data
-      L.geoJSON(data.feature_collection, {
-        onEachFeature: (feature, layer) ->
-          if (feature.properties && feature.properties)
-            layer.bindPopup(JSON.stringify(feature.properties, null, 2).replace(/\n/g, '
'));
-      }).addTo(map);
+    $('.btn-load-dataset').click((event) ->
+      event.preventDefault()
+
+      button = $(this)
+      datasetId = button.attr('id')
+      console.log "Clicked dataset: #{datasetId}"
+
+      # Load geobjects of dataset
+      $.getJSON("/datasets/#{datasetId}.json", (data) ->
+        console.log data
+        L.geoJSON(data.feature_collection, {
+          style: data.style,
+          pointToLayer: (feature, latlng) ->
+            L.circleMarker(latlng, geojsonMarkerOptions)
+          ,
+          onEachFeature: (feature, layer) ->
+            if (feature.properties && feature.properties)
+              layer.bindPopup(JSON.stringify(feature.properties, null, 2).replace(/\n/g, '
'));
+        }).addTo(map);
+      )
     )
-  )


Removes commented legacy commented out lines in test

--- tests/infrastructure/messaging.tests.coffee
+++ tests/infrastructure/messaging.tests.coffee
@@ -2,14 +2,12 @@

   customer = id: 'customer_123', name: 'Dominik'
   registration = id: 'registration_123'
-#  sharedCommitCollection = new Mongo.Collection('messaging_shared_commits')

   beforeEach ->
     @fakeDates = sinon.useFakeTimers('Date')
     @app = new CustomerApp()
     @app.configure {
       appId: 'CustomerApp'
-#      eventSourcing: { commitsCollection: sharedCommitCollection }
     }
     @generatedEventsForCustomerRegistration = [
       new CustomerApp.RegistrationInitiated({


Fix stupid error check with double request on projects tooltip

--- app/coffee/controllers/project.coffee
+++ app/coffee/controllers/project.coffee
@@ -47,11 +47,13 @@
             @scope.loading = true
             @scope.showingProjects = true

-            @rs.getProjects().then (projects) =>
+            promise = @rs.getProjects()
+
+            promise.then (projects) =>
                 @scope.myProjects = projects
                 @scope.loading = false

-            @rs.getProjects().then null, =>
+            promise.then null, =>
                 @scope.myProjects = []
                 @scope.loading = false


Remove 'Kakita' :poop:

Remove 'Kakita' :poop:

--- app/coffee/modules/issues/list.coffee
+++ app/coffee/modules/issues/list.coffee
@@ -192,7 +192,6 @@

     # Functions used from templates
     addNewIssue: ->
-        console.log "Kakita"
         @rootscope.$broadcast("issueform:new")

     addIssuesInBulk: ->


add `read_chunks_from_file()`

add `read_chunks_from_file()`


A takon is generated automatically from now

--- src/public/models/node.coffee
+++ src/public/models/node.coffee
@@ -90,10 +90,10 @@
 		#
 		addPeer: ( peer ) ->
 			peer.on('disconnect', ( ) => @removePeer(peer))
-			peer.on('peer.addSibling', ( ) => @addSibling(peer, false))
+			peer.on('peer.addSibling', ( ) => @addSibling(peer, false); console.log peer.id)

 			@_peers.add(peer)
-			@trigger('peer.added', peer)
+			@trigger('peer.added', peer) #

 		# Removes a peer from the peer list
 		#
@@ -183,6 +183,8 @@
 				@_parent = null

 			peer.role = Peer.Role.Child
+			if @getChildren().length > 2
+				@generateToken()

 		# Removes a peer as child node. Does not automatically close
 		# the connection but will make it a normal peer.
@@ -216,7 +218,7 @@
 				@_parent = null

 			peer.role = Peer.Role.Sibling
-
+			console.log peer, instantiate
 			if instantiate
 				peer.emit('peer.addSibling', @id)

@@ -250,7 +252,7 @@
 		setSuperNode: ( superNode = true ) =>
 			@isSuperNode = superNode
 			@server.emit('setSuperNode', @isSuperNode)
-			@trigger('setSuperNode', @isSuperNode)
+			@trigger('setSuperNode', @isSuperNode) # App is listening
 			@broadcast('peer.setSuperNode', @id, @isSuperNode)

 		# Is called when a peer becomes a supernode
@@ -266,7 +268,7 @@
 					@addSibling(peer)
 				else
 					peer = @connect(peerId)
-					peer.once('connect', =>
+					peer.once('channel.opened', =>
 						@addSibling(peer)
 					)

@@ -340,11 +342,10 @@
 				when 'peers'
 					return _(@getPeers()).map( ( peer ) -> peer.id )
 				when 'peer.requestParent'
-					if @getChildren().length < 4
-						child = @getPeer(args[0])
-						if child?
-							@addChild(child)
-							return true
+					child = @getPeer(args[0])
+					if child?
+						@addChild(child)
+						return true
 					return false

 		###
@@ -434,27 +435,16 @@
 			endTime = performance.now()
 			@benchmark.cpu = Math.round(endTime - startTime)

-		# Look up if node is having trouble
-		#
-		# @return [Boolean] Return true if node has troubles
-		#
-		hasDifficulties: ( ) =>
-			if @isSuperNode
-				if @getChildren().length > 3
-					return true
-			return false
-
 		# Generates a new token and gives it to a random child
 		#
 		# @return [String] Returns id of the selected Child which will receive a token
 		#
-		generateToken: ( ) =>
-			if @hasDifficulties()
-				token = new Token(null, @id)
-				children = @getChildren()
-				randomChild = children[_.random(0,children.length-1)]
-				randomChild.emit("token.add",token.serialize())
-				return randomChild.id
+		generateToken: () =>
+			token = new Token(null, @id)
+			children = @getChildren()
+			randomChild = children[_.random(0,children.length-1)]
+			randomChild.emit("token.add",token.serialize())
+			return randomChild.id

 		# Is called when a node receives a token from another Node
 		#


Enable mentions for edit comment form (#3940)

--- angular/core/components/thread_page/comment_form/edit_comment_form.coffee
+++ angular/core/components/thread_page/comment_form/edit_comment_form.coffee
@@ -1,6 +1,6 @@
 angular.module('loomioApp').factory 'EditCommentForm', ->
   templateUrl: 'generated/components/thread_page/comment_form/edit_comment_form.html'
-  controller: ($scope, comment, FormService, EmojiService) ->
+  controller: ($scope, comment, FormService, EmojiService, MentionService) ->
     $scope.comment = comment.clone()

     $scope.submit = FormService.submit $scope, $scope.comment,
@@ -8,3 +8,4 @@

     $scope.bodySelector = '.edit-comment-form__comment-field'
     EmojiService.listen $scope, $scope.comment, 'body', $scope.bodySelector
+    MentionService.applyMentions $scope, $scope.comment


Fixed array concat.

Fixed array concat.

--- app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee
@@ -81,15 +81,15 @@
         if article.from
           localRecipients = emailAddresses.parseAddressList(article.from)
           if localRecipients
-            recipients.push recipients.concat localRecipients
+            recipients = recipients.concat localRecipients
       if article.to
         localRecipients = emailAddresses.parseAddressList(article.to)
         if localRecipients
-          recipients.push recipients.concat localRecipients
+          recipients = recipients.concat localRecipients
       if article.cc
         localRecipients = emailAddresses.parseAddressList(article.cc)
         if localRecipients
-          recipients.push recipients.concat localRecipients
+          recipients = recipients.concat localRecipients
       if recipients.length > 1
         actions.push {
           name: 'reply all'


Remove incorrect commenting

Remove incorrect commenting

--- app/assets/javascripts/darkswarm/services/enterprise_list_modal.js.coffee
+++ app/assets/javascripts/darkswarm/services/enterprise_list_modal.js.coffee
@@ -1,8 +1,7 @@
 Darkswarm.factory "EnterpriseListModal", ($modal, $rootScope, $http, EnterpriseModal)->
-  # Build a modal popup for an enterprise.
   new class EnterpriseListModal
     open: (enterprises)->
-      scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
+      scope = $rootScope.$new(true)
       scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1
       scope.enterprises = enterprises
       scope.openModal = EnterpriseModal.open


fix(delete): check if id or key is provided for deletion

--- src/coffee/services/base.coffee
+++ src/coffee/services/base.coffee
@@ -492,6 +492,11 @@
     # TODO: describe which endpoints support this?
     unless version
       throw new Error "Version is required for deleting a resource (endpoint: #{@_currentEndpoint})"
+    if @constructor.supportsByKey is true
+      unless (@_params.key or @_params.id)
+        throw new Error "Missing resource id. You can set it by chaining '.byId(ID)' or '.byKey(KEY)'" unless @_params.key or @_params.id
+    else
+      throw new Error "Missing resource id. You can set it by chaining '.byId(ID)'" unless @_params.id

     endpoint = "#{@_currentEndpoint}?version=#{version}"
     @_delete(endpoint)


Using React in Atom

Using React in Atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -10,7 +10,7 @@
   'showIndentGuide': true
   'showInvisibles': true
   'lineHeight': 1.5
-  'fontSize': 14
+  'fontSize': 13
 'core':
   'themes': [
     'atom-dark-ui'
@@ -36,6 +36,7 @@
     'feedback'
     'sublime-tabs'
   ]
+  'useReactEditor': true
 'autosave':
   'enabled': true
 'spell-check':


update atom

update atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -18,7 +18,7 @@
       "atom-light-ui"
       "solarized-light-syntax"
     ]
-    hideGitIgnoredFiles: true
+    hideGitIgnoredFiles: false
     disabledPackages: [
       "background-tips"
       "exception-reporting"


Updated zentabs setting

Updated zentabs setting

--- atom/symlink.config.cson
+++ atom/symlink.config.cson
@@ -49,7 +49,6 @@
   welcome:
     showOnStartup: false
   zentabs:
-    neverCloseNew: true
     neverCloseUnsaved: true
 ".coffee.jsx.source":
   editor:


Allow dragging images without selecting them first

--- src/trix/input.coffee
+++ src/trix/input.coffee
@@ -33,7 +33,12 @@
       event.preventDefault()

   dragstart: (event) =>
-    @draggedRange = @responder?.getSelectedRange()
+    target = event.target
+    if range = @responder?.getSelectedRange()
+      @draggedRange = range
+    else if Trix.DOM.within(@element, target) and target.trixPosition?
+      position = target.trixPosition
+      @draggedRange = [position, position + 1]

   dragend: (event) =>
     delete @draggedRange


styleguide: Space before arrow

styleguide: Space before arrow

--- client/app/lib/providers/computehelpers.coffee
+++ client/app/lib/providers/computehelpers.coffee
@@ -25,7 +25,7 @@
    *  destroyed.
    * @returns {Promise}
   ###
-  @destroyExistingResources = (callback = kd.noop, waitForCompleteDeletion = no)->
+  @destroyExistingResources = (callback = kd.noop, waitForCompleteDeletion = no) ->
     destroyPromises = []

     # Creating a promise here, because @destroyExistingMachines does
@@ -49,7 +49,7 @@
     return result

-  @destroyExistingMachines = (callback = kd.noop, waitForCompleteDeletion = no)->
+  @destroyExistingMachines = (callback = kd.noop, waitForCompleteDeletion = no) ->

     { computeController } = kd.singletons


video/model: add an action to join video

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -635,6 +635,12 @@

   ###*
+   * Action to join to video session again.
+  ###
+  join: -> @init()
+
+
+  ###*
    * Action for muting a participant. Sends the signal, the rest will be
    * handled by the `signal:mute` handler.
    *


video/model: add speaker state and its actions

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -14,6 +14,7 @@
   defaultState:
     audio               : off
     video               : off
+    speaker             : on
     publishing          : off
     active              : no
     connected           : no
@@ -201,6 +202,17 @@

   ###*
+   * Action to mute/unmute speakers.
+   *
+   * @param {boolean} speakerState
+  ###
+  requestSpeakerStateChange: (speakerState) ->
+    return  if speakerState is @state.speaker
+
+    @setSpeakerState speakerState
+
+
+  ###*
    * Registers callbacks for service events.
    *
    * @param {OT.Session} session
@@ -643,6 +655,24 @@
     @emit 'VideoPublishStateChanged', state

+  ###*
+   * Set speaker state to given state. If `off` set all subscribers' audio
+   * volume to 0, if `on` set all to 100.
+   *
+   * @param {boolean} state
+  ###
+  setSpeakerState: (state) ->
+
+    volume = if state then 100 else 0
+
+    Object.keys(@subscribers).forEach (key) =>
+      subscriber = @subscribers[key].videoData
+      subscriber.setAudioVolume volume
+
+    @setState { speaker: state }
+    @emit 'SpeakerStateChanged', state
+
+
   ensurePublishing: (options, callback) ->

     @setActive()


video: model streamCreated check for connected state

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -103,7 +103,7 @@
   bindSessionEvents: (session) ->

     session.on 'streamCreated', (event) =>
-      return  if @state.publishing is off
+      return  if @state.connectedToSession is no

       options.height     or= "100%"
       options.width      or= "100%"


router: develop slug with app names

router: develop slug with app names

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -198,6 +198,9 @@
     createSectionHandler = (sec)=>
       ({params:{name}, query})=> @openSection sec, name, query

+    createSectionHandlerForDevelop = (sec)=>
+      ({params:{name, slug}, query})=> @openSection slug, name, query
+
     createContentHandler       = @bound 'createContentDisplayHandler'
     createStaticContentHandler = @bound 'createStaticContentDisplayHandler'

@@ -227,6 +230,7 @@
       '/:name?/Members'                 : createSectionHandler 'Members'
       '/:name?/Topics'                  : createSectionHandler 'Topics'
       '/:name?/Develop'                 : createSectionHandler 'StartTab'
+      '/:name?/Develop/:slug'           : createSectionHandlerForDevelop 'Develop'
       '/:name?/Apps'                    : createSectionHandler 'Apps'
       '/:name?/Account'                 : createSectionHandler 'Account'
       '/:name?/Demos'                   : createSectionHandler 'Demos'


Extract method _start_new_signature

Extract method _start_new_signature

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -102,7 +102,7 @@
   #
   expects: (method_name) ->
     _check_expects_usage(method_name)
-    @signatures.unshift( new MethodSignature(method_name) )     # .unshift pushes to front of array
+    _start_new_signature(@, method_name)
     @[ method_name ] ?= _build_mocked_method(@, method_name)
     _set_state(@, "expects")
     @
@@ -205,6 +205,9 @@
     errors += "'#{signature.method_name}(#{signature.args})' was never called\n"
   errors

+_start_new_signature = (mock, method_name) ->
+    mock.signatures.unshift( new MethodSignature(method_name) )     # .unshift pushes to front of array
+
 _set_args_for_current_signature = (mock, args) ->
   _current_signature(mock).args = args


Rename Expectation.called to Expectation._called

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -88,7 +88,7 @@
   throw new Error( errors ) unless errors == ""

 build_all_errors = ->
-  (build_not_called_error(expectation) for expectation in all_expectations when not expectation.called).join("")
+  (build_not_called_error(expectation) for expectation in all_expectations when not expectation._called).join("")

 build_not_called_error = (expectation) ->
   "'#{expectation._method_name}(#{expectation._args})' was never called\n"
@@ -102,7 +102,7 @@
     expectation = find_expectation(@, method_name, args...)
     throw_unknown_expectation("#{method_name}(#{args})") unless expectation?
     check_for_duplicate_expectations()
-    expectation.called = yes
+    expectation._called = yes
     throw expectation._throws if expectation._throws?
     expectation._returns

@@ -137,7 +137,7 @@
     @_args = []
     @_returns = undefined
     @_throws = undefined
-    @called = false
+    @_called = false
     @_install_mock_method()
     all_expectations.push(@)


smoothing spikes on price chart

smoothing spikes on price chart

--- app/js/services/market_service.coffee
+++ app/js/services/market_service.coffee
@@ -512,10 +512,16 @@
                 highest_bid = prc(t.highest_bid)
                 h = if lowest_ask > highest_bid then lowest_ask else highest_bid
                 l = if lowest_ask < highest_bid then lowest_ask else highest_bid
+
                 h = o if o > h
                 h = c if c > h
                 l = o if o < l
                 l = c if c < l
+
+                oc_avg = (o + c) / 2.0
+                h = 1.5 * Math.max(o,c) if h/oc_avg > 2.0
+                l = 0.66 * Math.min(o,c) if oc_avg/l > 2.0
+
                 ohlc_data.push [time, o, h, l, c]
                 volume_data.push [time, t.volume / market.quantity_asset.precision]


disabled broken test for now

disabled broken test for now

--- coffee/test/shells/videolink.shell.spec.coffee
+++ coffee/test/shells/videolink.shell.spec.coffee
@@ -150,7 +150,8 @@
             expect(triv.values().start).toBe t.start
             expect(triv.values().end).toBe t.end

-        it 'should update model values when timeRangeInputView changes', ->
+        # TODO(@tenedor)
+        xit 'should update model values when timeRangeInputView changes', ->
           rv = new RemixView viewOptions()
           rv.render()


info hiding

info hiding

--- src/util/index.coffee
+++ src/util/index.coffee
@@ -105,4 +105,4 @@
     MIXER.mix(@, arguments...)

-module.exports = {UTILS, get_protomixer, get_classmixer}+module.exports = {get_protomixer, get_classmixer}


disabled dashboard for guests and non admins

--- client/landing/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Groups.kdapplication/AppController.coffee
@@ -768,6 +768,10 @@

   createContentDisplay:(group, callback)->

+    unless KD.config.roles? and 'admin' in KD.config.roles
+      routeSlug = if group.slug is 'koding' then '/' else "/#{group.slug}/"
+      return KD.getSingleton('router').handleRoute "#{routeSlug}Activity"
+
     @groupView = groupView = new GroupView
       cssClass : "group-content-display"
       delegate : @getView()


added render line to allow programattic change of tabs (#6920)

--- bokehjs/src/coffee/models/widgets/tabs.coffee
+++ bokehjs/src/coffee/models/widgets/tabs.coffee
@@ -9,6 +9,7 @@
   connect_signals: () ->
     super()
     @connect(@model.properties.tabs.change, () => @rebuild_child_views())
+    @connect(@model.properties.active.change, () => @render())

   render: () ->
     super()


use property set_value correctly

use property set_value correctly

--- bokehjs/src/coffee/renderer/guide/axis.coffee
+++ bokehjs/src/coffee/renderer/guide/axis.coffee
@@ -516,7 +516,7 @@

     labels = @get('formatter').format(coords[dim])

-    view.major_label_props.set(ctx, view)
+    view.major_label_props.set_value(ctx)

     if _.isString(orient)
       hscale = 1
@@ -556,7 +556,7 @@
     orient = 'parallel'
     ctx = view.plot_view.canvas_view.ctx

-    view.axis_label_props.set(ctx, view)
+    view.axis_label_props.set_value(ctx)

     angle = Math.abs(_angle_lookup[side][orient])
     c = Math.cos(angle)
@@ -564,7 +564,7 @@

     if @get('axis_label')
       extent += @get('axis_label_standoff')
-      view.axis_label_props.set(ctx, view)
+      view.axis_label_props.set_value(ctx)
       w = ctx.measureText(@get('axis_label')).width * 1.1
       h = ctx.measureText(@get('axis_label')).ascent * 0.9
       if side == "above" or side == "below"


Количество изображений можно узнать проще

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -290,7 +290,7 @@
    Создание панели для тумбнейлов
   ###
   createThumbnails: ->
-    return @ if not @options.thumbnails or not @current or @images.length <= 1
+    return @ if not @options.thumbnails or not @current or @length <= 1

     _this   = @
     current = @images[@current]


added a test for ravel(,)

added a test for ravel(,)

--- src/vocabulary.coffee
+++ src/vocabulary.coffee
@@ -805,6 +805,8 @@
   withShape sr, r

 # Ravel (`,`)
+#
+#     ,2 3 4⍴'abcdefghijklmnopqrstuvwx' ⍝ returns 'abcdefghijklmnopqrstuvwx'
 monadic ',', 'Ravel', (a) -> array(a)[0...]

 # Catenate (`,`)


Fix bug

Fix bug

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -142,9 +142,9 @@
   else if questGoals[id].resetInterval is resetInterval
     q.count = 0
     for own k, v of questGoals[id] when typeof v is 'object' and v isnt null
-      init = 0 unless Number.isInteger(v.init)
-      q[k].count = init
-      q.count += init
+      v.init = 0 unless Number.isInteger(v.init)
+      q[k].count = v.init
+      q.count += v.init
 resetQuestRecordDaily = resetQuestRecord.bind(null, [2, 4, 5], 1)
 resetQuestRecordWeekly = resetQuestRecord.bind(null, [3], 2)
 resetQuestRecordMonthly = resetQuestRecord.bind(null, [6], 3)


Missing .ops when passing deltas from quill

--- lib/editors.coffee
+++ lib/editors.coffee
@@ -55,7 +55,7 @@
   observeLocalText: (backend) -> @locker.try backend, (backend) =>
     @editor.on "text-change", (deltas, source) ->
       # call the backend with deltas
-      backend deltas
+      backend deltas.ops

   observeLocalCursor: (backend) -> @locker.try backend, (backend) =>
     @editor.on "selection-change", (range, source) ->


fix for #1065 where feedback should be able to be changed not just also be set to false

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -66,7 +66,7 @@
     if @_local[planId]?.type is PLAN_TYPES.HOMEWORK or @_changed[planId]?.type is PLAN_TYPES.HOMEWORK
       @_changed[planId] ?= {}
       # need to default final posting json's is feedback immediate to false
-      @_changed[planId].is_feedback_immediate = false
+      @_changed[planId].is_feedback_immediate ?= false
       @_local[planId].settings.exercise_ids ?= []
       @_local[planId].settings.exercises_count_dynamic ?= TUTOR_SELECTIONS.default


webapp/primus: coffeescript needs and explicit process exit (that is new)

--- src/webapp-lib/primus/update_primus.coffee
+++ src/webapp-lib/primus/update_primus.coffee
@@ -15,6 +15,8 @@

     fs.writeFileSync('primus-engine.js', primus.library())

+    process.exit()
+

 program.usage('[options]').parse(process.argv)


Expand URLs before displaying them

Expand URLs before displaying them

--- src/scripts/tweet-content.coffee
+++ src/scripts/tweet-content.coffee
@@ -42,4 +42,12 @@
         console.log err
         return

-      msg.send "@#{tweet.user.screen_name}: #{tweet.text}"
+      tweet_text = tweet.text
+      if tweet.entities.urls?
+        for url in tweet.entities.urls
+          tweet_text = tweet_text.replace(url.url, url.expanded_url)
+      if tweet.entities.media?
+        for media in tweet.entities.media
+          tweet_text = tweet_text.replace(media.url, media.expanded_url)
+
+      msg.send "@#{tweet.user.screen_name}: #{tweet_text}"


Fix #77

Fix #77

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -58,7 +58,7 @@
     pths = executable.split ','
     for pth in pths
       pth = do pth.trim
-      if pth.search(path.sep) == -1
+      if pth.split(path.sep) == 1
         p = where pth
         if p then return [p, null] else continue
       pth = homeDirSubstitution pth


Data can be null in ajax request

Data can be null in ajax request

--- assets/scripts/lib/travis/ajax.coffee
+++ assets/scripts/lib/travis/ajax.coffee
@@ -33,13 +33,13 @@

     success = options.success || (->)
     options.success = (data) =>
-      Travis.lookup('controller:flash').loadFlashes(data.flash) if data.flash
+      Travis.lookup('controller:flash').loadFlashes(data.flash) if data?.flash
       delete data.flash if data?
       success.apply(this, arguments)

     error = options.error || (->)
     options.error = (data) =>
-      Travis.lookup('controller:flash').pushObject(data.flash) if data.flash
+      Travis.lookup('controller:flash').pushObject(data.flash) if data?.flash
       delete data.flash if data?
       error.apply(this, arguments)


project: test mode not loading ts-node

project: test mode not loading ts-node

--- src/smc-project/local_hub.coffee
+++ src/smc-project/local_hub.coffee
@@ -14,7 +14,21 @@
 doing a lot of IO-based things is what Node.JS is good at.
 ###

-require('ts-node').register(project:"#{__dirname}/tsconfig.json", cacheDirectory:'/tmp')
+program = require('commander')          # command line arguments -- https://github.com/visionmedia/commander.js/
+
+program.usage('[?] [options]')
+    .option('--tcp_port <n>', 'TCP server port to listen on (default: 0 = os assigned)', ((n)->parseInt(n)), 0)
+    .option('--raw_port <n>', 'RAW server port to listen on (default: 0 = os assigned)', ((n)->parseInt(n)), 0)
+    .option('--console_port <n>', 'port to find console server on (optional; uses port file if not given); if this is set we assume some other system is managing the console server and do not try to start it -- just assume it is listening on this port always', ((n)->parseInt(n)), 0)
+    .option('--kucalc', "Running in the kucalc environment")
+    .option('--test_firewall', 'Abort and exit w/ code 99 if internal GCE information is accessible')
+    .option('--test', "Start up everything, then immediately exit.  Used as a test and to ensure coffeescript and typescript is compiled/cache")
+    .parse(process.argv)
+
+if program.kucalc and not program.test
+    console.warn("ts-node is not enabled!")
+else
+    require('ts-node').register(project:"#{__dirname}/tsconfig.json", cacheDirectory:'/tmp')

 path    = require('path')
 async   = require('async')
@@ -24,7 +38,6 @@
 uuid    = require('uuid')
 winston = require('winston')
 request = require('request')
-program = require('commander')          # command line arguments -- https://github.com/visionmedia/commander.js/

 init_gitconfig = require('./gitconfig').init_gitconfig

@@ -373,14 +386,8 @@
         # we report and ignore errors
         winston.debug("ERROR set_extra_env -- cannot process '#{process.env.COCALC_EXTRA_ENV}' -- #{err}")

-program.usage('[?] [options]')
-    .option('--tcp_port <n>', 'TCP server port to listen on (default: 0 = os assigned)', ((n)->parseInt(n)), 0)
-    .option('--raw_port <n>', 'RAW server port to listen on (default: 0 = os assigned)', ((n)->parseInt(n)), 0)
-    .option('--console_port <n>', 'port to find console server on (optional; uses port file if not given); if this is set we assume some other system is managing the console server and do not try to start it -- just assume it is listening on this port always', ((n)->parseInt(n)), 0)
-    .option('--kucalc', "Running in the kucalc environment")
-    .option('--test_firewall', 'Abort and exit w/ code 99 if internal GCE information is accessible')
-    .option('--test', "Start up everything, then immediately exit.  Used as a test and to ensure coffeescript and typescript is compiled/cache")
-    .parse(process.argv)
+
+# Final steps: kucalc specific setup, environment variable cleanup, and then we issue the "start_server" command …

 if program.kucalc
     winston.debug("running in kucalc")
@@ -402,6 +409,9 @@
     if err
         process.exit(1)
     if program.test
-        winston.debug("Test mode -- now exiting")
-        process.exit(0)
-
+        winston.debug("Test mode -- waiting 5 seconds")
+        setTimeout ->
+            winston.debug("Test mode -- now exiting")
+            process.exit(0)
+        , 5000
+


Fix error when integration body (script) is undefined

--- packages/rocketchat-integrations/server/api/api.coffee
+++ packages/rocketchat-integrations/server/api/api.coffee
@@ -168,7 +168,7 @@
 			return RocketChat.API.v1.failure 'error-running-script'

 	if not @bodyParams?
-		RocketChat.API.v1.failure 'body-empty'
+		return RocketChat.API.v1.failure 'body-empty'

 	@bodyParams.bot =
 		i: @integration._id


test: add test constructor without path

test: add test constructor without path

--- test/load-config-test.coffee
+++ test/load-config-test.coffee
@@ -108,6 +108,12 @@
     it 'should create a new Config object', ->
       result = new loadConfig 'path1', {hi:112}
       result.should.have.property 'path', 'path1'
+      result.should.have.ownProperty 'options'
+      result.options.should.be.deep.equal {hi:112}
+
+    it 'should create a new Config object without path', ->
+      result = new loadConfig {hi:112}
+      result.should.have.property 'path', undefined
       result.should.have.ownProperty 'options'
       result.options.should.be.deep.equal {hi:112}


change to options object

change to options object

--- plugin/browserify.coffee
+++ plugin/browserify.coffee
@@ -51,7 +51,7 @@
     string = getString bundle

     # read the generated source map from the file
-    sourceMap = fs.readFileSync mapFileName, 'utf8'
+    sourceMap = fs.readFileSync mapFileName, encoding:'utf8'
     # leave source map file so it's cached

     # now that we have the compiled result as a string we can add it using CompileStep


* update read-stream test

* update read-stream test

--- test/read-stream-test.coffee
+++ test/read-stream-test.coffee
@@ -4,17 +4,29 @@
 ReadStream      = require '../lib/read-stream'
 consts          = require '../lib/consts'
 Memdown         = require 'memdown-sync'
-
+#LevelDown       = require 'leveldown-sync'

 FILTER_INCLUDED = consts.FILTER_INCLUDED
 FILTER_EXCLUDED = consts.FILTER_EXCLUDED
 FILTER_STOPPED  = consts.FILTER_STOPPED

+fillChar = (c, len=2) ->
+  result = ''
+  len++
+  while len -= 1
+    result += c
+  result
+toFixedInt = (value, digits=2)->
+  result = fillChar 0, digits
+  (result+value).slice(-digits)
+
+
 allData = {}
 for k in [0..99]
-  allData[("00"+k).slice(-2)] = Math.random().toString()
+  allData[toFixedInt(k, 2)] = Math.random().toString()
 initTestDB = ->
   db = Memdown()
+  #db = LevelDown('tempdb')
   db.open()
   for k,v of allData
     db.put(k, v)
@@ -119,6 +131,7 @@
       stream.on "end", ()->
         keys = Object.keys(data)
         assert.equal keys.length, count
+        assert.equal count, 11
         for k,v of data
           assert.ok k % 2 is 1, "key should be odd"
           assert.equal v, allData[k]
@@ -126,9 +139,9 @@
     it "should be next/last", (done)->
       count = 0
       lastKey = null
+      pageCount = 0
       nextPage = (db, aLastKey, aPageSize, cb)->
-        pageData = {}
-        pageCount = 0
+        pageData = []
         ReadStream db,
           next: aLastKey
           limit: aPageSize
@@ -138,14 +151,38 @@
           lastKey = aLastKey
         .on "data", (item)->
           item.key.should.be.gt(aLastKey) if aLastKey
-          pageCount++
+          pageData.push item
         .on "error", (err)->
           done(err)
         .on "end", ()->
-          assert.equal pageCount, aPageSize
-          cb() if cb
-      nextPage db, lastKey, 2, ->
-        lastKey.should.be.equal "01"
-        nextPage db, lastKey, 2, ->
-          lastKey.should.be.equal "03"
-          done()+          pageCount++
+          assert.equal pageData.length, aPageSize if pageCount < 50
+          cb(pageData) if cb
+      runNext = ->
+        if lastKey and pageCount <= 50
+          nextPage db, lastKey, 2, (data)->
+            lastId = (pageCount-1)*2+1
+            lastKey.should.be.equal toFixedInt(lastId,2) if lastKey
+            if data.length
+              data.should.be.deep.equal [
+                {key: toFixedInt(lastId-1), value: allData[toFixedInt(lastId-1)]}
+                {key: toFixedInt(lastId), value: allData[toFixedInt(lastId)]}
+              ]
+            else
+              pageCount.should.be.equal 51
+              should.not.exist lastKey
+            runNext()
+        else
+          pageCount.should.be.equal 51
+          should.not.exist lastKey
+          done()
+      nextPage db, lastKey, 2, (data)->
+        lastId = (pageCount-1)*2+1
+        #console.log "p=",pageCount, toFixedInt(lastId,2), lastKey
+        lastKey.should.be.equal toFixedInt(lastId,2)
+        data.should.be.deep.equal [
+          {key: toFixedInt(lastId-1), value: allData[toFixedInt(lastId-1)]}
+          {key: toFixedInt(lastId), value: allData[toFixedInt(lastId)]}
+        ]
+        runNext()
+


make auth token ttl match our docs

make auth token ttl match our docs

--- src/smc-hub/auth-token.coffee
+++ src/smc-hub/auth-token.coffee
@@ -61,7 +61,7 @@
             opts.database.save_auth_token
                 account_id : opts.user_account_id
                 auth_token : auth_token
-                ttl        : 86400    # ttl in seconds (default: 1 day)
+                ttl        : 12*3600    # ttl in seconds (12 hours)
                 cb         : cb
     ], (err) ->
         opts.cb(err, auth_token)


Always invalidate yardstick measurements when the editor becomes visible

...because content could get reflowed and previous measurements might
become inaccurate. Typically, this could occur when measuring while the
editor is hidden: in that case, the yardstick would always report `0px`
and save that position into the cache. Then, when the editor becomes
visible again, the wrong `0px` value would be returned, thus causing
cursors etc. to be displayed incorrectly.

This was being shadowed by a bug in our measurements cache, but after
fixing it in #12730 it started becoming evident.

--- src/text-editor-component.coffee
+++ src/text-editor-component.coffee
@@ -195,9 +195,10 @@

   becameVisible: ->
     @updatesPaused = true
-    if @invalidateMeasurementsWhenVisible
-      @invalidateMeasurements()
-      @invalidateMeasurementsWhenVisible = false
+    # Always invalidate LinesYardstick measurements when the editor becomes
+    # visible again, because content might have been reflowed and measurements
+    # could be outdated.
+    @invalidateMeasurements()
     @measureScrollbars() if @measureScrollbarsWhenShown
     @sampleFontStyling()
     @sampleBackgroundColors()
@@ -937,11 +938,8 @@
     @invalidateMeasurements()

   invalidateMeasurements: ->
-    if @isVisible()
-      @linesYardstick.invalidateCache()
-      @presenter.measurementsChanged()
-    else
-      @invalidateMeasurementsWhenVisible = true
+    @linesYardstick.invalidateCache()
+    @presenter.measurementsChanged()

   screenPositionForMouseEvent: (event, linesClientRect) ->
     pixelPosition = @pixelPositionForMouseEvent(event, linesClientRect)


JPermissionSet: show more meaningful AccessDenied information

like;

	[JCredential] permission 'update credential' denied for 'gokmen' on 'rakun' group. ip: '127.0.0.1'

--- workers/social/lib/social/models/group/permissionset.coffee
+++ workers/social/lib/social/models/group/permissionset.coffee
@@ -133,6 +133,13 @@
         if 'function' is typeof promise then promise.bind this
         else promise.success.bind this
       failure = promise.failure?.bind this
+
+      module =
+        if 'function' is typeof this then @name
+        else @constructor.name
+
+      permissions = (p.permission for p in advanced).join ', '
+
       JPermissionSet.checkPermission client, advanced, this, rest,
         (err, hasPermission, roles) ->
           client.roles = roles
@@ -143,6 +150,15 @@
           else if failure?
             failure.apply null, args
           else
+
+            try
+              { context: { group }, clientIP, connection } = client
+              { profile: { nickname } } = connection.delegate
+              from = "'#{nickname}' on '#{group}' group. ip: '#{clientIP}'"
+            catch
+              from = "unknown: #{args}"
+
+            console.log \
+              "[#{module}] permission '#{permissions}' denied for #{from}"
+
             callback new KodingError 'Access denied'
-
-


Cache fixes

Cache fixes

--- sync.coffee
+++ sync.coffee
@@ -61,8 +61,8 @@
 module.exports = (model_type, cache) ->
   sync = new AjaxSync(model_type)

-  sync_fn = (method, model, options={}) ->
-    sync['initialize']()
+  sync.fn = (method, model, options={}) -> # save for access by model extensions
+    sync.initialize()

     return module.exports.apply(null, Array::slice.call(arguments, 1)) if method is 'createSync' # create a new sync
     return sync if method is 'sync'
@@ -97,5 +97,5 @@
     ###################################
     sync[method].apply(sync, Array::slice.call(arguments, 1))

-  require('backbone-orm/lib/model_extensions')(model_type, sync_fn) # mixin extensions
-  return if cache then require('backbone-orm/lib/cache_sync')(model_type, sync_fn) else sync_fn+  require('backbone-orm/lib/model_extensions')(model_type) # mixin extensions
+  return if cache or _.isUndefined(cache) then require('backbone-orm/lib/cache_sync')(model_type, sync.fn) else sync.fn


Refactor

Refactor

Some restructuring of the code in preparation for the exercise.

--- src/coffee/app.coffee
+++ src/coffee/app.coffee
@@ -6,14 +6,6 @@
 ctx = canvas.getContext '2d'
 ctx.lineCap = 'round'
 ctx.lineJoin = 'round'
-ctx.fillStyle = 'white'
-
-updateBrush = ->
-  selected = document.getElementsByClassName('selected')[0]
-  color = window.getComputedStyle(selected).backgroundColor
-
-  ctx.lineWidth = size.value
-  ctx.strokeStyle = color

 onMouseDown = (event) ->
   ctx.beginPath()
@@ -32,17 +24,25 @@
   canvas.removeEventListener 'mousemove', onMouseMove
   canvas.removeEventListener 'mouseup', onMouseUp

+updateSize = ->
+  ctx.lineWidth = size.value
+
+updateColor = (element) ->
+  color = window.getComputedStyle(element).backgroundColor
+  ctx.strokeStyle = color
+
+onClearClick = ->
+  ctx.clearRect 0, 0, canvas.width, canvas.height
+
 onColorClick = (event) ->
   c.classList.remove 'selected' for c in colors
   event.target.classList.add 'selected'
-  updateBrush()
+  updateColor event.target

-onClearClick = ->
-  ctx.fillRect 0, 0, canvas.width, canvas.height
-
-updateBrush()
+updateSize()
+updateColor document.getElementsByClassName('selected')[0]

 canvas.addEventListener 'mousedown', onMouseDown
-size.addEventListener 'change', updateBrush
+size.addEventListener 'change', updateSize
 clear.addEventListener 'click', onClearClick
 c.addEventListener 'click', onColorClick for c in colors


Add tests for global configurations

Add tests for global configurations

--- tests/lib/activeroute.coffee
+++ tests/lib/activeroute.coffee
@@ -1,4 +1,39 @@
 makeClientTests = ->
+
+  it 'ActiveRoute.config({caseSensitive: false})', ->
+    expect ActiveRoute.config caseSensitive: false
+      .to.be.undefined
+    expect ActiveRoute.name 'Home'
+      .to.be.true
+    expect ActiveRoute.path '/'
+      .to.be.true
+
+    ActiveRoute.config caseSensitive: true
+
+  it 'ActiveRoute.configure({caseSensitive: false})', ->
+    expect ActiveRoute.configure caseSensitive: false
+      .to.be.undefined
+    expect ActiveRoute.name 'Home'
+      .to.be.true
+    expect ActiveRoute.path '/'
+      .to.be.true
+
+    ActiveRoute.configure caseSensitive: true
+
+  it 'ActiveRoute.config({activeClass: \'is-selected\', disabledClass: \'is-disabled\'})', ->
+    expect ActiveRoute.config
+      activeClass: 'is-selected'
+      disabledClass: 'is-disabled'
+    .to.be.undefined
+
+    expect Blaze._globalHelpers["isActiveRoute"] 'home'
+      .to.be.a.string 'is-selected'
+    expect Blaze._globalHelpers["isNotActiveRoute"] 'notHome'
+      .to.be.a.string 'is-disabled'
+
+    ActiveRoute.config
+      activeClass: 'active'
+      disabledClass: 'disabled'

   it 'ActiveRoute.name(\'home\')', ->
     expect ActiveRoute.name 'home'


fix up font-fixer html

fix up font-fixer html

--- lib/runner.coffee
+++ lib/runner.coffee
@@ -31,7 +31,7 @@
     # contains *r*egular, *b*old, *i*talic and i in b
     fixerProto = Object.create(HTMLElement::)
     fixerProto.createdCallback = ->
-      @innerHTML = "regularbolditalicitalic"
+      @innerHTML = "regularbolditalicitalic"
       return

     fixer = document.registerElement("fonts-fixer",


Eliminate unused argument

Eliminate unused argument

--- src/text-editor-component.coffee
+++ src/text-editor-component.coffee
@@ -403,7 +403,7 @@
       when 3
         @editor.getLastSelection().selectLine()

-    @handleDragUntilMouseUp event, (screenPosition) =>
+    @handleDragUntilMouseUp (screenPosition) =>
       @editor.selectToScreenPosition(screenPosition, true)

   onLineNumberGutterMouseDown: (event) =>
@@ -424,7 +424,7 @@

     @editor.setSelectedBufferRange([[clickedBufferRow, 0], [clickedBufferRow + 1, 0]], preserveFolds: true)

-    @handleDragUntilMouseUp event, (screenPosition) =>
+    @handleDragUntilMouseUp (screenPosition) =>
       dragRow = screenPosition.row
       dragBufferRow = @editor.bufferRowForScreenRow(dragRow)
       if dragBufferRow < clickedBufferRow # dragging up
@@ -440,7 +440,7 @@
     bufferRange = new Range([clickedBufferRow, 0], [clickedBufferRow + 1, 0])
     rowSelection = @editor.addSelectionForBufferRange(bufferRange, preserveFolds: true)

-    @handleDragUntilMouseUp event, (screenPosition) =>
+    @handleDragUntilMouseUp (screenPosition) =>
       dragRow = screenPosition.row
       dragBufferRow = @editor.bufferRowForScreenRow(dragRow)

@@ -466,7 +466,7 @@
     else
       @editor.selectToBufferPosition([clickedBufferRow + 1, 0])

-    @handleDragUntilMouseUp event, (screenPosition) =>
+    @handleDragUntilMouseUp (screenPosition) =>
       dragRow = screenPosition.row
       dragBufferRow = @editor.bufferRowForScreenRow(dragRow)
       if dragRow < tailPosition.row # dragging up
@@ -523,7 +523,7 @@
   onCursorMoved: =>
     @cursorMoved = true

-  handleDragUntilMouseUp: (event, dragHandler) =>
+  handleDragUntilMouseUp: (dragHandler) =>
     dragging = false
     lastMousePosition = {}
     animationLoop = =>


Agent pie: start/end angle pie transition work


fix(run): make retailer option name consistent

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -6,14 +6,14 @@
 ProductTypeGenerator = require './product-type-generator'

 argv = require('optimist')
-  .usage('Usage: $0 --types [CSV] --attributes [CSV] --target [folder] --retailer --zip --zipFileName [name]')
+  .usage('Usage: $0 --types [CSV] --attributes [CSV] --target [folder] --withRetailer --zip --zipFileName [name]')
   .describe('types', 'path to CSV file describing product-type general info')
   .describe('attributes', 'path to CSV file describing product-type attributes info')
   .describe('target', 'target directory for generated product types JSON files')
   .describe('withRetailer', 'whether to generate an extra file for master<->retailer support with a "mastersku" attribute or not')
   .describe('zip', 'whether to zip the target folder or not')
   .describe('zipFileName', 'the zipped file name (without extension)')
-  .default('retailer', false)
+  .default('withRetailer', false)
   .default('zip', false)
   .default('zipFileName', 'generated-product-types')
   .alias('types', 't')


Suppress output in good case.

Suppress output in good case.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -18,4 +18,5 @@
     attachments:
       "input.xml": content
   stockxmlimport.process d, (result) =>
-    console.log result+    if not result.message.status
+      console.log result


Close postgres connection on SIGINT

Close postgres connection on SIGINT

--- storage/lib/db.coffee
+++ storage/lib/db.coffee
@@ -2,6 +2,8 @@
 squel = require 'squel'
 Promise = require 'bluebird'
 Promise.promisifyAll pg
+
+process.on 'SIGINT', -> pg.end()

 module.exports = (options) ->
     migrate = require('./migrate') options


making _id the standard from the creation on .

--- lib/server.coffee
+++ lib/server.coffee
@@ -57,13 +57,13 @@
 			jumpon = 0
 			findinque = (id)->
 				for obj in workque
-					if obj.id is id or obj._id is id
+					if obj._id is id
 						return obj
 				return false
 			findplace = (id)->
 				found = -1
 				for obj,i in workque
-					if obj.id is id or obj._id is id
+					if obj._id is id
 						found = i
 				return found
 			dirtyqueue = 0
@@ -79,7 +79,7 @@
 							when "new"
 								act._status = "tofetch"
 								act._lastchange = ~~((new Date).getTime() / 1000)
-								getDocsCargo.push act.id
+								getDocsCargo.push act._id
 							when "tosend"
 								act._status = "onqueue"
 								act._lastchange = ~~((new Date).getTime() / 1000)
@@ -244,16 +244,17 @@
 							hostJobs[c.node.name].lastseen = ~~((new Date).getTime() / 1000)
 						syncJobs c.node.name, c.jobIds
 						datalog.gauge 'task_processing', c.jobIds.length, [ 'worker:' + c.node.name ] if c.jobIds? and Array.isArray(c.jobIds)
-					if c.id
+					if c.id and findinque(c.id)?
+						jobItem = findinque(c.id)
 						switch c.status
 							when 2 # job taken
-								findinque(c.id)?._status = "working"
-								findinque(c.id)?._takenby = c.node.name if c.node?.name?
-								findinque(c.id)?._lastchange = ~~((new Date).getTime() / 1000)
+								jobItem._status = "working"
+								jobItem._takenby = c.node.name if c.node?.name?
+								jobItem._lastchange = ~~((new Date).getTime() / 1000)
 							when 3 # job finished
 								if c.error
 									# error on the job
-									jobItem = findinque(c.id)
+
 									if jobItem._status is "working" and jobItem._takenby is c.node.name
 										jobItem._status = "errored"
 										jobItem._lastchange = ~~((new Date).getTime() / 1000)
@@ -270,8 +271,8 @@
 											return
 								else
 									# ok done
-									findinque(c.id)?._status = "completed"
-									findinque(c.id)?._lastchange = ~~((new Date).getTime() / 1000)
+									jobItem._status = "completed"
+									jobItem._lastchange = ~~((new Date).getTime() / 1000)
 									datalog.legauge 'task_completed', c.node.name
 					else
 						if c.startup
@@ -392,7 +393,9 @@
 								jobsCounter[0] = getbody.total_rows
 								if getbody.rows and getbody.rows.length > 0
 									for act in getbody.rows
-										if findplace(act.id) is -1
+										act._id = act.id # make job compilant
+										delete act.id
+										if findplace(act._id) is -1
 											act._status = "new"
 											act._lastchange =  ~~((new Date).getTime() / 1000)
 											workque.push act
@@ -550,7 +553,6 @@
 						s_wc.send JSON.stringify(
 							id: c._id
 							status: 2
-							idtype: c.idtype
 							node:
 								name: os.hostname()
 								loadavg: os.loadavg()
@@ -570,7 +572,6 @@
 				s_wc.send JSON.stringify(
 					id: c._id
 					status: 2
-					idtype: c.idtype
 					node:
 						name: os.hostname()
 						loadavg: os.loadavg()
@@ -630,7 +631,6 @@
 					#sending back the status
 					s_wc.send JSON.stringify(
 						id: c._id
-						idtype: c.idtype
 						stdout: stdout
 						error: error
 						status: 3


mashape: lower case header key, only apply rule to /api* routes

--- lib/mashape.coffee
+++ lib/mashape.coffee
@@ -4,7 +4,11 @@
 mashapeCheck = (req, res, next) ->
   console.log 'request headers: ', req.headers
   console.log 'mashape secret: ', MASHAPE_SECRET
-  if (req.headers['X-Mashape-Proxy-Secret'] isnt MASHAPE_SECRET)
+  console.log "req.route: ", req.route
+
+  return next() unless req.route?.path?.match /\/api\/.*/
+
+  if (req.headers['x-mashape-proxy-secret'] isnt MASHAPE_SECRET)
     msg = 'requests must be authorized by mashape.com'
     err = new restify.InvalidHeaderError msg
     return next err


on startup ask for host:port to connect to

don't spawn the interpreter---temporary restriction

--- client/init.coffee
+++ client/init.coffee
@@ -2,14 +2,18 @@
   if window.require? # are we running under node-webkit?
     {spawn} = require 'child_process'
     extend = (a...) -> r = {}; (for x in a then for k, v of x then r[k] = v); r
-    spawn process.env.APL_EXECUTABLE or 'apl', ['+s'], env: extend process.env, RIDE_LISTEN: '0.0.0.0:4502'
+#     spawn process.env.APL_EXECUTABLE or 'apl', ['+s'], env: extend process.env, RIDE_LISTEN: '0.0.0.0:4502'
     class FakeSocket
       emit: (e, a...) -> @other.onevent e: e, data: a
       onevent: ({e, data}) -> (for f in @[e] or [] then f data...); return
       on: (e, f) -> (@[e] ?= []).push f; return
     socket = new FakeSocket; socket1 = new FakeSocket; socket.other = socket1; socket1.other = socket
     server = require './server'
-    setTimeout (-> server.serve socket: socket1, 'host:port': '127.0.0.1:4502'), 3000 # give the interpreter some time to start
+#     setTimeout (-> server.serve socket: socket1), 3000 # give the interpreter some time to start
+    hostPort = prompt 'Connect to:', localStorage?.hostPort or '127.0.0.1:4502'
+    if !hostPort then return close()
+    localStorage?.hostPort = hostPort
+    server.serve socket: socket1, 'host:port': hostPort
   else
     socket = io()


fixes error on editors without the onDidChangeGrammar callback

--- lib/modules.coffee
+++ lib/modules.coffee
@@ -20,7 +20,7 @@
   activePaneChanged: ->
     @grammarChangeSubscription?.dispose()
     ed = atom.workspace.getActivePaneItem()
-    @grammarChangeSubscription = ed?.onDidChangeGrammar => @editorStateChanged()
+    @grammarChangeSubscription = ed?.onDidChangeGrammar? => @editorStateChanged()
     @editorStateChanged()

   # sets or clears the callback on cursor change based on the editor state


:lipstick:

:lipstick:

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -274,15 +274,14 @@
         true

   confirm: (view) =>
-    window.motion = @
     @editor.trigger 'vim-mode:search-complete'

   findOrBeep: (callback)->
-      pos = @findNext(@view.value)
-      if pos?
-        callback(pos)
-      else
-        shell.beep()
+    pos = @findNext(@view.value)
+    if pos?
+      callback(pos)
+    else
+      shell.beep()

   findNext: (term) ->
     regexp = new RegExp(term, 'g')


Initialize is no longer needed

Initialize is no longer needed

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -4,7 +4,6 @@

 class Motion
   constructor: (@editor, @state) ->
-    @initialize?()

   isComplete: -> true
   isRecordable: -> false


Using connection timeout for SQL Browser lookup

Added the usage of the connection timeout option for doing SQL Server Browser look-ups; currently, it's only possible to use the default timeout of 2 seconds.

--- src/connection.coffee
+++ src/connection.coffee
@@ -279,7 +279,7 @@
     else if @config.options.port && @config.options.instanceName
       throw new Error("Port and instanceName are mutually exclusive, but #{@config.options.port} and #{@config.options.instanceName} provided")
     else if @config.options.port
-      if @config.options.port < 0 or @config.options.port > 65536
+      if @config.options.port < 0 or @config.options.port > 65536
         throw new RangeError "Port should be > 0 and < 65536"

   createDebug: ->
@@ -437,12 +437,15 @@
     if (@config.options.port)
       @connectOnPort(@config.options.port)
     else
-      instanceLookup(@config.server, @config.options.instanceName, (message, port) =>
-        if message
-          @emit('connect', ConnectionError(message, 'EINSTLOOKUP'))
-        else
-          @connectOnPort(port)
-      )
+      instanceLookup(
+        @config.server
+        @config.options.instanceName
+        (message, port) =>
+          if message
+            @emit('connect', ConnectionError(message, 'EINSTLOOKUP'))
+          else
+            @connectOnPort(port)
+        @config.options.connectTimeout)

   connectOnPort: (port) ->
     @socket = new Socket({})


Modify fix to allow for backwards compatibility.

The fix for #243 needs to check if the new API call exists and use
the correct call based on the Node version.

- tls.createSecureContext will work for Node versions >= v0.11.14
- crypto.createCredentials will work for Node version < v0.11.14

--- src/connection.coffee
+++ src/connection.coffee
@@ -648,7 +648,10 @@
       payload.toString '  '

   initiateTlsSslHandshake: ->
-    credentials = tls.createSecureContext(@config.options.cryptoCredentialsDetails)
+    credentials = if tls.createSecureContext
+      tls.createSecureContext(@config.options.cryptoCredentialsDetails)
+    else
+      crypto.createCredentials(@config.options.cryptoCredentialsDetails)
     @securePair = tls.createSecurePair(credentials)

     @securePair.on('secure', =>


Strip whitespace from version detection

Strip whitespace from version detection

--- lib/proscli.coffee
+++ lib/proscli.coffee
@@ -94,7 +94,9 @@
           cliVer = {code: 3, extra: "STDOUT:#{eol}#{o}#{eol}#{eol}ERR:#{eol}#{e}"}
           respond cliVer
           return
-        version = /pros, version (.*)/.exec(o)?[1]
+        # coffeelint: disable=max_line_length
+        version = /pros, version \bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b/.exec(o)?[1]
+        # coffeelint: enable=max_line_length
         if version is undefined
           # try again one more time, just in case
           @execute cmd: ['pros', '--version'], nosb: nosb, cb: (c, o) ->
@@ -103,7 +105,9 @@
               cliVer = {code: 3, extra: extra: "STDOUT:#{eol}#{o}#{eol}#{eol}ERR:#{eol}#{e}"}
               respond cliVer
               return
-            version = /pros, version(.*)/.exec(o)?[1]
+            # coffeelint: disable=max_line_length
+            version = /pros, version \bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b/.exec(o)?[1]
+            # coffeelint: enable=max_line_length
             if !version or semver.lt version, minVersion
               # console.log o
               cliVer = {code: 1, extra: "v#{version} does not meet v#{minVersion}", version: version}


add test on res value in recoverDocs

add test on res value in recoverDocs

--- lib/request.coffee
+++ lib/request.coffee
@@ -69,7 +69,7 @@
 ## @callback {function} Continuation to pass control back to when complete.
 ## Callback all design documents from database
 recoverDocs = (res, docs, callback) =>
-    if res.length isnt 0
+    if res and res.length isnt 0
         doc = res.pop()
         db.get doc.id, (err, result) =>
             docs.push(result)


runtime: Fix exception after removing node/edge

Could be we still need to update the edges to subscribe to

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -392,8 +392,9 @@

     # Loop over all edges, unsubscribe
     graph.connections.forEach (conn) ->
-        if conn.src
-            srcId = graph.nodeMap[conn.src.process].id
+        node = graph.nodeMap[conn?.src?.process]
+        if conn.src and node
+            srcId = node.id
             srcComp = graph.processes[conn.src.process].component
             srcPort = runtime.library.outputPort(srcComp, conn.src.port).id
             offset += commandstream.writeCmd buffer, offset,