fixed coffeelint errors on workers/social/lib/social/models/account.coffee

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -1,8 +1,9 @@
+# coffeelint: disable=no_implicit_braces
 jraphical   = require 'jraphical'
 KodingError = require '../error'
 ApiError    = require './socialapi/error'

-{argv}      = require 'optimist'
+{ argv }    = require 'optimist'
 KONFIG      = require('koding-config-manager').load("main.#{argv.c}")

 module.exports = class JAccount extends jraphical.Module
@@ -23,12 +24,12 @@
   @getFlagRole            = 'content'
   @lastUserCountFetchTime = 0

-  {ObjectId, Register, secure, race, dash, daisy, signature} = require 'bongo'
-  {Relationship} = jraphical
-  {permit} = require './group/permissionset'
+  { ObjectId, Register, secure, race, dash, daisy, signature } = require 'bongo'
+  { Relationship } = jraphical
+  { permit } = require './group/permissionset'
   Validators = require './group/validators'
   Protected = require '../traits/protected'
-  {extend} = require 'underscore'
+  { extend } = require 'underscore'

   validateFullName = (value) -> not /<|>/.test value

@@ -55,7 +56,7 @@
         # { name: 'updateInstance' }
         { name : 'messageBusEvent' }
         { name : 'RemovedFromCollection' }
-        { name : 'NewWorkspaceCreated'}
+        { name : 'NewWorkspaceCreated' }
       ]
     sharedMethods :
       static:
@@ -219,7 +220,7 @@
       environmentIsCreated  : Boolean
       type                  :
         type                : String
-        enum                : ['invalid account type',[
+        enum                : ['invalid account type', [
                                 'registered'
                                 'unregistered'
                                 'deleted'
@@ -230,7 +231,7 @@
         nickname            :
           type              : String
           validate          : require('./name').validateName
-          set               : (value)-> value.toLowerCase()
+          set               : (value) -> value.toLowerCase()
         hash                : String
         ircNickname         : String
         firstName           :
@@ -260,7 +261,7 @@
       meta                  : require 'bongo/bundles/meta'
       onlineStatus          :
         type                : String
-        enum                : ['invalid status',['online','offline','away','busy']]
+        enum                : ['invalid status', ['online', 'offline', 'away', 'busy']]
         default             : 'online'
     broadcastableRelationships : [ 'follower' ]

@@ -271,101 +272,103 @@
       # targetType from string to object.
       JStackTemplate   = require './computeproviders/stacktemplate'

-      appStorage    :
-        as          : 'appStorage'
-        targetType  : "JAppStorage"
-
-      storage       :
-        as          : 'storage'
-        targetType  : 'JStorage'
-
-      tag:
-        as          : 'skill'
-        targetType  : "JTag"
-
-      domain        :
-        as          : 'owner'
-        targetType  : 'JProposedDomain'
-
-      proxyFilter   :
-        as          : 'owner'
-        targetType  : 'JProxyFilter'
-
-      referrer      :
-        targetType  : 'JReferral'
-        as          : 'referrer'
-      referred      :
-        targetType  : 'JReferral'
-        as          : 'referred'
-      invitation    :
-        as          : 'owner'
-        targetType  : 'JInvitation'
-
-      paymentMethod :
-        as          : 'payment method'
-        targetType  : 'JPaymentMethod'
-
-      subscription  :
-        as          : 'service subscription'
-        targetType  : 'JPaymentSubscription'
-
-      kite          :
-        as          : 'owner'
-        targetType  : JKite
-
-      credential    :
-        as          : ['owner', 'user']
-        targetType  : 'JCredential'
-
-      stackTemplate :
-        as          : 'user'
-        targetType  : JStackTemplate
-
-
-  constructor:->
+      return {
+        appStorage    :
+          as          : 'appStorage'
+          targetType  : 'JAppStorage'
+
+        storage       :
+          as          : 'storage'
+          targetType  : 'JStorage'
+
+        tag:
+          as          : 'skill'
+          targetType  : 'JTag'
+
+        domain        :
+          as          : 'owner'
+          targetType  : 'JProposedDomain'
+
+        proxyFilter   :
+          as          : 'owner'
+          targetType  : 'JProxyFilter'
+
+        referrer      :
+          targetType  : 'JReferral'
+          as          : 'referrer'
+        referred      :
+          targetType  : 'JReferral'
+          as          : 'referred'
+        invitation    :
+          as          : 'owner'
+          targetType  : 'JInvitation'
+
+        paymentMethod :
+          as          : 'payment method'
+          targetType  : 'JPaymentMethod'
+
+        subscription  :
+          as          : 'service subscription'
+          targetType  : 'JPaymentSubscription'
+
+        kite          :
+          as          : 'owner'
+          targetType  : JKite
+
+        credential    :
+          as          : ['owner', 'user']
+          targetType  : 'JCredential'
+
+        stackTemplate :
+          as          : 'user'
+          targetType  : JStackTemplate
+      }
+
+
+  constructor: ->
     super
     @notifyOriginWhen 'PrivateMessageSent', 'FollowHappened'
     @notifyGroupWhen 'FollowHappened'

-  @sendUpdateInstanceEvent = (obj, op) =>
-    JAccount.bongos.forEach (bongo) =>
-      bongo.handleEvent "instance", obj, "updateInstance", [op]
+  @sendUpdateInstanceEvent = (obj, op) ->
+    JAccount.bongos.forEach (bongo) ->
+      bongo.handleEvent 'instance', obj, 'updateInstance', [op]

   canEditPost: permit 'edit posts'

   canDeletePost: permit 'delete posts'

-  createSocialApiId:(callback)->
+  createSocialApiId:(callback) ->
     if @type is 'unregistered'
       return callback null, -1

     return callback null, @socialApiId  if @socialApiId
-    {createAccount} = require './socialapi/requests'
-    createAccount {id: @getId(), nickname: @profile.nickname}, (err, account)=>
+    { createAccount } = require './socialapi/requests'
+    createAccount { id: @getId(), nickname: @profile.nickname }, (err, account) =>
       return callback new ApiError err  if err
-      return callback {message: "Account is not set, malformed response from social api"} unless account?.id
-      @update $set: socialApiId: account.id, isExempt: account.isTroll, (err)->
+      return callback new KodingError 'Account is not set, malformed response from social api'  unless account?.id
+      @update $set: socialApiId: account.id, isExempt: account.isTroll, (err) ->
         # check for error
         if err
-          console.error "Error while creating account on social api", err
-          return callback { message: "Couldnt create/register Account"}
+          console.error 'Error while creating account on social api', err
+          return callback new KodingError 'Couldnt create/register Account'
         # check account
         # return account id from social api
         return callback null, account.id

-  checkGroupMembership: secure (client, groupName, callback)->
-    {delegate} = client.connection
-    JGroup = require "./group"
-    JGroup.one {slug : groupName}, (err, group)->
-      return callback new KodingError "An error occurred!" if err
+  checkGroupMembership: secure (client, groupName, callback) ->
+    { delegate } = client.connection
+    JGroup = require './group'
+    JGroup.one { slug : groupName }, (err, group) ->
+      return callback new KodingError 'An error occurred!' if err
       return callback null, no unless group

       Relationship.one {
         as          : 'member'
         targetId    : delegate.getId()
         sourceId    : group.getId()
-      }, (err, relation)=>
-        return callback new KodingError "An error occurred!" if err
+      }, (err, relation) ->
+        return callback new KodingError 'An error occurred!' if err
         return callback null, relation?

   changeUsername: (options, callback = (->)) ->
@@ -387,7 +390,7 @@
         return callback null

       else
-        return callback new KodingError "Username was not changed!"
+        return callback new KodingError 'Username was not changed!'

     # Validate username
     unless @constructor.validateAt 'profile.nickname', username
@@ -441,10 +444,10 @@

             # Free up the old username
             JName.remove name: oldUsername, (err) ->
-              console.warn "[JAccount.changeUsername]", err  if err?
-
-
-  checkPermission: (target, permission, callback)->
+              console.warn '[JAccount.changeUsername]', err  if err?
+
+
+  checkPermission: (target, permission, callback) ->
     JPermissionSet = require './group/permissionset'
     client =
       context     : { group: target.slug }
@@ -457,8 +460,8 @@
   @renderHomepage: require '../render/profile.coffee'

-  fetchHomepageView:(options, callback)->
-    {account} = options
+  fetchHomepageView:(options, callback) ->
+    { account } = options

     homePageOptions = extend options, {
       renderedAccount : account
@@ -468,12 +471,12 @@

     JAccount.renderHomepage homePageOptions, callback

-  fetchGroups: secure (client, options, callback)->
+  fetchGroups: secure (client, options, callback) ->
     [callback, options] = [options, callback]  unless callback
     options       ?= {}
     JGroup        = require './group'
-    {groupBy}     = require 'underscore'
-    {delegate}    = client.connection
+    { groupBy }   = require 'underscore'
+    { delegate }  = client.connection
     isMine        = @equals delegate
     edgeSelector  =
       sourceName  : 'JGroup'
@@ -486,10 +489,10 @@
       sort        : options.sort  or { timestamp: -1 }
       limit       : options.limit or 20
       skip        : options.skip  or 0
-    Relationship.someData edgeSelector, edgeFields, options, (err, cursor)->
+    Relationship.someData edgeSelector, edgeFields, options, (err, cursor) ->
       if err then callback err
       else
-        cursor.toArray (err, docs)->
+        cursor.toArray (err, docs) ->
           if err then callback err
           else unless docs
             callback null, []
@@ -497,40 +500,40 @@
             groupedDocs = groupBy docs, 'sourceId'
             targetSelector = { _id: $in: (doc.sourceId for doc in docs) }
             targetSelector.visibility = 'visible'  unless isMine
-            JGroup.all targetSelector, (err, groups)->
+            JGroup.all targetSelector, (err, groups) ->
               if err then callback err
-              else callback null, groups.map (group)->
+              else callback null, groups.map (group) ->
                 roles = (doc.as for doc in groupedDocs[group.getId()])
                 return { group, roles }

-  @verifyEmailByUsername = secure (client, username, callback)->
-    {connection:{delegate}, sessionToken} = client
+  @verifyEmailByUsername = secure (client, username, callback) ->
+    { connection:{ delegate }, sessionToken } = client
     unless delegate.can 'verify-emails'
       callback new KodingError 'Access denied'
     else
       JUser = require './user'
-      JUser.one {username}, (err, user)->
+      JUser.one { username }, (err, user) ->
         return  callback err if err
-        return  callback new Error "User is not found" unless user
-        user.confirmEmail (err)->
-          return callback new Error "An error occurred while confirming email" if err
+        return  callback new Error 'User is not found' unless user
+        user.confirmEmail (err) ->
+          return callback new Error 'An error occurred while confirming email' if err
           callback null, yes

-  @reserveNames =(options, callback)->
+  @reserveNames = (options, callback) ->
     [callback, options] = [options, callback]  unless callback
     options       ?= {}
     options.limit ?= 100
     options.skip  ?= 0
-    @someData {}, {'profile.nickname':1}, options, (err, cursor)=>
+    @someData {}, { 'profile.nickname':1 }, options, (err, cursor) =>
       if err then callback err
       else
         count = 0
-        cursor.each (err, account)=>
+        cursor.each (err, account) =>
           if err then callback err
           else if account?
-            {nickname} = account.profile
-            JName.claim nickname, 'JUser', 'username', (err, name)=>
+            { nickname } = account.profile
+            JName.claim nickname, 'JUser', 'username', (err, name) =>
               count++
               if err then callback err
               else
@@ -540,7 +543,7 @@
                   @reserveNames options, callback

-  @fetchBlockedUsers = secure ({connection:{delegate}}, options, callback) ->
+  @fetchBlockedUsers = secure ({ connection:{ delegate } }, options, callback) ->
     unless delegate.can 'list-blocked-users'
       return callback new KodingError 'Access denied!'

@@ -562,7 +565,7 @@

         acctSelector = 'profile.nickname': $in: users.map (u) -> u.username

-        JAccount.some acctSelector, {}, (err, accounts)=>
+        JAccount.some acctSelector, {}, (err, accounts) ->
           if err
             callback err
           else
@@ -572,8 +575,8 @@
             callback null, accounts

-  @findSuggestions = (client, seed, options, callback)->
-    {limit, blacklist, skip}  = options
+  @findSuggestions = (client, seed, options, callback) ->
+    { limit, blacklist, skip } = options
     ### TODO:
     It is highly dependent to culture and there are even onces w/o the concept
     of first and last names. For now we assume last part of the seed is the lastname
@@ -584,7 +587,7 @@
     deciding ourselves which parts of the search are for first or last name.
     MongoDB 2.4 and bongo implementation of aggregate required to use $concat
     ###
-    names = seed.toString().split('/')[1].replace(/[\\^]/g, "").split ' '
+    names = seed.toString().split('/')[1].replace(/[\\^]/g, '').split ' '
     names.push names.first if names.length is 1
     @some {
       $or : [
@@ -596,40 +599,40 @@
         $nin  : blacklist
       type    :
         $in   : ['registered', null]
-    },{
+    }, {
       skip
       limit
       sort    : 'profile.firstName' : 1
     }, callback

-  setEmailPreferences: (user, prefs, callback)->
+  setEmailPreferences: (user, prefs, callback) ->
     current = user.getAt('emailFrequency') or {}
-    Object.keys(prefs).forEach (granularity)->
+    Object.keys(prefs).forEach (granularity) ->
       state = prefs[granularity]
       current[granularity] = state# then 'instant' else 'never'

-    updateUserPref =->
-      user.update {$set: emailFrequency: current}, (err)->
+    updateUserPref = ->
+      user.update { $set: { emailFrequency: current } }, (err) ->
         return callback err  if err

     updateUserPref()

-  setEmailPreferences$: secure (client, prefs, callback)->
+  setEmailPreferences$: secure (client, prefs, callback) ->
     JUser = require './user'
-    JUser.fetchUser client, (err, user)=>
+    JUser.fetchUser client, (err, user) =>
       if err
         callback err
       else
         @setEmailPreferences user, prefs, callback

   # Update broken counts for user
-  updateCounts:->
+  updateCounts: ->
     JUser = require './user'
     # ReferredUsers count
     JAccount.count
       referrerUsername : @profile.nickname
-    , (err, count)=>
+    , (err, count) =>
       return if err
       count ?= 0
       @update ($set: 'counts.referredUsers': count), ->
@@ -638,7 +641,7 @@
     JReferrableEmail.count
       username   : @profile.nickname
       invited    : true
-    , (err, count)=>
+    , (err, count) =>
       return if err
       count ?= 0
       @update ($set: 'counts.invitations': count), ->
@@ -647,33 +650,33 @@
     @update ($set: 'counts.lastLoginDate': new Date), ->

     # Twitter follower count
-    JUser.one {username: @profile.nickname}, (err, user) =>
+    JUser.one { username: @profile.nickname }, (err, user) =>
       return if err or not user
       if followerCount = user.foreignAuth?.twitter?.profile?.followers_count
         @update $set: 'counts.twitterFollowers': followerCount, ->

-  dummyAdmins = [ "sinan", "devrim", "gokmen", "fatihacet", "arslan",
-                  "sent-hil", "cihangirsavas", "leeolayvar", "stefanbc",
-                  "szkl", "canthefason", "nitin", "usirin", "kodinglearn" ] # kodinglearn is nitin's impersonation account
-
-
-  isEmailVerified: (callback)->
-    @fetchUser (err, user)->
+  dummyAdmins = [ 'sinan', 'devrim', 'gokmen', 'fatihacet', 'arslan',
+                  'sent-hil', 'cihangirsavas', 'leeolayvar', 'stefanbc',
+                  'szkl', 'canthefason', 'nitin', 'usirin', 'kodinglearn' ] # kodinglearn is nitin's impersonation account
+
+
+  isEmailVerified: (callback) ->
+    @fetchUser (err, user) ->
       return callback err if err
-      callback null, (user.status is "confirmed")
-
-  markUserAsExempt: secure (client, exempt, callback)->
-    {delegate} = client.connection
+      callback null, (user.status is 'confirmed')
+
+  markUserAsExempt: secure (client, exempt, callback) ->
+    { delegate } = client.connection
     return callback new KodingError 'Access denied'  unless delegate.can 'flag', this
     return @markUserAsExemptUnsafe client, exempt, callback

-  markUserAsExemptUnsafe: (client, exempt, callback)->
+  markUserAsExemptUnsafe: (client, exempt, callback) ->
     # mark user as troll in social api
-    @markUserAsExemptInSocialAPI client, exempt, (err, data)=>
+    @markUserAsExemptInSocialAPI client, exempt, (err, data) =>
       return callback new ApiError err  if err
-      op = $set: {isExempt: exempt}
-      @update op, (err, result)=>
+      op = { $set: { isExempt: exempt } }
+      @update op, (err, result) =>
         if err
           console.error 'Could not update user exempt information'
           return callback err
@@ -682,45 +685,45 @@
         JAccount.sendUpdateInstanceEvent this, op
         callback null, result

-  markUserAsExemptInSocialAPI: (client, exempt, callback)->
-    {markAsTroll, unmarkAsTroll} = require './socialapi/requests'
-    @createSocialApiId (err, accountId)->
+  markUserAsExemptInSocialAPI: (client, exempt, callback) ->
+    { markAsTroll, unmarkAsTroll } = require './socialapi/requests'
+    @createSocialApiId (err, accountId) ->
       return callback err  if err
-      return callback {message: "account id is not set"} unless accountId
+      return callback new KodingError 'account id is not set'  unless accountId

       if exempt
-        markAsTroll {accountId}, callback
+        markAsTroll { accountId }, callback
       else
-        unmarkAsTroll {accountId}, callback
-
-
-  updateFlags: secure (client, flags, callback)->
-    {delegate} = client.connection
+        unmarkAsTroll { accountId }, callback
+
+
+  updateFlags: secure (client, flags, callback) ->
+    { delegate } = client.connection
     if delegate.can 'flag', this
-      @update {$set: globalFlags: flags}, callback
+      @update { $set: { globalFlags: flags } }, callback
     else
       callback new KodingError 'Access denied'

-  fetchUserByAccountIdOrNickname:(accountIdOrNickname, callback)->
-
-    kallback= (err, account)->
+  fetchUserByAccountIdOrNickname:(accountIdOrNickname, callback) ->
+
+    kallback = (err, account) ->
       return callback err if err
       JUser = require './user'
-      JUser.one {username: account.profile.nickname}, (err, user)->
-        callback err, {user, account}
-
-
-    JAccount.one { 'profile.nickname' : accountIdOrNickname }, (err, account)->
+      JUser.one { username: account.profile.nickname }, (err, user) ->
+        callback err, { user, account }
+
+
+    JAccount.one { 'profile.nickname' : accountIdOrNickname }, (err, account) ->
       return kallback err, account if account
-      JAccount.one  { _id : accountIdOrNickname }, (err, account)->
+      JAccount.one  { _id : accountIdOrNickname }, (err, account) ->
         return kallback err, account if account
         callback new KodingError 'Account not found'

-  blockUser: secure (client, accountIdOrNickname, durationMillis, callback)->
-    {delegate} = client.connection
+  blockUser: secure (client, accountIdOrNickname, durationMillis, callback) ->
+    { delegate } = client.connection
     if delegate.can('flag', this) and accountIdOrNickname? and durationMillis?
-      @fetchUserByAccountIdOrNickname accountIdOrNickname, (err, {user, account})->
+      @fetchUserByAccountIdOrNickname accountIdOrNickname, (err, { user, account }) ->
         return callback err if err
         blockedDate = new Date(Date.now() + durationMillis)
         account.sendNotification 'UserBlocked', { blockedDate }
@@ -728,10 +731,10 @@
     else
       callback new KodingError 'Access denied'

-  unblockUser: secure (client, accountIdOrNickname, callback)->
-    {delegate} = client.connection
+  unblockUser: secure (client, accountIdOrNickname, callback) ->
+    { delegate } = client.connection
     if delegate.can('flag', this) and accountIdOrNickname?
-      @fetchUserByAccountIdOrNickname accountIdOrNickname, (err, {user})->
+      @fetchUserByAccountIdOrNickname accountIdOrNickname, (err, { user }) ->
         return callback err if err
         user.unblock callback
     else
@@ -748,44 +751,44 @@
             return yes
     return no

-  isDummyAdmin = (nickname)-> !!(nickname in dummyAdmins)
-
-  @getFlagRole =-> 'owner'
+  isDummyAdmin = (nickname) -> !!(nickname in dummyAdmins)
+
+  @getFlagRole = -> 'owner'

   # WARNING! Be sure everything is safe when you change anything in this function
-  can:(action, target)->
+  can:(action, target) ->
     switch action
       when 'delete'
         # Users can delete their stuff but super-admins can delete all of them ಠ_ಠ
         @profile.nickname in dummyAdmins or target?.originId?.equals @getId()
-      when 'flag', 'reset guests', 'reset groups', 'administer names',        \
-           'administer url aliases', 'administer accounts', 'search-by-email',\
-           'migrate-koding-users', 'list-blocked-users', 'verify-emails',     \
+      when 'flag', 'reset guests', 'reset groups', 'administer names',         \
+           'administer url aliases', 'administer accounts', 'search-by-email', \
+           'migrate-koding-users', 'list-blocked-users', 'verify-emails',      \
            'bypass-validations'
         @profile.nickname in dummyAdmins

-  fetchRoles: (group, callback)->
+  fetchRoles: (group, callback) ->
     Relationship.someData {
       targetId: group.getId()
       sourceId: @getId()
-    }, {as:1}, (err, cursor)->
+    }, { as:1 }, (err, cursor) ->
       if err
         callback err
       else
-        cursor.toArray (err, roles)->
+        cursor.toArray (err, roles) ->
           if err
             callback err
           else
-            roles = (roles ? []).map (role)-> role.as
+            roles = (roles ? []).map (role) -> role.as
             roles.push 'guest' unless roles.length
             callback null, roles

-  fetchRole: secure ({connection}, callback)->
+  fetchRole: secure ({ connection }, callback) ->

     if isDummyAdmin connection.delegate.profile.nickname
-      callback null, "super-admin"
+      callback null, 'super-admin'
     else
-      callback null, "regular"
+      callback null, 'regular'

   # temp dummy stuff ends

@@ -811,7 +814,7 @@

     for objKey in objKeys
       if objKey not in allowedFields
-        return callback new KodingError "Modify fields is not valid"
+        return callback new KodingError 'Modify fields is not valid'

     if @equals(client.connection.delegate)
       op = $set: fields
@@ -822,61 +825,61 @@
         SocialAccount.update {
           id            : @socialApiId
           nick          : @profile.nickname
-          settings      : {shareLocation: fields.shareLocation}
+          settings      : { shareLocation: fields.shareLocation }
         }, callback

     else
       callback new KodingError 'Access denied'

-  getFullName:->
-    {firstName, lastName} = @data.profile
+  getFullName: ->
+    { firstName, lastName } = @data.profile
     return "#{firstName} #{lastName}"

-  fetchStorage$: (name, callback)->
+  fetchStorage$: (name, callback) ->

     @fetchStorage { 'data.name' : name }, callback

-  fetchStorages$: (whitelist=[], callback)->
+  fetchStorages$: (whitelist = [], callback) ->

     options = if whitelist.length then { 'data.name' : $in : whitelist } else {}

     @fetchStorages options, callback

-  store: secure (client, {name, content}, callback)->
+  store: secure (client, { name, content }, callback) ->
     unless @equals client.connection.delegate
-      return callback new KodingError "Attempt to access unauthorized storage"
-
-    @_store {name, content}, callback
-
-  unstore: secure (client, name, callback)->
+      return callback new KodingError 'Attempt to access unauthorized storage'
+
+    @_store { name, content }, callback
+
+  unstore: secure (client, name, callback) ->

     unless @equals client.connection.delegate
-      return callback new KodingError "Attempt to remove unauthorized storage"
-
-    @fetchStorage { 'data.name' : name }, (err, storage)=>
+      return callback new KodingError 'Attempt to remove unauthorized storage'
+
+    @fetchStorage { 'data.name' : name }, (err, storage) ->
       console.error err, storage  if err
       return callback err  if err
       unless storage
-        return callback new KodingError "No such storage"
+        return callback new KodingError 'No such storage'

       storage.remove callback

-  unstoreAll: (callback)->
-    @fetchStorages [], (err, storages)->
+  unstoreAll: (callback) ->
+    @fetchStorages [], (err, storages) ->
       daisy queue = storages.map (storage) ->
         -> storage.remove -> queue.next()
       queue.push -> callback null

-  _store: ({name, content}, callback)->
-    @fetchStorage { 'data.name' : name }, (err, storage)=>
+  _store: ({ name, content }, callback) ->
+    @fetchStorage { 'data.name' : name }, (err, storage) =>
       if err
-        return callback new KodingError "Attempt to access storage failed"
+        return callback new KodingError 'Attempt to access storage failed'
       else if storage
-        storage.update $set: {content}, (err) -> callback err, storage
+        storage.update { $set: { content } }, (err) -> callback err, storage
       else
-        storage = new JStorage {name, content}
-        storage.save (err)=>
+        storage = new JStorage { name, content }
+        storage.save (err) =>
           return callback err  if err
           rel = new Relationship
             targetId    : storage.getId()
@@ -884,16 +887,16 @@
             sourceId    : @getId()
             sourceName  : 'JAccount'
             as          : 'storage'
-            data        : {name}
-          rel.save (err)-> callback err, storage
+            data        : { name }
+          rel.save (err) -> callback err, storage

   fetchOrCreateAppStorage: (options, callback) ->
-    {appId, version} = options
-    @fetchAppStorage {'data.appId':appId, 'data.version':version}, (err, storage)=>
+    { appId, version } = options
+    @fetchAppStorage { 'data.appId':appId, 'data.version':version }, (err, storage) =>
       if err then callback err
       else unless storage?
         # log.info 'Creating new storage:', appId, version, @profile.nickname
-        newStorage = new JAppStorage {appId, version}
+        newStorage = new JAppStorage { appId, version }
         newStorage.save (err) =>
           if err then callback err
           else
@@ -905,91 +908,91 @@
               sourceId    : @getId()
               sourceName  : 'JAccount'
               as          : 'appStorage'
-              data        : {appId, version}
-            rel.save (err)-> callback err, newStorage
+              data        : { appId, version }
+            rel.save (err) -> callback err, newStorage
       else
         callback err, storage

   fetchAppStorage$: secure (client, options, callback) ->

     unless client?.connection?.delegate
-      return callback "Not a valid session"
+      return callback 'Not a valid session'

     unless @equals client.connection.delegate
-      return callback "Attempt to access unauthorized application storage"
+      return callback 'Attempt to access unauthorized application storage'

     @fetchOrCreateAppStorage options, callback

-  fetchUser:(callback)->
+  fetchUser:(callback) ->
     JUser = require './user'
     if /^guest-/.test @profile.nickname
       user = new JUser()
       user.username = @profile.nickname
       return callback null, user

-    JUser.one {username: @profile.nickname}, callback
+    JUser.one { username: @profile.nickname }, callback

   sendNotification: (event, contents) ->
     @createSocialApiId (err, socialApiId) =>
-      return console.error "Could not send notification to account:", err  if err
+      return console.error 'Could not send notification to account:', err  if err

       message = {
-        account: {id: socialApiId, nick: @profile.nickname}
-        eventName: "social"
+        account: { id: socialApiId, nick: @profile.nickname }
+        eventName: 'social'
         body:
           contents : contents
           event    : event
-          context  : contents?.group or "koding"
+          context  : contents?.group or 'koding'
       }

-      @emit 'messageBusEvent', {type: "dispatcher_notify_user", message: message}
-
-
-  cancelRequest: secure (client, slug, callback)->
+      @emit 'messageBusEvent', { type: 'dispatcher_notify_user', message: message }
+
+
+  cancelRequest: secure (client, slug, callback) ->
     options = targetOptions: selector: status: 'pending'
     JGroup = require './group'

     JGroup.one { slug }, (err, group) ->
       return callback err  if err

-      @fetchInvitationRequests {sourceId: group.getId()}, options, (err, [request])->
+      @fetchInvitationRequests { sourceId: group.getId() }, options, (err, [request]) ->
         return callback err                                  if err
         return callback 'could not find invitation request'  unless request
         request.remove callback

-  fetchInvitationByGroupSlug:(slug, callback)->
-    options = targetOptions: selector: {status: 'sent', group: slug}
-    @fetchInvitations {}, options, (err, [invite])->
+  fetchInvitationByGroupSlug:(slug, callback) ->
+    options = targetOptions: selector: { status: 'sent', group: slug }
+    @fetchInvitations {}, options, (err, [invite]) ->
       return callback err                          if err
       return callback 'could not find invitation'  unless invite

       JGroup = require './group'
-      JGroup.one { slug }, (err, groupObj)->
+      JGroup.one { slug }, (err, groupObj) ->
         return callback err  if err
         callback null, { invite, group: groupObj }

-  acceptInvitation: secure (client, slug, callback)->
-    @fetchInvitationByGroupSlug slug, (err, { invite, group })=>
+  acceptInvitation: secure (client, slug, callback) ->
+    @fetchInvitationByGroupSlug slug, (err, { invite, group }) =>
       return callback err  if err
-      groupObj.approveMember this, (err)->
+      groupObj.approveMember this, (err) ->
         return callback err  if err
         invite.update $set:status:'accepted', callback

-  ignoreInvitation: secure (client, slug, callback)->
-    @fetchInvitationByGroupSlug slug, (err, { invite })->
+  ignoreInvitation: secure (client, slug, callback) ->
+    @fetchInvitationByGroupSlug slug, (err, { invite }) ->
       return callback err  if err
       invite.update $set:status:'ignored', callback

   @byRelevance$ = permit 'list members',
-    success: (client, seed, options, callback)->
+    success: (client, seed, options, callback) ->
       if options.byEmail
         account = client.connection.delegate
         if account.can 'search-by-email'
           JUser = require './user'
-          JUser.one {email:seed}, (err, user)->
+          JUser.one { email:seed }, (err, user) ->
             return callback err, []  if err? or not user?
-            user.fetchOwnAccount (err, account)->
+            user.fetchOwnAccount (err, account) ->
               return callback err  if err?
               callback null, [account]
         else
@@ -997,36 +1000,36 @@
       else
         @byRelevance client, seed, options, callback

-  fetchMyPermissions: secure (client, callback)->
-    @fetchMyPermissionsAndRoles client, (err, permissions, roles)->
+  fetchMyPermissions: secure (client, callback) ->
+    @fetchMyPermissionsAndRoles client, (err, permissions, roles) ->
       callback err, permissions

-  fetchMyPermissionsAndRoles: secure (client, callback)->
+  fetchMyPermissionsAndRoles: secure (client, callback) ->
     JGroup = require './group'

     slug = client.context.group ? 'koding'
-    JGroup.one {slug}, (err, group)=>
+    JGroup.one { slug }, (err, group) =>
       return callback err  if err
-      return callback {message: "group not found"}  unless group
-
-      kallback = (err, roles)=>
+      return callback new KodingError 'group not found'  unless group
+
+      kallback = (err, roles) =>
         return callback err  if err

-        @fetchUser (err, user)=>
+        @fetchUser (err, user) ->
           return callback err  if err

           userId = user._id

-          {flatten} = require 'underscore'
-
-          if "admin" in roles
+          { flatten } = require 'underscore'
+
+          if 'admin' in roles

             perms = Protected.permissionsByModule
             callback null, { permissions: (flatten perms), roles, userId }

           else

-            group.fetchPermissionSetOrDefault (err, permissionSet)->
+            group.fetchPermissionSetOrDefault (err, permissionSet) ->
               return callback err if err

               perms = (perm.permissions.slice() for perm in permissionSet.permissions \
@@ -1038,39 +1041,39 @@

   ## NEWER IMPLEMENATION: Fetch ids from graph db, get items from document db.

-  unlinkOauth: secure (client, provider, callback)->
-    {delegate} = client.connection
+  unlinkOauth: secure (client, provider, callback) ->
+    { delegate } = client.connection
     isMine     = @equals delegate
     if isMine
-      @fetchUser (err, user)=>
+      @fetchUser (err, user) =>
         return callback err  if err

         query = {}
-        query["foreignAuth.#{provider}"] = ""
-        user.update $unset: query, (err)=>
+        query["foreignAuth.#{provider}"] = ''
+        user.update { $unset: query }, (err) =>
           return callback err  if err
           @oauthDeleteCallback provider, user, callback
     else
       callback new KodingError 'Access denied'

-  oauthDeleteCallback: (provider, user, callback)->
-    if provider is "google"
-      user.fetchAccount 'koding', (err, account)->
+  oauthDeleteCallback: (provider, user, callback) ->
+    if provider is 'google'
+      user.fetchAccount 'koding', (err, account) ->
         return callback err  if err
-        JReferrableEmail = require "./referrableemail"
+        JReferrableEmail = require './referrableemail'
         JReferrableEmail.delete user.username, callback
     else
       callback()

   # we are using this in sorting members list..
-  updateMetaModifiedAt: (callback)->
+  updateMetaModifiedAt: (callback) ->
     @update $set: 'meta.modifiedAt': new Date, callback

-  fetchEmail: secure (client, callback)->
-    {delegate} = client.connection
+  fetchEmail: secure (client, callback) ->
+    { delegate } = client.connection
     isMine     = @equals delegate
     if isMine
-      @fetchUser (err, user)->
+      @fetchUser (err, user) ->
         return callback err  if err
         callback null, user?.email
     else
@@ -1083,20 +1086,20 @@
       JPaymentMethod.decoratePaymentMethods paymentMethods, callback

   fetchPaymentMethods$: secure (client, callback) ->
-    {delegate} = client.connection
+    { delegate } = client.connection
     if (delegate.equals this) or delegate.can 'administer accounts'
       @fetchDecoratedPaymentMethods callback

-  fetchMetaInformation: secure (client, callback)->
-
-    {delegate} = client.connection
+  fetchMetaInformation: secure (client, callback) ->
+
+    { delegate } = client.connection
     unless delegate.can 'administer accounts'
       return callback new KodingError 'Access denied!'

     Payment = require './payment'

-    @fetchUser (err, user)=>
+    @fetchUser (err, user) =>

       return callback err  if err
       return callback new KodingError 'Failed to fetch user!'  unless user
@@ -1106,16 +1109,16 @@

       fakeClient = connection: delegate: this

-      Payment.subscriptions fakeClient, {}, (err, subscription)=>
+      Payment.subscriptions fakeClient, {}, (err, subscription) ->

         if err? or not subscription?
         then plan = 'free'
         else plan = subscription.planTitle

-        JMachine = require "./computeproviders/machine"
+        JMachine = require './computeproviders/machine'
         selector = 'users.id' : user.getId()

-        JMachine.some selector, limit: 30, (err, machines)->
+        JMachine.some selector, limit: 30, (err, machines) ->

           if err? then machines = err

@@ -1125,7 +1128,7 @@
           }

-  fetchSubscriptions$: secure ({ connection:{ delegate }}, options, callback) ->
+  fetchSubscriptions$: secure ({ connection:{ delegate } }, options, callback) ->
     return callback { message: 'Access denied!' }  unless @equals delegate

     [callback, options] = [options, callback]  unless callback
@@ -1162,20 +1165,20 @@

         callback null, { subscriptions, plans }

-  fetchEmailAndStatus: secure (client, callback)->
+  fetchEmailAndStatus: secure (client, callback) ->
     @fetchFromUser client, ['email', 'status'], callback

-  fetchEmailFrequency: secure (client, callback)->
+  fetchEmailFrequency: secure (client, callback) ->
     @fetchFromUser client, 'emailFrequency', callback

-  fetchOAuthInfo: secure (client, callback)->
+  fetchOAuthInfo: secure (client, callback) ->
     @fetchFromUser client, 'foreignAuth', callback

-  fetchFromUser: secure (client, key, callback)->
-    {delegate} = client.connection
+  fetchFromUser: secure (client, key, callback) ->
+    { delegate } = client.connection
     isMine     = @equals delegate
     if isMine
-      @fetchUser (err, user)->
+      @fetchUser (err, user) ->
         return callback err  if err
         if Array.isArray key
           results = {}
@@ -1188,8 +1191,8 @@
     else
       callback new KodingError 'Access denied'

-  isAuthorized: secure (client, name, callback)->
-    @fetchOAuthInfo client, (err, response)->
+  isAuthorized: secure (client, name, callback) ->
+    @fetchOAuthInfo client, (err, response) ->

       return callback err  if err

@@ -1201,19 +1204,19 @@

   setLastLoginTimezoneOffset: secure (client, options, callback) ->
-    {lastLoginTimezoneOffset} = options
-
-    return callback new KodingError "timezone offset is not set"  unless lastLoginTimezoneOffset?
-
-    @update $set: {lastLoginTimezoneOffset}, (err) ->
-      return callback new KodingError "Could not update last login timezone offset" if err
+    { lastLoginTimezoneOffset } = options
+
+    return callback new KodingError 'timezone offset is not set'  unless lastLoginTimezoneOffset?
+
+    @update { $set: { lastLoginTimezoneOffset } }, (err) ->
+      return callback new KodingError 'Could not update last login timezone offset' if err
       callback null

-  expireSubscription: secure ({connection}, callback) ->
-    if KONFIG.environment is "production"
-      return callback new KodingError "permission denied"
-
-    {expireSubscription} = require "./socialapi/requests"
+  expireSubscription: secure ({ connection }, callback) ->
+    if KONFIG.environment is 'production'
+      return callback new KodingError 'permission denied'
+
+    { expireSubscription } = require './socialapi/requests'
     expireSubscription connection.delegate.getId(), callback

@@ -1237,13 +1240,13 @@
     JSession         = require './session'
     { v4: createId } = require 'node-uuid'

-    JSession.one {clientId: sessionToken}, (err, session) ->
+    JSession.one { clientId: sessionToken }, (err, session) ->

       if err or not session
         return errorCallback()

       [otaToken] = createId().split '-'
-      session.update $set: {otaToken}, (err)->
+      session.update { $set: { otaToken } }, (err) ->
         if err then errorCallback()
         else callback null, otaToken

@@ -1316,7 +1319,7 @@
     _fetchUser client, (err, user) ->
       return callback err  if err

-      {disable, password} = options
+      { disable, password } = options

       if not disable and user.getAt 'twofactorkey'
         return callback new KodingError '2Factor authentication already in use.'
@@ -1330,10 +1333,10 @@

         return

-      {key, verification} = options
+      { key, verification } = options

       speakeasy    = require 'speakeasy'
-      generatedKey = speakeasy.totp {key, encoding: 'base32'}
+      generatedKey = speakeasy.totp { key, encoding: 'base32' }

       if generatedKey isnt verification
         return callback new KodingError \
@@ -1341,3 +1344,5 @@

       user.update $set: twofactorkey: key, (err) ->
         callback err
+
+


cron.coffee: fixed crashed

cron.coffee: fixed crashed

--- scripts/cron.coffee
+++ scripts/cron.coffee
@@ -8,7 +8,7 @@
 #   http://qiita.com/hotakasaito/items/03386fe1a68e403f5cb8

 cronJob = require('cron').CronJob
-Urls = require('./brainClass')
+Urls = require('./brainClass.coffee')

 module.exports = (robot) ->
 #  sayHello = ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -7,7 +7,8 @@
   health: 100
   maxHealth: 100

-enemy = GameObj
+enemy = GameObject
+  he

 player.position()


Fix days of week formatting (1 -> 01)

Fix days of week formatting (1 -> 01)

--- scripts/kerb.coffee
+++ scripts/kerb.coffee
@@ -17,7 +17,9 @@

     jsdom.env url, [ "http://code.jquery.com/jquery-1.5.min.js" ], (errors, window) ->
       d = new Date();
-      formatted_date = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate()
+      day = d.getDate()
+      day = (day < 10 ? '0' : '') + number
+      formatted_date = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + day
       traders = window.$("#date-"+formatted_date+" ul li div.rota_content")
       message_str = "\n"
       traders.each (index, element) =>
@@ -27,4 +29,4 @@
         message_str += trader_name + "\n"
         message_str += "  " + trader_desc + "\n"

-      msg.send message_str
+      msg.send message_str


only yield if we need to

only yield if we need to

--- src/methods.coffee
+++ src/methods.coffee
@@ -131,10 +131,11 @@
               rs.print str
             else
               throw "You tried to write to a PrintStream that wasn't System.out or System.err! For shame!"
-            # For the browser implementation -- the DOM doesn't get repainted
-            # unless we give the event loop a chance to spin.
-            rs.curr_frame().resume = -> # NOP
-            throw new util.YieldException (cb) -> setTimeout(cb, 0)
+            if node?
+              # For the browser implementation -- the DOM doesn't get repainted
+              # unless we give the event loop a chance to spin.
+              rs.curr_frame().resume = -> # NOP
+              throw new util.YieldException (cb) -> setTimeout(cb, 0)
       ]
   sun:
     misc:


add sorting for input keyframes

add sorting for input keyframes

--- src/options.coffee
+++ src/options.coffee
@@ -10,8 +10,19 @@

 class Options
     constructor: (@parent, @models=[], @views=[]) ->
+        @prio =
+            temperature: 2,
+            color: 1,
+            opacity: 0
+
         chrome.storage.local
             .get 'keyframes', (item) =>
+                # sort by option first, key_value for same option
+                item.keyframes
+                    .sort (a, b) =>
+                        @prio[a.option] - @prio[b.option] if a.option isnt b.option
+                        a.key_value - b.key_value
+
                 @add kf for kf in item.keyframes

         $ '#add'


[fix] coffee not output

[fix] coffee not output

--- src/package.coffee
+++ src/package.coffee
@@ -46,7 +46,7 @@
     (fs.readFileSync(lib, 'utf8') for lib in @libs).join("\n")

   compileAfters: ->
-    (fs.readFileSync(compilers.coffee(after), 'utf8') for after in @afters).join("\n")
+    (fs.readFileSync(after, 'utf8') for after in @afters).join("\n")

   compileJavascript: (minify = false) ->
     try


Tis what the maiden declared take 2

Tis what the maiden declared take 2

--- scripts/twss.coffee
+++ scripts/twss.coffee
@@ -6,4 +6,4 @@
       if Math.random() < 0.9
         msg.send "That's what she said"
       else
-        msg.send "Tis what the maiden declared
+        msg.send "Tis what the maiden declared"


Add key property for React

Add key property for React

--- src/components/student-dashboard/dont-forget-panel.cjsx
+++ src/components/student-dashboard/dont-forget-panel.cjsx
@@ -30,7 +30,7 @@
   renderBlock: (event, i, all) ->
     feedback = "#{event.complete_exercise_count}/#{event.exercise_count} complete"
     data = if i % 2 then @feedbackData(event) else @recoverData(event)
-    <BS.Col className={data.name.toLowerCase()} xs={12 / all.length}>
+    <BS.Col key={event.id} className={data.name.toLowerCase()} xs={12 / all.length}>

View {data.name}


Don't return collected array

Don't return collected array

--- src/package.coffee
+++ src/package.coffee
@@ -229,6 +229,7 @@
     for name, {versions} of @metadata.consumedServices
       for version, methodName of versions
         @activationDisposables.add atom.packages.serviceHub.consume(name, version, @mainModule[methodName].bind(@mainModule))
+    return

   loadKeymaps: ->
     if @bundledPackage and packagesCache[@name]?


Clean up keymap disabled config check and remove spurious newline

--- src/package.coffee
+++ src/package.coffee
@@ -201,11 +201,11 @@
   activateResources: ->
     @activationDisposables = new CompositeDisposable

-    value = not _.include(atom.config.get("core.disabledKeymaps") ? [], @name)
-    if value
+    keymapIsDisabled = _.include(atom.config.get("core.disabledKeymaps") ? [], @name)
+    if keymapIsDisabled
+      @deactivateKeymaps()
+    else
       @activateKeymaps()
-    else if not value
-      @deactivateKeymaps()

     for [menuPath, map] in @menus when map['context-menu']?
       try
@@ -259,7 +259,6 @@
     for [path, map] in @keymaps
       if map.length > 0
         return true
-
     false

   activateServices: ->


[master] translation unit online

[master] translation unit online

--- translator/run.coffee
+++ translator/run.coffee
@@ -1,13 +1,14 @@
 #!/usr/bin/env coffee
 Q = require 'q'
 _ = require 'lodash'
+Progress = require 'progress'
 translator = require './'
 database = require '../database'

 if require.main == module
   Q.all [
     database.redis.getConnection 0
-  , database.redis.getConnection 1
+    database.redis.getConnection 1
   ]
   .then (res) ->
     sourceRedis = res[0]
@@ -16,12 +17,30 @@
     .then (keys) ->
       keys = _.filter keys, (key) ->
         key != 'progress'
-      Q.ninvoke sourceRedis, 'get', keys[0]
-      .then (entry) ->
-        entry = JSON.parse entry
-        translator.baidu.translate entry.title + '\n' + entry.content.replace(/
/g, '')
-      .then (res) ->
-        console.log res
+      bar = new Progress('[:bar] :percent :etas',
+        total: keys.length
+        width: 100
+      )
+      translateOne = (key) ->
+        Q.ninvoke sourceRedis, 'get', key
+        .then (entry) ->
+          entry = JSON.parse entry
+          translator.baidu.translate entry.title + '\n' + entry.content.replace(/
/g, '')
+          .then (res) ->
+            d =
+              translation: res
+            targetRedis.set "#{entry.id}", JSON.stringify(d)
+            bar.tick 1
+      Q.all _.map(_.range(300), ->
+        loo = ->
+          val = keys.pop()
+          if val
+            translateOne val
+            .then loo
+          else
+            Q()
+        loo()
+      )
     .then ->
       targetRedis.closeConnection()
       sourceRedis.closeConnection()


Changes to add protocol

Changes to add protocol

--- gui/web_app/coffee/settings.coffee
+++ gui/web_app/coffee/settings.coffee
@@ -21,8 +21,14 @@
       return
     return

+  populateProtocols = (protocolJson) ->
+    protocolJson = JSON.parse protocolJson
+    renderList "protocolScript", {"protocolList": protocolJson.protocol}
+    return
+
   ### Main ###
   httpGet("http://127.0.0.1:5000/api/v1.0/proteins", populateProteins)
+  httpGet("http://127.0.0.1:5000/api/v1.0/protocols", populateProtocols)

   return


Removed paste as text and code icons

Removed paste as text and code icons

--- app/assets/javascripts/components/itsi_authoring/rich_text_editor.js.coffee
+++ app/assets/javascripts/components/itsi_authoring/rich_text_editor.js.coffee
@@ -17,8 +17,8 @@
         menubar: false
         statusbar: false
         toolbar_items_size: 'small'
-        toolbar: "undo redo | bold italic strikethrough underline | aligncenter alignjustify alignleft alignright indent outdent | subscript superscript | numlist bullist | link unlink | hr image table pastetext | code"
-        plugins: 'paste link hr image table code'
+        toolbar: "undo redo | bold italic strikethrough underline | aligncenter alignjustify alignleft alignright indent outdent | subscript superscript | numlist bullist | link unlink | hr image table"
+        plugins: 'paste link hr image table'
         paste_as_text: true
         setup: (editor) =>
           # both events are needed as the 'change' event is only sent when the input loses focus (which handles menu choices like formatting)
@@ -29,4 +29,3 @@

     render: ->
       (textarea {ref: 'textarea', name: @props.name, cols: 100, rows: 5, defaultValue: @props.text})
-


[grunt] use better variable name for options in Nunjucks task config

--- tasks/templates.coffee
+++ tasks/templates.coffee
@@ -17,7 +17,7 @@
   # Config
   # ======

-  taskConfig =
+  options =
     autoescape          : false
     data                : grunt.config('data')
     nunjucksEnv         : grunt.config('path.source.templates')
@@ -36,15 +36,15 @@
       baseLocaleAsRoot  : true
       gettext           : grunt.config('i18n.gettext')

-  gettext    = taskConfig.i18n.gettext
-  baseLocale = taskConfig.i18n.baseLocale
+  gettext    = options.i18n.gettext
+  baseLocale = options.i18n.baseLocale

-  { getLocalesNames, getLocaleProps, getLocaleDir, getLangcode, getRegioncode, isoLocale } = new i18nTools(taskConfig.i18n.locales, baseLocale, taskConfig.i18n.baseLocaleAsRoot)
+  { getLocalesNames, getLocaleProps, getLocaleDir, getLangcode, getRegioncode, isoLocale } = new i18nTools(options.i18n.locales, baseLocale, options.i18n.baseLocaleAsRoot)

   locales      = getLocalesNames()

-  buildDir     = taskConfig.files.dest
-  templatesDir = taskConfig.files.cwd
+  buildDir     = options.files.dest
+  templatesDir = options.files.cwd

   # =======================
   # Config l10n of Nunjucks
@@ -53,14 +53,14 @@
   locales.forEach (currentLocale) =>
     localeDir     = getLocaleDir(currentLocale)
     localeProps   = getLocaleProps(currentLocale)
-    localizedData = taskConfig.data(currentLocale)
+    localizedData = options.data(currentLocale)

     # Define targets, with unique options and files for each locale
     @config "nunjucks.#{currentLocale}",

       options:
-        paths                : taskConfig.nunjucksEnv
-        autoescape           : taskConfig.autoescape
+        paths                : options.nunjucksEnv
+        autoescape           : options.autoescape
         data                 : localizedData
         configureEnvironment : (env) ->

@@ -99,9 +99,9 @@
             getLangcode(locale)

         preprocessData: (data) ->
-          pagepath     = humanReadableUrl(@src[0].replace(templatesDir, ''), taskConfig.humanReadableUrls.exclude)
+          pagepath     = humanReadableUrl(@src[0].replace(templatesDir, ''), options.humanReadableUrls.exclude)
           breadcrumb   = crumble(pagepath)
-          matterData   = grunt.file.readJSON(taskConfig.files.matter)
+          matterData   = grunt.file.readJSON(options.files.matter)
           pageProps    = (get(matterData, breadcrumb) or {}).props

           set data, 'site.__matter__', matterData
@@ -120,12 +120,12 @@

       files: [
         expand: true
-        cwd: taskConfig.files.cwd
-        src: taskConfig.files.src
-        dest: join(taskConfig.files.dest, localeDir)
-        ext: taskConfig.files.ext
+        cwd: options.files.cwd
+        src: options.files.src
+        dest: join(options.files.dest, localeDir)
+        ext: options.files.ext
         rename: (dest, src) =>
-          src = if taskConfig.humanReadableUrls.enabled then humanReadableUrl(src, taskConfig.humanReadableUrls.exclude) else src
+          src = if options.humanReadableUrls.enabled then humanReadableUrl(src, options.humanReadableUrls.exclude) else src
           join(dest, src)
       ]


[grunt] reload Gray Matter when templates changes

--- tasks/templates.coffee
+++ tasks/templates.coffee
@@ -393,7 +393,7 @@
     watch:
       templates:
         files: ['<%= path.source.templates %>/{,**/}*.nj', '!<%= path.source.templates %>{,**/}_*.nj']
-        tasks: ['newer:nunjucks']
+        tasks: ['grayMatter', 'newer:nunjucks']
       templatesPartials:
         files: ['<%= path.source.templates %>/{,**/}_*.nj']
-        tasks: ['nunjucks']+        tasks: ['grayMatter', 'nunjucks']


- [grunt] `nunjucks-2-html` now can render files in subfolders too

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -9,7 +9,7 @@
       files: [
         expand: true
         cwd: '<%= path.source.layouts %>/'
-        src: '*.nj'
+        src: '**/*.nj'
         dest: '<%= path.build.root %>/'
         ext: '.html'
       ]


[grunt] configuratable base locale as root of site

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -24,6 +24,7 @@
     i18n:
       locales           : grunt.config('data.site.locales')
       baseLocale        : grunt.config('data.site.baseLocale')
+      baseLocaleAsRoot  : true
       defaultDomain     : 'messages'
     numberDefaultFormat : '0,0[.]00'
     urlify:
@@ -102,7 +103,7 @@

   # Output or not locale's dir name based on whether it's base locale or not.
   getLocaleDir = (locale) ->
-    urlify(if locale == baseLocale then '' else locale)
+    urlify(if taskConfig.i18n.baseLocaleAsRoot and locale == baseLocale then '' else locale)

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


Better statements

Better statements

--- test/Reporter.coffee
+++ test/Reporter.coffee
@@ -2,6 +2,28 @@
 Reporter = require './../src/Reporter'

 errors = [
+    level: 'error'
+    name: 'some_error'
+    filename: 'some_file'
+    line: 6
+,
+    level: 'warning'
+    name: 'some_warning'
+    filename: 'some_file'
+    line: 4
+]
+
+multipleErrors = [
+    level: 'error'
+    name: 'some_error'
+    filename: 'some_file'
+    line: 6
+,
+    level: 'warning'
+    name: 'some_warning'
+    filename: 'some_file'
+    line: 4
+,
     level: 'error'
     name: 'some_error'
     filename: 'some_file'
@@ -64,3 +86,10 @@
             expect(rep.warnCount).to.equal 0
             expect(rep.errCount).to.equal 0
             expect(rep.log).to.not.equal ''
+
+        it 'should log multiple errors and warning', ->
+            rep = new Reporter
+            rep.aggregate multipleErrors, 'some_file'
+            expect(rep.errCount).to.equal 2
+            expect(rep.warnCount).to.equal 2
+            expect(rep.log).to.not.equal ''


Test unwatchBodyHeight

Test unwatchBodyHeight

--- test/api-spec.coffee
+++ test/api-spec.coffee
@@ -166,3 +166,23 @@
           window.removeEventListener 'message', setHeightHandler
           done()
       window.addEventListener 'message', setHeightHandler
+
+
+    it 'unwatchBodyHeight stops watching for height changes', (done) ->
+      iframe.style = 'height: 100px'
+      interval = iframe.contentWindow.papi.watchBodyHeight()
+      interval = iframe.contentWindow.papi.unwatchBodyHeight()
+
+      setHeightWithCSS(iframe)
+
+      setHeightHandler = (event) ->
+        return unless event.source == iframe.contentWindow
+        if event.data.event == 'setHeight' && event.data.data.pixels != 0
+          assert false, 'Got an automatic setHeight event while called unwatchBodyHeight'
+          done()
+      window.addEventListener 'message', setHeightHandler
+
+      finish = ->
+        window.removeEventListener 'message', setHeightHandler
+        done()
+      setTimeout finish, 100


Use move.isNonDamaging

Use move.isNonDamaging

--- test/bw/moves.coffee
+++ test/bw/moves.coffee
@@ -2535,7 +2535,7 @@

         mock = @sandbox.mock(@team2)
         # Whirlwind, Roar
-        if move.power > 0
+        if !move.isNonDamaging()
           mock.expects("switch").never()

         @team2.at(0).setHP(1)


:bug: :fire: Remove double subscription to the same buffer

--- src/project.coffee
+++ src/project.coffee
@@ -360,7 +360,6 @@

   addBuffer: (buffer, options={}) ->
     @addBufferAtIndex(buffer, @buffers.length, options)
-    @subscribeToBuffer(buffer)

   addBufferAtIndex: (buffer, index, options={}) ->
     @buffers.splice(index, 0, buffer)


check for filled day object; fixes #325

check for filled day object; fixes #325

--- both/methods/user/user.coffee
+++ both/methods/user/user.coffee
@@ -121,7 +121,7 @@
 			user.profile.available = mo: [], tu: [], we: [], th: [], fr: [], sa: [], su: []
 			Meteor.users.update Meteor.userId(), $set: 'profile.available': user.profile.available

-		if user.profile.available && hour in user.profile.available[day]
+		if user.profile.available?[day] && hour in user.profile.available[day]
 			pull = {}
 			pull['profile.available.'+ day] = hour


embeds: removed sound cloud widget from the stream, it will now be a regular link embed http://d.pr/i/UeQS

--- client/landing/app/Applications/Activity.kdapplication/views/embedbox.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/embedbox.coffee
@@ -196,7 +196,7 @@

   getRichEmbedWhitelist:->
     [
-      "SoundCloud"
+      # "SoundCloud"
     ]

   fetchEmbed:(url="#",options={},callback=noop)->


Search: reject illegal input /cc @humanchimp

--- client/Main/searchcontroller.coffee
+++ client/Main/searchcontroller.coffee
@@ -13,6 +13,9 @@
   search: (indexName, seed, options) ->

     new Promise (resolve, reject) =>
+
+      return reject new Error 'Illegal input'  if seed is ''
+
       index = @getIndex "#{ indexName }#{ KD.config.algolia.indexSuffix }"
       index.search seed, (success, results) ->

@@ -32,7 +35,10 @@
       .then (it) -> [it]

   searchAccounts: (seed) ->
-    @search 'accounts', seed
+
+    seed = seed.replace /\W/g, ''
+
+    @search 'accounts', seed, hitsPerPage : 10
       .then (data) ->
         throw new Error "No data!" if data.length is 0
         return data


Server: removed minor log

Server: removed minor log

--- client/landing/server/server.coffee
+++ client/landing/server/server.coffee
@@ -18,9 +18,9 @@
   app.use '/', express.static STATIC_PATH

   app.use bodyParser.urlencoded({ extended: false })
-
+
   app.use basicAuth 'koding', 'hackathon'
-
+
   app.post '/WFGH/Apply', (req, res) ->
     res.status(200).send {
       totalApplicants    : 14812
@@ -45,7 +45,6 @@
     request _request, (err, response, body) ->
       if body isnt "User not found"
         gravatar = JSON.parse body
-        console.log gravatar
         res.status(200).send(gravatar)

       else


Centralise the logging logic.

Centralise the logging logic.

--- src/application.coffee
+++ src/application.coffee
@@ -20,12 +20,51 @@
 		channel: "device-#{uuid.value}-logs"
 	)

-exports.logSystemEvent = logSystemEvent = (message) ->
+logTypes =
+	stopApp:
+		eventName: 'Application kill'
+		humanName: 'Killing application'
+	stopAppSuccess:
+		eventName: 'Application stop'
+		humanName: 'Killed application'
+
+	downloadApp:
+		eventName: 'Application download'
+		humanName: 'Downloading application'
+	downloadAppSuccess:
+		eventName: 'Application downloaded'
+		humanName: 'Downloaded application'
+
+	installApp:
+		eventName: 'Application install'
+		humanName: 'Installing application'
+
+	startApp:
+		eventName: 'Application start'
+		humanName: 'Starting application'
+	startAppSuccess:
+		eventName: 'Application started'
+		humanName: 'Started application'
+	startAppError:
+		eventName: 'Application started'
+		humanName: 'Failed to start application'
+
+	updateApp:
+		eventName: 'Application update'
+		humanName: 'Updating application'
+
+logSystemEvent = (logType, app, err) ->
+	message = "#{logType.humanName} '#{app.imageId}'"
+	if err?
+		# Report the message from the original cause to the user.
+		errMessage = err.cause.json ? err.cause.message ? err.message
+		message += " due to '#{errMessage}'"
 	logger.log({ message, isSystem: true })
+	utils.mixpanelTrack(logType.eventName, {app, err})
+	return

 kill = (app) ->
-	logSystemEvent('Killing application ' + app.imageId)
-	utils.mixpanelTrack('Application kill', app)
+	logSystemEvent(logTypes.stopApp, app)
 	updateDeviceState(status: 'Stopping')
 	container = docker.getContainer(app.containerId)
 	console.log('Stopping and deleting container:', container)
@@ -50,7 +89,7 @@
 			return
 		throw err
 	.tap ->
-		utils.mixpanelTrack('Application stop', app.imageId)
+		logSystemEvent(logTypes.stopAppSuccess, app)
 		knex('app').where('id', app.id).delete()

 isValidPort = (port) ->
@@ -60,12 +99,12 @@
 fetch = (app) ->
 	docker.getImage(app.imageId).inspectAsync()
 	.catch (error) ->
-		utils.mixpanelTrack('Application download', app)
-		logSystemEvent('Downloading application ' + app.imageId)
+		logSystemEvent(logTypes.downloadApp, app)
 		updateDeviceState(status: 'Downloading')
 		dockerUtils.fetchImageWithProgress app.imageId, (progress) ->
 			updateDeviceState(download_progress: progress.percentage)
 		.then ->
+			logSystemEvent(logTypes.downloadAppSuccess, app)
 			updateDeviceState(download_progress: null)
 			docker.getImage(app.imageId).inspectAsync()

@@ -91,8 +130,7 @@
 		containerPromise.catch ->
 			fetch(app)
 			.then (imageInfo) ->
-				utils.mixpanelTrack('Application install', app)
-				logSystemEvent('Installing application ' + app.imageId)
+				logSystemEvent(logTypes.installApp, app)
 				updateDeviceState(status: 'Installing')

 				ports = {}
@@ -125,8 +163,7 @@
 			else
 				knex('app').insert(app)
 		.tap (container) ->
-			utils.mixpanelTrack('Application start', app)
-			logSystemEvent('Starting application ' + app.imageId)
+			logSystemEvent(logTypes.startApp, app)
 			updateDeviceState(status: 'Starting')
 			ports = {}
 			if portList?
@@ -143,19 +180,14 @@
 					'/var/run/docker.sock:/run/docker.sock'
 				]
 			)
-			# Bluebird throws OperationalError for errors resulting in the normal execution of a promisified function.
-			.catch Promise.OperationalError, (err) ->
-				# Report the message from the original cause to the user.
-				message = err.cause.json ? err.cause.message ? err.message
-				logSystemEvent("Unable to start application #{app.imageId} due to:\n#{message}")
-				# And rethrow the error, to be handled later as necessary.
+			.catch (err) ->
+				logSystemEvent(logTypes.startAppError, app, err)
 				throw err
 			.then ->
 				updateDeviceState(commit: app.commit)
 				logger.attach(app)
 	.tap ->
-		utils.mixpanelTrack('Application start', app.imageId)
-		logSystemEvent('Starting application ' + app.imageId)
+		logSystemEvent(logTypes.startAppSuccess, app)
 	.finally ->
 		updateDeviceState(status: 'Idle')

@@ -254,8 +286,7 @@
 				updatingPromises = toBeUpdated.map (imageId) ->
 					localApp = apps[imageId]
 					app = remoteApps[imageId]
-					utils.mixpanelTrack('Application update', app)
-					logSystemEvent('Updating application')
+					logSystemEvent(logTypes.updateApp, app)
 					kill(localApp)
 					.then ->
 						start(app)


<model> Implemented applyRules

<model> Implemented applyRules

--- server/models/rule.coffee
+++ server/models/rule.coffee
@@ -145,6 +145,7 @@
 			callback err, null
 			return

+		# @todo async.map stops and calls the callback at the first returned error. We might not want such a behavior...
 		async.map sensorRules, ((sensorRule, cb) ->
 			if (!sensorRule.intervalEnd || measure.value < sensorRule.intervalEnd) && (!sensorRule.intervalStart || measure.value >= sensorRule.intervalStart)
 				# If the measure triggers the SensorRule, update the corresponding Rule:
@@ -181,4 +182,23 @@
 				else
 					callback null, null
 		), callback
-	+
+###
+# applyRules
+# ====
+# Applies the ActuatorRules (reactions) of the given rules.
+# @param rules (Rules[]): 					Rules
+# @param actuatorsDrivers (Driver[]): 		List of drivers supported by the system
+# @param callback (Function(Error):null): 	Callback
+###
+RuleModel.applyMetRules = (rules, actuatorsDrivers, callback) ->
+	# @todo async.each stops and calls the callback at the first returned error. We might not want such a behavior...
+	async.each rules, ((rule, cb) ->
+		ActuatorRule.request "byRule", key: rule.id, (err, actuatorRules)->
+			if err
+				callback 'Error while finding ActuatorRules associated to Rule #'+rule.id+': '+err
+				return
+			async.each actuatorRules, ((actuatorRule, cb2) ->
+				actuatorRule.apply actuatorsDrivers, cb2
+			), cb
+		), callback


fixes sort order on activity

fixes sort order on activity

--- workers/social/lib/social/models/graph/graph.coffee
+++ workers/social/lib/social/models/graph/graph.coffee
@@ -79,7 +79,7 @@
               {collections, wantedOrder} = @getIdsFromAResultSet relatedResult.reply
               @fetchObjectsFromMongo collections, wantedOrder, (err, dbObjects)->
                 res.replies.push obj for obj in dbObjects
-                tempRes.push res
+                tempRes[i] = res
                 fin()
             else
               tempRes.push res


fall back to far future max-age for responses with no cache-control

Fixing this:

https://img.skitch.com/20120413-f96b7h1h4gic7pug79kb4ittck.png

--- server.coffee
+++ server.coffee
@@ -67,7 +67,7 @@
       else
         newHeaders =
           'content-type'           : srcResp.headers['content-type']
-          'cache-control'          : srcResp.headers['cache-control']
+          'cache-control'          : srcResp.headers['cache-control'] || 'public, max-age=31536000'
           'content-length'         : content_length
           'Camo-Host'              : camo_hostname
           'X-Content-Type-Options' : 'nosniff'


Changed gathering to be 10 a second

Changed gathering to be 10 a second

--- server.coffee
+++ server.coffee
@@ -5,6 +5,7 @@
 Config = {
 		updateCompletionDelay: 500				# milliseconds between updating the doneCount for the client while gathering data
 		gatheringTimeout: 120*1000				# timeout of the gathering (time after receiving last result) non-updated plugins will be marked as inactive after this
+		gatherRequestsPerSecond: 10				# how many HTTP data gather requests will be send each second
 	}

 # Upgrade of the plugin
@@ -22,25 +23,44 @@
 	return 0

 # Client call to update databases
-exports.client_gatherHistory = ->
+exports.client_gatherHistory = ->
+	log '[gatherHistory()] Starting to request'
 	Timer.cancel 'gatheringTimeout', {}
 	Timer.cancel 'updateCompletion', {}
 	Db.shared.set 'doneCount', 0
 	Db.shared.set 'lastDoneCount', 0
 	Db.shared.set 'updating', 'true'
-	log '[gatherHistory()] Starting to request'
-	Db.backend.iterate 'pluginInfo' , (group) !->
-		Db.backend.set 'pluginInfo', group.key(), 'upToDate', 'false'
-		if Db.backend.peek('pluginInfo', group.key(), 'active') is 'true'
-			log '  Requesting from: '+group.key()
-			Http.post
-				url: 'https://happening.im/x/' + group.key()
-				data: '64foNwpEfn3LQrTQC2q5NijPqG92Nv2xYi65gFz6uTJjPJS2stN7MbyNygtvKvNS'
-				name: 'historyResult'
-	log '[gatherHistory()] Done sending requests'
+	Db.backend.set 'pluginInfoCopy', Db.backend.peek('pluginInfo')
+	currentRequest = 0
+	Db.backend.iterate 'pluginInfoCopy' , (group) !->
+		Db.backend.set 'pluginInfoCopy', group.key(), 'upToDate', 'false'
+		currentRequest++
+	Db.shared.set 'currentRequest', currentRequest
+	Timer.set 0, 'doGatherStep', {}
 	Timer.set Config.gatheringTimeout, 'gatheringTimeout', {}
 	Timer.set Config.updateCompletionDelay, 'updateCompletion', {}
 	return 0
+
+exports.doGatherStep = (args) ->
+	current = 0
+	currentRequest = Db.shared.peek('currentRequest')
+	Db.backend.iterate 'pluginInfoCopy' , (group) !->
+		if current >= currentRequest and current < (currentRequest+Config.gatherRequestsPerSecond)
+			if Db.backend.peek('pluginInfoCopy', group.key(), 'active') is 'true'
+				log '  Requesting from: '+group.key()
+				Http.post
+					url: 'https://happening.im/x/' + group.key()
+					data: '64foNwpEfn3LQrTQC2q5NijPqG92Nv2xYi65gFz6uTJjPJS2stN7MbyNygtvKvNS'
+					name: 'historyResult'
+		current++
+	currentRequest = currentRequest-Config.gatherRequestsPerSecond
+	Db.shared.set 'currentRequest', currentRequest
+	if currentRequest > 0
+		Timer.set 1000, 'doGatherStep', {}
+	else
+		log '[doGatherStep()] Done sending requests'
+	return 0
+

 # Client call for updating statistics
 exports.client_updateStatistics = ->
@@ -50,9 +70,9 @@
 exports.updateCompletion = (args) ->
 	done = true
 	doneCount = 0
-	Db.backend.iterate 'pluginInfo', (group) !->
-		if Db.backend.peek('pluginInfo', group.key(), 'active') isnt 'false'
-			if Db.backend.peek('pluginInfo', group.key(), 'upToDate') is 'false'
+	Db.backend.iterate 'pluginInfoCopy', (group) !->
+		if Db.backend.peek('pluginInfoCopy', group.key(), 'active') isnt 'false'
+			if Db.backend.peek('pluginInfoCopy', group.key(), 'upToDate') is 'false'
 				done = false
 			else
 				doneCount++
@@ -72,6 +92,7 @@
 	Timer.cancel 'updateCompletion', {}
 	Db.shared.set('latestUpdate', new Date()/1000)
 	Db.shared.set 'updating', 'false'
+	Db.backend.remove 'pluginInfoCopy'
 	recalculateStatistics()

 # A callback result from a Conquest plugin after asked for database
@@ -86,8 +107,8 @@
 				Db.backend.remove('recievedData', result.groupCode, 'history', 'groupCode')
 				Db.backend.set('recievedData', result.groupCode, 'players', result.players)
 				Db.backend.remove('recievedData', result.groupCode, 'history', 'players')
-				if Db.backend.peek('pluginInfo', result.groupCode, 'upToDate') is 'false'
-					Db.backend.set 'pluginInfo', result.groupCode, 'upToDate', 'true'
+				if Db.backend.peek('pluginInfoCopy', result.groupCode, 'upToDate') is 'false'
+					Db.backend.set 'pluginInfoCopy', result.groupCode, 'upToDate', 'true'
 					Db.backend.incr 'pluginInfo', result.groupCode, 'updateNumber'
 			else
 				log "[historyResult()] NO groupcode!"
@@ -98,9 +119,9 @@

 # Triggers when not all plugins responded in time, sets plugins to inactive
 exports.gatheringTimeout = (args) ->
-	Db.backend.iterate 'pluginInfo', (group) !->
-		if Db.backend.peek('pluginInfo', group.key(), 'upToDate') is 'false'
-			Db.backend.set 'pluginInfo', group.key(), 'active', 'false'
+	#Db.backend.iterate 'pluginInfo', (group) !-> TODO reenable
+	#	if Db.backend.peek('pluginInfo', group.key(), 'upToDate') is 'false'
+	#		Db.backend.set 'pluginInfo', group.key(), 'active', 'false'
 	finishGathering()

 # Update number of plugins registered
@@ -144,7 +165,7 @@
 					endedSetup++
 				else if gameState == 1
 					endedRunning++
-				else if gameState ==2
+				else if gameState == 2
 					endedProper++
 			# Team statistics
 			game.iterate 'game', 'teams', (team) !->


Check only if result is an object.

Check only if result is an object.

--- server.coffee
+++ server.coffee
@@ -3,7 +3,7 @@
 checkNames = (publish, collectionNames, computation, result) ->
   if result and _.isArray result
     resultNames = (cursor._getCollectionName() for cursor in result when '_getCollectionName' of cursor)
-  else if result and '_getCollectionName' of result
+  else if result and _.isObject result and '_getCollectionName' of result
     resultNames = [result._getCollectionName()]
   else
     resultNames = []


Notifications added when close to beacon

When you are close to a beacon but have the app not open this method
will give you a notification.

--- server.coffee
+++ server.coffee
@@ -23,9 +23,39 @@
 		log 'Restarting game'
 		initializeGame()

-# Get background location from player, TODO: notify player when close to beacon
+# Get background location from player.
 exports.onGeoloc = (userId, geoloc) ->
 	log 'Geoloc from ' + Plugin.userName(userId) + '('+userId+'): ', JSON.stringify(geoloc)
+	recieved = new Date()/1000
+	if Db.shared.peek('gameState') is 1 and (recieved - (Db.shared.peek('lastNotification', userId) || 0))> 30*60
+		beacons = Db.shared.ref('game', 'beacons')
+		beaconRadius = Db.shared.peek('game', 'beaconRadius')
+		found=false;
+		#Check if user is in range of an enemy beacon, opening the app will capture the beacon
+		beacons.iterate (beacon) ->
+			if beacon.peek('owner') isnt getTeamOfUser(userId) and !found
+				log distance(geoloc.latitude, geoloc.longitude, beacon.peek('location', 'lat'), beacon.peek('location', 'lng'))
+				if distance(geoloc.latitude, geoloc.longitude, beacon.peek('location', 'lat'), beacon.peek('location', 'lng')) < beaconRadius
+					#send notifcation
+					Event.create
+						unit: 'inRange'
+						text: 'You are in range of an enemy beacon, capture it now!'
+					found=true;
+		#Check if user is nearby an enemy beacon.
+		if !found
+			beacons.iterate (beacon) ->
+				if beacon.peek('owner') isnt getTeamOfUser(userId) and !found
+					dist = distance(geoloc.latitude, geoloc.longitude, beacon.peek('location','lat'), beacon.peek('location','lng'))
+					if dist < beaconRadius *2.5
+						#send notifcation
+						Event.create
+							unit: 'nearby'
+							text: 'You are ' + parseInt(dist,10)+ ' m away from an enemy beacon, capture it now!'
+						found=true;
+		#Last notification send, so that the user will not be spammed with notifications
+		if found
+			Db.shared.set('lastNotification', userId, recieved)
+

 # Handle new users joining the happening
 exports.onJoin = (userId) ->
@@ -143,7 +173,7 @@
 				# Cancel timers of ongoing caputes/neutralizes (new ones will be set below if required)
 				Timer.cancel 'onCapture', {beacon: beacon.key(), players: getInrangePlayers(beacon.key())}
 				Timer.cancel 'onNeutralize', {beacon: beacon.key(), players: getInrangePlayers(beacon.key())}
-				removed = undefined
+				removed = undefined;
 				if newStatus
 					owner = beacon.peek 'owner'
 					log 'Added to inRange: id=', client, ', name=', Plugin.userName(client)
@@ -314,7 +344,7 @@
 # ==================== Functions ====================
 # Get a string of the players that are inRange of a beacon
 getInrangePlayers = (beacon) ->
-	playersStr = undefined
+	playersStr = undefined;
 	Db.shared.iterate 'game', 'beacons', beacon, 'inRange', (player) !->
 		if playersStr?
 			playersStr = playersStr + ', ' + player.key()


server: assume that the exercise file is named "ex.hbs"

--- server.coffee
+++ server.coffee
@@ -18,7 +18,7 @@
 class ShowIDE extends ControllerAction
   handle: ->
     root = __dirname
-    exercises = path.join(root,"tutorials-build",@params.name,"ex1.html")
+    exercises = path.join(root,"tutorials-build",@params.name,"ex.html")
     fs.readFile exercises, {encoding: "utf8"}, (err,content) =>
       @res.render('ide',exercises: content,name: @params.name)


The window title should be the filename of the currently viewed document. [#109914028]

--- src/code/client.coffee
+++ src/code/client.coffee
@@ -62,6 +62,10 @@
         @_setState shareProvider: provider
         break

+    @appOptions.ui or= {}
+    @appOptions.ui.windowTitlePrefix or= "#{document.title}: "
+    @_setWindowTitle()
+
     @_ui.init @appOptions.ui

     # check for autosave
@@ -315,6 +319,7 @@
       dirty: false
     for own key, value of additionalState
       state[key] = value
+    @_setWindowTitle metadata?.name
     @_setState state
     @_event type, {content: content.getText()}

@@ -355,6 +360,10 @@
     suffix = if queryString? then "?#{queryString}" else ""
     "#{document.location.origin}#{document.location.pathname}#{suffix}"

+  _setWindowTitle: (name) ->
+    if @appOptions?.ui?.windowTitlePrefix
+      document.title = "#{@appOptions.ui.windowTitlePrefix}#{if name?.length > 0 then name else (tr "~MENUBAR.UNTITLED_DOCUMENT")}"
+
 module.exports =
   CloudFileManagerClientEvent: CloudFileManagerClientEvent
   CloudFileManagerClient: CloudFileManagerClient


It Was a Dark and Stormy Decade…

It Was a Dark and Stormy Decade…

--- src/coffee/game.coffee
+++ src/coffee/game.coffee
@@ -1,48 +1,70 @@
-locations =
-  home:      "in the residential district"
-  market:    "in the market"
-  slums:     "in the slums"
-  palace:    "in the royal palace"
-  outskirts: "in the outskirts"
+origins =
+  illusionist: 'an illusionist'
+  hallucinist: 'a hallucinist'
+  hypnotist: 'a hypnotist'

 angular.module 'gameDefinition', ['qbn.edsl']
   .run (qbnEdsl) ->
     {quality, qualityType} = qbnEdsl

-    quality 'hours', qualityType.item,
-      'Hours Remaining'
-      'After this, there will be no stopping the Khanduke.'
-      value: 72
-
-    quality 'stealth', qualityType.stat,
-      'Stealth'
-      'Hiding, Sneaking, Smuggling'
-      value: 1
-
-    quality 'sorcery', qualityType.stat,
-      'Sorcery'
-      'Casting, Blasting, Conjuring'
-      value: 1
-
-    quality 'strength', qualityType.stat,
-      'Strength'
-      'Action, Power, Combat'
-      value: 1
-
-    quality 'discovered', qualityType.unique,
-      'Been Discovered'
-      'That\'s not good.'
-      value: false
-
-    quality 'location', qualityType.string,
-      '!!ERROR!!'
+    quality 'day',
+      () -> "Day #{@value} of the Investigation"
+      'Day'
       undefined
-      value: null
+      value: 1
+
+    quality 'bother',
+      () -> "You have already bothered your client today"
+      'Bother'
+      'If you want to trouble her again, you\'ll have to try tomorrow.'
+
+    quality 'illusionHunch', qualityType.item,
+      'Illusion Hunch'
+      'Regenerates at the start of each day.'
+      value: 1
+
+    quality 'hallucinationHunch', qualityType.item,
+      'Hallucination Hunch'
+      'Regenerates at the start of each day.'
+      value: 1
+
+    quality 'hypnotismHunch', qualityType.item,
+      'Hypnotism Hunch'
+      'Regenerates at the start of each day.'
+      value: 1
+
+    quality 'blueback', qualityType.item,
+      'Blueback'
+      'Magical counterfeit-proof bills. They\'re actually more of an iridescent black.'
+
+    quality 'cantripUp', qualityType.item,
+      'Cantrip-Up'
+      'The beverage of mages. Contains concentrated warpweft that mildly enhances magical powers.'
+
+    quality 'rumor', qualityType.item,
+      'Rumor'
+      'Good, old-fashioned gossip. Juicy secrets that lose their value once spread.'
+
+    quality 'cagedDemon', qualityType.item,
+      'Caged Demon'
+      'Demonology is illegal, but harvesting these from old battlefields is a public service.'
+
+    quality 'origin',
+      () -> "You were #{@value}"
+      'Origin'
+      (origin) ->
+        switch origin
+          when origins.illusionist
+            'Gives you 1 more Illusion Hunch each day.'
+          when origins.hallucinist
+            'Gives you 1 more Hallucination Hunch each day.'
+          when origins.hypnotist
+            'Gives you 1 more Hypnotism Hunch each day.'

     return

   .run (qbnEdsl) ->
-    {storylet, choice, front, retreat, onwards, reqs, consq} = qbnEdsl
+    {storylet, start, choice, front, retreat, onwards, reqs, consq} = qbnEdsl

     retreat choice 'retreat',
       'On second thought, maybe not…'
@@ -52,9 +74,7 @@
       'The story continues…'

     ## Intro
-
-    front choice 'lets-begin',
-      'Begin the Story'
+    start 'lets-begin'

     storylet 'lets-begin',
       'It was a dark and stormy decade…'
@@ -81,20 +101,44 @@

     beginSnippet =
       '''
-      Ah, yes, that was it. Anyway, that's all over now. The war left you without a scrap of magic
-      to your name, just a strange itch whenever you were in the presence of your old field of work.
+      Yes, that was it. Anyway, that's all over now. The war left you without a scrap of magic
+      to your name, just a strange itch whenever you're in the presence of your old field of work.
       But you, you were enterprising. You parleyed that subliminal itch, that instinct about magic,
       into a career as a detective. When people have problems that seem magical in nature, they come
       to you. You are The Disillusionist.
       '''
     beginChoice =
-      choice 'begin-case'
+      choice 'begin-case',
+        'Tell me about my latest case.'

     storylet 'begin-illusion',
       'Ah, Illusion'
-      '''
-      The acrid smell of spellcraft was in the air, something you rarely enoucntered outside your
-      own home.
+      beginSnippet
+      consequences:
+        origin: consq.set origins.illusionist
+      choices: [beginChoice]
+
+    storylet 'begin-hallucination',
+      'Ah, Hallucination'
+      beginSnippet
+      consequences:
+        origin: consq.set origins.hallucinist
+      choices: [beginChoice]
+
+    storylet 'begin-hypnotism',
+      'Ah, Hypnotism'
+      beginSnippet
+      consequences:
+        origin: consq.set origins.hypnotist
+      choices: [beginChoice]
+
+    storylet 'begin-case',
+      'It Was Late on a Tuesday…'
+      '''
+      It was late on a Tuesday when Mrs. Abigail Brown walked into your office. Immediately, you
+      knew this wasn't the usual cheating-husband job. There was a tear to her eye before she even
+      got in your door, not the mixture of determination and shame that eventually gave way to
+      either sobbing or rage.
       '''

     return


Scrolled to bottom when focusing on textbox

--- src/commentList.coffee
+++ src/commentList.coffee
@@ -9,14 +9,8 @@
   Meteor.subscribe 'comments', series: series

 TemplateClass.rendered = ->
-  $commentList = @$('.comment-list')
-  $items = $('.items', $commentList)
-  $innerItems = $('.inner-items', $items)
-  scrollToBottom = _.debounce ->
-    $items.scrollTop $innerItems.height()
-  , 300
-  Collections.observe getCursor(), scrollToBottom
-  scrollToBottom()
+  Collections.observe getCursor(), delayedScrollToBottom.bind(@, @)
+  delayedScrollToBottom(@)

 TemplateClass.helpers
   items: -> getCursor()
@@ -25,6 +19,16 @@

 TemplateClass.events
   'click a.login': -> Router.go('login')
+  'focus .comment.form': (e, template) -> delayedScrollToBottom(template)
+
+scrollToBottom = (template) ->
+  template = getTemplate(template)
+  $commentList = @$('.comment-list')
+  $items = $('.items', $commentList)
+  $innerItems = $('.inner-items', $items)
+  $items.scrollTop $innerItems.height()
+
+delayedScrollToBottom = _.debounce scrollToBottom, 300

 getCursor = -> Comments.find series: getTemplate().data.series
 getTemplate = (template) -> Templates.getNamedInstance(templateName, template)


Get the window stuff loaded up top.

Get the window stuff loaded up top.

Is there a reason we had it being loaded at the bottom?

--- src/startup.coffee
+++ src/startup.coffee
@@ -12,6 +12,7 @@
 Project = require 'project'
 Settings = require 'settings'
 Storage = require 'storage'
+require 'window'

 atom.event = new Event
 # atom.on, atom.off, etc.
@@ -38,5 +39,4 @@
 else
   throw "I DON'T KNOW ABOUT #{path}"

-require 'window'
 window.startup()


SocialWorker: add isApiTokenEnabled field and setApiTokenAvailability method

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -244,6 +244,10 @@
           (signature String, String, Function)
         setPlan:
           (signature String, Function)
+        setApiTokenAvailability: [
+          (signature Object, Function)
+          (signature Object, Object, Function)
+        ]
     schema          :
       title         :
         type        : String
@@ -302,6 +306,8 @@
       initalData    : Object
       # Generic config object for future requirements on groups ~ GG
       config        : Object
+      # Api token can be disabled or enabled for the group
+      isApiTokenEnabled : Boolean

     broadcastableRelationships : [
       'member', 'moderator', 'admin'
@@ -1518,3 +1524,20 @@
       return callback null, accounts

+  setApiTokenAvailability: (options, callback) ->
+
+    { isApiTokenEnabled } = options
+    unless isApiTokenEnabled
+      return callback new KodingError 'isApiTokenEnabled is a required field'
+
+    query = { $set : { isApiTokenEnabled } }
+    @update query, callback
+
+
+  setApiTokenAvailability$: permit
+    advanced: PERMISSION_EDIT_GROUPS
+    success: (client, options, callback) ->
+      @setApiTokenAvailability options, callback
+
+
+


 Merge branch 'master.groupDeletion.removeAdminDeletion' into 'master'

Groups: removed group deletion with admin rights.

Earlier this week, I added a feature to allow to delete groups by Koding admins. (This allows deleting koding group itself.)

I'm removing this to prevent accidents.

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1254,8 +1254,7 @@
     @fetchOwner (err, owner)=>
       return callback err if err
       unless owner.getId().equals client.connection.delegate.getId()
-        unless client.connection.delegate.can "reset groups"
-          return callback new KodingError 'You must be the owner to perform this action!'
+        return callback new KodingError 'You must be the owner to perform this action!'

       removeHelper = (model, err, callback, queue)->
         return callback err if err


replace dash -> async, next -> fin

replace dash -> async, next -> fin

--- workers/social/lib/social/render/scriptblock.coffee
+++ workers/social/lib/social/render/scriptblock.coffee
@@ -1,7 +1,7 @@
 # coffeelint: disable=cyclomatic_complexity
 module.exports = (options = {}, callback) ->

-  { dash }  = require 'bongo'
+  async     = require 'async'
   encoder   = require 'htmlencode'
   { argv }  = require 'optimist'

@@ -86,14 +86,14 @@

   queue = [

-    (next) ->
+    (fin) ->
       socialApiCacheFn = require '../cache/socialapi'
       socialApiCacheFn options, (err, data) ->
         console.error 'could not get prefetched data', err  if err
         socialapidata = data
-        next()
+        fin()

-    (next) ->
+    (fin) ->
       groupName = session?.groupName or 'koding'

       # due to some reason, I suspect JSON.stringify somewhere, undefined
@@ -106,34 +106,34 @@

         currentGroup = group  if group

-        next()
+        fin()

-    (next) ->
+    (fin) ->
       bongoModels.JWorkspace.fetchByMachines$ client, (err, workspaces) ->
         console.log err  if err
         userWorkspaces = workspaces or []
-        next()
+        fin()

-    (next) ->
+    (fin) ->
       bongoModels.JMachine.some$ client, {}, (err, machines) ->
         console.log err  if err
         userMachines = machines or []
-        next()
+        fin()

-    (next) ->
+    (fin) ->
       bongoModels.Sidebar.fetchEnvironment client, (err, data) ->
         userEnvironmentData = data
-        next()
+        fin()

-    (next) ->
+    (fin) ->
       client.connection.delegate.fetchUser (err, user) ->
         if err
           console.error '[scriptblock] user not found', err
-          return next()
+          return fin()

         if user then userId = user.getId()
         else console.error '[scriptblock] user not found', err
-        next()
+        fin()
   ]

-  dash queue, -> callback null, createHTML(), socialapidata
+  async.parallel queue, -> callback null, createHTML(), socialapidata


Added friendlier error handling if server cannot start

--- src/timbits.coffee
+++ src/timbits.coffee
@@ -75,10 +75,15 @@
 				@add file.substring(0, file.lastIndexOf(".")), require("#{path}/#{file}")

 	# starts the server
-	@server.listen process.env.PORT || process.env.C9_PORT || config.port
-	log.info "Timbits server listening on port #{@server.address().port} in #{@server.settings.env} mode"
-	server.address = @server.address().address
-	server.port = @server.address().port
+	try
+		@server.listen process.env.PORT || process.env.C9_PORT || config.port
+		log.info "Timbits server listening on port #{@server.address().port} in #{@server.settings.env} mode"
+		server.address = @server.address().address
+		server.port = @server.address().port
+	catch err
+		log.error "Server could not start on port #{process.env.PORT || process.env.C9_PORT || config.port}. (#{err})"
+		console.log "\nPress Ctrl+C to Exit"
+		process.kill process.pid, 'SIGTERM'
 	@server

 # the box that holds each of the individual timbits created


Update mouse to work with version 0.3.4

Update mouse to work with version 0.3.4

--- source/scripts/utils/mouse.coffee
+++ source/scripts/utils/mouse.coffee
@@ -9,12 +9,14 @@
 mouse = new Mouse
   parent: 'section.tasks'
   query: '.task'
-  offsetY: -31
-  offsetX: 0
-  helper: (elements) ->
-    length = elements.length
-    return "Moving #{ length } task#{ if length > 1 then 's' else ''}"
-
+  select: true
+  sort: true
+  drag:
+    offsetY: -31
+    offsetX: 0
+    helper: (elements) ->
+      length = elements.length
+      return "Moving #{ length } task#{ if length > 1 then 's' else ''}"

 ###*
  * DROPPABLES


support property extraction in takeWhile

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -136,6 +136,7 @@
       else
         Bacon.more
   takeWhile: (f) ->
+    f = toExtractor(f)
     @withHandler (event) ->
       if event.filter(f)
         @push event


Remove unnecessary Bacon namespace usage in fromPromise

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -15,7 +15,7 @@
 Bacon = @Bacon = {}

 Bacon.fromPromise = (promise) ->
-  new Bacon.EventStream(
+  new EventStream(
     (sink) ->
       onSuccess = (value) ->
         sink next(value)


Groups: Uppercase button name.

Groups: Uppercase button name.

--- client/Pricing/AppView.coffee
+++ client/Pricing/AppView.coffee
@@ -79,7 +79,7 @@
       callback              : @bound "createGroup"
       buttons               :
         Create              :
-          title             : "Create"
+          title             : "CREATE"
           type              : "submit"
           style             : "solid green"
       fields                :


AdminModal: Use new AdminInvitationsView.

--- client/admin/lib/index.coffee
+++ client/admin/lib/index.coffee
@@ -7,8 +7,8 @@
 CustomViewsManager        = require './views/customviews/customviewsmanager'
 GroupStackSettings        = require './views/groupstacksettings'
 OnboardingAdminView       = require './views/onboarding/onboardingadminview'
+AdminInvitationsView      = require './views/invitations/admininvitationsview'
 GroupPermissionsView      = require './views/grouppermissionsview'
-GroupsInvitationView      = require './views/groupsinvitationview'
 GroupsBlockedUserView     = require './views/groupsblockeduserview'
 GroupGeneralSettingsView  = require './views/groupgeneralsettingsview'

@@ -26,19 +26,18 @@
       title    : 'Team Settings'
       items    : [
         { slug : 'Settings',       title : 'Settings',          viewClass : GroupGeneralSettingsView }
-        { slug : 'Members',        title : 'Members',           viewClass : AdminMembersView }
-      # { slug : 'Policies',       title : 'Membership Policy', viewClass : kd.View }
-        { slug : 'Invitations',    title : 'Invitations',       viewClass : GroupsInvitationView }
-        { slug : 'Permissions',    title : 'Permissions',       viewClass : GroupPermissionsView }
-        { slug : 'Stacks',         title : 'Compute Stacks',    viewClass : GroupStackSettings }
+        { slug : 'Members',        title : 'Members',           viewClass : AdminMembersView         }
+        { slug : 'Invitations',    title : 'Invitations',       viewClass : AdminInvitationsView     }
+        { slug : 'Permissions',    title : 'Permissions',       viewClass : GroupPermissionsView     }
+        { slug : 'Stacks',         title : 'Compute Stacks',    viewClass : GroupStackSettings       }
       ]
     koding     :
       title    : 'Koding Administration'
       items    : [
-        { slug : 'Blocked',        title : 'Blocked Users',     viewClass : GroupsBlockedUserView }
-        { slug : 'Widgets',        title : 'Custom Views',      viewClass : CustomViewsManager }
-        { slug : 'Onboarding',     title : 'Onboarding',        viewClass : OnboardingAdminView }
-        { slug : 'Administration', title : 'Administration',    viewClass : AdministrationView }
+        { slug : 'Blocked',        title : 'Blocked Users',     viewClass : GroupsBlockedUserView    }
+        { slug : 'Widgets',        title : 'Custom Views',      viewClass : CustomViewsManager       }
+        { slug : 'Onboarding',     title : 'Onboarding',        viewClass : OnboardingAdminView      }
+        { slug : 'Administration', title : 'Administration',    viewClass : AdministrationView       }
       ]


configurable recurry

configurable recurry

--- src/recurry.coffee
+++ src/recurry.coffee
@@ -22,7 +22,7 @@
   ascii     = require('easy-table')

   recurry =
-    url: ( if process.env.DEBUG then "http://localhost:3333" else "http://lb.recurry.2webapp.com")
+    url: ( if process.env.RECURRY_URL then process.env.RECURRY_URL else "http://localhost:3333")
     usage:
       setscheduler: "Usage: recurry setscheduler <id> <phrase>\n\n
 Example: recurry setscheduler 12 every 5 mins\n\nphrases: \n


Changed the "Change Course" and "Register for Course" to "Change Section" and "Register for Section" respectively.

--- src/user/menu.cjsx
+++ src/user/menu.cjsx
@@ -53,9 +53,9 @@

   renderCourseOption: ->
     if @props.course?.isRegistered()
-      courseChangeText = 'Change Course'
+      courseChangeText = 'Change Section'
     else
-      courseChangeText = 'Register for Course'
+      courseChangeText = 'Register for Section'
     <BS.MenuItem onClick={@modifyCourse}>{courseChangeText}</BS.MenuItem>

   renderStudentIdOption: ->


Refactor rules for matching substitution references

--- grammars/restructuredtext.cson
+++ grammars/restructuredtext.cson
@@ -65,7 +65,7 @@
 			{include: "#emphasis"}
 			{include: "#link-target-inline"}
 			{include: "#interpreted-text"}
-			{include: "#substitution"}
+			{include: "#substitution-reference"}
 			{include: "#literal"}
 			{include: "#link-reference"}
 			{include: "#footnote"}
@@ -638,12 +638,43 @@

 	# Substitution reference: “|linked|_” or “|unlinked|”
-	substitution:
-		name: "support.variable.substitution.restructuredtext"
-		match: "(?<!\\\\)(\\|)[^|]+(?<!\\\\)(\\|_{0,2})"
+	"substitution-reference":
+		patterns: [
+			{include: "#substitution-reference-singleline"}
+			{include: "#substitution-reference-multiline"}
+		]
+
+	# Substitution names can be wrapped across lines (although not paragraph breaks),
+	# making this pattern problematic inside grid-tables and line-blocks. Hence why it's
+	# distinct from a more restrictive single-line variant so that multi-line substitutions
+	# can still be written inside paragraphs and similar block constructs.
+	"substitution-reference-multiline":
+		disabled: yes # TODO: Remove once the table rules have been refactored
+		name:  "meta.substitution-reference.restructuredtext"
+		begin: "(?:^|(?<=[-:/'\"<\x28\\\x5B{\\s«»༺⟬⟮⸠⸡⸢⸤⸦⸨‚„‟‛])|(?<![\\x00-\\x9F])(?<=[\\p{Ps}\\p{Pi}\\p{Pf}\\p{Pd}\\p{Po}]))(\\|)"
+		end:   "(?=^\\s*$)|(\\|)(?:(__)\\b|(_)\\b)?(?=$|[-.,:;!?\\\\/'\"\x29\\\x5D}>\\s«»༻⟭⟯⸡⸠⸣⸥⸧⸩‚„‟‛]|(?![\\x00-\\x9F])[\\p{Pe}\\p{Pi}\\p{Pf}\\p{Pd}\\p{Po}])"
+		contentName: "entity.name.substitution.restructuredtext"
+		beginCaptures:
+			1: name: "punctuation.definition.substitution.start.restructuredtext"
+		endCaptures:
+			1: name: "punctuation.definition.substitution.end.restructuredtext"
+			2: name: "punctuation.definition.reference.anonymous.restructuredtext"
+			3: name: "punctuation.definition.reference.named.restructuredtext"
+
+	"substitution-reference-singleline":
+		name:  "meta.substitution-reference.restructuredtext"
+		match: """(?x)
+			(?:^|(?<=[-:/'\"<\x28\\\x5B{\\s«»༺⟬⟮⸠⸡⸢⸤⸦⸨‚„‟‛])|(?<![\\x00-\\x9F])(?<=[\\p{Ps}\\p{Pi}\\p{Pf}\\p{Pd}\\p{Po}]))
+			(\\|)(?=[^|\\s])(.+?)(?<!\\s)(\\|)
+			(?:(__)\\b|(_)\\b)?
+			(?=$|[-.,:;!?\\\\/'\"\x29\\\x5D}>\\s«»༻⟭⟯⸡⸠⸣⸥⸧⸩‚„‟‛]|(?![\\x00-\\x9F])[\\p{Pe}\\p{Pi}\\p{Pf}\\p{Pd}\\p{Po}])
+		"""
 		captures:
-			1: name: "punctuation.definition.substitution.restructuredtext"
-			2: name: "punctuation.definition.substitution.restructuredtext"
+			1: name: "punctuation.definition.substitution.start.restructuredtext"
+			2: name: "entity.name.substitution.restructuredtext"
+			3: name: "punctuation.definition.substitution.end.restructuredtext"
+			4: name: "punctuation.definition.reference.anonymous.restructuredtext"
+			5: name: "punctuation.definition.reference.named.restructuredtext"

 	"substitution-definition":
@@ -652,7 +683,7 @@
 			# Image substitution – “.. |foo| image:: ./path/to/image.png”
 			{
 				name: "meta.substitution-definition.image.restructuredtext"
-				begin: "^(\\s*)(\\.\\.)\\s(\\|)(?=\\S)([^\\|]+)((?<=\\S)\\|)\\s+(image)(::)\\s*(\\S+)"
+				begin: "^(\\s*)(\\.\\.)\\s+(\\|)(?=[^|\\s])(.+?)((?<=\\S)\\|)\\s+(image)(::)\\s*(\\S+)"
 				end:   "^(?!\\s*$|\\1[ \\t]+\\S)"
 				patterns: [include: "#image-options"]
 				beginCaptures:
@@ -669,7 +700,7 @@
 			# Generic/custom definition – “.. |foo| something else:: …”
 			{
 				name: "meta.substitution-definition.restructuredtext"
-				begin: "^(\\s*)(\\.\\.)\\s(\\|)(?=\\S)([^\\|]+)((?<=\\S)\\|)\\s+(\\S+.*(?=::))(::)(.*)"
+				begin: "^(\\s*)(\\.\\.)\\s+(\\|)(?=[^|\\s])(.+?)((?<=\\S)\\|)\\s+(\\S+.*(?=::))(::)(.*)"
 				end:   "^(?!\\s*$|\\1[ \\t]+\\S)"
 				patterns: [include: "#directive-options"]
 				beginCaptures:


Adds /system/up route

Adds /system/up route

--- client/lib/setup/index.coffee
+++ client/lib/setup/index.coffee
@@ -28,6 +28,10 @@

   # Override Backbone to use server-side sync
   Backbone.sync = require 'backbone-super-sync'
+
+  # Route to ping for system up
+  app.get '/system/up', (req, res) ->
+    res.send 200, { nodejs: true }

   # Mount generic middleware & run setup modules
   if 'production' is NODE_ENV