added gitgnore for sync

added gitgnore for sync

--- lib/server-script.coffee
+++ lib/server-script.coffee
@@ -40,16 +40,18 @@
                                    dismissable: true
   save: ->
     if not fs.existsSync @serverScriptFolder then @initSetupFolder(); return
-    if not (@setup  = @loadCsonInitFile 'server-setup.cson') or
+    if not (@setup = @loadCsonInitFile 'server-setup.cson') or
        not (secret = @loadCsonInitFile 'secrets.cson') then return
-    pwdStr = (if secret.password then ':' + password else '')
-    @server = secret.login.user + pwdStr + '@' + @setup.server.location
-    # console.log @setup, secret, @server
-    # console.log @doSSH 'ls -al'
+    pwdStr = (if secret.login.password then ':' + secret.login.password else '')
+    usrStr = (if secret.login.user then secret.login.user + pwdStr + '@' else '')
+    @server = usrStr + @setup.server.location
+    console.log @server, '\n', @doSSH 'ls -al'

     if @setup.options.syncChangedFiles
+      gitIgnStr = (if @setup.options.useGitignore \
+                   then " --exclude=.git --filter=':- .gitignore' " else ' ')
       remotePath = @server + ':' + path.normalize @setup.server.projectRoot
-      cmd = "rsync -a --filter=':- .gitignore' #{@rootDirPath}/ #{remotePath}/\n"
+      cmd = 'rsync -a' + gitIgnStr + "#{@rootDirPath}/ #{remotePath}/\n"
       console.log cmd
       console.log execSync cmd, timeout:5e3, encoding:'utf8', maxBuffer:10e6


Init.coffee and Snippets.cson support

Init.coffee and Snippets.cson support

Added support for Init.coffee and Snippets.cson

--- lib/sync-settings.coffee
+++ lib/sync-settings.coffee
@@ -32,6 +32,10 @@
         content: @fileContent atom.keymap.getUserKeymapPath()
       "styles.less":
         content: @fileContent atom.themes.getUserStylesheetPath()
+      "init.coffee":
+        content: @fileContent atom.config.configDirPath + "/init.coffee"
+      "snippets.cson":
+        content: @fileContent atom.config.configDirPath + "/snippets.cson"

     @createClient().gists.edit
       id: atom.config.get 'sync-settings.gistId'
@@ -69,6 +73,14 @@
       styles = res.files['styles.less']?.content
       console.debug "styles.less = ", res.files['styles.less']?.content
       fs.writeFileSync(atom.themes.getUserStylesheetPath(), res.files['styles.less'].content) if styles
+
+      initCoffee = res.files['init.coffee']?.content
+      console.debug "init.coffee = ", initCoffee
+      fs.writeFileSync(atom.config.configDirPath + "/init.coffee", initCoffee) if initCoffee
+
+      snippetsCson = res.files['snippets.cson']?.content
+      console.debug "snippets.cson = ", snippetsCson
+      fs.writeFileSync(atom.config.configDirPath + "/snippets.cson", snippetsCson) if snippetsCson

   createClient: ->
     token = atom.config.get 'sync-settings.personalAccessToken'


:fire: Remove space-pen legacy code

:fire: Remove space-pen legacy code

--- lib/table-element.coffee
+++ lib/table-element.coffee
@@ -20,12 +20,6 @@
 class TableElement extends HTMLElement
   PropertyAccessors.includeInto(this)
   EventsDelegation.includeInto(this)
-
-  @content: ->
-    @div class: 'table-edit', =>
-      @input type: 'text', class: 'hidden-input', outlet: 'hiddenInput'
-      @div outlet: 'head', class: 'table-edit-header'
-      @div outlet: 'body', class: 'scroll-view'

   createdCallback: ->
     @gutter = false


test #22

test #22

--- lib/touch-gesture.coffee
+++ lib/touch-gesture.coffee
@@ -37,7 +37,7 @@
     if event.type=='touchstart' and @startTouches==null
       @startTouches = event.touches

-    @currentTouch = event.touches[0] if event.touches.lenght>0
+    @currentTouch = event.touches[0] if event.touches.length>0

     event.left = @currentTouch.clientX
     event.top = @currentTouch.clientY


Add editor.nonWordCharacters to editor config panel

--- src/app/editor-config-panel.coffee
+++ src/app/editor-config-panel.coffee
@@ -31,3 +31,7 @@
       @div class: 'row', =>
         @label for: 'editor.showInvisibles', "Show Invisible Characters:"
         @input id: 'editor.showInvisibles', type: 'checkbox'
+
+      @div class: 'row', =>
+        @label for: 'editor.nonWordCharacters', "Non-Word Characters:"
+        @input id: 'editor.nonWordCharacters', size: 50


Closes #82 - Remove alert if unable to fetch new version

--- adagios/media/coffee/adagios.coffee
+++ adagios/media/coffee/adagios.coffee
@@ -64,15 +64,11 @@
     current_version = $('#current_version').text()
     $.getJSON("http://adagios.opensource.is/cgi-bin/version.cgi?version=#{current_version}&callback=?", (data) ->
       this
-    ).error( (jqXHR, text) ->
-      alert("Failed to fetch data: URL: \"" + this.url + "\" Server Status: \"" + jqXHR.status + "\" Status: \"" + jqXHR.message + "\"");
-      this
     ).success( (data) ->
       if $('span#current_version').text() != data['version']
         $('div#updates_avail').show()
       $this.text data['version']
       $('a#version_info').attr 'href', data['link']
-
     )
     this

@@ -182,9 +178,9 @@
           $this.adagios_ob_dtPopulate()
       ).error (jqXHR) ->

-
-      # TODO - fix this to a this style
-
+
+      # TODO - fix this to a this style
+
       #targetDataTable = $(this).data('datatable');
       #targetDataTable.parent().parent().parent().html('

ERROR

Failed to fetch data::
URL: ' + this.url + '
Server Status: ' + jqXHR.status + ' ' + jqXHR.statusText + '

');
       this
@@ -440,11 +436,11 @@
         $(this).adagios_ob_run_check_command()

     ).error (jqXHR) ->
-
-      # TODO - fix this to a this style
+
+      # TODO - fix this to a this style
       alert "Failed to fetch data: URL: \"" + @url + "\" Server Status: \"" + jqXHR.status + "\" Status: \"" + jqXHR.statusText + "\""

-
+
     # Stop the button from POST'ing
     this
 ) jQuery


Fix some extremely stupid errors.

Fix some extremely stupid errors.

--- add-note-count-to-focus-task.coffee
+++ add-note-count-to-focus-task.coffee
@@ -69,7 +69,6 @@
          Matching project names were : [#{names}]."
     )

-    taskBasename = 'Process TextExpander suggestions'
     task = @_findBy(
       query:
         completed: false
@@ -86,11 +85,11 @@
   run: ->
     @_updateOmniFocusTask(
       taskBasename: 'Process TextExpander suggestions'
-      count: @_countNotesInInbox()
+      count: @_countTextExpanderSuggestions()
     )
     @_updateOmniFocusTask(
       taskBasename: 'Process Evernote inbox'
-      count: @_countTextExpanderSuggestions()
+      count: @_countNotesInInbox()
     )

 new UpdateFocusTasks().run()


enhance: add device type enums

enhance: add device type enums

--- app/enums.coffee
+++ app/enums.coffee
@@ -77,6 +77,11 @@
     HALFYEARLY: 6
     YEARLY: 10

+  DEVICE_TYPE:
+    NO_PREFERENCE: 0
+    PHONE_REQUIRED: 1
+    TABLET_REQUIRED: 2
+

 # Populate `CHOICES`
 for enumName, enumValues of ENUMS


change logging message to be different from LatexRunner

--- services/clsi/app/coffee/CompileManager.coffee
+++ services/clsi/app/coffee/CompileManager.coffee
@@ -28,7 +28,7 @@
 		compileDir = getCompileDir(request.project_id, request.user_id)

 		timer = new Metrics.Timer("write-to-disk")
-		logger.log project_id: request.project_id, user_id: request.user_id, "starting compile"
+		logger.log project_id: request.project_id, user_id: request.user_id, "syncing resources to disk"
 		ResourceWriter.syncResourcesToDisk request.project_id, request.resources, compileDir, (error) ->
 			if error?
 				logger.err err:error, project_id: request.project_id, user_id: request.user_id, "error writing resources to disk"


Add pattern-matching for user-defined identifiers

Source: http://aplwiki.com/LearnApl/AplData#Names

--- grammars/apl.cson
+++ grammars/apl.cson
@@ -9,6 +9,7 @@
 	{ include: "#strings" }
 	{ include: "#float"   }
 	{ include: "#int"     }
+	{ include: "#name"    }

 	# Comments
 	{
@@ -181,3 +182,11 @@
 				name: "invalid.illegal.string.apl"
 			}]
 		}]
+
+
+	# Names
+	name:
+		patterns: [{
+			name: "storage.type.name.apl"
+			match: "[A-Za-z0-9∆⍙_]+[A-Za-z0-9∆⍙_¯]*"
+		}]


apache error log support.

apache error log support.

--- grammars/log.cson
+++ grammars/log.cson
@@ -33,6 +33,10 @@
   }
   {
     'match': '^[0-9\.]* - -?'
+    'name': 'definition.comment.log'
+  }
+  {
+    'match': '^\\[[A-Za-z0-9 :]+\\]?'
     'name': 'definition.comment.log'
   }

@@ -86,7 +90,7 @@
     'name': 'definition.log.log-info'
   }

-  # Apache
+  # Apache access log
   {
     'match': ' ([4|5][0-9]{2}) [0-9]*$'
     'captures':
@@ -98,6 +102,20 @@
     'captures':
       '1':
         'name': 'definition.log.log-success'
+  }
+
+  # Apache error log
+  {
+    'match': '\\[error\\]'
+    'name': 'definition.log.log-error'
+  }
+  {
+    'match': '\\[info\\]'
+    'name': 'definition.log.log-info'
+  }
+  {
+    'match': '\\[notice\\]'
+    'name': 'definition.log.log-verbose'
   }

   # Nabto log syntax


proper NPE fix

proper NPE fix

--- app/assets/javascripts/monitoring/views/metric_list.js.coffee
+++ app/assets/javascripts/monitoring/views/metric_list.js.coffee
@@ -51,7 +51,10 @@

         s = ".check[check_id=" + metric.get("check_id") + "] .metric[metric_id='" + metric.id + "']"
         metric.graph = Bixby.monitoring.render_metric(s, metric, opts)
-        metric.graph._bixby_mode = "pan" if metric.graph? # on panning in list view, no zoom
+
+        return if !metric.graph?
+
+        metric.graph._bixby_mode = "pan" # on panning in list view, no zoom

         # fired when panning is completed on the given graph
         # update all other graphs with more data


Remove hacked together jQuery trigger

Remove hacked together jQuery trigger

This was needed when using AmpersandView


conversations: add keyclick handler for autocomplete button

fixes CNVS-9136

test plan:
  * open conversations
  * compose a new message
  * focus the recipient field
  * verify that you can activate the button to the right
      using the keyboard

Change-Id: I9cc19ec95f7f1f66668209db2362ba9d5d99a9a5
Reviewed-on: https://gerrit.instructure.com/26597
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Zach Pendleton <514dbb4d54d4f29e454990df7d075678f43f92aa@instructure.com>
QA-Review: Matt Fairbourn <5f353e1c97bb9cc046b9db20beca0b9392f6f1b2@instructure.com>
Product-Review: Zach Pendleton <514dbb4d54d4f29e454990df7d075678f43f92aa@instructure.com>

--- app/coffeescripts/views/conversations/AutocompleteView.coffee
+++ app/coffeescripts/views/conversations/AutocompleteView.coffee
@@ -93,6 +93,7 @@
       'click     .ac-clear'            : '_onClearTokens'
       'click     .ac-token-remove-btn' : '_onRemoveToken'
       'click     .ac-search-btn'       : '_onSearch'
+      'keyclick  .ac-search-btn'       : '_onSearch'
       'focus     .ac-input'            : '_onInputFocus'
       'input     .ac-input'            : '_onSearchTermChange'
       'keydown   .ac-input'            : '_onInputAction'


fix new post

fix new post

--- lms/static/coffee/src/discussion/views/new_post_view.coffee
+++ lms/static/coffee/src/discussion/views/new_post_view.coffee
@@ -122,7 +122,6 @@

         DiscussionUtil.safeAjax
             $elem: $(event.target)
-            $loading: $(event.target) if event
             url: url
             type: "POST"
             dataType: 'json'


preventDefault on shift + esc shortcut

preventDefault on shift + esc shortcut

--- client/views/main.coffee
+++ client/views/main.coffee
@@ -10,6 +10,7 @@

 		unread = Session.get('unread')
 		if e.keyCode is 27 and e.shiftKey is true and unread? and unread isnt ''
+			e.preventDefault()
 			e.stopPropagation()
 			swal
 				title: t('Clear_all_unreads_question')


Add support for firefox by getting rid of new implementation of ellipse method on canvas context

--- src/language/modules/shapes.coffee
+++ src/language/modules/shapes.coffee
@@ -25,7 +25,15 @@
     rx *= session.ratio
     ry *= session.ratio

-    session.ctx.ellipse x, y, rx, ry, 0, 0, 2 * Math.PI, false
+    startingAngle = 0
+    endingAngle = 2 * Math.PI; # 360 degrees is equal to 2π radians
+
+    session.ctx.save()
+    session.ctx.translate x, y
+    session.ctx.scale rx, ry
+    session.ctx.arc 0, 0, 1, startingAngle, endingAngle, -1
+    session.ctx.restore()
+
     utils.endShape()

 circle = (radius) ->


display words

display words

--- src/layout/inspect_commands.coffee
+++ src/layout/inspect_commands.coffee
@@ -10,13 +10,11 @@
 {make} = require '../render/make'

 exports.inspect_commands = (sprite) ->
-  command_buttons = make.buttons('command', [
-      "shape"
-      "name"
-      "fill"
-      "position"
-      "direction"
-    ], my.button,
-    (button, args) -> button.editing = true
-    # TODO: Implement editable command
+  language = sprite.get('language')
+  words = Object.keys language
+  command_buttons = make.buttons(
+    'command',
+    words,
+    my.button,
+    (button, args) -> button.send('command', button)
   )


Update _tracklist.coffee

Update _tracklist.coffee

Song stops when opening in browser

--- coffee/_tracklist.coffee
+++ coffee/_tracklist.coffee
@@ -94,6 +94,7 @@
             else
               link = data.feed.entry[0].link[0].href
               gui.Shell.openExternal(link)
+              videojs('video_player').pause()
     )
     menu.append new gui.MenuItem(
       label: l10n.get('find_more'),


added param w:0 to connection

added param w:0 to connection

--- modules/stores/platforms/node/lib/engines/MongoStore.coffee
+++ modules/stores/platforms/node/lib/engines/MongoStore.coffee
@@ -11,11 +11,8 @@
         init: (options, fn)->
             mongoq = require 'mongoq'

-            @_db = mongoq 'mongodb://'+(options.host || 'localhost')+'/'+options.name
+            @_db = mongoq 'mongodb://'+(options.host || 'localhost')+'/'+options.name, (options.options || w:1)
             @_client = @_db.collection options.collection
-
-            if !floyd.tools.objects.isArray(list = options.index)
-                list = [list]

             if (list = options.index)
                 if !floyd.tools.objects.isArray list
@@ -32,7 +29,10 @@

             fn()

-
+        close: (fn)->
+            @_db.close()
+            fn?()
+
         get: (key, fn)->
             @_client.findOne _id:key, fn

@@ -75,12 +75,13 @@
         distinct: (field, query, fn)->
             @_client.distinct field, query, fn

-        find: (query, options, fields, fn)->
-            query ?= {}
-
+        find: (query, options, fields, fn)->
+
+            #console.log 'query', query, options, fields
             q = @_client.find(query)
             q.count (err, size)=>
-
+                return fn(err) if err
+                #console.log 'size', size
                 options ?= {}

                 options.skip = options.offset
@@ -96,5 +97,7 @@
                 options.size = size

                 q.toArray (err, items)=>
-
-                    fn err, @_filterFields(items, fields), options, fields
+                    return fn(err) if err
+                    process.nextTick ()=>
+                        fn null, @_filterFields(items, fields), options, fields
+


#166019337 add regex to replace apostrophe when checking conditional logic on checkboxes

--- app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
@@ -50,7 +50,7 @@
           else
             if $conditionElement.is(":checkbox")
               # limit binding of each checkbox if data-label-value and answer are the same-kdh
-              $conditionElement = $conditionContainer.find(".form-control[data-label-value='" + condition.answer.replace("/","\\/") + "']")
+              $conditionElement = $conditionContainer.find(".form-control[data-label-value='" + condition.answer.replace("/","\\/").replace("'","\\'") + "']")
               self.bindConditions($conditionElement)
             else
               for element in $conditionElement
@@ -145,7 +145,7 @@

       if $conditionElement.is(":checkbox")# || $triggerElement.is(":radio"))
         # limit binding of each checkbox if data-label-value and answer are the same-kdh
-        $conditionElement = $conditionElement.closest('.form-container-entry-item').find(".form-control[data-label-value='" + condition.answer.replace("/","\\/") + "']")
+        $conditionElement = $conditionElement.closest('.form-container-entry-item').find(".form-control[data-label-value='" + condition.answer.replace("/","\\/").replace("'","\\'") + "']")

       hideQuestions = self.setHideQuestions(condition, $conditionElement)
       conditionMet = !hideQuestions
@@ -413,7 +413,7 @@
     $conditionElement.val()

 $ ->
-  if $('input#survey_survey_template_id').length
+  if $('input#survey_survey_template_id').length
     #call findRules on document ready
     cl = new ConditionalLogic
     cl.findRules()


KDDiaObject restrictions for creating connections between joints

--- client/landing/app/Applications/Demos.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Demos.kdapplication/AppView.coffee
@@ -84,7 +84,6 @@
     options.cssClass = KD.utils.curry 'environments-item', options.cssClass
     options.jointItemClass = EnvironmentItemJoint
     options.draggable = no
-
     super options, data

   viewAppended:->
@@ -101,20 +100,27 @@

 class EnvironmentRuleItem extends EnvironmentItem
   constructor:(options={}, data)->
-    options.joints = ['right']
-    options.cssClass = 'rule'
+    options.joints             = ['right']
+    options.cssClass           = 'rule'
+    options.allowedConnections =
+      EnvironmentDomainItem : ['left']
     super options, data

 class EnvironmentDomainItem extends EnvironmentItem
   constructor:(options={}, data)->
     options.joints = ['left', 'right']
     options.cssClass = 'domain'
+    options.allowedConnections =
+      EnvironmentRuleItem    : ['right']
+      EnvironmentMachineItem : ['left']
     super options, data

 class EnvironmentMachineItem extends EnvironmentItem
   constructor:(options={}, data)->
     options.joints = ['left']
     options.cssClass = 'machine'
+    options.allowedConnections =
+      EnvironmentDomainItem : ['right']
     super options, data
     @usage = new KDProgressBarView


added failing unit test for _ parsing

added failing unit test for _ parsing

--- test/overall/expressionParser.mocha.coffee
+++ test/overall/expressionParser.mocha.coffee
@@ -77,6 +77,12 @@

       expect(ex1.toJS()).to.deep.equal(ex2.toJS())

+    it.skip "should not get confused with underscores", ->
+      ex1 = $('player').is('23_michael_jordan')
+      ex2 = $('player').is('"23_michael_jordan"')
+
+      expect(ex1.toJS()).to.deep.equal(ex2.toJS())
+
     it "should work with lots of keywords 1", ->
       ex1 = Expression.parse('$y and true and $z')
       ex2 = $('y').and(r(true), $('z'))


remove unused lodash functions

remove unused lodash functions

--- config/grunt/dist.coffee
+++ config/grunt/dist.coffee
@@ -46,10 +46,10 @@
     options:
       modifier: 'modern'
       include: [
-        'difference', 'flatten', 'intersection', 'last'
-        'all', 'each', 'invoke', 'map', 'pluck', 'reduce'
+        'difference', 'intersection', 'last'
+        'all', 'each', 'invoke', 'map', 'reduce'
         'bind', 'defer', 'partial'
-        'clone', 'extend', 'defaults', 'has', 'keys', 'omit', 'values'
+        'clone', 'extend', 'defaults', 'omit', 'values'
         'isElement', 'isEqual', 'isNumber', 'isObject', 'isString'
         'uniqueId'
       ]


PUBDEV-185 Always include required fields in model-build requests.

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -213,7 +213,7 @@
     for controls in _controlGroups
       for control in controls
         value = control.value()
-        if includeUnchangedParameters or (control.defaultValue isnt value)
+        if includeUnchangedParameters or control.isRequired or (control.defaultValue isnt value)
           switch control.kind
             when 'dropdown'
               if value


changes adapter to ActiveModelAdapter

changes adapter to ActiveModelAdapter

--- ember-checkout/app/adapters/application.coffee
+++ ember-checkout/app/adapters/application.coffee
@@ -1,6 +1,6 @@
 `import DS from 'ember-data'`

-ApplicationAdapter = DS.RESTAdapter.extend
+ApplicationAdapter = DS.ActiveModelAdapter.extend
   namespace: 'api'
   headers:
     'X-Spree-Order-Token': Spree.current_order_token


Add missing Settings.api specs

Add missing Settings.api specs

--- spec/settings_spec.coffee
+++ spec/settings_spec.coffee
@@ -124,3 +124,94 @@

         expect(@settings.url.beacon(session))
           .to.equal(endpoint)
+
+  describe '.api', ->
+    it 'has property .settings', ->
+      expect(@settings.api)
+        .to.have.property('settings')
+        .that.is.an('object')
+
+    it 'has property .yogurt', ->
+      expect(@settings.api)
+        .to.have.property('yogurt')
+        .that.is.an('object')
+
+    it 'has property .site', ->
+      expect(@settings.api)
+        .to.have.property('site')
+        .that.is.an('object')
+
+    it 'has property .ecommerce', ->
+      expect(@settings.api)
+        .to.have.property('ecommerce')
+        .that.is.an('object')
+
+    describe '.settings', ->
+      it 'has property .key', ->
+        expect(@settings.api.settings)
+          .to.have.property('key')
+          .that.is.a('string')
+          .that.equals('settings')
+
+      it 'has property .set_account', ->
+        expect(@settings.api.settings)
+          .to.have.property('set_account')
+          .that.is.a('string')
+          .that.equals('setAccount')
+
+      it 'has property .set_callback', ->
+        expect(@settings.api.settings)
+          .to.have.property('set_callback')
+          .that.is.a('string')
+          .that.equals('setCallback')
+
+      it 'has property .redirect_to', ->
+        expect(@settings.api.settings)
+          .to.have.property('redirect_to')
+          .that.is.a('string')
+          .that.equals('redirectTo')
+
+    describe '.yogurt', ->
+      it 'has property .key', ->
+        expect(@settings.api.yogurt)
+          .to.have.property('key')
+          .that.is.a('string')
+          .that.equals('yogurt')
+
+      it 'has property .product_click', ->
+        expect(@settings.api.yogurt)
+          .to.have.property('product_click')
+          .that.is.a('string')
+          .that.equals('productClick')
+
+    describe '.site', ->
+      it 'has property .key', ->
+        expect(@settings.api.site)
+          .to.have.property('key')
+          .that.is.a('string')
+          .that.equals('site')
+
+      it 'has property .send_pageview', ->
+        expect(@settings.api.site)
+          .to.have.property('send_pageview')
+          .that.is.a('string')
+          .that.equals('sendPageview')
+
+    describe '.ecommerce', ->
+      it 'has property .key', ->
+        expect(@settings.api.ecommerce)
+          .to.have.property('key')
+          .that.is.a('string')
+          .that.equals('ecommerce')
+
+      it 'has property .add_transaction', ->
+        expect(@settings.api.ecommerce)
+          .to.have.property('add_transaction')
+          .that.is.a('string')
+          .that.equals('addTransaction')
+
+      it 'has property .add_item', ->
+        expect(@settings.api.ecommerce)
+          .to.have.property('add_item')
+          .that.is.a('string')
+          .that.equals('addItem')


Log incoming requests to static file server.

--- smoke-test.coffee
+++ smoke-test.coffee
@@ -54,6 +54,8 @@
   path: process.cwd()
   index: 'index.html'
 }))
+server.on 'request', (req, res) ->
+  console.log(' < %s %s', chalk.green(req.method), req.url)
 server.listen(8000)
 console.log('Server up, e.g. http://localhost:8000/?doc=_mathdown_test_smoke')


Unnecesary define parent

Unnecesary define parent

--- examples/app/source/aside/default.coffee
+++ examples/app/source/aside/default.coffee
@@ -8,4 +8,4 @@

   _log: (method, event) -> console.log "aside > #{method}", event

-aside = new Options parent: document.body
+aside = new Options()


util: fixing 3 tests for misc.defaults

util: fixing 3 tests for misc.defaults

--- src/smc-util/test/misc-test.coffee
+++ src/smc-util/test/misc-test.coffee
@@ -237,7 +237,7 @@
         global.DEBUG = @debug_orig

     beforeEach =>
-        @console_debug_stub = sinon.stub(global.console, "debug")
+        @console_debug_stub = sinon.stub(global.console, "warn")
         @console_trace_stub = sinon.stub(global.console, "trace")

     afterEach =>


make prev edit more concise

make prev edit more concise

--- src/smc-webapp/editor_latex.coffee
+++ src/smc-webapp/editor_latex.coffee
@@ -93,10 +93,7 @@
             @spell_check()

         @latex_editor.syncdoc.on 'connect', () =>
-            if @load_conf().zoom_width?
-                @preview.zoom_width = @load_conf().zoom_width
-            else
-                @preview.zoom_width = 100
+            @preview.zoom_width = @load_conf().zoom_width ? 100
             @update_preview()
             @spell_check()


more mapping tests

more mapping tests

--- src/spec/basic_mapping.spec.coffee
+++ src/spec/basic_mapping.spec.coffee
@@ -30,6 +30,16 @@
     .finally ->
       fs.removeTree testDir

+  simpleMapping = (inObj, columnMapping) ->
+    new mapping.Mapping
+      transformers: transformer.defaultTransformers
+      columnMappers: mapping.defaultColumnMappers
+      mappingConfig:
+        columnMapping: columnMapping
+    .init()
+    .then (mapping) ->
+      mapping.transformRow ["default"], inObj
+
   it 'should map CSV file with standard mappings and produce 2 output CSV for "default" and "additional" groups', (done) ->
     withTestDir (testDir)->
       createTestMapper testDir, 'test-data/test-mapping.json',
@@ -55,24 +65,47 @@
     .fail (error) ->
       done(error)

-  it "should show nice message when regex VT does not match the object", (done) ->
-    new mapping.Mapping
-      transformers: transformer.defaultTransformers
-      columnMappers: mapping.defaultColumnMappers
-      mappingConfig:
-        columnMapping: [{
-          type: "transformColumn"
-          fromCol: "a"
-          toCol: "b"
-          valueTransformers: [
-            {type: "regexp", find: "\\d{10}", replace: "foo"}
-          ]
-        }]
-    .init()
-    .then (mapping) ->
-      mapping.transformRow ["default"], {a: "Hello World!"}
+  it "should show nice message when regex value transformer does not match the object", (done) ->
+    simpleMapping {a: "Hello World!"}, [{
+      type: "transformColumn"
+      fromCol: "a"
+      toCol: "b"
+      valueTransformers: [
+        {type: "regexp", find: "\\d{10}", replace: "foo"}
+      ]
+    }]
     .then (result) ->
       done("No error message!")
     .fail (error) ->
-      expect(error.message).toEqual "Error during mapping from column 'a' to column 'b' with current value 'Hello World!': Regex /\\d{10}/g does not match value 'Hello World!'."
+      expect(error.message).toEqual "Error during mapping from column 'a' to column 'b' with current value 'Hello World!':
+        Regex /\\d{10}/g does not match value 'Hello World!'."
       done()
+
+  it "should show nice message when multipart value transformer has part of the wring size", (done) ->
+    simpleMapping {a: "Hello World!"}, [{
+      type: "addColumn"
+      toCol: "b"
+      valueTransformers: [{
+        type: "multipartString"
+        parts: [{
+          size: 10
+          pad: "0"
+          valueTransformers: [
+            {type: "constant", value: "bar"}
+          ]
+        }, {
+          size: 15
+          fromCol: 'a'
+          valueTransformers: [
+            {type: "regexp", find: "^(.*)$", replace: "$1 - foo"}
+          ]
+        }]
+      }]
+    }]
+    .then (result) ->
+      done("No error message!")
+    .fail (error) ->
+      expect(error.message).toEqual "Error during generation of column 'b': Generated column part size
+        (18 - 'Hello World! - foo') is smaller than expected size (15) and no padding is defined for this column.
+        Source column 'a' (part 1) with current value 'Hello World!'."
+      done()


Added Config->deletePlugin()

Added Config->deletePlugin()

--- src/config.coffee
+++ src/config.coffee
@@ -106,3 +106,27 @@
           @save()
           @config[hostname]

+  deletePlugin: (hostname, plugin_name) ->
+    self = @
+    hostname = helpers.getHostname hostname
+    index = false
+    plugins = @getHostname hostname
+
+    if not plugins or not plugin_name
+      false
+    else
+      if not @getPlugin hostname, plugin_name
+        false
+      else
+        _.each plugins, (element, idx, list) ->
+          if element.name is plugin_name
+            index = idx
+
+        if index is false
+          false
+        else
+          delete self.config[hostname][index]
+
+          @save()
+          @config[hostname]
+


"arguments" is overwritten by closure arguments

--- src/config.coffee
+++ src/config.coffee
@@ -648,11 +648,12 @@
   # * `true` if the value was set.
   # * `false` if the value was not able to be coerced to the type specified in the setting's schema.
   set: ->
+    [keyPath, value, options] = arguments
+
     unless @settingsLoaded
-      @pendingOperations.push(() => @set.apply(@, arguments))
+      @pendingOperations.push () => @set.call(this, keyPath, value, options)
       return

-    [keyPath, value, options] = arguments
     scopeSelector = options?.scopeSelector
     source = options?.source
     shouldSave = options?.save ? true
@@ -684,7 +685,7 @@
   #   * `source` (optional) {String}. See {::set}
   unset: (keyPath, options) ->
     unless @settingsLoaded
-      @pendingOperations.push(() => @unset.apply(@, arguments))
+      @pendingOperations.push () => @unset.call(this, keyPath, options)
       return

     {scopeSelector, source} = options ? {}


now pass travis CI

now pass travis CI

--- spec/vim-mode-spec.coffee
+++ spec/vim-mode-spec.coffee
@@ -58,8 +58,6 @@
         atom.commands.findCommands(target: editorElement).filter (cmd) ->
           cmd.name.startsWith("vim-mode-plus:")

-      _ = require 'underscore-plus'
       expect(vimCommands().length).toBeGreaterThan(0)
       atom.packages.deactivatePackage(packageName)
-      console.log _.pluck(vimCommands(), 'name')
       expect(vimCommands().length).toBe(0)


No need for crypto module

No need for crypto module

--- models/time_entry.coffee
+++ models/time_entry.coffee
@@ -1,5 +1,4 @@
 _ = require 'underscore'
-crypto = require 'crypto'

 class TimeEntry
   constructor: (props) ->


Extract logout to function, so different redirect can be called

--- services/web/app/coffee/Features/User/UserController.coffee
+++ services/web/app/coffee/Features/User/UserController.coffee
@@ -118,7 +118,7 @@
 									logger.err err:err, "error populateTeamInvites"
 								res.sendStatus(200)

-	logout : (req, res)->
+	_doLogout: (req, cb = (err) ->) ->
 		metrics.inc "user.logout"
 		user = AuthenticationController.getSessionUser(req)
 		logger.log user: user, "logging out"
@@ -127,9 +127,14 @@
 		req.session.destroy (err)->
 			if err
 				logger.err err: err, 'error destorying session'
+				cb(err)
 			if user?
 				UserSessionsManager.untrackSession(user, sessionId)
 				SudoModeHandler.clearSudoMode(user._id)
+			cb()
+
+	logout : (req, res)->
+		UserController._doLogout req, (err) ->
 			res.redirect '/login'

 	register : (req, res, next = (error) ->)->


adding todo for objects updating

adding todo for objects updating


added clear option for engine

added clear option for engine


dispatchTimeLineAction: Handle errors.

dispatchTimeLineAction: Handle errors.


added thanks.coffee

added thanks.coffee


make ui.ComponentStack more like Component

--- ui.coffee
+++ ui.coffee
@@ -31,10 +31,18 @@

 class ui.ComponentStack
-  constructor: ({@uiType, @container, @stack, @count}) ->
+  constructor: ({@uiType, container, @stack, @count}) ->
     @type = @uiType.name
+    @_container = container
     check @uiType, ui.ComponentType
     check @count, Number
+    check container, CBGA.Container
+    # pretend we're a component
+    if @stack?
+      @[@uiType.stackProperty] = @stack
+
+  # for compatibility with the Component API
+  container: -> @_container

 class ui.ComponentType
@@ -137,6 +145,7 @@
             Blaze.Each (-> cursor), =>
               @getCounterTemplate count, container.rules.name

+
 class ui.Controller extends EventEmitter
   # does nothing for now, but can be used for instanceof


Comments: render emojis on new comments

Comments: render emojis on new comments

--- client/activity/lib/views/comments/commentlistitemview.coffee
+++ client/activity/lib/views/comments/commentlistitemview.coffee
@@ -268,6 +268,9 @@
     @timeAgoView = new KDTimeAgoView {}, createdAt

     JView::viewAppended.call this
+
+    kd.utils.defer => emojify.run @getElement()
+
     # @setAnchors()


tests

tests

--- api/apps/articles/test/model.coffee
+++ api/apps/articles/test/model.coffee
@@ -66,6 +66,47 @@
         Article.where {}, (err, { results }) ->
           results[0].title.should.equal 'Hello Wurld'
           done()
+
+    it 'can find articles featured to an artist', (done) ->
+      fabricate 'articles', [
+        {
+          title: 'Foo'
+          featured_artist_ids: [ObjectId('4dc98d149a96300001003033')]
+        }
+        {
+          title: 'Bar'
+          primary_featured_artist_ids: [ObjectId('4dc98d149a96300001003033')]
+        }
+        {
+          title: 'Baz'
+          featured_artist_ids: [ObjectId('4dc98d149a96300001003033'), 'abc']
+          primary_featured_artist_ids: [ObjectId('4dc98d149a96300001003033')]
+        }
+      ], ->
+        Article.where(
+          { artist_id: '4dc98d149a96300001003033' }
+          (err, { results }) ->
+            _.pluck(results, 'title').sort().join('').should.equal 'BarBazFoo'
+            done()
+        )
+
+    it 'can find articles featured to an artwork', (done) ->
+      fabricate 'articles', [
+        {
+          title: 'Foo'
+          featured_artwork_ids: [ObjectId('4dc98d149a96300001003033')]
+        }
+        {
+          title: 'Baz'
+          featured_artwork_ids: [ObjectId('4dc98d149a96300001003033'), 'abc']
+        }
+      ], ->
+        Article.where(
+          { artwork_id: '4dc98d149a96300001003033' }
+          (err, { results }) ->
+            _.pluck(results, 'title').sort().join('').should.equal 'BazFoo'
+            done()
+        )

   describe '#find', ->


Fix message directive

Fix message directive

Largely working

--- app/assets/directive/message.coffee
+++ app/assets/directive/message.coffee
@@ -4,7 +4,7 @@
   'constantService', '$sce',
   (constants, $sce) ->
     restrict: 'A'
-    compile: ($scope, $element, $attrs) ->
+    compile: ($element, $attrs) ->
       opts = {}
       opts.sce = $sce.HTML if 'messageHtml' in $attrs
       if $attrs.message.contains('{{')


fix click handler

fix click handler

--- core/app/backbone/views/react_install_extension_button.coffee
+++ core/app/backbone/views/react_install_extension_button.coffee
@@ -35,7 +35,7 @@
         _div ['in-your-browser-dashed-border'],
           _a ["js-bookmarklet-button", "in-your-browser-bookmarklet",
               "button-success", "button-huge",
-              onclick: ((e)-> e.preventDefault())],
+              onClick: ((e)-> e.preventDefault())],
             _span [style: display: 'none'], 'Factlink'
         _div [],
           _em [],


fixes bug in event listener for loadedmetadata

--- app/assets/javascripts/thyme.coffee
+++ app/assets/javascripts/thyme.coffee
@@ -347,7 +347,7 @@
   # for the events, see https://www.w3schools.com/jsref/event_oncanplay.asp
   initialChapters = true
   initialMetadata = true
-  video.addEventListener 'loadedmetadata',
+  video.addEventListener 'loadedmetadata', ->
     if initialChapters and chaptersElement.readyState == 2
       displayChapters()
       initialChapters = false


Adjust endpoints along bottom of flow node


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -67,7 +67,7 @@
   update: (dataSet) ->
     console.log 'update pie', dataSet
     that = this
-    @piedata = @pie(data[0].value)
+    @piedata = @pie(dataSet[0].value)
     console.log 'update pie', @pieData
     #create a marker element if it doesn't already exist
     defs = @svg.select('defs')


Added comments

Added comments

--- adagios/media/js/adagios.coffee
+++ adagios/media/js/adagios.coffee
@@ -78,10 +78,12 @@
       if aData[1] isnt undefined and aData[1] isnt null
         return true

+    # Showing all objectgroups without a name
     if cache_type is "1" and aData[2] is "#{object_type}group"
       if aData[1] is undefined or aData[1] is null
         return true

+    # Showing all objects without a name
     if cache_type is "0" and aData[2] is "#{object_type}"
       if aData[1] is undefined or aData[1] is null
         return true


Fix counter issue I've more white hairs now.

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -273,10 +273,10 @@
     JGroup  = require './group'
     JUser   = require './user'

-    addVm = ({ target, user, name, sudo, groups, type, planCode, planOwner })->
+    addVm = ({ target, user, name, sudo, groups, groupSlug
+               type, planCode, planOwner })->

       uid = 0
-      groupSlug = if type is 'group' then name else 'koding'
       hostnameAlias = JVM.createAliases {
         nickname : user.username
         type, uid, groupSlug
@@ -318,15 +318,23 @@
           creator.fetchUser (err, user)->
             if err then handleError err
             else
+              # Following is just here to register this name in the counters collection
+              ((require 'koding-counter') {
+                db          : JVM.getClient()
+                counterName : "#{group.slug}~"
+                offset      : 0
+              }).next ->
+
               addVm {
                 user
-                type    : 'group'
-                target  : group
-                planCode  : 'free'
-                planOwner : "group_#{group._id}"
-                sudo    : yes
-                name    : group.slug
-                groups  : wrapGroup group
+                type     : 'group'
+                target   : group
+                planCode : 'free'
+                planOwner: "group_#{group._id}"
+                sudo     : yes
+                name     : "#{group.slug}~0"
+                groupSlug: group.slug
+                groups   : wrapGroup group
               }

     JGroup.on 'GroupDestroyed', (group)->
@@ -338,6 +346,13 @@
       member.fetchUser (err, user)->
         if err then handleError err
         else if group.slug is 'koding'
+          # Following is just here to register this name in the counters collection
+          ((require 'koding-counter') {
+            db          : JVM.getClient()
+            counterName : "koding~#{member.profile.nickname}~"
+            offset      : 0
+          }).next ->
+
           # TODO: this special case for koding should be generalized for any group.
           addVm {
             user
@@ -347,6 +362,7 @@
             planOwner : "user_#{member._id}"
             sudo      : yes
             name      : "koding~#{member.profile.nickname}~0"
+            groupSlug : group.slug
             groups    : wrapGroup group
           }
         else


vm: add a TODO

vm: add a TODO

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -32,7 +32,7 @@
       name              : String
       users             : Array
       groups            : Array
-      usage             :
+      usage             : # TODO: usage seems like the wrong term for this.
         cpu             :
           type          : Number
           default       : 1


Autocomplete: fetching item's default text made more user friendly

--- src/components/autocomplete/autocompletefetchingitem.coffee
+++ src/components/autocomplete/autocompletefetchingitem.coffee
@@ -9,4 +9,4 @@
     super options, data

-  partial: -> 'Fetching in process...'
+  partial: -> 'Loading...'


Rename to workflow assignment

Rename to workflow assignment

--- app/pages/admin/project-status.cjsx
+++ app/pages/admin/project-status.cjsx
@@ -25,7 +25,7 @@
   'column'
   'grid'
   'invert'
-  'workflow level'
+  'workflow assignment'
 ]

 ProjectToggle = React.createClass
@@ -214,7 +214,7 @@
         <ProjectExperimentalFeatures project={@props.project} />

Workflow Settings

-          The workflow level dropdown is for the workflow level experimental feature.
+          The workflow level dropdown is for the workflow assignemnt experimental feature.
           {if @state.error

{@state.error}
}
           {if @state.workflows.length is 0


Ensure state isn't directly mutated.

Ensure state isn't directly mutated.

--- app/pages/admin/project-status.cjsx
+++ app/pages/admin/project-status.cjsx
@@ -158,21 +158,25 @@
     project: null

   componentDidMount: ->
+    @getWorkflows()
+
+  onChangeWorkflowLevel: (workflow, event) ->
+    selected = event.target.value
+    workflowToUpdate = workflow
+
+    # In Autosave component
+    if selected is 'none'
+      workflowToUpdate.update({ 'configuration.level': undefined })
+    else
+      workflowToUpdate.update({ 'configuration.level': selected })
+
+    @getWorkflows()
+
+  getWorkflows: ->
     getWorkflowsInOrder @props.project, fields: 'display_name,active,configuration'
       .then (workflows) =>
         usedWorkflowLevels = @getUsedWorkflowLevels(workflows)
-        @setState usedWorkflowLevels: usedWorkflowLevels, workflows: workflows
-
-  onChangeWorkflowLevel: (workflow, event) ->
-    selected = event.target.value
-    if selected is 'none'
-      workflow.update({ 'configuration.level': undefined })
-    else
-      workflow.update({ 'configuration.level': selected })
-
-    usedWorkflowLevels = @getUsedWorkflowLevels(@state.workflows);
-
-    @setState usedWorkflowLevels: usedWorkflowLevels
+        @setState { usedWorkflowLevels, workflows }

   getUsedWorkflowLevels: (workflows) ->
     usedWorkflowLevels = []


fixing whitespace issues

fixing whitespace issues

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -1,17 +1,17 @@
 'use strict'

 angular.module('appApp.controllers')
-  .controller('MainCtrl', ['$scope', 'ApiGet', ($scope, ApiGet) ->
-    $scope.htmlTooltip1  = "Find your Representatives";
-    $scope.htmlTooltip2  = "Compare your Representatives";
-    $scope.htmlTooltip3  = "Find your Representatives";
-    $scope.htmlTooltip4  = "See who Funds your Representatives";
-    $scope.htmlTooltip5  = "Search for Bills your Representatives Voted On";
-    $scope.htmlTooltip6  = "Find your Representatives";
-    $scope.htmlTooltip7  = "Geolocation";
-    $scope.htmlTooltip8  = "Annotate the Bills!";
-    $scope.htmlTooltip9  = "Deleted Tweets";
-    $scope.htmlTooltip10 = "Find your Representatives";
-    $scope.htmlTooltip11 = "Find your Representatives";
-    $scope.htmlTooltip12 = "Find your Representatives";
-  ])
+  .controller 'MainCtrl', ['$scope', ($scope) ->
+    $scope.htmlTooltip1  = "Find your Representatives"
+    $scope.htmlTooltip2  = "Compare your Representatives"
+    $scope.htmlTooltip3  = "Find your Representatives"
+    $scope.htmlTooltip4  = "See who Funds your Representatives"
+    $scope.htmlTooltip5  = "Search for Bills your Representatives Voted On"
+    $scope.htmlTooltip6  = "Find your Representatives"
+    $scope.htmlTooltip7  = "Geolocation"
+    $scope.htmlTooltip8  = "Annotate the Bills!"
+    $scope.htmlTooltip9  = "Deleted Tweets"
+    $scope.htmlTooltip10 = "Find your Representatives"
+    $scope.htmlTooltip11 = "Find your Representatives"
+    $scope.htmlTooltip12 = "Find your Representatives"
+  ]


Make key pair operation comments.

Make key pair operation comments.


1.8.4 configuring new metadata stores

1.8.4 configuring new metadata stores

--- app/src/api/sync_rest_client.coffee
+++ app/src/api/sync_rest_client.coffee
@@ -8,29 +8,30 @@

   constructor: (addr) ->
     super
+    @chain=''
     if ledger.config.network.name != 'bitcoin' and (ledger.config.network.bip44_coin_type == '0' or ledger.config.network.bip44_coin_type == '145')
-      addr = addr + '?chain=' + ledger.config.network.name
+      @chain = '?chain=' + ledger.config.network.name
     @basePath = "accountsettings/#{addr}"

   # @param [Function] cb A callback function with object.md5 as argument.
   # @return A promise
   get_settings_md5: ->
-    @http().get(url: @basePath+'/md5').then (r) => r.md5
+    @http().get(url: @basePath+'/md5'+@chain).then (r) => r.md5

   # @return A promise
   get_settings: ->
-    @http().get(url: @basePath).then (r) => JSON.parse(r.settings)
+    @http().get(url: @basePath+@chain).then (r) => JSON.parse(r.settings)

   # @param [Object] settings data to put on sync server.
   # @return A promise
   post_settings: (settings) ->
-    @http().post(url: @basePath, data: {settings: settings}).then (r) => r.md5
+    @http().post(url: @basePath+@chain, data: {settings: settings}).then (r) => r.md5

   # @param [Object] settings data to put on sync server.
   # @return A promise
   put_settings: (settings) ->
-    @http().put(url: @basePath, data: {settings: settings}).then (r) => r.md5
+    @http().put(url: @basePath+@chain, data: {settings: settings}).then (r) => r.md5

   # @return A promise
   delete_settings: ->
-    @http().delete(url: @basePath)
+    @http().delete(url: @basePath+@chain)


Dont update result if the top level expression is malformed, regardless of whether the module is malformed.

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -2923,12 +2923,12 @@
 fakeCompile = (ctx, token) ->
   token.tea = toConstrained ctx.freshTypeVariable star
   token.scope = ctx.currentScopeIndex()
+  ctx.markMalformed()
   if ctx.assignTo()
     token.assignable = top: ctx.isAtDeferrableDefinition()
     precs: []
     assigns: []
   else
-    ctx.markMalformed()
     assignCompile ctx, token, jsNoop()

 atomCompile = (ctx, atom) ->
@@ -5578,6 +5578,7 @@
     js: library + immutable + (listOfLines map lookupJs, (setToArray runtimeDependencies moduleName)) + '\n;' + js
     ast: ast
     errors: checkTypes ctx
+    malformed: ctx.isMalformed

 importsFor = (moduleSet) ->
   lookupDefinitions = (name) ->


First onreadystatechange then send

First onreadystatechange then send

--- src/urlhandlers/xmlhttprequest.coffee
+++ src/urlhandlers/xmlhttprequest.coffee
@@ -17,10 +17,10 @@
             xhr.timeout = options.timeout or 0
             xhr.withCredentials = options.withCredentials or false
             xhr.overrideMimeType('text/xml');
-            xhr.send()
             xhr.onreadystatechange = ->
                 if xhr.readyState == 4
                     cb(null, xhr.responseXML)
+            xhr.send()
         catch
             cb()


process.exit 0 instead of process.exit 1 in the comments

--- index_test.coffee
+++ index_test.coffee
@@ -7,8 +7,8 @@
     #      when commented out - it works locally
     #process.exit 0
     #throw new Error("Exit lambda")
-    #setTimeout (-> process.exit 1), 1000
-    #process.nextTick (-> process.exit 1)
+    #setTimeout (-> process.exit 0), 1000
+    #process.nextTick (-> process.exit 0)
     return
 }


Move .hubot_history string to a variable

--- src/adapters/shell.coffee
+++ src/adapters/shell.coffee
@@ -12,6 +12,8 @@
                 parseInt(process.env.HUBOT_SHELL_HISTSIZE)
               else
                 1024
+
+historyPath = ".hubot_history"

 class Shell extends Adapter
   send: (envelope, strings...) ->
@@ -50,7 +52,7 @@

     @cli.on 'history', (item) =>
       if item.length > 0 and item isnt 'exit' and item isnt 'history'
-        fs.appendFile '.hubot_history', "#{item}\n", (err) =>
+        fs.appendFile historyPath, "#{item}\n", (err) =>
           @robot.emit 'error', err if err

     @cli.on 'close', () =>
@@ -59,7 +61,7 @@
         startIndex = history.length - historySize
         history = history.reverse().splice(startIndex, historySize)

-        outstream = fs.createWriteStream('.hubot_history')
+        outstream = fs.createWriteStream(historyPath)
         # >= node 0.10
         outstream.on 'finish', () =>
           @shutdown()
@@ -74,9 +76,9 @@
          @shutdown()

   loadHistory: (callback) ->
-    fs.exists '.hubot_history', (exists) ->
+    fs.exists historyPath, (exists) ->
       if exists
-        instream = fs.createReadStream('.hubot_history')
+        instream = fs.createReadStream(historyPath)
         outstream = new stream
         outstream.readable = true
         outstream.writable = true


allow scripts rev to handle multiple build files

--- app/templates/gulp/tasks/rev.coffee
+++ app/templates/gulp/tasks/rev.coffee
@@ -32,10 +32,10 @@
 #     $REV SCRIPTS
 #*------------------------------------*/
 gulp.task 'rev:scripts', ['minify:scripts'], () ->
-  gulp.src(["#{conf.path.prod.js}/main.bundle.min.js"])
-    .pipe rename('main.bundle.js')
+  gulp.src(["#{conf.path.prod.js}/*.bundle.min.js"])
+    .pipe rename({ suffix: '', extname: '', })
     .pipe rev()
-    .pipe rename({suffix: '.min'})
+    .pipe rename({ suffix: '.min', extname: '.js' })
     .pipe gulp.dest(conf.path.prod.js)
     .pipe rev.manifest(conf.revManifest.path, conf.revManifest.opts)
     .pipe gulp.dest('./')


[grunt] resolve locale url based on provided or absent `url` property

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -104,7 +104,9 @@

   # Output or not locale's dir name based on whether it's base locale or not.
   getLocaleDir = (locale) ->
-    urlify(if taskConfig.i18n.baseLocaleAsRoot and locale == baseLocale then '' else locale)
+    _baseUrl = _.find(taskConfig.i18n.locales, { locale: locale }).url
+    _url = if _baseUrl then _baseUrl else locale
+    urlify(if taskConfig.i18n.baseLocaleAsRoot and locale == baseLocale then '' else _url)

   ###*
    * Get language code from locale, without country


Reboot connexion every five minutes

Reboot connexion every five minutes

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -681,6 +681,15 @@
             @codemirror.setCursor
                 line: Infinity
                 ch: Infinity
+        connect: =>
+            host = window.location.hostname
+            port = window.location.port
+            if port is ''
+                port = 13457
+
+            window.conn = new rethinkdb.net.HttpConnection
+                host: host
+                port: port

         initialize: =>
             if @has_been_initialized.value is false
@@ -688,16 +697,11 @@
                     @suggestions.table.push suggestion
                 @has_been_initialized.value = true

-            host = window.location.hostname
-            port = window.location.port
-            if port is ''
-                port = 13457
-
-            window.conn = new rethinkdb.net.HttpConnection
-                host: host
-                port: port
+            @connect()
             window.r = rethinkdb.query
             window.R = r.R
+
+            @interval = setInterval @connect, 60*5*1000

             # We escape the last function because we are building a regex on top of it.
             @unsafe_to_safe_regexstr = []
@@ -801,6 +805,7 @@
             @input_query.destroy()
             @data_container.destroy()
             window.conn.close()
+            clearInterval @interval

     class @InputQuery extends Backbone.View


Reset extra_row - Related to #3037

Reset extra_row - Related to #3037

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -2605,6 +2605,7 @@
                         if @current_results.length < @limit # We display @limit results per page, if we don't have enough, we keep requesting more
                             @current_results.push data
                             @state.cursor.next get_result_callback
+                            @extra_row = undefined # We don't know if there's an extra row yet, reset its value to undefined
                         else if @current_results.length is @limit # If we've reached the limit of results we can show, we still want to know if there are more results available
                             @extra_row = data # We requested an extra row, but won't display it on the current page, so we need to save it for later (when the user wants to show more results)
                             get_result_callback() # Display results


Use existential operator.

Use existential operator.

--- src/coffee/mapping.coffee
+++ src/coffee/mapping.coffee
@@ -86,8 +86,8 @@
     for attr in attribs
       @_add(xml, order, attr)

-    xml.e('customerNumber').t(if customer and customer.customerNumber then customer.customerNumber else 'UNKNOWN').up()
-    xml.e('externalCustomerId').t(if customer and customer.externalId then customer.externalId else 'UNKNOWN').up()
+    xml.e('customerNumber').t(if customer?.customerNumber then customer.customerNumber else 'UNKNOWN').up()
+    xml.e('externalCustomerId').t(if customer?.externalId then customer.externalId else 'UNKNOWN').up()

     states = [ 'orderState', 'shipmentState', 'paymentState' ]
     for attr in states


down to one day

down to one day

--- public/javascripts/application.coffee
+++ public/javascripts/application.coffee
@@ -87,7 +87,7 @@
         hours = Math.floor diff % 86400 / 3600
         minutes = Math.floor diff % 3600 / 60
         secs = Math.floor diff % 60
-        countdown.html (if days > 0 then days + ' days ' else '') + (if hours > 0 then hours + ' hours ' else '') + (if minutes > 0 || hours > 0 then minutes + ' minutes ' else minutes) + secs + ' seconds' + ' left'
+        countdown.html (if days > 0 then days + ' day ' else '') + (if hours > 0 then hours + ' hours ' else '') + (if minutes > 0 || hours > 0 then minutes + ' minutes ' else minutes) + secs + ' seconds' + ' left'
         setTimeout tick, 1000
     tick()


removed another un-needed log

removed another un-needed log

--- packages/rocketchat-lib/settings/server/updateServices.coffee
+++ packages/rocketchat-lib/settings/server/updateServices.coffee
@@ -4,7 +4,6 @@

 	timer = Meteor.setTimeout ->
 		services = RocketChat.models.Settings.find({_id: /^(Accounts_OAuth_|Accounts_OAuth_Custom_)[a-z_-]+$/i}).fetch()
-		console.log services
 		for service in services
 			console.log "Updating login service #{service._id}".blue


Jekyll is not the same as github flavoured markdown

--- assets/scripts/app/views/log.coffee
+++ assets/scripts/app/views/log.coffee
@@ -219,7 +219,7 @@
         target.closest('.fold').toggleClass('open')

     logUrl: (->
-      repo = @get('log.job.repo')
+      repo = @get('controller.currentItem.repo')
       item = @get('controller.currentItem')

       if repo && item


liveupdates: now without weird animation in the first 10 pixels of scrolling

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -459,8 +459,7 @@
     @_state = 'public'

     @scrollView.on 'scroll', (event) =>
-      if event.delegateTarget.scrollTop > 10
-        # scrollshadow and switch off liveupdates
+      if event.delegateTarget.scrollTop > 0
         @activityHeader.setClass "scrolling-up-outset"
         @activityHeader.liveUpdateButton.setValue off


[backport] Fix missing injection of analytics service on related tasks directive.

--- app/coffee/modules/related-tasks.coffee
+++ app/coffee/modules/related-tasks.coffee
@@ -25,7 +25,7 @@

 module = angular.module("taigaRelatedTasks", [])

-RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $analytics) ->
+RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading) ->
     templateView = _.template("""

@@ -256,7 +256,7 @@
             $el.off()

     return {link: link}
-module.directive("tgRelatedTaskCreateForm", ["$tgRepo", "$compile", "$tgConfirm", "$tgModel", "$tgLoading", RelatedTaskCreateFormDirective])
+module.directive("tgRelatedTaskCreateForm", ["$tgRepo", "$compile", "$tgConfirm", "$tgModel", "$tgLoading", "$tgAnalytics", RelatedTaskCreateFormDirective])

 RelatedTaskCreateButtonDirective = ($repo, $compile, $confirm, $tgmodel) ->
     template = _.template("""


clean up semicolons

clean up semicolons

--- assets/threejs_game_renderer.coffee
+++ assets/threejs_game_renderer.coffee
@@ -7,29 +7,29 @@
     aspect = dw / dh
     d = 180

-    @camera = new THREE.OrthographicCamera(-d*aspect, d*aspect, d, -d, 1, 4000);
-    @camera.position.set(d, d, d);
-    @camera.rotation.order = 'YXZ';
-    @camera.rotation.y = - Math.PI / 4;
-    @camera.rotation.x =   Math.atan(-1 / Math.sqrt(2));
+    @camera = new THREE.OrthographicCamera(-d*aspect, d*aspect, d, -d, 1, 4000)
+    @camera.position.set(d, d, d)
+    @camera.rotation.order = 'YXZ'
+    @camera.rotation.y = - Math.PI / 4
+    @camera.rotation.x =   Math.atan(-1 / Math.sqrt(2))

     if (window.WebGLRenderingContext)
       try
-        @threeRenderer = new THREE.WebGLRenderer();
+        @threeRenderer = new THREE.WebGLRenderer()
       catch error
-        @threeRenderer = new THREE.CanvasRenderer();
+        @threeRenderer = new THREE.CanvasRenderer()
     else
-      @threeRenderer = new THREE.CanvasRenderer();
+      @threeRenderer = new THREE.CanvasRenderer()

-    @threeRenderer.setSize(dw, dh);
-    document.body.appendChild(@threeRenderer.domElement);
+    @threeRenderer.setSize(dw, dh)
+    document.body.appendChild(@threeRenderer.domElement)

     controls = new THREE.OrbitControls(@camera, @threeRenderer.domElement)
     controls.noZoom = true
     controls.noPan  = false
     controls.noRotate = true
-    controls.maxPolarAngle = Math.PI / 2;
-    #controls.zoomSpeed = 0.1;
+    controls.maxPolarAngle = Math.PI / 2
+    #controls.zoomSpeed = 0.1

     this.update(state)

@@ -71,7 +71,7 @@
     # Lighting
     @scene.add new THREE.AmbientLight(0x444444)
     light = new THREE.PointLight(0xffffff, 0.8)
-    light.position.set(0, 50, 50);
+    light.position.set(0, 50, 50)
     @scene.add light

     # Axis marker
@@ -100,4 +100,4 @@
     window.requestAnimationFrame($.proxy(this.render, this, state))

     this.update(state) # technically, we only need to do this if the scene has changed, not every frame.
-    @threeRenderer.render( @scene, @camera );
+    @threeRenderer.render( @scene, @camera )


app-settings-menu: Minor tweaks

app-settings-menu: Minor tweaks

--- client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
+++ client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
@@ -102,7 +102,7 @@
       tabHandleContainer : @mainTabHandleHolder
     ,null

-    @mainTabView.on "PaneDidShow", => KD.utils.wait 10, =>
+    @mainTabView.on "PaneDidShow", => @utils.wait 10, =>
       appManifest = getFrontAppManifest()
       @mainSettingsMenuButton[if appManifest?.menu then "show" else "hide"]()

@@ -120,10 +120,10 @@
     mc.sidebarController = new SidebarController view : @sidebar
     @sidebarPanel.addSubView @sidebar

-  getMainSettingsMenuButton:->
+  getMainSettingsMenuButton: ->
     new KDButtonView
       domId    : "main-settings-menu"
-      cssClass : "kdsettingsmenucontainer transparent hidden"
+      cssClass : "kdsettingsmenucontainer transparent"
       iconOnly : yes
       iconClass: "dot"
       callback : ->


Removing debug statements.

Removing debug statements.

--- src/construct/mdns.coffee
+++ src/construct/mdns.coffee
@@ -72,17 +72,17 @@
   _onMessage: (buffer, rinfo) =>
     packet = DnsPacket.parse(buffer)
     event = {address: rinfo.address, hostname: null}
-    console.log event
+    # console.log event

     for service in packet.answer
       # This would add ipv6 if we supported it:
       # event.address = service.address if service.type == 28
       continue unless service.class == 1 and service.type == 12
       continue unless service.data?
-      console.log service
+      # console.log service
       event.serviceName = serviceName = service.data.split(".")[0]
       event.path = "/printers/#{serviceName}/"
-    console.log event
+    # console.log event
     @emit "serviceUp", event
     clearInterval @mdnsInterval


remove atom-ternjs-client.coffee

remove atom-ternjs-client.coffee

--- lib/atom-ternjs-client.coffee
+++ lib/atom-ternjs-client.coffee
@@ -1,145 +0,0 @@
-module.exports =
-class Client
-
-  port: null
-  manager: null
-  projectDir: null
-
-  constructor: (manager, projectDir) ->
-    @manager = manager
-    @projectDir = projectDir
-
-  completions: (file, end) ->
-    @post('query', query:
-      type: 'completions'
-      file: file
-      end: end
-      types: true
-      includeKeywords: true
-      sort: @manager.packageConfig.options.sort
-      guess: @manager.packageConfig.options.guess
-      docs: @manager.packageConfig.options.documentation
-      urls: @manager.packageConfig.options.urls
-      origins: @manager.packageConfig.options.origins
-      lineCharPositions: true
-      caseInsensitive: @manager.packageConfig.options.caseInsensitive
-    )
-
-  documentation: (file, end) ->
-    @post('query', query:
-      type: 'documentation'
-      file: file
-      end: end
-    )
-
-  refs: (file, end) ->
-    @post('query', query:
-      type: 'refs'
-      file: file
-      end: end
-    )
-
-  updateFull: (editor, editorMeta) ->
-    editorMeta?.diffs = []
-    @post('query', files: [
-        type: 'full'
-        name: atom.project.relativizePath(editor.getURI())[1]
-        text: editor.getText()
-      ]
-    )
-
-  updatePart: (editor, editorMeta, start, text) ->
-    editorMeta?.diffs = []
-    @post('query', files: [
-        type: 'part'
-        name: atom.project.relativizePath(editor.getURI())[1]
-        offset: {line: start, ch: 0}
-        text: editor.getText()
-      ]
-    )
-
-  update: (editor) ->
-    editorMeta = @manager.getEditor(editor)
-    file = atom.project.relativizePath(editor.getURI())[1].replace(/\\/g, '/')
-    # check if this file is excluded via dontLoad
-    return Promise.resolve({}) if @manager.server?.dontLoad(file)
-    # check if the file is registered, else return
-    @files().then (data) =>
-      registered = data.files.indexOf(file) > -1
-      return Promise.resolve({}) if editorMeta and editorMeta.diffs.length is 0 and registered
-      if registered
-        buffer = editor.getBuffer()
-        # if buffer.getMaxCharacterIndex() > 5000
-        #   start = 0
-        #   end = 0
-        #   text = ''
-        #   for diff in editorMeta.diffs
-        #     start = Math.max(0, diff.oldRange.start.row - 50)
-        #     end = Math.min(buffer.getLineCount(), diff.oldRange.end.row + 5)
-        #     text = buffer.getTextInRange([[start, 0], [end, buffer.lineLengthForRow(end)]])
-        #   promise = @updatePart(editor, editorMeta, start, text)
-        # else
-        promise = @updateFull(editor, editorMeta)
-      else
-        Promise.resolve({})
-    , (err) ->
-      console.log err
-
-  rename: (file, end, newName) ->
-    @post('query', query:
-      type: 'rename'
-      file: file
-      end: end
-      newName: newName
-    )
-
-  lint: (file, text) ->
-    @post('query', query:
-      type: 'lint'
-      file: file,
-      files: [
-        type: 'full'
-        name: file
-        text: text
-      ]
-    )
-
-  type: (editor, position) ->
-    file = atom.project.relativizePath(editor.getURI())[1]
-    end = {line: position.row, ch: position.column}
-
-    @post('query', query:
-      type: 'type'
-      file: file
-      end: end
-      preferFunction: true
-    )
-
-  definition: ->
-    editor = atom.workspace.getActiveTextEditor()
-    cursor = editor.getLastCursor()
-    position = cursor.getBufferPosition()
-    file = atom.project.relativizePath(editor.getURI())[1]
-    end = {line: position.row, ch: position.column}
-
-    @post('query', query:
-      type: 'definition'
-      file: file
-      end: end
-    ).then (data) =>
-      if data?.start
-        @manager.helper?.setMarkerCheckpoint()
-        @manager.helper?.openFileAndGoTo(data.start, data.file)
-    , (err) ->
-      console.log err
-
-  files: ->
-    @post('query', query:
-      type: 'files'
-    ).then (data) =>
-      data
-
-  post: (type, data) ->
-    console.log(data);
-    promise = @manager.server.request(type, data)
-    return promise


check if enabled

check if enabled

--- lib/autohide-tree-view.coffee
+++ lib/autohide-tree-view.coffee
@@ -101,6 +101,7 @@
     @initialized = true

   enable: (treeViewPkg) ->
+    console.log 'autohide-tree-view: enable'
     treeViewPkg ?= atom.packages.getActivePackage 'tree-view'
     return unless treeViewPkg?
     @enabled = true
@@ -110,6 +111,7 @@
     @applyHiddenWidth()
     @applyAnimate()
     @hide true
+    console.log 'autohide-tree-view: enabled'

   disable: ->
     @enabled = false


bar-hierarchy: fixed bug with breadcrumb link not working

--- app/charts/bar-hierarchy.coffee
+++ app/charts/bar-hierarchy.coffee
@@ -373,8 +373,8 @@

   updateBreadcrumb = (node) ->
-
     path = breadcrumbPath node
+    console.log path

     breadcrumbList = breadcrumb.select("ul")
     # enter
@@ -404,8 +404,8 @@
     breadcrumbList.selectAll("li.node a")
       .attr("href", "#")
       .text((d) -> d[nameAttr])
-      .on "click", (d, i) ->
-        if (d != node) then up(d.children[0])
+      .on "click", (d, i) ->
+        if (i < path.length - 1) then up(path[i + 1]) #d.children[0])

     updateBreadcrumbCaption(node)


increased timeout to 4 mins....

increased timeout to 4 mins....

--- app/coffee/FileConverter.coffee
+++ app/coffee/FileConverter.coffee
@@ -4,7 +4,7 @@
 exec = require('child_process').exec
 approvedFormats = ["png"]

-twoMinsInMs = 2 * (60 * 1000)
+fourMinsInMs = 4 * (60 * 1000)

 module.exports =

@@ -18,7 +18,7 @@
 			return callback err
 		args = "nice convert -flatten -density 300 #{sourcePath} #{destPath}"
 		opts =
-			timeout: twoMinsInMs
+			timeout: fourMinsInMs
 		exec args, opts, (err, stdout, stderr)->
 			timer.done()
 			if err?
@@ -38,7 +38,7 @@
 			height: 300
 		args = "nice convert -flatten -background white -resize 260x -density 300 #{sourcePath} #{destPath}"
 		opts =
-			timeout: twoMinsInMs
+			timeout: fourMinsInMs
 		exec args, opts,(err, stdout, stderr)->
 			if err?
 				logger.err err:err, stderr:stderr, sourcePath:sourcePath, "something went wrong converting file to preview"
@@ -57,7 +57,7 @@
 			height: 849
 		args = "nice convert -flatten -background white -resize 548x -density 300 #{sourcePath} #{destPath}"
 		opts =
-			timeout: twoMinsInMs
+			timeout: fourMinsInMs
 		exec args, opts,(err, stdout, stderr)->
 			if err?
 				logger.err err:err, stderr:stderr, sourcePath:sourcePath, "something went wrong converting file to preview"


hard delete a doc on health check

hard delete a doc on health check

--- app/coffee/HealthChecker.coffee
+++ app/coffee/HealthChecker.coffee
@@ -1,4 +1,4 @@
-ObjectId = require("mongojs").ObjectId
+{db, ObjectId} = require "./mongojs"
 request = require("request")
 async = require("async")
 _ = require("underscore")
@@ -40,4 +40,4 @@
 		async.series jobs, (err)->
 			if err?
 				callback(err)
-			request.del getOpts(), callback
+			db.docs.remove {_id: doc_id, project_id: project_id}, callback


fix a bug while List.setLength: should remove invalidIndexes after last child

--- src/core/base/List.coffee
+++ src/core/base/List.coffee
@@ -197,6 +197,9 @@
   setLength: (newLength) ->
     children = @children
     last = children.length-1
+    if @node
+      insertLocation = binarySearch(newLength, @invalidIndexes)
+      @invalidIndexes = @invalidIndexes.slice(0, insertLocation)
     while last>=newLength
       @removeChild(last)
       last--


Warning about object-valued selector keys in denormed reactives

--- models.coffee
+++ models.coffee
@@ -845,6 +845,12 @@
                     qsString = J.fetching.stringifyQs querySpec

                     if J._watchedQuerySpecSet.get()?
+                        for selectorKey, value of selector
+                            if J.util.isPlainObject(value) and not _.any(k[0] is '$' for k of value)
+                                console.warn "***Dependencies for object-valued selector keys are untracked.
+                                    Use a combination of individual dot-paths instead."
+                                console.warn "    #{JSON.stringify querySpec, null, 4}"
+
                         J._watchedQuerySpecSet.get()[qsString] = true

                     mongoFieldsArg = J.fetching.projectionToMongoFieldsArg @, options.fields ? {}


Fixed camera

Fixed camera

Camera matrix stuff was wrong. Now it is right.

--- src/Camera.coffee
+++ src/Camera.coffee
@@ -1,10 +1,10 @@
-Pixi = require "pixi.js"
+Pixi = require 'pixi.js'
 Matrix = Pixi.Matrix
 Point = Pixi.Point

 # Controls the viewport
 class Camera
-  constructor: (@renderer, @x = 0, @y = 0, @z = 10.0, @angle = 0) ->
+  constructor: (@renderer, @x = 0, @y = 0, @z = 30.0, @angle = 0) ->
     @following = null

   # Make the camera center on this thing every frame
@@ -21,29 +21,25 @@
     return [@renderer.pixiRenderer.width, @renderer.pixiRenderer.height]

   # Convert screen coordinates to world coordinates
-  toWorld: (x, y) =>
+  toWorld: ([x, y], depth = 1.0) =>
     [w, h] = @getViewportSize()
-    if not x?
-      y = x.y
-      x = x.x
     p = new Point(x, y)
-    return @getMatrix().apply(p, p)
+    p = @getMatrix(depth).applyInverse(p, p)
+    return [p.x, p.y]

   # Convert world coordinates to screen coordinates
-  toScreen: (x, y) =>
+  toScreen: ([x, y], depth = 1.0) =>
     [w, h] = @getViewportSize()
-    if not x?
-      y = x.y
-      x = x.x
     p = new Point(x, y)
-    return @getMatrix().applyInverse(p, p)
+    p = @getMatrix(depth).apply(p, p)
+    return [p.x, p.y]

-  # Creates a transformation matrix to go from screen space to world space.
-  getMatrix: (scale = 1.0) =>
+  # Creates a transformation matrix to go from screen world space to screen space.
+  getMatrix: (depth = 1.0) =>
     [w, h] = @getViewportSize()
     m = new Matrix()
-    m.translate(-@x, -@y)
-    m.scale(@z * scale, @z * scale)
+    m.translate(-@x * depth, -@y * depth)
+    m.scale(@z * depth, @z * depth)
     m.rotate(@angle)
     m.translate(w / 2, h / 2)
     return m
@@ -53,13 +49,11 @@
     layer = layerInfo.layer
     [w, h] = @getViewportSize()

-    p = @toWorld(0, 0)
-
-    layer.x = p.x
-    layer.y = p.y
+    # [layer.x, layer.y] = [-@x + w / 2, -@y + h / 2]
+    [layer.x, layer.y] = @toScreen([0, 0])

     layer.rotation = @angle
     layer.scale.x = @z
-    layer.scale.y = -@z
+    layer.scale.y = @z

 module.exports = Camera


Test implementation for popupFeedPost.

Test implementation for popupFeedPost.

--- src/Carrot.coffee
+++ src/Carrot.coffee
@@ -132,6 +132,36 @@
     params['object_instance_id'] = objectInstanceId if objectInstanceId
     @postSignedRequest("/me/actions.json", params, @callbackHandler(callback))

+  popupFeedPost: (actionId, objectInstanceId, actionProperties, objectProperties, callback) ->
+    if FB?
+      actionProperties = if typeof actionProperties is "string" then actionProperties else JSON.stringify(actionProperties || {})
+      objectProperties = if typeof objectProperties is "string" then objectProperties else JSON.stringify(objectProperties || {})
+      params = {
+        'action_id': actionId,
+        'action_properties': actionProperties,
+        'object_properties': objectProperties
+      }
+      params['object_instance_id'] = objectInstanceId if objectInstanceId
+      @getSignedRequest("/me/tweet.json", params, (jqXHR) =>
+        FB.ui({
+            method: 'feed',
+            name: 'Facebook Dialogs',
+            link: 'https://developers.facebook.com/docs/dialogs/',
+            picture: 'http://fbrell.com/f8.jpg',
+            caption: 'Reference Documentation',
+            description: 'Dialogs provide a simple, consistent interface for applications to interface with users.'
+          },
+          (response) ->
+            if response and response.post_id
+              alert 'Post was published.'
+            else
+              alert 'Post was not published.'
+
+            callback(jqXHR.responseJSON) if callback
+        )
+      )
+
+
   getTweet: (actionId, objectInstanceId, actionProperties, objectProperties, callback) ->
     actionProperties = if typeof actionProperties is "string" then actionProperties else JSON.stringify(actionProperties || {})
     objectProperties = if typeof objectProperties is "string" then objectProperties else JSON.stringify(objectProperties || {})


test(macAutocomplete): Fixed broken test due to jasmine 2.0 update

--- test/unit/autocomplete.spec.coffee
+++ test/unit/autocomplete.spec.coffee
@@ -278,32 +278,22 @@
       $timeout     = _$timeout_

     it "should call select", ->
-      called            = false
-      selectedItem      = ""
       $rootScope.source = data
-      $rootScope.select = (selected) ->
-        selectedItem = selected
-        called       = true
+      $rootScope.select = jasmine.createSpy "select"

       element = $compile("<mac-autocomplete ng-model='test' mac-autocomplete-source='source' mac-autocomplete-on-select='select(selected)'></mac-autocomplete>") $rootScope
       $rootScope.$digest()

-      runs ->
-        changeInputValue element, "f"
-        $rootScope.$digest()
-
-        $timeout.flush()
-
-        element.triggerHandler
-          type: "keydown"
-          which: keys.ENTER
-
-      waitsFor ->
-        return called
-      , "selected item", 200
-
-      runs ->
-        expect(selectedItem).toBe "foo"
+      changeInputValue element, "f"
+      $rootScope.$digest()
+
+      $timeout.flush()
+
+      element.triggerHandler
+        type: "keydown"
+        which: keys.ENTER
+
+      expect($rootScope.select).toHaveBeenCalled()

     it "should call success", ->
       $httpBackend.when("GET", "/api/autocomplete?q=f").respond({data})


Remove React.createClass

Remove React.createClass

--- app/pages/lab/help/example.cjsx
+++ app/pages/lab/help/example.cjsx
@@ -1,6 +1,7 @@
 React = require 'react'
 counterpart = require 'counterpart'
 {Markdown} = require 'markdownz'
+createReactClass = require 'create-react-class'

 counterpart.registerTranslations 'en',
   example:
@@ -246,7 +247,7 @@
       *Note:* if you have a large subject set it may be cumbersome to manually create a manifest. We suggest using a command-line or other tool to copy-paste a directory list of files into a spreadsheet to help you get started.
     '''

-module.exports = React.createClass
+module.exports = createReactClass
   displayName: 'example'

   render: ->


more sensible default for numberOfLines

more sensible default for numberOfLines

--- lib/minimap-codeglance.coffee
+++ lib/minimap-codeglance.coffee
@@ -6,7 +6,7 @@
   config:
     numberOfLines:
       type: 'integer'
-      default: 3
+      default: 6
       minimum: 1
     panelLocation:
       type: 'string'


Fix bug related to paths containing spaces

Resolves #42

--- lib/parsers/log-parser.coffee
+++ lib/parsers/log-parser.coffee
@@ -30,7 +30,8 @@
       # Simplest Thing That Works™ and KISS®
       match = line.match(outputPattern)
       if match?
-        result.outputFilePath = path.resolve(@projectPath, match[1])
+        filePath = match[1].replace(/\"/g, '')  # TODO: Fix with improved regex.
+        result.outputFilePath = path.resolve(@projectPath, filePath)
         continue

       match = line.match(errorPattern)


Images optimization when compile production added.

--- app/templates/_Gruntfile.coffee
+++ app/templates/_Gruntfile.coffee
@@ -89,7 +89,7 @@
           pngquant: true
           cwd: 'app/compile/img'
           src: ['**/*.{png,jpg,gif}']
-          dest: 'app/compile/img/minified'
+          dest: 'app/production/img'
         ]

     watch:
@@ -115,5 +115,7 @@

   <% if (datauri) { %>grunt.loadNpmTasks "grunt-datauri"<% } %>

+  grunt.registerTask "make_production", ["imagemin"]
+
   grunt.registerTask "server", "connect"
   grunt.registerTask "default", "watch"


focus pane

focus pane

--- lib/runtime/evaluation.coffee
+++ lib/runtime/evaluation.coffee
@@ -101,28 +101,18 @@
     {editor, mod, edpath} = @currentContext()
     {word, range} = words.getWord(editor) unless word? and range?
     if word.length == 0 || !isNaN(word) then return
-    # client.import("docs")({word: word, mod: mod}).then (result) =>
-    #   if result.error then return
-    #   v = views.render result
-    #   processLinks(v.getElementsByTagName('a'))
-    #   if atom.config.get('julia-client.uiOptions.docsDisplayMode') == 'inline'
-    #     d = new @ink.InlineDoc editor, range,
-    #       content: v
-    #       highlight: true
-    #     d.view.classList.add 'julia'
-    #   else
-    #     docpane.pane.showDocument(v, [])
-    if atom.config.get('julia-client.uiOptions.docsDisplayMode') == 'inline'
-      client.import("docs")({word: word, mod: mod}).then (result) =>
-        if result.error then return
-        v = views.render result
-        processLinks(v.getElementsByTagName('a'))
+    client.import("docs")({word: word, mod: mod}).then (result) =>
+      if result.error then return
+      v = views.render result
+      processLinks(v.getElementsByTagName('a'))
+      if atom.config.get('julia-client.uiOptions.docsDisplayMode') == 'inline'
         d = new @ink.InlineDoc editor, range,
           content: v
           highlight: true
         d.view.classList.add 'julia'
-    else
-      docpane.pane._search(word, mod, false, false, true)
+      else
+        docpane.pane.open()
+        docpane.pane.showDocument(v, [])

   showError: (r, lines) ->
     @errorLines?.lights.destroy()


fix non english characters being used as file names

--- lib/sources/championgg.coffee
+++ lib/sources/championgg.coffee
@@ -305,9 +305,7 @@
     }

   # Inserts new item sets in to a global object to be used when we get to saving files.
-  pushChampData = (champ, position, build) ->
-    positionForFile = position.replace(/ /g, '_')
-
+  pushChampData = (champ, position, positionForFile, build) ->
     if _.includes(position, 'adc')
       title = position.toUpperCase()
     else
@@ -335,13 +333,13 @@
   # If split item sets
   if window.cSettings.splititems
     builds = splitItemSets()
-    pushChampData(champ, "#{currentPosition} MostFrequent", builds.mfBuild)
-    pushChampData(champ, "#{currentPosition} HighestWin", builds.hwBuild)
+    pushChampData(champ, "#{currentPosition} #{T.t('most_freq')}", "#{currentPosition}_mostfreq", builds.mfBuild)
+    pushChampData(champ, "#{currentPosition} #{T.t('highest_win')}", "#{currentPosition}_highwin", builds.hwBuild)

   # If normal item sets
   else
     builds = normalItemSets()
-    pushChampData(champ, currentPosition, builds)
+    pushChampData(champ, currentPosition, currentPosition, builds)

   # TODO: Lodash map.
   # Now we execute for the other positions for the champs, if there are any.


Fix harmless error

Fix harmless error

--- apps/search/client/index.coffee
+++ apps/search/client/index.coffee
@@ -15,11 +15,12 @@
     'click .search-result' : 'trackClick'

   initialize: (options) ->
-    for result in options.results
-      if result.display_model == 'artist'
-        @initializeArtistRow result
-      else if result.display_model == 'category'
-        @initializeGeneRow result
+    if options.results
+      for result in options.results
+        if result.display_model is 'artist'
+          @initializeArtistRow result
+        else if result.display_model is 'category'
+          @initializeGeneRow result

   initializeArtistRow: (result) ->
     new Artist(id: result.id).fetchArtworks


some csl vars need special care

some csl vars need special care

--- resource/translators/reference.coffee
+++ resource/translators/reference.coffee
@@ -411,6 +411,9 @@
       if name == 'referencetype'
         @referencetype = value.value
         continue
+
+      # these are handled just like 'arxiv' and 'lccn', respectively
+      value.format = 'key-value' if name in ['pmid', 'pmcid']

       switch value.format
         # CSL names are not in BibTeX format, so only add it if there's a mapping


restored view content because it crashes without it

--- lib/sync-settings-view.coffee
+++ lib/sync-settings-view.coffee
@@ -4,6 +4,9 @@

 module.exports =
 class SyncSettingsView extends View
+  @content: ->
+    @div class: 'sync-settings overlay from-top', =>
+      @div "The SyncSettings package is Alive! It's ALIVE!", class: "message"

   initialize: (serializeState) ->
     @gist = null


Tests: Updated timeouts.

Tests: Updated timeouts.

--- tests/src/activity/activity.coffee
+++ tests/src/activity/activity.coffee
@@ -65,7 +65,7 @@
       .click                 '.kdcontextmenu .edit-post'
       .clearValue            activitySelector + ' .edit-widget [testpath=ActivityInputView]'
       .setValue              activitySelector + ' .edit-widget [testpath=ActivityInputView]', post + '\n'
-      .pause                 3000
+      .pause                 10000
       .assert.containsText   activitySelector, post # Assertion
       .end()

@@ -82,7 +82,7 @@
       .click                        activitySelector + ' .settings-menu-wrapper'
       .click                        '.kdcontextmenu .delete-post'
       .click                        '.kdmodal-inner .modal-clean-red'
-      .pause                        3000, ->
+      .pause                        10000, ->
         text = browser.getText activitySelector
         assert.notEqual text, post # Assertion
       .end()
@@ -96,7 +96,7 @@
     commentSelector = activitySelector + ' .comment-container .kdlistitemview-comment:first-child'

     browser
-      .waitForElementVisible    commentSelector, 3000
+      .waitForElementVisible    commentSelector, 10000
       .click                    commentSelector + ' [testpath=activity-like-link]'
       .waitForElementVisible    commentSelector + ' .liked:not(.count)', 10000 # Assertion
       .end()
@@ -110,9 +110,9 @@
     commentSelector = activitySelector + ' .comment-container .kdlistitemview-comment:first-child'

     browser
-      .waitForElementVisible    commentSelector, 3000
+      .waitForElementVisible    commentSelector, 10000
       .click                    commentSelector + ' [testpath=activity-like-link]'
-      .waitForElementVisible    commentSelector + ' [testpath=activity-like-link]', 3000
+      .waitForElementVisible    commentSelector + ' [testpath=activity-like-link]', 10000
       .click                    commentSelector + ' [testpath=activity-like-link]'
       .waitForElementVisible    commentSelector + ' .liked:not(.count)', 10000 # Assertion
       .end()
@@ -125,13 +125,13 @@
     post            =  helpers.getFakeText()

     browser
-      .waitForElementPresent    commentSelector, 3000
+      .waitForElementPresent    commentSelector, 10000
       .click                    commentSelector
-      .waitForElementVisible    '.kdcontextmenu .edit-comment', 5000
+      .waitForElementVisible    '.kdcontextmenu .edit-comment', 10000
       .click                    '.kdcontextmenu .edit-comment'
       .clearValue               activitySelector + ' .comment-container .comment-input-widget [testpath=CommentInputView]'
       .setValue                 activitySelector + ' .comment-container .comment-input-widget [testpath=CommentInputView]', post + '\n'
-      .pause                    3000
+      .pause                    10000
       .assert.containsText      activitySelector + ' .comment-container', post # Assertion
       .end()

@@ -144,12 +144,12 @@
     post            =  helpers.getFakeText()

     browser
-      .waitForElementPresent    commentSelector, 3000
+      .waitForElementPresent    commentSelector, 10000
       .click                    commentSelector
-      .waitForElementVisible    '.kdcontextmenu .delete-comment', 5000
+      .waitForElementVisible    '.kdcontextmenu .delete-comment', 10000
       .click                    '.kdcontextmenu .delete-comment'
       .click                    '.kdmodal-inner .modal-clean-red'
-      .pause                    3000, ->
+      .pause                    10000, ->
         text = browser.getText activitySelector + ' .comment-container'
         assert.notEqual text, post # Assertion
       .end()
@@ -162,12 +162,12 @@
     commentSelector = activitySelector + ' .comment-container button.comment-menu'

     browser
-      .waitForElementPresent    commentSelector, 5000
+      .waitForElementPresent    commentSelector, 10000
       .click                    commentSelector
-      .waitForElementVisible    '.kdcontextmenu .delete-comment', 5000
+      .waitForElementVisible    '.kdcontextmenu .delete-comment', 10000
       .click                    '.kdcontextmenu .delete-comment'
       .click                    '.kdmodal-inner .modal-cancel'
-      .waitForElementNotPresent '.kdoverlay', 5000
+      .waitForElementNotPresent '.kdoverlay', 10000
       .assert.containsText      activitySelector + ' .comment-container', comment # Assertion
       .end()

@@ -180,8 +180,9 @@

   #   browser
   #     .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
-  #     .waitForElementVisible    '.kdtabpaneview.search', 15000
-  #     .waitForElementVisible    selector, 15000
+  #     .waitForElementVisible    '.kdtabpaneview.search', 10000
+  #     .waitForElementVisible    selector, 10000
+  #     .pause                    10000
   #     .assert.containsText      selector, word # Assertion
   #     .end()

@@ -218,6 +219,7 @@

   #   browser
   #     .waitForElementVisible   '[testpath=channel-title]' + ' .following', 2000
+  #     .pause                    10000
   #     .click                   '[testpath=channel-title]' + ' .following'
   #     .waitForElementVisible   '[testpath="public-feed-link/Activity/Topic/public"]', 2000
   #     .click                   '[testpath="public-feed-link/Activity/Topic/public"]'


new(webapi): use secure api connection

new(webapi): use secure api connection

--- src/WebAPI.coffee
+++ src/WebAPI.coffee
@@ -1,6 +1,6 @@
 # Copyright (c) 2015 Markus Kohlhase <mail@markus-kohlhase.de>

-URL       = "http://api.ofdb.io/v0"
+URL       = "https://api.ofdb.io/v0"
 NOMINATIM = "http://nominatim.openstreetmap.org"
 request   = require "superagent/lib/client"
 saPrefix  = require "superagent-prefix"


Server: removed missing module

Server: removed missing module

--- workers/social/lib/social/render/loggedout/grouphome.coffee
+++ workers/social/lib/social/render/loggedout/grouphome.coffee
@@ -6,7 +6,6 @@
   fetchScripts = require './../scriptblock'
   getGraphMeta = require './../graphmeta'
   getTitle     = require './../title'
-  getSidebar   = require './sidebar'

   {
     account, slug, title, content, body,


fix file.url for native or browser

fix file.url for native or browser

--- www/js/model.coffee
+++ www/js/model.coffee
@@ -136,7 +136,7 @@
 			res.ctime = new Date(Date.parse(res.ctime))
 			res.mtime = new Date(Date.parse(res.mtime))
 			res.iconUrl = iconUrl(res.contentType)
-			res.url = if env.isMobile() then "#{env.serverUrl()}/api/file/content/#{res.path}" else "#{env.serverUrl()}/#{res.path}"
+			res.url = if env.isNative() then "#{env.serverUrl()}/api/file/content/#{res.path}" else "#{env.serverUrl()}/#{res.path}"
 			return new File res

 		$parse: (res, opts) ->


spec: fix 404 spam in DiscussionTopics/EditViewSpec

Test Plan:
1. On master, run the spec for
   spec/coffeescripts/views/DiscussionTopics/EditViewSpec.coffee. Verify
   you see many warnings in the terminal that look like:

   11 06 2017 16:35:32.778:WARN [web-server]: 404: /api/v1/courses/1/groups
   11 06 2017 16:35:32.837:WARN [web-server]: 404: /api/v1/users/1/assignment_groups?include%5B%5D=assignments

2. Run the same spec with this commit checked out and verify you do not
   see any of the errors mentioned above.

Change-Id: Ia37ff311fbcb1d4ee3677bf2e28271ef56349b43
Reviewed-on: https://gerrit.instructure.com/115030
Reviewed-by: Gary Mei <4dff5ebcff9ed76793b70b9470ac64791a16ed11@instructure.com>
Reviewed-by: Jeremy Neander <20252aad5efdc666f083d82ab63ed0f9f72a043e@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>
QA-Review: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>

--- spec/coffeescripts/views/DiscussionTopics/EditViewSpec.coffee
+++ spec/coffeescripts/views/DiscussionTopics/EditViewSpec.coffee
@@ -85,7 +85,9 @@
   QUnit.module 'EditView',
     setup: ->
       fakeENV.setup()
+      @server = sinon.fakeServer.create(respondImmediately: true)
     teardown: ->
+      @server.restore()
       fakeENV.teardown()
     editView: ->
       editView.apply(this, arguments)
@@ -228,7 +230,9 @@
       ENV.CONDITIONAL_RELEASE_SERVICE_ENABLED = true
       ENV.CONDITIONAL_RELEASE_ENV = { assignment: { id: 1 }, jwt: 'foo' }
       $(document).on 'submit', -> false
+      @server = sinon.fakeServer.create(respondImmediately: true)
     teardown: ->
+      @server.restore()
       fakeENV.teardown()
       $(document).off 'submit'
     editView: ->


Segragate SSL details fetching from the server launch

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -227,26 +227,40 @@
             message = "Exception while launching HTTP server:\r\n%s"
             logger.warn message.red, error.stack; process.exit -1

+    # This routine takes care of resolving all the necessary details
+    # for successfully creating and running an HTTPS (SSL) server.
+    # The details are typically at least the key and the certficiate.
+    # This implementation draws data from the config file and then
+    # used it to obtain the necessary content and whater else needs.
+    resolveSslDetails: ->
+        assert secure = nconf.get "secure"; options = {}
+        key = paths.relative process.cwd(), secure.key
+        cert = paths.relative process.cwd(), secure.cert
+        logger.info "Using SSL key file at %s".grey, key
+        logger.info "Using SSL cert file at %s".grey, cert
+        logger.debug "Assembling the HTTPS options".grey
+        options.key = fs.readFileSync paths.resolve key
+        options.cert = fs.readFileSync paths.resolve cert
+        assert options.cert.length >= 64, "invalid SSL cert"
+        assert options.key.length >= 64, "invalid SSL key"
+        options.secure = secure; return Object options
+
     # Setup and launch either HTTP or HTTPS servers to listen at
     # the configured addresses and ports. This method reads up the
     # scoping configuration in order to obtain the data necessary
     # for instantiating, configuring and launching up the servers.
     startupHttpsServer: ->
-        options = Object.create {}
-        assert secure = nconf.get "secure"
         assert server = nconf.get "server"
-        assert host = nconf.get "server:host"
-        assert port = server.https, "no HTTPS port"
-        key = paths.relative process.cwd(), secure.key
-        cert = paths.relative process.cwd(), secure.cert
-        logger.info "Using SSL key file at %s".grey, key
-        logger.info "Using SSL cert file at %s".grey, cert
-        options.key = fs.readFileSync paths.resolve key
-        options.cert = fs.readFileSync paths.resolve cert
-        rsecure = "Running HTTPS server at %s".magenta
-        logger.info rsecure, "#{host}:#{port}".underline
+        assert hostname = nconf.get "server:host"
+        assert _.isNumber(server.https), "no HTTPS port"
+        assert _.isObject options = @resolveSslDetails()
+        running = "Running HTTPS server at %s".magenta
+        location = "#{hostname}:#{server.https}".toString()
+        logger.info running.underline, location.underline
         @secure = https.createServer options, @connect
-        @secure?.listen server.https, host; return @
+        @secure.listen server.https, hostname
+        @secure.on "connection", (socket) ->
+            return socket.setNoDelay yes

     # Setup and launch either HTTP or HTTPS servers to listen at
     # the configured addresses and ports. This method reads up the
@@ -256,11 +270,11 @@
         assert server = nconf.get "server"
         assert hostname = nconf.get "server:host"
         assert _.isNumber(server.http), "no HTTP port"
-        rserver = "Running HTTP server at %s".magenta
-        assert location = "#{hostname}:#{server.http}"
-        logger.info rserver, location.underline
-        @server = http.createServer @connect
-        @server?.listen server.http, hostname
+        running = "Running HTTP server at %s".magenta
+        location = "#{hostname}:#{server.http}".toString()
+        logger.info running.underline, location.underline
+        @server = http.createServer @connect, undefined
+        @server.listen server.http, hostname
         @server.on "connection", (socket) ->
             return socket.setNoDelay yes


Updated generic-parser (fixes)

Updated generic-parser (fixes)

--- src/generic-parser.coffee
+++ src/generic-parser.coffee
@@ -169,18 +169,18 @@
   ignore: (stringArray)->
     if typeof stringArray is 'string'
       stringArray = [stringArray]
-    parser.collectUntilFalse => parser.takeIfInStringArray stringArray
+    @collectUntilFalse => @takeIfInStringArray stringArray
     return

   takeAll: (stringArray)->
     if typeof stringArray is 'string'
       stringArray = [stringArray]
-    return parser.collectUntilFalse => parser.takeIfInStringArray stringArray
+    return @collectUntilFalse => @takeIfInStringArray stringArray

   takeAllUntil: (stringArray)->
     if typeof stringArray is 'string'
       stringArray = [stringArray]
-    return takeUntilInStringArray stringArray
+    return @takeUntilInStringArray stringArray


remove empty args

remove empty args

--- src/hubot-influxdb.coffee
+++ src/hubot-influxdb.coffee
@@ -253,7 +253,7 @@
   #automatically turn on alerts if configured
   alert_room = nconf.get "HUBOT_INFLUXALERTS_AUTO_ALERT_ROOM"
   if alert_room
-    alertIntervalId = setInterval () ->
+    alertIntervalId = setInterval ->
       check_for_alerts robot
     , nconf.get("ALERT_HUBOT_INFLUXALERTS_CHECK_INTERVAL")

@@ -262,7 +262,7 @@
       msg.send "Alert checking already on"
       return

-    alertIntervalId = setInterval () ->
+    alertIntervalId = setInterval ->
       check_for_alerts(robot, undefined)
     , nconf.get("ALERT_HUBOT_INFLUXALERTS_CHECK_INTERVAL")
     msg.send "Alert checking toggled on (corpsethumb)"


Change pm bundle from motoz3 to OnePlus6

--- assets/coffeescript/product_list.coffee
+++ assets/coffeescript/product_list.coffee
@@ -161,7 +161,7 @@
   return ['hololens_w120_e200b', 'htcvive_e200b', 'epsonbt300_w120_e200b']

 get_additional_product_ids = ->
-  return ['camera_e200l','camera_e200r','pm_motoz3','support_6','support_12']
+  return ['camera_e200l','camera_e200r','pm_oneplus6','support_6','support_12']

 get_product_database = ->
@@ -659,6 +659,13 @@
       description_store: "Connect your Pupil headset to the Moto Z3 play. Record up to 4 hours of video locally on the phone, or stream video and sensor data over Wifi. The bundle comes with: Moto Z3 Play (blue), hot-swappable Moto power pack, 64gb SD card, USBC-USBC cable, and is pre-loaded with the Pupil Mobile app. (Note: Pupil headsets with 3d world camera are not compatible with Pupil Mobile)."
       description_cart: "Moto Z3 Play (blue), hot-swappable Moto power pack, 64gb SD card, USBC-USBC cable, and is pre-loaded with the Pupil Mobile app. Connects to Pupil headset via USBC cable (included)."
       img: [additional_product_path,'pm_nexus5x.jpg'].join('/')
+    pm_oneplus6:
+      cost: 750
+      title_product: 'Pupil Mobile Bundle'
+      title_store: "Pupil Mobile Bundle"
+      description_store: "Connect your Pupil headset to the OnePlus 6. Record up to 2.5 hours of video locally on the phone, or stream video and sensor data over Wifi. The bundle comes with: OnePlus 6 128gb, USBC-USBC cable, and is pre-loaded with the Pupil Mobile app. (Note: Pupil headsets with 3d world camera are not compatible with Pupil Mobile)."
+      description_cart: "OnePlus 6 128gb, USBC-USBC cable, and is pre-loaded with the Pupil Mobile app. Connects to Pupil headset via USBC cable (included)."
+      img: [additional_product_path,'pm_nexus5x.jpg'].join('/')
     support_6:
       cost: 1000
       title_product: 'Support Contract'


Remove transitionTo deprecation warning

Remove transitionTo deprecation warning

--- app/assets/javascripts/controllers/task_controller.js.coffee
+++ app/assets/javascripts/controllers/task_controller.js.coffee
@@ -7,5 +7,5 @@
       @send(@get('onClose'))

     showManager: ->
-      @transitionTo('paper.manage', @get('paper'))
+      @transitionToRoute('paper.manage', @get('paper'))


Emit close with code and message for debugging

--- src/client.coffee
+++ src/client.coffee
@@ -120,12 +120,12 @@
         # flags.masked will be set if the data was masked
         @onMessage JSON.parse(data)

-      @ws.on 'error', (error)=>
+      @ws.on 'error', (error) =>
         # TODO: Reconnect?
         @emit 'error', error

-      @ws.on 'close', =>
-        @emit 'close'
+      @ws.on 'close', (code, message) =>
+        @emit 'close', code, message
         @connected = false
         @socketUrl = null


Fix #93 - Test config on windows

Fix #93 - Test config on windows

--- lib/config.coffee
+++ lib/config.coffee
@@ -65,7 +65,7 @@
             return false

         # Test Composer.
-        testResult = exec.spawnSync(@config.composer, ["--version"])
+        testResult = exec.spawnSync(@config.php, [@config.composer, "--version"])

         if testResult.status = null or testResult.status != 0
             atom.notifications.addError(errorTitle, {'detail': errorMessage})


Fix bug in 16e273944c

Fix bug in 16e273944c

A `<` had accidentally been replaced with a `>`. Doh!

--- extension/packages/huffman.coffee
+++ extension/packages/huffman.coffee
@@ -66,7 +66,7 @@

     # Find the index to insert the sum so that the sorting is maintained. That is faster than
     # sorting the elements in each iteration.
-    break for element, index in elements by -1 when sum.weight >= element.weight
+    break for element, index in elements by -1 when sum.weight <= element.weight
     elements.splice(index + 1, 0, sum)

   root = elements[0] # `elements.length == 1` by now.


Remove deprecations

Remove deprecations

--- lib/load-paths-handler.coffee
+++ lib/load-paths-handler.coffee
@@ -1,7 +1,7 @@
 fs = require 'fs'
 path = require 'path'
 _ = require 'underscore-plus'
-{Git} = require 'atom'
+{GitRepository} = require 'atom'
 {Minimatch} = require 'minimatch'

 asyncCallsInProgress = 0
@@ -69,5 +69,5 @@
       console.warn "Error parsing ignore pattern (#{ignore}): #{error.message}"

   callback = @async()
-  repo = Git.open(rootPath, refreshOnWindowFocus: false) if ignoreVcsIgnores
+  repo = GitRepository.open(rootPath, refreshOnWindowFocus: false) if ignoreVcsIgnores
   loadFolder(rootPath)