'bundle' script now creates all bundles except 'qt'

--- bundle.coffee
+++ bundle.coffee
@@ -40,17 +40,17 @@

 stack = new utils.async.Stack

-# stack.add createBundle, null, [platform: 'node', release: true]
+stack.add createBundle, null, [platform: 'node', release: true]
 stack.add createBundle, null, [platform: 'node', release: false]
-# stack.add createBundle, null, [platform: 'browser', release: true]
+stack.add createBundle, null, [platform: 'browser', release: true]
 stack.add createBundle, null, [platform: 'browser', release: false]
-# stack.add createBundle, null, [platform: 'browser', extras: {game: true}, release: true]
-# stack.add createBundle, null, [platform: 'browser', extras: {game: true}, release: false]
+stack.add createBundle, null, [platform: 'browser', extras: {game: true}, release: true]
+stack.add createBundle, null, [platform: 'browser', extras: {game: true}, release: false]
 # stack.add createBundle, null, [platform: 'qt', release: true]
 # stack.add createBundle, null, [platform: 'qt', release: false]
-# stack.add createBundle, null, [platform: 'android', release: true]
-# stack.add createBundle, null, [platform: 'android', release: false]
-# stack.add createBundle, null, [platform: 'ios', release: true]
-# stack.add createBundle, null, [platform: 'ios', release: false]
+stack.add createBundle, null, [platform: 'android', release: true]
+stack.add createBundle, null, [platform: 'android', release: false]
+stack.add createBundle, null, [platform: 'ios', release: true]
+stack.add createBundle, null, [platform: 'ios', release: false]

 stack.runAll ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -1,6 +1,6 @@
 module "EngineSelector"

-test
+test "engine#"

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -4,7 +4,7 @@
   engine = Engine()

   engine.add
-
+    x:

 test "#find", ->
   engine = Engine()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -14,7 +14,8 @@
     y: 10

   engine.add
-    class: "Awe
+    class: "Awesome"
+    x:

 test "#find", ->
   engine = Engine()


Pass file references as a secondary argument

If the package providing the service needs additional information on the
file, they can't do so without querying the filesystem. For instance, an
author may need a link-icon shown for symlinked files. Without providing
a direct file reference, this becomes much more cumbersome.

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -19,7 +19,7 @@
     @fileName.dataset.name = @file.name
     @fileName.dataset.path = @file.path

-    iconClass = FileIcons.getService().iconClassForPath(@file.path)
+    iconClass = FileIcons.getService().iconClassForPath(@file.path, @file)
     if iconClass
       unless Array.isArray iconClass
         iconClass = iconClass.toString().split(/\s+/g)


tab size changed to 2

tab size changed to 2

--- lib/html2jade.coffee
+++ lib/html2jade.coffee
@@ -1,248 +1,248 @@

 class Parser
-    constructor: (@options = {}) ->
-        @jsdom = require('jsdom')
-
-    parse: (arg, cb) ->
-        if arg?
-            @jsdom.env arg, (errors, window) ->
-                if errors?.length
-                    cb(errors)
-                else
-                    cb(null, window)
+  constructor: (@options = {}) ->
+    @jsdom = require('jsdom')
+
+  parse: (arg, cb) ->
+    if arg?
+      @jsdom.env arg, (errors, window) ->
+        if errors?.length
+          cb(errors)
         else
-            cb('null file')
+          cb(null, window)
+    else
+      cb('null file')

 class Helper
-    constructor: (@options = {}) ->
-        @options.wrapLength ?= 80
-
-    tagHead: (node) ->
-        result = if node.tagName isnt 'DIV' then node.tagName.toLowerCase() else ''
-        if node.id
-            result += '#' + node.id
-        if node.hasAttribute('class')
-            classes = node.getAttribute('class').split(/\s+/).filter (item) ->
-                item? and item.trim().length > 0
-            result += '.' + classes.join('.')
-        result = 'div' if result.length is 0
-        result
-
-    tagAttr: (node) ->
-        attrs = node.attributes
-        if attrs.length is 0
-            ''
+  constructor: (@options = {}) ->
+    @options.wrapLength ?= 80
+
+  tagHead: (node) ->
+    result = if node.tagName isnt 'DIV' then node.tagName.toLowerCase() else ''
+    if node.id
+      result += '#' + node.id
+    if node.hasAttribute('class')
+      classes = node.getAttribute('class').split(/\s+/).filter (item) ->
+        item? and item.trim().length > 0
+      result += '.' + classes.join('.')
+    result = 'div' if result.length is 0
+    result
+
+  tagAttr: (node) ->
+    attrs = node.attributes
+    if attrs.length is 0
+      ''
+    else
+      result = []
+      for attr in attrs
+        nodeName = attr.nodeName
+        if nodeName isnt 'id' and nodeName isnt 'class' and typeof attr.nodeValue?
+          result.push attr.nodeName + '=\'' + attr.nodeValue.replace(/'/g, '\\\'') + '\''
+      if result.length > 0
+        '(' + result.join(', ') + ')'
+      else
+        ''
+
+  tagText: (node) ->
+    if node.firstChild?.nodeType isnt 3
+      null
+    else if node.firstChild isnt node.lastChild
+      null
+    else
+      data = node.firstChild.data
+      if data.length > @options.wrapLength or data.match(/\r|\n/)
+        null
+      else
+        data
+
+  forEachChild: (parent, cb) ->
+    if parent
+      child = parent.firstChild
+      while child
+        cb(child)
+        child = child.nextSibling
+
+  writeTextContent: (node, output, pipe = true, trim = true, wrap = true) ->
+    output.enter()
+    this.forEachChild node, (child) =>
+      this.writeText child, output, pipe, trim, wrap
+    output.leave()
+
+  writeText: (node, output, pipe = true, trim = true, wrap = true) ->
+    if node.nodeType is 3
+      data = node.data or ''
+      if data.length > 0
+        lines = data.split(/\r|\n/)
+        lines.forEach (line) =>
+          this.writeTextLine line, output, pipe, trim, wrap
+
+  writeTextLine: (line, output, pipe = true, trim = true, wrap = true) ->
+    prefix = if pipe then '| ' else ''
+    if trim
+      line = if line then line.trim() else ''
+    if line and line.length > 0
+      if not wrap or line.length <= @options.wrapLength
+        output.writeln prefix + line
+      else
+        lines = this.breakLine line
+        if lines.length is 1
+          output.writeln prefix + line
         else
-            result = []
-            for attr in attrs
-                nodeName = attr.nodeName
-                if nodeName isnt 'id' and nodeName isnt 'class' and typeof attr.nodeValue?
-                    result.push attr.nodeName + '=\'' + attr.nodeValue.replace(/'/g, '\\\'') + '\''
-            if result.length > 0
-                '(' + result.join(', ') + ')'
-            else
-                ''
-
-    tagText: (node) ->
-        if node.firstChild?.nodeType isnt 3
-            null
-        else if node.firstChild isnt node.lastChild
-            null
+          lines.forEach (line) =>
+            this.writeTextLine line, output, pipe, trim, wrap
+
+  breakLine: (line) ->
+    if line and line.length > 0
+      lines = []
+      words = line.split(/\s+/)
+      line = ''
+      while words.length
+        word = words.shift()
+        if line.length + word.length > @options.wrapLength
+          lines.push line
+          line = word
+        else if line.length
+          line += ' ' + word
         else
-            data = node.firstChild.data
-            if data.length > @options.wrapLength or data.match(/\r|\n/)
-                null
-            else
-                data
-
-    forEachChild: (parent, cb) ->
-        if parent
-            child = parent.firstChild
-            while child
-                cb(child)
-                child = child.nextSibling
-
-    writeTextContent: (node, output, pipe = true, trim = true, wrap = true) ->
-        output.enter()
-        this.forEachChild node, (child) =>
-            this.writeText child, output, pipe, trim, wrap
-        output.leave()
-
-    writeText: (node, output, pipe = true, trim = true, wrap = true) ->
-        if node.nodeType is 3
-            data = node.data or ''
-            if data.length > 0
-                lines = data.split(/\r|\n/)
-                lines.forEach (line) =>
-                    this.writeTextLine line, output, pipe, trim, wrap
-
-    writeTextLine: (line, output, pipe = true, trim = true, wrap = true) ->
-        prefix = if pipe then '| ' else ''
-        if trim
-            line = if line then line.trim() else ''
-        if line and line.length > 0
-            if not wrap or line.length <= @options.wrapLength
-                output.writeln prefix + line
-            else
-                lines = this.breakLine line
-                if lines.length is 1
-                    output.writeln prefix + line
-                else
-                    lines.forEach (line) =>
-                        this.writeTextLine line, output, pipe, trim, wrap
-
-    breakLine: (line) ->
-        if line and line.length > 0
-            lines = []
-            words = line.split(/\s+/)
-            line = ''
-            while words.length
-                word = words.shift()
-                if line.length + word.length > @options.wrapLength
-                    lines.push line
-                    line = word
-                else if line.length
-                    line += ' ' + word
-                else
-                    line = word
-            if line.length
-                lines.push line
-            lines
-        else
-            []
+          line = word
+      if line.length
+        lines.push line
+      lines
+    else
+      []

 publicIdDocTypeNames =
-    "-//W3C//DTD XHTML 1.0 Transitional//EN":   "transitional"
-    "-//W3C//DTD XHTML 1.0 Strict//EN":         "strict"
-    "-//W3C//DTD XHTML 1.0 Frameset//EN":       "frameset"
-    "-//W3C//DTD XHTML 1.1//EN":                "1.1"
-    "-//W3C//DTD XHTML Basic 1.1//EN":          "basic"
-    "-//WAPFORUM//DTD XHTML Mobile 1.2//EN":    "mobile"
-
+  "-//W3C//DTD XHTML 1.0 Transitional//EN": "transitional"
+  "-//W3C//DTD XHTML 1.0 Strict//EN":     "strict"
+  "-//W3C//DTD XHTML 1.0 Frameset//EN":   "frameset"
+  "-//W3C//DTD XHTML 1.1//EN":        "1.1"
+  "-//W3C//DTD XHTML Basic 1.1//EN":      "basic"
+  "-//WAPFORUM//DTD XHTML Mobile 1.2//EN":  "mobile"
+
 systemIdDocTypeNames =
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd":          "transitional"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd":                "strict"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd":              "frameset"
-    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd":                     "1.1"
-    "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd":               "basic"
-    "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd":    "mobile"
-
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd":      "transitional"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd":        "strict"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd":        "frameset"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd":           "1.1"
+  "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd":       "basic"
+  "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd":  "mobile"
+
 class Converter
-    constructor: (@options = {}) ->
-        @helper = @options.helper ?= new Helper(@options)
-
-    document: (document, output) ->
-        if document.doctype?
-            doctype = document.doctype
-            docTypeName = undefined
-            publicId = doctype.publicId
-            systemId = doctype.systemId
-            if publicId? and publicIdDocTypeNames[publicId]?
-                docTypeName = publicIdDocTypeNames[publicId]
-            else if systemId? and systemIdDocTypeNames[systemId]?
-                docTypeName = systemIdDocTypeNames[systemId]?
-            else if doctype.name? and doctype.name.toLowerCase() is 'html'
-                docTypeName = '5'
-            if docTypeName?
-                output.writeln '!!! ' + docTypeName
-
-        this.element document.documentElement, output
-
-    element: (node, output) ->
-        tagName = node.tagName.toLowerCase()
-        tagHead = @helper.tagHead node
-        tagAttr = @helper.tagAttr node
-        tagText = @helper.tagText node
-        if ['script', 'style'].indexOf(tagName) isnt -1
-            output.writeln tagHead + tagAttr
-            @helper.writeTextContent node, output, false, false, false
-        else if ['pre'].indexOf(tagName) isnt -1
-            # HACK: workaround jade's wonky PRE handling
-            output.writeln tagHead + tagAttr + '.'
-            output.enter()
-            firstline = true
-            @helper.forEachChild node, (child) =>
-                if child.nodeType is 3
-                    data = child.data
-                    if data? and data.length > 0
-                        if firstline
-                            # suckup starting linefeed if any
-                            if data.search(/\r\n|\r|\n/) is 0
-                                data = data.replace(/\r\n|\r|\n/, '')
-                            data = '\\n' + data
-                            firstline = false
-                        data = data.replace /\t/g, '\\t'
-                        data = data.replace /\r\n|\r|\n/g, '\n' + output.indents
-                        output.write data
-            output.writeln()
-            output.leave()
-        else if tagText
-            output.writeln tagHead + tagAttr + ' ' + tagText
-        else
-            output.writeln tagHead + tagAttr
-            this.children node, output
-
-        #if tagName is 'SCRIPT'
-
-    children: (parent, output) ->
-        output.enter()
-        @helper.forEachChild parent, (child) =>
-            nodeType = child.nodeType
-            if nodeType is 1 # element
-                this.element child, output
-            else if nodeType is 3 # text
-                this.text child, output
-            else if nodeType is 8 # comment
-                this.comment child, output
-            else
-                output.writeln '*** nodeType: ' + nodeType
-        output.leave()
-
-    text: (node, output) ->
-        node.normalize()
-        @helper.writeText node, output
-
-    comment: (node, output) ->
-        condition = node.data.match /\s*\[(if\s+[^\]]+)\]/
-        if condition
-            output.writeln '/' + condition[1]
-            this.conditional node, output
-        else
-            output.writeln '//' + node.data
-
-    conditional: (node, output) ->
-        #console.log('******* ' + require('util').inspect(node))
-        data = node._text #.replace(node.data, '').replace('<![endif]', '')
-        #console.log(require('util').inspect(data))
-        data = data.replace(/\s*\[if\s+[^\]]+\]>\s*/, '')
-        data = data.replace('<![endif]', '')
-        output.enter()
-        parser = new Parser()
-        parser.parse data, (errors, window) =>
-            this.children window.document.body, output
-        output.leave()
+  constructor: (@options = {}) ->
+    @helper = @options.helper ?= new Helper(@options)
+
+  document: (document, output) ->
+    if document.doctype?
+      doctype = document.doctype
+      docTypeName = undefined
+      publicId = doctype.publicId
+      systemId = doctype.systemId
+      if publicId? and publicIdDocTypeNames[publicId]?
+        docTypeName = publicIdDocTypeNames[publicId]
+      else if systemId? and systemIdDocTypeNames[systemId]?
+        docTypeName = systemIdDocTypeNames[systemId]?
+      else if doctype.name? and doctype.name.toLowerCase() is 'html'
+        docTypeName = '5'
+      if docTypeName?
+        output.writeln '!!! ' + docTypeName
+
+    this.element document.documentElement, output
+
+  element: (node, output) ->
+    tagName = node.tagName.toLowerCase()
+    tagHead = @helper.tagHead node
+    tagAttr = @helper.tagAttr node
+    tagText = @helper.tagText node
+    if ['script', 'style'].indexOf(tagName) isnt -1
+      output.writeln tagHead + tagAttr
+      @helper.writeTextContent node, output, false, false, false
+    else if ['pre'].indexOf(tagName) isnt -1
+      # HACK: workaround jade's wonky PRE handling
+      output.writeln tagHead + tagAttr + '.'
+      output.enter()
+      firstline = true
+      @helper.forEachChild node, (child) =>
+        if child.nodeType is 3
+          data = child.data
+          if data? and data.length > 0
+            if firstline
+              # suckup starting linefeed if any
+              if data.search(/\r\n|\r|\n/) is 0
+                data = data.replace(/\r\n|\r|\n/, '')
+              data = '\\n' + data
+              firstline = false
+            data = data.replace /\t/g, '\\t'
+            data = data.replace /\r\n|\r|\n/g, '\n' + output.indents
+            output.write data
+      output.writeln()
+      output.leave()
+    else if tagText
+      output.writeln tagHead + tagAttr + ' ' + tagText
+    else
+      output.writeln tagHead + tagAttr
+      this.children node, output
+
+    #if tagName is 'SCRIPT'
+
+  children: (parent, output) ->
+    output.enter()
+    @helper.forEachChild parent, (child) =>
+      nodeType = child.nodeType
+      if nodeType is 1 # element
+        this.element child, output
+      else if nodeType is 3 # text
+        this.text child, output
+      else if nodeType is 8 # comment
+        this.comment child, output
+      else
+        output.writeln '*** nodeType: ' + nodeType
+    output.leave()
+
+  text: (node, output) ->
+    node.normalize()
+    @helper.writeText node, output
+
+  comment: (node, output) ->
+    condition = node.data.match /\s*\[(if\s+[^\]]+)\]/
+    if condition
+      output.writeln '/' + condition[1]
+      this.conditional node, output
+    else
+      output.writeln '//' + node.data
+
+  conditional: (node, output) ->
+    #console.log('******* ' + require('util').inspect(node))
+    data = node._text #.replace(node.data, '').replace('<![endif]', '')
+    #console.log(require('util').inspect(data))
+    data = data.replace(/\s*\[if\s+[^\]]+\]>\s*/, '')
+    data = data.replace('<![endif]', '')
+    output.enter()
+    parser = new Parser()
+    parser.parse data, (errors, window) =>
+      this.children window.document.body, output
+    output.leave()

 class Output
-    constructor: (@stream) ->
-        @indents = ''
-
-    enter: -> @indents += '  '
-    leave: -> @indents = @indents.substring(2)
-
-    write: (data, indent=true) ->
-        data ?= ''
-        if indent
-            @stream.write @indents + data
-        else
-            @stream.write data
-
-    writeln: (data, indent=true) ->
-        data ?= ''
-        if indent
-            @stream.write @indents + data + '\n'
-        else
-            @stream.write data + '\n'
+  constructor: (@stream) ->
+    @indents = ''
+
+  enter: -> @indents += '  '
+  leave: -> @indents = @indents.substring(2)
+
+  write: (data, indent=true) ->
+    data ?= ''
+    if indent
+      @stream.write @indents + data
+    else
+      @stream.write data
+
+  writeln: (data, indent=true) ->
+    data ?= ''
+    if indent
+      @stream.write @indents + data + '\n'
+    else
+      @stream.write data + '\n'

 exports.Parser = Parser
@@ -252,15 +252,15 @@

 # simple conversion
 exports.convert = (input, output, options) ->
-    options ?= {}
-    # specify parser and converter to override default instance
-    options.parser ?= new Parser(options)
-    options.parser.parse input, (errors, window) ->
-        if errors?.length
-            errors
-        else
-            output ?= new Output(process.stdout)
-            options.converter ?= new Converter(options)
-            options.converter.document window.document, output
-            null
-
+  options ?= {}
+  # specify parser and converter to override default instance
+  options.parser ?= new Parser(options)
+  options.parser.parse input, (errors, window) ->
+    if errors?.length
+      errors
+    else
+      output ?= new Output(process.stdout)
+      options.converter ?= new Converter(options)
+      options.converter.document window.document, output
+      null
+


lifecycle: simplification

lifecycle: simplification

--- lib/lifecycle.coffee
+++ lib/lifecycle.coffee
@@ -9,8 +9,7 @@
     ctx.execute
       cmd: "service hadoop-hdfs-journalnode status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   jn_start: (ctx, callback) ->
     {hdfs_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.jn_status ctx, (err, running) ->
@@ -35,38 +34,45 @@
         # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} --script hdfs stop journalnode\""
         cmd: 'service hadoop-hdfs-journalnode stop'
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   nn_status: (ctx, callback) ->
     ctx.execute
       cmd: "service hadoop-hdfs-namenode status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   nn_start: (ctx, callback) ->
-    {hdfs_user, hadoop_conf_dir, hdfs_site, nameservice, ha_client_config, hdfs_namenode_timeout} = ctx.config.ryba
-    state = (started) ->
-      callback null, started
     lifecyle.nn_status ctx, (err, running) ->
-      # return callback err, false if err or running
-      return callback err if err
-      return state false if running
+      return callback err, false if err or running
       ctx.log "NameNode start"
       ctx.execute
         # su -l hdfs -c "/usr/lib/hadoop/sbin/hadoop-daemon.sh --config /etc/hadoop/conf --script hdfs start namenode"
         # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} --script hdfs start namenode\""
-        cmd: 'service hadoop-hdfs-namenode start'
-        # code_skipped: 1
-      , (err, started) ->
-        return callback err if err
-        return callback null, false unless started
-        ipc_port = url.parse(ha_client_config["dfs.namenode.rpc-address.#{nameservice}.#{ctx.config.shortname}"]).port or 8020
-        http_port = if hdfs_site['dfs.https.enable'] is 'false'
-        then url.parse(ha_client_config["dfs.namenode.http-address.#{nameservice}.#{ctx.config.shortname}"]).port or 50070
-        else url.parse(ha_client_config["dfs.namenode.https-address.#{nameservice}.#{ctx.config.shortname}"]).port or 50470
-        ctx.waitIsOpen ctx.config.host, [ipc_port, http_port], timeout: hdfs_namenode_timeout, (err) ->
-          return callback err if err
-          state true
+        cmd: "service hadoop-hdfs-namenode start"
+        code_skipped: [1, 3]
+      , callback
+    # {hdfs_user, hadoop_conf_dir, hdfs_site, nameservice, ha_client_config, hdfs_namenode_timeout} = ctx.config.ryba
+    # state = (started) ->
+    #   callback null, started
+    # lifecyle.nn_status ctx, (err, running) ->
+    #   # return callback err, false if err or running
+    #   return callback err if err
+    #   return state false if running
+    #   ctx.log "NameNode start"
+    #   ctx.execute
+    #     # su -l hdfs -c "/usr/lib/hadoop/sbin/hadoop-daemon.sh --config /etc/hadoop/conf --script hdfs start namenode"
+    #     # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} --script hdfs start namenode\""
+    #     cmd: 'service hadoop-hdfs-namenode start'
+    #     # code_skipped: 1
+    #   , (err, started) ->
+    #     return callback err if err
+    #     return callback null, false unless started
+    #     ipc_port = url.parse(ha_client_config["dfs.namenode.rpc-address.#{nameservice}.#{ctx.config.shortname}"]).port or 8020
+    #     http_port = if hdfs_site['dfs.https.enable'] is 'false'
+    #     then url.parse(ha_client_config["dfs.namenode.http-address.#{nameservice}.#{ctx.config.shortname}"]).port or 50070
+    #     else url.parse(ha_client_config["dfs.namenode.https-address.#{nameservice}.#{ctx.config.shortname}"]).port or 50470
+    #     ctx.waitIsOpen ctx.config.host, [ipc_port, http_port], timeout: hdfs_namenode_timeout, (err) ->
+    #       return callback err if err
+    #       state true
   nn_stop: (ctx, callback) ->
     {hdfs_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.nn_status ctx, (err, running) ->
@@ -77,8 +83,7 @@
         # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} --script hdfs stop namenode\""
         cmd: 'service hadoop-hdfs-namenode stop'
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   nn_restart: (ctx, callback) ->
     ctx.log "NameNode restart"
     lifecyle.nn_stop ctx, (err) ->
@@ -88,8 +93,7 @@
     ctx.execute
       cmd: "service hadoop-hdfs-zkfc status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   zkfc_start: (ctx, callback) ->
     {hdfs_user} = ctx.config.ryba
     lifecyle.zkfc_status ctx, (err, running) ->
@@ -100,9 +104,7 @@
         # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh start zkfc\""
         cmd: 'service hadoop-hdfs-zkfc start'
         # code_skipped: 1
-      , (err, started) ->
-        return callback err if err
-        callback err, started
+      , callback
   zkfc_stop: (ctx, callback) ->
     {hdfs_user} = ctx.config.ryba
     lifecyle.zkfc_status ctx, (err, running) ->
@@ -113,17 +115,15 @@
         # cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh stop zkfc\""
         cmd: 'service hadoop-hdfs-zkfc stop'
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   snn_start: (ctx, callback) ->
     {hdfs_user, hadoop_conf_dir} = ctx.config.ryba
     ctx.log "SNN start"
     ctx.execute
       # su -l hdfs -c "/usr/lib/hadoop/sbin/hadoop-daemon.sh --config /etc/hadoop/conf start secondarynamenode"
       cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} start secondarynamenode\""
-      # code_skipped: 1
-    , (err, started) ->
-      callback err, started
+      code_skipped: 1
+    , callback
   snn_stop: (ctx, callback) ->
     {hdfs_user, hadoop_conf_dir} = ctx.config.ryba
     ctx.log "SNN stop"
@@ -131,16 +131,13 @@
       # su -l hdfs -c "/usr/lib/hadoop/sbin/hadoop-daemon.sh --config /etc/hadoop/conf stop secondarynamenode"
       cmd: "su -l #{hdfs_user.name} -c \"/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} stop secondarynamenode\""
       # code_skipped: 1
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   dn_status: (ctx, callback) ->
     ctx.execute
       cmd: "service hadoop-hdfs-datanode status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   dn_start: (ctx, callback) ->
-    {hadoop_conf_dir} = ctx.config.ryba
     lifecyle.dn_status ctx, (err, running) ->
       return callback err, false if err or running
       ctx.log "DataNode start"
@@ -149,10 +146,8 @@
         # cmd: "HADOOP_SECURE_DN_USER=hdfs /usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} --script hdfs start datanode"
         cmd: "service hadoop-hdfs-datanode start"
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   dn_stop: (ctx, callback) ->
-    {hadoop_conf_dir} = ctx.config.ryba
     lifecyle.dn_status ctx, (err, running) ->
       return callback err, false if err or not running
       ctx.log "DataNode stop"
@@ -161,19 +156,12 @@
         # cmd: "/usr/lib/hadoop/sbin/hadoop-daemon.sh --config #{hadoop_conf_dir} stop datanode"
         cmd: "service hadoop-hdfs-datanode stop"
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   rm_status: (ctx, callback) ->
-    # {yarn_pid_dir, yarn_user} = ctx.config.ryba
-    # ctx.log "ResourceManager status"
-    # lifecyle.is_pidfile_running ctx, "#{yarn_pid_dir}/#{yarn_user.name}/yarn-#{yarn_user.name}-resourcemanager.pid", (err, running) ->
-    #   ctx.log "DataNode status: #{if running then 'RUNNING' else 'STOPED'}"
-    #   callback err, running
     ctx.execute
       cmd: "service hadoop-yarn-resourcemanager status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   rm_start: (ctx, callback) ->
     {yarn_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.rm_status ctx, (err, running) ->
@@ -184,8 +172,7 @@
         # cmd: "su -l #{yarn_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec && /usr/lib/hadoop-yarn/sbin/yarn-daemon.sh --config #{hadoop_conf_dir} start resourcemanager\""
         cmd: "service hadoop-yarn-resourcemanager start"
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   rm_stop: (ctx, callback) ->
     {yarn_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.rm_status ctx, (err, running) ->
@@ -196,8 +183,7 @@
         # cmd: "su -l #{yarn_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec && /usr/lib/hadoop-yarn/sbin/yarn-daemon.sh --config #{hadoop_conf_dir} stop resourcemanager\""
         cmd: "service hadoop-yarn-resourcemanager stop"
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   nm_status: (ctx, callback) ->
     # {yarn_pid_dir, yarn_user} = ctx.config.ryba
     # ctx.log "NodeManager status"
@@ -207,8 +193,7 @@
     ctx.execute
       cmd: "service hadoop-yarn-nodemanager status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   nm_start: (ctx, callback) ->
     {yarn_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.nm_status ctx, (err, running) ->
@@ -219,8 +204,7 @@
         # cmd: "su -l #{yarn_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec && /usr/lib/hadoop-yarn/sbin/yarn-daemon.sh --config #{hadoop_conf_dir} start nodemanager\""
         cmd: "service hadoop-yarn-nodemanager start"
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   nm_stop: (ctx, callback) ->
     {yarn_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.nm_status ctx, (err, running) ->
@@ -231,21 +215,13 @@
         # cmd: "su -l #{yarn_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec && /usr/lib/hadoop-yarn/sbin/yarn-daemon.sh --config #{hadoop_conf_dir} stop nodemanager\""
         cmd: "service hadoop-yarn-nodemanager stop"
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   jhs_status: (ctx, callback) ->
-    # {mapred_pid_dir, mapred_user} = ctx.config.ryba
-    # ctx.log "JobHistoryServer status"
-    # lifecyle.is_pidfile_running ctx, "#{mapred_pid_dir}/#{mapred_user.name}/mapred-#{mapred_user.name}-historyserver.pid", (err, running) ->
-    #   ctx.log "JobHistoryServer status: #{if running then 'RUNNING' else 'STOPED'}"
-    #   callback err, running
     ctx.execute
       cmd: "service hadoop-mapreduce-historyserver status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   jhs_start: (ctx, callback) ->
-    {mapred_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.jhs_status ctx, (err, running) ->
       return callback err, false if err or running
       ctx.log "JobHistoryServer start"
@@ -254,10 +230,8 @@
         # cmd: "su -l #{mapred_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec/ && /usr/lib/hadoop-mapreduce/sbin/mr-jobhistory-daemon.sh --config #{hadoop_conf_dir} start historyserver\""
         cmd: 'service hadoop-mapreduce-historyserver start'
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   jhs_stop: (ctx, callback) ->
-    {mapred_user, hadoop_conf_dir} = ctx.config.ryba
     lifecyle.jhs_status ctx, (err, running) ->
       return callback err, false if err or not running
       ctx.log "JobHistoryServer stop"
@@ -266,14 +240,12 @@
         # cmd: "su -l #{mapred_user.name} -c \"export HADOOP_LIBEXEC_DIR=/usr/lib/hadoop/libexec/ && /usr/lib/hadoop-mapreduce/sbin/mr-jobhistory-daemon.sh --config #{hadoop_conf_dir} stop historyserver\""
         cmd: 'service hadoop-mapreduce-historyserver stop'
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   hive_metastore_status: (ctx, callback) ->
     ctx.execute
       cmd: "service hive-hcatalog-server status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   hive_metastore_start: (ctx, callback) ->
     {hive_metastore_host, hive_metastore_port, hive_metastore_timeout} = ctx.config.ryba
     lifecyle.hive_metastore_status ctx, (err, running) ->
@@ -306,8 +278,7 @@
     ctx.execute
       cmd: "service hive-server2 status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   hive_server2_start: (ctx, callback) ->
     {hive_server2_host, hive_server2_port, hive_server2_timeout} = ctx.config.ryba
     lifecyle.hive_server2_status ctx, (err, running) ->
@@ -329,8 +300,7 @@
         # su -l hive -c "kill `cat /var/run/hive/server2.pid`"
         cmd: 'service hive-server2 stop'
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   hive_server2_restart: (ctx, callback) ->
     ctx.log "Hive Server2 restart"
     lifecyle.hive_server2_stop ctx, (err) ->
@@ -351,8 +321,7 @@
         # su -l oozie -c "/usr/lib/oozie/bin/oozied.sh start"
         cmd: "su -l #{oozie_user.name} -c \"/usr/lib/oozie/bin/oozied.sh start\""
         # code_skipped: 1
-      , (err, started) ->
-        callback err, started
+      , callback
   oozie_stop: (ctx, callback) ->
     {oozie_user} = ctx.config.ryba
     lifecyle.oozie_status ctx, (err, running) ->
@@ -362,8 +331,7 @@
         # su -l oozie -c "/usr/lib/oozie/bin/oozied.sh stop"
         cmd: "su -l #{oozie_user.name} -c \"/usr/lib/oozie/bin/oozied.sh stop\""
         # code_skipped: 1
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   hbase_master_status: (ctx, callback) ->
     # {hbase_pid_dir, hbase_user} = ctx.config.ryba
     ctx.log "HBase Master status"
@@ -373,8 +341,7 @@
     ctx.execute
       cmd: "service hbase-master status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   hbase_master_start: (ctx, callback) ->
     {hbase_user, hbase_conf_dir} = ctx.config.ryba
     lifecyle.hbase_master_status ctx, (err, running) ->
@@ -384,8 +351,7 @@
         # su -l hbase -c "/usr/lib/hbase/bin/hbase-daemon.sh --config /etc/hbase/conf start master"
         # cmd: "su -l #{hbase_user.name} -c \"/usr/lib/hbase/bin/hbase-daemon.sh --config #{hbase_conf_dir} start master\""
         cmd: "service hbase-master start"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   hbase_master_stop: (ctx, callback) ->
     {hbase_user, hbase_conf_dir} = ctx.config.ryba
     lifecyle.hbase_master_status ctx, (err, running) ->
@@ -395,8 +361,7 @@
         # su -l hbase -c "/usr/lib/hbase/bin/hbase-daemon.sh --config /etc/hbase/conf stop master"
         # cmd: "su -l #{hbase_user.name} -c \"/usr/lib/hbase/bin/hbase-daemon.sh --config #{hbase_conf_dir} stop master\""
         cmd: "service hbase-master stop"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   hbase_regionserver_status: (ctx, callback) ->
     # {hbase_pid_dir, hbase_user} = ctx.config.ryba
     ctx.log "HBase RegionServer status"
@@ -406,8 +371,7 @@
     ctx.execute
       cmd: "service hbase-regionserver status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   hbase_regionserver_start: (ctx, callback) ->
     {hbase_user, hbase_conf_dir} = ctx.config.ryba
     lifecyle.hbase_regionserver_status ctx, (err, running) ->
@@ -417,8 +381,7 @@
         # su -l hbase -c "/usr/lib/hbase/bin/hbase-daemon.sh --config /etc/hbase/conf start regionserver"
         # cmd: "su -l #{hbase_user.name} -c \"/usr/lib/hbase/bin/hbase-daemon.sh --config #{hbase_conf_dir} start regionserver\""
         cmd: 'service hbase-regionserver start'
-      , (err, started) ->
-        callback err, started
+      , callback
   hbase_regionserver_stop: (ctx, callback) ->
     {hbase_user, hbase_conf_dir} = ctx.config.ryba
     lifecyle.hbase_regionserver_status ctx, (err, running) ->
@@ -428,8 +391,7 @@
         # su -l hbase -c "/usr/lib/hbase/bin/hbase-daemon.sh --config /etc/hbase/conf stop regionserver"
         # cmd: "su -l #{hbase_user.name} -c \"/usr/lib/hbase/bin/hbase-daemon.sh --config #{hbase_conf_dir} stop regionserver\""
         cmd: 'service hbase-regionserver stop'
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   webhcat_status: (ctx, callback) ->
     {webhcat_pid_dir} = ctx.config.ryba
     # lifecyle.is_pidfile_running ctx, "#{webhcat_pid_dir}/webhcat.pid", (err, running) ->
@@ -438,8 +400,7 @@
     ctx.execute
       cmd: "service hive-webhcat-server status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   webhcat_start: (ctx, callback) ->
     lifecyle.webhcat_status ctx, (err, running) ->
       return callback err, false if err or running
@@ -447,8 +408,7 @@
       ctx.execute
         # su -l hive -c "/usr/lib/hive-hcatalog/sbin/webhcat_server.sh start"
         cmd: "service hive-webhcat-server start"
-      , (err, started) ->
-        callback err, true
+      , callback
   webhcat_stop: (ctx, callback) ->
     lifecyle.webhcat_status ctx, (err, running) ->
       return callback err, false if err or not running
@@ -456,8 +416,7 @@
       ctx.execute
         # su -l hive -c "/usr/lib/hive-hcatalog/sbin/webhcat_server.sh stop"
         cmd: "service hive-webhcat-server stop"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   hue_status: (ctx, callback) ->
     ctx.log "Hue status"
     # We are not here to check if service is installed, for example this is
@@ -468,25 +427,21 @@
     ctx.execute
       cmd: "service hue status"
       code_skipped: [1, 3]
-    , (err, running) ->
-      ctx.log "Hue status: #{if running then 'RUNNING' else 'STOPED'}"
-      callback err, running
+    , callback
   hue_start: (ctx, callback) ->
     lifecyle.hue_status ctx, (err, running) ->
       return callback err, false if err or running
       ctx.log "Hue start"
       ctx.execute
         cmd: "service hue start"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   hue_stop: (ctx, callback) ->
     lifecyle.hue_status ctx, (err, running) ->
       return callback err, false if err or not running
       ctx.log "Hue stop"
       ctx.execute
         cmd: "service hue stop"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback
   zookeeper_status: (ctx, callback) ->
     # {zookeeper_pid_dir} = ctx.config.ryba
     ctx.log "Zookeeper status"
@@ -496,8 +451,7 @@
     ctx.execute
       cmd: "service zookeeper-server status"
       code_skipped: [1, 3]
-    , (err, stopped) ->
-      callback err, stopped
+    , callback
   zookeeper_start: (ctx, callback) ->
     {zookeeper_user, zookeeper_conf_dir, zookeeper_port} = ctx.config.ryba
     lifecyle.zookeeper_status ctx, (err, running) ->
@@ -520,8 +474,7 @@
         # su -l zookeeper -c "/usr/lib/zookeeper/bin/zkServer.sh stop /etc/zookeeper/conf/zoo.cfg"
         # cmd: "su -l #{zookeeper_user.name} -c \"/usr/lib/zookeeper/bin/zkServer.sh stop #{zookeeper_conf_dir}/zoo.cfg\""
         cmd: "service zookeeper-server stop"
-      , (err, stopped) ->
-        callback err, stopped
+      , callback

 module.exports.is_pidfile_running = (ctx, path, callback) ->
   ctx.execute


Fix blank allowed hosts

Fix blank allowed hosts

--- lib/otter/bin.coffee
+++ lib/otter/bin.coffee
@@ -22,7 +22,7 @@
   server.start
     port: options['-p']
     path: options['<path>']
-    allowedHosts: options['-a']?.split(',')
+    allowedHosts: options['-a'].split(',') if options['-a']
   console.log "Server started on port #{options['-p']}."


fix(app generator docs): fix comment instruction

--- generators/app/templates/src/app.coffee
+++ generators/app/templates/src/app.coffee
@@ -60,7 +60,7 @@

 Q               = require( 'q' )

-##  Uncomment / remove for your developement convenience.
+##  Comment out or remove this for your developement convenience.
 ##
 ##  https://github.com/kriskowal/q/wiki/API-Reference#qstopunhandledrejectiontracking
 ##


Add comparison case-specifiers

Add comparison case-specifiers

"case-specifiers"? is that the right thing to call these?

--- grammars/powershell.cson
+++ grammars/powershell.cson
@@ -42,7 +42,7 @@
     'name': 'keyword.operator.bitwise.powershell'
   }
   {
-    'match': '\\B(?i:(-eq|-lt|-gt|-le|-ge|-ne|-notlike|-like|-match|-notmatch|-contains|-notcontains|-in|-notin|-replace))\\b'
+    'match': '\\B(?i:-([i|c]?(eq|lt|gt|le|ge|ne|notlike|like|match|notmatch|contains|notcontains|in|notin|replace)))\\b'
     'name': 'keyword.operator.comparison.powershell'
   }
   {


* node deletion

* node deletion

--- app/assets/javascripts/components/larch-tree_component.js.coffee
+++ app/assets/javascripts/components/larch-tree_component.js.coffee
@@ -11,20 +11,20 @@
   init: ->
     @_super()
     @ensureProperty('nodes')
-    @ensureProperty('store')
+    @ensureProperty('store')
     @ensureProperty('removeNode')
     @ensureProperty('serverPath')

   ensureProperty: (name) ->
     throw "Missing property '#{name}' for Larch.TreeComponent" if Ember.isEmpty(@get(name))
-
+
   roots: (->
      @get('sortedNodes').filterBy('ancestryDepth',0)
   ).property('sortedNodes.@each.depth')

   actions:
-    removeNode: ->
-      @sendAction 'removeNode'
+    removeNode: (node) ->
+      @sendAction 'removeNode', node
       false

     moveUp: (item) ->
@@ -36,7 +36,7 @@
       false

     changeParent: (item_id,parent_id,position = null) ->
-      data = { menu_item: { parent_id: parent_id }}
+      data = { parent_id: parent_id }
       path = @get('serverPath')
       @postToServer("#{path}/#{item_id}",data,type: 'PUT').then =>
         console.log "Item #{item_id} changed parent."


fixes order page

fixes order page

--- assets/order.coffee
+++ assets/order.coffee
@@ -1,4 +1,4 @@
-{ init } = require '../apps/contract/client/order_view.coffee'
+{ init } = require '../apps/future/client/order_view.coffee'

 $ ->
   init()


Color numbers inside function calls

Color numbers inside function calls

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -236,6 +236,9 @@
       }
       {
         'include': '#builtin_functions'
+      }
+      {
+        'include': '#numbers'
       }
       {
         'match': '[A-Za-z_][A-Za-z0-9_]{0,31}'


#2 Updated uuid algorithm for reducing the collision chance

--- lib/somewhere.coffee
+++ lib/somewhere.coffee
@@ -6,9 +6,12 @@
 database = {}

 _uuid = () ->
-  s4 = ->
-    return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
-  return "#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"
+  date = new Date().getTime()
+  uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c) ->
+    r = (date + Math.random() * 16) % 16 | 0
+    date = Math.floor date/16
+    v = if c is 'x' then r else r & 7 | 8
+    v.toString 16

 _checkCollection = (collection) ->
   return if database[collection]


Add header to generated file

Add header to generated file

--- lib/transpile.coffee
+++ lib/transpile.coffee
@@ -1,6 +1,7 @@
 _ = require 'lodash'
 jsStringEscape = require 'js-string-escape'
 runtime = require './runtime'
+product = require '../package.json'
 push = Array.prototype.push

 ###
@@ -15,6 +16,10 @@
   # console.dir rules, colors: true, depth:10
   result = []

+  # header
+  result.push '// Generated by ', product.name, ' ', product.version, '\n'
+
+  # exportable
   result.push 'module.exports = function($config) {\n'

   # fallback
@@ -40,12 +45,12 @@
   if topRule?
     result.push "return $global['#{topRule}']();\n"

-  # module.exports = ... {
+  # done!
   result.push '};'

   result.join ''

-# TODO: Study extensibility model (user function)
+# TODO: Study extensibility model for composable externals
 composable = ['Mapping']

 types =


Turn off default up/down scrolling from ScrollView

When https://github.com/atom/atom/pull/2368 was merged, ScrollView
gained the ability to scroll when the up and down arrow keys are
pressed (more precisely, when core:move-up or core:move-down
events are triggered).

Since Tree View uses a ScrollView, this means that core:move-up
and core:move-down events both select the previous/next item
in the Tree View, and make the Tree View scroll up/down.

This change turns off the scrolling behavior by removing the
ScrollView's default event handler for the core:move-up and
core:move-down events.

Fixes #152.

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -58,6 +58,10 @@
       else
         @selectEntry(entryToSelect)
         @showFullMenu()
+
+    # turn off default scrolling behavior from ScrollView
+    @off 'core:move-up'
+    @off 'core:move-down'

     @on 'mousedown', '.tree-view-resize-handle', (e) => @resizeStarted(e)
     @command 'core:move-up', => @moveUp()


Use custom label for each OS file manager

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -317,33 +317,41 @@
   #               to.
   # pathToOpen  - Path to a file or directory.
   #
-  # Returns the name of the executable to call, and a list of arguments to pass.
-  getFileManagerCall: (entryType, pathToOpen) ->
+  # Returns an object containing a command, a human-readable label, and the
+  # arguments.
+  fileManagerCommandForPath: (entryType, pathToOpen) ->
     switch process.platform
       when 'darwin'
-        return ['open', ['-R', pathToOpen]]
+        command: 'open'
+        label: 'Finder'
+        args: ['-R', pathToOpen]
       when 'win32'
-        return ['cmd.exe', ['/c', 'start', 'explorer.exe', pathToOpen]]
+        command: 'cmd.exe'
+        label: 'Explorer'
+        args: ['/c', 'start', 'explorer.exe', pathToOpen]
       else
         # Strip the filename from the path to make sure we pass a directory
         # path. If we pass xdg-open a file path, it will open that file in the
         # most suitable application instead, which is not what we want.
         pathToOpen =  path.dirname(pathToOpen) if entryType is 'file'
-        ['xdg-open', [pathToOpen]]
+
+        command: 'xdg-open'
+        label: 'File Manager'
+        args: [pathToOpen]

   showSelectedEntryInFileManager: ->
     entry = @selectedEntry()
     return unless entry
     entryType = if entry instanceof DirectoryView then 'directory' else 'file'

-    [command, args] = @getFileManagerCall(entryType, entry.getPath())
+    {command, args, label} = @fileManagerCommandForPath(entryType, entry.getPath())

     errorLines = []
     stderr = (lines) -> errorLines.push(lines)
     exit = (code) ->
       if code isnt 0
         atom.confirm
-          message: "Opening #{entryType} in #{command} failed"
+          message: "Opening #{entryType} in #{label} failed"
           detailedMessage: errorLines.join('\n')
           buttons: ['OK']


TEST - added several could-have-continuted tests - TWO ARE FAILING

--- test/tests/Caffeine.Eight/FailingParseInfo/CouldHaveContinued.coffee
+++ test/tests/Caffeine.Eight/FailingParseInfo/CouldHaveContinued.coffee
@@ -97,6 +97,72 @@
         column: 2
         expectingInfo: expecting: "/[a-z]+/": "to-continue": "root", "started-at": "1:1"

+  basic: ->
+    test "no match at all simple", ->
+      class MyParser extends Parser
+        @rule
+          root: "foo"
+          foo: "bar"
+          bar: /bar/
+
+      myParser = new MyParser
+      assert.rejects -> myParser.parse "bad"
+      .then (error)->
+        validateCompileError error,
+          failureIndex: 0
+          line: 0
+          column: 0
+
+        # log myParser.nonMatches
+        assert.eq Object.keys(myParser.nonMatches).sort(), [
+            "FooRuleFooVariant: 'foo'"
+          ]
+
+  couldMatchKeys: ->
+    test "no match at all", ->
+      class MyParser extends Parser
+        @rule
+          root: "foo"
+          foo: "bar? baz"
+          bar: /bar/
+          baz: /baz/
+
+      myParser = new MyParser
+      assert.rejects -> myParser.parse "bad"
+      .then (error)->
+        validateCompileError error,
+          failureIndex: 0
+          line: 0
+          column: 0
+
+        # log myParser.nonMatches
+        assert.eq Object.keys(myParser.nonMatches).sort(), [
+            "FooRuleFooVariant: 'foo'"
+          ]
+
+    test "partial match", ->
+      class MyParser extends Parser
+        @rule
+          root: "foo"
+          foo:  "duh? bar? baz"
+          duh:  /duh/
+          bar:  /bar/
+          baz:  /baz/
+
+      myParser = new MyParser
+      assert.rejects -> myParser.parse "duhbad"
+      .then (error)->
+        validateCompileError error,
+          failureIndex: 3
+          line: 0
+          column: 3
+
+        # log myParser.nonMatches
+        assert.eq Object.keys(myParser.nonMatches).sort(), [
+            "BarRuleBarVariant: /bar/"
+            'BazRuleBazVariant: /baz/'
+          ]
+
   misc: ->

     test "nonMatches keys", ->


[misc] test/acceptance: do not hard code the logging level

There is an environment variable LOG_LEVEL to set it.

--- test/acceptance/coffee/helpers/TrackChangesApp.coffee
+++ test/acceptance/coffee/helpers/TrackChangesApp.coffee
@@ -1,5 +1,5 @@
 app = require('../../../../app')
-require("logger-sharelatex").logger.level("info")
+require("logger-sharelatex")
 logger = require("logger-sharelatex")
 Settings = require("settings-sharelatex")


Fix the flash when logging in

Fix the flash when logging in

--- apps/authentication/routes.coffee
+++ apps/authentication/routes.coffee
@@ -18,8 +18,7 @@
       Organization.findOne name: req.body.name, (err, org) ->
         if org and org.hashed_password == hexDigest(req.body.password)
           req.session.org_id = org.id
-          req.flash 'info',
-            "You are logged in as #{req.session.currentOrg}"
+          req.flash 'info', "You are logged in as #{org.name}"
           res.redirect '/dashboard'
         else
           req.flash 'error', errMsg


let user opinion return without s

let user opinion return without s

--- core/app/backbone/models/wheel.coffee
+++ core/app/backbone/models/wheel.coffee
@@ -45,13 +45,15 @@

   isUserOpinion: (type) -> @get('opinion_types')[type].is_user_opinion

-  userOpinionWithS: -> @userOpinion()
+  userOpinionWithS: ->
+    opinion = @userOpinion()
+    opinion and (opinion + 's')

   userOpinion: ->
     @_userOpinions()[0]

   _userOpinions: ->
-    "#{type}s" for type, opinionType of @get('opinion_types') when opinionType.is_user_opinion
+    type for type, opinionType of @get('opinion_types') when opinionType.is_user_opinion

   updateTo: (authority, opinionTypes) ->
     new_opinion_types = {}


Add summary warning of multiple emits.

Add summary warning of multiple emits.

--- compiler/index.coffee
+++ compiler/index.coffee
@@ -115,6 +115,11 @@
                 SDKError.warn('files', 'Projects SHOULD have a /404.html')
             unless _emitFile.files_emitted_indexed['index.html'] or _emitFile.files_emitted_indexed['/index.html']
                 SDKError.warn('files', 'Projects SHOULD have a /index.html')
+
+            num_indexed = Object.keys(_emitFile.files_emitted_indexed).length
+            num_emitted = _emitFile.files_emitted_indexed
+            if num_indexed isnt num_emitted
+                SDKError.warn('files', "#{ num_emitted - num_indexed } too many emits. Check for multiple emits of the same file.")
             onCompile?(_emitFile.files_emitted, compileAssets.files_emitted, project_package, project_config)

         compileAssets


EditComment: view structure is changed

EditComment: view structure is changed

--- client/Social/Activity/views/comments/commentlistitemview.coffee
+++ client/Social/Activity/views/comments/commentlistitemview.coffee
@@ -27,8 +27,15 @@
     @author = new ProfileLinkView { origin }

     @body = @getBody data
-
-    @edited = @getEdited data
+    @editCommentWrapper = new KDCustomHTMLView
+      cssClass : "edit-comment-wrapper hidden"
+
+    @editInfo = new KDCustomHTMLView
+      tagName: "span"
+      cssClass: "hidden"
+      pistachio: "(edited)"
+
+    if data.getAt 'editedAt' then @editInfo.show()

     if deleterId? and deleterId isnt originId
       @deleter = new ProfileLinkView {}, data.getAt('deletedBy')
@@ -77,30 +84,28 @@
           return
         data.body = comment
         data.editedAt = new Date
-        @edited = @getEdited data
         @hideEditCommentForm(data)

   cancelCommentUpdate: ->
     @hideEditCommentForm(@getData())

   hideEditCommentForm:(data)->
-    @body = @getBody data
-    @edited.show()
-    @settings = @getSettings(data)
-    @timeAgoView = new KDTimeAgoView {}, data.meta.createdAt
-    @updateTemplate yes
-
+    @settings.show()
+    @editComment.destroy()
+    @body.show()
+    @editInfo.show() if data.getAt 'editedAt'
+    @editCommentWrapper.hide()

   showEditCommentForm:(data)->
     @settings.hide()
-    @body.destroy()
-    @edited.hide()
-    @body = new EditCommentForm
+    @body.hide()
+    @editInfo.hide()
+    @editComment = new EditCommentForm
       editable : yes
       delegate : this,
       data
-    @timeAgoView = new KDTimeAgoView {}, data.meta.createdAt
-    @updateTemplate yes
+    @editCommentWrapper.addSubView @editComment
+    @editCommentWrapper.show()

   getSettings:(data)->
     button = new KDButtonViewWithMenu
@@ -117,12 +122,6 @@
     new KDCustomHTMLView
       pistachio: "{p{@utils.applyTextExpansions #(body), yes}}",
       data
-
-  getEdited:(data) ->
-    if data.getAt 'editedAt'
-      new KDCustomHTMLView tagName: 'span', pistachio: "(edited)"
-    else new KDCustomHTMLView tagName: 'span', cssClass: 'hidden'
-

   getDeleteButton:(data)->
     button = new KDCustomHTMLView
@@ -211,7 +210,8 @@
       <div class='comment-contents clearfix'>
         {{> @author}}
         {{> @body}}
-        {{> @edited}}
+        {{> @editCommentWrapper}}
+        {{> @editInfo}}
         {{> @settings}}
         {{> @likeView}}
         {{> @replyView}}


show update my machine modal

show update my machine modal

--- client/home/lib/stacks/components/stacktemplateitem/index.coffee
+++ client/home/lib/stacks/components/stacktemplateitem/index.coffee
@@ -3,8 +3,41 @@
 React = require 'kd-react'
 TimeAgo = require 'app/components/common/timeago'
 UnreadCount = require 'app/components/sidebarmachineslistitem/unreadcount'
+getBoundingClientReact = require 'app/util/getBoundingClientReact'
+StackUpdatedWidget = require 'app/components/sidebarstacksection/stackupdatedwidget'

 module.exports = class StackTemplateItem extends React.Component
+
+  constructor: ->
+
+    super
+
+    @state        =
+      coordinates :
+        left      : 0
+        top       : 0
+      showWidget  : no
+
+    $('.kdscrollview').on 'scroll', @bound 'scrollOnPage'
+
+
+  componentWillReceiveProps: -> @setCoordinates()
+
+
+  componentDidMount: -> @setCoordinates()
+
+  scrollOnPage: ->
+
+    @setState { showWidget: no }
+
+
+  setCoordinates: ->
+
+    return  unless @refs.stackTemplateItem
+
+    coordinates = getBoundingClientReact @refs.stackTemplateItem
+    @setState { coordinates: coordinates }
+

   renderButton: ->

@@ -29,6 +62,24 @@
       count={@getStackUnreadCount()}
       onClick={@bound 'handleUnreadCountClick'} />

+
+  handleUnreadCountClick: ->
+
+    @setCoordinates()
+    @setState { showWidget: yes }
+
+
+  renderStackUpdatedWidget: ->
+
+    { coordinates, showWidget } = @state
+
+    return null  unless @getStackUnreadCount()
+    return null  if not coordinates.left and coordinates.top
+
+    coordinates.top = coordinates.top - 156
+    <StackUpdatedWidget className={'stackTemplate'} coordinates={coordinates} stack={@props.stack} show={showWidget} />
+
+
   render: ->

     { template, stack, onOpen } = @props
@@ -39,12 +90,14 @@

         { makeTitle { template, stack } }

       {@renderUnreadCount()}
+      {@renderStackUpdatedWidget()}

         Last updated <TimeAgo from={template.getIn ['meta', 'modifiedAt']} />


Dont call it if its not exists

Dont call it if its not exists

--- client/landing/app/CommonViews/comments/commentviewheader.coffee
+++ client/landing/app/CommonViews/comments/commentviewheader.coffee
@@ -61,7 +61,7 @@

     # Get correct number of items in list from controller
     # I'm not sure maybe its not a good idea
-    if @parent.commentController?.getItemCount?()
+    if @parent?.commentController?.getItemCount?()
       @onListCount = @parent.commentController.getItemCount()

     _newCount = @getData().repliesCount


Removed unneeded variable declaration

Removed unneeded variable declaration

--- js-library/app/js/util/highlight.coffee
+++ js-library/app/js/util/highlight.coffee
@@ -17,8 +17,6 @@
 Factlink.startHighlighting = ->
   console.info "Factlink:", "startHighlighting"

-  facts = []
-
   fetchFacts().done (facts_data) ->
     # If there are multiple matches on the page, loop through them all
     for fact_data in facts_data


Extracted highlightFacts method and always trigger factlink.factsLoaded

--- js-library/app/js/util/highlight.coffee
+++ js-library/app/js/util/highlight.coffee
@@ -1,45 +1,40 @@
 Factlink.Facts = []
+
+highlightFacts = (facts_data) ->
+  # If there are multiple matches on the page, loop through them all
+  for fact_data in facts_data
+    # Select the ranges (results)
+    ranges = Factlink.search(fact_data.displaystring)
+    $.merge Factlink.Facts, Factlink.selectRanges(ranges, fact_data.id)
+
+  Factlink.trigger "factlink.factsLoaded", facts_data

 # Function which will collect all the facts for the current page
 # and select them.
 # Returns deferred object
 fetchFacts = (siteUrl=Factlink.siteUrl()) ->
-  # The URL to the Factlink backend
-  src = FactlinkConfig.api + "/site?url=" + encodeURIComponent(siteUrl)
-
   $.ajax
-    url: src
+    # The URL to the Factlink backend
+    url: FactlinkConfig.api + "/site?url=" + encodeURIComponent(siteUrl)
     dataType: "jsonp"
     crossDomain: true
     type: "GET"
     jsonp: "callback"
+    success: highlightFacts

 highlighting = false
-
 Factlink.startHighlighting = ->
   return if highlighting
   highlighting = true

   console.info "Factlink:", "startHighlighting"
-  fetchFacts().done (facts_data) ->
-    # If there are multiple matches on the page, loop through them all
-    for fact_data in facts_data
-      # Select the ranges (results)
-      ranges = Factlink.search(fact_data.displaystring)
-      $.merge Factlink.Facts, Factlink.selectRanges(ranges, fact_data.id)
+  fetchFacts()

-    Factlink.trigger "factlink.factsLoaded", facts_data
-
-# Don't check for highlighting here, and also don't trigger, as this is a
+# Don't check for highlighting here, as this is a
 # special hacky-patchy method for in the blog
 Factlink.highlightAdditionalFactlinks = (siteUrl) ->
   console.info "Factlink:", "highlightAdditionalFactlinks"
-  fetchFacts(siteUrl).done (facts_data) ->
-    # If there are multiple matches on the page, loop through them all
-    for fact_data in facts_data
-      # Select the ranges (results)
-      ranges = Factlink.search(fact_data.displaystring)
-      $.merge Factlink.Facts, Factlink.selectRanges(ranges, fact_data.id)
+  fetchFacts()

 Factlink.stopHighlighting = ->
   return unless highlighting


select input hiding fix

select input hiding fix

--- apps/partner_application/client/index.coffee
+++ apps/partner_application/client/index.coffee
@@ -22,6 +22,7 @@
   if window.location.search?.indexOf('gallery') > -1
     showHideGalleryForm 'Gallery'
     $('.partner-type-select').val('Gallery').hide()
+    $('.partner-type-label').hide()
   else
     showHideGalleryForm false


Formatting.

Formatting.

--- lib/client/special_event_handler.coffee
+++ lib/client/special_event_handler.coffee
@@ -11,6 +11,7 @@
     click : (remoteEvent, clientEvent) ->
         clientEvent.preventDefault()
         @socket.emit('processEvent', remoteEvent)
+
     # Valid targets:
     #   input, select, textarea
     #


add google.test.coffee

add google.test.coffee

--- workers/social/lib/social/models/computeproviders/google.test.coffee
+++ workers/social/lib/social/models/computeproviders/google.test.coffee
@@ -1,9 +1,11 @@
-Google = require './google'
+Google      = require './google'
+JCredential = require './credential.coffee'

 { expect
   withConvertedUser
   checkBongoConnectivity
-  generateDummyUserFormData } = require '../../../../testhelper'
+  generateDummyUserFormData }      = require '../../../../testhelper'
+{ withConvertedUserAndCredential } = require '../../../../testhelper/models/computeproviders'

 # this function will be called once before running any test
@@ -33,41 +35,48 @@

   describe '#create()', ->

-    describe 'when no data is provided', ->
+    describe 'when credential is provided', ->

       it 'should create default meta data', (done) ->

+        withConvertedUserAndCredential { provider : 'google' }, (data) ->
+
+          { credential, client } = data
+          { clientSecretsContent, privateKeyContent, projectId } = credential
+
+          Google.create client, data, (err, data) ->
+            expect(err).to.not.exist
+
+            { meta } = data
+            expect(meta.type)                 .to.be.equal 'googlecompute'
+            expect(meta.bucket_name)          .to.be.equal 'my-project-packer-images'
+            expect(meta.client_secrets_file)  .to.be.equal clientSecretsContent
+            expect(meta.private_key_file)     .to.be.equal privateKeyContent
+            expect(meta.project_id)           .to.be.equal projectId
+            expect(meta.source_image)         .to.be.equal 'debian-7-wheezy-v20131014'
+            expect(meta.zone)                 .to.be.equal 'us-central1-a'
+            done()
+
+
+
+    describe 'when credential is not provided', ->
+
+      it 'should set some of the default values', (done) ->
+
         client  = null
-        options = { credential : 'someCredential' }
+        options = {}

         Google.create client, options, (err, data) ->
           expect(err).to.not.exist
-          expect(data.meta.type)       .to.be.equal 'google'
-          expect(data.meta.image)      .to.be.equal 'ubuntu-13-10-x64'
-          expect(data.meta.size)       .to.be.equal '512mb'
-          expect(data.meta.region)     .to.be.equal 'sfo1'
-          expect(data.credential)      .to.be.equal options.credential
-          done()

-
-    describe 'when data is provided', ->
-
-      it 'should create meta by given data', (done) ->
-
-        client  = null
-
-        options =
-          region       : 'someRegion'
-          credential   : 'someCredential'
-          instanceType : 'someInstanceType'
-
-        Google.create client, options, (err, data) ->
-          expect(err).to.not.exist
-          expect(data.meta.type)       .to.be.equal 'google'
-          expect(data.meta.image)      .to.be.equal 'ubuntu-13-10-x64'
-          expect(data.meta.size)       .to.be.equal options.instanceType
-          expect(data.meta.region)     .to.be.equal options.region
-          expect(data.credential)      .to.be.equal options.credential
+          { meta } = data
+          expect(meta.type)                 .to.be.equal 'googlecompute'
+          expect(meta.bucket_name)          .to.be.equal 'my-project-packer-images'
+          expect(meta.client_secrets_file)  .to.not.exist
+          expect(meta.private_key_file)     .to.not.exist
+          expect(meta.project_id)           .to.not.exist
+          expect(meta.source_image)         .to.be.equal 'debian-7-wheezy-v20131014'
+          expect(meta.zone)                 .to.be.equal 'us-central1-a'
           done()


removed function which sets no longer used css attribute

--- core/app/backbone/views/autocompleted_add_to_channel_view.coffee
+++ core/app/backbone/views/autocompleted_add_to_channel_view.coffee
@@ -122,17 +122,8 @@
     @$(".btn").removeClass "disabled"

-  updateText: ->
-    value = @$el.find("input.typeahead").val()
-    if value.length
-      @$el.addClass "has-text"
-      @$(".search").text value
-    else
-      @$el.removeClass "has-text"
-
   autoComplete: ->
     searchValue = @$("input.typeahead").val()
-    @updateText()

     return  if @_lastKnownSearchValue is searchValue or not @_proceed


Removed no longer used view

Removed no longer used view

--- core/app/backbone/views/topics/topic_popover_content_view.coffee
+++ core/app/backbone/views/topics/topic_popover_content_view.coffee
@@ -1,8 +0,0 @@
-class window.TopicPopoverContentView extends StatisticsPopoverContentView
-
-  templateHelpers: ->
-    heading: @model.get('title')
-
-  onRender: ->
-    @buttonRegion.show new FavouriteTopicButtonView topic: @model, mini: true
-    @statisticsRegion.show new TopicStatisticsView model: @model


Replace lower/upper bound of number range control with min/max

This commit also cleans up the references to the lower and upper bound
inputs by adding references to them in the ui section and using that
reference instead of looking them up with a selector on each reference.

--- src/coffee/cilantro/ui/field/controls/number.coffee
+++ src/coffee/cilantro/ui/field/controls/number.coffee
@@ -18,8 +18,25 @@
         initialize: (options) ->
             @model = options.model

+            @model.stats.on 'reset', =>
+                @statsMin = _.find(@model.stats.models, (stat) ->
+                    return stat.get('label') == 'Min'
+                )?.get('value')
+
+                if @statsMin? and not @ui.lowerBound.val()
+                    @ui.lowerBound.val(@statsMin)
+
+                @statsMax = _.find(@model.stats.models, (stat) ->
+                    return stat.get('label') == 'Max'
+                )?.get('value')
+
+                if @statsMax and not @ui.upperBound.val()
+                    @ui.upperBound.val(@statsMax)
+
         ui:
             inOutSelect: '.btn-select'
+            lowerBound: '.range-from'
+            upperBound: '.range-to'

         onRender: ->
             @inOutSelect = new button.ButtonSelect
@@ -48,8 +65,8 @@
             return @model.id

         getOperator: ->
-            from = @$('.range-from').val()
-            to = @$('.range-to').val()
+            from = @ui.lowerBound.val()
+            to = @ui.upperBound.val()
             operator = ''

             if from != "" and to != ""
@@ -64,10 +81,10 @@
             return operator

         getValue: ->
-            from_text = @$('.range-from').val()
+            from_text = @ui.lowerBound.val()
             from_num = new Number(from_text)

-            to_text = @$('.range-to').val()
+            to_text = @ui.upperBound.val()
             to_num = new Number(to_text)

             value = []
@@ -96,16 +113,16 @@
             switch @operator
                 when 'range', '-range'
                     if value[0]?
-                        @$('.range-from').val(value[0])
+                        @ui.lowerBound.val(value[0])
                     else
-                        @$('.range-from').val('')
+                        @ui.lowerBound.val('')
                     if value[1]?
-                        @$('.range-to').val(value[1])
+                        @ui.upperBound.val(value[1])
                     else
-                        @$('.range-to').val('')
+                        @ui.upperBound.val('')
                 when 'gte'
-                    @$('.range-from').val(value)
+                    @ui.lowerBound.val(value)
                 when 'lte'
-                    @$('.range-to').val(value)
+                    @ui.upperBound.val(value)

     { NumberControl }


Only set __proto__ in TermBase if it exists

IE 10 doesn't have the `__proto__` property. So for JS interpreters without `__proto__` we skip the `__proto__` magic (thereby disabling the `foo('bracket')` syntax in ReQL).

Fixes #162
Fix suggested by @mikemintz

--- drivers/javascript/ast.coffee
+++ drivers/javascript/ast.coffee
@@ -52,9 +52,12 @@
 class TermBase
     showRunWarning: true
     constructor: ->
-        self = (ar (field) -> self.bracket(field))
-        self.__proto__ = @.__proto__
-        return self
+        if {}.__proto__ != undefined
+            self = (ar (field) -> self.bracket(field))
+            self.__proto__ = @.__proto__
+            self
+        else
+            @

     run: (connection, options, callback) ->
         # Valid syntaxes are


Fixing error message for 2.3 driver and 2.2 server

Review by @josh

--- drivers/javascript/net.coffee
+++ drivers/javascript/net.coffee
@@ -1109,7 +1109,10 @@
                         j = i+1
                         status_str = status_buf.toString()
                         # Get the reply from the server, and parse it as JSON
-                        server_reply = JSON.parse(status_str)
+                        try
+                            server_reply = JSON.parse(status_str)
+                        catch json_error
+                            throw new err.ReqlDriverError(status_str)

                         if state is 1
                             if not server_reply.success


fix(composer): disable plugins during composition events

--- src/components/contenteditable/contenteditable.cjsx
+++ src/components/contenteditable/contenteditable.cjsx
@@ -95,7 +95,7 @@
   Edits made within the editing function will eventually fire _onDOMMutated
   ###
   atomicEdit: (editingFunction, extraArgsObj={}) =>
-    @_teardownListeners()
+    @_teardownNonMutationListeners()

     editor = new EditorAPI(@_editableNode())

@@ -109,7 +109,7 @@
     catch error
       NylasEnv.emitError(error)

-    @_setupListeners()
+    @_setupNonMutationListeners()

   focus: => @_editableNode().focus()

@@ -135,7 +135,7 @@

   componentDidMount: =>
     @setInnerState editableNode: @_editableNode()
-    @_setupListeners()
+    @_setupNonMutationListeners()
     @_mutationObserver.observe(@_editableNode(), @_mutationConfig())

   # When we have a composition event in progress, we should not update
@@ -160,7 +160,7 @@

   componentWillUnmount: =>
     @_mutationObserver.disconnect()
-    @_teardownListeners()
+    @_teardownNonMutationListeners()
     @_teardownServices()

   setInnerState: (innerState={}) =>
@@ -252,12 +252,12 @@
     defaultKeymaps = {}
     return _.extend(defaultKeymaps, @_boundExtensionKeymapHandlers())

-  _setupListeners: =>
+  _setupNonMutationListeners: =>
     @_broadcastInnerStateToToolbar = true
     document.addEventListener("selectionchange", @_saveSelection)
     @_editableNode().addEventListener('contextmenu', @_onShowContextMenu)

-  _teardownListeners: =>
+  _teardownNonMutationListeners: =>
     @_broadcastInnerStateToToolbar = false
     document.removeEventListener("selectionchange", @_saveSelection)
     @_editableNode().removeEventListener('contextmenu', @_onShowContextMenu)
@@ -333,13 +333,19 @@
   # composition event starts. Without the `_inCompositionEvent` flag
   # stopping the re-render, the asynchronous update request will cause us
   # to re-render and blow away our newly started 2nd composition event.
+  #
+  # While we're in a composition event it's important that `_onDOMMutated`
+  # still get fired so the selection gets updated and the latest body
+  # saved for the next render. However, we want to disable any plugins
+  # since they may inadvertently kill the composition editor by mutating
+  # the DOM.
   _onCompositionStart: =>
     @_inCompositionEvent = true
-    @_teardownListeners()
+    @_teardownNonMutationListeners()

   _onCompositionEnd: =>
     @_inCompositionEvent = false
-    @_setupListeners()
+    @_setupNonMutationListeners()

   _onShowContextMenu: (event) =>
     @refs["toolbarController"]?.forceClose()
@@ -394,6 +400,7 @@
       @_runExtensionMethod(extension, method, argsObj)

   _runExtensionMethod: (extension, method, argsObj={}) =>
+    return if @_inCompositionEvent
     return if not extension[method]?
     editingFunction = extension[method].bind(extension)
     @atomicEdit(editingFunction, argsObj)
@@ -501,12 +508,12 @@
       previousExportedSelection: @innerState.exportedSelection

   _restoreSelection: =>
-    @_teardownListeners()
+    @_teardownNonMutationListeners()
     selection = new ExtendedSelection(@_editableNode())
     selection.importSelection(@innerState.exportedSelection)
     if selection.isInScope()
       @_onSelectionChanged(selection)
-    @_setupListeners()
+    @_setupNonMutationListeners()

   # When the component updates, the selection may have changed from our
   # last known saved position. This can happen for a couple of reasons:


remove unused scope.dashboards

remove unused scope.dashboards

--- src/components/dashboard/dashboard.directive.coffee
+++ src/components/dashboard/dashboard.directive.coffee
@@ -373,7 +373,6 @@
   return {
       restrict: 'EA',
       scope: {
-        dashboards: '='
       },
       template: $templateCache.get('dashboard/dashboard.tmpl.html'),
       controller: 'ImpacDashboardCtrl'


'Updating for version 0.12.6dev4'

'Updating for version 0.12.6dev4'

--- bokehjs/src/coffee/version.coffee
+++ bokehjs/src/coffee/version.coffee
@@ -1 +1 @@
-export version = '0.12.6dev3'
+export version = '0.12.6dev4'


quick hack for node emulation

quick hack for node emulation

--- browser/node.coffee
+++ browser/node.coffee
@@ -608,6 +608,9 @@
     fs_state.close f
     return true

+  utimesSync: (path, atime, mtime) ->
+    #XXX: this is a NOP, but it shouldn't be. We need to fix the way we stat files first
+
 # Node's Path API
 root.path =
   normalize: (path) -> path


Show a notification if user already liked

--- client/app/Applications/Activity.kdapplication/ActivityActions.coffee
+++ client/app/Applications/Activity.kdapplication/ActivityActions.coffee
@@ -55,7 +55,12 @@
         if KD.isLoggedIn()
           # oldCount = @likeCount.data.meta.likes
           activity.like (err)=>
-            log arguments, 'you like me!'
+            # log arguments, 'you like me!'
+            if err
+              new KDNotificationView
+                title     : "You already liked this!"
+                duration  : 1300
+            # FIXME Implement Unlike behaviour
             ###
             newCount = @likeCount.data.meta.likes
             if oldCount < newCount then @likeLink.updatePartial("Unlike")


make auth a bit more verbose

make auth a bit more verbose

--- client/lib/middleware/auth.coffee
+++ client/lib/middleware/auth.coffee
@@ -1,9 +1,18 @@
-auth = require 'basic-auth'
+basicAuth = require 'basic-auth'

 module.exports = (req, res, next) ->
-  user = auth(req)
-  if !user or user.name isnt process.env.LOCAL_USER or user.pass isnt process.env.LOCAL_PASSWORD
-    res.set 'WWW-Authenticate', 'Basic realm="Europa"'
-    return res.sendStatus(401).send()

-  next()+  unauthorized = (res) ->
+    res.set 'WWW-Authenticate', 'Basic realm=Authorization Required'
+    return res.sendStatus(401)
+
+  user = basicAuth(req)
+
+  if !user or !user.name or !user.pass
+    return unauthorized(res)
+
+  if user.name is process.env.LOCAL_USER && user.pass is process.env.LOCAL_PASSWORD
+    return next()
+  else
+    return unauthorized(res)
+


don't need rootPath

don't need rootPath

--- gulp-nav.coffee
+++ gulp-nav.coffee
@@ -14,7 +14,6 @@
    orders
    hrefExtension
    demoteTopIndex
-   rootPath
 ###

 path = require 'path'
@@ -22,9 +21,11 @@
 through = require 'through2'
   .obj

+root = null
+rootName = null
+
 module.exports =
-  ({sources, targets, titles, orders, hrefExtension, demoteTopIndex,
-  rootPath}={}) ->
+  ({sources, targets, titles, orders, hrefExtension, demoteTopIndex}={}) ->
     # defaults
     sources ?= ['data', 'frontMatter']
     targets ?= ['nav', 'data.nav']
@@ -32,7 +33,6 @@
     orders ?= 'order'
     hrefExtension ?= 'html'
     demoteTopIndex ?= no
-    rootPath ?= '/'               # XXX finish implementing this!
     # single options don't have to come wrapped in an Array
     sources = [ sources ] unless Array.isArray sources
     targets = [ targets ] unless Array.isArray targets
@@ -51,7 +51,7 @@
       title = (source[title] for title in titles).reduce (x, y) -> x ?= y
       order = (source[order] for order in orders).reduce (x, y) -> x ?= y
       # insert new nav into the tree
-      nav = insertNavIntoTree file.relative, hrefExtension, title, order, rootPath
+      nav = insertNavIntoTree file.relative, hrefExtension, title, order
       # set properties of vinyl object XXX does this need error handling?
       for target in targets
         obj = file
@@ -80,12 +80,9 @@
   exists: no
   title: null

-root = null
-rootName = null
-
 orderGen = 9999

-insertNavIntoTree = (relativePath, extension, title, order, rootPath) ->
+insertNavIntoTree = (relativePath, extension, title, order) ->
   _path = path.resolve '/', relativePath
     .replace /index\.[^/]+$/, ''              # index identified with directory
     .replace /\.[^./]+$/, '.' + extension     # e.g. '.jade' -> '.html'


figure postFix once

figure postFix once

--- gulp-nav.coffee
+++ gulp-nav.coffee
@@ -113,6 +113,7 @@
 # properties are used because the structure is circular so we need some
 # laziness.
 navInContext = (nav, context, root) ->
+  postFix = if context[-1..][0][-1..] in ['/', '.'] then '..' else '.'
   Object.defineProperties
     title: nav.title
     # how you get here from there, but only if here is an actual place
@@ -122,7 +123,6 @@
     parent:
       enumerable: yes             # these properties should be easy to find
       get: ->                     # they're accessors because we need lazy eval
-        postFix = if context[-1..][0][-1..] in ['/', '.'] then '..' else '.'
         navInContext nav.parent, context.concat postFix
     children:
       enumerable: yes


make fragments-user api urls available to the client - hell yeah : )

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -68,6 +68,7 @@
       libs
       before
       shared
+      gulp.src('node_modules/fragments-user/src/factories/url.coffee').pipe(gulpCoffee({bare: true}))
       client
       after
     ]


NPM installs in the correct directory.

NPM installs in the correct directory.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -122,7 +122,8 @@
     installItems.push(item+'@'+pkg.dependencies[item])

   cmd = 'npm install ' + installItems.join(' ')
-  exec cmd, {'cwd': './dev'}, (err, std, ste) ->
+  cmd = cmd + ' --prefix ' + process.cwd() + '/dev'
+  exec cmd, (err, std, ste) ->
     console.log(err) if err
     console.log(std)
     console.log(ste) if ste


fix stylus build's 'include css' option

fix stylus build's 'include css' option

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -69,7 +69,9 @@
 gulp.task 'styles', ->
   styles = gulp
     .src paths.styles.source
-    .pipe(stylus({set: ['include css']}))
+    .pipe stylus
+      'include css': true
+
     .on 'error', handleError
     .pipe prefix 'last 2 versions', 'Chrome 34', 'Firefox 28', 'iOS 7'


An other minor change on gulpfile in an other attempt to fix it.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -99,7 +99,7 @@
         .pipe(cache("jade"))
         .pipe(jadeInheritance({basedir: './app'}))
         .pipe(jade({pretty: true}))
-        .pipe(gulp.dest("#{paths.dist}/partials"))
+        .pipe(gulp.dest("#{paths.dist}"))

 gulp.task "template", ->
     gulp.src("#{paths.app}/index.jade")
@@ -249,7 +249,7 @@

 # The default task (called when you run gulp from cli)
 gulp.task "default", [
-    "jade-watch",
+    "jade-deploy",
     "template",
     "styles-watch",
     "copy",


fix(build): add index.html itself to the list of files to watch for index task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -66,6 +66,7 @@
 # JS/CSS to inject in index.html
 # Order is important when injecting them into index.html
 injectPaths = [
+  sources.index
   "#{ destinations.libs }/angular.#{ if isDist then 'min.' else '' }js"
   "#{ destinations.libs }/angular-ui-router.#{ if isDist then 'min.' else '' }js"
   "#{ destinations.js }/**/*.js"


tweak

tweak

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -1,8 +1,8 @@
 gulp = require 'gulp'
 Carte = require './lib/carte'
-path = 'public/javascripts/app.js'

 carte = new Carte()
+path = 'public/javascripts/app.js'

 gulp.task 'build', ->
   carte.build watch: false, path: path


dependencies fix

dependencies fix

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -34,6 +34,12 @@
           cjs: 'jquery'
           global: '$'
           param: 'jquery'
+        }, {
+          name: 'es6-promise'
+          amd: 'es6-promise'
+          cjs: 'es6-promise'
+          global: '$'
+          param: 'es6-promise'
         }
       ]
   .pipe gulp.dest './src'


Refactor gulpfile

Refactor gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -7,41 +7,53 @@
 rimraf = require 'gulp-rimraf'
 plumber = require 'gulp-plumber'

+dir =
+  tmp: './tmp/'
+
+file =
+  main: 'd3-meets-chart.js'
+  specRunner: 'spec-runner.js'
+
+src =
+  coffeeSrc: [
+    './src/chart.coffee'
+    './src/chart-d3-chart.coffee'
+    './src/chart-d3-pie.coffee'
+    './src/*.coffee'
+  ]
+  coffeeSpec: [
+    './spec/spec-helper.coffee'
+    './spec/chart-d3-chart-spec.coffee'
+    './spec/chart-d3-pie-spec.coffee'
+    './spec/*-spec.coffee'
+  ]
+  specRunner: dir.tmp + file.specRunner
+
 gulp.task 'coffee-src', ->
   gulp
-    .src [
-      './src/chart.coffee'
-      './src/chart-d3-chart.coffee'
-      './src/chart-d3-pie.coffee'
-      './src/*.coffee'
-    ]
+    .src src.coffeeSrc
     .pipe plumber()
     .pipe coffee(bare: true)
-    .pipe concat('d3-meets-chart.js')
-    .pipe gulp.dest('./tmp/')
+    .pipe concat(file.main)
+    .pipe gulp.dest(dir.tmp)

 gulp.task 'coffee-spec', ->
   gulp
-    .src [
-      './spec/spec-helper.coffee'
-      './spec/chart-d3-chart-spec.coffee'
-      './spec/chart-d3-pie-spec.coffee'
-      './spec/*-spec.coffee'
-    ]
+    .src src.coffeeSpec
     .pipe plumber()
     .pipe coffee(bare: true)
-    .pipe concat('spec-runner.js')
-    .pipe gulp.dest('./tmp/')
+    .pipe concat(file.specRunner)
+    .pipe gulp.dest(dir.tmp)

 gulp.task 'mocha-exe', ['coffee'], ->
   gulp
-    .src './tmp/spec-runner.js'
+    .src src.specRunner
     .pipe plumber()
     .pipe mocha(reporter: 'spec')

 gulp.task 'mocha-clean', ['mocha-exe'], ->
   gulp
-    .src './tmp/spec-runner.js'
+    .src src.specRunner
     .pipe rimraf()
     .pipe notify("☕")


Modify gulpfile.coffee

Modify gulpfile.coffee

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -36,12 +36,11 @@
       .pipe gulp.dest('./lib')
     gulp.src paths.tests
       .pipe $.sourcemaps.init()
-      .pipe($.coffee({ bare: true }).on('error', $.util.log))
+      .pipe($.coffee(bare: true).on('error', $.util.log))
       .pipe $.sourcemaps.write()
       .pipe $.espower()
       .pipe gulp.dest('./compile/test')
   )
-  undefined

 gulp.task 'test', ['compile'], ->
   gulp.src ['./compile/test/**/*.js'], {cwd: __dirname}


Set uglify option 'keep_fname' true

Set uglify option 'keep_fname' true

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -5,5 +5,5 @@
 gulp.task 'build', (done)->
   gulp.src 'src/dfa.js'
     .pipe babel({presets:['env']})
-    .pipe uglify()
+    .pipe uglify({ keep_fnames: true })
     .pipe gulp.dest('.')


Include CSS in watch

Include CSS in watch

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

 gulp.task 'watch', (callback) ->

-	gulp.watch(config.srcSass, ['styles'])._watcher.on 'all', livereload
+	gulp.watch([config.srcCss, srcSass], ['styles'])._watcher.on 'all', livereload
 	# gulp.watch(config.srcPlugins, ['plugins'])._watcher.on 'all', livereload
 	# gulp.watch(config.srcBower, ['bower'])._watcher.on 'all', livereload
 	gulp.watch(config.srcClientScripts, ['clientScripts'])._watcher.on 'all', livereload


Update gulp file

Update gulp file

remove trash files

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -32,9 +32,9 @@
     'bootstrap-material-design/dist/css/roboto.min.css'
   ]
   static: [
-    'bootstrap/dist/fonts/**/*'
-    'bootcards/dist/fonts/**/*'
-    'bootstrap-material-design/dist/fonts/**/*'
+    'bootstrap/dist/**/*.+(eot|svg|ttf|woff|woff2)'
+    'bootcards/dist/**/*.+(eot|svg|ttf|woff|woff2)'
+    'bootstrap-material-design/dist/**/*.+(eot|svg|ttf|woff|woff2)'
   ]


refactor

refactor

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -6,9 +6,10 @@
 mocha = require 'gulp-mocha'
 sourcemaps = require 'gulp-sourcemaps'

-onError = (e) ->
-  gutil.log e
-  @emit 'end'
+ignoreError = (stream) ->
+  stream.on 'error', (e) ->
+    gutil.log e
+    @emit 'end'

 gulp.task 'build', ->
   gulp.src './src/*'
@@ -18,7 +19,7 @@
 gulp.task 'build-dev', ->
   gulp.src './src/*'
     .pipe sourcemaps.init()
-    .pipe babel(modules: 'umd').on 'error', onError
+    .pipe ignoreError babel(modules: 'umd')
     .pipe sourcemaps.write()
     .pipe gulp.dest './dist/'

@@ -33,8 +34,8 @@
 gulp.task 'build-test-dev', ->
   gulp.src './test/*'
     .pipe sourcemaps.init()
-    .pipe coffee().on 'error', onError
-    .pipe espower().on 'error', onError
+    .pipe ignoreError coffee()
+    .pipe ignoreError espower()
     .pipe sourcemaps.write()
     .pipe gulp.dest './.tmp/'

@@ -46,7 +47,7 @@

 gulp.task 'test-dev', ['build-dev', 'build-test-dev'], ->
   gulp.src './.tmp/*'
-    .pipe mocha().on 'error', onError
+    .pipe ignoreError mocha()

 gulp.task 'watch', ['build-dev'], ->
   gulp.watch ['./src/*', './test/*'], ['test-dev']


gulpタスク修正

gulpタスク修正

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -37,12 +37,13 @@
 options = minimist process.argv.slice(2), knownOptions;

 # Tasks
-gulp.task 'browser-sync', ->
+gulp.task 'serve', ->
     browserSync
         server:
             baseDir: BASEPATH
         port: PORT
-        browser: "google chrome"
+        browser: 'google chrome'
+        startPath: PATHS.STATIC.SRC
     return

 gulp.task 'styles', ->
@@ -97,6 +98,6 @@
     return

 gulp.task 'default', [
-    'browser-sync'
+    'serve'
     'watch'
 ]


Fixed typo in __lt__ for dict.coffee

Fixed typo in __lt__ for dict.coffee


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


Fix proposal scrolling

Fix proposal scrolling

--- lineman/app/components/thread_page/thread_page_controller.coffee
+++ lineman/app/components/thread_page/thread_page_controller.coffee
@@ -15,7 +15,7 @@
       if (position = $location.search().position) and AbilityService.canVoteOn(proposal)
         $rootScope.$broadcast 'triggerVoteForm', position
       "#proposal-#{@proposalToFocus.key}"
-    if @commentToFocus
+    else if @commentToFocus
       "#comment-#{@commentToFocus.id}"
     else if Records.events.findByDiscussionAndSequenceId(@discussion, @sequenceIdToFocus)
       '.activity-card__last-read-activity'
@@ -45,11 +45,11 @@

   $scope.$on 'threadPageEventsLoaded',    (event) =>
     @eventsLoaded = true
-    @proposalToFocus = Records.proposals.find $location.search().proposal
+    @commentToFocus = Records.comments.find parseInt($location.search().comment)
     @performScroll() if @proposalsLoaded or !@discussion.anyClosedProposals()
   $scope.$on 'threadPageProposalsLoaded', (event) =>
     @proposalsLoaded = true
-    @commentToFocus = Records.comments.find parseInt($location.search().comment)
+    @proposalToFocus = Records.proposals.find $location.search().proposal
     @performScroll() if @eventsLoaded

   @showLintel = (bool) ->


changed directive to match on element instead of attribute

--- coffee/directives/fixtable.coffee
+++ coffee/directives/fixtable.coffee
@@ -9,8 +9,8 @@
 					if col.width then fixtable._setColumnWidth i+1, col.width
 				scope.data = scope.$parent[scope.options.data]
 		replace: true
-		restrict: 'A'
+		restrict: 'E'
 		scope:
-			options: '=fixtable'
+			options: '='
 		templateUrl: 'fixtable/templates/fixtable.html'
 ]


Scum Sabine doesn't need the '-swx56' suffix, same way Kath doesn't.

--- coffeescripts/cards-common.coffee
+++ coffeescripts/cards-common.coffee
@@ -4028,7 +4028,7 @@
         }
         {
             name: 'Sabine Wren (Scum)'
-            canonical_name: "sabinewren-swx56"
+            canonical_name: "sabinewren"
             id: 220
             unique: true
             faction: 'Scum and Villainy'


Fix problem with ddp connection from some urls

--- packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee
+++ packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee
@@ -4,7 +4,7 @@
 RocketChat.settings.get 'Site_Url', (key, value) ->
 	if value?.trim() isnt ''
 		__meteor_runtime_config__.ROOT_URL = value
-		__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL = value
+
 		if Meteor.absoluteUrl.defaultOptions?.rootUrl?
 			Meteor.absoluteUrl.defaultOptions.rootUrl = value


Go yellow when even

Go yellow when even

--- components/DetermineWinner.coffee
+++ components/DetermineWinner.coffee
@@ -45,4 +45,4 @@
         colors: [[0, 0, 255]]
       return
     output.sendDone
-      colors: [[0, 0, 0]]
+      colors: [[255, 255, 0]]


Updated atom.io configuration

Updated atom.io configuration

--- config.cson
+++ config.cson
@@ -25,6 +25,8 @@
       beautify_on_save: true
   core:
     closeDeletedFileTabs: true
+    followSymlinks: false
+    openEmptyEditorOnStart: false
     telemetryConsent: "no"
   "exception-reporting":
     userId: "110bb6f9-b221-46bb-894e-cc3b978a51b6"


Fix a few adapter issues.

Fix a few adapter issues.

--- hubot-dotnet/index.coffee
+++ hubot-dotnet/index.coffee
@@ -1,10 +1,13 @@
 {Robot, Adapter, TextMessage, EnterMessage, LeaveMessage, Response} = require 'hubot'

-DotNetServer = require './dotnet'
+DotNetServer = require './server'

 class DotNet extends Adapter

+  constructor: ->
+    @port = process.env.HUBOT_DOTNET_PORT || 8880
+
   send: (envelope, strings...) ->
     @server.sendChat envelope.message.client, str for str in strings

@@ -16,7 +19,7 @@

   run: ->
-    @server = new DotNetServer 8880
+    @server = new DotNetServer @port

     @server.on 'chat', (user, message, client) =>
       console.log user, ':', message


Minor performance tweak.

Minor performance tweak.

Two minor tweaks:

1. Do not use ".indexOf()" three times for each comparison; do it just
   once.
2. Check the common case (no match) first.

These are very minor performance tweaks; but, with global link hints,
we pay this cost n times (for n frames).

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -506,14 +506,15 @@
         for searchWord in searchWords
           linkWordScores =
             for linkWord, idx in linkWords
-              if linkWord == searchWord
-                if idx == 0 then 8 else 6
-              else if linkWord.startsWith searchWord
-                if idx == 0 then 4 else 2
-              else if 0 <= linkWord.indexOf searchWord
-                1
+              position = linkWord.indexOf searchWord
+              if position < 0
+                0 # No match.
+              else if position == 0 and searchWord.length == linkWord.length
+                if idx == 0 then 8 else 6 # Whole-word match.
+              else if position == 0
+                if idx == 0 then 4 else 2 # Match at the start of a word.
               else
-                0
+                1 # 0 < position; other match.
           Math.max linkWordScores...

       if 0 in searchWordScores


indented

indented

--- lib/Bumped.default.coffee
+++ lib/Bumped.default.coffee
@@ -1,7 +1,7 @@
 'use strict'

-Args = require 'args-js'
-objectAssign = require('object-assign')
+Args         = require 'args-js'
+objectAssign = require 'object-assign'

 module.exports =


loading all items into dataStore in one go.

--- demo/grid/src/importer.coffee
+++ demo/grid/src/importer.coffee
@@ -9,6 +9,8 @@
 			ids = []

 			that.import = (csv,cb)->
+				cb = (ids)->
+					console.log ids
 				#logic to parse the csv
 				subjects = $.csv2Array csv,
 					separator: template.separator
@@ -33,11 +35,15 @@

 				syncer.done ->
 					setTimeout ->
+						_updateList = []
+						_loadList = []
 						for item in items
 							if dataStore.contains [item]
-								dataStore.updateItems [item]
+								_updateList.push item
 							else
-								dataStore.loadItems [item]
+								_loadList.push item
+						dataStore.updateItems _updateList if _updateList.length isnt 0
+						dataStore.loadItems _loadList if _loadList.length isnt 0
 						cb(ids) if cb?
 					,0
 			that


Add Atom package jsx-comment

Add Atom package jsx-comment

--- atom/packages.cson
+++ atom/packages.cson
@@ -12,6 +12,7 @@
   "git-history"
   "git-plus"
   "highlight-selected"
+  "jsx-comment"
   "language-elixir"
   "language-elm"
   "language-erlang"


Add snippets for plain C

Add snippets for plain C

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -1,8 +1,9 @@
 # Your snippets

-# C++ and JavaScript
-
-'.source.cpp,
+# C, C++ and JavaScript
+
+'.source.c,
+ .source.cpp,
  .source.js':

   # Conditional blocks
@@ -23,6 +24,22 @@
     'prefix': 'while'
     'body': 'while (${1:condition}) {\n\t$2\n}'

+  # Switch constructs
+
+  'switch':
+    'prefix': 'switch'
+    'body': 'switch (${1:variable}) {\n\t$2\n}'
+
+  'case':
+    'prefix': 'case'
+    'body': 'case ${1:value}:\n\t$2'
+
+# C++ and JavaScript
+
+
+'.source.cpp,
+ .source.js':
+
   # Error handling

   'try':
@@ -37,19 +54,10 @@
     'prefix': 'finally'
     'body': 'finally {\n\t$1\n}'

-  # Switch constructs
-
-  'switch':
-    'prefix': 'switch'
-    'body': 'switch (${1:variable}) {\n\t$2\n}'
-
-  'case':
-    'prefix': 'case'
-    'body': 'case ${1:value}:\n\t$2'
-
-# C++
-
-'.source.cpp':
+# C and C++
+
+'.source.c,
+ .source.cpp':

   'include guard':
     'prefix': 'once'
@@ -59,54 +67,70 @@
     'prefix': 'inc'
     'body': '#include $1'

+  'for':
+    'prefix': 'for'
+    'body': 'for (int ${1:i} = ${2:0}; ${1:i} < ${3:end}; ${1:i}${4:++}) {\n\t$5\n}'
+
+  'function':
+    'prefix': 'f'
+    'body': '${1:void} ${2:fname}($3) {\n\t$4\n}'
+
+  'struct':
+    'prefix': 'struct'
+    'body': 'struct ${1:Struct} {\n\t$2\n};'
+
+# C
+
+'.source.c':
+
+  'include stdio':
+    'prefix': 'incstdio'
+    'body': '#include <stdio.h>\n'
+
+  'printf':
+    'prefix': 'printf'
+    'body': 'printf($1);'
+
+# C++
+
+'.source.cpp':
+
   'include iostream':
-    'prefix': 'incio'
+    'prefix': 'inciostream'
     'body': '#include <iostream>\n'

   'using namespace std':
     'prefix': 'using'
     'body': 'using namespace std;\n'

-  'for':
-    'prefix': 'for'
-    'body': 'for (int ${1:i} = ${2:0}; ${1:i} < ${3:end}; ${1:i}${4:++}) {\n\t$5\n}'
-
-  'function':
-    'prefix': 'f'
-    'body': '${1:void} ${2:fname}($3) {\n\t$4\n}'
+  'constructor definition':
+    'prefix': 'ctor'
+    'body': '${1:Class}::${1:Class}($2) {\n\t$3\n}'
+
+  'destructor definition':
+    'prefix': 'dtor'
+    'body': '${1:Class}::~${1:Class}() {\n\t$3\n}'
+
+  'class':
+    'prefix': 'class'
+    'body': 'class ${1:Class} {\n\t$2\n};'
+
+  'public blocks':
+    'prefix': 'public'
+    'body': 'public:\n\t$1'
+
+  'private blocks':
+    'prefix': 'private'
+    'body': 'private:\n\t$1'
+
+  'protected blocks':
+    'prefix': 'protected'
+    'body': 'protected:\n\t$1'

   'function method':
     'prefix': 'fm'
     'body': '${1:void} ${2:Class}::${3:fname}($4) {\n\t$5\n}'

-  'struct':
-    'prefix': 'struct'
-    'body': 'struct ${1:Struct} {\n\t$2\n};'
-
-  'constructor definition':
-    'prefix': 'ctor'
-    'body': '${1:Class}::${1:Class}($2) {\n\t$3\n}'
-
-  'destructor definition':
-    'prefix': 'dtor'
-    'body': '${1:Class}::~${1:Class}() {\n\t$3\n}'
-
-  'class':
-    'prefix': 'class'
-    'body': 'class ${1:Class} {\n\t$2\n};'
-
-  'public blocks':
-    'prefix': 'public'
-    'body': 'public:\n\t$1'
-
-  'private blocks':
-    'prefix': 'private'
-    'body': 'private:\n\t$1'
-
-  'protected blocks':
-    'prefix': 'protected'
-    'body': 'protected:\n\t$1'
-
   'this pointer access':
     'prefix': 'this'
     'body': 'this->'


Rename wrapptm snippet to wrap

Rename wrapptm snippet to wrap

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -428,7 +428,7 @@
     'body': '{\n\tmountToApp: function ($1) {\n\n\t\t $2\n\n\t}\n}'

   'wrap prototype method':
-    'prefix': 'wrapptm'
+    'prefix': 'wrap'
     'body': '${1:Module}.prototype.${2:methodName} = _.wrap(${1:Module}.prototype.${2:methodName}, function (fn) {\n\tfn.apply(this, _.toArray(arguments).slice(1));$3\n});'

   'wrap getContext':


check incoming hash when present

check incoming hash when present

--- services/document-updater/app/coffee/ShareJsUpdateManager.coffee
+++ services/document-updater/app/coffee/ShareJsUpdateManager.coffee
@@ -6,6 +6,7 @@
 {EventEmitter} = require "events"
 util = require "util"
 RealTimeRedisManager = require "./RealTimeRedisManager"
+crypto = require "crypto"

 ShareJsModel:: = {}
 util.inherits ShareJsModel, EventEmitter
@@ -42,6 +43,10 @@
 			logger.log project_id: project_id, doc_id: doc_id, error: error, "applied update"
 			model.getSnapshot doc_key, (error, data) =>
 				return callback(error) if error?
+				# only check hash when present and no other updates have been applied
+				if update.hash? and update.v == version
+					ourHash = ShareJsUpdateManager._computeHash(data.snapshot)
+					return callback(new Error("Invalid hash")) if ourHash != update.hash
 				docLines = data.snapshot.split(/\r\n|\n|\r/)
 				callback(null, docLines, data.v, model.db.appliedOps[doc_key] or [])

@@ -53,3 +58,9 @@
 	_sendOp: (project_id, doc_id, op) ->
 		RealTimeRedisManager.sendData {project_id, doc_id, op}

+	_computeHash: (content) ->
+		return crypto.createHash('sha1')
+			.update("blob " + content.length + "\x00")
+			.update(content, 'utf8')
+			.digest('hex')
+


Test the `cacheWarm` option for preview.

--- services/filestore/test/acceptence/coffee/SendingFileTest.coffee
+++ services/filestore/test/acceptence/coffee/SendingFileTest.coffee
@@ -150,3 +150,22 @@
 					expect(response.statusCode).to.equal 200
 					expect(new Buffer(body.substring(0, 8)).toString('hex')).to.equal 'efbfbd504e470d0a1a0a'
 					done()
+
+		describe "warming the cache", ->
+
+			beforeEach ->
+				@fileUrl = @fileUrl + '?style=preview&cacheWarm=true'
+
+			it "should not time out", (done) ->
+				@timeout(1000 * 20)
+				request.get @fileUrl, (err, response, body) =>
+					expect(response).to.not.equal null
+					done()
+
+			it "should respond with only an 'OK'", (done) ->
+				# note: this test relies of the imagemagick conversion working
+				@timeout(1000 * 20)
+				request.get @fileUrl, (err, response, body) =>
+					expect(response.statusCode).to.equal 200
+					body.should.equal 'OK'
+					done()