Fixed the Couchbase server to shutdown the connection!

--- server/src/Component/Builtin/Database/CouchMuffin.coffee
+++ server/src/Component/Builtin/Database/CouchMuffin.coffee
@@ -16,12 +16,10 @@
         @_cherries = @component 'Cherries'
         @$ = @component 'QueryBuilder', true

-    _query: (statement, callback) ->
+    _query: (query, callback) ->
         @_bucket.query query, (error, result) ->
-            if error
-                callback error
-            else
-                callback null, result
+            callback error if error
+            callback null, result

     _createCounter: (callback) ->
         @insert @_counterKey, 1, (error) ->
@@ -40,8 +38,7 @@

     # Bind all methods from MyNinja into the model instance (expect for init() and bind() itself)
     bind: (model) ->
-#        methodsToBind = ['findById', 'find', 'findAll', 'removeAll', 'removeById', 'remove', 'query', 'updateAll', 'save']
-        methodsToBind = ['findById', 'findManyById', 'removeById', 'save', 'insert']
+        methodsToBind = ['findById', 'findManyById', 'removeById', 'save', 'insert', 'findAll']
         for methodName in methodsToBind
             muffinMethod = @[methodName]
             ((muffinMethod) =>
@@ -177,8 +174,6 @@

     # Finds several records using the specified conditions
     findAll: (params, callback) ->
-        callback = params.callback ? ->
-
         conditions = params.conditions ? null
         builder = @$.selectStarFrom(@_dataSource.bucketName)
         builder.where(conditions) if conditions
@@ -186,9 +181,7 @@
         builder.having(params.having) if params.having?
         sql = builder.build()

-        @_query sql, (error, results) ->
-            return callback(error) if error
-            return callback(null, results)
+        @_query sql, callback

 #    # Deletes all records from the table - BE CAREFUL
 #    # @param {function} callback Called when the operation is completed (error)


Support setting a donation amount in the url

--- src/scripts/pages/donate/form/form.coffee
+++ src/scripts/pages/donate/form/form.coffee
@@ -1,4 +1,5 @@
 define (require) ->
+  linksHelper = require('cs!helpers/links')
   BaseView = require('cs!helpers/backbone/views/base')
   template = require('hbs!./form-template')
   require('less!./form')
@@ -969,6 +970,7 @@
     templateHelpers:
       countries: countries
       states: states
+      amount: () -> @amount

     events:
       'change form input[name="first"]': 'updateName'
@@ -977,6 +979,11 @@
       'change form input[name="AMT"]': 'updateDonation'
       'change form input[name="BILL_EMAIL_ADDRESS"]': 'updateEmail'

+    initialize: () ->
+      super()
+      queryString = linksHelper.serializeQuery(location.search)
+      @amount = queryString.amount or 10
+
     updateName: (e) ->
       $form = @$el.find('form')
       first = $form.find('input[name="first"]').val()


Relocate unused patterns for disposal

Relocate unused patterns for disposal

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -374,12 +374,6 @@
       { include: '#nestedSquareBrackets' }
     ]
   }
-  endArgumentsMeta: {
-    patterns: [
-      { include: '#doubleBackslash' }
-      { include: '#escapedCurlyBracket' }
-    ]
-  }
   inlineMathMode: {
     comment: 'This can be triggered using $ or \( \). Both can be used in the same pair.'
     contentName: 'string.other.math.inline.latex'
@@ -702,34 +696,40 @@
     name: 'support.function.general.latex'
     match: '\\\\[a-zA-Z@]+'
   }
-underscoreWithArgument: {
-  comment: 'Matches an underscore and between curly brackets'
-  name: 'punctuation.subscript.latex'
-  begin: '_\\s*(?={)'
-  end: '(?<=\\})'
-  patterns: [
-    { include: '#argumentScope' }
-  ]
-}
-underscoreNoArgument: {
-  comment: 'Matches an underscore and next character or macro. Considering making this give a warning, as brackets is best practice'
-  name: 'punctuation.subscript.latex'
-  match: '_\\s*(\\\\[a-zA-Z]+|\\\\[.]|.)?'
-}
-caretWithArgument: {
-  comment: 'Matches a caret and between curly brackets'
-  name: 'markup.other.superscript.latex'
-  begin: '\\^\\s*'
-  beginCaptures:
-    0:
-      name: 'punctuation.superscript.latex'
-  end: '(?<=[^\\^])'
-  patterns: [
-    { include: '$self' }
-  ]
-}
-caretNoArgument: {
-  comment: 'Matches a caret and next character or macro. Considering making this give a warning, as brackets is best practice'
-  name: 'punctuation.superscript.latex'
-  match: '\\^\\s*(\\\\[a-zA-Z]+|\\\\[.]|.)?'
-}
+  underscoreWithArgument: {
+    comment: 'Matches an underscore and between curly brackets'
+    name: 'punctuation.subscript.latex'
+    begin: '_\\s*(?={)'
+    end: '(?<=\\})'
+    patterns: [
+      { include: '#argumentScope' }
+    ]
+  }
+  underscoreNoArgument: {
+    comment: 'Matches an underscore and next character or macro. Considering making this give a warning, as brackets is best practice'
+    name: 'punctuation.subscript.latex'
+    match: '_\\s*(\\\\[a-zA-Z]+|\\\\[.]|.)?'
+  }
+  caretWithArgument: {
+    comment: 'Matches a caret and between curly brackets'
+    name: 'markup.other.superscript.latex'
+    begin: '\\^\\s*'
+    beginCaptures:
+      0:
+        name: 'punctuation.superscript.latex'
+    end: '(?<=[^\\^])'
+    patterns: [
+      { include: '$self' }
+    ]
+  }
+  caretNoArgument: {
+    comment: 'Matches a caret and next character or macro. Considering making this give a warning, as brackets is best practice'
+    name: 'punctuation.superscript.latex'
+    match: '\\^\\s*(\\\\[a-zA-Z]+|\\\\[.]|.)?'
+  }
+  endArgumentsMeta: {
+    patterns: [
+      { include: '#doubleBackslash' }
+      { include: '#escapedCurlyBracket' }
+    ]
+  }


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_camera.coffee
+++ src/engine_camera.coffee
@@ -5,7 +5,15 @@

   followTypes =
     centered: (object, options) ->
-      Matrix.translation(App.width / 2 - object.I.x, App.height / 2 - object.I.y)
+      defaults =
+        x: object.I.x
+        y: object.I.y
+        width: 0
+        height: 0
+
+      options = Object.extend(defaults, currentOptions)
+
+      Matrix.translation(App.width / 2 - options.x, App.height / 2 - options.y)

   self.bind "afterUpdate", ->
     if currentObject


Fixing issue that reloads datasets when brushing

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -186,6 +186,8 @@
                     @tooltipBrushMax.transition()
                         .duration(100)
                         .style("opacity", 0)
+
+                @wasBrushing = true
             )
             .on('brush', =>
                 if @options.selectionLimit != null
@@ -247,7 +249,7 @@
                     @options.zoom.translate(@prevTranslate)
                 else
                     [start, end] = @scales.x.domain();
-                    @center(start, end)
+                    @center(start, end, false)
             )
             .on('zoomend', =>
                 display = @scales.x.domain()
@@ -255,6 +257,10 @@
                     start: display[0],
                     end: display[1]
                 })
+                if not @wasBrushing
+                    for dataset of @datasets
+                        @reloadDataset(dataset)
+                @wasBrushing = false
             )
         @svg.call(@options.zoom)

@@ -311,13 +317,11 @@
         # First paint lines and ticks
         for dataset of @datasets
             if !@datasets[dataset].lineplot
-                @reloadDataset(dataset)
                 @redrawDataset(dataset)

         # Afterwards paint lines so they are not overlapped
         for dataset of @datasets
             if @datasets[dataset].lineplot
-                @reloadDataset(dataset)
                 @redrawDataset(dataset)

         # add classes to the ticks. When we are dealing with dates
@@ -742,9 +746,9 @@
         return false unless @datasets[id]?

     # redraws.
-    center: (params...) ->
-        start = new Date(params[0])
-        end = new Date(params[1])
+    center: (start, end, doReload = true) ->
+        start = new Date(start)
+        end = new Date(end)
         [ start, end ] = [ end, start ] if end < start

         diff = end - start
@@ -760,7 +764,9 @@
         @options.zoom.scale((@options.display.end - @options.display.start) / (end - start))
         @options.zoom.translate([ @options.zoom.translate()[0] - @scales.x(start), 0 ])
         @redraw()
-
+        if doReload
+            for dataset of @datasets
+                @reloadDataset(dataset)
         true

     # zoom to start/end. redraws.


:memo: Return -> Returns

:memo: Return -> Returns

--- src/file.coffee
+++ src/file.coffee
@@ -305,7 +305,7 @@
   #
   # * `text` The {String} text to write to the underlying file.
   #
-  # Return undefined.
+  # Returns undefined.
   writeSync: (text) ->
     previouslyExisted = @existsSync()
     @writeFileWithPrivilegeEscalationSync(@getPath(), text)


Add test for attribute definition of type 'number'.

--- src/spec/producttypegenerator.spec.coffee
+++ src/spec/producttypegenerator.spec.coffee
@@ -177,6 +177,31 @@

     expect(@generator._createAttributeDefinitions([attributeRow1, attributeRow2, attributeRow3])).toEqual expectedAttributeDefinition

+  it 'should return one attribute definition of type number', ->
+
+    attributeRow =
+      name: 'size'
+      type: 'number'
+      isVariant: 'false'
+      isRequired: 'false'
+      isSearchable: 'false'
+      'label.de': 'Größe'
+      'label.en': 'Size'
+
+    expectedAttributeDefinition =
+      size:
+        name: 'size'
+        label:
+          de: 'Größe'
+          en: 'Size'
+        type: 'number'
+        isVariant: 'false'
+        isRequired: 'false'
+        isSearchable: 'false'
+
+    expect(@generator._createAttributeDefinitions([attributeRow])).toEqual expectedAttributeDefinition
+
+
   it 'should return an array with product type definitions', ->

     productTypeDefinition1 =


added consider 192.168.xxx.xxx as development, added Firefox and IE detection

--- src/fz2d.coffee
+++ src/fz2d.coffee
@@ -68,8 +68,7 @@
   # Public: Development environment?
   @development: (() ->
     return 'development' if Fz2D.debug?
-    return 'development' if /localhost|127.0.0.1/i.test(window.location.hostname)
-    # return 'development' if document.getElementById('_fz2d_development')?
+    return 'development' if /localhost|127.0.0.1|192.168.\d+.\d+/i.test(window.location.hostname)
     Fz2D.production = 'production'
     null
   )()
@@ -89,6 +88,23 @@
     m = window.navigator.userAgent.match(/(iphone|ipod|ipad|android|iemobile|blackberry|bada)/i)
     if m
       m[1]
+    else
+      null
+  )()
+
+  # Public: Is Firefox?
+  @firefox: (() ->
+    if /firefox/i.test(window.navigator.userAgent)
+      'firefox'
+    else
+      null
+  )()
+
+  # Public: Is Internet Explorer?
+  @ie: (() ->
+    m = window.navigator.userAgent.match(/(msie \d+|iemobile\/\d+|WPDesktop)/i)
+    if m
+      parseInt(m[1].replace(/(msie\s+|iemobile\/)/i, '')) || 11
     else
       null
   )()


Fixes #70

Fixes #70

--- assets/js/src/main.coffee
+++ assets/js/src/main.coffee
@@ -5,8 +5,6 @@
   el = document.body
   el.dataset.page = Uno.context()
   el.dataset.device = Uno.device()
-  $(window).on "resize", Uno.device()
-  $(window).on "orientationchange", Uno.device()

   Uno.readTime()
   FastClick.attach el unless Uno.is 'device', 'desktop'


Fixed misleading logging (mongoose connection).

--- app/templates/index.coffee
+++ app/templates/index.coffee
@@ -8,7 +8,7 @@

 mongoose.connect config.mongoUrl, (error) ->
 	Log.error error if error
-	Log.info "Mongoose connected to #{config.mongoUrl}."
+	Log.info "Mongoose connected to #{config.mongoUrl}." unless error

 app = express()


Help text for options.

Help text for options.

--- node_modules/one_pass/app.coffee
+++ node_modules/one_pass/app.coffee
@@ -60,8 +60,8 @@
     new Commander.constructor()
       .version('0.0.0')
       .description('1Password command line client.')
-      .option('-d, --data <data>')
-      .option('-r, --raw')
+      .option('-d, --data <data>', 'path to keychain')
+      .option('-r, --raw', 'show raw item data (for bug reports)')
       .parse(args)

   databasePath: (callback) ->


fixed that bulk invite/approve should start with oldest requests, instead of the newest

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -950,8 +950,9 @@
     success: (client, count, callback)->
       @fetchInvitationRequests {}, {
         targetOptions :
-          selector    : { status  : 'pending' }
-          options     : { limit   : count }
+          selector    : { status    : 'pending' }
+          options     : { limit     : count }
+        sort          : { timestamp : 1 }
       }, (err, requests)->
         if err then callback err
         else


group: add kallback func to gather all errors and log out them

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1576,84 +1576,82 @@
       account = client?.connection?.delegate
       { sessionToken } = client

-      # mark this team as deleted
-      @update { $set: { markAs: 'deleted' } }, (err) =>
+      @checkUserPassword account, password, (err) =>

         return callback new KodingError err  if err

-        @checkUserPassword account, password, (err) =>
-
-          return callback new KodingError err  if err
-
-          slug = @getAt 'slug'
-          JName = require '../name'
-
-          removeHelper = (model, err, next) ->
-            return next err  if err
-            return next()  unless model
-
-            model.remove (err) -> next err
-
-          removeHelperMany = (klass, models, err, next) ->
-            return next err  if err
-            return next()    if not models or models.length < 1
-
-            ids = (model._id for model in models)
-            klass.remove ({ _id: { $in: ids } }), (err) -> next err
-
-          async.series [
-
-            (next) ->
-              JName.one { name: slug }, (err, name) ->
-                removeHelper name, err, next
-
-            (next) =>
-              @fetchPermissionSet (err, permSet) ->
-                removeHelper permSet, err, next
-
-            (next) =>
-              @fetchDefaultPermissionSet (err, permSet) ->
-                removeHelper permSet, err, next
-
-            (next) ->
-              JInvitation = require '../invitation'
-              JInvitation.remove { groupName: slug }, (err) ->
-                next err
-
-            (next) =>
-              ComputeProvider = require '../computeproviders/computeprovider'
-              ComputeProvider.destroyGroupResources this, -> next()
-
-            (next) ->
-              url = '/api/social/payment/subscription/delete'
-              { deleteReq } = require '../socialapi/requests'
-
-              deleteReq url, { sessionToken }, (err, body) ->
-                next err
-
-            (next) =>
-              JSession = require '../session'
-              @sendNotification 'GroupDestroyed', slug, ->
-                JSession.remove { groupName: slug }, (err) ->
-                  next err
-
-            (next) ->
-              JApiToken = require '../apitoken'
-              JApiToken.remove { group: slug }, (err) ->
-                next err
-
-            (next) =>
-              @constructor.emit 'GroupDestroyed', this
-              next()
-
-            (next) =>
-              @remove (err) -> next err
-
-          ], (err) =>
-            if err
-              @sendNotification 'GroupDestroyed'
-              @remove()
-            callback()
+        slug = @getAt 'slug'
+        JName = require '../name'
+
+        errors = []
+
+        kallback = (label, next, err) ->
+
+          errors.push { label, err }  if err
+          next()
+
+        removeHelper = (model, err, next, label) ->
+
+          if err or not model
+            return kallback label, next, err
+
+          model.remove (err) -> kallback label, next, err
+
+        async.series [
+
+          (next) ->
+            JName.one { name: slug }, (err, name) ->
+              removeHelper name, err, next, 'JName'
+
+          (next) =>
+            @fetchPermissionSet (err, permSet) ->
+              removeHelper permSet, err, next, 'PermissionSet'
+
+          (next) =>
+            @fetchDefaultPermissionSet (err, permSet) ->
+              removeHelper permSet, err, next, 'DefaultPermissionSet'
+
+          (next) ->
+            JInvitation = require '../invitation'
+            JInvitation.remove { groupName: slug }, (err) ->
+              kallback 'JInvitation', next, err
+
+          (next) =>
+            ComputeProvider = require '../computeproviders/computeprovider'
+            ComputeProvider.destroyGroupResources this, -> next()
+
+          (next) ->
+            url = '/api/social/payment/subscription/delete'
+            { deleteReq } = require '../socialapi/requests'
+
+            deleteReq url, { sessionToken }, (err, body) ->
+              kallback 'Subscription', next, err
+
+          (next) =>
+            JSession = require '../session'
+            @sendNotification 'GroupDestroyed', slug, ->
+              JSession.remove { groupName: slug }, (err) ->
+                kallback 'JSession', next, err
+
+          (next) ->
+            JApiToken = require '../apitoken'
+            JApiToken.remove { group: slug }, (err) ->
+              kallback 'JApiToken', next, err
+
+          (next) =>
+            @constructor.emit 'GroupDestroyed', this
+            next()
+
+          (next) =>
+            @remove (err) -> kallback 'JGroup', next, err
+
+        ], =>
+          if errors.length
+            @sendNotification 'GroupDestroyed'
+            errors.forEach (error) ->
+              console.log '[GROUP_DESTROY_FAILED]: for ', slug, ' in ', error.label, ' with error', error.err
+
+          callback()

   sendNotificationToAdmins: (event, contents) ->


server: remove commented out scriptblock code

--- workers/social/lib/social/render/scriptblock.coffee
+++ workers/social/lib/social/render/scriptblock.coffee
@@ -96,17 +96,13 @@
     queue = [
       ->
         bongoModels.JCustomPartials.one selector, (err, partial)->
-          console.log ">>>>>>>>> partial", partial
           customPartial = partial.data  if not err and partial
           queue.fin()
       ->
         bongoModels.JGroup.one {slug : slug or 'koding'}, (err, group) ->
-          console.log ">>>>>>>>> group", group
           console.log err if err

           bongoModels.JReferralCampaign.one isActive: yes, (err, campaignData_)->
-            console.log ">>>>>>>>> JReferralCampaign", campaignData_
-
             if not err and campaignData_ and campaignData_.data
               campaignData = campaignData_.data

@@ -128,31 +124,6 @@

     dash queue, -> callback null, createHTML()

-    # add custom partials into body
-    # bongoModels.JCustomPartials.one selector, (err, partial)->
-    #   customPartial = partial.data  if not err and partial
-
-    #   bongoModels.JGroup.one {slug : slug or 'koding'}, (err, group) ->
-    #     console.log err if err
-
-        # add custom partial into referral campaign
-    #     bongoModels.JReferralCampaign.one isActive: yes, (err, campaignData_)->
-
-    #       if not err and campaignData_ and campaignData_.data
-    #         campaignData = campaignData_.data
-
-    #       if group
-    #         currentGroup = group
-
-    #       bongoModels.JWorkspace.fetch client, {}, (err, workspaces) ->
-    #         console.log err  if err
-    #         userWorkspaces = workspaces or []
-
-    #         bongoModels.JMachine.some$ client, {}, (err, machines) ->
-    #           console.log err  if err
-    #           userMachines = machines or []
-    #           callback null, createHTML()
-

   socialApiCacheFn = require '../cache/socialapi'
   socialApiCacheFn options, (err, data)->


Don’t combine changes in patch

Don’t combine changes in patch

Keeping them distinct ensures our position translation will keep tokens
distinct.

--- src/display-layer.coffee
+++ src/display-layer.coffee
@@ -8,7 +8,7 @@
 module.exports =
 class DisplayLayer
   constructor: (@buffer, {@tabLength, patchSeed}) ->
-    @patch = new Patch(patchSeed)
+    @patch = new Patch(combineChanges: false, seed: patchSeed)
     @buffer.onDidChange(@bufferDidChange.bind(this))
     @computeTransformation(0, @buffer.getLineCount())
     @emitter = new Emitter


Fix a bug when replacing fragments during a running animation or transition

--- lib/assets/javascripts/up/flow.js.coffee
+++ lib/assets/javascripts/up/flow.js.coffee
@@ -134,9 +134,11 @@
         swapElements($old, $new, step.pseudoClass, step.transition, options)

   findOldFragment = (selector) ->
-    u.presence($(".up-popup " + selector)) ||
-    u.presence($(".up-modal " + selector)) ||
-    u.presence($(selector)) ||
+    selectorWithExcludes = "#{selector}:not(.up-ghost, .up-destroying)"
+    # Prefer to replace fragments in an open popup or modal
+    u.presence($(".up-popup #{selectorWithExcludes}")) ||
+    u.presence($(".up-modal #{selectorWithExcludes}")) ||
+    u.presence($(selectorWithExcludes)) ||
     u.error('Could not find selector %o in current body HTML', selector)

   parseResponse = (html) ->


Update visual settings in Atom, increase font size and change syntax theme

--- atom/dot-atom/config.cson
+++ atom/dot-atom/config.cson
@@ -73,8 +73,14 @@
     ]
     packagesWithKeymapsDisabled: []
     telemetryConsent: "no"
+    themes: [
+      "one-dark-ui"
+      "alpenglow-twilight-atom-syntax"
+    ]
   editor:
     fontFamily: "Hack"
+    fontSize: 16
+    lineHeight: 1.2
     preferredLineLength: 79
     scrollPastEnd: true
     showIndentGuide: true


Fix uncommitted / unpublished changes

Fix uncommitted / unpublished changes

--- lib/advanced-web-editor.coffee
+++ lib/advanced-web-editor.coffee
@@ -356,6 +356,7 @@
       @lifeCycle.setupToolbar(@toolBar)

   doPreStartCheck: () ->
+    keepEditing = false
     deferred = q.defer()
     @lifeCycle.openProjectFolder()
     @lifeCycle.checkUncommittedChanges()
@@ -393,20 +394,26 @@
                   deferred.resolve @doSaveOrPublish(action)
                 'Keep editing': =>
                   if action == 'save'
-                    deferred.resolve true#do Nothing
+                    #
                   else
                     @lifeCycle.checkoutThenUpdate state.branches.sort()[0]
                       .then () -> deferred.resolve true
                       .fail (error) -> deferred.reject error

+                  @lifeCycle.statusStarted()
+                  @startStatusCheck()
+                  keepEditing = true
+                  deferred.resolve true
+
         else
           @lifeCycle.statusReady()
           return @lifeCycle.updateMaster()
       .then () =>
-        return @lifeCycle.updateDevelop()
+        return @lifeCycle.updateDevelop() if !keepEditing
       .then () =>
-        atom.notifications.addInfo("Everything is up to date. Start editing when you are ready")
-        @lifeCycle.statusReady()
+        if !keepEditing
+          atom.notifications.addInfo("Everything is up to date. Start editing when you are ready")
+          @lifeCycle.statusReady()
         deferred.resolve true
       .fail (e) =>
         console.log e


new api url

new api url

--- src/scripts/app.coffee
+++ src/scripts/app.coffee
@@ -1,4 +1,4 @@
-apiUrl = "//54.77.4.249:8000"
+apiUrl = "//fv15api.bemit.dk"

 angular.module "ng-app", [
   "ngTouch"


do not event event

do not event event

--- demo/scripts/stypi/ot/jetstate.coffee
+++ demo/scripts/stypi/ot/jetstate.coffee
@@ -64,7 +64,7 @@

   reset: (delta) ->
     delta = JetDelta.getInitial(delta) if _.isString(delta)
-    @editor.applyDelta(delta)
+    @editor.applyDelta(delta, false)
     @arrived = delta
     @inFlight = JetDelta.getIdentity(@arrived.endLength)
     @inLine = JetDelta.getIdentity(@arrived.endLength)
@@ -81,7 +81,7 @@
     @inFlight = JetSync.follows(delta, @inFlight, true)
     @inLine = JetSync.follows(flightDeltaFollows, @inLine, true)

-    @editor.applyDelta(textFollows)
+    @editor.applyDelta(textFollows, false)

   takeoff: ->
     console.assert(@inFlight?, "inFlight is", @inFlight, "at takeoff")


fix a bug

fix a bug

--- lib/build/build-manager.coffee
+++ lib/build/build-manager.coffee
@@ -4,6 +4,8 @@
 _ = require 'underscore'

 uuid = require 'uuid'
+
+os = require 'os'

 fsIsDirectorySync = (path) ->
   try
@@ -33,7 +35,7 @@
     buildStateView = new (require './build-state-view')()

     # 这样就可以可以不仅在windows还是mac都可以获取到.atom路径
-    decs = "#{atom.getConfigDirPath()}/atom-butterfly"
+    decs = "#{os.tmpdir()}/atom-butterfly"
     zipFile = "#{uuid.v1()}.zip"
     unless fsIsDirectorySync(decs)
       console.log "新建文件夹：#{decs}"


add "the" to invitation

add "the" to invitation

--- src/smc-hub/hub.coffee
+++ src/smc-hub/hub.coffee
@@ -1230,7 +1230,7 @@
                             if mesg.link2proj? # make sure invitees know where to go
                                 base_url = mesg.link2proj.split("/")
                                 base_url = "#{base_url[0]}//#{base_url[2]}"
-                                direct_link = "Then go to project '#{mesg.title}'."
+                                direct_link = "Then go to the project '#{mesg.title}'."
                             else # fallback for outdated clients
                                 base_url = 'https://cloud.sagemath.com/'
                                 direct_link = ''


Add 'compile:babel' task

Add 'compile:babel' task

--- gulp/tasks/compile.coffee
+++ gulp/tasks/compile.coffee
@@ -2,7 +2,16 @@
 config = require("../config")
 $      = config.plugins

-gulp.task("compile", ["compile:coffee", "compile:scss", "compile:haml"])
+gulp.task("compile", ["compile:babel", "compile:coffee", "compile:scss", "compile:haml"])
+
+gulp.task "compile:babel", ->
+  gulp.src(config.src.babel)
+    .pipe($.plumber())
+    .pipe($.sourcemaps.init())
+    .pipe($.babel())
+    .pipe($.uglify())
+    .pipe($.sourcemaps.write(config.map))
+    .pipe(gulp.dest(config.dist.js))

 gulp.task "compile:coffee", ["lint:coffee"], ->
   gulp.src(config.src.coffee)
@@ -22,4 +31,4 @@
 gulp.task "compile:haml", ->
   gulp.src(config.src.haml)
   .pipe($.haml())
-  .pipe(gulp.dest(config.dist.html))+  .pipe(gulp.dest(config.dist.html))


[Fix] gulp replace

[Fix] gulp replace

--- gulp/tasks/replace.coffee
+++ gulp/tasks/replace.coffee
@@ -4,7 +4,7 @@
 config = require('../config')

 gulp.task 'replace', ->
-  env =  'development'
+  env = 'development'
   settings = JSON.parse(fs.readFileSync("./#{config.appDir}/config/environments/#{env}.json", 'utf8'))

   gulp.src("./#{config.appDir}/config/config.coffee")
@@ -16,7 +16,7 @@
         }
         {
           match: 'env'
-          replacement: settings.env
+          replacement: env
         }
       ]
     ))


Make the code a little bit more coffeescript-like

--- backbone.tableview.coffee
+++ backbone.tableview.coffee
@@ -128,7 +128,7 @@
     # Navigate to url with all the parameters in data in the querystring
     updateUrl: =>
         uri = Backbone.history.fragment
-        if (i = uri.indexOf("?")) > 0
+        if (i = uri.indexOf "?") > 0
             uri = uri.substring(0, i)
         first = true
         for key, val of @data
@@ -138,7 +138,7 @@
             else
                 separator = "&"
             uri = uri + separator + key + "=" + val
-        @router.navigate(uri)
+        @router.navigate uri

     # Return a parsed querystring with the "?" (eg. query = "/users?hi=1&bye=hello")
     # returns {hi: "1", bye: "hello"}


Throw error if trying to beautify Perl without setting Perl Tidy path

See #138, #33.

--- lib/langs/perl-beautify.coffee
+++ lib/langs/perl-beautify.coffee
@@ -6,6 +6,10 @@

 getCmd = (inputPath, outputPath, options) ->
   # console.debug "[perl-beautify] options: " + JSON.stringify(options)
+  if not options.perltidy_path?
+    return new Error("'Perl Perltidy Path' not set!" +
+      " Please set this in the Atom Beautify package settings.")
+
   args = [
     '"' + options.perltidy_path + '"'
     '--standard-output'


:bug: documentation for TextEditor::indentationForBufferRow()

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -2930,9 +2930,9 @@
   Section: Indentation
   ###

-  # Essential: Get the indentation level of the given a buffer row.
-  #
-  # Returns how deeply the given row is indented based on the soft tabs and
+  # Essential: Get the indentation level of the given buffer row.
+  #
+  # Determines how deeply the given row is indented based on the soft tabs and
   # tab length settings of this editor. Note that if soft tabs are enabled and
   # the tab length is 2, a row with 4 leading spaces would have an indentation
   # level of 2.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_effect.coffee
+++ src/text_effect.coffee
@@ -1,7 +1,7 @@
 ###*
 The Text Effect class provides a method to display moving text onscreen, fading out the text over the effect duration.

-    # adds a FloatingTextEffect to the engine
+    # adds a TextEffect to the engine
     # at (50, 50). This effect will float upward
     # at 90 pixels/sec and will fadeOut over 0.5 seconds
     engine.add 'FloatingTextEffect'


:lipstick: Removes commented code

:lipstick: Removes commented code

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -32,7 +32,6 @@
     @editor = @editorView.getModel()
     @buffer = @editorView.getEditor().buffer

-    # @subscribe @buffer, 'changed', @registerBufferChanges
     @subscribe @editor, 'screen-lines-changed.minimap', (changes) =>
       @pendingChanges.push changes
       @requestUpdate()


Fix stupid typo

Fix stupid typo

--- src/tools/defer.coffee
+++ src/tools/defer.coffee
@@ -2,4 +2,4 @@
 setTimeout wrapper
 ###

-module.exports = wnd.setImmediate or wndwnd.setTimeout
+module.exports = wnd.setImmediate or wnd.setTimeout


KDFramework: lazyload threshold fix

KDFramework: lazyload threshold fix

--- client/Framework/core/KDView.coffee
+++ client/Framework/core/KDView.coffee
@@ -516,7 +516,7 @@

         ratio = (scrollTop + view.getHeight()) / scrollHeight

-        if dynamicThreshold > ratio > lastRatio
+        if dynamicThreshold < ratio > lastRatio
           @emit 'LazyLoadThresholdReached', {ratio}

         lastRatio = ratio


Fix indent

Fix indent

--- lib/python-import-magic.coffee
+++ lib/python-import-magic.coffee
@@ -28,5 +28,5 @@
   reindex: ->
     call
       cmd: 'reindex', 'utf-8', (out) ->
-      console.log 'Import magic', out.message
+        console.log 'Import magic', out.message
   provide: -> provider


stub activity

stub activity

--- src/draw_controls.coffee
+++ src/draw_controls.coffee
@@ -10,6 +10,11 @@
         Right: {turn: -1}
       }
     }
-    activity: {}
+    activity: {
+      click: (world, {turtle, key, value}) ->
+        -> turtle.call(key, {dir: value})
+      _children: {
+      }
+    }
   }
 }


Datatable: Small fix for the last change where a new method to change the page was added.

--- src/elements/DataTable/DataTable.coffee
+++ src/elements/DataTable/DataTable.coffee
@@ -322,7 +322,7 @@
 	loadPage: (page) ->
 		maxPage = Math.floor(@rows?.length / @_chunk_size)
 		if not CUI.util.isNumber(page) or maxPage < 0 or page > maxPage
-			return
+			page = 0

 		@__offset = page * @_chunk_size
 		@displayValue()


Record the file name of a control's source in the control documentation.

--- grunt/quidoc.coffee
+++ grunt/quidoc.coffee
@@ -303,6 +303,8 @@
     if extractor?
       source = fs.readFileSync filePath, "utf8"
       controlDocs = extractor.extract source
+      # During markup->CoffeeScript port, track file type
+      controlDocs.filePath = filePath
       controlDocs.type = extension.slice 1
       className = controlDocs.className
       if className?


Compilation auto de tous les fichiers stylus

--- grunt/stylus.coffee
+++ grunt/stylus.coffee
@@ -2,6 +2,9 @@
 	compile:
 		options:
 			urlfunc: 'embedurl'
-		files:
-			'dist/css/client.css': 'styles/client.styl'
-			'dist/css/cover.css': 'styles/cover.styl'
+		files: [
+			expand: true
+			src: 'styles/**/*.styl'
+			dest: 'dist/css/'
+			ext: '.css'
+		]


implement arrow key support

implement arrow key support

--- client/js/views/picture_view.coffee
+++ client/js/views/picture_view.coffee
@@ -37,4 +37,16 @@
     previous = @model.get 'previous'
     preloadMedia '#preload .previous', previous if previous

+$ ->
+  $(document).keydown (event) ->
+    LEFT_ARROW = 37
+    RIGHT_ARROW = 39
+
+    $link = $()
+    $link = $('#picture .next-link:visible') if event.keyCode == RIGHT_ARROW
+    $link = $('#picture .prev-link:visible') if event.keyCode == LEFT_ARROW
+    $link.click()
+
+    return !$link.length
+
 module.exports = {PictureView}


group: redirect to "/Login" when invitation banner callback

--- client/landing/Login/AppView.coffee
+++ client/landing/Login/AppView.coffee
@@ -457,7 +457,7 @@

   headBannerShowInvitation:(invite)->
     @showHeadBanner "Cool! you got an invite! If you already have an account click here to sign in.", =>
-      @animateToForm "login"
+      KD.singleton("router").handleRoute "/Login"
       @headBanner.hide()

     KD.getSingleton('router').clear @getRouteWithEntryPoint 'Register'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_levels.coffee
+++ src/engine_levels.coffee
@@ -45,7 +45,7 @@
         engine.setState GameOver()

   ###*
-  Load map for the next level.
+  Load map for

   engine.nextLevel()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_levels.coffee
+++ src/engine_levels.coffee
@@ -62,7 +62,7 @@
   Reload the current level.

-  engine.goToLevel 'bossFight'
+  engine.realodLEvel

   @name goToLevel


Default opts.

Default opts.

--- src/event-emitter.coffee
+++ src/event-emitter.coffee
@@ -1,5 +1,5 @@
 class EventEmitter
-  constructor: (opts) ->
+  constructor: (opts = {}) ->
     @debug         = opts.debug ? false
     @_listeners    = {}
     @_allListeners = []


Minor revise of the service impl

Minor revise of the service impl

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -86,16 +86,15 @@
     # Supports implicit extraction of captured groups in the match.
     # Use this to configure what resources should match with service.
     @resource: (pattern) ->
-        identify = (@nick or @name).underline
-        duplicate = pattern in (@resources or [])
+        identify = @identify().underline
         regexify = (s) -> new RegExp "^#{RegExp.escape(s)}$"
-        pattern = regexify pattern  if _.isString pattern
-        inspected = pattern.unescape()?.underline or pattern.source
+        pattern = regexify pattern if _.isString pattern
+        inspected = pattern.unescape()?.underline or pattern
         associate = "Associating #{inspected} resource with #{identify}"
         notRegexp = "The #{inspected} is not a valid regular expression"
-        throw new Error notRegexp unless _.isRegExp pattern
-        (@resources ?= []).push pattern unless duplicate
-        (logger.debug associate.grey unless duplicate); this
+        assert _.isRegExp(pattern), notRegexp
+        (@resources ?= []).push pattern
+        logger.debug associate.grey; @

     # This is a very basic method that adds the specified regular
     # expression pattern to the list of permitted domain patterns.
@@ -103,16 +102,15 @@
     # Supports implicit extraction of captured groups in the match.
     # Use this to configure what domains should match with service.
     @domain: (pattern) ->
-        identify = (@nick or @name).underline
-        duplicate = pattern in (@domains or [])
-        regexify = (s) -> new RegExp RegExp.escape(s)
-        pattern = regexify(pattern)  if _.isString(pattern)
-        inspected = pattern.unescape()?.underline or pattern.source
-        associate = "Associating #{inspected} domain with #{identify}"
+        identify = @identify().underline
+        regexify = (s) -> new RegExp "^#{RegExp.escape(s)}$"
+        pattern = regexify pattern if _.isString pattern
+        inspected = pattern.unescape()?.underline or pattern
+        associate = "Associating #{inspected} resource with #{identify}"
         notRegexp = "The #{inspected} is not a valid regular expression"
-        throw new Error notRegexp unless _.isRegExp pattern
-        (@domains ?= []).push pattern unless duplicate
-        (logger.debug associate.grey unless duplicate); this
+        assert _.isRegExp(pattern), notRegexp
+        (@domains ?= []).push pattern
+        logger.debug associate.grey; @

     # Unregister the current service instance from the kernel router.
     # You should call this method only after the service has been
@@ -148,9 +146,8 @@
         presource = (pattern) -> pattern.test pathname
         domainOk = _.some domains, pdomain
         resourceOk = _.some resources, presource
-        parameters = [request, response, next]
         matches = domainOk and resourceOk
-        @emit "matches", matches, parameters...
+        @emit "matches", matches, arguments...
         return domainOk and resourceOk

     # This method should process the already matched HTTP request.
@@ -170,6 +167,5 @@
         presource = _.find resources, presource
         assert gdomain isnt null, "missing domain"
         assert gresource isnt null, "missing resource"
-        parameters = [request, response, next]
-        @emit "process", gdomain, gresource, parameters...
+        @emit "process", gdomain, gresource, arguments...
         return domain: gdomain, resource: gresource


Redirect to login page after resetting password

--- client/services/loginservice.coffee
+++ client/services/loginservice.coffee
@@ -134,7 +134,7 @@
             handleRedirect = ->
               if remainingSeconds == 0
                 Session.set("isRedirecting", false)
-                Router.go('/')
+                Router.go('/login')
               else
                 remainingSeconds -= 1
                 Session.set("remainingSeconds", remainingSeconds)


Ensure playlist position is 0 when playlist is empty

--- frontend/app/js/playlist-service.coffee
+++ frontend/app/js/playlist-service.coffee
@@ -16,7 +16,7 @@
     addReplacePlay: (uri, type) -> mpd.addToPlaylist(uri, type, true,  true)

   $rootScope.$on MPD_STATUS, (event, data) ->
-    api.position = parseInt(data.Pos)+1
+    api.position = parseInt(data.Pos||-1)+1
     api.length = data.playlistlength
     # TODO: only load the playlist when the playlist changed (mpd subsystems)
     mpd.currentPlaylist().then (data) ->


Clean up topic creation.

Clean up topic creation.

--- client/src/scripts/main-view.coffee
+++ client/src/scripts/main-view.coffee
@@ -16,10 +16,10 @@
     else
       _listViews.remove _topicListView

-  createTopic = (title, handle, isEnabled) ->
+  createTopic = (title, handle) ->
     self =
       title: title
-      isDisabled: not isEnabled
+      isDisabled: not isFunction handle
       display: -> handle() if handle

   switchTopic = (topic) ->
@@ -60,14 +60,14 @@
     _.loadNotifications predicate

   _topics = node$ [
-    _frameTopic = createTopic 'Datasets', switchToFrames, yes
-    _modelTopic = createTopic 'Models', switchToModels, yes
-    _scoringTopic = createTopic 'Scoring', switchToScoring, yes
-    _timelineTopic = createTopic 'Timeline', null, no
-    _notificationTopic = createTopic 'Notifications', switchToNotifications, yes
-    _jobTopic = createTopic 'Jobs', null, no
-    _clusterTopic = createTopic 'Cluster', null, no
-    _administrationTopic = createTopic 'Administration', null, no
+    _frameTopic = createTopic 'Datasets', switchToFrames
+    _modelTopic = createTopic 'Models', switchToModels
+    _scoringTopic = createTopic 'Scoring', switchToScoring
+    _timelineTopic = createTopic 'Timeline', null
+    _notificationTopic = createTopic 'Notifications', switchToNotifications
+    _jobTopic = createTopic 'Jobs', null
+    _clusterTopic = createTopic 'Cluster', null
+    _administrationTopic = createTopic 'Administration', null
   ]

   _topicListView = Steam.TopicListView _, _topics


Refactoring of enum inspection.

Refactoring of enum inspection.

--- lib/formats/jsonschema-v4.coffee
+++ lib/formats/jsonschema-v4.coffee
@@ -247,32 +247,39 @@
   ], cb

-inspectEnum = (enumElement, resolvedType, cb) ->
-  return cb new Error "Multiple nested types for enum." if resolvedType.nested.length > 1
-  nestedTypeName = resolvedType.nested?[0]
-
-  items = inspect.listItems enumElement
-  if items.length
-    groupItemsByPrimitiveTypes items, nestedTypeName, (err, groups, nonPrimitiveItems) ->
-      return cb err if err
-
+inspectEnumItems = (items, nestedTypeName, cb) ->
+  async.waterfall [
+    (next) -> groupItemsByPrimitiveTypes items, nestedTypeName, next
+    (groups, nonPrimitiveItems, next) ->
       for group in groups
         hasSamples = inspect.haveVariableValues group.items
         group.strategy = if hasSamples then 'singleType' else 'values'
         group.values = []
-
-      cb null, {inline: false, groups, nonPrimitiveItems}
-  else
-    hasSamples = inspect.hasVariableValues enumElement
-    cb null,
-      inline: true
-      nonPrimitiveItems: []
-      groups: [
-        typeName: nestedTypeName
-        items: []
-        values: inspect.listValues enumElement
-        strategy: if hasSamples then 'singleType' else 'values'
-      ]
+      next null, {inline: false, groups, nonPrimitiveItems}
+  ], cb
+
+
+inspectEnumInline = (enumElement, nestedTypeName, cb) ->
+  if inspect.hasVariableValues enumElement
+    values = []
+    strategy = 'singleType'
+  else
+    values = inspect.listValues enumElement
+    strategy = 'values'
+
+  group = {typeName: nestedTypeName, items: [], values, strategy}
+  cb null, {inline: true, nonPrimitiveItems: [], groups: [group]}
+
+
+inspectEnum = (enumElement, resolvedType, cb) ->
+  return cb new Error "Multiple nested types for enum." if resolvedType.nested.length > 1
+  nestedTypeName = resolvedType.nested?[0]
+
+  items = inspect.listItems enumElement
+  if items.length
+    inspectEnumItems items, nestedTypeName, cb
+  else
+    inspectEnumInline enumElement, nestedTypeName, cb

 # Generates JSON Schema representation for given *Element* node containing


Queue interactive commands

Queue interactive commands

--- lib/ghc-modi-process-base.coffee
+++ lib/ghc-modi-process-base.coffee
@@ -101,12 +101,16 @@
         child.stdin.write "#{text}#{EOT}"
       handle()

-  runModiCmd: ({dir, options, command, text, uri, args, callback, legacyInteractive}) =>
+  runModiCmd: (o) =>
+    {dir, options, command, text, uri, args, callback, legacyInteractive} = o
     debug "Trying to run ghc-modi in #{dir.getPath()}"
     process = @spawnProcess(dir, legacyInteractive, options)
     unless process
       debug "Failed. Falling back to ghc-mod"
-      return @runModCmd {options, command, text, uri, args, callback}
+      return @runModCmd o
+    if process.stdout.isPaused()
+      setTimeout (=> @runModiCmd o), 100
+      return
     process.stdout.pause()
     Promise.resolve().then ->
       if text?


Fix #28

Fix #28

--- lib/ide-haskell-repl-view.coffee
+++ lib/ide-haskell-repl-view.coffee
@@ -64,15 +64,15 @@
     @cwd = Util.getRootDir @uri

     builder = try @upi.getConfigParam('ide-haskell-cabal', 'builder')
+
+    setImmediate =>
+      if typeof builder?.then is 'function'
+        builder.then => @runREPL(builder?.name)
+      else
+        @runREPL(builder?.name)
+
+  runREPL: (builder) ->
     builder ?= atom.config.get 'ide-haskell-repl.defaultRepl'
-
-    setImmediate =>
-      if typeof builder.then is 'function'
-        builder.then => @runREPL(builder.name)
-      else
-        @runREPL(builder.name)
-
-  runREPL: (builder) ->
     subst =
       'nix-build': 'cabal'
       'none': 'ghci'


Show prompt

Show prompt

--- lib/ide-haskell-repl-view.coffee
+++ lib/ide-haskell-repl-view.coffee
@@ -25,6 +25,7 @@
     @output.setGrammar \
       atom.grammars.grammarForScopeName 'text.tex.latex.haskell'
     @element.appendChild @errDiv = document.createElement 'pre'
+    @element.appendChild @promptDiv = document.createElement 'div'
     @element.appendChild @editorDiv = document.createElement 'div'
     @editorDiv.classList.add('ide-haskell-repl-editor')
     @editorDiv.appendChild @editorElement =
@@ -38,6 +39,8 @@
       lines = @editor.getScreenLineCount()
       @editorDiv.style.setProperty 'height',
         "#{lines*lh}px"
+    setPrompt = (prompt) =>
+      @promptDiv.innerText = prompt+'>'

     @editorElement.onDidAttach -> setEditorHeight()
     @editor.onDidChange ->
@@ -65,7 +68,10 @@
             line.slice(0,10000) + '...'
           else
             line
-        if lines.slice(-1)[0] is '#~IDEHASKELLREPL~#'
+        rx = /^#~IDEHASKELLREPL~(.*)~#$/
+        if rx.test promptline = lines.slice(-1)[0]
+          [_, prompt] = rx.exec promptline
+          setPrompt prompt if prompt?
           lines =
             if lines.slice(-2)[0]
               lines.slice(0,-1)
@@ -86,7 +92,7 @@

     ghci = @process.process

-    ghci.stdin.write(":set prompt \"\\n#~IDEHASKELLREPL~#\\n\"#{EOL}")
+    ghci.stdin.write(":set prompt \"\\n#~IDEHASKELLREPL~%s~#\\n\"#{EOL}")
     ghci.stdin.write(":set prompt2 \"\"#{EOL}")
     ghci.stdin.write(":set editor atom #{EOL}")
     ghci.stdin.write(":load #{@uri}#{EOL}")


WIP changes to improve performance when loading the tree. Prevented loading the tree twice. Improved performance for checking.

--- src/tree.coffee
+++ src/tree.coffee
@@ -25,19 +25,70 @@
   data = @data
   model = @model
   items = @items
-  cursor = Collections.getCursor(items)
   settings = getSettings()
   template = @
-  loadTree(@)
+  # loadTree(@)
+  refreshTree(@)
+
+TemplateClass.destory = ->
+  _.each @checkboxes, ($checkbox) ->
+    # Remove bound events.
+    $checkbox.off()
+
+TemplateClass.events
+  'tree.select .tree': (e, template) -> handleSelectionEvent(e, template)
+  'tree.click .tree': (e, template) -> handleClickEvent(e, template)
+  'tree.dblclick .tree': (e, template) ->
+    id = e.node.id
+
+####################################################################################################
+# LOADING
+####################################################################################################
+
+loadTree = (element) ->
+  template = getTemplate(element)
+  $em = getElement(element)
+  getTreeElement(element).remove()
+  $tree = createTreeElement()
+  $em.append($tree)
+  model = template.model
+  docs = Collections.getItems(template.items)
+  treeData = model.docsToNodeData(docs)
+  settings = getSettings(element)
+  treeArgs =
+    data: treeData.data
+    autoOpen: settings.autoExpand
+    selectable: settings.selectable
+  treeArgs.onCreateLi = onCreateNode.bind(null, template)
+
+  # Check all new items if needed.
+  if settings.checked
+    template.check.setIds(_.keys(treeData.visited.ids))
+
+  $tree.tree(treeArgs)
+  setUpReactiveUpdates(template)
+
+# refreshTree = Functions.debounceLeft(loadTree, 1000)
+refreshTree = _.debounce(loadTree, 1000)
+
+setUpReactiveUpdates = (template) ->
+  return if template.isReactiveSetup

   # Only a reactive cursor can observe for changes. A simple array can only render a tree once.
+  cursor = Collections.getCursor(template.items)
   return unless cursor
-  @autorun ->
+
+  settings = getSettings(template)
+  model = template.model
+
+  template.autorun ->

     Collections.observe cursor,
       added: (newDoc) ->
         id = newDoc._id
         data = model.docToNodeData(newDoc, {children: false})
+        # Check all new items if needed.
+        if settings.checked then template.check.add([id])
         docParentId = model.getParent(data)
         unless docParentId
           # There is a significant memory leak caused by re-loading the entire tree after each
@@ -52,7 +103,7 @@
           $tree.tree('addNodeBefore', data, nextSiblingNode)
         else
           $tree.tree('appendNode', data, sortResults.parentNode)
-        autoExpand = getSettings(template).autoExpand
+        autoExpand = settings.autoExpand
         if autoExpand
           expandNode(template, id)
         parentNode = getNode(template, id).parent
@@ -90,39 +141,7 @@
         $tree = getTreeElement(template)
         $tree.tree('removeNode', node)

-TemplateClass.destory = ->
-  _.each @checkboxes, ($checkbox) ->
-    # Remove bound events.
-    $checkbox.off()
-
-TemplateClass.events
-  'tree.select .tree': (e, template) -> handleSelectionEvent(e, template)
-  'tree.click .tree': (e, template) -> handleClickEvent(e, template)
-  'tree.dblclick .tree': (e, template) ->
-    id = e.node.id
-
-####################################################################################################
-# LOADING
-####################################################################################################
-
-loadTree = (element) ->
-  template = getTemplate(element)
-  $em = getElement(element)
-  getTreeElement(element).remove()
-  $tree = createTreeElement()
-  $em.append($tree)
-  model = template.model
-  docs = Collections.getItems(template.items)
-  treeData = model.docsToNodeData(docs)
-  settings = getSettings(element)
-  treeArgs =
-    data: treeData
-    autoOpen: settings.autoExpand
-    selectable: settings.selectable
-  treeArgs.onCreateLi = onCreateNode.bind(null, template)
-  $tree.tree(treeArgs)
-
-refreshTree = Functions.debounceLeft(loadTree, 1000)
+  template.isReactiveSetup = true

 ####################################################################################################
 # EXPANSION
@@ -250,10 +269,17 @@

 getCheckedIds = (element) -> getTemplate(element).check.getIds()

-uncheckAll = (element) ->
+setAllChecked = (element, check) ->
+  check ?= true
+  template = getTemplate(element)
   return unless isCheckable(element)
-  selectedIds = getTemplate(element).check.removeAll()
-  handleCheckResult(element, {added: selectedIds, removed: []})
+  if check
+    ids = template.collection.find().forEach (doc) -> doc._id
+    changedIds = template.check.setIds(ids).added
+    handleCheckResult(element, {added: changedIds, removed: []})
+  else
+    changedIds = template.check.removeAll()
+    handleCheckResult(element, {added: [], removed: changedIds})

 toggleChecked = (element, ids) ->
   return unless isCheckable(element)
@@ -373,11 +399,13 @@
     unless @collection
       throw new Error('No collection provided when creating tree data')

-  getChildren: (doc) ->
+  getChildren: (doc, args) ->
+    args ?= {}
     # Search for root document if doc is undefined
     id = doc?._id ? null
     children = @collection.find({parent: id}).fetch()
     children.sort(@compareDocs)
+
     children

   hasChildren: (doc) -> @getChildren(doc).length == 0
@@ -389,13 +417,21 @@
   docToNodeData: (doc, args) ->
     args = _.extend({
       children: true
+      visited: {count: 0, ids: {}}
     }, args)
+    return if args.visited.ids[doc._id]# || args.visited.count >= 200
+
+    args.visited.ids[doc._id] = true
+    args.visited.count++
     data =
       id: doc._id
       label: doc.name
     if args.children
       childrenDocs = @getChildren(doc)
-      childrenData = _.map childrenDocs, @docToNodeData, @
+      childrenData = []
+      _.each childrenDocs, (childDoc) =>
+        childData = @docToNodeData(childDoc, args)
+        if childData then childrenData.push(childData)
       data.children = childrenData
     data

@@ -403,10 +439,11 @@
     data = []
     rootDocs = _.filter docs, (doc) => !@hasParent(doc)
     rootDocs.sort(@compareDocs)
+    args = {visited: {count: 0, ids: {}}}
     _.each rootDocs, (doc) =>
-      datum = @docToNodeData(doc)
+      datum = @docToNodeData(doc, args)
       data.push(datum)
-    data
+    Setter.merge {data: data}, args

   compareDocs: (docA, docB) ->
     if docA.name < docB.name then -1 else 1
@@ -458,7 +495,7 @@
     @remove(toRemove)
     toRemove

-  toggle: (ids) ->
+  toggle: (ids, enabled) ->
     existingIds = @getIds()
     toRemove = _.intersection(existingIds, ids)
     toAdd = _.difference(ids, existingIds)
@@ -491,7 +528,7 @@
   uncheckNode: uncheckNode
   setCheckedIds: setCheckedIds
   getCheckedIds: getCheckedIds
-  uncheckAll: uncheckAll
+  setAllChecked: setAllChecked
   toggleChecked: toggleChecked
   addChecked: addChecked
   removeChecked: removeChecked


Allow overriding reconnect connection parameter in options

--- src/vent.coffee
+++ src/vent.coffee
@@ -50,7 +50,7 @@
         @options = _.extend(default_options, options)

         @amqp_options =
-            reconnect: @setup.reconnect || true
+            reconnect: @setup.reconnect || @options.reconnect || true
             reconnectBackoffStrategy: @setup.backoff_strategy || "linear"
             reconnectBackoffTime: @setup.backoff_time || 500
             defaultExchangeName: @options.channel


Fix for classname issues.

Fix for classname issues.

--- src/view.coffee
+++ src/view.coffee
@@ -59,11 +59,19 @@
     el passed in as an option.
     ###
     ensureClass: (el, className=@className) ->
+        if el.jQuery then return el.addClass(className)
+
         if not className then return
         wanted = className?.split(/\s+/) ? []
-        existing = el.className.split(/\s+/)
-
-        el.className = _.uniq(existing.concat(wanted)).join(' ')
+
+        switch typeof el.className
+            when 'string'
+                existing = el.className?.split(/\s+/) ? []
+                el.className = _.uniq(existing.concat(wanted)).join(' ')
+            when 'object'
+                # SVG Element or child
+                existing = el.className?.baseVal?.split(/\s+/) ? []
+                el.className?.baseVal = _.uniq(existing.concat(wanted)).join(' ')

     ###
     Adds a list of views as children of this view.


Fuzzy remove guide.

Fuzzy remove guide.

--- lib/multi-wrap-guide-view.coffee
+++ lib/multi-wrap-guide-view.coffee
@@ -173,12 +173,14 @@
       columns: @columns
       scope: @editor.getRootScopeDescriptor()

-  # Private: Removes the guide at the given column, if one exists.
+  # Private: Removes the guide at or near the given column, if one exists.
   removeGuide: (column) ->
     return unless atom.workspace.getActiveTextEditor() is @editor
-    i = @columns.indexOf(column)
-    if i > -1
-      @columns.splice(i, 1)
+    for i in [column, column - 1, column + 1, column - 2, column + 2]
+      index = @columns.indexOf(i)
+      if index > -1
+        @columns.splice(index, 1)
+        break
     @saveColumns()
     @showGuides()
     @didChangeGuides()
@@ -227,11 +229,8 @@
     @columns = $.unique(@columns.sort (a, b) -> a - b)
     scope = @editor.getRootScopeDescriptor()
     scopeSelector = @getRootScopeSelector()
-    if @doAutoSave()
-      if @columns.length is 1
-        atom.config.set 'editor.preferredLineLength', @columns[0], scopeSelector: scopeSelector
-      else
-        atom.config.set 'multi-wrap-guide.columns', @columns, scopeSelector: scopeSelector
+    return unless @doAutoSave()
+    atom.config.set 'multi-wrap-guide.columns', @columns, scopeSelector: scopeSelector

   # Private: Mouse leave event handler, cancels guide dragging.
   mouseLeave: (e) =>


Fixes small spelling error.

Fixes small spelling error.

--- lib/multi-wrap-guide-view.coffee
+++ lib/multi-wrap-guide-view.coffee
@@ -58,7 +58,7 @@
     column

   # Private: Returns the column at the given page x position in piexls.
-  columnFromPostiionX: (x) ->
+  columnFromPositionX: (x) ->
     x += @editor.getScrollLeft()
     charWidth = @editorElement.getDefaultCharacterWidth()
     leftSide = (x // charWidth) * charWidth
@@ -250,7 +250,7 @@
   # Private: Sets the tip text based on the guide's current position.
   # Pre-condition: The tip element must be appended to the guide.
   setTip: (guide) ->
-    column = @columnFromPostiionX parseInt(guide.css 'left')
+    column = @columnFromPositionX parseInt(guide.css 'left')
     @setTipColumn guide, column

   # Private: Sets the tip text to be the given column.


green box has gravity!

green box has gravity!

--- ludumdare26/ludumdare26.coffee
+++ ludumdare26/ludumdare26.coffee
@@ -33,8 +33,9 @@

 # entrypoint
 game.start = ->
-
-    game.director = new lime.Director(document.body,1024,768)
+    @WIDTH = 1024
+    @HEIGHT = 768
+    game.director = new lime.Director(document.body,game.WIDTH,game.HEIGHT)
     game.world = setupWorld()
     game.titleScreen()

@@ -46,8 +47,8 @@
 setupWorld = ->
     gravity = new box2d.Vec2(0, 200)
     bounds = new box2d.AABB()
-    bounds.minVertex.Set -1024, -768
-    bounds.maxVertex.Set 2*1024, 2*768
+    bounds.minVertex.Set -game.WIDTH, -game.HEIGHT
+    bounds.maxVertex.Set 2*game.WIDTH, 2*game.HEIGHT
     new box2d.World(bounds, gravity, true)

@@ -74,24 +75,25 @@

     player1 = new game.Player
         x: 300
-        y: 500
+        y: game.HEIGHT /2
         width: 50
         height: 50
-
+        density: 2
+
     scene.appendChild player1._shape
     game.worldObjects.push player1

-    circle = new game.Object
-        x: 200
-        y: 600
-        width: 900
-        height: 30
+    ground = new game.Object
+        x: game.WIDTH /2
+        y: game.HEIGHT - game.HEIGHT/4
+        width: game.WIDTH
+        height: game.HEIGHT / 4

-    circle._shape.setFill 155,155,155
+    ground._shape.setFill 155,155,155

-    scene.appendChild circle._shape
+    scene.appendChild ground._shape

-    game.worldObjects.push circle
+    game.worldObjects.push ground

 #this is required for outside access after code is compiled in ADVANCED_COMPILATIONS mode


Bolt on header validation

Bolt on header validation

--- library/membrane/validate.coffee
+++ library/membrane/validate.coffee
@@ -119,7 +119,6 @@
     # the `name` and add it to the current request. If the `message`
     # is supplied then it will be forced as an error messages. Use
     # this method to automatically obtain contex for the parameter.
-    # This variation of method is intended to work on the parameters.
     param: (request, name, message) ->
         notParams = "the request has no params"
         notRequest = "a #{request} is not a request"
@@ -153,6 +152,60 @@
         assert _.isObject(response), notResponse
         assert _.isObject(request), notRequest
         @validateValues request.params, (error, results) ->
-            params = [results, request, response, continuation]
-            return @renderParamValidation params... if error
+            signature = [results, request, response, continuation]
+            return @renderParamValidation signature... if error
             return continuation.bind(this) results
+
+# This is an ABC service intended to be used only as a compund. It
+# provides a complete validation solution for request headers. The
+# important difference is this validation system supports asynchronous
+# validators which is what differs it from existent solutions. This
+# validation system is a one-stop-shop for checking all the inputs!
+module.exports.HValidator = class HValidator extends Validator
+
+    # This is a marker that indicates to some internal subsystems
+    # that this class has to be considered abstract and therefore
+    # can not be treated as a complete class implementation. This
+    # mainly is used to exclude or account for abstract classes.
+    @abstract yes
+
+    # Create a validation context for request header designated by
+    # the `name` and add it to the current request. If the `message`
+    # is supplied then it will be forced as an error messages. Use
+    # this method to automatically obtain contex for the parameter.
+    header: (request, name, message) ->
+        notParams = "the request has no params"
+        notRequest = "a #{request} is not a request"
+        assert _.isObject(request), notRequest
+        assert headers = request.headers, notParams
+        return @value headers, name, message
+
+    # This method is a default implementation of the renderer that
+    # will be called when the validation has failed. You can easily
+    # override it in either your service or in an external compound.
+    # By default it renders JSON object with errors mapped to headers.
+    renderHeaderValidation: (results, request, response) ->
+        notRequest = "a #{request} is not a request"
+        notResponse = "a #{response} is not a respnonse"
+        assert _.isObject(response), notResponse
+        assert _.isObject(request), notRequest
+        response.statusCode = 400 # bad headers
+        strings = _.map results, (e) -> e.message
+        map = _.object _.keys(results), strings
+        return @reject response, headers: map
+
+    # Given the request with possible validation contexts appended
+    # run all the validator contexts in parallel and wait for the
+    # completion. If no validation mistakes found, run continuation.
+    # If some mistakes are found, however, `@renderHeaderValidation`.
+    validateParameters: (request, response, continuation) ->
+        notRequest = "a #{request} is not a request"
+        notResponse = "a #{response} is not a response"
+        notContinuation = "a #{continuation} is not function"
+        assert _.isFunction(continuation), notContinuation
+        assert _.isObject(response), notResponse
+        assert _.isObject(request), notRequest
+        @validateValues request.headers, (error, results) ->
+            signature = [results, request, response, continuation]
+            return @renderHeaderValidation signature... if error
+            return continuation.bind(this) results


Don't differentiate overridden titles for now

--- src/scripts/models/contents/node.coffee
+++ src/scripts/models/contents/node.coffee
@@ -27,7 +27,8 @@

     parse: (response, options = {}) ->
       # Don't overwrite the title from the book's table of contents
-      if @get('title') then delete response.title
+      #if @get('title') then delete response.title
+      response.title = @get('title') or response.title

       if response.mediaType is 'application/vnd.org.cnx.collection'
         # Only load the contents once


Use fat arrow.

Use fat arrow.

--- src/spec/integration/import.spec.coffee
+++ src/spec/integration/import.spec.coffee
@@ -71,7 +71,7 @@
         #{@productType.id},myProduct,1,slug,EUR 899;CH-EUR 999;CH-USD 77777700 #retailerA
         """
       @importer.import(csv)
-      .then (result) ->
+      .then (result) =>
         expect(_.size result).toBe 1
         expect(result[0]).toBe '[row 2] New product created.'
         @client.products.where("productType(id=\"#{@productType.id}\")").fetch()


Stringify spec error

Stringify spec error

--- src/spec/integration/states.spec.coffee
+++ src/spec/integration/states.spec.coffee
@@ -38,7 +38,7 @@
       done()
     .fail (error) =>
       @logger.error error
-      done(error)
+      done(JSON.stringify(error))

   afterEach (done) ->
     @client.states.byId(@state.id).delete(@state.version)
@@ -48,7 +48,7 @@
       done()
     .fail (error) =>
       @logger.error error
-      done(error)
+      done(JSON.stringify(error))

   it 'should update a state', (done) ->
     @client.states.byId(@state.id).update(updateState(@state.version))
@@ -60,7 +60,7 @@
       done()
     .fail (error) =>
       @logger.error error
-      done(error)
+      done(JSON.stringify(error))

   it 'should create some states and use them as transitions references', (done) ->
     Q.all _.map [1..101], => @client.states.save(newState())
@@ -86,5 +86,5 @@
         done()
     .fail (error) =>
       @logger.error error
-      done(error)
+      done(JSON.stringify(error))


lint(spellchecker): remove trailing semicolons

--- src/nylas-spellchecker.coffee
+++ src/nylas-spellchecker.coffee
@@ -40,9 +40,9 @@
     dict = path.join(require.resolve('spellchecker'), '..', '..', 'vendor', 'hunspell_dictionaries')
     try
       # HACK: Special case being in an asar archive
-      unpacked = dict.replace('.asar' + path.sep, '.asar.unpacked' + path.sep);
+      unpacked = dict.replace('.asar' + path.sep, '.asar.unpacked' + path.sep)
       if require('fs').statSyncNoException(unpacked)
-        dict = unpacked;
+        dict = unpacked
     catch

     dict


metric: updated request time formatting

metric: updated request time formatting

--- src/models/metric.coffee
+++ src/models/metric.coffee
@@ -113,7 +113,7 @@
   }
   {
     name: 'request time 95% (ms)'
-    format: '0.00'
+    format: '0'
     numerator:
       select: 'percentile(value, 95)'
       from: 'timing'


metric: added views

metric: added views

--- src/models/metric.coffee
+++ src/models/metric.coffee
@@ -8,6 +8,16 @@
 dayToMS = util.dayToMS

 metrics = [
+  {
+    name: 'Views'
+    format: '0'
+    isGroupSizeDependent: true
+    numerator:
+      select: 'count(userId)'
+      from: 'view'
+      where: (day) ->
+        "time >= #{dayToMS day}ms AND time < #{dayToMS day + 1}ms"
+  }
   {
     name: 'Revenue (USD)'
     apps: ['kitten-cards']


:bug: fix error when child of factor has no type(such as Enumeration member)

--- src/renderer/components/signatures/doc-signatures-type-component.coffee
+++ src/renderer/components/signatures/doc-signatures-type-component.coffee
@@ -18,7 +18,9 @@
     <span style={Array.prototype.concat.apply([], [styles.base, @props.style])}>
       {
         elm = []
-        if !@props.type.name? && @props.type.type == 'reflection'
+        if !@props.type?
+          # do nothing
+        else if !@props.type.name? && @props.type.type == 'reflection'
           # type.name
           #
           # TODO


Disabled test for embedded

Disabled test for embedded

--- test/generators/relational/has_one.coffee
+++ test/generators/relational/has_one.coffee
@@ -178,6 +178,9 @@
         queue.await done

     it 'Can create a model and update the relationship (hasOne)', (done) ->
+      # TODO: implement embedded set - should clone in set or the caller needed to clone? (problem is sharing an in memory instance)
+      return done() if embed
+
       related_key = 'reverse'
       related_id_accessor = 'reverse_id'


Add index to analytics.log.event

Add index to analytics.log.event

--- server/analytics/AnalyticsLogEvent.coffee
+++ server/analytics/AnalyticsLogEvent.coffee
@@ -6,5 +6,6 @@
     type: Date
     'default': Date.now
 }, {strict: false})
+AnalyticsLogEventSchema.index({event: 1, created: -1})

 module.exports = AnalyticsLogEvent = mongoose.model('analytics.log.event', AnalyticsLogEventSchema)


Turn off colour as breaks programmatic things

--- code/li.coffee
+++ code/li.coffee
@@ -172,6 +172,10 @@
     ipstuff += ' Pub:' + item.ip_address
   if item.private_ip_address?
     ipstuff += ' Priv:' + item.private_ip_address
+  # Disable colour for now as doesn't work with some scripting of li list
+  # XXX DO NOT enable without making the colour conditional on it being called by a human
+  colour = ''
+  colour_off = ''
   console.log "#{colour}#{item.name}#{colour_off} \x1b[22;37m[#{item.config.name}]#{ipstuff}\x1b[0m #{item.comments}"

 friendly_state = (state) ->


config change

config change

--- both/config/_config.coffee
+++ both/config/_config.coffee
@@ -1,7 +1,7 @@
 @Config =
 	name: 'My App'
 	title: 'Make Meteor Apps. Fast.'
-	subtitle: 'Create beautiful and functioning Meteor apps really quick'
+	subtitle: 'Create beautiful  Meteor apps really fast'
 	logo: ->
 		'<b>' + @name + '</b>'
 	footer: ->


:lipstick: Resolve atom.sh once

:lipstick: Resolve atom.sh once

--- tasks/test-task.coffee
+++ tasks/test-task.coffee
@@ -9,11 +9,12 @@
   grunt.registerTask 'run-specs', 'Run the specs', ->
     passed = true
     done = @async()
+    atomPath = path.resolve('atom.sh')

     queue = async.queue (packagePath, callback) ->
       options =
         cmd: path.resolve('node_modules/.bin/apm')
-        args: ['test', '-p', path.resolve('atom.sh')]
+        args: ['test', '-p', atomPath]
         opts:
           cwd: packagePath
       spawn options, (error, results, code) ->


hide controls when deatching command panel

--- src/packages/command-panel/lib/command-panel-view.coffee
+++ src/packages/command-panel/lib/command-panel-view.coffee
@@ -115,6 +115,7 @@
     rootView.focus()
     @previewList.hide()
     @previewCount.hide()
+    @expandCollapse.hide()
     super

   escapedCommand: ->


Fixed time constant in adminUser caching

--- server/informatics/InformaticsUser.coffee
+++ server/informatics/InformaticsUser.coffee
@@ -49,7 +49,7 @@
         return adminUser

     @findAdmin: () ->
-        if not adminUser or (new Date() - adminUser.loginTime > 1000 * 1000 * 60 * 60)
+        if not adminUser or (new Date() - adminUser.loginTime > 1000 * 60 * 60)
             logger.info("Creating new adminUser")
             newAdminUser =
                 user: await InformaticsUser._findAdmin()


Uses new minimap API for char widths

Uses new minimap API for char widths

--- lib/minimap-find-results-view.coffee
+++ lib/minimap-find-results-view.coffee
@@ -28,7 +28,7 @@
     # I'll use fixed scale.
     adjustResults: ->
       return if @adjusted
-      @css '-webkit-transform', "scale3d(0.69,1,1)"
+      @css '-webkit-transform', "scale3d(#{minimapInstance.getCharWidthRatio()},1,1)"
       @adjusted = true

     getMinimap: ->


rewritten rebadylize() without DOM manipulations, added events

--- jquery-badyl.coffee
+++ jquery-badyl.coffee
@@ -1,11 +1,11 @@
 ###
 @name jquery-badyl
 @description Meet Badyl – bootstrap affix-like wheel reinvent.
-@version 1.7.42
+@version 1.7.53
 @author Se7enSky studio <info@se7ensky.com>
 ###

-###! jquery-badyl 1.7.42 http://github.com/Se7enSky/jquery-badyl###
+###! jquery-badyl 1.7.53 http://github.com/Se7enSky/jquery-badyl###

 plugin = ($) ->

@@ -34,7 +34,9 @@
 			@state = null
 			@badylized = no
 			@$refEl = $(@$el.attr "data-badyl-ref-el")
+			@$originalParent = @$el.parent()
 			@prevWindowScrollTop = 0
+			@smartResizeTimeout = null
 			@badylize()

 			# (window.badyls or= []).push @
@@ -44,13 +46,12 @@

 		badylize: ->
 			return if @badylized
-			@originalWidth = @$el.width()
+			@containerInnerWidth = @measureInnerWidth @$originalParent
 			@originalHeight = @$el.height()

 			@badylInnerHeight = @originalHeight + @config.offset * 2

-			windowHeight = $(window).height()
-			return if @originalHeight is 0
+			# return if @originalHeight is 0

 			@badylHeight = @$refEl.height() + @config.offset * 2

@@ -61,7 +62,7 @@
 					margin: "-#{@config.offset}px 0"
 				.append @$badylInner = $("""<div>""")
 					.css
-						width: "#{@originalWidth}px"
+						width: "#{@containerInnerWidth}px"
 						height: "#{@badylInnerHeight}px"
 						padding: "#{@config.offset}px 0"
 					.append @$originalElement = @$el.clone()
@@ -76,29 +77,56 @@

 			@badylized = yes

+			@$originalElement.trigger "badylized"
+
 		rebadylize: ->
+			return unless @badylized
+			clearTimeout @smartResizeTimeout if @smartResizeTimeout
+
+			@containerInnerWidth = @measureInnerWidth @$originalParent
+			# return if @originalHeight is 0
 			@rebadylizeFromState = @state
-			@debadylize()
-			@badylize()
+			@badylized = no
+			@state = null
+
+			@badylHeight = @$refEl.height() + @config.offset * 2
+
+			@$badylContainer.css
+				position: 'relative'
+				height: "#{@badylHeight}px"
+				margin: "-#{@config.offset}px 0"
+			@$badylInner.css
+				width: "#{@containerInnerWidth}px"
+				padding: "#{@config.offset}px 0"
+			@originalHeight = @$originalElement.height()
+			@badylInnerHeight = @originalHeight + @config.offset * 2
+			@$badylInner.css
+				height: "#{@badylInnerHeight}px"
+			@badylOffsetTop = @$badylContainer.offset().top
+			@refreshInnerCss()
+			@badylized = yes
+
+			@$originalElement.trigger "rebadylized"

 		debadylize: ->
 			return unless @badylized
+			clearTimeout @smartResizeTimeout if @smartResizeTimeout
 			@unbindEvents()
 			@$badylContainer.replaceWith @$el = @$originalElement
 			@$el.data "badyl", @
 			@badylized = no
 			@state = null
+			@$el.trigger "debadylized"

 		bindEvents: ->
 			$(window).on "scroll", @windowScrollHandler = (e) =>
 				@refreshInnerCss()

-			smartResizeTimeout = null
 			$(window).on "resize", @windowResizeHandler = (e) =>
-				clearTimeout smartResizeTimeout if smartResizeTimeout
-				smartResizeTimeout = setTimeout =>
-					@rebadylize()
-					smartResizeTimeout = null
+				clearTimeout @smartResizeTimeout if @smartResizeTimeout
+				@smartResizeTimeout = setTimeout =>
+					@rebadylize() if @badylized
+					@smartResizeTimeout = null
 				, 100

 		unbindEvents: ->
@@ -169,6 +197,12 @@
 			@$badylInner.css addCss if addCss
 			@state = newState

+		measureInnerWidth: ($el) ->
+			$el.append $measureDiv = $("<div>").css display: "block", width: "100%"
+			result = $measureDiv.width()
+			$measureDiv.remove()
+			result
+
 	$.fn.badyl = (method, args...) ->
 		@each ->
 			badyl = $(@).data 'badyl'


Changed way to handle media ending. Previous version didnt work with Safari

--- js/media/audioplayer/audioplayer.coffee
+++ js/media/audioplayer/audioplayer.coffee
@@ -25,6 +25,8 @@
   play: ->
     if @_mediaElement?
       @_mediaElement.setVolume( 1 )
+      @_mediaElement.setMuted( false )
+      @_mediaElement.addEventListener( 'ended', ( => @_mediaEnded() ), false )
       @_mediaElement.play()
     @_playStopButton.setLabel(@options.stopLabel) if @_playStopButton?
     @_playPauseButton.setLabel(@options.pauseLabel) if @_playPauseButton?
@@ -43,11 +45,7 @@
   skipBack: ->
     @seek()
   idle: ->
-    return unless @playing and @_mediaElement?
-    #Change player state as stopped when media is end
-    if @_mediaElement.ended
-      @stop()
-      @playing = false
+    true
   playStop: ->
     if @playing
       @stop()
@@ -142,6 +140,9 @@
     @_enableAll( @enabled )
   _mediaFailed: ->
     console.log('HAudioPlayer media failure:',arguments)
+  _mediaEnded:->
+    @stop()
+    @playing = false
   die: ->
     @pause()
     ELEM.del(@_audioElementId) if @_audioElementId?


Use originalTime instead of time for screenshots

--- modules/player/commands.coffee
+++ modules/player/commands.coffee
@@ -360,7 +360,7 @@

       try
         Core.util.sendTyping(m.channel)
-        time = if nowPlaying.duration then nowPlaying.time + 2 else 0
+        time = if nowPlaying.duration then nowPlaying.originalTime + 2 else 0
         screenshot = await @util.getScreenshot nowPlaying.videoPath, time
         m.channel.send files: [{
           name: "focabot-#{nowPlaying.uid}-#{time}.jpg"


using append instead of pushes

using append instead of pushes

--- src/md.coffee
+++ src/md.coffee
@@ -435,12 +435,11 @@
                 do after2
             # Block quotes (and similar elements) are relatively straight forward.
             when 'BLOCKQUOTE', 'DD'
-              quoteMd = '> '
               # Special case for Vanilla blockquotes with the "rel" attr
               if @has ele, 'rel', no
                 rel = @attr ele, 'rel', @options.absolute
-                quoteMd = "@#{rel} said:\n" + quoteMd
-              after = @pushLeft quoteMd
+                @append "@#{rel} said:\n"
+              after = @pushLeft '> '
             # Links on the other hand are probably the trickiest.
             when 'A'
               # Extract the link URL from `ele`.


何故かコレを追加しないと広告が出ない

何故かコレを追加しないと広告が出ない

--- app/assets/javascripts/components/footer.js.cjsx
+++ app/assets/javascripts/components/footer.js.cjsx
@@ -24,6 +24,7 @@
           mobile={@props.mobile}
         /> if @state.renderAds
       }
+
<ResponsiveAdsense client='a' slot='b' />


Add offset to marker tooltip

Add offset to marker tooltip

--- app/assets/javascripts/me-add-to-playlist.coffee
+++ app/assets/javascripts/me-add-to-playlist.coffee
@@ -105,6 +105,7 @@

")
               $('#heading0').after(new_marker_section)
             offset = response.marker.start_time/1000
+            offset_str = mejs.Utility.secondsToTimeCode(offset)
             new_marker = $("

                 <form accept-charset='UTF-8' action='/avalon_marker/"+response.id+"' class='edit_avalon_marker' data-remote='true' id='edit_avalon_marker_"+response.id+"' method='post'>

@@ -115,7 +116,7 @@
                     "+response.marker.title+"

-                    "+mejs.Utility.secondsToTimeCode(offset)+"
+                    "+offset_str+"

                     <button class='btn btn-default btn-xs edit_marker' id='edit_marker_"+response.id+"' name='edit_marker' type='button'>
@@ -135,7 +136,8 @@
             else
               $('#markers').append(new_marker)
             offset_percent = Math.round(if isNaN(parseFloat(offset)) then 0 else (100*offset / currentPlayer.media.duration))
-            $('.mejs-time-rail').append('')
+            marker_title = String(response.marker.title).replace(/"/g, '"')+' ['+offset_str+']'
+            $('.mejs-time-rail').append('')
             new_marker.find('button.edit_marker').click(enableMarkerEditForm);
             new_marker.find('.edit_avalon_marker').on('ajax:success', handle_edit_save).on 'ajax:error', (e, xhr, status, error) ->
               alert 'Request failed.'


Add complete event callback to the polling service

--- app/assets/javascripts/polling_service.js.coffee
+++ app/assets/javascripts/polling_service.js.coffee
@@ -5,6 +5,8 @@

   updateElement= (element) ->
     $element = $(element)
+    return if $element.data('polling_is_updating') == true
+    $element.data( 'polling_is_updating', true );
     url = $element.data('updatePath')
     return unless url

@@ -27,22 +29,26 @@
         else
           # no redirect -> replace content with html from response
           #exists = $.contains(document.documentElement, $element)
-          $element.replaceWith(data)
-
-
-  # update method which is called periodically
-  update= () ->
+          $element.replaceWith(data)
+      error: () ->
+        $element.data( 'polling_is_updating', false );
+      complete: () ->
+        $('body').trigger( 'polling:update_complete' );
+
+
+  # update method which is called periodically
+  update= () ->
     # get current timestamp
     timestamp = Math.round((new Date().getTime())/ 1000)
-
+
     # for each element found by selector do
     $(selector).each () ->
       $element  = $(this)
-
+
       # element's own update interval
       updateInterval = $element.data('updateInterval') || 10
-      updateInterval = updateInterval*1000 if updateInterval < 1000
-
+      updateInterval = updateInterval*1000
+
       # modulo operation: rest of current timestamp divided by element's interval should be zero
       shouldUpdate = (timestamp % Math.round(updateInterval/ interval))==0


version絞込でScoreがないときの動作を修正

version絞込でScoreがないときの動作を修正

--- app/assets/javascripts/stores/score_store.coffee
+++ app/assets/javascripts/stores/score_store.coffee
@@ -19,25 +19,31 @@
     remain = 0
     for id, _ of SheetStore.get()
       score = scores[id]
-      score ||=
-        state: 7
       remain++ if threshold < score.state
     remain

 setScore = (score) ->
   sheetId = score.sheet_id
   delete score.sheet_id
-  scores[sheetId] ||= {}
   score.color = Env.color[score.state]
   score.display = ''
   score.sheetId = sheetId
   scores[sheetId] = score
+
+initScore = ->
+  for sheetId, _ of SheetStore.get()
+    scores[sheetId] ||=
+      state: 7
+      display: ''
+      sheetId: sheetId
+      color: Env.color[7]

 ScoreStore.dispatchToken = AbilitysheetDispatcher.register (payload) ->
   action = payload.action
   switch action
     when AbilitysheetConstants.RECEIVED_SCORE_DATA
       scores = {}
+      initScore()
       setScore score for score in payload.scores
       ScoreStore.emitChange()
     when AbilitysheetConstants.UPDATED_SCORE_DATA
@@ -46,24 +52,20 @@
     when AbilitysheetConstants.SHOW_SCORE_DATA
       for id, score of scores
         continue unless score.state is payload.state
-        scores[id] ||= {}
         scores[id].display = ''
       ScoreStore.emitChange()
     when AbilitysheetConstants.HIDE_SCORE_DATA
       for id, score of scores
         continue unless score.state is payload.state
-        scores[id] ||= {}
         scores[id].display = 'none'
       ScoreStore.emitChange()
     when AbilitysheetConstants.SHOW_SHEET_DATA
       for id, sheet of SheetStore.get()
         continue unless sheet.version is payload.version
-        scores[id] ||= {}
         scores[id].display = ''
       ScoreStore.emitChange()
     when AbilitysheetConstants.HIDE_SHEET_DATA
       for id, sheet of SheetStore.get()
         continue unless sheet.version is payload.version
-        scores[id] ||= {}
         scores[id].display = 'none'
       ScoreStore.emitChange()


Fixing scroll offset and last known window position.

--- app/assets/javascripts/views/portfolio.js.coffee
+++ app/assets/javascripts/views/portfolio.js.coffee
@@ -13,6 +13,7 @@
         initialize: ->
             templates = @collection.templates.get('templates')
             @constructor.template = templates['portfolios-index'].template
+            @isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test navigator.userAgent

         render: ->
             @$el.html @constructor.template portfolios: @collection.toJSON()
@@ -50,7 +51,8 @@
             found = false
             last = jQuery.extend {}, $outer_parent
             $prev_items = jQuery '.portfolio-wrapper .item-full'
-            lastWindowPosition = @winYPos()
+            @lastWindowPosition = @winYPos()
+            scrollOffset = if @isMobile then 20 else 345

             # Find the next item that has a different y pos
             # The max length is 3 so no need for more than that
@@ -78,15 +80,15 @@
             $image_div = $new_items.find '.item-more div.images'
             $restOfImages = $image_div.find 'img:not(:first-child)'
             $restOfImages.hide()
-            $new_items.slideDown 500, -> $restOfImages.show()
+            $new_items.slideDown 1000, -> $restOfImages.show()

             # Init the slideshow
-            $image_div.slideshow scrollToOffset: 375
+            $image_div.slideshow scrollToOffset: scrollOffset

             # Scrolling won't happen from plugin unless there are images, so do manually
             if 0 is $image_div.length
                 setTimeout ->
-                    $new_items.smoothScroll 375
+                    $new_items.smoothScroll scrollOffset
                 , 300

             # Add arrow


upd nofile_builder

upd nofile_builder

--- kit/nofile_builder.coffee
+++ kit/nofile_builder.coffee
@@ -5,7 +5,7 @@
     kit: { _, log, remove, spawn, Promise }
 } = nobone

-class Builder
+class NofileBuilder
     constructor: (options) ->
         defaults =
             dirname: __dirname
@@ -33,7 +33,8 @@

                 'server': [
                     'Run dev server.',
-                    (opts) ->
+                    (opts) =>
+                        self = @
                         { service, renderer } = nobone()

                         run = ->
@@ -42,9 +43,9 @@
                                 log '>> Server start at port: '.cyan + opts.port

                         if opts.rebuild
-                            @_build(opts)
+                            @_build()
                             .then ->
-                                @_build_doc opts
+                                self._build_doc()
                             .then ->
                                 run()
                         else
@@ -53,9 +54,9 @@

                 'test': [
                     'Run test runner.',
-                    (opts) ->
+                    (opts) =>
                         if opts.cli
-                            @_build(opts)
+                            @_build()
                             .then ->
                                 spawn 'karma', ['start', 'karma.conf.js'].concat([
                                     '--single-run',
@@ -90,9 +91,9 @@
                 args.unshift(name)
                 handler.apply(null, args)

-    _build: (options) =>
+    _build: =>
         Builder = kit.require './kit/builder', @opts.dirname
-        builder = new Builder(options)
+        builder = new Builder()
         builder.start()

     _build_doc: =>
@@ -144,4 +145,4 @@
                         kit.symlink '../' + p, to
             ]

-module.exports = Builder
+module.exports = NofileBuilder


Change editorconfig key bindings to ctrl-cmd-*


code review

code review

--- BackofficeBundle/Resources/public/coffee/mediatheque/SuperboxView.coffee
+++ BackofficeBundle/Resources/public/coffee/mediatheque/SuperboxView.coffee
@@ -6,7 +6,7 @@

   events:
     'change select#media_crop_format': 'changeView'
-    'click a#crop_action_button': 'setUpCrop'
+    'click a#crop_action_button': 'setupCrop'
     'click a#upload_action_button': 'setupOverrideForm'
     'click a#crop_button': 'cropImage'

@@ -29,7 +29,7 @@
     @setupMetaForm()
     displayLoader('#alternative-loader')

-  setUpCrop: ->
+  setupCrop: ->
     superboxViewParam['jcrop_api'].destroy() if superboxViewParam['jcrop_api'] != undefined

     $(".media-override-format-form").hide()


fixed test

fixed test

--- test/DANCE_test.coffee
+++ test/DANCE_test.coffee
@@ -10,7 +10,7 @@
       respond: sinon.spy()
       hear: sinon.spy()

-    require('../src/DANCE')(@robot)
+    require('../src/dance.coffee')(@robot)

   it 'registers a hear listener', ->
     expect(@robot.hear).to.have.been.calledWith(/dance/)


Added functionality for default values to model

--- model.coffee
+++ model.coffee
@@ -2,8 +2,19 @@

 class Model extends Spine.Model

+	@defaults: (atts) ->
+		@defaultValues = atts
+
 	@configure: (name, attributes...) ->
 		attributes = attributes.concat(['created_at', 'updated_at'])
 		super name, attributes...
+
+	@create: (atts, options) ->
+
+		# Set default values
+		for attribute in @attributes
+			unless attribute in atts
+				atts[attribute] = @defaultValues[attribute] if @defaultValues[attribute]
+		super

 module.exports = Model


Optimize release task (don't deploy rollbar sourcemaps twice)

--- gulp/tasks/release.coffee
+++ gulp/tasks/release.coffee
@@ -15,7 +15,7 @@
                   cb

-releaseTasks = ["deploy:rollbar-sourcemaps", "release:android", "release:ios"]
+releaseTasks = ["deploy:rollbar-sourcemaps:enable", "release:android", "release:ios"]
   .filter (taskName) -> !!gulp.tasks[taskName]

 if releaseTasks.length > 0


tests for #1591: splatted expressions in destructuring assignment must be assignable

--- test/assignment.coffee
+++ test/assignment.coffee
@@ -301,3 +301,8 @@

   if a then a ?= 2 else a = 3
   eq a, nonce
+
+test "#1591, #1101: splatted expressions in destructuring assignment must be assignable", ->
+  nonce = {}
+  for nonref in ['', '""', '0', 'f()', '(->)'].concat CoffeeScript.RESERVED
+    eq nonce, (try CoffeeScript.compile "[#{nonref}...] = v" catch e then nonce)


validate defaults

validate defaults

--- test/basic.test.coffee
+++ test/basic.test.coffee
@@ -1,5 +1,9 @@
 gulp = require('gulp')
 path = require('path')
+rename = require('gulp-rename')
+fs = require('fs')
+es = require('event-stream')
+assert = require('chai').assert

 suite('basic', () ->
   umd = null
@@ -8,17 +12,31 @@
     umd = require('../src/umd')
   )

-  test('templateName', (cb) ->
-    gulp
-    .src(path.join(__dirname, 'fixtures/fixture-content.js'))
-    .pipe(umd({
-      require: {
-        argA: 'lib-a'
-        argB: 'lib-b'
-        argC: { name: 'lib-c', amd: 'lib-c2' }
-      }
-    }))
-    .pipe(gulp.dest(path.join(__dirname, 'output')))
-    .on('end', cb)
-  )
+  validate = (name, options) ->
+    test(name, (cb) ->
+      gulp
+      .src(path.join(__dirname, 'fixtures/fixture-content.js'))
+      .pipe(rename((path) =>
+        path.basename = name
+      ))
+      .pipe(umd(options))
+      .pipe(gulp.dest(path.join(__dirname, 'found')))
+      .pipe(es.map((file, cb) ->
+        fs.readFile(path.join(__dirname, 'expected', file.basename), 'utf8', (err, data) ->
+          if err?
+            return cb(err)
+
+          assert.equal(
+            file.contents.toString().replace(/\r\n|\r/g, '\n')
+            data.toString().replace(/\r\n|\r/g, '\n')
+            'Did not produce the expected output'
+          )
+
+          cb(null, file)
+        )
+      ))
+      .on('end', cb)
+    )
+
+  validate('defaults')
 )


Removing some duplication

Removing some duplication

--- lib/elixir-autocomplete-provider.coffee
+++ lib/elixir-autocomplete-provider.coffee
@@ -91,31 +91,24 @@

     return "" if serverSuggestion.match(/^[\s\d]/)

-    switch kind
-      when 'attribute'
-        createSuggestionForAttribute(name, prefix)
-      when 'var'
-        createSuggestionForVariable(name)
-      when 'private_function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore, captureBefore)
-      when 'public_function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore, captureBefore)
-      when 'function'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore, captureBefore)
-      when 'public_macro'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore, captureBefore)
-      when 'macro'
-        createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore, captureBefore)
-      when 'module'
-        createSuggestionForModule(serverSuggestion, name, desc, prefix, subtype)
-      else
-        console.log("Unknown kind: #{serverSuggestion}")
-        {
-          text: serverSuggestion
-          type: 'exception'
-          iconHTML: '?'
-          rightLabel: kind || 'hint'
-        }
+    if kind == 'attribute'
+      createSuggestionForAttribute(name, prefix)
+    else if kind == 'var'
+      createSuggestionForVariable(name)
+    else if kind == 'module'
+      createSuggestionForModule(serverSuggestion, name, desc, prefix, subtype)
+    else if kind in ['private_function', 'public_function', 'public_macro']
+      createSuggestionForFunction(serverSuggestion, name, kind, signature, "", desc, spec, prefix, pipeBefore, captureBefore)
+    else if kind in ['function', 'macro']
+      createSuggestionForFunction(serverSuggestion, name, kind, signature, mod, desc, spec, prefix, pipeBefore, captureBefore)
+    else
+      console.log("Unknown kind: #{serverSuggestion}")
+      {
+        text: serverSuggestion
+        type: 'exception'
+        iconHTML: '?'
+        rightLabel: kind || 'hint'
+      }

   createSuggestionForAttribute = (name, prefix) ->
     if prefix.match(/^@/)


Send previously chosen solutions to score and resolve callbacks of contest

--- lib/Thenable.coffee
+++ lib/Thenable.coffee
@@ -95,10 +95,10 @@

     unless typeof resolve is 'function'
       # Auto-break unless until callback is provided
-      resolve = (chosen) -> true
+      resolve = (c, chosenSolutions) -> true

     unless typeof score is 'function'
-      score = (fulfills) -> fulfills[0]
+      score = (c, fulfills, chosenSolutions) -> fulfills[0]

     callback = (choice, data) ->
       composite = choice.continue name
@@ -115,9 +115,9 @@
                 path: path
                 choice: option.choice
                 value: option.value
-          chosen = score subChoice, fulfills
+          chosen = score subChoice, fulfills, chosenSolutions
           chosenSolutions.push chosen
-          accepted = resolve subChoice, chosen
+          accepted = resolve subChoice, chosenSolutions
           return Collection tasks, composite, subChoice, data, onResult unless accepted
           composite.deliver chosenSolutions.map (c) -> c.value
           return


refactor

refactor

--- lib/antispam.coffee
+++ lib/antispam.coffee
@@ -1,5 +1,23 @@

 # -- Private --------------------------------------------
+
+
+existDOTbeforeAT = (string) ->
+  at_position = string.indexOf('AT')
+  dot_position = string.indexOf('DOT')
+  dot_position < at_position
+
+replaceDOT = (string) ->
+  string.replace('DOT', '.')
+
+replaceAT = (string) ->
+  string.replace('AT', '@')
+
+contains = (string, delimiter) ->
+  string.indexOf(delimiter) > 0
+
+
+

 # -- Public --------------------------------------------
@@ -7,23 +25,18 @@

   @parser: (string) ->

-    if (string.indexOf('AT') > 0 and string.indexOf('.') > 0)
-      result = string.replace('AT', '@')
-      return result
+    if (contains(string,'AT') and contains(string,'.'))
+      return replaceAT(string)

-    if (string.indexOf('AT') > 0 and string.indexOf('DOT') > 0)
-      at_position = string.indexOf('AT')
-      dot_position = string.indexOf('DOT')
-
-      if dot_position < at_position
+    if (contains(string,'AT') and contains(string,'DOT'))
+      if existDOTbeforeAT(string)
         return string
-
       else
-        result = string.replace('AT', '@').replace('DOT', '.')
+        result = replaceAT(string)
+        result = replaceDOT(result)
         return result

-    else
-      string
+    string


TOUCH IT #3

TOUCH IT #3

--- lib/app-list.coffee
+++ lib/app-list.coffee
@@ -44,6 +44,7 @@
       onThreeTouch: @touch

   touch: (e) =>
+    console.log "TOUCH"
     @dom.css 'right',"#{event.diff.right}px"


Fixed issue where hours were not being properly rebuilt into a command

--- src/scripts/hound.coffee
+++ src/scripts/hound.coffee
@@ -149,11 +149,12 @@
       else if scope isnt 'self' and scope isnt 'org'
         if not isNaN(comps[0]) and
            (comps[1] is 'hour' or comps[1] is 'hours')
-          comps = [comps.join(' ')]
+          comps = ['self', comps.join(' ')]
         else if comps.length > 2
           comps = ['self', comps.slice(1).join(' ')]
         else
           comps = ['self', comps[0]]
+        scope = comps[0]
       action = comps[1] || 'info'
       console.log scope
       console.log action


add tests for creation of document

add tests for creation of document

--- test/data_tests.coffee
+++ test/data_tests.coffee
@@ -13,10 +13,15 @@
 db = connection.database('cozy')

+# TEST SECTION #################################################################

 before (done) ->
     # Prepare database for tests
-    db.save '321', {"value":"val"} # insert id 321 : Existence
+    db.destroy ->
+        console.log 'DB destroyed'
+        db.create ->
+            console.log 'DB recreated'
+            db.save '321', {"value":"val"} # insert id 321 : Existence

     # start app
     app.listen(8888)
@@ -29,8 +34,12 @@

 describe "Existence", ->
-    describe "Check Existence of a Note that does not exist in database", ->
-        it "When I send a request to check existence of Note with id 123", \
+    describe "Check Existence of a Document that does not exist in database", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to check existence of Document with id 123", \
                 (done) ->
             client.get "data/exist/123/", (error, response, body) =>
                 response.should.be.json
@@ -42,8 +51,12 @@
             should.exist @body.exist
             @body.exist.should.not.be.ok

-    describe "Check Existence of a Note that does exist in database", ->
-        it "When I send a request to check existence of Note with id 321", \
+    describe "Check Existence of a Document that does exist in database", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to check existence of Document with id 321", \
                 (done) ->
             client.get "data/exist/321/", (error, response, body) =>
                 response.should.be.json
@@ -58,8 +71,12 @@

 describe "Find", ->
-    describe "Find a Note that does not exist in database", ->
-        it "When I send a request to get Note with id 123", (done) ->
+    describe "Find a Document that does not exist in database", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to get Document with id 123", (done) ->
             client.get "data/123/", (error, response, body) =>
                 @response = response
                 done()
@@ -67,8 +84,12 @@
         it "Then error 404 should be returned", ->
             @response.statusCode.should.equal(404)

-    describe "Find a Note that does exist in database", ->
-        it "When I send a request to get Note with id 321", (done) ->
+    describe "Find a Document that does exist in database", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to get Document with id 321", (done) ->
             client.get 'data/321/', (error, response, body) =>
                 response.should.be.json
                 response.statusCode.should.equal(200)
@@ -77,3 +98,49 @@

         it "Then { _id: '321', value: 'val'} should be returned", ->
             @body.should.deep.equal {"_id": '321', "value":"val"}
+
+
+
+describe "Create", ->
+    describe "Try to Create a Document with id 321", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to create a document with id 321", (done) ->
+            client.post 'data/321/', {"value":"created value"}, (error, response, body) =>
+                @response = response
+                done()
+
+        it "Then error 409 should be returned", ->
+            @response.statusCode.should.equal(409)
+
+    describe "Create a Document with id 987", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to create a document with id 987", (done) ->
+            client.post 'data/987/', {"value":"created value"}, (error, response, body) =>
+                response.should.be.json
+                response.statusCode.should.equal(201)
+                @body = JSON.parse body
+                done()
+
+        it "Then { _id: '987' } should be returned", ->
+            @body.should.have.property '_id', '987'
+
+    describe "Create a Document without an id", ->
+        before ->
+            delete @body
+            delete @response
+
+        it "When I send a request to create a document without an id", (done) ->
+            client.post 'data/', {"value":"created value"}, (error, response, body) =>
+                response.should.be.json
+                response.statusCode.should.equal(201)
+                @body = JSON.parse body
+                done()
+
+        it "Then the id of the new document should be returned", ->
+            @body.should.have.property '_id'