updated text to include Alex's changes

updated text to include Alex's changes

updated text to include Alex's changes

--- app/pages/lab/project-details.cjsx
+++ app/pages/lab/project-details.cjsx
@@ -195,7 +195,7 @@
               options={DISCIPLINES}
               multi={true}
               onChange={@handleDisciplineTagChange} />
-              <small className="form-help">Select one or more discipline tags that best describe your project. These tags will determine the subject categories your project will appear under on the main Zooniverse projects page, if your project becomes a full Zooniverse project. </small>
+              <small className="form-help">Enter or select one or more discipline tags to identify which field(s) of research your project belongs to. These tags will determine the categories your project will appear under on the main Zooniverse projects page, if your project becomes a full Zooniverse project. </small>
               <br />
               </AutoSave>
               <AutoSave resource={@props.project}>


cleaning

cleaning

--- app/views/CNeditor/CNeditor.coffee
+++ app/views/CNeditor/CNeditor.coffee
@@ -2203,15 +2203,15 @@

                     if context.currentLineEl.nodeName in ['SPAN','A']
                         console.log "span"
-
                         context.currentLineEl.appendChild txtNode
                     else
                         console.log "no span"
                         spanEl = document.createElement('span')
                         spanEl.appendChild txtNode
                         console.log spanEl
-
-                        context.currentLineEl.appendChild spanEl
+                        context.currentLineEl = spanEl
+
+                        console.log context.currentLineEl

                     console.log "lineEl"
                     console.log context.currentLineEl


Added missing quote in Dependencies

Added missing quote in Dependencies

--- src/scripts/android-os.coffee
+++ src/scripts/android-os.coffee
@@ -3,7 +3,7 @@
 #
 # Dependencies:
 #   "phantom": "0.5.2"
-#   "cheerio: "0.12.1"
+#   "cheerio": "0.12.1"
 #
 # Configuration:
 #   None
@@ -58,4 +58,4 @@
             .join '\n'

             msg.send "#{res}"
-            ph.exit()+            ph.exit()


Update src/scripts/coffee/app.coffee

Update src/scripts/coffee/app.coffee

Better resize

--- src/scripts/coffee/app.coffee
+++ src/scripts/coffee/app.coffee
@@ -74,7 +74,7 @@

       text_size = 15 #pixels
       text_movement = cell_radius / 2 + text_size / 2 + 5
-      text_buffer = text_size + cell_radius / 2 + 10
+      text_buffer = text_size + cell_radius / 2 + 15

       canvas_length = cell_radius * (n - 1) + text_buffer * 2

@@ -300,6 +300,7 @@

       # Replaced by http://www.shapevent.com/scaleraphael/
+      ###
       length = @container_size
       canvas.height(length)
       canvas.width(length)
@@ -307,6 +308,14 @@
       viewbox_length = canvas_length*canvas_length/canvas.width()
       paper.setViewBox(0, 0, viewbox_length*2, viewbox_length*2, true)
       paper.setSize(canvas_length*2,canvas_length*2)
+      ###
+
+      length = this.container_size;
+      canvas.height(length);
+      canvas.width(length);
+      viewbox_length = canvas_length * canvas_length / canvas.width();
+      paper.setViewBox(0, 0, canvas_length, canvas_length, false);
+      paper.setSize(length, length);

       return _GoBoard


Fix madness with 3+ people (closures rock!)

--- static/scripts/main.coffee
+++ static/scripts/main.coffee
@@ -176,14 +176,6 @@

             if who != "x"

-                peer.on "connection", (connection) =>
-
-                    connection.on "open", =>
-
-                        @connections.push connection
-
-                        @listenForMessage connection
-
                 connection = peer.connect "x"

                 connection.on "error", (error) =>
@@ -205,14 +197,24 @@

                                 connection = peer.connect peerId

-                                connection.on "error", (error) =>
-                                    alert error.type
-
-                                connection.on "open", =>
-
-                                    @connections.push connection
-
-                                    @listenForMessage connection
+                                do (connection) =>
+
+                                    connection.on "error", (error) =>
+                                        alert error.type
+
+                                    connection.on "open", =>
+
+                                        @connections.push connection
+
+                                        @listenForMessage connection
+
+                peer.on "connection", (connection) =>
+
+                    connection.on "open", =>
+
+                        @connections.push connection
+
+                        @listenForMessage connection

     render: ->
         (Dom.div null,


Map XML fence to grammar

Map XML fence to grammar

--- src/packages/markdown-preview/lib/markdown-preview-view.coffee
+++ src/packages/markdown-preview/lib/markdown-preview-view.coffee
@@ -18,6 +18,7 @@
   "bash": "sh"
   "js": "js"
   "javascript": "js"
+  "xml": "xml"

 module.exports =
 class MarkdownPreviewView extends ScrollView


synctable: additional robustness -- ignore any output from past changefeed queries; only update table if connected first

--- src/smc-util/synctable.coffee
+++ src/smc-util/synctable.coffee
@@ -317,7 +317,8 @@
             cb?("closed")
             return
         first_resp = true
-        #this_id = misc.uuid().slice(0,8)
+        query_id = misc.uuid()
+        @_query_id = query_id
         #console.log("#{this_id} -- query #{@_table}: _run")
         @_client.query
             query   : @_query
@@ -325,6 +326,10 @@
             timeout : 30
             options : @_options
             cb      : (err, resp) =>
+                if @_query_id != query_id
+                    # ignore any potential output from past attempts to query.
+                    return
+
                 if err == 'socket-end' and @_client.is_project()
                     # This is a synctable in a project and the socket that it was
                     # using for getting changefeed updates from a hub ended.
@@ -375,7 +380,7 @@
                         delete @_state  # undefined until @_reconnect sets it (in same tick)
                         @_reconnect()
                     else
-                        if resp?.event != 'query_cancel'
+                        if resp?.event != 'query_cancel' and @_state == 'connected'
                             @_update_change(resp)
                         #else
                         #    console.log("#{this_id} -- query_cancel")


change synctable behavior on reconnect to not throw away locally saved records; don't leak on multiple disconnect messages

--- src/smc-util/synctable.coffee
+++ src/smc-util/synctable.coffee
@@ -164,11 +164,12 @@
                 @_client.once('signed_in', connect)
                 @_client_listeners.signed_in = connect

-        disconnected = =>
-            dbg("disconnected -- #{misc.to_json(@_query)}")
-            @_state = 'disconnected'
-            @_client.once 'connected', connect
-            @_client_listeners.connected = connect
+        disconnected = () =>
+            if @_state != 'disconnected'
+                dbg("disconnected -- #{misc.to_json(@_query)}")
+                @_state = 'disconnected'
+                @_client.once 'connected', connect
+                @_client_listeners.connected = connect

         @_client.on('disconnected', disconnected)
         @_client_listeners.disconnected = disconnected
@@ -462,9 +463,19 @@
                         conflict = true
                 else
                     # This is a value defined locally that does not exist
-                    # on the remote serve.
-                    @_value_local = @_value_local.delete(key)
-                    changed_keys.push(key)
+                    # on the remote serve.   It could be that the value
+                    # was deleted when we weren't connected, in which case
+                    # we should delete the value we have locally.  On the
+                    # other hand, maybe the local value was newly set
+                    # while we weren't connected, so we know it but the
+                    # backend server doesn't, which case we should keep it,
+                    # and set conflict=true, so it gets saved to the backend.
+                    # Given that in sync we always want to keep, and basically
+                    # all of the synctables in SMC involve no deleting (just adding to or
+                    # changing fields), we MAKE THE CHOICE that we always keep the
+                    # local value.
+                    # This would be deleting local:  @_value_local = @_value_local.delete(key); changed_keys.push(key)
+                    conflict = true

             # NEWLY ADDED:
             # Next check through each key in what's on the remote database,


Store credentials on authentication

Store credentials on authentication

--- tentacle-server.coffee
+++ tentacle-server.coffee
@@ -41,6 +41,7 @@
     @tentacle.start()

   authenticateWithMeshblu: (credentials) =>
+    @credentials = credentials
     try
       debug "authenticating with credentials: #{JSON.stringify(credentials)}"
       @meshbluConn = Meshblu.createConnection


fix: don't set Content-Length for empty request bodies

--- src/transaction-runner.coffee
+++ src/transaction-runner.coffee
@@ -455,7 +455,9 @@
     for key, value of transaction.request.headers
       caseInsensitiveRequestHeadersMap[key.toLowerCase()] = key

-    if not caseInsensitiveRequestHeadersMap['content-length'] and transaction.request['body'] != ''
+    if not caseInsensitiveRequestHeadersMap['content-length'] and
+        transaction.request['body']? and
+        transaction.request['body'] != ''
       logger.verbose('Calculating Content-Length of the request body')
       transaction.request.headers['Content-Length'] = Buffer.byteLength(transaction.request['body'], 'utf8')


refactor: Addressing PR comments

refactor: Addressing PR comments

--- src/transaction-runner.coffee
+++ src/transaction-runner.coffee
@@ -617,6 +617,7 @@
         # Create test message from messages of all validation errors
         message = ''
         for own sectionName, validatorOutput of gavelResult or {} when sectionName isnt 'version'
+          # Section names are 'statusCode', 'headers', 'body' (and 'version', which is irrelevant)
           for gavelError in validatorOutput.results or []
             message += "#{sectionName}: #{gavelError.message}\n"
         test.message = message


fix virustotal.coffee

fix virustotal.coffee

--- src/scripts/virustotal.coffee
+++ src/scripts/virustotal.coffee
@@ -94,7 +94,7 @@
               if vt_json.response_code == 1

                 summary = """VirusTotal IP Result: #{ip}
-                - Detected Communicating Samples: #{vt_json.detected_communicating_samples.length}
+                - Passive DNS replications:       #{vt_json.resolutions.length}
                 - Detected URLs:                  #{vt_json.detected_urls.length}
                 - Link:                           https://www.virustotal.com/en/ip-address/#{ip}/information/
                 """


fix tests

fix tests

Server doesn't apper to be present. I'll leave it there but add a validation

--- test/alias_test.coffee
+++ test/alias_test.coffee
@@ -42,7 +42,7 @@

   afterEach ->
     do robot.shutdown
-    do robot.server.close
+    do robot.server.close if robot.server
     process.removeAllListeners 'uncaughtException'

   sharedExample = (done, src, dst)->


Avoid writing clipboard data on cut and copy for collapsed selections. Fixes #425

--- src/trix/controllers/input_controller.coffee
+++ src/trix/controllers/input_controller.coffee
@@ -223,16 +223,18 @@
       @draggingPoint = null

     cut: (event) ->
-      if @serializeSelectionToDataTransfer(event.clipboardData)
-        event.preventDefault()
-
-      @delegate?.inputControllerWillCutText()
-      @deleteInDirection("backward")
-      @requestRender() if event.defaultPrevented
+      if @responder?.selectionIsExpanded()
+        if @serializeSelectionToDataTransfer(event.clipboardData)
+          event.preventDefault()
+
+        @delegate?.inputControllerWillCutText()
+        @deleteInDirection("backward")
+        @requestRender() if event.defaultPrevented

     copy: (event) ->
-      if @serializeSelectionToDataTransfer(event.clipboardData)
-        event.preventDefault()
+      if @responder?.selectionIsExpanded()
+        if @serializeSelectionToDataTransfer(event.clipboardData)
+          event.preventDefault()

     paste: (event) ->
       paste = event.clipboardData ? event.testClipboardData


Fix default CSS

Fix default CSS

--- src/trix/core/helpers/custom_elements.coffee
+++ src/trix/core/helpers/custom_elements.coffee
@@ -1,15 +1,24 @@
+defaults =
+  extendsTagName: "div"
+  css: "%t { display: block; }"
+
 Trix.registerElement = (tagName, definition = {}) ->
   tagName = tagName.toLowerCase()
   properties = rewriteFunctionsAsValues(definition)

-  # TODO: Figure out why adding defaultCSS nukes all other styles in demo.css
-  # defaultCSS = properties.defaultCSS ? "%t { display: block }"
-  defaultCSS = "%t { display: block }"
+  extendsTagName = properties.extendsTagName ? defaults.extendsTagName
+  delete properties.extendsTagName
+
+  defaultCSS = properties.defaultCSS
   delete properties.defaultCSS
+
+  if defaultCSS? and extendsTagName is defaults.extendsTagName
+    defaultCSS += "\n#{defaults.css}"
+  else
+    defaultCSS = defaults.css
+
   installDefaultCSSForTagName(defaultCSS, tagName)

-  extendsTagName = properties.extendsTagName ? "div"
-  delete properties.extendsTagName
   extendedPrototype = Object.getPrototypeOf(document.createElement(extendsTagName))
   extendedPrototype.__super__ = extendedPrototype


fix tests

fix tests

--- test/basic-test.coffee
+++ test/basic-test.coffee
@@ -40,7 +40,7 @@
 	atomShellExe += '.exe' if platform is 'win32'
 	testDir = path.join 'tmp', moduleName
 	cmd = """
-		env ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 #{atomShellExe} -e "require('#{moduleName}'); console.log('OK: required #{moduleName}')"
+		env ATOM_SHELL_INTERNAL_RUN_AS_NODE=1 #{atomShellExe} -e "require('./tmp/node_modules/#{moduleName}'); console.log('OK: required #{moduleName}')"
 	"""
 	errMsg = ''
 	child = exec cmd
@@ -138,10 +138,10 @@
 		testInstallMulti 'leveldown@1.0.0'
 		testInstallMulti 'nslog@1.0.1'
 		testInstallMulti 'pathwatcher@2.3.5'
-		# testInstallMulti 'node-sass@1.2.3'
+	##	testInstallMulti 'node-sass@1.2.3'

 	describe 'native module /w node-pre-gyp', ->
-		# testInstallMulti 'nodegit@0.2.4', null, null, compatibility: yes
+	##	testInstallMulti 'nodegit@0.2.4', null, null, compatibility: yes
 	##	testInstallMulti 'node-expat@2.3.3'
 	##	testInstallMulti 'ffi@1.2.7'
 	##	testInstallMulti 'midi@0.9.0'


Remove unnecessary color codes.

Remove unnecessary color codes.

--- test/configfile.coffee
+++ test/configfile.coffee
@@ -18,7 +18,7 @@

     it 'should report a compiler error', (done) ->
       tests.shouldBuildPrompt (err, prompt) ->
-        prompt.should.include "\x1b[41m\x1b[37m Your prompt file is not valid CoffeeScript. \x1b[0m"
+        prompt.should.include "Your prompt file is not valid CoffeeScript."
         done err

   describe 'JavaScript Loading Error', ->
@@ -26,5 +26,5 @@

     it 'should report a compiler error', (done) ->
       tests.shouldBuildPrompt (err, prompt) ->
-        prompt.should.include "\x1b[41m\x1b[37m Your prompt file triggered a JavaScript error. \x1b[0m"
+        prompt.should.include "Your prompt file triggered a JavaScript error."
         done err


Loop backwards to avoid another edge case (better tests coming soon™)

--- src/view/iterator_view.coffee
+++ src/view/iterator_view.coffee
@@ -53,7 +53,7 @@
     if isInDOM
       subview.propagateToSubviews('viewWillAppear') for subview in @appendedViews

-    for subview, index in @subviews.toArray() when subview._targeted
+    for subview, index in @subviews.toArray() by -1 when subview._targeted
       if sibling = @subviews.at(index + 1)?.get('node')
         sibling.parentNode.insertBefore(subview.get('node'), sibling)
       else


remove accidental debug line

remove accidental debug line

--- test/core.tests.coffee
+++ test/core.tests.coffee
@@ -26,7 +26,6 @@
         JSON.stringify(opts)
       ]
       spawnArgs = [spawnArgs[0]] if opts.noargs
-      console.log spawnArgs.join ' '
       mochaPhantomJS = spawn "#{process.cwd()}/phantomjs", spawnArgs
       mochaPhantomJS.stdout.on 'data', (data) -> stdout = stdout.concat data.toString()
       mochaPhantomJS.stderr.on 'data', (data) -> stderr = stderr.concat data.toString()


Add tests for ipv4-flowspec

Add tests for ipv4-flowspec

--- test/gobgp-node.coffee
+++ test/gobgp-node.coffee
@@ -8,6 +8,9 @@
   global_rib = ->
     JSON.parse(exec('gobgp -j global rib'))

+  flowspec_rib = ->
+    JSON.parse(exec('gobgp -j global rib -a ipv4-flowspec'))
+
   communities = (prefix) ->
     table = global_rib()
     paths = table.filter (i) -> i['prefix']==prefix
@@ -16,36 +19,39 @@
     comms = paths[0]['paths'][0]['attrs'].filter (i) -> i['type']==8
     return comms[0]['communities']

+  PREFIX = '10.0.0.0/24'
+  FLOWSPEC_PREFIX = "match source #{PREFIX} then rate-limit 10000"

   beforeEach ->
-    exec 'gobgp global rib del 10.0.0.0/24'
+    exec "gobgp global rib del #{PREFIX}"
+    exec "gobgp global rib -a ipv4-flowspec del #{FLOWSPEC_PREFIX}"

   describe 'family ipv4-unicast', ->
     it 'originates a route', ->
       expect(global_rib()).to.be.empty

-      gobgp.modPath family: 'ipv4-unicast', '10.0.0.0/24'
+      gobgp.modPath family: 'ipv4-unicast', PREFIX

       table = global_rib()
       expect(table.length).to.equal 1
-      expect(table[0]['prefix']).to.equal '10.0.0.0/24'
+      expect(table[0]['prefix']).to.equal PREFIX

     it 'originates a route with BGP community string', ->
       expect(global_rib()).to.be.empty

-      gobgp.modPath family: 'ipv4-unicast', '10.0.0.0/24 community no-advertise'
+      gobgp.modPath family: 'ipv4-unicast', "#{PREFIX} community no-advertise"

       table = global_rib()
       expect(table.length).to.equal 1
-      expect(table[0]['prefix']).to.equal '10.0.0.0/24'
+      expect(table[0]['prefix']).to.equal PREFIX

-      expect(communities('10.0.0.0/24')).to.eql [4294967042]
+      expect(communities(PREFIX)).to.eql [4294967042]

     it 'originates a route with BGP community byte array', ->
       expect(global_rib()).to.be.empty

-      path = gobgp.serializePath('ipv4-unicast', '10.0.0.0/24')
+      path = gobgp.serializePath('ipv4-unicast', PREFIX)
       path.pattrs.push new Buffer([
         0xc0,                      # Optional, Transitive
         0x08,                      # Type Code: Communities
@@ -56,12 +62,12 @@

       table = global_rib()
       expect(table.length).to.equal 1
-      expect(table[0]['prefix']).to.equal '10.0.0.0/24'
+      expect(table[0]['prefix']).to.equal PREFIX

-      expect(communities('10.0.0.0/24')).to.eql [4294967042]
+      expect(communities(PREFIX)).to.eql [4294967042]

-    it 'shows the RIB', ->
-      exec 'gobgp global rib add 10.0.0.0/24'
+    it 'shows the RIB', ->  # TODO: This does actually nothing. Usechai-as-promised
+      exec "gobgp global rib add #{PREFIX}"

       gobgp.getRib family: 'ipv4-unicast', (err, table) ->
         expect(table['type']).to.equal 'GLOBAL'
@@ -69,12 +75,43 @@
         expect(table['destinations'].length).to.equal 1

         path = table['destinations'][0]
-        expect(path['prefix']).to.equal '10.0.0.0/24'
+        expect(path['prefix']).to.equal PREFIX

     it 'withdraws a route', ->
-      exec 'gobgp global rib add 10.0.0.0/24'
+      exec "gobgp global rib add #{PREFIX}"
       expect(global_rib()).not.to.be.empty

-      gobgp.modPath family: 'ipv4-unicast', withdraw: true, '10.0.0.0/24'
+      gobgp.modPath family: 'ipv4-unicast', withdraw: true, PREFIX

       expect(global_rib()).to.be.empty
+
+
+  describe 'family ipv4-flowspec', ->
+    it 'originates a route', ->
+      expect(flowspec_rib()).to.be.empty
+
+      gobgp.modPath family: 'ipv4-flowspec', FLOWSPEC_PREFIX
+
+      table = flowspec_rib()
+      expect(table.length).to.equal 1
+      expect(table[0].prefix).to.equal "[source:#{PREFIX}]"
+
+    it 'shows the RIB', ->  # TODO: This does actually nothing. Usechai-as-promised
+      exec "gobgp global rib -a ipv4-flowspec add #{FLOWSPEC_PREFIX}"
+
+      gobgp.getRib family: 'ipv4-flowspec', (err, table) ->
+        expect(table.type).to.equal 'GLOBAL'
+        expect(table.family).to.equal 65669
+        expect(table.destinations.length).to.equal 1
+
+        path = table.destinations[0]
+        expect(path.prefix).to.equal "[source:#{PREFIX}]"
+        expect(path.paths[0].attrs[2].value[0].rate).to.equal 10000
+
+    it 'withdraws a route', ->
+      exec "gobgp global rib -a ipv4-flowspec add #{FLOWSPEC_PREFIX}"
+      expect(flowspec_rib()).not.to.be.empty
+
+      gobgp.modPath family: 'ipv4-flowspec', withdraw: true, FLOWSPEC_PREFIX
+
+      expect(flowspec_rib()).to.be.empty


comment on dev dependency updater

comment on dev dependency updater


Throw error when using the selector failed

--- src/stateful_widget.js.coffee
+++ src/stateful_widget.js.coffee
@@ -52,6 +52,7 @@
     constructor: ( selector ) ->
       @_uid ?= @_generateUID()
       @$el = $( selector )
+      throw new Error "Unable to select DOM element with selector '#{selector}'" unless @$el.length
       @el = @$el[0]
       @initState @_states[0] if @_states?[0]?
       @_bindEvents()


Use include_test_file everywhere

Use include_test_file everywhere

--- test/mycha_spec.coffee
+++ test/mycha_spec.coffee
@@ -46,8 +46,8 @@
         expect(helper_index).to.be.lessThan second_test_index

       it 'runs all the tests', ->
-        expect(@mocha_argument).to.contain path.resolve 'test_data/two_tests/test/one_test.coffee'
-        expect(@mocha_argument).to.contain path.resolve 'test_data/two_tests/test/two_test.coffee'
+        expect(@mocha_argument).to.include_test_file 'two_tests', 'one_test.coffee'
+        expect(@mocha_argument).to.include_test_file 'two_tests', 'two_test.coffee'

       it 'does not provide any other arguments than listed above plus the done callback', ->
         expect(@mocha_argument.length).to.equal 8
@@ -85,8 +85,8 @@
         expect(helper_index).to.be.lessThan second_test_index

       it 'runs all the tests', ->
-        expect(@mocha_argument).to.contain path.resolve 'test_data/two_tests/test/one_test.coffee'
-        expect(@mocha_argument).to.contain path.resolve 'test_data/two_tests/test/two_test.coffee'
+        expect(@mocha_argument).to.include_test_file 'two_tests', 'one_test.coffee'
+        expect(@mocha_argument).to.include_test_file 'two_tests', 'two_test.coffee'

       it 'does not provide any other arguments than listed above plus the done callback', ->
         expect(@mocha_argument.length).to.equal 8
@@ -124,7 +124,7 @@
         expect(helper_index).to.be.lessThan second_test_index

       it 'runs only the given test', ->
-        expect(@mocha_argument[6]).to.equal path.resolve 'test_data/two_tests/test/two_test.coffee'
+        expect(@mocha_argument).to.include_test_file 'two_tests', 'two_test.coffee'

       it 'does not provide any other arguments than listed above plus the done callback', ->
         expect(@mocha_argument.length).to.equal 8


:art: cleanup and use native classList.toggle

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,10 +1,4 @@
 {CompositeDisposable} = require 'atom'
-
-getEditor = ->
-  atom.workspace.getActiveTextEditor()
-
-getView = (model) ->
-  atom.views.getView(model)

 OverwriteConfig = 'vim-mode-plus-move-selected-text.overwrite'
 OverwriteClass = 'vim-mode-plus-move-selected-text-overwrite'
@@ -18,19 +12,19 @@

   eachEditorElement: (fn) ->
     atom.workspace.getTextEditors().forEach (editor) ->
-      fn(getView(editor))
+      fn(atom.views.getView(editor))

   activate: ->
     @subscriptions = new CompositeDisposable

     @subscribe atom.config.observe OverwriteConfig, (newValue) =>
       @eachEditorElement (editorElement) ->
-        editorElement.classList.remove(OverwriteClass)
-        editorElement.classList.add(OverwriteClass) if newValue
+        editorElement.classList.toggle(OverwriteClass, newValue)

     @subscribe atom.commands.add 'atom-text-editor',
       'vim-mode-plus-user:toggle-overwrite': ->
-        atom.config.set(OverwriteConfig, not atom.config.get(OverwriteConfig))
+        newValue = not atom.config.get(OverwriteConfig)
+        atom.config.set(OverwriteConfig, newValue)

   deactivate: ->
     @subscriptions?.dispose()


update

update

--- src/tex-writer-columns.coffee
+++ src/tex-writer-columns.coffee
@@ -210,7 +210,6 @@
   # if column_count isnt 1
   [ ..., meta, ]  = event
   ### TAINT this event should be namespaced and handled only right before output ###
-  debug '8871112', [ '(', 'multi-columns', [ column_count, ], ( copy meta ), ]
   unless meta[ 'multi-columns' ] is 'omit-open'
     send [ '(', 'multi-columns', [ column_count, ], ( copy meta ), ]
   return null


style: Simplify expression

style: Simplify expression

--- src/transaction-runner.coffee
+++ src/transaction-runner.coffee
@@ -455,9 +455,7 @@
     for key, value of transaction.request.headers
       caseInsensitiveRequestHeadersMap[key.toLowerCase()] = key

-    if not caseInsensitiveRequestHeadersMap['content-length'] and
-        transaction.request['body']? and
-        transaction.request['body'] != ''
+    if transaction.request.body and not caseInsensitiveRequestHeadersMap['content-length']
       logger.verbose('Calculating Content-Length of the request body')
       transaction.request.headers['Content-Length'] = Buffer.byteLength(transaction.request['body'], 'utf8')


Exposes insertAttachments function in editor model

--- src/trix/models/editor.coffee
+++ src/trix/models/editor.coffee
@@ -41,6 +41,9 @@

   insertAttachment: (attachment) ->
     @composition.insertAttachment(attachment)
+
+  insertAttachments: (attachments) ->
+    @composition.insertAttachments(attachments)

   insertDocument: (document) ->
     @composition.insertDocument(document)


fix titles

fix titles

--- HTML/osx.coffee
+++ HTML/osx.coffee
@@ -68,7 +68,7 @@
         sender: 'editor'

   title: (text) ->
-    Chrome.activeWindow().setTitle text
+    App.window.title = text

   toggleFullscreen: ->
     if Chrome.fullscreen?


cleanup

cleanup

--- assets/javascripts/audio.js.coffee
+++ assets/javascripts/audio.js.coffee
@@ -52,32 +52,3 @@
   window.audio2 = document.getElementsByTagName("audio")[1]
   player = new Player(10)
   player.play()
-  #audio1.load()
-  #audio1.play()
-  #audio.pause()
-
-  #$display = $("#display-samples")
-  #lines = []
-  #window.writeSamples = (event) ->
-  #  lines.push "#{event.frameBuffer[0]}, #{event.frameBuffer[1]}, #{event.frameBuffer[2]}"
-  #  lines.shift() if lines.length > 20
-  #  $display.html(lines.join("<br>"))
-
-  #audio.addEventListener("MozAudioAvailable", writeSamples, false)
-
-  #vol = 1
-  #interval = 600
-
-  #fadeout = setInterval ->
-  #  if vol > 0
-  #    vol -= 0.05
-  #    vol = if vol < 0 then 0 else vol
-  #    audio1.volume = vol
-  #  else
-  #    clearInterval(fadeout)
-  #  if vol < 0.4 && audio2.paused
-  #    console.log "audio2 start was called"
-  #    audio2.volume = 1
-  #    audio2.play()
-  #  console.log "#{vol} #{fadeout}"
-  #, interval


remove unused line

remove unused line

--- public/fav-client.coffee
+++ public/fav-client.coffee
@@ -165,8 +165,6 @@
     view = new Tweets(item: fav)
     el = view.render().el
     @items.append(el)
-    # adjust height
-    # $(el).height (Math.floor($(el).height() / $(el).width()) + 1) * $(el).width() - 16
     $(@items).masonry("appended", el).masonry('reload')

   moreFavs: =>


Update Gruntfile.coffee

Update Gruntfile.coffee

--- presentation/Gruntfile.coffee
+++ presentation/Gruntfile.coffee
@@ -76,7 +76,7 @@
                 },{
                     expand: true
                     src: ['index.html']
-                    dest: 'dist/'
+                    dest: '../docs/'
                     filter: 'isFile'
                 }]


use Promise.resolve syntax

use Promise.resolve syntax

--- lib/sync.coffee
+++ lib/sync.coffee
@@ -13,19 +13,17 @@
     utils.readFile(path.join(srcDir, ".git", ref)).then (file)->
       sha = file.split("\n")[0]
       #is there a better way to combine the data from these two promises?
-      return new Promise (resolve, reject)->
-        resolve {ref, sha}
+      Promise.resolve {ref, sha}

 #last syncer commit hash
 getSyncerHead = (srcDir)->
   utils.cmd(srcDir, "git show-ref --hash syncer/head").then ({stdout, stderr})->
-    return new Promise (resolve, reject)->
-      resolve(stdout.split("\n")[0])
+    return Promise.resolve (stdout.split("\n")[0])
   , ({stdout, stderr})-> #if ref doesn't exist just return a promise that resolves to null
     console.log stdout if stdout
     console.error stderr if stderr
-    return new Promise (resolve, reject)->
-      resolve null
+    Promise.resolve null
+

 commitWorkingDir = (parentCommit, message, srcDir)->
   # create a fake commit w/ last known user commit and working branch encoded in message
@@ -35,8 +33,7 @@
       command = "git commit-tree #{treeHash} -p #{parentCommit} -m \"#{message}\"\n"
       utils.cmd(srcDir, command).then ({stdout, stderr})->
         commitHash = stdout.split("\n")[0]
-        return new Promise (resolve, reject)->
-          resolve commitHash
+        Promise.resolve commitHash

 # Two kinds of syncs
 # a) new branch (first time syncing to branch or just switched branches)


Added compiler to App.Appnima.Payment extension

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -66,6 +66,9 @@
           user:
             coffee: '<%=folder.app%>extension/appnima/user/**/*.coffee'
             stylus: '<%=folder.app%>extension/appnima/user/style/*.styl'
+          payment:
+            coffee: '<%=folder.app%>extension/appnima/payment/**/*.coffee'
+            stylus: '<%=folder.app%>extension/appnima/payment/style/*.styl'
         carousel:
           coffee: '<%=folder.app%>extension/carousel/**/*.coffee'
           stylus: '<%=folder.app%>extension/carousel/style/*.styl'
@@ -89,29 +92,31 @@
     # TASKS
     # ==========================================================================
     concat:
-      core              : files: '<%=folder.build%>core.coffee'                 : '<%= core.coffee %>'
-      # App
-      app               : files: '<%=folder.build%>app.coffee'                  : '<%= app.coffee %>'
-      app_appnima_user  : files: '<%=folder.build%>app.appnima.user.coffee'     : '<%= app.extension.appnima.user.coffee %>'
-      app_carousel      : files: '<%=folder.build%>app.carousel.coffee'         : '<%= app.extension.carousel.coffee %>'
-      app_gmaps         : files: '<%=folder.build%>app.gmaps.coffee'            : '<%= app.extension.gmaps.coffee %>'
-      app_stripe        : files: '<%=folder.build%>app.stripe.coffee'           : '<%= app.extension.stripe.coffee %>'
-      app_chart        : files: '<%=folder.build%>app.chart.coffee'             : '<%= app.extension.chart.coffee %>'
+      core                : files: '<%=folder.build%>core.coffee'                 : '<%= core.coffee %>'
+      # App
+      app                 : files: '<%=folder.build%>app.coffee'                  : '<%= app.coffee %>'
+      app_appnima_user    : files: '<%=folder.build%>app.appnima.user.coffee'     : '<%= app.extension.appnima.user.coffee %>'
+      app_appnima_payment : files: '<%=folder.build%>app.appnima.payment.coffee'  : '<%= app.extension.appnima.payment.coffee %>'
+      app_carousel        : files: '<%=folder.build%>app.carousel.coffee'         : '<%= app.extension.carousel.coffee %>'
+      app_gmaps           : files: '<%=folder.build%>app.gmaps.coffee'            : '<%= app.extension.gmaps.coffee %>'
+      app_stripe          : files: '<%=folder.build%>app.stripe.coffee'           : '<%= app.extension.stripe.coffee %>'
+      app_chart           : files: '<%=folder.build%>app.chart.coffee'            : '<%= app.extension.chart.coffee %>'
       # Test
-      test              :   files: '<%=folder.build%>test.coffee'               : '<%= core.test %>'
+      test                :   files: '<%=folder.build%>test.coffee'               : '<%= core.test %>'

     coffee:
-      core              : files: '<%=folder.build%>core.js'                     : '<%=folder.build%>core.coffee'
-      spec              : files: '<%=folder.build%>spec.js'                     : '<%= core.spec %>'
-      # App
-      app               : files: '<%=folder.build%>app.js'                      : '<%=folder.build%>app.coffee'
-      app_appnima_user  : files: '<%=folder.build%>app.appnima.user.js'         : '<%=folder.build%>app.appnima.user.coffee'
-      app_carousel      : files: '<%=folder.build%>app.carousel.js'             : '<%=folder.build%>app.carousel.coffee'
-      app_gmaps         : files: '<%=folder.build%>app.gmaps.js'                : '<%=folder.build%>app.gmaps.coffee'
-      app_stripe        : files: '<%=folder.build%>app.stripe.js'               : '<%=folder.build%>app.stripe.coffee'
-      app_chart        : files: '<%=folder.build%>app.chart.js'                 : '<%=folder.build%>app.chart.coffee'
+      core                : files: '<%=folder.build%>core.js'                     : '<%=folder.build%>core.coffee'
+      spec                : files: '<%=folder.build%>spec.js'                     : '<%= core.spec %>'
+      # App
+      app                 : files: '<%=folder.build%>app.js'                      : '<%=folder.build%>app.coffee'
+      app_appnima_user    : files: '<%=folder.build%>app.appnima.user.js'         : '<%=folder.build%>app.appnima.user.coffee'
+      app_appnima_payment : files: '<%=folder.build%>app.appnima.payment.js'      : '<%=folder.build%>app.appnima.payment.coffee'
+      app_carousel        : files: '<%=folder.build%>app.carousel.js'             : '<%=folder.build%>app.carousel.coffee'
+      app_gmaps           : files: '<%=folder.build%>app.gmaps.js'                : '<%=folder.build%>app.gmaps.coffee'
+      app_stripe          : files: '<%=folder.build%>app.stripe.js'               : '<%=folder.build%>app.stripe.coffee'
+      app_chart           : files: '<%=folder.build%>app.chart.js'                : '<%=folder.build%>app.chart.coffee'
       # Test
-      test              : files: '<%=folder.build%>test.js'                     : '<%=folder.build%>test.coffee'
+      test                : files: '<%=folder.build%>test.js'                     : '<%=folder.build%>test.coffee'

     uglify:
       options:  banner: "<%= meta.banner %>"#, report: "gzip"
@@ -125,6 +130,9 @@
       app_appnima_user:
         options: mangle: false
         files: '<%=folder.app%>extension/appnima/user/<%=pkg.name%>.app.appnima.user.js': '<%=folder.build%>app.appnima.user.js'
+      app_appnima_payment:
+        options: mangle: false
+        files: '<%=folder.app%>extension/appnima/payment/<%=pkg.name%>.app.appnima.payment.js': '<%=folder.build%>app.appnima.payment.js'
       app_carousel:
         options: mangle: false
         files: '<%=folder.app%>extension/carousel/<%=pkg.name%>.app.carousel.js': '<%=folder.build%>app.carousel.js'
@@ -165,6 +173,9 @@
       app_appnima_user:
         options: compress: true
         files: '<%=folder.app%>extension/appnima/user/<%=pkg.name%>.app.appnima.user.css' : '<%=app.extension.appnima.user.stylus%>'
+      app_appnima_payment:
+        options: compress: true
+        files: '<%=folder.app%>extension/appnima/payment/<%=pkg.name%>.app.appnima.payment.css' : '<%=app.extension.appnima.payment.stylus%>'
       app_carousel:
         options: compress: true
         files: '<%=folder.app%>extension/carousel/<%=pkg.name%>.app.carousel.css': '<%=app.extension.carousel.stylus%>'
@@ -218,6 +229,9 @@
       app_appnima_user:
         files: ['<%= app.extension.appnima.user.coffee %>']
         tasks: ['concat:app_appnima_user', 'coffee:app_appnima_user', 'uglify:app_appnima_user']
+      app_appnima_payment:
+        files: ['<%= app.extension.appnima.payment.coffee %>']
+        tasks: ['concat:app_appnima_payment', 'coffee:app_appnima_payment', 'uglify:app_appnima_payment']
       app_carousel:
         files: ['<%= app.extension.carousel.coffee %>']
         tasks: ['concat:app_carousel', 'coffee:app_carousel', 'uglify:app_carousel']
@@ -233,6 +247,9 @@
       app_appnima_user_stylus:
         files: ['<%= app.extension.appnima.user.stylus %>']
         tasks: ['stylus:app_appnima_user']
+      app_appnima_payment_stylus:
+        files: ['<%= app.extension.appnima.payment.stylus %>']
+        tasks: ['stylus:app_appnima_payment']
       app_carousel_stylus:
         files: ['<%= app.extension.carousel.stylus %>']
         tasks: ['stylus:app_carousel']


Changes on grunt file (now with uglify with mangle)

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -54,21 +54,24 @@

     uglify:
-      options: compress: false, banner: "<%= meta.banner %>"
+      options:
+        report: "gzip"
+        mangle: false
+        banner: "<%= meta.banner %>"
       core: files: '<%=meta.bower%>/<%=pkg.name%>.js': '<%=meta.build%>/<%=pkg.name%>.debug.js'
       organisms: files: '<%=meta.bower%>/<%=pkg.name%>.organisms.js': '<%=meta.build%>/<%=pkg.name%>.organisms.js'
       templates: files: '<%=meta.bower%>/<%=pkg.name%>.templates.js': '<%=meta.build%>/<%=pkg.name%>.templates.js'

     jasmine:
-        pivotal:
-          src: [
-            '<%=meta.build%>/<%=pkg.name%>.debug.js',
-            '<%=meta.build%>/<%=pkg.name%>.organisms.js',
-            '<%=meta.build%>/<%=pkg.name%>.templates.js']
-          options:
-            vendor: 'spec/components/jquery/jquery.min.js'
-            specs: '<%=meta.build%>/<%=pkg.name%>.spec.js',
+      pivotal:
+        src: [
+          '<%=meta.build%>/<%=pkg.name%>.debug.js',
+          '<%=meta.build%>/<%=pkg.name%>.organisms.js',
+          '<%=meta.build%>/<%=pkg.name%>.templates.js']
+        options:
+          vendor: 'spec/components/jquery/jquery.min.js'
+          specs: '<%=meta.build%>/<%=pkg.name%>.spec.js',

     stylus:
@@ -84,6 +87,7 @@
       icons:
         options: compress: false
         files: '<%=meta.bower%>_icons/<%=pkg.name%>.icons.css': '<%=source.stylus.icons%>'
+

     watch:
       core:
@@ -114,6 +118,7 @@
         files: ['<%= source.stylus.icons %>']
         tasks: ['stylus:icons']

+
   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-contrib-uglify'


add new function test

add new function test

--- test/test_scfes.coffee
+++ test/test_scfes.coffee
@@ -27,6 +27,34 @@
       multiple_recovery_time = @scfes.getMultipleRecoveryTime(10, 80, 25)
       expect(multiple_recovery_time).to.eql([15*6*60, 25*6*60, 25*6*60, 5*6*60])
       done()
+
+  describe "getExpFromDifficulty", ->
+    beforeEach (done) ->
+      @scfes = new HubotScfes
+      @clock = sinon.useFakeTimers(0, "setTimeout", "clearTimeout", "setInterval", "clearInterval", "Date")
+      done()
+
+    it.skip "not set is expert", (done) ->
+      assert.equal @scfes.getExpFromDifficulty(), 83.0
+      done()
+
+    it.skip "expert", (done) ->
+      assert.equal @scfes.getExpFromDifficulty("expert"), 83.0
+      done()
+
+    it.skip "hard", (done) ->
+      assert.equal @scfes.getExpFromDifficulty("hard"), 46.0
+      done()
+
+
+    it.skip "normal", (done) ->
+      assert.equal @scfes.getExpFromDifficulty("normal"), 26.0
+      done()
+
+    it.skip "easy", (done) ->
+      assert.equal @scfes.getExpFromDifficulty("easy"), 12.0
+      done()
+

   describe "remindMultipleRecoveryTime", ->
     beforeEach (done) ->
@@ -91,8 +119,8 @@
       done()

     describe "correct return date", ->
-      it "expart", (done) ->
-        #e expart is 83 exp
+      it "expert", (done) ->
+        #e expert is 83 exp
         date = @scfes.getNextLevelupTime(830 + 50, "ex")
         expect(date).to.eql(new Date(6 * 60 * 25 * 11 * 1000))
         done()


Fixing the docs :)

Fixing the docs :)

--- src/scripts/puppetdb.coffee
+++ src/scripts/puppetdb.coffee
@@ -2,8 +2,8 @@
 #   PuppetDB integration with hubot
 #
 # Commands:
-#   hubot rundeck show status in [environment]   - Shows the current status statistics
-#   hubot rundeck show stats in [environment]    - Shows the current resource/node statistics
+#   hubot puppetdb show status in [environment]   - Shows the current status statistics
+#   hubot puppetdb show stats in [environment]    - Shows the current resource/node statistics
 #   hubot puppetdb show aliases                  - shows the aliases for the list of puppetboard instances
 #   hubot puppetdb add alias [alias name] [url]  - sets the alias for a given url
 #   hubot puppetdb clear alias [alias name]      - removed the given alias


Complete specs for Platforms#_generateTiles subroutines.

--- tests/platforms.coffee
+++ tests/platforms.coffee
@@ -188,3 +188,17 @@

         expect(vars.iLedgeRow).toBe 1
         expect(vars.prevFacing).toBe 'left'
+
+    describe '#_setupEachRow', ->
+      vars = null
+
+      beforeEach -> vars = { iLedgeLayer: 0 }
+
+      it 'resets row tiles for upcoming row only on first ledge layer', ->
+        platforms._setupEachRow vars
+        expect(vars.rowTiles).toEqual []
+
+        vars.iLedgeLayer++
+        vars.rowTiles.push Platforms.Tile.Solid for c in [0...13]
+        platforms._setupEachRow vars
+        expect(vars.rowTiles).not.toEqual []


Ensure `postId` session variable is set before rendering blog edit route.

--- router.coffee
+++ router.coffee
@@ -130,7 +130,7 @@
         return @redirect('/blog')

     Session.set 'postId', @params.id
-    @next()
+    @next() if Session.get("postId").length?
   action: ->
     @render() if @ready()
   waitOn: -> [


Tell people to include a link anyways in support requests...

--- src/smc-webapp/support.cjsx
+++ src/smc-webapp/support.cjsx
@@ -508,6 +508,9 @@
                     value       = {@props.body}
                     onChange    = {@data_change} />
             </FormGroup>
+

+                Include a link (the URL in your browser) to absolutely anything relevant to your question.
+

         </form>


remove the parent
that doens't sound right...

Signed-off-by: Jessica González <52329a27ea5670aeec0efeeb0773bf1b4f1affa1@missallsunday.com>

--- src/summernoteDrafts.coffee
+++ src/summernoteDrafts.coffee
@@ -148,8 +148,7 @@
           else
             alert lang.noDraft
           false
-        return
-      return
+
       $deleteDraft = @$dialog.find 'a.delete-draft'
         .click (e) ->
           if confirm lang.youSure
@@ -160,11 +159,11 @@
             if data
               store.remove key
               self = $ this
-              self.hide 'slow', ->
-                self.remove()
-                alert lang.deleted
+              self.parent().hide 'slow', ->
+                $(this).remove()
                 return

             else
               alert lang.noDraft
+      return
     return


tweaks to scope

tweaks to scope

--- scope.coffee
+++ scope.coffee
@@ -18,20 +18,20 @@
   # where it should declare its variables, and a reference to the function that
   # it wraps.
   constructor: (@parent, @expressions, @method) ->
-    @variables = [{name: 'arguments', type: 'arguments'}]
+    @variables = []
     @positions = {}
     if @parent
-      {@garbage} = @parent
+      @garbage = @parent.garbage
     else
       @garbage   = []
       Scope.root = this
-
+
   # Adds a new variable or overrides an existing one.
-  setVar: (name, type) ->
+  add: (name, type) ->
     if @positions.hasOwnProperty name
       @variables[@positions[name]].type = type
     else
-      @positions[name] = -1 + @variables.push {name, type}
+      @positions[name] = @variables.push({name, type}) - 1
     this

   # Create a new garbage level
@@ -42,14 +42,14 @@
   # Return to the previous garbage level and erase referenced temporary
   # variables in current level from scope.
   endLevel: ->
-    @setVar name, 'reuse' for name in @garbage.pop() when @type(name) is 'var'
+    @add name, 'reuse' for name in @garbage.pop() when @type(name) is 'var'
     this

   # Look up a variable name in lexical scope, and declare it if it does not
   # already exist.
   find: (name, options) ->
     return true if @check name, options
-    @setVar name, 'var'
+    @add name, 'var'
     false

   # Test variables and return `true` the first time `fn(v)` returns `true`
@@ -60,7 +60,7 @@
   # Reserve a variable name as originating from a function parameter for this
   # scope. No `var` required for internal references.
   parameter: (name) ->
-    @setVar name, 'param'
+    @add name, 'param'

   # Just check to see if a variable has already been declared, without reserving,
   # walks up to the root scope.
@@ -75,25 +75,25 @@
       '_' + name + if index > 1 then index else ''
     else
       '_' + (index + parseInt name, 36).toString(36).replace /\d/g, 'a'
-
+
   # Gets the type of a variable.
   type: (name) ->
     for v in @variables when v.name is name then return v.type
     null
-
+
   # If we need to store an intermediate result, find an available name for a
   # compiler-generated variable. `_var`, `_var2`, and so on...
   freeVariable: (type) ->
     index = 0
     index++ while @check(temp = @temporary type, index) and @type(temp) isnt 'reuse'
-    @setVar temp, 'var'
+    @add temp, 'var'
     last(@garbage)?.push temp
     temp

   # Ensure that an assignment is made at the top of this scope
   # (or at the top-level scope, if requested).
   assign: (name, value) ->
-    @setVar name, value: value, assigned: true
+    @add name, value: value, assigned: true

   # Does this scope reference any variables that need to be declared in the
   # given function body?


#161855482 fix checkConditionsAndHideShow method params

--- app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
@@ -64,7 +64,7 @@
           if $repeater.length > 0
               inRepeater = true
           if rule.conditions.length > 1
-            self.checkConditionsAndHideShow(rule.conditions, ancestorId, $ruleContainer, $ruleContainer, inRepeater, matchType)
+            self.checkConditionsAndHideShow(rule.conditions, ancestorId, $ruleContainer, $ruleContainer, inRepeater, matchType, rule)
           else if rule.type == "Hanuman::VisibilityRule"
             self.hideShowQuestions(hideQuestions, ancestorId, $ruleContainer, $ruleContainer, inRepeater)

@@ -92,7 +92,7 @@
           #$container = $(this).closest(".form-container-repeater")
           $container = $ruleElement
           rules = $.parseJSON($ruleElement.attr("data-rule"))
-          $(rules).each ->
+          $(rules).each ->
             rule = this
             matchType = rule.match_type
             questionId = $triggerElement.closest('.form-container-entry-item').attr('data-question-id')
@@ -101,7 +101,7 @@
             matchingCondition = _.where(conditions, {question_id: Number(questionId)})
             if matchingCondition.length > 0
               if conditions.length > 1
-                self.checkConditionsAndHideShow(conditions, ancestorId, $ruleElement, $container, inRepeater, matchType)
+                self.checkConditionsAndHideShow(conditions, ancestorId, $ruleElement, $container, inRepeater, matchType, rule)
               else
                 hideQuestions = self.setHideQuestions(conditions[0], $triggerElement)
                 if rule.type == "Hanuman::VisibilityRule"
@@ -113,7 +113,7 @@
           $ruleElement = $(this)
           $container = $ruleElement
           rules = $.parseJSON($ruleElement.attr("data-rule"))
-          $(rules).each ->
+          $(rules).each ->
             rule = this
             matchType = rule.match_type
             questionId = $triggerElement.closest('.form-container-entry-item').attr('data-question-id')
@@ -122,12 +122,12 @@
             matchingCondition = _.where(conditions, {question_id: Number(questionId)})
             if matchingCondition.length > 0
               if conditions.length > 1
-                self.checkConditionsAndHideShow(conditions, ancestorId, $ruleElement, $container, inRepeater, matchType, rule.type)
+                self.checkConditionsAndHideShow(conditions, ancestorId, $ruleElement, $container, inRepeater, matchType, rule)
               else
                 hideQuestions = self.setHideQuestions(conditions[0], $triggerElement)
                 if rule.type == "Hanuman::VisibilityRule"
                   self.hideShowQuestions(hideQuestions, ancestorId, $ruleElement, $container, inRepeater)
-                else if hideQuestions == false
+                else if hideQuestions == false
                   self.setLookupValue(rule.value, $ruleElement)
     return

@@ -164,7 +164,7 @@
       else
         # if one false then hide the conditioanl logic
         hideShow = true
-
+
     if rule.type == "Hanuman::VisibilityRule"
       self.hideShowQuestions(hideShow, ancestorId, $ruleElement, $container, inRepeater)
     else if hideShow == false
@@ -172,25 +172,25 @@

   setLookupValue: (value, $ruleElement) ->
-    answerType = $ruleElement.data('element-type')
-
+    answerType = $ruleElement.data('element-type')
+
     switch answerType
       when 'radio'
         $ruleElement.find('input[type="radio"][value="' + value + '"]').prop("checked", true)
-
+
       when 'checkbox'
         $ruleElement.find('input[type="checkbox"]').prop("checked", true)
-
+
       when 'checkboxes'
         selectedOptions = value.split(",")
-        $ruleElement.find('input[type="checkbox"]').each ->
+        $ruleElement.find('input[type="checkbox"]').each ->
           if selectedOptions.indexOf($(this).attr('value')) != -1
             $(this).prop("checked", true)

       when 'chosenmultiselect'
         selectedOptions = value.split(",")
         $ruleElement.find('input[type="select"]').val(selectedOptions).trigger('chosen:updated');
-
+
       when 'chosenselect'
         $ruleElement.find('input[type="select"]').val(value).trigger('chosen:updated');

@@ -199,12 +199,12 @@

       when 'date', 'number', 'text', 'time'
         $ruleElement.find('input[type="text"]').val(value)
-
+
       when 'textarea'
         $ruleElement.find('textarea').val(value)
-
-
-
+
+
+

   #setHideQuestions variable
   setHideQuestions: (condition, $triggerElement) ->
@@ -254,17 +254,17 @@
     #TODO set these to default values once we implement default values - kdh
     # container.find("input[type!=hidden]").val("")
     textFields = container.find(":text")
-    textFields.each ->
+    textFields.each ->
       if $(this).attr("data-default-answer") && $(this).data("default-answer") != "null"
         $(this).val($(this).data("default-answer"))
-      else
+      else
         $(this).val("")

     textAreas = container.find("textarea")
-    textAreas.each ->
+    textAreas.each ->
       if $(this).attr("data-default-answer") && $(this).data("default-answer") != "null"
         $(this).val($(this).data("default-answer"))
-      else
+      else
         $(this).val("")

     # un-select dropdown
@@ -272,7 +272,7 @@
     selects.each ->
       if $(this).attr("data-default-answer") && $(this).data("default-answer") != "null"
         $(this).val($(this).data("default-answer"))
-      else
+      else
         $(this).val("")

       $(this).trigger("chosen:updated") if $(this).hasClass('chosen')
@@ -282,7 +282,7 @@
     checkboxes.each ->
       if $(this).attr("data-default-answer") && $(this).data("default-answer") == "true"
         $(this).prop('checked', true)
-      else
+      else
         $(this).prop('checked', false)

     # un-select radio buttons
@@ -290,7 +290,7 @@
     radiobuttons.each ->
       if $(this).attr("data-default-answer") && $(this).data("default-answer") != "null" && $(this).data("label-value") == $(this).data("default-answer")
         $(this).prop('checked', true)
-      else
+      else
         $(this).prop('checked', false)

     multiselects = container.find("select[multiple]")


Render button state via events.

Render button state via events.

--- app/assets/javascripts/modules/timelet/views/items/clock.js.coffee
+++ app/assets/javascripts/modules/timelet/views/items/clock.js.coffee
@@ -20,8 +20,9 @@
   initialize: ->
     @model.set timer: @model.get('duration')
     @listenTo @model, 'change:timer', @renderTimer
+    @listenTo @model, 'change:running', @renderPlayButton

-  # Starts a timer with the value stored in the model.
+  # Starts or pauses a timer with the value stored in the model.
   #
   # @param [jQuery.Event] event the click event
   #
@@ -29,11 +30,10 @@
     if @running
       clearInterval @running
       delete @running
-      @ui.start.text '\uF04B'
-      return
-
-    @ui.start.text '\uF04C'
-    @running = setInterval @tick, 1000
+      @model.set 'running', false
+    else
+      @running = setInterval @tick, 1000
+      @model.set 'running', true

   # Start editing the name of the timelet.
   #
@@ -65,3 +65,6 @@
   #
   renderTimer: =>
     @ui.timer.text @model.get('timer')
+
+  renderPlayButton: =>
+    @ui.start.text if @running then '\uF04C' else '\uF04B'


making checkboxcolumn working when grid is not editable

--- app/assets/javascripts/netzke-extension/selection_column.js.coffee
+++ app/assets/javascripts/netzke-extension/selection_column.js.coffee
@@ -24,6 +24,7 @@
         if this.selected.items.indexOf(record) == -1
           this.select record, true
         else this.deselect record
+        view.viewReady = true
         view.refreshNode recordIndex
       false
     else @callParent arguments


Scroll: disabled pointer-events hack

Scroll: disabled pointer-events hack

--- core/KDWindowController.coffee
+++ core/KDWindowController.coffee
@@ -69,12 +69,15 @@
       {body} = document
       _.throttle (event)=>
         @emit "ScrollHappened", event
-        clearTimeout timer
-        unless body.classList.contains 'onscroll'
-          body.classList.add 'onscroll'
-
-        timer = KD.utils.wait 400, ->
-          body.classList.remove 'onscroll'
+        # commented out to see the current performance
+        # w/o pointer-events hack
+
+        # clearTimeout timer
+        # unless body.classList.contains 'onscroll'
+        #   body.classList.add 'onscroll'
+
+        # timer = KD.utils.wait 400, ->
+        #   body.classList.remove 'onscroll'
       , 50
     , no


KodingAppsController: putAppScripts: fix onLoad issues

--- client/Main/kodingappscontroller.coffee
+++ client/Main/kodingappscontroller.coffee
@@ -28,23 +28,25 @@
     style        = new KDCustomHTMLView
       tagName    : "link"
       cssClass   : "internal-app-#{name}"
+      bind       : 'load'
+      load       : ->
+        log "Style loaded? for #{name} # don't trust this ..."
       attributes :
         rel      : "stylesheet"
         href     : getStyleUrl name
-        onload   : KD.utils.defer ->
-          log "Style loaded? for #{name} # don't trust this ..."
-
-    style.appendToSelector 'head'
+
+    $('head')[0].appendChild style.getElement()

     script       = new KDCustomHTMLView
       tagName    : "script"
       cssClass   : "internal-app-#{name}"
+      bind       : 'load'
+      load       : -> callback null
       attributes :
         type     : "text/javascript"
         src      : getScriptUrl name
-        onload   : KD.utils.defer -> callback null
-
-    script.appendToSelector 'head'
+
+    $('head')[0].appendChild script.getElement()

   @manifests = {}


Reset product item value when quantity of bid is changed

--- app/assets/javascripts/app/controllers/people/affairs/products.js.coffee
+++ app/assets/javascripts/app/controllers/people/affairs/products.js.coffee
@@ -99,6 +99,8 @@
     'click a[name="cancel"]': 'cancel'
     'click button[name=person-affair-product-destroy]': 'destroy'
     'click button[name=reset_value]': 'reset_value'
+    'change #person_affair_product_bid_percentage': 'clear_value'
+    'change #person_affair_product_quantity': 'clear_value'

   constructor: ->
     super
@@ -151,6 +153,10 @@
   reset_value: (e) ->
     e.preventDefault()
     @el.find("#person_affair_product_value").val @product.computed_value
+
+  clear_value: (e) ->
+    e.preventDefault()
+    @el.find("#person_affair_product_value").val null

 class Index extends App.ExtendedController
   events:


ApplicationTabHandleHolder: Now plusHandle become optional. Default is true to remain backward compatibility.

--- client/app/CommonViews/applicationview/applicationtabhandleholder.coffee
+++ client/app/CommonViews/applicationview/applicationtabhandleholder.coffee
@@ -1,16 +1,17 @@
 class ApplicationTabHandleHolder extends KDView
   constructor: (options = {}, data) ->

-    options.cssClass ?= "application-tab-handle-holder"
-    options.bind      = "mouseenter mouseleave"
+    options.cssClass      or= "application-tab-handle-holder"
+    options.bind            = "mouseenter mouseleave"
+    options.addPlusHandle  ?= yes

     super options, data

-    @on 'PlusHandleClicked', =>
-      @getDelegate().addNewTab()
+    if options.addPlusHandle
+      @on 'PlusHandleClicked', => @getDelegate().addNewTab()

   viewAppended: ->
-    @addPlusHandle()
+    @addPlusHandle()  if @getOptions().addPlusHandle

   addPlusHandle: ->
     @addSubView @plusHandle = new KDCustomHTMLView
@@ -22,4 +23,4 @@

   repositionPlusHandle: (handles) ->
     handlesLength = handles.length
-    @plusHandle.$().insertAfter handles[handlesLength - 1].$() if handlesLength+    @plusHandle?.$().insertAfter handles[handlesLength - 1].$() if handlesLength


Ctrl+Alt+T fix

Ctrl+Alt+T fix

--- client/ide/views/tabview/ideview.coffee
+++ client/ide/views/tabview/ideview.coffee
@@ -123,21 +123,18 @@

   createTerminal: (options) ->

-    { machine, path, session, joinUser, hash } = options
-    { appManager } = KD.singletons
-    frontApp       = appManager.getFrontApp()
-    machine       ?= frontApp.mountedMachine
-
-    unless machine
-      { machines } = KD.getSingleton 'computeController'
-      machineId  = frontApp.mountedMachineUId
-
-    unless path
+    { appManager }   = KD.singletons
+    frontApp         = appManager.getFrontApp()
+    options.machine ?= frontApp.mountedMachine
+
+    unless options.path
       workspaceData = frontApp.workspaceData or {}
       { rootPath, isDefault } = workspaceData

       if rootPath and not isDefault
-        path = frontApp.workspaceData.rootPath
+        options.path = frontApp.workspaceData.rootPath
+
+    { machine, joinUser } = options

     terminalPane = new IDE.TerminalPane options
     @createPane_ terminalPane, { name: 'Terminal' }


Prevent loading the error monitor in nodejs.

--- client/src/scripts/error-monitor.coffee
+++ client/src/scripts/error-monitor.coffee
@@ -1,9 +1,11 @@
 Steam.ErrorMonitor = (_) ->
-
-  if window
-    window.onerror = (message, url, lineNumber) ->
-      _.fatal message,
-        url: url
-        lineNumber: lineNumber
+  window.onerror = (message, url, lineNumber) ->
+    _.fatal message,
+      url: url
+      lineNumber: lineNumber

+
+
+
+


force re-fetch resources (client side)

force re-fetch resources (client side)

so that you always have the latest version

--- app/assets/javascripts/mixins/async_model_route_mixin.js.coffee
+++ app/assets/javascripts/mixins/async_model_route_mixin.js.coffee
@@ -1,7 +1,7 @@
 Bandango.AsyncModelRouteMixin = Ember.Mixin.create
   asyncModelPromise: (->
     @controller.get("store").findAll @get("asyncModel")
-  ).property()
+  ).property().volatile() # has to be evaluated always

   fetchAsyncModel: ->
     @controller.set "isFetching", true


Check result of dependent service

Check result of dependent service

--- test/dependency.coffee
+++ test/dependency.coffee
@@ -26,6 +26,8 @@

   it 'should not fail when the dependency load function is specified', (done) ->
     # specify loader, then...
-    @services.doSomething {@sessionId}, (err) =>
+    @services.doSomething {@sessionId}, (err, {result}) =>
       should.not.exist err
+      should.exist result
+      result.should.equal 'it worked'
       done()


correct whitespace

correct whitespace

--- assignments/coffeescript/accumulate/accumulate_test.spec.coffee
+++ assignments/coffeescript/accumulate/accumulate_test.spec.coffee
@@ -5,7 +5,6 @@
   it 'empty accumulation', ->
     accumulator = (e) -> e * e
     expect([]).toEqual [].accumulate(accumulator)
-

   it 'accumulate squares', ->
     accumulator = (number) -> number * number


Simplified the markdown watch glob

Simplified the markdown watch glob

--- .metalsmith/gulpfile.coffee
+++ .metalsmith/gulpfile.coffee
@@ -29,9 +29,8 @@
   ]
   coffee: 'static/**/*.coffee'
   documents: [
-    '!../.metalsmith'
-    '!node_modules/**'
-    '../**'
+    '!**'
+    '../**/*.md'
   ]
   sass: './sass/**/*.scss'
   static: [


Fix events of javascripts to work with Turbolinks

--- backend/app/assets/javascripts/comable/admin/application.coffee
+++ backend/app/assets/javascripts/comable/admin/application.coffee
@@ -17,19 +17,25 @@
 # functions
 # ---

+beforeunload_message = ->
+  # TODO: Install 'i18n-js' gem
+  'The changes not saved. Are you sure you want to move from this page?'
+
 add_beforeunload_event = ->
   $form = $('form[method!="get"]')
   $form.change(->
-    $(window).on('beforeunload', (event) ->
-      # TODO: Install 'i18n-js' gem
-      confirmation_message = 'The changes not saved. Are you sure you want to move from this page?'
-      (event || window.event).returnValue = confirmation_message # for Gecko and Trident
-      confirmation_message                                       # for Gecko and WebKit
+    $(window).bind('beforeunload', ->
+      beforeunload_message()
+    )
+    $(document).on('page:before-change', ->
+      confirm(beforeunload_message())
     )
   )
-  $form.submit(->
-    $(window).off('beforeunload')
-  )
+  remove_beforeunload_function = ->
+    $(window).unbind('beforeunload')
+    $(document).off('page:before-change')
+  $form.submit(remove_beforeunload_function)
+  $(document).on('page:change', remove_beforeunload_function)

 window.add_fields = (_this, association, content) ->
   new_id = new Date().getTime()
@@ -41,14 +47,15 @@
 # ---

 $(document).ready(->
-  $(document).on('change', '.btn-file :file', ->
+  add_beforeunload_event()
+
+  $('.btn-file :file').change(->
     $(this).closest('form').submit()
   )
+
+  $('[data-toggle="tooltip"]').tooltip()
 )

-add_beforeunload_event()
-
-$('[data-toggle="tooltip"]').tooltip()

 NProgress.configure(
   showSpinner: false,


allow setting a common helper, can make children a helper

--- test-integration/helpers/test-element.coffee
+++ test-integration/helpers/test-element.coffee
@@ -51,12 +51,14 @@
       @test.driver.isElementPresent(@options.loadingLocator).then (isPresent) -> not isPresent
     , waitTime

+  setCommonHelper: (name, helper) =>
+    @el[name] = helper
+    # alias
+    @["get#{S.capitalize(name, false)}"] = helper.get.bind(helper)
+
   setCommonElement: (commonElementInfo, name) =>
     {locator, isSingle} = commonElementInfo
-    @el[name] = new TestItemHelper(@test, locator, name, isSingle)
-
-    # alias
-    @["get#{S.capitalize(name, false)}"] = @el[name].get.bind(@el[name])
+    @setCommonHelper(new TestItemHelper(@test, locator, name, isSingle))

 # Using defined properties for access eliminates the possibility


--- renderer/lib/init.coffee
+++ renderer/lib/init.coffee
@@ -37,3 +37,11 @@
 else
   global.__filename = __filename
   global.__dirname = __dirname
+
+# Redirect window.onerror to uncaughtException.
+window.onerror = (error) ->
+  if global.process.listeners('uncaughtException').length > 0
+    global.process.emit 'uncaughtException', error
+    true
+  else
+    false


Public members

Public members

Because that’s not even _really_ private

--- src/wintermute/state.coffee
+++ src/wintermute/state.coffee
@@ -5,12 +5,12 @@
   constructor: ->
     @game = null

-    @_families = {}
-    @_systems = []
-    @_entities = []
+    @families = {}
+    @systems = []
+    @entities = []

   addEntity: (entity) ->
-    for family in @_families
+    for family in @families
       family.addEntityIfMatches entity

     entity.onComponentAdded.add (entity, component) =>
@@ -19,45 +19,45 @@
     entity.onComponentRemoved.add (entity, component) =>
       @onComponentRemoved entity, component

-    @_entities.push entity
+    @entities.push entity

   removeEntity: (entity) ->
-    for id, family of @_families
+    for id, family of @families
       family.removeEntity entity

-    @_entities = _.without @_entities, entity
-    @_entities.length
+    @entities = _.without @entities, entity
+    @entities.length

   getEntities: (componentNames) ->
     familyId = "$#{componentNames.join(",")}"
-    unless @_families[familyId]
-      @_families[familyId] = new Family componentNames
+    unless @families[familyId]
+      @families[familyId] = new Family componentNames

-      for entity in @_entities
-        @_families[familyId].addEntityIfMatches entity
+      for entity in @entities
+        @families[familyId].addEntityIfMatches entity

-    @_families[familyId].getEntities()
+    @families[familyId].getEntities()

   addSystem: (system) ->
     system.state = this
-    @_systems.push system
+    @systems.push system

   removeSystem: (system) ->
     system.state = null
-    @_systems = _.without @_systems, system
-    @_systems.length
+    @systems = _.without @systems, system
+    @systems.length

   reset: ->
-    @_entities = []
-    @_systems = []
-    @_families = {}
+    @entities = []
+    @systems = []
+    @families = {}

   onComponentAdded: (entity, componentName) ->
-    for id, family of @_families
+    for id, family of @families
       family.onComponentAdded entity, componentName

   onComponentRemoved: (entity, componentName) ->
-    for id, family of @_families
+    for id, family of @families
       family.onComponentRemoved entity, componentName

   enter: ->
@@ -69,7 +69,7 @@
   resume: ->

   update: (delta) ->
-    for system in @_systems
+    for system in @systems
       system.update delta

 module.exports = State


Revert "don't close the tree view on cmd-w"

This reverts commit ef48c355fbabbb668d723dfea74a696382828d81.

--- src/packages/tree-view/src/tree-view.coffee
+++ src/packages/tree-view/src/tree-view.coffee
@@ -48,7 +48,7 @@
     @on 'click', '.entry', (e) => @entryClicked(e)
     @command 'core:move-up', => @moveUp()
     @command 'core:move-down', => @moveDown()
-    @command 'core:close', => false
+    @command 'core:close', => @detach(); false
     @command 'tree-view:expand-directory', => @expandDirectory()
     @command 'tree-view:collapse-directory', => @collapseDirectory()
     @command 'tree-view:open-selected-entry', => @openSelectedEntry(true)


Default properties for Vectors.

Default properties for Vectors.

--- src/math/vector.coffee
+++ src/math/vector.coffee
@@ -5,7 +5,7 @@
   x: 0
   y: 0

-  constructor: (@x, @y) ->
+  constructor: (@x=0, @y=0) ->

   set: (v) -> @x = v.x; @y = v.y; this
   set2: (x, y) -> @x = x; @y = y; this
@@ -92,7 +92,7 @@
   y: 0
   z: 0

-  constructor: (@x, @y, @z) ->
+  constructor: (@x=0, @y=0, @z=0) ->

   set: (v) -> @x = v.x; @y = v.y; @z = v.z; this
   set3: (x, y, z) -> @x = x; @y = y; @z = z; this


refactor(funnel): add backward ticks

refactor(funnel): add backward ticks

--- scripts/gitter-activity-notifier.coffee
+++ scripts/gitter-activity-notifier.coffee
@@ -275,11 +275,11 @@
             if parts[2] == 'passed'
                 messages.push(travisOk + vsprintf('Pull Request %1$s#%2$s ([Reviewable %2$s](https://reviewable.io/reviews/%1$s/%2$s)) has __passed__: [Travis %5$s](%4$s)', parts))
             else
-                messages.push(travisBroken + vsprintf('%6$s owes muffins now!!! :cake: Pull Request %1$s#%2$s ([Reviewable %2$s](https://reviewable.io/reviews/%1$s/%2$s)) is __broken__: [Travis %5$s](%4$s)', parts))
+                messages.push(travisBroken + vsprintf('`%6$s` owes muffins now!!! :cake: Pull Request %1$s#%2$s ([Reviewable %2$s](https://reviewable.io/reviews/%1$s/%2$s)) is __broken__: [Travis %5$s](%4$s)', parts))

         for commitid, parts of store[roomid].commit
             console.log(commitid, parts)
-            messages.push(pushimg + vsprintf('%1$s pushed %2$s commit(s) to [%3$s](https://github.com/%3$s/): [\[compare\]](%4$s)', parts))
+            messages.push(pushimg + vsprintf('`%1$s` pushed %2$s commit(s) to [%3$s](https://github.com/%3$s/): [\[compare\]](%4$s)', parts))

         # funnel notification to a single room is specified; otherwise post to the event origin room
         target = if notificationRoom == 'same' then roomid else notificationRoom


explicitly request tall images for artwork columns on artwork page

--- src/mobile/apps/artwork/components/related_artworks/queries/index.coffee
+++ src/mobile/apps/artwork/components/related_artworks/queries/index.coffee
@@ -15,7 +15,7 @@
   }
   image {
     placeholder
-    url
+    url (version: "tall")
     is_default
     thumb: resized(width: 350, version: ["large", "larger"]) {
       url


open images

open images

--- HTML/atomicity.coffee
+++ HTML/atomicity.coffee
@@ -31,10 +31,13 @@
   setMode()
   Chrome.setDirty false
 open = ->
-  Chrome.title _.last filename.split('/')
-  editor.getSession().setValue File.read filename
-  setMode()
-  Chrome.setDirty false
+  if /png|jpe?g|gif/i.test filename
+    Chrome.openURL filename
+  else
+    Chrome.title _.last filename.split('/')
+    editor.getSession().setValue File.read filename
+    setMode()
+    Chrome.setDirty false
 setMode = ->
   if /\.js$/.test filename
     editor.getSession().setMode new JavaScriptMode


tests for callbacks, still havent found how to reproduce uniqueness executing twice bug

--- test/cases/support/callbackChainTest.coffee
+++ test/cases/support/callbackChainTest.coffee
@@ -48,6 +48,10 @@
         process.nextTick =>
           @_asyncMethodWithAsyncCallback = true
           blockDone()
+
+      complete = (error) =>
+        console.log error
+        methodDone()

       @runCallbacks 'asyncMethodWithAsyncCallback', block, methodDone


collections export for #185

collections export for #185

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -399,23 +399,24 @@
   # monkey-patch translate to capture export path and auto-export
   Zotero.Translate.Export.prototype.translate = ((original) ->
     return ->
+      # requested translator
+      translator = @translator?[0]
+      return original.apply(this, arguments) unless translator
+
+      # detect BBT
+      for own name, bbt of Zotero.BetterBibTeX.translators
+        break if bbt.translatorID == translator.translatorID
+        bbt = null
+
       # convert group into its library items
       if @_collection?.objectType == 'group'
-        group = @_collection
+        @_group = @_collection
         delete @_collection
-        @_items = Zotero.DB.columnQuery('select itemID from items where libraryID in (select libraryID from groups where groupID = ?) and not itemID in (select itemID from deletedItems)', [group.id])
+        @_items = Zotero.DB.columnQuery('select itemID from items where libraryID in (select libraryID from groups where groupID = ?) and not itemID in (select itemID from deletedItems)', [@_group.id])
         @_items = Zotero.Items.get(@_items) unless @_items.length == 0

-      # requested translator
-      translatorID = @translator?[0]
-      translatorID = translatorID.translatorID if translatorID?.translatorID
-
-      for own name, header of Zotero.BetterBibTeX.translators
-        break if header.translatorID == translatorID
-        header = null
-
       # regular behavior for non-BBT translators
-      return original.apply(this, arguments) unless header
+      return original.apply(this, arguments) unless bbt

       # export path for relative exports
       @_displayOptions.exportPath = @location.path.slice(0, -@location.leafName.length) if @location && typeof @location == 'object'
@@ -435,9 +436,9 @@
       progressWin.changeHeadline('Auto-export')

       switch
-        when group # group export, already converted to its corresponding items above
+        when @_group # group export, already converted to its corresponding items above
           progressWin.addLines(["Group #{group.name} set up for auto-export"])
-          collection = "group:#{group.id}"
+          collection = "group:#{@_group.id}"

         when @_collection?.id
           progressWin.addLines(["Collection #{@_collection.name} set up for auto-export"])
@@ -455,11 +456,19 @@
       progressWin.startCloseTimer()

       if collection
-        @_displayOptions.translatorID = translatorID
+        @_displayOptions.translatorID = translator.translatorID
         Zotero.BetterBibTeX.auto.add(collection, @location.path, @_displayOptions)

       return original.apply(this, arguments)
     )(Zotero.Translate.Export.prototype.translate)
+
+  # monkey-patch _prepareTranslation to add collections for group export
+  Zotero.Translate.Export.prototype._prepareTranslation = ((original) ->
+    return ->
+      r = original.apply(this, arguments)
+      @_itemGetter._collectionsLeft = @_group.getCollections() if @_group && @_translatorInfo?.configOptions?.getCollections
+      return r
+    )(Zotero.Translate.Export.prototype._prepareTranslation)

   # monkey-patch buildCollectionContextMenu to add group library export
   zoteroPane = Zotero.getActiveZoteroPane()


Revert "Test: tweak e2e video test for travis"

This reverts commit 8476c98ff6ee3a341f70d15ddfe776d47535809f.

--- test/e2e/app/work/work.projects.spec.coffee
+++ test/e2e/app/work/work.projects.spec.coffee
@@ -70,12 +70,9 @@
               when 'video'
                 item.$('video').getAttribute('poster').then (poster) ->
                   expect(poster).toMatch(RegExp(dataItem.poster))
-                  checkDone()
-                  ### phantom can't seem to test this?
                   item.$('video').getAttribute('src').then (src) ->
                     expect(src).toMatch(RegExp("#{dataItem.mp4}|#{dataItem.ogg}|#{dataItem.webm}"))
                     checkDone()
-                  ###

       it 'should optionally have: description, press, team', (done) ->
         doneIdx = 0


fix a bug where the notifications were being given the undefined class

--- modules/notify/main/index.coffee
+++ modules/notify/main/index.coffee
@@ -41,8 +41,10 @@
   view = container.view('.hx-notification')
   view.enter (d) ->
     selection = @append('div')
+    optionalClass = if d.options.cssclass then " #{d.options.cssclass}" else ''
+
     selection
-      .class('hx-notification ' + d.options.cssclass)
+      .class("hx-notification#{optionalClass}")
       .forEach (node) ->
         setupNotification(d, selection)
         d.trueHeight = selection.style('height')
@@ -88,7 +90,7 @@
   constructor: (@manager, @message, options) ->
     @options = hx.merge {
       icon: undefined
-      cssClass: undefined
+      cssclass: undefined
       timeout: @manager._.defaultTimeout
       pinnable: true
       renderer: (node, message) -> hx.select(node).text(message)
@@ -143,7 +145,8 @@
     mergedOptions = hx.merge({
       icon: 'hx-icon ' + iconClass
     }, options)
-    mergedOptions.cssclass = contextClass + ' ' + (options.cssclass or '')
+    optionalClass = if mergedOptions.cssclass then " #{mergedOptions.cssclass}" else ''
+    mergedOptions.cssclass = "#{contextClass}#{optionalClass}"
     manager.notify(message, mergedOptions)

   info: (message, options = {}) ->


sinan change

sinan change

--- client/app/MainApp/filetree/controllers/findercontroller.coffee
+++ client/app/MainApp/filetree/controllers/findercontroller.coffee
@@ -49,31 +49,31 @@

       @treeController.initTree [mount]

-      @fetchStorage (storage)=>
-
-        recentFolders = if storage.bucket?.recentFolders?
-          storage.bucket.recentFolders
-        else
-          [
-            "/Users/#{nickname}"
-            "/Users/#{nickname}/Sites"
-            "/Users/#{nickname}/Sites/#{nickname}.beta.koding.com"
-            "/Users/#{nickname}/Sites/#{nickname}.beta.koding.com/website"
-          ]
-
-        @utils.wait 2000, =>
+      # @fetchStorage (storage)=>
+      #
+      #   recentFolders = if storage.bucket?.recentFolders?
+      #     storage.bucket.recentFolders
+      #   else
+      recentFolders = [
+        "/Users/#{nickname}"
+        "/Users/#{nickname}/Sites"
+        "/Users/#{nickname}/Sites/#{nickname}.beta.koding.com"
+        "/Users/#{nickname}/Sites/#{nickname}.beta.koding.com/website"
+      ]
+
+      @utils.wait 2000, =>

-          a = Date.now()
-          mount.emit "fs.fetchContents.started"
-          KD.getSingleton('kiteController').run
-            withArgs  :
-              command : "ls #{recentFolders.join(" ")} -lpva --group-directories-first --time-style=full-iso"
-          , (err, response)=>
-            if response
-              files = FSHelper.parseLsOutput recentFolders, response
-              @treeController.addNodes files
-            log "#{(Date.now()-a)/1000}sec"
-            mount.emit "fs.fetchContents.finished"
+        a = Date.now()
+        mount.emit "fs.fetchContents.started"
+        KD.getSingleton('kiteController').run
+          withArgs  :
+            command : "ls #{recentFolders.join(" ")} -lpva --group-directories-first --time-style=full-iso"
+        , (err, response)=>
+          if response
+            files = FSHelper.parseLsOutput recentFolders, response
+            @treeController.addNodes files
+          log "#{(Date.now()-a)/1000}sec"
+          mount.emit "fs.fetchContents.finished"

     else
       mount         = FSHelper.createFile


client: stackwizard: added a cancel button

--- client/stacks/lib/views/stacks/onboarding/onboardingview.coffee
+++ client/stacks/lib/views/stacks/onboarding/onboardingview.coffee
@@ -108,6 +108,13 @@

   createFooter: ->

+    @cancelButton = new kd.ButtonView
+      cssClass : 'StackEditor-OnboardingModal--cancel'
+      title    : 'CANCEL'
+      callback : =>
+        kd.singletons.router.handleRoute '/IDE'
+        @parent.cancel()
+
     @backButton = new kd.ButtonView
       cssClass  : 'outline back'
       title     : 'Back'


plan-viz: white background for details and put border on top.

--- community/browser/lib/visualization/components/queryPlan.coffee
+++ community/browser/lib/visualization/components/queryPlan.coffee
@@ -339,6 +339,22 @@
               .transition()
               .attr('transform', (d) -> "translate(#{d.x},#{d.y})")
             children:
+
+              'rect.background':
+                data: (d) -> [d]
+                selections: (enter, update) ->
+                  enter
+                  .append('rect')
+                  .attr('class', 'background')
+
+                  update
+                  .transition()
+                  .attr('width', operatorWidth)
+                  .attr('height', (d) -> d.height)
+                  .attr('rx', operatorCornerRadius)
+                  .attr('ry', operatorCornerRadius)
+                  .attr('fill', 'white')
+                  .style('stroke', 'none')

               'g.header':
                 data: (d) -> [d]
@@ -416,23 +432,6 @@
                       .attr('y', 13)
                       .attr('fill', (d) -> color(d.operatorType)['text-color-internal'])
                       .text((d) -> d.operatorType)
-
-              'rect.outline':
-                data: (d) -> [d]
-                selections: (enter, update) ->
-                  enter
-                  .append('rect')
-                  .attr('class', 'outline')
-
-                  update
-                  .transition()
-                  .attr('width', operatorWidth)
-                  .attr('height', (d) -> d.height)
-                  .attr('rx', operatorCornerRadius)
-                  .attr('ry', operatorCornerRadius)
-                  .attr('fill', 'none')
-                  .attr('stroke-width', 1)
-                  .style('stroke', (d) -> color(d.operatorType)['border-color'])

               'g.detail':
                 data: operatorDetails
@@ -567,6 +566,23 @@
                     update
                     .text((d) -> d.text)
                   )
+
+              'rect.outline':
+                data: (d) -> [d]
+                selections: (enter, update) ->
+                  enter
+                  .append('rect')
+                  .attr('class', 'outline')
+
+                  update
+                  .transition()
+                  .attr('width', operatorWidth)
+                  .attr('height', (d) -> d.height)
+                  .attr('rx', operatorCornerRadius)
+                  .attr('ry', operatorCornerRadius)
+                  .attr('fill', 'none')
+                  .attr('stroke-width', 1)
+                  .style('stroke', (d) -> color(d.operatorType)['border-color'])
     })

   display = (queryPlan) ->


[improvement] Showed summary as heading in Ticket Details modal rather than the word "Description" (1m)

--- app/assets/javascripts/houston-scheduler/helpers/jquery_extensions.coffee
+++ app/assets/javascripts/houston-scheduler/helpers/jquery_extensions.coffee
@@ -47,7 +47,7 @@

             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
-
Description

+
#{ticket.summary}

             #{ticket.description}


remove the admin links

remove the admin links

--- client/landing/app/MainApp/avatararea/avatarareagroupswitcherpopup.coffee
+++ client/landing/app/MainApp/avatararea/avatarareagroupswitcherpopup.coffee
@@ -12,7 +12,6 @@
       startWithLazyLoader : yes

     @listController.on "AvatarPopupShouldBeHidden", @bound 'hide'
-

     @avatarPopupContent.addSubView switchToTitle = new KDView
       height   : "auto"
@@ -83,20 +82,7 @@
           title   : "Opens in a new browser window."
           delayIn : 300

-  viewAppended:->
-    JView::viewAppended.call this
-
-    {group:{slug}, roles} = @getData()
-
-    dashboardHref = "/#{slug}/Dashboard"
-
-    if 'admin' in roles
-      @addSubView new CustomLinkView
-        title     : 'Admin dashboard'
-        href      : dashboardHref
-        click     : (event)->
-          event.preventDefault()
-          KD.getSingleton('router').handleRoute dashboardHref
+  viewAppended: JView::viewAppended

   pistachio: ->
     {roles} = @getData()


multiselect2: Made deselect work even if selectScope is not available.

This happens when we search and the selected item disappears from the body.

--- django_cradmin/static/django_cradmin/src/lib/multiselect2/services.coffee
+++ django_cradmin/static/django_cradmin/src/lib/multiselect2/services.coffee
@@ -33,9 +33,10 @@
       $selectElement = angular.element('#' + selectButtonDomId)
       if $selectElement?
         selectScope = $selectElement.isolateScope()
-        selectScope.onDeselect()
-        targetScope = @__getTargetScope(selectScope.getTargetDomId())
-        targetScope.onDeselect(selectScope)
+        if selectScope?
+          selectScope.onDeselect()
+          targetScope = @__getTargetScope(selectScope.getTargetDomId())
+          targetScope.onDeselect(selectScope)
       else
         console.log "Element ##{selectButtonDomId} is not in the DOM"


USe parallel limit on zip file streaming

--- services/web/app/coffee/Features/Downloads/ProjectZipStreamManager.coffee
+++ services/web/app/coffee/Features/Downloads/ProjectZipStreamManager.coffee
@@ -48,4 +48,4 @@
 							archive.append stream, name: path
 							stream.on "end", () ->
 								callback()
-			async.series jobs, callback
+			async.parallelLimit jobs, 5, callback


fix error no route edit media

fix error no route edit media

--- MediaAdminBundle/Resources/public/coffee/LoadBaseConfigurationRoute.coffee
+++ MediaAdminBundle/Resources/public/coffee/LoadBaseConfigurationRoute.coffee
@@ -1,11 +1,16 @@
 ((router) ->
+  router.addRoutePattern('listFolder', 'folder/:folderId/list');
+  router.addRoutePattern('mediaEdit', 'folder/:folderId/list/media/:mediaId/edit');
+
   router.route 'folder/:folderId/list/media/:mediaId/edit', 'mediaEdit', (folderId, mediaId) ->
     @initDisplayRouteChanges '#' + folderId
     @addRoutePattern 'apiMediaEdit', $('#' + folderId).data('media-edit-url')
     SuperboxLoad folderId, mediaId
     return
+
   router.route 'folder/:folderId/list', 'listFolder', (folderId) ->
     @initDisplayRouteChanges()
     GalleryLoad $('#' + folderId)
     return
+
 ) window.appRouter


sip still

sip still

--- app/assets/javascripts/ckeditor/plugins/effective_regions/plugin.js.coffee
+++ app/assets/javascripts/ckeditor/plugins/effective_regions/plugin.js.coffee
@@ -1,26 +1,45 @@
 SaveAll = {
   replaceSnippets: (html) ->
     obj = $('
' + html + '
')
-    obj.find('div[data-snippet]').each -> $(this).replaceWith("[#{$(this).data('snippet')}]")
+    obj.find('div[data-snippet-data]').each -> $(this).replaceWith("[#{$(this).data('snippet')}]")
     obj.html()
+
+  instanceData: (instance) ->
+    console.log 'INSTANCE DATA'
+
+    snippets = {}
+
+    for id, widget of instance.widgets.instances
+      console.log widget
+      snippet_id = $(widget.wrapper.$).data('cke-widget-id')
+      snippets["snippet_#{snippet_id}"] = widget.data
+      snippets["snippet_#{snippet_id}"]['class_name'] = widget.name
+
+      snippet_data = $(widget.element.$).data('snippet-data')
+      snippet_data['id'] = snippet_id
+      $(widget.element.$).data('snippet-data', snippet_data)
+
+      console.log "WIDGET HTML"
+      console.log $(widget.element.$).data('snippet-data')
+
+    content = instance.getData()
+
+    console.log "CONTENT:"
+    console.log content
+
+    {
+      content: instance.getData(),
+      snippets: snippets
+    }

   exec: (editor) ->
     data = {}
-
-    for name, instance of CKEDITOR.instances # All CKEditors on the whole page
-      snippets_data = {}
-      for name, widget of instance.widgets.instances
-        console.log name
-        console.log widget
-        console.log widget.data
-        snippets_data[widget.snippet_id()] = widget.data
-
-      data[name] = {
-        content: @replaceSnippets(instance.getData())
-        snippets: snippets_data
-      }
+    data[name] = @instanceData(instance) for name, instance of CKEDITOR.instances

     url = window.location.protocol + '//' + window.location.host + '/edit' + window.location.pathname
+
+    console.log "Saving..."
+    console.log data

     $.ajax
       url: url
@@ -28,9 +47,7 @@
       dataType: 'json'
       data: { effective_regions: data }
       async: false
-      success: (data) ->
-        console.log 'success!'
-        console.log data
+      success: (data) -> console.log 'success!'
 }

 Regions = {
@@ -69,9 +86,8 @@
   build: (editor, name, values) ->
     snippet = {}

-    snippet['snippet_id'] = -> $(this.wrapper.$).find('div.cke_widget_element').data('snippet')
     snippet['configured'] = false
-    snippet['template'] = values.template
+    snippet['template'] = "

" # This gets replaced when we click on the Submit Dialog button
     snippet['dialog_url'] = values.dialog_url
     snippet['dialog'] = name if values.dialog_url
     snippet['requiredContent'] = "div(#{name})"
@@ -86,10 +102,11 @@
         complete: (data) -> $(widget.wrapper.$).find('div.cke_widget_element').html(data.responseText)

     snippet['init'] = ->
+      for k, v of $(this.wrapper.$).find('div.cke_widget_element').data('snippet-data')
+        this.data[k] = v
+
       this.on 'dialog', (evt) -> @configured = true
       this.on 'data', (evt) -> @loadTemplate(evt.sender) if @configured
-
-    #snippet['data'] = ->

     snippet
 }


Add placeholder test for ng-class.

Add placeholder test for ng-class.

--- test/html-parse.coffee
+++ test/html-parse.coffee
@@ -19,3 +19,4 @@
         classes = htmlParse.getClasses(html)
         assert.deepEqual(classes, ['bodyclass', 'class1', 'class2', 'htmlclass'])

+    it 'Recognizes classes in Angular.JS ng-class'


JName: fix next() with fin()

JName: fix next() with fin()

--- workers/social/lib/social/models/name.coffee
+++ workers/social/lib/social/models/name.coffee
@@ -110,11 +110,11 @@
       models = []
       queue = nameObj.slugs.map (slug, i)->->
         konstructor = Base.constructors[slug.constructorName]
-        return queue.next() unless konstructor
+        return queue.fin() unless konstructor
         selector = {}
         selector[slug.usedAsPath] = slug.slug
         konstructor.one selector, (err, model)->
-          return queue.next() if err or not model
+          return queue.fin() if err or not model
           models[i] = model
           queue.fin()


Send keys version

Send keys version

--- test/js/totodoo.coffee
+++ test/js/totodoo.coffee
@@ -49,7 +49,8 @@
 			drvr = @driver
 			# wait for page to be loaded
 			@driver.wait((()-> drvr.executeScript('return document.readyState')), 10000).then ()->
-				drvr.executeScript("document.getElementById('new-todo').setAttribute('value', 'New item')")
+				#drvr.executeScript("document.getElementById('new-todo').setAttribute('value', 'New item')")
+				drvr.findElement(id: 'new-todo').sendKeys('New item')
 				drvr.findElement(id: 'new-todo').submit()
 				size = drvr.executeScript('return window.document.querySelectorAll("#todo-list li").length')
 				expect(size).to.eventually.equal


加入对module include option.stopCallback的测试

--- test/moduleSpec.coffee
+++ test/moduleSpec.coffee
@@ -21,7 +21,7 @@

             o.should.have.property(member, m[member]) for member of m

-        it "should merge methodized method to obj if option.methodize set be true", ->
+        it "should merge methodized method to obj if option.methodize be true", ->
             sayHello =  (man) ->
                     "hello " + man.name
             m =
@@ -36,7 +36,7 @@
             #check methodized
             o.sayHello().should.eql sayHello(o)

-        it "should call the onIncluded() after included", ->
+        it "should call the onIncluded() after include", ->
             spy = sinon.spy()

             m =
@@ -48,7 +48,7 @@
             spy.calledOn(o).should.be.true
             spy.calledWith(o).should.be.true

-        it "should call the onIncluded() on passing binding context after included", ->
+        it "should call the onIncluded() with passing context", ->
             spy = sinon.spy()

             m =
@@ -64,17 +64,16 @@
             spy.calledOn(o).should.be.true
             spy.calledWith(a).should.be.true

-        it "should not merge specific member, such as init method, meta member which name starts with __, onIncluded callback", ->
+        it "should not merge specific member, include meta member which name starts with __, onIncluded callback", ->
             m =
                 onIncluded: ->
                 __interface__: []
-                init: ->
                 member1: {}

             o = {}
             M.$include(o, m)

-            o.should.not.have.property(member) for member in ["onIncluded", "__interface__", "init"]
+            o.should.not.have.property(member) for member in ["onIncluded", "__interface__"]
             o.should.have.property("member1")

         it "should implementation all of interfaces from module", ->
@@ -91,6 +90,17 @@
             o.__interfaces__.should.containEql inter for inter in interfaces

+        it "should not call onIncluded() if option.stopCallback be true", ->
+            m =
+                onIncluded: sinon.spy()
+
+            M.$include({}, m, {stopCallback: true})
+
+            m.onIncluded.called.should.be.false

+
+
+
+


more complete mock queries

more complete mock queries

--- test/phabs_test.coffee
+++ test/phabs_test.coffee
@@ -98,6 +98,10 @@
             ownerPHID: 'PHID-USER-42'
             } })
           .get('/api/user.query')
+          .query(query = {
+            'phids[0]': 'PHID-USER-42',
+            'api.token': 'xxx'
+          })
           .reply(200, { result: [{ userName: 'toto' }] })

       afterEach ->
@@ -140,14 +144,16 @@
         do nock.disableNetConnect
         nock(process.env.PHABRICATOR_URL)
           .get('/api/maniphest.info')
+          .query({
+            'task_id': 42,
+            'api.token': 'xxx'
+          })
           .reply(200, { result: {
             status: 'open',
             priority: 'Low',
             name: 'Test task',
             ownerPHID: null
             } })
-          .get('/api/user.query')
-          .reply(200, { result: [{ userName: 'toto' }] })

       afterEach ->
         nock.cleanAll()
@@ -162,6 +168,10 @@
         do nock.disableNetConnect
         nock(process.env.PHABRICATOR_URL)
           .get('/api/maniphest.info')
+          .query({
+            'task_id': 42,
+            'api.token': 'xxx'
+          })
           .reply(200, { result: {
             status: 'open',
             priority: 'Low',
@@ -169,6 +179,10 @@
             ownerPHID: 'PHID-USER-000000'
             } })
           .get('/api/user.query')
+          .query(query = {
+            'phids[0]': 'PHID-USER-000000',
+            'api.token': 'xxx'
+          })
           .reply(200, { result: [] })

       afterEach ->


Removed owner read/write notification from permissions view.

--- client/landing/app/MainApp/filetree/itemsubviews/setpermissionsview.coffee
+++ client/landing/app/MainApp/filetree/itemsubviews/setpermissionsview.coffee
@@ -87,16 +87,6 @@
           @displayOctalPermissions()
           @setPermission()
     @switches[name]
-
-  bindSwitchNotifications: ->
-    ownerSwitches = @switches.owner
-    ownerSwitches[0].on "SwitchStateChanged", (newState) => @warnUser newState
-    ownerSwitches[1].on "SwitchStateChanged", (newState) => @warnUser newState
-
-  warnUser: (newState) ->
-    if newState is no
-      new KDNotificationView
-        title:  "Everything is something happened!"

   getBinaryOfGroup: (group) ->
     binary = ''
@@ -200,7 +190,6 @@
       everyone  : mode[2]

     @createSwitches name, permission for name, permission of permissions
-    @bindSwitchNotifications()

     setTimeout =>
       @displayOctalPermissions()


update specs to new load defaults for course signature

--- test/flux/tasking.spec.coffee
+++ test/flux/tasking.spec.coffee
@@ -31,10 +31,10 @@
 COURSE =
   id: '1'
   periods: [
-    {id: '1', name: '1st'},
-    {id: '2', name: '2nd'},
-    {id: '3', name: '3rd'},
-    {id: '4', name: '4th'}
+    {id: '1', name: '1st', is_archived: false},
+    {id: '2', name: '2nd', is_archived: false},
+    {id: '3', name: '3rd', is_archived: false},
+    {id: '4', name: '4th', is_archived: false}
   ]

 DEFAULT_TIMES =
@@ -111,7 +111,7 @@
     course = makeCourse()
     indexedDefaults = makeIndexedDefaults()

-    TaskingActions.loadDefaults(course.id, course)
+    TaskingActions.loadDefaults(course.id, course, course.periods)

     _.each TaskingStore.getDefaults('1'), (tasking, taskingKey) ->
       expect(tasking).to.matchTasking(indexedDefaults[taskingKey])
@@ -121,7 +121,7 @@
   it 'should set all to true for creating when defaults are same', ->

     course = makeCourse()
-    TaskingActions.loadDefaults(course.id, course)
+    TaskingActions.loadDefaults(course.id, course, course.periods)

     TaskingActions.loadTaskToCourse(NEW_TASK_ID, course.id)
     TaskingActions.create(NEW_TASK_ID)
@@ -131,7 +131,7 @@
   it 'should set all to false for creating when defaults are different', ->

     course = makeCourse(DEFAULT_TIMES, PERIOD_DEFAULT_TIMES_DIFFERENT)
-    TaskingActions.loadDefaults(course.id, course)
+    TaskingActions.loadDefaults(course.id, course, course.periods)

     TaskingActions.loadTaskToCourse(NEW_TASK_ID, course.id)
     TaskingActions.create(NEW_TASK_ID)
@@ -144,7 +144,7 @@
     courseDifferent = makeCourse(DEFAULT_TIMES, PERIOD_DEFAULT_TIMES_DIFFERENT)
     courseDifferent.id = '2'

-    TaskingActions.loadDefaults(course.id, course)
+    TaskingActions.loadDefaults(course.id, course, course.periods)
     TaskingActions.loadTaskToCourse(NEW_TASK_ID, course.id)
     TaskingActions.create(NEW_TASK_ID)

@@ -169,7 +169,7 @@
     courseDifferent = makeCourse(DEFAULT_TIMES, PERIOD_DEFAULT_TIMES_DIFFERENT)
     courseDifferent.id = '2'

-    TaskingActions.loadDefaults(course.id, course)
+    TaskingActions.loadDefaults(course.id, course, course.periods)
     TaskingActions.loadTaskToCourse(NEW_TASK_ID, course.id)
     TaskingActions.create(NEW_TASK_ID, {open_date: DATES.YESTERDAY, due_date: DATES.TOMORROW})


warm up NACL library to fix failing test in PhantomJS

--- tests/specs/04.mailbox.coffee
+++ tests/specs/04.mailbox.coffee
@@ -55,6 +55,11 @@
         expect(MailBox._nonceData n2).is.equal data
         done()

+  # first call of Mailbox.fromSeed returns an object with wrong keys in PhantomJS environment,
+  # so this line is needed to "warm-up" NACL and generate correct keyRings for tests.
+  # TODO: get rid of this
+  MailBox.fromSeed('warmup')
+
   it 'Mailbox from well known seed', (done)->
     handle done, MailBox.fromSeed('hello').then (m)->
       pk = m.keyRing.getPubCommKey()


Let moment handle searching the string

Let moment handle searching the string

--- SingularityUI/app/collections/LogLines.coffee
+++ SingularityUI/app/collections/LogLines.coffee
@@ -11,7 +11,7 @@

     delimiter: /\n/

-    timestampRegex: /\d{2}:\d{2}:\d{2}.\d{3}/
+    # timestampRegex: /\d{2}:\d{2}:\d{2}.\d{3}/

     # How much we request at a time (before growing it)
     baseRequestLength: 30000
@@ -177,21 +177,21 @@

         # create the objects for LogLine models
         res = lines.map (data) =>
-            regexResult = @timestampRegex.exec data
-            # TODO: We need to give "orphaned" lines at the beginning of a file a timestamp if we have any
-            if regexResult isnt null
-              timestamp = moment regexResult[0], 'HH:mm:ss.SSS'
-              @lastTimestamp = timestamp
-              @timestampIndex = 0
-            else
-              timestamp = @lastTimestamp
-              if @lastTimestamp
-                @timestampIndex++
-
-            line = {data, offset, timestamp, @timestampIndex, @taskId}
-            offset += data.length + 1
-
-            line
+          tryTimestamp = moment data, 'HH:mm:ss.SSS'
+          # TODO: We need to give "orphaned" lines at the beginning of a file a timestamp if we have any
+          if tryTimestamp.isValid()
+            timestamp = tryTimestamp
+            @lastTimestamp = timestamp
+            @timestampIndex = 0
+          else
+            timestamp = @lastTimestamp
+            if @lastTimestamp
+              @timestampIndex++
+
+          line = {data, offset, timestamp, @timestampIndex, @taskId}
+          offset += data.length + 1
+
+          line

         res