isCoach bug fix

isCoach bug fix

Use “of” for object/dictionary membership

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -31,7 +31,7 @@
         return @model.get('loaded')
       isCoach: ->
         moduleUUID = @model.getUuid()?.split('?')[0]
-        _.contains(settings.conceptCoach.moduleUuids, moduleUUID)
+        moduleUUID of settings.conceptCoach.moduleUuids

     editable:
       '.media-body':


added test for the different versions of `precious object`

--- test/mocha/cli.spec.coffee
+++ test/mocha/cli.spec.coffee
@@ -66,6 +66,18 @@
               fixFloats: true

+  # Object
+  describe "o[bject]`, given a spec-conforming json string", ->
+    it "produces the expected output", ->
+      (proExec "cat test/io/for/nativity.json").then (input) ->
+        (proExec "#{precious} o '#{input}'").then (result) ->
+          (proExec "#{precious} object '#{input}'").then (also) ->
+            (proExec "cat test/io/out/nativity.json").then (expected) ->
+              assertSame [result, also, expected],
+                parse: true
+                fixFloats: true
+
+
   # Consistency

   describe '{*}` re-run with the extra [0]["re"]', ->


positioning

positioning

--- public/javascripts/tetris.coffee
+++ public/javascripts/tetris.coffee
@@ -7,7 +7,7 @@

 window.startTetris = (gs) ->

-  Tetris = {
+  Tetris =
     gridSize: 20
     blockSize: 18
     shapes: {}
@@ -17,7 +17,6 @@
       gs.addEntity(level)
       pusher.connection.bind 'connected', ->
         gs.addEntity(Tetris.Shape.randomShape(x:0, y:0, color: '#ff0', owned: true))
-  }

   class Level
     constructor: ->
@@ -43,8 +42,8 @@

     draw: (c) ->
       drawBlock = (blockDef) =>
-        x = (@x*Tetris.gridSize) + (blockDef[0]*Tetris.gridSize)
-        y = (@y*Tetris.gridSize) + (blockDef[1]*Tetris.gridSize)
+        x = (@x*Tetris.gridSize) + (blockDef[0]*Tetris.gridSize) + 1
+        y = (@y*Tetris.gridSize) + (blockDef[1]*Tetris.gridSize) + 1
         c.fillStyle = @color
         c.fillRect(x, y, Tetris.blockSize, Tetris.blockSize)
       definition = @shapeDefinition(this.rotation)


fix crash

fix crash

--- lib/codeglance-view.coffee
+++ lib/codeglance-view.coffee
@@ -20,12 +20,7 @@
     @style.height = nLines * @getLineHeight() + 'px'

   getLineHeight: ->
-    @style.transform = 'translateY(100000px)'
-    @show()
-    lineHeight = @editorView.shadowRoot.querySelector('.line').clientHeight
-    @hide()
-    @style.transform = ''
-    lineHeight
+    lineHeight = @editor.getLineHeightInPixels()

   resetGrammar: ->
     grammar = switch atom.config.get 'minimap-codeglance.useSyntaxTheme'
@@ -68,10 +63,10 @@
     gutter.hide() for gutter in @editor.getGutters()

   setMinimap: (@minimap) ->
+    @attach()
+    @resize()
     @resetGrammar()
     @resetText()
-    @attach()
-    @resize()

   showLinesAtOffset: (offset) ->
     @fixDisplayBufferHeight()


Prefer Editor.getModel().

Prefer Editor.getModel().

--- lib/conflict-marker.coffee
+++ lib/conflict-marker.coffee
@@ -14,7 +14,7 @@
   Subscriber.includeInto this

   constructor: (@state, @editorView) ->
-    @conflicts = Conflict.all(@state, @editorView.getEditor())
+    @conflicts = Conflict.all(@state, @editorView.getModel())
     @adapter = EditorAdapter.adapt(@editorView)

     @editorView.addClass 'conflicted' if @conflicts


Focus input when moving to console closes #27

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -104,6 +104,9 @@
       p = p.splitDown()
       p.setFlexScale 1/2
     p.activateItem @view
+    p.onDidActivate => setTimeout =>
+      if document.activeElement == @view[0]
+          @view.focusInput(true)

   toggle: ->
     if atom.workspace.getPaneItems().indexOf(@view) > -1


Fix typo

Fix typo

--- lib/emojis-provider.coffee
+++ lib/emojis-provider.coffee
@@ -4,7 +4,7 @@
 emoji = require('emoji-images')

 module.exports =
-  selector: '.source.gfm, .text.md .text.html, .text.slim, .text.plain, .text.git-commit, .comment, .string, .source.emojicode'
+  selector: '.source.gfm, .text.md, .text.html, .text.slim, .text.plain, .text.git-commit, .comment, .string, .source.emojicode'

   wordRegex: /::?[\w\d_\+-]+$/
   emojiFolder: 'atom://autocomplete-emojis/node_modules/emoji-images/pngs'


payment: add a JPaymentSubscription#checkUsage method

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -17,9 +17,17 @@
       uuid          : 'unique'
     sharedMethods   :
       static        : [
-        'fetchUserSubscriptions', 'fetchUserSubscriptionsWithPlan', 'checkUserSubscription'
+        'fetchUserSubscriptions'
+        'fetchUserSubscriptionsWithPlan'
+        'checkUserSubscription'
       ]
-      instance      : ['cancel', 'resume', 'calculateRefund', 'spend']
+      instance      : [
+        'cancel'
+        'resume'
+        'calculateRefund'
+        'spend'
+        'checkUsage'
+      ]
     schema          :
       uuid          : String
       planCode      : String
@@ -157,6 +165,15 @@
       return callback err  if err
       update_ sub, callback

+  checkUsage: (product, callback) ->
+    { quantities } = product
+
+    unless quantities?
+      quantities = {}
+      quantities[product.planCode] = 1
+
+    callback { message: 'this needs to be implemented' }, quantities
+
   spend: secure (client, options, callback) ->
     JPaymentPlan = require './plan'


Interact with DevTools asynchronously

Interact with DevTools asynchronously

--- src/application-delegate.coffee
+++ src/application-delegate.coffee
@@ -66,13 +66,13 @@
     ipc.send("call-window-method", "setFullScreen", fullScreen)

   openWindowDevTools: ->
-    remote.getCurrentWindow().openDevTools()
+    ipc.send("call-window-method", "openDevTools")

   toggleWindowDevTools: ->
-    remote.getCurrentWindow().toggleDevTools()
+    ipc.send("call-window-method", "toggleDevTools")

   executeJavaScriptInWindowDevTools: (code) ->
-    remote.getCurrentWindow().executeJavaScriptInDevTools(code)
+    ipc.send("call-window-method", "executeJavaScriptInDevTools", code)

   setWindowDocumentEdited: (edited) ->
     ipc.send("call-window-method", "setDocumentEdited", edited)


Remove www.

Remove www.

--- lib/available-package-view.coffee
+++ lib/available-package-view.coffee
@@ -31,7 +31,7 @@
           @installButton.text('Installed')

     @learnMoreButton.on 'click', =>
-      shell.openExternal "https://www.atom.io/packages/#{@pack.name}"
+      shell.openExternal "https://atom.io/packages/#{@pack.name}"

   setStatusIcon: (iconName) ->
     @status.removeClass('icon-check icon-alert icon-cloud-download')


lets make markdown-preview do the rendering

this is depending on markdown-preview version
[0.58.0](https://github.com/atom/markdown-preview/releases/tag/v0.58.0)

--- lib/installed-package-view.coffee
+++ lib/installed-package-view.coffee
@@ -4,7 +4,6 @@
 _ = require 'underscore-plus'
 fs = require 'fs-plus'
 shell = require 'shell'
-roaster = require 'roaster'
 {View} = require 'atom'

 ErrorView = require './error-view'
@@ -119,14 +118,7 @@

   openMarkdownFile: (path) ->
     if atom.packages.isPackageActive('markdown-preview')
-      content = fs.readFileSync(path, {encoding: 'UTF-8'})
-      sanitize = true
-      roaster content, {sanitize}, (error, html) =>
-        if error
-          console.error(error)
-        else
-          atom.workspace.open("markdown-preview://" + path).done (markdown) ->
-            markdown.html(html)
+      atom.workspace.open("markdown-preview://" + path)
     else
       atom.workspaceView.open(path)


:art:

:art:

--- lib/package-generator-view.coffee
+++ lib/package-generator-view.coffee
@@ -62,8 +62,7 @@
         @close()

   getPackagePath: ->
-    packagePath = @miniEditor.getText()
-    packagePath = packagePath.trim()
+    packagePath = @miniEditor.getText().trim()
     packageName = _.dasherize(path.basename(packagePath))
     path.join(path.dirname(packagePath), packageName)


Adding the close

Adding the close

--- app/assets/javascripts/darkswarm/controllers/checkout/billing_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/checkout/billing_controller.js.coffee
@@ -8,4 +8,4 @@
     $scope.order.bill_address.city,
     $scope.order.bill_address.zipcode]

-  #$timeout $scope.onTimeout
+  $timeout $scope.onTimeout


auth should conditionally check for token

--- lib/middleware/auth.coffee
+++ lib/middleware/auth.coffee
@@ -8,4 +8,5 @@
 module.exports = (p_req) ->

   Backbone.sync.editRequest = (req) ->
-    req.set('X-AUTH-TOKEN': p_req.user.get('authentication_token'))+    if p_req.user?
+      req.set('X-AUTH-TOKEN': p_req.user.get('authentication_token'))


add delete button

add delete button

--- BackofficeBundle/Resources/public/coffee/adminFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/adminFormView.coffee
@@ -2,19 +2,18 @@
   el: '#OrchestraBOModal'

   initialize: (options) ->
+    console.log options
     @url = options.url
     @options = options
     @deleteButton = @options.deleteurl && @options.confirmtext && @options.confirmtitle
     @method = if options.method then options.method else 'GET'
     @events = {}
-    if @deleteButton
-      @events['click .submit_form'] = 'addEventOnSave'
-    else
-      @events['submit form'] = 'addEventOnSave'
     if options.triggers
       for i of options.triggers
         @events[options.triggers[i].event] = options.triggers[i].name
         eval "this." + options.triggers[i].name + " = options.triggers[i].fct"
+    @formEvent = 'submit'
+    @formClass = 'form'
     @loadTemplates [
         'deleteButton'
     ]
@@ -46,34 +45,38 @@
       $('.modal-footer', @el).html @renderTemplate('deleteButton', @options)
       $('.modal-footer', @el).removeClass("hidden-info")
       $('.modal-footer', @el).prepend($('.submit_form', @$el))
+      @formEvent = 'click'
+      @formClass = '.submit_form'
     $("[data-prototype]", @$el).each ->
       PO.formPrototypes.addPrototype $(this)
       return
+    @addEventOnSave()
     Backbone.Wreqr.radio.commands.execute 'widget', 'loaded', @$el

-  addEventOnSave: (event) ->
-    event.preventDefault() # prevent native submit
-    displayLoader($('.submit_form', @$el).parent())
-    viewContext = @
-    $("form", viewContext.$el).ajaxSubmit
-      statusCode:
-        200: (response) ->
-          viewContext.renderContent(
-            html: response
-          )
-          if $('#node_nodeId', viewContext.$el).length > 0
-            displayRoute = appRouter.generateUrl "showNode",
-              nodeId: $('#node_nodeId', viewContext.$el).val()
-          else if $('#template_templateId', viewContext.$el).length > 0
-            displayRoute = appRouter.generateUrl "showTemplate",
-              templateId: $('#template_templateId', viewContext.$el).val()
-          else
-            displayRoute = Backbone.history.fragment
-            Backbone.history.loadUrl(displayRoute)
-          displayMenu(displayRoute)
-        400: (response) ->
-          viewContext.renderContent(
-            html: response.responseText
-          )
+  addEventOnSave: ->
+    viewContext = this
+    $(@formClass, @$el).on @formEvent, (e) ->
+      e.preventDefault() # prevent native submit
+      displayLoader($('.submit_form', viewContext.$el).parent())
+      $("form", viewContext.$el).ajaxSubmit
+        statusCode:
+          200: (response) ->
+            view = viewContext.renderContent(
+              html: response
+            )
+            if $('#node_nodeId', viewContext.$el).length > 0
+              displayRoute = appRouter.generateUrl "showNode",
+                nodeId: $('#node_nodeId', viewContext.$el).val()
+            else if $('#template_templateId', viewContext.$el).length > 0
+              displayRoute = appRouter.generateUrl "showTemplate",
+                templateId: $('#template_templateId', viewContext.$el).val()
+            else
+              displayRoute = Backbone.history.fragment
+              Backbone.history.loadUrl(displayRoute)
+            displayMenu(displayRoute)
+          400: (response) ->
+            view = viewContext.renderContent(
+              html: response.responseText
+            )
     return
 )


fixes #11. catch form submit.

fixes #11. catch form submit.

--- web-app/src/app/files/files-section-view.coffee
+++ web-app/src/app/files/files-section-view.coffee
@@ -12,6 +12,7 @@
       'class': 'modal-dialog files-section-view'

     events:
+      'submit form.file-info': 'onSave'
       'click button.save': 'onSave'

     initialize: (options) ->


add expectations to tag button test

add expectations to tag button test

--- test/components/overview/tag_button.coffee
+++ test/components/overview/tag_button.coffee
@@ -15,3 +15,6 @@
       />
     )
     renderedButton = ReactTestUtils.findRenderedDOMComponentWithClass(TestButton, 'plus')
+    expect(renderedButton.className).to.eq('button border plus')
+    expect(renderedButton.innerHTML).to.eq('+')
+    expect(renderedButton.tagName.toLowerCase()).to.eq('button')


Break modeline pattern across lines for readability


Separate conditionals from generic requests group

This allows separate styling of control flow keywords, which some themes
may use to differentiate conditionals from other similar-looking tokens.

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -320,15 +320,26 @@
 			name: "meta.function.request.$1.roff"
 			begin: "(?x) ^([.'])[ \t]*
 				(ab|ad|af|am|as|bd|bp|br|c2|cc|ce|cf|ch|cs|cu|da|de|di|ds
-				|dt|ec|el|em|eo|ev|ex|fc|fi|fl|fp|ft|hc|hw|hy|ie|if|ig|in
-				|it|lc|lg|lf|ll|ls|lt|mc|mk|na|ne|nf|nh|nm|nn|nr|ns|nx|os
-				|pc|pi|pl|pm|pn|po|ps|rd|rm|rn|rr|rs|rt|so|sp|ss|sv|sy|ta
-				|tc|ti|tl|tm|tr|uf|vs|wh)
+				|dt|ec|em|eo|ev|ex|fc|fi|fl|fp|ft|hc|hw|hy|ig|in|it|lc|lg
+				|lf|ll|ls|lt|mc|mk|na|ne|nf|nh|nm|nn|nr|ns|nx|os|pc|pi|pl
+				|pm|pn|po|ps|rd|rm|rn|rr|rs|rt|so|sp|ss|sv|sy|ta|tc|ti|tl
+				|tm|tr|uf|vs|wh)
 				(?=[ \t]|$)"
 			end: "(?<!\\\\)(?=\n)"
 			beginCaptures:
 				1: {name: "punctuation.definition.request.roff"}
 				2: {name: "entity.name.roff"}
+			patterns: [{include: "#params"}]
+
+		}, {
+
+			# Flow control/conditional requests
+			name: "meta.function.request.$1.roff"
+			begin: "^([.'])[ \t]*(ie|if|el)(?=[ \t]|$)"
+			end: "(?<!\\\\)(?=\n)"
+			beginCaptures:
+				1: {name: "punctuation.definition.request.roff"}
+				2: {name: "keyword.control.roff"}
 			patterns: [{include: "#params"}]

 		}, {


Allow comments after a .PS call

Allow comments after a .PS call

This was partially covered by d748e8c, but the pattern only accommodated
roff comments. Pic uses the more familiar #-based syntax instead.

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -2159,7 +2159,7 @@
 				4: {patterns: [include: "#params"]}
 		},{
 			# .PS/.PE: Pic
-			begin: "^([.'])[ \t]*(PS)\\b[ \t]*(\\\\[#\"].*)?$"
+			begin: "^([.'])[ \t]*(PS)\\b[ \t]*(?:(#.*)|(\\\\[#\"].*))?$"
 			end:   "^([.'])[ \t]*(PE)\\b"
 			contentName: "markup.other.graphics.preprocessor.pic.roff"
 			patterns: [include: "#pic"]
@@ -2167,7 +2167,8 @@
 				0: {name: "meta.function.begin.picture.section.macro.roff"}
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.function.name.roff"}
-				3: {patterns: [include: "#escapes"]}
+				3: {patterns: [include: "#pic"]}
+				4: {patterns: [include: "#escapes"]}
 			endCaptures:
 				0: {name: "meta.function.end.picture.section.macro.roff"}
 				1: {name: "punctuation.definition.macro.roff"}


Corrected Stub Dir

Corrected Stub Dir

--- test/streams/coffee.coffee
+++ test/streams/coffee.coffee
@@ -6,9 +6,7 @@

-
-stubsdir  = path.resolve path.join __dirname, '..', '..',
-  'build', 'test', 'stubs'
+stubsdir  = path.join process.cwd(), 'build', 'test', 'stubs'


Social: add a new function for creating social api id for account

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -262,6 +262,7 @@
           (signature String, Function)

     schema                  :
+      socialApiId           : Number
       skillTags             : [String]
       locationTags          : [String]
       systemInfo            :
@@ -428,6 +429,21 @@
     @notifyOriginWhen 'PrivateMessageSent', 'FollowHappened'
     @notifyGroupWhen 'FollowHappened'

+  createSocialApiId:(callback)->
+    return callback null, @socialApiId  if @socialApiId
+    {createAccount} = require './socialapi/requests'
+    createAccount @getId(), (err, account)=>
+      return callback err if err
+      @update $set: socialApiId: account.id, (err)->
+        # check for error
+        if err
+          console.error "Error while creating account on social api", err
+          return callback { message: "Couldnt create/register Account"}
+        # check account
+        return callback {message: "Account is not set, malformed response from social api"} unless account?.id
+        # return account id from social api
+        return callback null, account.id
+
   checkGroupMembership: secure (client, groupName, callback)->
     {delegate} = client.connection
     JGroup = require "./group"


worker/social: use current delegate while fetching current groups

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -301,8 +301,9 @@

   fetchRelativeGroups$: secure (client, callback) ->
-
-    @fetchRelativeGroups callback
+    delegate = client?.connection?.delegate
+    return callback new Error 'malformed request'
+    delegate.fetchRelativeGroups callback

   fetchRelativeGroups: (callback) ->


Remove load plugin options

Remove load plugin options

--- gulp/config.coffee
+++ gulp/config.coffee
@@ -26,10 +26,6 @@
     eslint :
       configFile : ".eslintrc.yml"

-  plugins : require("gulp-load-plugins")({
-    rename :
-      "gulp-ruby-sass" : "sass"
-      "gulp-ruby-haml" : "haml"
-  })
+  plugins : require("gulp-load-plugins")()

 module.exports = config


Remove config.src.babel

Remove config.src.babel

--- gulp/config.coffee
+++ gulp/config.coffee
@@ -1,6 +1,5 @@
 config =
   src :
-    babel  : "./src/js/**/*.js"
     scss   : "./src/scss/**/*.scss"
     fonts  : [
       "./node_modules/bootstrap-sass/assets/fonts/bootstrap/**"


Add mixpanel events

Add mixpanel events


fix race condition for creating a user directory

--- gist-cloner.coffee
+++ gist-cloner.coffee
@@ -55,7 +55,7 @@

   userfolder = base + user
   folder = userfolder + '/' + gist.id
-  fs.mkdir userfolder, ->
+  fs.mkdirSync userfolder

   #shell.cd(userfolder)
   # TODO don't use token in clone url (git init; git pull with token)


#17 Исправлена ошибка с сортировкой.

#17 Исправлена ошибка с сортировкой.

Сортировка выполнялась с приведением высоты к строке, соответственно
500 было больше чем 4000

--- app/assets/javascripts/app/collections/weather_data.js.coffee
+++ app/assets/javascripts/app/collections/weather_data.js.coffee
@@ -4,6 +4,10 @@
   initialize: (opts) ->
     @url = (opts.parent_url + '/weather_data') if _.has(opts, 'parent_url')

-  comparator: (item) ->
-    keys = ['actual_on', 'altitude']
-    (item.get key for key in keys)
+  comparator: (first, second) ->
+    switch
+      when first.get('actual_on') > second.get('actual_on') then return 1
+      when first.get('actual_on') < second.get('actual_on') then return -1
+      when Number(first.get('altitude')) > Number(second.get('altitude')) then return 1
+      when Number(first.get('altitude')) < Number(second.get('altitude')) then return -1
+      else return 0


css plugins

css plugins

--- app/assets/javascripts/plugins/views/candidacy_cell.js.coffee
+++ app/assets/javascripts/plugins/views/candidacy_cell.js.coffee
@@ -2,9 +2,7 @@

   initialize: ->
     # @selected = false
-
-  tagName: "li"
-
+
   events:
     "click": "candidacyClick"


bugfix if options.limit is -1

bugfix if options.limit is -1

--- modules/stores/lib/Context.coffee
+++ modules/stores/lib/Context.coffee
@@ -135,6 +135,8 @@
                 fn ?= fields
                 fields = null

+            options.limit = null if options.limit is -1
+
             @_find query, options, fields, fn

         ##


change status to state

change status to state

--- src/coffee/ezBreadcrumbs.coffee
+++ src/coffee/ezBreadcrumbs.coffee
@@ -390,9 +390,9 @@
             o.el.data o.stateKey, state

         _this.getState = ->
-            status = o.el.data o.stateKey
-
-            return if typeof status is "undefined" then 'decompressed' else status
+            state = o.el.data o.stateKey
+
+            return if typeof state is "undefined" then 'decompressed' else status

         _this.isCompressed = ->
             return if _this.getState() is 'compressed' then true else false


change toast message for create-project-page

--- app/components/create-project-page/create-project-page.coffee
+++ app/components/create-project-page/create-project-page.coffee
@@ -16,4 +16,4 @@
         $scope.bucket.save().then (data) ->
           projectId = data.buckets[0].id
           $location.path("/projects/#{projectId}")
-          Toast.show('You launched a project for funding')+          Toast.show('You drafted a new project')


feat(response): separate test options in original request

--- src/coffee/services/base.coffee
+++ src/coffee/services/base.coffee
@@ -547,7 +547,7 @@

     originalRequest = _.extend(
       originalRequest,
-      options
+      { options }
     )

     if error


debug is false by default to avoid source map unless specified

--- bin/op/index.coffee
+++ bin/op/index.coffee
@@ -7,9 +7,8 @@
 module.exports = (options) ->

   op = # start with some default info
-    options: basedir:'.', debug:true
+    options: basedir:'.', debug:false
     transforms: []
-    #require: []
     quiet: false

   info = # defined when a module name is specified, true, or false when `not`


Remove deprecation

Remove deprecation

--- lib/symbol-provider.coffee
+++ lib/symbol-provider.coffee
@@ -196,7 +196,7 @@

     # Do we want autocompletions from all open buffers?
     if atom.config.get('autocomplete-plus.includeCompletionsFromAllBuffers')
-      for editor in atom.workspace.getEditors()
+      for editor in atom.workspace.getTextEditors()
         # FIXME: downside is that some of these editors will not be tokenized :/
         symbolList = symbolList.concat @getSymbolsFromEditor(editor, minimumWordLength)


Allow editable elements to be linked to model values

--- src/scripts/helpers/backbone/views/editable.coffee
+++ src/scripts/helpers/backbone/views/editable.coffee
@@ -1,4 +1,6 @@
 define (require) ->
+  $ = require('jquery')
+  _ = require('underscore')
   BaseView = require('cs!helpers/backbone/views/base')

   observerConfig =
@@ -9,24 +11,43 @@
   return class EditableView extends BaseView
     initialize: () ->
       super()
+      @observers = {}

-      @listenTo(@model, 'change:edit', @toggleEdit)
+      @listenTo(@model, 'change:editable', @_toggleEditable)

-      @observer = new MutationObserver (mutations) =>
-        mutations.forEach (mutation) =>
-          page = @model.get('currentPage')
+    onBeforeEditable: () -> # noop
+    onEditable: () -> # noop

-          @model.set('changed', true)
-          page.set('changed', true)
+    _toggleEditable: () ->
+      @onBeforeEditable()

-    toggleEdit: () ->
-      edit = @model.get('edit')
-      $editable = @$el.find(@editable)
+      if @editable
+        edit = @model.get('editable')

-      $editable.attr('contenteditable', edit)
+        _.each @editable, (options, selector) =>
+          $editable = @$el.find(selector)

-      if edit
-        $editable.each (index) =>
-          @observer.observe($editable.get(index), observerConfig)
-      else
-        @observer.disconnect()
+          switch options.type
+            when 'contenteditable' then $editable.attr('contenteditable', edit)
+            when 'aloha' then console.log 'FIX: enable aloha'
+
+          if edit
+            options.onEditable?()
+            $editable.each (index) =>
+              if @observers[selector] then @observers[selector].disconnect()
+
+              @observers[selector] = new MutationObserver (mutations) =>
+                mutations.forEach (mutation) =>
+                  page = @model.get('currentPage')
+
+                  @model.set('changed', true)
+                  page.set('changed', true)
+
+                  @model.set(options.value, $($editable.get(index)).html())
+
+              @observers[selector].observe($editable.get(index), options.config or observerConfig)
+          else
+            options.onUneditable?()
+            @observers[selector].disconnect()
+
+      @onEditable()


jupyter: fix a test

jupyter: fix a test

--- src/smc-webapp/jupyter/test/export-to-ipynb.coffee
+++ src/smc-webapp/jupyter/test/export-to-ipynb.coffee
@@ -12,7 +12,7 @@

     it 'by directly calling export_to_ipynb', ->
         ipynb = export_to_ipynb(cell_list:actions.store.get('cell_list'), cells:actions.store.get('cells'), kernelspec:{})
-        expect(ipynb).toEqual({ cells: [ { cell_type: 'code', execution_count: 0, metadata: { collapsed: false }, outputs: [], source: [] } ], metadata: { kernelspec: {}, language_info: {} }, nbformat: 4, nbformat_minor: 0 })
+        expect(ipynb).toEqual({ cells: [ { cell_type: 'code', execution_count: 0, metadata: { collapsed: false }, outputs: [], source: [] } ], metadata: { kernelspec: {} }, nbformat: 4, nbformat_minor: 0 })

     it 'by calling function in the store', ->
         ipynb = export_to_ipynb(cell_list:actions.store.get('cell_list'), cells:actions.store.get('cells'))
@@ -23,7 +23,7 @@
         actions.set_cell_input(id, 'a=2\nb=3\na+b')
         actions.set_cell_output(id, {0:{data:{'text/plain':'5'}}})
         ipynb = export_to_ipynb(cell_list:actions.store.get('cell_list'), cells:actions.store.get('cells'), kernelspec:{})
-        expect(ipynb).toEqual({"cells":[{"cell_type":"code","source":["a=2\n","b=3\n","a+b"],"metadata":{"collapsed":false},"execution_count":0,"outputs":[{"data":{"text/plain":["5"]},"output_type":"execute_result","metadata":{},"execution_count":0}]}],"metadata":{"kernelspec":{}, language_info: {} },"nbformat":4,"nbformat_minor":0})
+        expect(ipynb).toEqual({"cells":[{"cell_type":"code","source":["a=2\n","b=3\n","a+b"],"metadata":{"collapsed":false},"execution_count":0,"outputs":[{"data":{"text/plain":["5"]},"output_type":"execute_result","metadata":{},"execution_count":0}]}],"metadata":{"kernelspec":{} },"nbformat":4,"nbformat_minor":0})

 describe 'tests exporting a file with many cells -- ', ->
     before(setup)


Cleanup install command's requires.

Cleanup install command's requires.

--- src/commands/install.cmd.coffee
+++ src/commands/install.cmd.coffee
@@ -2,14 +2,11 @@
 {resolve} = require 'path'
 Neat = require '../neat'

-utils = resolve Neat.neatRoot, "lib/utils"
-
 COFFEE = "#{Neat.neatRoot}/node_modules/.bin/coffee"
+{puts, error, info, green, red} = Neat.require "utils/logs"
+{run, aliases, describe} = Neat.require "utils/commands"
 {'package.json':generate} = Neat.require 'generators'
-
-{puts, error, info, green, red} = require "../utils/logs"
-{run, aliases, describe} = require resolve utils, "commands"
-{render} = require resolve utils, "templates"
+{render} = Neat.require "utils/templates"

 install = (pr) ->
   throw new Error "No program provided to install" unless pr?


Login: appController minor code styling

Login: appController minor code styling

--- client/Login/AppController.coffee
+++ client/Login/AppController.coffee
@@ -1,7 +1,6 @@
 class LoginAppsController extends AppController

-  KD.registerAppClass this,
-    name         : 'Login'
+  KD.registerAppClass this, name : 'Login'

   constructor:(options = {}, data)->
@@ -13,7 +12,9 @@

     super options, data

+
   prepareFinishRegistrationForm: (token) ->
+
     { JPasswordRecovery } = KD.remote.api
     JPasswordRecovery.fetchRegistrationDetails token, (err, details) =>
       view = @getView()
@@ -26,11 +27,15 @@
       view.setCustomDataToForm 'finishRegistration', recoveryToken: token
       view.animateToForm 'finishRegistration'

-  headBannerShowInvitation:(invite)->
+
+  headBannerShowInvitation: (invite) ->
+
     view = @getView()
     view.headBannerShowInvitation invite

+
   setStorageData: (key, value) ->
+
     @appStorage = KD.getSingleton('appStorageController').storage 'Login', '1.0'
     @appStorage.fetchStorage (storage) =>
       @appStorage.setValue key, value, (err) ->


Truncate and escape author

Truncate and escape author

--- framer/Components/ShareComponent.coffee
+++ framer/Components/ShareComponent.coffee
@@ -135,10 +135,27 @@

 		@_startListening()

+	_truncateCredential: (str, words) ->
+		maxLength = 36
+		maxLengthWithAvatar = 25
+
+		str = _.escape(str)
+
+		if words
+			separator = " "
+		else
+			separator = ""
+
+		# If an avatar is shown
+		if @shareInfo.twitter isnt undefined and str.length > maxLengthWithAvatar
+			str = _.truncate(str, {"length": maxLengthWithAvatar, "separator": separator})
+
+		else if str.length > maxLength
+			str = _.truncate(str, {"length": maxLength, "separator": separator})
+
+		return str
+
 	_checkData: ->
-		truncate = (str, n) ->
-			truncatedString = str
-			truncatedString.substr(0, n-1).trim() + "…"

 		# Remove leading @ from the Twitter handle
 		if _.startsWith(@shareInfo.twitter, "@")
@@ -146,13 +163,7 @@

 		# Truncate title if too long
 		if @shareInfo.title
-			maxLengthWithAvatar = 26
-			maxLength = 34
-
-			if @shareInfo.twitter and @shareInfo.title.length > maxLengthWithAvatar
-				@shareInfo.title = truncate(@shareInfo.title, maxLengthWithAvatar)
-			else if @shareInfo.title.length > maxLength
-				@shareInfo.title = truncate(@shareInfo.title, maxLength)
+			@shareInfo.title = @_truncateCredential(@shareInfo.title, true)

 	# Render main sheet
 	_renderSheet: ->
@@ -324,6 +335,8 @@

 			# If author name isn't available, fallback to Twitter handle
 			name = if @shareInfo.author then @shareInfo.author else "@#{@shareInfo.twitter}"
+			name = @_truncateCredential(name)
+
 			showAuthor("#{name}")

 		# If there's no twitter handle, show plain author name
@@ -392,7 +405,6 @@
 		)

 		showFullDescription = =>
-			@options.truncated = false
 			@description.height = @descriptionSize.height
 			@description.html = parseDescription(@shareInfo.description)

@@ -406,9 +418,6 @@

 		# Truncate if description is too long
 		if @shareInfo.description.length > @options.maxDescriptionLength
-
-			@options.truncated = true
-
 			truncated = @shareInfo.description.substring(@options.maxDescriptionLength,length).trim()
 			@options.shortDescription = truncated + "…"


Tidy some TODOs

Tidy some TODOs

--- src/test/runtime/ReactiveFunctionRunnerSpec.coffee
+++ src/test/runtime/ReactiveFunctionRunnerSpec.coffee
@@ -217,7 +217,7 @@
       parseUserFunctions 'c = obj.c'
       changes.should.eql [{obj: {a: 10, b: 20}}, {c: null}]

-    it 'selects null for member of null', ->        #TODO initial null
+    it 'selects null for member of null', ->
       parseUserFunctions 'obj = none'
       parseUserFunctions 'c = obj.c'
       changes.should.eql [{obj: null}, {c: null}]
@@ -529,7 +529,6 @@
       changesFor("sq").should.eql [null, [400], [400, 900], [400, 900, 1600]]

-      #TODO this should not have a zero at start
     it 'applies a transform function to an input stream using all function', ->
       parseUserFunctions 'sq = fromEach(all(theInput), in * in)'
       inputs 20, 30, 40
@@ -538,7 +537,7 @@
     it 'applies a transform function to the sequence values in a stream using plain value', ->
       parseUserFunctions 'sq = fromEach(theInput, in * in)'
       inputs [2, 3, 4], [5, 6], [7]
-      changesFor("sq").should.eql [null, [4, 9, 16], [25, 36], [49]]       # TODO should first be null or []?
+      changesFor("sq").should.eql [null, [4, 9, 16], [25, 36], [49]]

     it 'finds the squares of the sequence values in a stream using plain version', ->
       providedFunctions


Added doit conditional for null handling in render method

--- bokehjs/src/coffee/models/glyphs/text.coffee
+++ bokehjs/src/coffee/models/glyphs/text.coffee
@@ -13,13 +13,14 @@
       if (isNaN(sx[i]+sy[i]+x_offset[i]+y_offset[i]+angle[i]) or not text[i]?)
         continue

-      ctx.save()
-      ctx.translate(sx[i]+x_offset[i], sy[i]+y_offset[i])
-      ctx.rotate(angle[i])
+      if @visuals.text.doit
+        ctx.save()
+        ctx.translate(sx[i]+x_offset[i], sy[i]+y_offset[i])
+        ctx.rotate(angle[i])

-      @visuals.text.set_vectorize(ctx, i)
-      ctx.fillText(text[i], 0, 0)
-      ctx.restore()
+        @visuals.text.set_vectorize(ctx, i)
+        ctx.fillText(text[i], 0, 0)
+        ctx.restore()

   draw_legend: (ctx, x1, x2, y1, y2) ->
     ctx.save()


activity: define initial cssClass options of `ActivityLikeLink` class

--- client/Social/Activity/views/likelink.coffee
+++ client/Social/Activity/views/likelink.coffee
@@ -1,6 +1,8 @@
 class ActivityLikeLink extends CustomLinkView

   constructor: (options = {}, data) ->
+
+    options.cssClass = KD.utils.curry "action-link like-link", options.cssClass

     @state = data.interactions.like.isInteracted


Terminate all inline formatting before callable macros

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -1259,7 +1259,17 @@
 			# .Em: Emphasised text (Italic)
 			name: "meta.function.$1.callable.macro.mdoc.roff"
 			begin: "(?<=Em)\\G|(?<=\\s)(Em)(?=\\s)"
-			end:   "(?<!\\\\)$|(?=\\s+(?:Em|Li|Sy|No|Bf|Ar|Fl|Op|Ta))|(?=\\\\(?:\"|f[A-Za-z0-9]))"
+			end:   """(?x)
+				(?<!\\\\)$ |
+				(?=
+					\\s+
+					(?:Ac|Ad|An|Ao|Ap|Aq|Ar|At|Bc|Bo|Bq|Brc|Bro|Brq|Bsx|Bx|Cd|Cm|Dc|Do|Dq|Dv|Dx|Ec|Em
+					|En|Eo|Er|Es|Ev|Fa|Fc|Fl|Fn|Fr|Ft|Fx|Ic|Li|Lk|Ms|Mt|Nm|No|Ns|Nx|Oc|Oo|Op|Ot|Ox|Pa
+					|Pc|Pf|Po|Pq|Qc|Ql|Qo|Qq|Sc|So|Sq|Sx|Sy|Ta|Tn|Ux|Va|Vt|Vt|Xc|Xo|Xr)
+					\\s+   |
+					\\\\"  |
+					\\\\f[A-Za-z0-9]
+				)"""
 			beginCaptures:
 				1: name: "entity.function.name.roff"
 			patterns: [
@@ -1272,7 +1282,17 @@
 			# .Sy: Symbolic text (Bold)
 			name: "meta.function.$1.callable.macro.mdoc.roff"
 			begin: "(?<=Sy)\\G|(?<=\\s)(Sy)(?=\\s)"
-			end:   "(?<!\\\\)$|(?=\\s+(?:Em|Li|Sy|No|Bf|Ar|Fl|Op|Ta))|(?=\\\\(?:\"|f[A-Za-z0-9]))"
+			end:   """(?x)
+				(?<!\\\\)$ |
+				(?=
+					\\s+
+					(?:Ac|Ad|An|Ao|Ap|Aq|Ar|At|Bc|Bo|Bq|Brc|Bro|Brq|Bsx|Bx|Cd|Cm|Dc|Do|Dq|Dv|Dx|Ec|Em
+					|En|Eo|Er|Es|Ev|Fa|Fc|Fl|Fn|Fr|Ft|Fx|Ic|Li|Lk|Ms|Mt|Nm|No|Ns|Nx|Oc|Oo|Op|Ot|Ox|Pa
+					|Pc|Pf|Po|Pq|Qc|Ql|Qo|Qq|Sc|So|Sq|Sx|Sy|Ta|Tn|Ux|Va|Vt|Vt|Xc|Xo|Xr)
+					\\s+   |
+					\\\\"  |
+					\\\\f[A-Za-z0-9]
+				)"""
 			beginCaptures:
 				1: name: "entity.function.name.roff"
 			patterns: [
@@ -1285,7 +1305,17 @@
 			# .Li: Literal text (Monospaced)
 			name: "meta.function.$1.callable.macro.mdoc.roff"
 			begin: "(?<=Li)\\G|(?<=\\s)(Li)(?=\\s)"
-			end:   "(?<!\\\\)$|(?=\\s+(?:Em|Li|Sy|No|Bf|Ar|Fl|Op|Ta))|(?=\\\\(?:\"|f[A-Za-z0-9]))"
+			end:   """(?x)
+				(?<!\\\\)$ |
+				(?=
+					\\s+
+					(?:Ac|Ad|An|Ao|Ap|Aq|Ar|At|Bc|Bo|Bq|Brc|Bro|Brq|Bsx|Bx|Cd|Cm|Dc|Do|Dq|Dv|Dx|Ec|Em
+					|En|Eo|Er|Es|Ev|Fa|Fc|Fl|Fn|Fr|Ft|Fx|Ic|Li|Lk|Ms|Mt|Nm|No|Ns|Nx|Oc|Oo|Op|Ot|Ox|Pa
+					|Pc|Pf|Po|Pq|Qc|Ql|Qo|Qq|Sc|So|Sq|Sx|Sy|Ta|Tn|Ux|Va|Vt|Vt|Xc|Xo|Xr)
+					\\s+   |
+					\\\\"  |
+					\\\\f[A-Za-z0-9]
+				)"""
 			beginCaptures:
 				1: name: "entity.function.name.roff"
 			patterns: [
@@ -1298,7 +1328,17 @@
 			# .Ar: Command arguments, displayed in fixed-width italics
 			name: "meta.function.argument-names.callable.macro.mdoc.roff"
 			begin: "(?<=Ar)\\G|(?<=\\s)(Ar)(?=\\s)"
-			end:   "(?<!\\\\)$|(?=\\s+(?:Em|Li|Sy|No|Bf|Ar|Fl|Op|Ta))|(?=\\\\(?:\"|f[A-Za-z0-9]))"
+			end:   """(?x)
+				(?<!\\\\)$ |
+				(?=
+					\\s+
+					(?:Ac|Ad|An|Ao|Ap|Aq|Ar|At|Bc|Bo|Bq|Brc|Bro|Brq|Bsx|Bx|Cd|Cm|Dc|Do|Dq|Dv|Dx|Ec|Em
+					|En|Eo|Er|Es|Ev|Fa|Fc|Fl|Fn|Fr|Ft|Fx|Ic|Li|Lk|Ms|Mt|Nm|No|Ns|Nx|Oc|Oo|Op|Ot|Ox|Pa
+					|Pc|Pf|Po|Pq|Qc|Ql|Qo|Qq|Sc|So|Sq|Sx|Sy|Ta|Tn|Ux|Va|Vt|Vt|Xc|Xo|Xr)
+					\\s+   |
+					\\\\"  |
+					\\\\f[A-Za-z0-9]
+				)"""
 			beginCaptures:
 				1: name: "entity.function.name.roff"
 			patterns: [
@@ -1311,7 +1351,17 @@
 			# .Fl: Program flags, displayed in fixed-width bold type
 			name: "meta.function.flags.callable.macro.mdoc.roff"
 			begin: "(?<=Fl)\\G|(?<=\\s)(Fl)(?=\\s)"
-			end:   "(?<!\\\\)$|(?=\\s+(?:Em|Li|Sy|No|Bf|Ar|Fl|Op|Ta))|(?=\\\\(?:\"|f[A-Za-z0-9]))"
+			end:   """(?x)
+				(?<!\\\\)$ |
+				(?=
+					\\s+
+					(?:Ac|Ad|An|Ao|Ap|Aq|Ar|At|Bc|Bo|Bq|Brc|Bro|Brq|Bsx|Bx|Cd|Cm|Dc|Do|Dq|Dv|Dx|Ec|Em
+					|En|Eo|Er|Es|Ev|Fa|Fc|Fl|Fn|Fr|Ft|Fx|Ic|Li|Lk|Ms|Mt|Nm|No|Ns|Nx|Oc|Oo|Op|Ot|Ox|Pa
+					|Pc|Pf|Po|Pq|Qc|Ql|Qo|Qq|Sc|So|Sq|Sx|Sy|Ta|Tn|Ux|Va|Vt|Vt|Xc|Xo|Xr)
+					\\s+   |
+					\\\\"  |
+					\\\\f[A-Za-z0-9]
+				)"""
 			beginCaptures:
 				1: name: "entity.function.name.roff"
 			patterns: [


Added 'on' keyword to grammar

Added 'on' keyword to grammar

--- grammars/dart.cson
+++ grammars/dart.cson
@@ -172,7 +172,7 @@
         'name': 'keyword.cast.dart'
       }
       {
-        'match': '\\b(try|catch|finally|throw|rethrow)\\b'
+        'match': '\\b(try|on|catch|finally|throw|rethrow)\\b'
         'name': 'keyword.control.catch-exception.dart'
       }
       {


Force a page reload to get a new session object

--- client/code/view/subscribe.coffee
+++ client/code/view/subscribe.coffee
@@ -38,7 +38,10 @@
       data:
         recurly_token: token
       success: (result) =>
-        app.navigate '/thankyou', trigger: true
+        # Do a window refresh here, and not a backbone navigate
+        # because we want to get a fresh user session that has
+        # a fresh accountLevel field (obtained from the server).
+        window.location.href = '/thankyou'
       error: (err) =>
         alert err


Establishing pattern for generation of sigu gramatic.


A little dryness on your counter-top, underscore sort where is now a function

--- bootstrap-magic.coffee
+++ bootstrap-magic.coffee
@@ -66,6 +66,9 @@
       @startVal = @endVal
       $input.trigger 'change'

+objByCat = ->
+  myCat = currentCat.get()
+  _.where(bootstrap_magic_variables, { category: myCat })

 #Time for Templates

@@ -91,7 +94,7 @@
   #   return bootstrap_magic_variables

   "categories" : ->  _.map _.groupBy(bootstrap_magic_variables, 'category'), (obj) ->  obj[0]
-  "subCategories" : ->  _.map _.where(bootstrap_magic_variables, { category: currentCat.get() }), (obj) -> obj
+  "subCategories" : ->  _.map objByCat(), (obj) -> obj
   "previewTmpl" : -> Template["bootstrap_magic_preview_#{camelToSnake @keyName}"] || null
   "inputTmpl" : -> Template["bootstrap_magic_input_#{@type}"] || null
   "formattedCat" : -> formatCamel @category
@@ -107,10 +110,8 @@

   'click .menu-secondary-list' : ->
     currentCat.set(@category)
-    myCat = currentCat.get()
-    objByCat = _.where(bootstrap_magic_variables, { category: myCat })
-    if (_.map objByCat, (obj) -> obj).length is 1
-      currentSubCat.set(objByCat[0].keyName)
+    if (_.map objByCat(), (obj) -> obj).length is 1
+      currentSubCat.set(objByCat()[0].keyName)
       $('.sub-cat-message h4').remove()
       $('.sub-cat-item').show()
     else


Stop animation when destroyed

Stop animation when destroyed

--- client/index.coffee
+++ client/index.coffee
@@ -108,7 +108,9 @@
     triangles[i].draw()
     i++

-  renderer.render stage
+  return unless renderer
+
+  renderer?.render stage
   requestAnimationFrame draw

 generateTriangles = ->


add waypoint detector to billboard

add waypoint detector to billboard

--- client/index.coffee
+++ client/index.coffee
@@ -58,7 +58,9 @@

   $main_header = $('#main-header')

-  $('.card__heading, .character-selector__heading').waypoint
+  $('.card__heading,
+     .character-selector__heading,
+     .billboard__heading').waypoint
     handler: (direction) ->
       if direction is 'down'
         $main_header.addClass 'has-background'


dont want this after all

dont want this after all

--- html-app/app/scripts/load-session.coffee
+++ html-app/app/scripts/load-session.coffee
@@ -1,6 +1,6 @@
-'use strict'
-
-# This is only here for development purposes. In the live app,
-# load_session.js will be generated automatically
-angular.module('gratefulplaceApp',)
-  .value "loadedSession", { username: "John", id: 1 }+# 'use strict'
+#
+# # This is only here for development purposes. In the live app,
+# # load_session.js will be generated automatically
+# angular.module('gratefulplaceApp',)
+#   .value "loadedSession", { username: "John", id: 1 }


Rebind File-Icons setting-shortcut to use CTRL key

Keep pressing the wrong damn one.

--- .config/keymap.cson
+++ .config/keymap.cson
@@ -49,7 +49,7 @@
 # Navigation
 "atom-workspace atom-text-editor:not(.mini)":
 	"cmd-g":          "go-to-line:toggle"
-	"alt-f":          "file-icons:open-settings"
+	"ctrl-f":         "file-icons:open-settings"

 ".platform-darwin":
 	"cmd-0":          "tree-view:toggle"


Add shortcut to open a folder in developer mode

--- .config/keymap.cson
+++ .config/keymap.cson
@@ -46,6 +46,7 @@

 '.platform-darwin':
 	'cmd-0':        'tree-view:toggle'
+	'shift-cmd-O':  'application:open-dev'

 'atom-text-editor':
 	'cmd-l':        'grammar-selector:show'


new(entryForm): show message on failure in top of entry form additionally

--- src/components/EntryForm.coffee
+++ src/components/EntryForm.coffee
@@ -75,6 +75,10 @@
       h3 null, if isEdit then "Eintrag bearbeiten" else "Neuer Eintrag"
       @props.error and div className: "err",
         "Der Eintrag konnte nicht gespeichert werden: #{@props.error.message}"
+      (not @props.error) and @props.submitFailed and div className: "err",
+        "Bitte überprüfen Sie ihre Eingaben!"
+      license.error and license.touched and div className:"err",
+        license.error
       div className: "pure-form",

         fieldset null,


Open IDE Github repository for contribute link.

--- client/ide/views/statusbar.coffee
+++ client/ide/views/statusbar.coffee
@@ -43,7 +43,8 @@
         separator           : yes

     items['Show Shortcuts'] = callback: -> appManager.tell 'IDE', 'showShortcutsView'
-    items.Contribute        = callback: -> appManager.tell 'IDE', 'showContributeView'
+    items.Contribute        = callback: ->
+      KD.utils.createExternalLink 'https://github.com/koding/IDE'
     items.Quit              = callback: ->
       appManager.quitByName 'IDE'
       KD.getSingleton('router').handleRoute '/Activity'


Hide loader after all app icons loaded

Hide loader after all app icons loaded

--- client/app/Applications/StartTab.kdapplication/AppView.coffee
+++ client/app/Applications/StartTab.kdapplication/AppView.coffee
@@ -122,11 +122,11 @@
     @removeAppIcons()
     @showLoader()
     @getSingleton("kodingAppsController").fetchApps (err, apps)=>
-      @hideLoader()
       @decorateApps apps

   decorateApps:(apps)->
     @removeAppIcons()
+    @refreshButton.hide()
     @putAppIcons apps

     @getSingleton("kodingAppsController").appStorage.fetchValue 'shortcuts', (shortcuts)=>
@@ -138,6 +138,8 @@

       @appItemContainer.addSubView @appIcons['GET_MORE_APPS'] = new GetMoreAppsButton
         delegate : @
+      @hideLoader()
+      @refreshButton.show()

   removeAppIcons:->

@@ -147,7 +149,6 @@
   putAppIcons:(apps)->

     @refreshButton.show()
-    @hideLoader()
     for app, manifest of apps
       do (app, manifest)=>
         @appItemContainer.addSubView @appIcons[manifest.name] = new StartTabAppThumbView


Comment unneeded globals defaults like deploy path/urls

--- gulp/config.coffee
+++ gulp/config.coffee
@@ -106,12 +106,12 @@
         COMPRESS_ASSETS: true

         # If those 2 variables are defined, the app will be deployed to the remote server after compiling the release.
-        ANDROID_DEPLOY_APPBIN_PATH: "deploy@ionicstarter.com:/u/apps/ionicstarter/shared/public/uploads/ionicstarter-production.apk"
-        ANDROID_DEPLOY_APPBIN_URL: "http://ionicstarter.com/uploads/ionicstarter-production.apk"
+        # ANDROID_DEPLOY_APPBIN_PATH: "deploy@ionicstarter.com:/u/apps/ionicstarter/shared/public/uploads/ionicstarter-production.apk"
+        # ANDROID_DEPLOY_APPBIN_URL: "http://ionicstarter.com/uploads/ionicstarter-production.apk"

         # If those 2 variables are defined, the app will be deployed to the remote server after compiling the release.
-        IOS_DEPLOY_APPBIN_PATH: "deploy@ionicstarter.com:/u/apps/ionicstarter/shared/public/uploads/ionicstarter-production.ipa"
-        IOS_DEPLOY_APPBIN_URL: "http://ionicstarter.com/uploads/ionicstarter-production.ipa"
+        # IOS_DEPLOY_APPBIN_PATH: "deploy@ionicstarter.com:/u/apps/ionicstarter/shared/public/uploads/ionicstarter-production.ipa"
+        # IOS_DEPLOY_APPBIN_URL: "http://ionicstarter.com/uploads/ionicstarter-production.ipa"

         # Required for the release to be signed with correct certificate.
         IOS_PROVISIONING_PROFILE: "keys/ios/ionicstarterstaging.mobileprovision"


Workspace: Disabled sorting and closeAppWhenAllTabsClosed for tabbed editor.

--- client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
+++ client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
@@ -41,8 +41,10 @@
       addPlusHandle     : no

     @tabView = new ApplicationTabView
-      delegate           : @
-      tabHandleContainer : @tabHandleContainer
+      delegate                  : @
+      sortable                  : no
+      closeAppWhenAllTabsClosed : no
+      tabHandleContainer        : @tabHandleContainer

     @tabView.on "PaneAdded", (pane) =>
       {tabHandle} = pane


Hour stats. #150

Hour stats. #150

--- client/stats.coffee
+++ client/stats.coffee
@@ -53,6 +53,8 @@
       weekDay = weekStart()
     format =
       switch unit
+        when 'hour'
+          'HH:mm'
         when 'day', 'week'
           'ddd, MMM DD, YYYY' #'YYYY-MM-DD'
         when 'month'
@@ -70,7 +72,7 @@
         stats.labels.push lastDate.format format
         for dataset in stats.datasets
           dataset.data.push 0
-      Messages.find stats.query.call(t)
+      msgs = Messages.find stats.query.call(t)
       ,
         fields:
           created: true
@@ -78,7 +80,9 @@
           title: true
           authors: true
         sort: created: 1
-      .forEach (msg) =>
+      if unit == 'hour'
+        msgs = _.sortBy msgs.fetch(), (msg) -> moment(msg.created).format 'HH:mm'
+      msgs.forEach (msg) =>
         switch unit
           when 'week'
             day = moment(msg.created).startOf 'day'
@@ -86,11 +90,15 @@
               day.day -7 + weekDay  ## previous week
             else
               day.day weekDay  ## same week
+          when 'hour'
+            day = moment(msg.created).startOf unit
+            .year 2000
+            .dayOfYear 1
           else
             day = moment(msg.created).startOf unit
         if lastDate?
           if lastDate.valueOf() > day.valueOf()
-            console.warn "Backwards time travel from #{lastDate} to #{day}"
+            console.warn "Backwards time travel from #{lastDate.format()} to #{day.format()}"
             lastDate = day
             makeDay()
           else


Use clearer default for url

Use clearer default for url

--- core/app/backbone/modules/discussion_modal_on_frontend.coffee
+++ core/app/backbone/modules/discussion_modal_on_frontend.coffee
@@ -9,9 +9,10 @@
       Backbone.history.navigate background_page_url, false
       FactlinkApp.discussionModalRegion.close()

-  DiscussionModalOnFrontend.openDiscussion = (fact, url) ->
+  DiscussionModalOnFrontend.openDiscussion = (fact, url=background_page_url) ->
     Backbone.history.navigate fact.get('url'), false
-    background_page_url = Backbone.history.getFragment(url) if url?
+    background_page_url = Backbone.history.getFragment(url)
+
     newClientModal = new DiscussionModalContainer
     FactlinkApp.discussionModalRegion.show newClientModal
     newClientModal.mainRegion.show new NDPDiscussionView model: fact


Get rid of premature optimization

Get rid of premature optimization

--- core/app/backbone/views/react_install_extension_button.coffee
+++ core/app/backbone/views/react_install_extension_button.coffee
@@ -27,11 +27,10 @@
   displayName: 'ReactInstallExtensionOrBookmarklet'
   componentWillMount: ->
     check = =>
-      if !@state || !@state.extension_installed
-        @setState(
-          extension_installed:
-            document.documentElement.getAttribute('data-factlink-extension-loaded')?
-        )
+      @setState(
+        extension_installed:
+          document.documentElement.getAttribute('data-factlink-extension-loaded')?
+      )
     document.addEventListener('readystatechange', check)
     check()


Update canonicalization to match new XWS rules.

--- coffeescripts/cards-common.coffee
+++ coffeescripts/cards-common.coffee
@@ -3535,7 +3535,7 @@
         }
         {
             name: "Poe Dameron (PS9)"
-            canonical_name: "Poe Dameron".canonicalize()
+            canonical_name: "poedameron-swx57"
             id: 196
             unique: true
             faction: "Resistance"
@@ -3593,7 +3593,7 @@
         }
         {
             name: "Han Solo (TFA)"
-            canonical_name: "Han Solo".canonicalize()
+            canonical_name: "hansolo-swx57"
             id: 200
             unique: true
             faction: "Resistance"
@@ -3634,7 +3634,7 @@
         }
         {
             name: "Chewbacca (TFA)"
-            canonical_name: "Chewbacca".canonicalize()
+            canonical_name: "chewbacca-swx57"
             id: 202
             unique: true
             faction: "Resistance"
@@ -3702,7 +3702,7 @@
         {
             name: "R2-D2"
             aka: [ "R2-D2 (Crew)" ]
-            canonical_name: 'r2d2'
+            canonical_name: 'r2d2-swx22'
             id: 3
             unique: true
             slot: "Astromech"
@@ -5682,7 +5682,7 @@
         }
         {
             name: "Millennium Falcon (TFA)"
-            canonical_name: "Millennium Falcon".canonicalize()
+            canonical_name: "millenniumfalcon-swx57"
             id: 40
             unique: true
             points: 1


Add more information to the updateStatus hook

--- server/code/model/dataset.coffee
+++ server/code/model/dataset.coffee
@@ -64,6 +64,18 @@
     @save (err) =>
       boxes = _.map @views, (v) -> v.box
       message = JSON.stringify
+        origin:
+          box: @box
+          boxServer: @boxServer
+          user: @user
+          tool: @tool
+          displayName: @displayName
+          status: @status
+          views: @views
+          boxJSON: @boxJSON
+          createdDate: @createdDate
+          creatorShortName: @creatorShortName
+          creatorDisplayName: @creatorDisplayName
         boxes: boxes
         type: @status.type
         message: @status.message


Add error logging to process forking

Add error logging to process forking

--- server/controllers/deploy.coffee
+++ server/controllers/deploy.coffee
@@ -13,7 +13,15 @@
     return res.send 500, "Only commits from deploy branch are accepted"

   console.log "Forking #{process.cwd()}/bin/deploy.coffee"
-  cp.fork("#{process.cwd()}/bin/deploy.coffee")
+
+  deployProcess = cp.fork("#{process.cwd()}/bin/deploy.coffee")
+  theProcess.stdout.on('data', (data) ->
+    console.log(data.toString())
+  )
+  theProcess.stderr.on('data', (data) ->
+    console.log("Error: #{data.toString()}")
+  )
+
   console.log "Forked!"

   res.send 200


Add memory limit for running containers

Add memory limit for running containers

--- server/libs/container/run.coffee
+++ server/libs/container/run.coffee
@@ -10,6 +10,7 @@
 module.exports = (language, entrypoint, volume, cb) ->
   containerOptions =
     Image: "runner"
+    Memory: 50e6
     DisableNetwork: true
     Cmd: [
       language


SVG export uses correct xmlns

SVG export uses correct xmlns

--- src/core/LiterallyCanvas.coffee
+++ src/core/LiterallyCanvas.coffee
@@ -407,7 +407,9 @@

     {x, y, width, height} = opts.rect
     "
-      <svg width='#{width}' height='#{height}'
+      <svg
+          xmlns='http://www.w3.org/2000/svg'
+          width='#{width}' height='#{height}'
           viewBox='0 0 #{width} #{height}'>
         <rect width='#{width}' height='#{height}' x='0' y='0'
           fill='#{@colors.background}' />


a little documentation

a little documentation

--- demo.coffee
+++ demo.coffee
@@ -1,3 +1,4 @@
+# code to wire the evolution code to the demo page
 initializationParameters =
   pause: [ 10, 0, 1000, 'minimum pause between ticks' ]
   maxDistance: [ 60, 30, 100, 'maximum distance an organism can see' ]


Safety for when there is no runtime

Safety for when there is no runtime

--- components/MapStateToProps.coffee
+++ components/MapStateToProps.coffee
@@ -47,6 +47,7 @@
           props.runtime = populateRuntime state
           return
         when 'runtimePackets'
+          return unless state.runtime?.id
           return unless updated.runtimePackets[state.runtime.id]
           packets = updated.runtimePackets[state.runtime.id].toarray()
           packets.reverse()


Removing one unused routine, and adding two more (that will be shared amongst SVGLayer and SVGGroup)


feat: dragenter event handler

feat: dragenter event handler

--- cgFileUpload.coffee
+++ cgFileUpload.coffee
@@ -35,6 +35,7 @@
         onbeforeupload: '&'
         onerror: '&'
         uploadUrl: '@'
+        ondragenter: '&'
     link: (scope, elem, attrs) ->

         elem = elem[0]
@@ -89,6 +90,7 @@
             dropStyle = 'dropping'

             elem.addEventListener 'dragenter', (e) ->
+                scope.ondragenter?()
                 e.preventDefault()
                 return true


Close #31

Close #31

--- coffee/index.coffee
+++ coffee/index.coffee
@@ -81,8 +81,8 @@
       program = spawn cmnd, args.concat src, '--output=' + tmp_dir.path

       # Verbose Output
-      if options.verbose
-        program.stdout.on 'data', (data) ->
+      program.stdout.on 'data', (data) ->
+        if options.verbose
           gutil.log data.toString()

       # return data


Add tests for null and not-null values in rows.

--- test/unit/token/row-token-parser-test.coffee
+++ test/unit/token/row-token-parser-test.coffee
@@ -23,6 +23,7 @@

   test.strictEqual(token.length, buffer.length - 1)
   test.strictEqual(token.columns.length, 1)
+  test.ok(!token.columns[0].isNull)
   test.strictEqual(token.columns[0].value, value)
   test.strictEqual(token.columns[0].metadata, colMetaData[0])

@@ -50,6 +51,7 @@

   test.strictEqual(token.length, buffer.length - 1)
   test.strictEqual(token.columns.length, 1)
+  test.ok(!token.columns[0].isNull)
   test.strictEqual(token.columns[0].value, value)
   test.strictEqual(token.columns[0].metadata, colMetaData[0])

@@ -77,7 +79,34 @@

   test.strictEqual(token.length, buffer.length - 1)
   test.strictEqual(token.columns.length, 1)
+  test.ok(!token.columns[0].isNull)
   test.strictEqual(token.columns[0].value, value)
   test.strictEqual(token.columns[0].metadata, colMetaData[0])

   test.done()
+
+module.exports.intN = (test) ->
+  colMetaData = [
+    type:
+      name: 'IntN'
+      dataLengthLength: 1
+  ]
+
+  value = 0
+
+  buffer = new Buffer(1 + 1)
+  pos = 0;
+
+  buffer.writeUInt8(TYPE.ROW, pos); pos++
+  buffer.writeUInt8(value, pos); pos++
+  #console.log(buffer)
+
+  token = parser(buffer, 1, colMetaData)
+  #console.log(token)
+
+  test.strictEqual(token.length, buffer.length - 1)
+  test.strictEqual(token.columns.length, 1)
+  test.ok(!token.columns[0].value)
+  test.ok(token.columns[0].isNull)
+
+  test.done()


Fixing typo

Fixing typo

--- example/source/second/main.coffee
+++ example/source/second/main.coffee
@@ -3,7 +3,7 @@
   @scaffold "source/second/main.yml"

   buttonClick: ->
-    modal = new Atoms.Organism.Confirm
+    modal = new Atoms.Molecule.Confirm
       icon    : "search"
       title   : "Find your friends"
       text    : "lorem ipsum"


Un-break unit tests

Un-break unit tests

--- services/web/test/unit/coffee/Authentication/AuthenticationControllerTests.coffee
+++ services/web/test/unit/coffee/Authentication/AuthenticationControllerTests.coffee
@@ -98,6 +98,7 @@
 			@req.session.destroy = sinon.stub().callsArgWith(0, null)
 			@req.session.save = sinon.stub().callsArgWith(0, null)
 			@req.sessionStore = {generate: sinon.stub()}
+			@AuthenticationController.finishLogin = sinon.stub()
 			@passport.authenticate.callsArgWith(1, null, @user, @info)
 			@err = new Error('woops')

@@ -123,27 +124,10 @@
 			afterEach ->
 				delete @req.session.postLoginRedirect

-			it 'should call req.login', () ->
+			it 'should call finishLogin', () ->
 				@AuthenticationController.passportLogin @req, @res, @next
-				@req.login.callCount.should.equal 1
-				@req.login.calledWith(@user).should.equal true
-
-			it 'should send a json response with redirect', () ->
-				@AuthenticationController.passportLogin @req, @res, @next
-				@res.json.callCount.should.equal 1
-				@res.json.calledWith({redir: 'some_redirect'}).should.equal true
-
-			describe 'when session.save produces an error', () ->
-				beforeEach ->
-					@req.session.save = sinon.stub().callsArgWith(0, new Error('woops'))
-
-				it 'should return next with an error', () ->
-					@AuthenticationController.passportLogin @req, @res, @next
-					@next.calledWith(@err).should.equal true
-
-				it 'should not return json', () ->
-					@AuthenticationController.passportLogin @req, @res, @next
-					@res.json.callCount.should.equal 0
+				@AuthenticationController.finishLogin.callCount.should.equal 1
+				@AuthenticationController.finishLogin.calledWith(@user).should.equal true

 		describe 'when authenticate does not produce a user', ->

@@ -151,9 +135,9 @@
 				@info = {text: 'a', type: 'b'}
 				@passport.authenticate.callsArgWith(1, null, false, @info)

-			it 'should not call req.login', () ->
+			it 'should not call finishLogin', () ->
 				@AuthenticationController.passportLogin @req, @res, @next
-				@req.login.callCount.should.equal 0
+				@AuthenticationController.finishLogin.callCount.should.equal 0

 			it 'should not send a json response with redirect', () ->
 				@AuthenticationController.passportLogin @req, @res, @next
@@ -255,7 +239,6 @@
 				@LoginRateLimiter.processLoginRequest.callsArgWith(1, null, true)
 				@AuthenticationManager.authenticate = sinon.stub().callsArgWith(2, null, @user)
 				@req.sessionID = Math.random()
-				@AnalyticsManager.identifyUser = sinon.stub()
 				@AuthenticationController.doPassportLogin(@req, @req.body.email, @req.body.password, @cb)

 			it "should attempt to authorise the user", ->
@@ -263,35 +246,37 @@
 					.calledWith(email: @email.toLowerCase(), @password)
 					.should.equal true

-			it "should call identifyUser", ->
-				@AnalyticsManager.identifyUser.calledWith(@user._id, @req.sessionID).should.equal true
-
-			it "should setup the user data in the background", ->
-				@UserHandler.setupLoginData.calledWith(@user).should.equal true
-
 			it "should establish the user's session", ->
 				@cb.calledWith(null, @user).should.equal true

-			it "should set res.session.justLoggedIn", ->
-				@req.session.justLoggedIn.should.equal true
-
-			it "should record the successful login", ->
-				@AuthenticationController._recordSuccessfulLogin
-					.calledWith(@user._id)
-					.should.equal true
-
-			it "should tell the rate limiter that there was a success for that email", ->
-				@LoginRateLimiter.recordSuccessfulLogin.calledWith(@email.toLowerCase()).should.equal true
-
-			it "should log the successful login", ->
-				@logger.log
-					.calledWith(email: @email.toLowerCase(), user_id: @user._id.toString(), "successful log in")
-					.should.equal true
-
-			it "should track the login event", ->
-				@AnalyticsManager.recordEvent
-					.calledWith(@user._id, "user-logged-in")
-					.should.equal true
+			# TODO: move these to a test for the async handlers, or for finishLogin
+
+			# it "should call identifyUser", ->
+			# 	@AnalyticsManager.identifyUser.calledWith(@user._id, @req.sessionID).should.equal true
+
+			# it "should setup the user data in the background", ->
+			# 	@UserHandler.setupLoginData.calledWith(@user).should.equal true
+
+			# it "should set res.session.justLoggedIn", ->
+			# 	@req.session.justLoggedIn.should.equal true
+
+			# it "should record the successful login", ->
+			# 	@AuthenticationController._recordSuccessfulLogin
+			# 		.calledWith(@user._id)
+			# 		.should.equal true
+
+			# it "should tell the rate limiter that there was a success for that email", ->
+			# 	@LoginRateLimiter.recordSuccessfulLogin.calledWith(@email.toLowerCase()).should.equal true
+
+			# it "should log the successful login", ->
+			# 	@logger.log
+			# 		.calledWith(email: @email.toLowerCase(), user_id: @user._id.toString(), "successful log in")
+			# 		.should.equal true
+
+			# it "should track the login event", ->
+			# 	@AnalyticsManager.recordEvent
+			# 		.calledWith(@user._id, "user-logged-in")
+			# 		.should.equal true

 		describe 'when the user is not authenticated', ->
 			beforeEach ->


suggest context functions for no token

suggest context functions for no token

--- app/editor.coffee
+++ app/editor.coffee
@@ -130,14 +130,7 @@
 suggest = (cm, showHints, options) ->
   cur = cm.getCursor()
   token = cm.getTokenAt(cur)
-  if token.type is null
-    # TODO why only vars here?
-    list = (k for k of cm.ctx.imported_vars)
-    showHints
-      list: list
-      from: CodeMirror.Pos cur.line, token.end
-      to: CodeMirror.Pos cur.line, token.end
-  else if token.type is 'string'
+  if token.type is 'string'
     open = token.string[0]
     string = token.string[1..]
     close = string[string.length - 1]


Fix a regression where link hint chars were passed through to the underlying page.

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -178,6 +178,7 @@
           @hideMarker(@hintMarkers[i])
         for i of linksMatched
           @showMarker(linksMatched[i], @markerMatcher.hintKeystrokeQueue.length)
+    false # We've handled this key, so prevent propagation.

   #
   # When only one link hint remains, this function activates it in the appropriate way.


Let HighCharts use the local time

Let HighCharts use the local time

--- app/js/app.coffee
+++ app/js/app.coffee
@@ -120,3 +120,7 @@

     $idleProvider.idleDuration(1776)
     $idleProvider.warningDuration(60)
+
+    Highcharts.setOptions
+        global:
+            useUTC: false


Revert "start and end times of Taaniyot are now based on fixed minutes, not proportional ones"

This reverts commit cce75c160ab707366e55dbea881fbf9456df1483.

--- source/javascripts/mincha.coffee
+++ source/javascripts/mincha.coffee
@@ -54,8 +54,8 @@
   plag_is_before_615: -> @plag().isBefore(@today().hour(18).minute(15))
   set_hakochabim: -> time_format(moment(@zmanim.set_hakochabim))
   rabbenu_tam: -> time_format(moment(@sunset).add(73, 'minute'))
-  set_hakochabim_geonim: -> # 13.5 fixed minutes after sunset, rounded to end of minute
-    moment(@sunset).add('14', 'minutes')
+  set_hakochabim_geonim: -> # 13.5 dakot zemaniyot after sunset, rounded to end of minute
+    moment(@sunset).add(parseInt((@zmanim.sunset - @zmanim.sunrise) * 3 / 160000 + 60), 'seconds')
   chag: -> @_chag ?= (
     name_of_chag = switch
       when (@hebrew_date.isErebPesach() && !@hebrew_date.isShabbat()) || @hebrew_date.is1stDayOfPesach() || @hebrew_date.is2ndDayOfPesach() then 'pesach-first-days'
@@ -121,7 +121,7 @@
       $(".#{@chag()}.habdala").removeClass("hidden") if 0 == @hebrew_date.gregorianDate.getDay()
     else
       fast_begins_row.find(".dow, .date").attr("rowspan", if @hebrew_date.isTaanitEster() then (if 13 == @hebrew_date.dayOfMonth then 4 else 3) else 2)
-      fast_begins_row.find(".time").html(moment(@zmanim.sunrise).subtract(73, 'minutes').format('h:mm A'))
+      fast_begins_row.find(".time").html(moment(@zmanim.magen_abraham_dawn).format('h:mm A'))
     fast_ends = @set_hakochabim_geonim()
     $(".#{@chag()}.fast-ends").removeClass('hidden').find(".time").html(fast_ends.format('h:mm A'))
     if @hebrew_date.isTaanitEster()


update httpbind to use static

update httpbind to use static

--- core/core_modules/httpbind.coffee
+++ core/core_modules/httpbind.coffee
@@ -1,6 +1,7 @@
 Fs   = require 'fs'
 Fse  = require 'fs.extra'
 Path = require 'path'
+express = require 'express'

 findTargetPath = (folder,filename,index,callback)->
     targetPath = ""
@@ -16,6 +17,20 @@

 class HttpBind
     constructor : (@mew)->
+        @staticPathDefinitionPool = {}
+
+    bindStatic : (location,context)->
+        if location and context
+            if Fs.existsSync(location)
+                if @staticPathDefinitionPool[context]
+                    throw new Error("target static context already bind to : #{@staticPathDefinitionPool[context]}")
+                else
+                    @mew.brain.httpManager.app.use context,express.static(location)
+                    @staticPathDefinitionPool[context]=location
+            else
+                throw new Error("location not exists")
+        else
+            throw new Error("location or context not defined")

     bindUpload : (path,folder,callback)->
         @bindHttp path,"post",(req,res,next)=>


natural sorting algorithm is extracted from PivotData class; and is also used in sorting unused attributes

--- pivot.coffee
+++ pivot.coffee
@@ -127,7 +127,7 @@
         #thanks http://stackoverflow.com/a/12213072/112871
         (record) ->
             date = new Date(Date.parse(record[col]))
-            formatString.replace /%(.)/g, (m, p) ->
+            formatString.replace /%(.)/g, (m, p) ->
                 switch p
                     when "y" then date.getFullYear()
                     when "m" then zeroPad(date.getMonth()+1)
@@ -140,7 +140,32 @@
                     when "S" then zeroPad(date.getSeconds())
                     else "%" + p

-$.pivotUtilities = {aggregatorTemplates, aggregators, renderers, derivers}
+naturalSort = (as, bs) => #from http://stackoverflow.com/a/4373421/112871
+    rx = /(\d+)|(\D+)/g
+    rd = /\d/
+    rz = /^0/
+    if typeof as is "number" or typeof bs is "number"
+        return 1  if isNaN(as)
+        return -1  if isNaN(bs)
+        return as - bs
+    a = String(as).toLowerCase()
+    b = String(bs).toLowerCase()
+    return 0  if a is b
+    return (if a > b then 1 else -1)  unless rd.test(a) and rd.test(b)
+    a = a.match(rx)
+    b = b.match(rx)
+    while a.length and b.length
+        a1 = a.shift()
+        b1 = b.shift()
+        if a1 isnt b1
+            if rd.test(a1) and rd.test(b1)
+                return a1.replace(rz, ".0") - b1.replace(rz, ".0")
+            else
+                return (if a1 > b1 then 1 else -1)
+    a.length - b.length
+
+
+$.pivotUtilities = {aggregatorTemplates, aggregators, renderers, derivers, naturalSort}

 ###
 functions for accessing input
@@ -192,30 +217,8 @@
         @colTotals = {}
         @allTotal = @aggregator(this, [], [])
         @sorted = false
-
-    natSort: (as, bs) => #from http://stackoverflow.com/a/4373421/112871
-      rx = /(\d+)|(\D+)/g
-      rd = /\d/
-      rz = /^0/
-      if typeof as is "number" or typeof bs is "number"
-        return 1  if isNaN(as)
-        return -1  if isNaN(bs)
-        return as - bs
-      a = String(as).toLowerCase()
-      b = String(bs).toLowerCase()
-      return 0  if a is b
-      return (if a > b then 1 else -1)  unless rd.test(a) and rd.test(b)
-      a = a.match(rx)
-      b = b.match(rx)
-      while a.length and b.length
-        a1 = a.shift()
-        b1 = b.shift()
-        if a1 isnt b1
-          if rd.test(a1) and rd.test(b1)
-            return a1.replace(rz, ".0") - b1.replace(rz, ".0")
-          else
-            return (if a1 > b1 then 1 else -1)
-      a.length - b.length
+
+    natSort: (as, bs) => naturalSort(as, bs)

     arrSort: (a,b) => @natSort a.join(), b.join()

@@ -249,7 +252,7 @@
                 @rowKeys.push rowKey
                 @flatRowKeys.push flatRowKey
             if not @rowTotals[flatRowKey]
-                @rowTotals[flatRowKey] = @aggregator(this, rowKey, [])
+                @rowTotals[flatRowKey] = @aggregator(this, rowKey, [])
             @rowTotals[flatRowKey].push record

         if colKey.length != 0
@@ -264,7 +267,7 @@
             if flatRowKey not of @tree
                 @tree[flatRowKey] = {}
             if flatColKey not of @tree[flatRowKey]
-                @tree[flatRowKey][flatColKey] = @aggregator(this, rowKey, colKey)
+                @tree[flatRowKey][flatColKey] = @aggregator(this, rowKey, colKey)
             @tree[flatRowKey][flatColKey].push record

     getAggregator: (rowKey, colKey) =>
@@ -274,7 +277,7 @@
             agg = @allTotal
         else if rowKey.length == 0
             agg = @colTotals[flatColKey]
-        else if colKey.length == 0
+        else if colKey.length == 0
             agg = @rowTotals[flatRowKey]
         else
             agg = @tree[flatRowKey][flatColKey]
@@ -433,7 +436,7 @@
     catch e
         console.error(e.stack)
         result = opts.localeStrings.computeError
-
+
     @html result
     return this

@@ -466,7 +469,7 @@
     if not existingOpts? or overwrite
         opts = $.extend defaults, inputOpts
     else
-        opts = existingOpts
+        opts = existingOpts

     try
         #cache the input in some useful form
@@ -645,11 +648,12 @@

             # if requested make sure unused columns are in alphabetical order
             if opts.autoSortUnusedAttrs
+                natSort = $.pivotUtilities.naturalSort
                 unusedAttrsContainer = $("td#unused.pvtAxisContainer")
-                $(unusedAttrsContainer).children("li").sort((a, b) ->
-                    (if $(a).text().toLowerCase() > $(b).text().toLowerCase() then 1 else -1)
-                ).appendTo unusedAttrsContainer
-
+                $(unusedAttrsContainer).children("li")
+                    .sort((a, b) => natSort($(a).text(), $(b).text()))
+                    .appendTo unusedAttrsContainer
+
         #the very first refresh will actually display the table
         refresh()


Fix grammar in spec description

Fix grammar in spec description

--- spec/package-manager-spec.coffee
+++ spec/package-manager-spec.coffee
@@ -215,7 +215,7 @@
             expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})

       describe "when the package throws an error while loading", ->
-        it "logs warning instead of throwing an exception", ->
+        it "logs a warning instead of throwing an exception", ->
           atom.config.set("core.disabledPackages", [])
           spyOn(console, "warn")
           expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -259,8 +259,8 @@
         #console.log totaltickets
         totalLabel.append('text')
             .text(totalTickets)
-            .attr('font-size','totallabelfontsize')
             .attr('text-anchor', 'middle')
+            .attr('base-alignment', 'mathematical')
             .attr('filter','url(#dropshadow)')

         oldPieData = piedata


Agent pie: edit pointer transition

Agent pie: edit pointer transition


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -2,48 +2,8 @@

     @accessor 'data'

-    @_current = ''
-
-    #$(@node).fadeOut().fadeIn()
-    @container = $(@node).parent()
-
-    #
-    # CONFIG ZONE
-    #
-
-    # Width of the SVG area
-    @width = (Dashing.widget_base_dimensions[0] * @container.data('sizex')) - Dashing.widget_margins[0] * 4 * (@container.data('sizex') - 1)
-
-    # Height of the SVG area allowing for header and footer text
-    @height = (Dashing.widget_base_dimensions[1] * @container.data('sizey')) - 120
-
-    # Calculated min dimension of the SVG area
-    @radius = Math.min(@width, @height) / 2
-
-    # Outer radius of the pie
-    @radiuso = Math.min(@width, @height) / 3
-
-    # Inner radius of the pie (zero = pie, non-zero = donut)
-    @radiusi = @radiuso * 2 / 3
-
-    # Color scale for pie slices
-    @color = d3.scale.category20()
-
-    # X-offset for drop shadow filter
-    @dropshadowx = 2
-
-    # Y-offset for drop shadow filter
-    @dropshadowy = 2
-
-    # [STRING] Blur value for drop shadow filter
-    @dropshadowblur = '1.2'
-
-    #
-    # END CONFIG ZONE
-    #
-
-    @pie = d3.layout.pie().value((d) -> d.value).sort(null)
-    @arc = d3.svg.arc().innerRadius(@radiusi).outerRadius(@radiuso)
+    @pie = d3.layout.pie()
+    @arc = d3.svg.arc()

     #constructor: ->
     ready: ->


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -356,7 +356,7 @@
                 return "M" + (d.r-2) + "," + d.b + "L" + (d.l+2) + "," + d.b + " " + d.cx + "," + d.cy

         )
-  pieTween: (d, i) {
+  pieTween: (d, i) ->

         i = d3.interpolate({
             startAngle: 0,


fixed bug in article model when encoding empty relation collections

--- app/assets/javascripts/ems/models/article.coffee
+++ app/assets/javascripts/ems/models/article.coffee
@@ -22,17 +22,19 @@

   @encode 'channel_ids',
     encode: (channelIds, name, object, article) ->
-      channels =  article.get('channels').toArray()
       channelIds ||= []
-      channelIds.push channel.id for channel in channels
+      channels =  article.get('channels')
+      if channels
+        channelIds.push channel.id for channel in channels.toArray()

       return channelIds

   @encode 'tag_ids',
     encode: (tagIds, name, object, article) ->
-      tags =  article.get('tags').toArray()
       tagIds ||= []
-      tagIds.push tag.id for tag in tags
+      tags =  article.get('tags')
+      if tags
+        tagIds.push tag.id for tag in tags.toArray()

       return tagIds


Implement ::serialize in example

Implement ::serialize in example

--- src/deserializer-manager.coffee
+++ src/deserializer-manager.coffee
@@ -11,6 +11,11 @@
 #
 #   @deserialize: (state) ->
 #     new MyPackageView(state)
+#
+#   constructor: (@state) ->
+#
+#   serialize: ->
+#     @state
 # ```
 module.exports =
 class DeserializerManager


Fixed the way that ranges are passed in

Fixed the way that ranges are passed in

--- app/assets/javascripts/models/accounts.js.coffee
+++ app/assets/javascripts/models/accounts.js.coffee
@@ -3,36 +3,41 @@
     @data = {}

     @refreshPage: (fromDate) ->
-      bank.Account.calculateRange fromDate, true, ->
-          bank.Ajax.get(Routes.account_transactions_path(accountId), {
-              dataType: 'html'
-              success: (data) ->
-                  $('.transactions-wrapper').html(data)
-                  $('.transactions-wrapper').removeClass('waiting')
-                  bank.Account.calculateRange fromDate, false, ->
-                      bank.Account.refreshTotals()
-              data:
-                  start_month: bank.Account.time.month
-                  start_year: bank.Account.time.year
-          })
+      bank.Account.calculateRange fromDate, true, =>
+          bank.Ajax.get(
+              Routes.account_transactions_path(accountId), {
+                  dataType: 'html'
+                  success: (data) ->
+                      $('.transactions-wrapper').html(data)
+                      $('.transactions-wrapper').removeClass('waiting')
+                      bank.Account.calculateRange fromDate, false, ->
+                          bank.Account.refreshTotals()
+                  data:
+                      month: @time.month
+                      year: @time.year
+              })

     @calculateRange: (fromDate, toCurrent, callback = ->) ->
       if toCurrent
-          finish =
+          if @time.year < fromDate.year and @time.month < fromDate.month
+              return callback()
+
+          finish = finish:
               month: bank.Account.time.month
               year: bank.Account.time.year
       else
-          finish = null
+          finish = {}
+

       bank.Ajax.post(Routes.account_calculate_path(accountId), {
           dataType: 'html'
           success: (data) ->
               callback()
-          data:
+          data: $.extend(
               start:
                   month: fromDate.month
                   year: fromDate.year
-              finish: finish
+          , finish)
       })

     @refreshTotals: () ->
@@ -41,10 +46,6 @@
                 $('.totals-wrapper').html(data)
                 refreshMinMax()
             dataType: 'HTML'
-
-        bank.Ajax.post(Routes
-            .account_review_path(accountId, @time.month, @time.year)
-        )

     refreshMinMax = ->
         bank.Ajax.get Routes.account_min_max_path(accountId),


fixed epsilon-rounding

fixed epsilon-rounding

--- app/assets/javascripts/pullVerticesWorker.coffee
+++ app/assets/javascripts/pullVerticesWorker.coffee
@@ -59,9 +59,12 @@
 		max_z = min_z = cubeVertices[0][2] | 0
 		for i in [1...cubeVertices.length]
 			vertex = cubeVertices[i]
-			x = vertex[0] | 0
-			y = vertex[1] | 0
-			z = vertex[2] | 0
+			x = vertex[0]
+			y = vertex[1]
+			z = vertex[2]
+			x = (x + if x >= 0 then EPSILON else -EPSILON) | 0
+			y = (y + if y >= 0 then EPSILON else -EPSILON) | 0
+			z = (z + if z >= 0 then EPSILON else -EPSILON) | 0
 			max_x = if x > max_x then x else max_x
 			max_y = if y > max_y then y else max_y
 			max_z = if z > max_z then z else max_z


vm: annotate vm state

vm: annotate vm state

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -138,6 +138,10 @@
         default         : KONFIG.defaultVMConfigs.freeVM.cpu ? 1
       stack             : ObjectId
       meta              : Object
+      state             :
+        type            : String
+        enum            : ['UNKNOWN', ['RUNNING','STOPPED','FAILED']]
+        default         : 'STOPPED'

   @updateInitScript = secure (client, hostnameAlias, script, callback) ->
     {delegate} = client.connection


change

change

--- js/vis.coffee
+++ js/vis.coffee
@@ -27,8 +27,8 @@

   # names will also be used to color the bars
   colorScale = d3.scale.ordinal()
-    .range(["#CD0000","#647381","#708090","#7e8c9b","#8c99a6",
-    "#9aa6b1","#a9b2bc","#b7bfc7","#c5ccd2",
+    .range(["#CD0000","#FF82AB","#FFB5C5","#87CEFF","#B0E2FF",
+    "#FFDAB9","#FFDEAD","#FFEFDB","#F0FFF0",
     "#d4d8dd"])

   # yPadding is removed to make room for country names


Klient: expose kite.systemInfo wrapper to client as systemInfo

--- client/Main/kite/kites/klient.coffee
+++ client/Main/kite/kites/klient.coffee
@@ -6,6 +6,7 @@

     exec               : 'exec'
     ping               : 'kite.ping'
+    systemInfo         : 'kite.systemInfo'

     fsReadDirectory    : 'fs.readDirectory'
     fsGlob             : 'fs.glob'


use syncOptions when saving

use syncOptions when saving

--- client/lanes/screens/Commands.coffee
+++ client/lanes/screens/Commands.coffee
@@ -17,8 +17,11 @@
         @screen.setModelUrl?(model)
         @options.modelDidRebind?(model)

+    getSyncOptions: ->
+        _.result(@screen, 'syncOptions') || {}
+
     saveModel: ->
-        @getModel().save()
+        @getModel().save(@getSyncOptions())

     toggleEdit: ->
         @screen.setState(isEditing: !@isEditing())


use external browser for dyalog.com link in About

--- client/about.coffee
+++ client/about.coffee
@@ -35,5 +35,6 @@
     .dialog
       title: 'About', width: 520, height: 410, buttons: buttons
       open: -> $(@).find('textarea').focus(); return
+    .on 'click', 'a[href^=http]', -> D.openExternal $(@).attr 'href'; false
     .find('textarea').val(info).select()
   return


comment fix

comment fix

--- models/partner_show.coffee
+++ models/partner_show.coffee
@@ -243,14 +243,11 @@
   closed: -> @get('status') is 'closed'
   renderable: -> @get('eligible_artworks_count') > 0 || @get('images_count') > 2

-  # opens at any time between the previous monday and future weekend if monday - thursday, if saturday or sunday include to next weekend
+  # opens at any time between the previous and future weekend
   openingThisWeek: ->
-    start = moment().day(1).startOf('day')
-    startAt = moment(@startAtDate())
-    if moment().day() < 5
-      end = moment().day(8).startOf('day')
-    else
-      end = moment().day(13).startOf('day')
+    start = moment().day(-2).startOf('day')
+    end = moment().day(8).startOf('day')
+    startAt = @startAtDate()
     start < startAt && end > startAt

   startAtDate: ->


Social: integrate version and health check endpoints into social worker

--- workers/social/lib/social/main.coffee
+++ workers/social/lib/social/main.coffee
@@ -118,4 +118,11 @@
   app.post '/xhr', koding.expressify()
   app.get '/xhr',(req,res)->
     res.send "Socialworker is OK"
+
+  app.get '/version',(req,res)->
+    res.send "Socialworker is running with version: #{KONFIG.version}"
+
+  app.get '/healthCheck',(req,res)->
+    res.send "Socialworker is OK"
+
   app.listen argv.p


rearrange to use include-named-match-rules pattern.

--- grammars/log.cson
+++ grammars/log.cson
@@ -7,144 +7,172 @@
 # Try to fuzzy match a time stamp on first line
 'firstLineMatch': '^[0-9]{2}.?[0-9]{2}.?[0-9]{2}.?[0-9]{2}.[0-9]{2}.?[0-9]{2}.+'
 'patterns': [
-
-  # General syntax
   {
-    'match': '[ \\[]\/[^ ,]+',
-    'name': 'keyword.log'
+    'include': '#general'
   }
   {
-    'match': ' [a-z]+:\/\/[^ ,]+'
-    'name': 'keyword.log'
+    'include': '#timestamps'
   }
   {
-    'match': '".*?"'
-    'name': 'keyword.log'
+    'include': '#android'
   }
   {
-    'match': '\'.*?\''
-    'name': 'keyword.log'
-  }
-
-  # Time stamp syntax
-  {
-    'match': '^[0-9.,: \-]*?[0-9]{3}[:]? '
-    'name': 'definition.comment.log'
+    'include': '#ios'
   }
   {
-    'match': '^[0-9\.]* - -?'
-    'name': 'definition.comment.log'
+    'include': '#idea'
   }
   {
-    'match': '^\\[[A-Za-z0-9 :]+\\]?'
-    'name': 'definition.comment.log'
-  }
-
-  # Android Log syntax
-  {
-    'match': '.* GC_FOR_ALLOC .*'
-    'name': 'variable.parameter.gc-alloc.log'
+    'include': '#apache'
   }
   {
-    'match': '[A|E]\/.*?[﹕|:]'
-    'name': 'definition.log.log-error'
-  }
-  {
-    'match': 'W\/.*?[﹕|:]'
-    'name': 'definition.log.log-warning'
-  }
-  {
-    'match': 'D\/.*?[﹕|:]'
-    'name': 'definition.log.log-debug'
-  }
-  {
-    'match': 'I\/.*?[﹕|:]'
-    'name': 'definition.log.log-info'
-  }
-  {
-    'match': 'V\/.*?[﹕|:]'
-    'name': 'definition.log.log-verbose'
-  }
-
-  # iOS log syntax
-  {
-    'match': '^[A-Z]+[a-zA-Z0-9\/ ]*?:'
-    'name': 'definition.log.log-verbose'
-  }
-  {
-    'match': '[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}'
-    'name': 'keyword.log'
-  }
-
-  # IDEA log
-  {
-    'match': '\\[[0-9\ ]*\\].*ERROR ?'
-    'name': 'definition.log.log-error'
-  }
-  {
-    'match': '\\[[0-9\ ]*\\].*WARN ?'
-    'name': 'definition.log.log-warning'
-  }
-  {
-    'match': '\\[[0-9\ ]*\\].*INFO ?'
-    'name': 'definition.log.log-info'
-  }
-
-  # Apache access log
-  {
-    'match': ' ([4|5][0-9]{2}) [0-9]*$'
-    'captures':
-      '1':
-        'name': 'definition.log.log-failed'
-  }
-  {
-    'match': ' ([2|3]0[0-9]{1}) [0-9]*$'
-    '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
-  {
-    'match': '^\#.*'
-    'name': ''
-  }
-  {
-    'match': '\{00[0-9a-f]+\}'
-    'name': ''
-  }
-  {
-    'match': '\\[[A-Z_]+,(fatal|error)[^:]*'
-    'name': 'definition.log.log-error'
-  }
-  {
-    'match': '\\[[A-Z_]+,warn[^:]*'
-    'name': 'definition.log.log-warning'
-  }
-  {
-    'match': '\\[[A-Z_]+,info[^:]*'
-    'name': 'definition.log.log-info'
-  }
-  {
-    'match': '\\[[A-Z_]+,debug[^:]*'
-    'name': 'definition.log.log-debug'
-  }
-  {
-    'match': '\\[[A-Z_]+,(trace|thrd)[^:]*'
-    'name': 'definition.log.log-verbose'
+    'include': '#nabto'
   }
 ]
+
+'repository':
+  'general':
+    'patterns': [
+      {
+        'match': '[ \\[]\/[^ ,]+',
+        'name': 'keyword.log'
+      }
+      {
+        'match': ' [a-z]+:\/\/[^ ,]+'
+        'name': 'keyword.log'
+      }
+      {
+        'match': '".*?"'
+        'name': 'keyword.log'
+      }
+      {
+        'match': '\'.*?\''
+        'name': 'keyword.log'
+      }
+    ]
+  'timestamps':
+    'patterns': [
+      {
+        'match': '^[0-9.,: \-]*?[0-9]{3}[:]? '
+        'name': 'definition.comment.log'
+      }
+      {
+        'match': '^[0-9\.]* - -?'
+        'name': 'definition.comment.log'
+      }
+      {
+        'match': '^\\[[A-Za-z0-9 :]+\\]?'
+        'name': 'definition.comment.log'
+      }
+    ]
+  'android':
+    'patterns': [
+      {
+        'match': '.* GC_FOR_ALLOC .*'
+        'name': 'variable.parameter.gc-alloc.log'
+      }
+      {
+        'match': '[A|E]\/.*?[﹕|:]'
+        'name': 'definition.log.log-error'
+      }
+      {
+        'match': 'W\/.*?[﹕|:]'
+        'name': 'definition.log.log-warning'
+      }
+      {
+        'match': 'D\/.*?[﹕|:]'
+        'name': 'definition.log.log-debug'
+      }
+      {
+        'match': 'I\/.*?[﹕|:]'
+        'name': 'definition.log.log-info'
+      }
+      {
+        'match': 'V\/.*?[﹕|:]'
+        'name': 'definition.log.log-verbose'
+      }
+    ]
+  'ios':
+    'patterns': [
+      {
+        'match': '^[A-Z]+[a-zA-Z0-9\/ ]*?:'
+        'name': 'definition.log.log-verbose'
+      }
+      {
+        'match': '[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}'
+        'name': 'keyword.log'
+      }
+    ]
+  'idea':
+    'patterns': [
+      {
+        'match': '\\[[0-9\ ]*\\].*ERROR ?'
+        'name': 'definition.log.log-error'
+      }
+      {
+        'match': '\\[[0-9\ ]*\\].*WARN ?'
+        'name': 'definition.log.log-warning'
+      }
+      {
+        'match': '\\[[0-9\ ]*\\].*INFO ?'
+        'name': 'definition.log.log-info'
+      }
+    ]
+  'apache':
+    'pattern': [
+      {
+        'match': ' ([4|5][0-9]{2}) [0-9]*$'
+        'captures':
+          '1':
+            'name': 'definition.log.log-failed'
+      }
+      {
+        'match': ' ([2|3]0[0-9]{1}) [0-9]*$'
+        'captures':
+          '1':
+            'name': 'definition.log.log-success'
+      }
+      {
+        'match': '\\[error\\]'
+        'name': 'definition.log.log-error'
+      }
+      {
+        'match': '\\[info\\]'
+        'name': 'definition.log.log-info'
+      }
+      {
+        'match': '\\[notice\\]'
+        'name': 'definition.log.log-verbose'
+      }
+    ]
+  'nabto':
+    'patterns': [
+      {
+        'match': '^\#.*'
+        'name': ''
+      }
+      {
+        'match': '\{00[0-9a-f]+\}'
+        'name': ''
+      }
+      {
+        'match': '\\[[A-Z_]+,(fatal|error)[^:]*'
+        'name': 'definition.log.log-error'
+      }
+      {
+        'match': '\\[[A-Z_]+,warn[^:]*'
+        'name': 'definition.log.log-warning'
+      }
+      {
+        'match': '\\[[A-Z_]+,info[^:]*'
+        'name': 'definition.log.log-info'
+      }
+      {
+        'match': '\\[[A-Z_]+,debug[^:]*'
+        'name': 'definition.log.log-debug'
+      }
+      {
+        'match': '\\[[A-Z_]+,(trace|thrd)[^:]*'
+        'name': 'definition.log.log-verbose'
+      }
+    ]


Fix precedence error with Pic arrow operators

--- grammars/pic.cson
+++ grammars/pic.cson
@@ -407,11 +407,12 @@
 	# Mathematical symbols
 	operators:
 		patterns: [
+			{match: "<->|<-|->",  name: "keyword.operator.arrow.pic"}
+
 			match: "[=><]=?|!=|&&|\\|\\|"
 			name: "keyword.operator.comparison.pic"

 			{match: ":?=",        name: "keyword.operator.assignment.pic"}
-			{match: "<-|<->|->",  name: "keyword.operator.arrow.pic"}
 			{match: "[-/+*%^]",   name: "keyword.operator.arithmetic.pic"}
 		]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/floating_text_effect.coffee
+++ src/floating_text_effect.coffee
@@ -3,7 +3,7 @@
 to move the text upward and fade it out over 0.5 seconds.

     # adds a FloatingTextEffect to the engine
-    # at (50, 50). This
+    # at (50, 50). This effect will float up
     engine.add 'FloatingTextEffect'
       x: 50
       y: 50


Allow submitting new post form with cmd/ctrl + return

--- assets/javascripts/views/new_post_form.js.coffee
+++ assets/javascripts/views/new_post_form.js.coffee
@@ -20,6 +20,15 @@
       @updateCharCounter()
       null
     @updateCharCounter()
+
+    ## cmd/ctr enter == submit
+    @$textarea.on 'keydown.keysubmit', (e) =>
+      if (e.metaKey || e.ctrlKey) && e.keyCode == 13
+        e.preventDefault()
+        @submit()
+        false
+      else
+        true

     ## permissions
     @$publicCheckbox = ($ '[name=public]', @$el)
@@ -62,7 +71,7 @@
     @$publicCheckbox.attr('disabled', 'disabled')

   submit: (e) =>
-    e.preventDefault()
+    e.preventDefault() if e
     data = @getData()
     return false unless @validate data


add try catch around json parse to avoid syntax error end of input when json malformed.

--- me.coffee
+++ me.coffee
@@ -152,10 +152,16 @@
 											if rs.headers['content-encoding'] == 'gzip'
 												zlib.gunzip buffer, (err, decoded) ->
 													return callback err if err
-													body = JSON.parse decoded.toString()
+													try
+														body = JSON.parse decoded.toString()
+													catch e
+														return callback e if e
 													return callback null, fieldMap(body, content.fields, filter)
 											else
-												body = JSON.parse buffer.toString()
+												try
+													body = JSON.parse buffer.toString()
+												catch e
+													return callback e if e
 												return callback null, fieldMap(body, content.fields, filter)


Automatically reconnect WebSocket

Automatically reconnect WebSocket

--- ui/app/scripts/services/Channel.coffee
+++ ui/app/scripts/services/Channel.coffee
@@ -27,7 +27,7 @@
       $rootScope.$apply () ->
         matrix[id].notify(packet)

-    channelDeferred = $q.defer()
+    channelDeferred = $callback.defer()
     Channel.connected = () ->
       channelDeferred.promise

@@ -41,9 +41,14 @@

     connect = (url) ->
       socket = new WebSocket(url)
+      socket.onclose = () ->
+        setTimeout((->
+          connect(url)
+        ), 1000)
       socket.onopen = () ->
         channel = new ChannelObject(socket)
-        channelDeferred.resolve(channel)
+        channelDeferred.notify(channel)
+

     getConfig().then (url) ->
       connect(url)


removing finish from intro

removing finish from intro

--- hubot-scripts/intro.coffee
+++ hubot-scripts/intro.coffee
@@ -15,6 +15,5 @@
     for x of introduction
       setTimeout ((y) ->
         msg.send "#{introduction[y]}"
-        msg.finish()
       ), (1500 * x), x
     msg.finish()


Make sure VBox and HBox still work

Make sure VBox and HBox still work

Not adding tests because about to remove HBox and VBox

--- bokehjs/src/coffee/models/layouts/basebox.coffee
+++ bokehjs/src/coffee/models/layouts/basebox.coffee
@@ -9,5 +9,22 @@
       children: [ p.Array, [] ]
     }

+  get_layoutable_children: () ->
+    return @get('children')
+
+  get_edit_variables: () ->
+    edit_variables = super()
+    # Go down the children to pick up any more constraints
+    for child in @get_layoutable_children()
+      edit_variables = edit_variables.concat(child.get_edit_variables())
+    return edit_variables
+
+  get_constraints: () ->
+    constraints = super()
+    # Go down the children to pick up any more constraints
+    for child in @get_layoutable_children()
+      constraints = constraints.concat(child.get_constraints())
+    return constraints
+
 module.exports =
   Model: BaseBox


Rename filter constants, alias f0 method

--- instruments.coffee
+++ instruments.coffee
@@ -249,12 +249,12 @@
 class Filter

   # Biquad filter types
-  @LPF = 0                # H(s) = 1 / (s^2 + s/Q + 1)
-  @HPF = 1                # H(s) = s^2 / (s^2 + s/Q + 1)
-  @BPF_CONSTANT_SKIRT = 2 # H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q)
-  @BPF_CONSTANT_PEAK = 3  # H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain)
+  @LOW_PASS = 0                # H(s) = 1 / (s^2 + s/Q + 1)
+  @HIGH_PASS = 1                # H(s) = s^2 / (s^2 + s/Q + 1)
+  @BAND_PASS_CONSTANT_SKIRT = 2 # H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q)
+  @BAND_PASS_CONSTANT_PEAK = 3  # H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain)
   @NOTCH = 4              # H(s) = (s^2 + 1) / (s^2 + s/Q + 1)
-  @APF = 5                # H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1)
+  @ALL_PASS = 5                # H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1)
   @PEAKING_EQ = 6         # H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1)
   @LOW_SHELF = 7          # H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1)
   @HIGH_SHELF = 8         # H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A)
@@ -317,6 +317,18 @@
                       # dB/octave, remains proportional to S for all other values for a
                       # fixed f0/Fs and dBgain.

+  #
+  # Basic filter parameters
+  setCutoffFrequency: (freq) ->
+    @setF0(freq)
+
+  setQ: (q) ->
+    @parameterType = Filter.Q
+    @Q = Math.max(Math.min(q, 115.0), 0.001)
+    @recalculateCoefficients()
+
+  #
+  # Advanced filter parameters
   coefficients: ->
     b = [@b0, @b1, @b2]
     a = [@a0, @a1, @a2]
@@ -324,11 +336,6 @@

   setFilterType: (type) ->
     @type = type
-    @recalculateCoefficients()
-
-  setQ: (q) ->
-    @parameterType = Filter.Q
-    @Q = Math.max(Math.min(q, 115.0), 0.001)
     @recalculateCoefficients()

   setBW: (bw) ->
@@ -380,7 +387,7 @@
     #

     switch @type
-      when Filter.LPF       # H(s) = 1 / (s^2 + s/Q + 1)
+      when Filter.LOW_PASS       # H(s) = 1 / (s^2 + s/Q + 1)
         @b0 =  (1 - cosw0)/2
         @b1 =   1 - cosw0
         @b2 =  (1 - cosw0)/2
@@ -388,7 +395,7 @@
         @a1 =  -2 * cosw0
         @a2 =   1 - alpha

-      when Filter.HPF       # H(s) = s^2 / (s^2 + s/Q + 1)
+      when Filter.HIGH_PASS       # H(s) = s^2 / (s^2 + s/Q + 1)
         @b0 =  (1 + cosw0)/2
         @b1 = -(1 + cosw0)
         @b2 =  (1 + cosw0)/2
@@ -396,7 +403,7 @@
         @a1 =  -2 * cosw0
         @a2 =   1 - alpha

-      when Filter.BPF_CONSTANT_SKIRT       # H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q)
+      when Filter.BAND_PASS_CONSTANT_SKIRT       # H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q)
         @b0 =   sinw0/2
         @b1 =   0
         @b2 =  -sinw0/2
@@ -404,7 +411,7 @@
         @a1 =  -2*cosw0
         @a2 =   1 - alpha

-      when Filter.BPF_CONSTANT_PEAK       # H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain)
+      when Filter.BAND_PASS_CONSTANT_PEAK       # H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain)
         @b0 =   alpha
         @b1 =   0
         @b2 =  -alpha
@@ -420,7 +427,7 @@
         @a1 =  -2*cosw0
         @a2 =   1 - alpha

-      when Filter.APF       # H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1)
+      when Filter.ALL_PASS       # H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1)
         @b0 =   1 - alpha
         @b1 =  -2*cosw0
         @b2 =   1 + alpha


fix status name

fix status name

--- src/layout/mixins/status.coffee
+++ src/layout/mixins/status.coffee
@@ -24,7 +24,7 @@
   value = value.all() if sprite.is_array(value)
   "#{value}"

-exports.inspect_status = (sprite) ->
+exports.status = (sprite) ->

   status_buttons = make.buttons('stat', [
       "-"


refactor: remove language-properties fileTypes

--- grammars/language-properties.cson
+++ grammars/language-properties.cson
@@ -1,9 +1,7 @@
 # Hack for fix grammar parsing bug (`java-properties`, `git-config`)
 name: 'AsciiDoc Hack for properties'
 scopeName: 'source.asciidoc.properties'
-fileTypes: [
-  'ASCIIDOC_PROPERTIES'
-]
+fileTypes: []
 patterns: [
   {
     include: '#section'


test: also log user account details

test: also log user account details

--- it/pingpong.coffee
+++ it/pingpong.coffee
@@ -18,6 +18,7 @@
 logger = new Log 'info'

 Symphony = require '../src/symphony'
+Q = require 'q'

 throw new Error('BOT_USER_CERT undefined') unless process.env.BOT_USER_CERT
 throw new Error('BOT_USER_KEY undefined') unless process.env.BOT_USER_KEY
@@ -54,23 +55,24 @@

 logger.info 'Connections initiated, starting tests...'

-# print bot user diagnostics and send a message from user account
-botConnection.whoAmI()
+# print bot & user account diagnostics, send message from user -> bot and verify receipt
+userConnection.whoAmI()
+  .then (response) ->
+    userConnection.getUser({userId: response.userId})
+  .then (response) ->
+    logger.info "User name is #{response.displayName} [#{response.emailAddress}]"
+    botConnection.whoAmI()
   .then (response) ->
     botConnection.getUser({userId: response.userId})
   .then (response) ->
     logger.info "Bot name is #{response.displayName} [#{response.emailAddress}]"
     # get conversation between user & bot
     userConnection.createIM(response.id)
-  .then (response) =>
+  .then (response) ->
     # send ping from user to bot
     userConnection.sendMessage(response.id, "ping", "TEXT")
-  .fail (err) ->
-    logger.error "Failed to get bot details and send message from user: #{err}"
-    process.exit(1)
-  .done
-
-botConnection.createDatafeed()
+  .then (response) ->
+    botConnection.createDatafeed()
   .then (response) ->
     logger.info "Created datafeed: #{response.id}"
     botConnection.readDatafeed(response.id)
@@ -78,5 +80,6 @@
     logger.info "Received '#{msg.message}'" for msg in response when msg.v2messageType = 'V2Message'
     process.exit(0)
   .fail (err) ->
-    logger.error "Failed to receive a message: #{err}"
-    process.exit(2)
+    logger.error "Ping integration test failure: #{err}"
+    process.exit(1)
+  .done


Input: lodash require

Input: lodash require

--- input/index.coffee
+++ input/index.coffee
@@ -1,3 +1,4 @@
+_ = require 'lodash'
 z = require 'zorium'
 Rx = require 'rxjs/Rx'


Extract controls events registration in a method

--- lib/available-package-view.coffee
+++ lib/available-package-view.coffee
@@ -57,6 +57,7 @@
     {@name} = @pack

     @handlePackageEvents()
+    @handleControlsEvent()
     @updateEnablement()
     @loadCachedMetadata()

@@ -112,6 +113,7 @@
             """
             console.error("No available version compatible with the installed Atom version: #{atom.getVersion()}")

+  handleControlsEvent: ->
     @installButton.on 'click', =>
       @install()