fixed coffeelint errors on workers/social/lib/social/models/group/index.coffee

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1,27 +1,27 @@
-{Module}     = require 'jraphical'
-{difference} = require 'underscore'
+{ Module }     = require 'jraphical'
+{ difference } = require 'underscore'

 module.exports = class JGroup extends Module

   [ERROR_UNKNOWN, ERROR_NO_POLICY, ERROR_POLICY] = [403010, 403001, 403009]

-  {Relationship} = require 'jraphical'
-
-  {Inflector, ObjectId, ObjectRef, secure, daisy, race, dash, signature} = require 'bongo'
+  { Relationship } = require 'jraphical'
+
+  { Inflector, ObjectId, ObjectRef, secure, daisy, race, dash, signature } = require 'bongo'

   JPermissionSet = require './permissionset'
-  {permit}       = JPermissionSet
+  { permit }     = JPermissionSet

   JAccount     = require '../account'
   JPaymentPack = require '../payment/pack'

   KodingError    = require '../../error'
   Validators     = require './validators'
-  {throttle, extend}     = require 'underscore'
+  { throttle, extend }     = require 'underscore'

   PERMISSION_EDIT_GROUPS = [
-    {permission: 'edit groups'}
-    {permission: 'edit own groups', validateWith: Validators.own}
+    { permission: 'edit groups' }
+    { permission: 'edit own groups', validateWith: Validators.own }
   ]

   @trait __dirname, '../../traits/filterable'
@@ -39,24 +39,24 @@
     slugifyFrom     : 'slug'
     slugTemplate    : '#{slug}'
     feedable        : no
-    memberRoles     : ['admin','moderator','member','guest']
+    memberRoles     : ['admin', 'moderator', 'member', 'guest']
     permissions     :
       'grant permissions'                 : []
-      'open group'                        : ['member','moderator']
+      'open group'                        : ['member', 'moderator']
       'list members'                      :
         public                            : ['moderator', 'member']
         private                           : ['moderator', 'member']
       'read group activity'               :
-        public                            : ['guest','member','moderator']
-        private                           : ['member','moderator']
+        public                            : ['guest', 'member', 'moderator']
+        private                           : ['member', 'moderator']
       'create groups'                     : ['moderator']
       'edit groups'                       : ['moderator']
-      'edit own groups'                   : ['member','moderator']
-      'query collection'                  : ['member','moderator']
+      'edit own groups'                   : ['member', 'moderator']
+      'query collection'                  : ['member', 'moderator']
       'update collection'                 : ['moderator']
       'assure collection'                 : ['moderator']
       'remove documents from collection'  : ['moderator']
-      'view readme'                       : ['guest','member','moderator']
+      'view readme'                       : ['guest', 'member', 'moderator']
       'send invitations'                  : ['moderator']

       # those are for messages
@@ -230,7 +230,7 @@
       slug          :
         type        : String
         validate    : require('../name').validateName
-        set         : (value)-> value.toLowerCase()
+        set         : (value) -> value.toLowerCase()
       privacy       :
         type        : String
         enum        : ['invalid privacy type', [
@@ -277,69 +277,73 @@
       'member', 'moderator', 'admin'
       'owner', 'tag', 'role'
     ]
-    relationships   : ->
-      JAccount     = require '../account'
-
-      bundle        :
-        targetType  : 'JGroupBundle'
-        as          : 'owner'
-      permissionSet :
-        targetType  : JPermissionSet
-        as          : 'permset'
-      defaultPermissionSet:
-        targetType  : JPermissionSet
-        as          : 'defaultpermset'
-      member        :
-        targetType  : JAccount
-        as          : 'member'
-      moderator     :
-        targetType  : JAccount
-        as          : 'moderator'
-      admin         :
-        targetType  : JAccount
-        as          : 'admin'
-      owner         :
-        targetType  : JAccount
-        as          : 'owner'
-      subgroup      :
-        targetType  : 'JGroup'
-        as          : 'parent'
-      tag           :
-        targetType  : 'JTag'
-        as          : 'tag'
-      role          :
-        targetType  : 'JGroupRole'
-        as          : 'role'
-      membershipPolicy :
-        targetType  : 'JMembershipPolicy'
-        as          : 'owner'
-      invitation:
-        targetType  : 'JInvitation'
-        as          : 'owner'
-      paymentMethod :
-        targetType  : 'JPaymentMethod'
-        as          : 'linked payment method'
-      product       :
-        targetType  : 'JPaymentProduct'
-        as          : 'product'
-      pack          :
-        targetType  : 'JPaymentPack'
-        as          : 'product pack'
-      plan          :
-        targetType  : 'JPaymentPlan'
-        as          : 'group plan'
-      subscription  :
-        targetType  : 'JPaymentSubscription'
-        as          : 'payment plan subscription'
-      credential    :
-        as          : ['owner', 'user']
-        targetType  : 'JCredential'
-
-
-  constructor:->
+    relationships : ->
+      JAccount = require '../account'
+
+      return {
+        bundle        :
+          targetType  : 'JGroupBundle'
+          as          : 'owner'
+        permissionSet :
+          targetType  : JPermissionSet
+          as          : 'permset'
+        defaultPermissionSet:
+          targetType  : JPermissionSet
+          as          : 'defaultpermset'
+        member        :
+          targetType  : JAccount
+          as          : 'member'
+        moderator     :
+          targetType  : JAccount
+          as          : 'moderator'
+        admin         :
+          targetType  : JAccount
+          as          : 'admin'
+        owner         :
+          targetType  : JAccount
+          as          : 'owner'
+        subgroup      :
+          targetType  : 'JGroup'
+          as          : 'parent'
+        tag           :
+          targetType  : 'JTag'
+          as          : 'tag'
+        role          :
+          targetType  : 'JGroupRole'
+          as          : 'role'
+        membershipPolicy :
+          targetType  : 'JMembershipPolicy'
+          as          : 'owner'
+        invitation:
+          targetType  : 'JInvitation'
+          as          : 'owner'
+        paymentMethod :
+          targetType  : 'JPaymentMethod'
+          as          : 'linked payment method'
+        product       :
+          targetType  : 'JPaymentProduct'
+          as          : 'product'
+        pack          :
+          targetType  : 'JPaymentPack'
+          as          : 'product pack'
+        plan          :
+          targetType  : 'JPaymentPlan'
+          as          : 'group plan'
+        subscription  :
+          targetType  : 'JPaymentSubscription'
+          as          : 'payment plan subscription'
+        credential    :
+          as          : ['owner', 'user']
+          targetType  : 'JCredential'
+      }
+
+
+  # due to a bug in coffeelint 1.10.1
+  # coffeelint: disable=no_implicit_braces
+  constructor: ->
     super

-    @on 'MemberAdded', (member)->
+    @on 'MemberAdded', (member) ->
       @constructor.emit 'MemberAdded', { group: this, member }
       unless @slug is 'guests'
         @sendNotificationToAdmins 'GroupJoined',
@@ -350,7 +354,7 @@
         @broadcast 'MemberJoinedGroup',
           member : ObjectRef(member).data

-    @on 'MemberRemoved', (member)->
+    @on 'MemberRemoved', (member) ->
       @constructor.emit 'MemberRemoved', { group: this, member }
       unless @slug is 'guests'
         @sendNotificationToAdmins 'GroupLeft',
@@ -361,7 +365,7 @@
         @broadcast 'MemberLeftGroup',
           member : ObjectRef(member).data

-    @on 'MemberRolesChanged', (member)->
+    @on 'MemberRolesChanged', (member) ->
       @constructor.emit 'MemberRolesChanged', { group: this, member }

   @render        :
@@ -389,7 +393,7 @@
       JName                 = require '../name'
       group                 = new this groupData
       group.privacy         = 'private'
-      defaultPermissionSet  = new JPermissionSet {}, {privacy: group.privacy}
+      defaultPermissionSet  = new JPermissionSet {}, { privacy: group.privacy }
       { sessionToken }      = client

       queue = [
@@ -470,8 +474,8 @@

       daisy queue

-  @create$ = secure (client, formData, callback)->
-    {delegate} = client.connection
+  @create$ = secure (client, formData, callback) ->
+    { delegate } = client.connection

     # subOptions = targetOptions: selector: tags: "custom-plan"
     # delegate.fetchSubscription null, subOptions, (err, subscription) =>
@@ -485,8 +489,8 @@
       #   return callback err  if err
       callback null, { group }

-  @findSuggestions = (client, seed, options, callback)->
-    {limit, blacklist, skip}  = options
+  @findSuggestions = (client, seed, options, callback) ->
+    { limit, blacklist, skip }  = options

     @some
       title      : seed
@@ -501,20 +505,20 @@

   # currently groups in a group show global groups, so it does not
   # make sense to allow this method based on current group's permissions
-  @byRelevance$ = secure (client, seed, options, callback)->
+  @byRelevance$ = secure (client, seed, options, callback) ->
     @byRelevance client, seed, options, callback

-  @fetchSecretChannelName =(groupSlug, callback)->
+  @fetchSecretChannelName = (groupSlug, callback) ->
     JName = require '../name'
-    JName.fetchSecretName groupSlug, (err, secretName, oldSecretName)->
+    JName.fetchSecretName groupSlug, (err, secretName, oldSecretName) ->
       if err then callback err
       else callback null, "group.secret.#{secretName}",
         if oldSecretName then "group.secret.#{oldSecretName}"

-  @cycleChannel =do->
-    cycleChannel = (groupSlug, callback=->)->
+  @cycleChannel = do ->
+    cycleChannel = (groupSlug, callback = -> ) ->
       JName = require '../name'
-      JName.cycleSecretName groupSlug, (err, oldSecretName, newSecretName)=>
+      JName.cycleSecretName groupSlug, (err, oldSecretName, newSecretName) =>
         if err then callback err
         else
           routingKey = "group.secret.#{oldSecretName}.cycleChannel"
@@ -522,15 +526,15 @@
           callback null
     return throttle cycleChannel, 5000

-  cycleChannel:(callback)-> @constructor.cycleChannel @slug, callback
-
-  @broadcast =(groupSlug, event, message)->
+  cycleChannel:(callback) -> @constructor.cycleChannel @slug, callback
+
+  @broadcast = (groupSlug, event, message) ->
     if message?
       event = ".#{event}"
     else
       [message, event] = [event, message]
       event = ''
-    @fetchSecretChannelName groupSlug, (err, secretChannelName, oldSecretChannelName)=>
+    @fetchSecretChannelName groupSlug, (err, secretChannelName, oldSecretChannelName) =>
       if err? then console.error err
       else unless secretChannelName? then console.error 'unknown channel'
       else
@@ -542,15 +546,15 @@
           event       : 'feed-new'
         }

-  broadcast:(message, event)->
+  broadcast:(message, event) ->
     @constructor.broadcast @slug, message, event

   changeMemberRoles: permit 'grant permissions',
-    success:(client, targetId, roles, callback)->
+    success:(client, targetId, roles, callback) ->
       remove = []
       sourceId = @getId()
       roles.push 'member'  unless 'member' in roles
-      Relationship.some {targetId, sourceId}, {}, (err, rels)->
+      Relationship.some { targetId, sourceId }, {}, (err, rels) ->
         return callback err  if err

         for rel in rels
@@ -558,27 +562,27 @@
           else remove.push rel._id

         if remove.length > 0
-          Relationship.remove _id: $in: remove, (err)-> console.log 'removed'; callback err  if err
-
-        queue = roles.map (role)->->
+          Relationship.remove _id: $in: remove, (err) -> console.log 'removed'; callback err  if err
+
+        queue = roles.map (role) -> ->
           (new Relationship
             targetName  : 'JAccount'
             targetId    : targetId
             sourceName  : 'JGroup'
             sourceId    : sourceId
             as          : role
-          ).save (err)->
+          ).save (err) ->
             callback err  if err
             queue.fin()
         dash queue, callback

-  addDefaultRoles:(callback)->
+  addDefaultRoles:(callback) ->
     group = this
     JGroupRole = require './role'
-    JGroupRole.all {isDefault: yes}, (err, roles)->
+    JGroupRole.all { isDefault: yes }, (err, roles) ->
       if err then callback err
       else
-        queue = roles.map (role)->->
+        queue = roles.map (role) -> ->
           group.addRole role, queue.fin.bind queue
         dash queue, callback

@@ -591,27 +595,27 @@

     # even if incoming email doesnt have a @ in it, whole string will be taken
     # into consideration as domain name
-    domain = email.substring email.indexOf("@")+1 # get the part after @
+    domain = email.substring email.indexOf('@') + 1 # get the part after @

     return domain in @allowedDomains

   updatePermissions: permit 'grant permissions',
-    success:(client, permissions, callback=->)->
-      @fetchPermissionSet (err, permissionSet)=>
+    success:(client, permissions, callback = -> ) ->
+      @fetchPermissionSet (err, permissionSet) =>
         return callback err if err
         if permissionSet
-          permissionSet.update $set:{permissions}, callback
+          permissionSet.update $set:{ permissions }, callback
         else
-          permissionSet = new JPermissionSet {permissions, isCustom: true}
+          permissionSet = new JPermissionSet { permissions, isCustom: true }
           permissionSet.save (err) =>
             return callback err if err
-            @addPermissionSet permissionSet, (err)->
+            @addPermissionSet permissionSet, (err) ->
               return callback err if err
               console.log 'permissionSet is added'
               callback null

-  fetchPermissions:do->
-    fixDefaultPermissions_ =(model, permissionSet, callback)->
+  fetchPermissions:do ->
+    fixDefaultPermissions_ = (model, permissionSet, callback) ->
       # It was lately recognized that we needed to have a default permission
       # set that is created at the time of group creation, because other
       # permissions may be roled out over time, and it is best to be secure by
@@ -620,25 +624,25 @@
       # to underprivileged roles.  We will create this group's "default
       # permissions" by cloning the group's current permission set. C.T.
       defaultPermissionSet = permissionSet.clone()
-      defaultPermissionSet.save (err)->
+      defaultPermissionSet.save (err) ->
         if err then callback err
-        else model.addDefaultPermissionSet defaultPermissionSet, (err)->
+        else model.addDefaultPermissionSet defaultPermissionSet, (err) ->
           if err then callback err
           else callback null, defaultPermissionSet

     fetchPermissions = permit 'grant permissions',
-      success:(client, callback)->
-        {permissionsByModule} = require '../../traits/protected'
-        {delegate}            = client.connection
+      success:(client, callback) ->
+        { permissionsByModule } = require '../../traits/protected'
+        { delegate }            = client.connection
         permissionSet         = null
         defaultPermissionSet  = null
         daisy queue = [
-          => @fetchPermissionSet (err, model)->
+          => @fetchPermissionSet (err, model) ->
               if err then callback err
               else
                 permissionSet = model
                 queue.next()
-          => @fetchDefaultPermissionSet (err, model)=>
+          => @fetchDefaultPermissionSet (err, model) =>
               if err then callback err
               else if model?
                 console.log 'already had defaults'
@@ -647,7 +651,7 @@
                 queue.next()
               else
                 console.log 'needed defaults fixed'
-                fixDefaultPermissions_ this, permissionSet, (err, newModel)->
+                fixDefaultPermissions_ this, permissionSet, (err, newModel) ->
                   defaultPermissionSet = newModel
                   queue.next()
           -> callback null, {
@@ -657,26 +661,26 @@
             }
         ]

-  fetchRolesByAccount:(account, callback)->
+  fetchRolesByAccount:(account, callback) ->
     Relationship.someData {
       targetId: account.getId()
       sourceId: @getId()
-    }, {as:1}, (err, cursor)->
+    }, { as:1 }, (err, cursor) ->
       if err then callback err
       else
-        cursor.toArray (err, arr)->
+        cursor.toArray (err, arr) ->
           if err then callback err
           else
             roles = if arr.length > 0 then (doc.as for doc in arr) else ['guest']
             callback null, roles

-  fetchMyRoles: secure (client, callback)->
+  fetchMyRoles: secure (client, callback) ->
     @fetchRolesByAccount client.connection.delegate, callback

   fetchUserRoles: permit 'grant permissions',
-    success:(client, ids, callback)->
+    success:(client, ids, callback) ->
       [callback, ids] = [ids, callback]  unless callback
-      @fetchRoles (err, roles)=>
+      @fetchRoles (err, roles) =>
         roleTitles = (role.title for role in roles)
         selector = {
           targetName  : 'JAccount'
@@ -684,22 +688,22 @@
           as          : { $in: roleTitles }
         }
         selector.targetId = $in: ids  if ids
-        Relationship.someData selector, {as:1, targetId:1}, (err, cursor)->
+        Relationship.someData selector, { as:1, targetId:1 }, (err, cursor) ->
           if err then callback err
           else
-            cursor.toArray (err, arr)->
+            cursor.toArray (err, arr) ->
               if err then callback err
               else callback null, arr

   fetchUserStatus: permit 'grant permissions',
-    success:(client, nicknames, callback)->
+    success:(client, nicknames, callback) ->
       JUser    = require '../user'
-      JUser.someData username: $in: nicknames, {status:1, username:1}, (err, cursor) ->
+      JUser.someData username: $in: nicknames, { status:1, username:1 }, (err, cursor) ->
         return callback err  if err
         cursor.toArray callback

   fetchMembers$: permit 'list members',
-    success:(client, rest...)->
+    success:(client, rest...) ->
       # when max limit is over 20 it starts giving "call stack exceeded" error
       [selector, options, callback] = Module.limitEdges 10, 19, rest
       # delete options.targetOptions
@@ -707,7 +711,7 @@
       @fetchMembers selector, options, callback

   fetchAdmins$: permit 'list members',
-    success:(client, rest...)->
+    success:(client, rest...) ->
       # when max limit is over 20 it starts giving "call stack exceeded" error
       [selector, options, callback] = Module.limitEdges 10, 19, rest
       # delete options.targetOptions
@@ -715,7 +719,7 @@
       @fetchAdmins selector, options, callback

   fetchModerators$: permit 'list members',
-    success:(client, rest...)->
+    success:(client, rest...) ->
       # when max limit is over 20 it starts giving "call stack exceeded" error
       [selector, options, callback] = Module.limitEdges 10, 19, rest
       # delete options.targetOptions
@@ -727,9 +731,9 @@
   searchMembers: permit 'list members',
     success: (client, seed, options = {}, callback) ->
       cleanSeed = seed.replace(/[^\w\s-]/).trim()
-      seed = RegExp cleanSeed, "i"
-
-      names = seed.toString().split('/')[1].replace('^','').split ' '
+      seed = RegExp cleanSeed, 'i'
+
+      names = seed.toString().split('/')[1].replace('^', '').split ' '
       names.push names.first  if names.length is 1

       selector =
@@ -743,26 +747,26 @@
           # CtF null does not effect the results here, it only searches for registered ones.
           # probably jraphical problem, because the query correctly works in mongo

-      {limit, skip} = options
+      { limit, skip } = options
       options.sort  = 'meta.createdAt' : -1
       options.limit = Math.min limit ? 10, 15
       # CtF @fetchMembers first fetches all group-member relationships, and then filters accounts with found targetIds.
       # As a result searching groups with large number of members is very time consuming. For now the only group
       # with large member count is koding, so i have seperated it here. as a future work hopefully we will make
       # the search queries via elasticsearch.
-      if @slug is "koding"
+      if @slug is 'koding'
         JAccount = require '../account'
         JAccount.some selector, options, callback
       else
-        options.targetOptions = {options, selector}
+        options.targetOptions = { options, selector }

         @fetchMembers {}, options, callback

-  fetchHomepageView: (options, callback)->
-    {account, section} = options
+  fetchHomepageView: (options, callback) ->
+    { account, section } = options
     kallback = =>
-      @fetchMembershipPolicy (err, policy)=>
+      @fetchMembershipPolicy (err, policy) =>
         if err then callback err
         else
           homePageOptions = extend options, {
@@ -778,7 +782,7 @@
           JGroup.render[prefix].groupHome homePageOptions, callback

     if @visibility is 'hidden' and section isnt 'Invitation'
-      @isMember account, (err, isMember)->
+      @isMember account, (err, isMember) ->
         return callback err if err
         if isMember then kallback()
         else do callback
@@ -786,7 +790,7 @@
       kallback()

-  createMembershipPolicy:(requestType, queue, callback)->
+  createMembershipPolicy:(requestType, queue, callback) ->
     [callback, queue] = [queue, callback]  unless callback
     queue ?= []

@@ -795,18 +799,18 @@
     membershipPolicy.approvalEnabled = no  if requestType is 'by-invite'

     queue.push(
-      -> membershipPolicy.save (err)->
+      -> membershipPolicy.save (err) ->
         if err then callback err
         else queue.next()
-      => @addMembershipPolicy membershipPolicy, (err)->
+      => @addMembershipPolicy membershipPolicy, (err) ->
         if err then callback err
         else queue.next()
     )
     queue.push callback  if callback
     daisy queue

-  destroyMemebershipPolicy:(callback)->
-    @fetchMembershipPolicy (err, policy)->
+  destroyMemebershipPolicy:(callback) ->
+    @fetchMembershipPolicy (err, policy) ->
       if err then callback err
       else unless policy?
         callback new KodingError '404 Membership policy not found'
@@ -818,38 +822,38 @@
       { permission: 'edit own groups', validateWith: Validators.own }
       { permission: 'edit groups' }
     ]
-    success : (client, formData, callback)->
+    success : (client, formData, callback) ->
       # do not allow people to change there slugs
       delete formData.slug
       delete formData.slug_
-      @update {$set:formData}, callback
+      @update { $set:formData }, callback

   modifyMembershipPolicy: permit
     advanced: PERMISSION_EDIT_GROUPS
-    success: (client, formData, callback)->
-      @fetchMembershipPolicy (err, policy)->
+    success: (client, formData, callback) ->
+      @fetchMembershipPolicy (err, policy) ->
         if err then callback err
         else policy.update $set: formData, callback

   toggleFeature: permit 'grant permissions',
-    success:(client, options, callback)->
+    success:(client, options, callback) ->
       if not options.feature or not options.role or not options.operation
-        return callback {message:"request is not valid"}
+        return callback new KodingError 'request is not valid'

       @disabledFeatures = {}  unless @disabledFeatures
-      @disabledFeatures[options.role] =[]  unless @disabledFeatures[options.role]
-
-      if options.operation is "disable"
+      @disabledFeatures[options.role] = []  unless @disabledFeatures[options.role]
+
+      if options.operation is 'disable'
         if options.feature not in @disabledFeatures?[options.role]
           @disabledFeatures[options.role].push options.feature
           return @update callback
         else
-          return callback {message:"item is not in the list "}
+          return callback new KodingError 'item is not in the list '
       else

         if options.feature not in @disabledFeatures?[options.role]
-          return callback {message:"item is not in the list"}
+          return callback new KodingError 'item is not in the list'
         else
           ops = (feature for feature in @disabledFeatures?[options.role] when feature isnt options.feature)
           @disabledFeatures[options.role] = ops
@@ -857,9 +861,9 @@

   canEditGroup: permit 'grant permissions',
-    success: (client, callback)->
+    success: (client, callback) ->
       callback null, yes
-    failure: (client, callback)->
+    failure: (client, callback) ->
       callback null, no

@@ -868,8 +872,8 @@
   @canListMembers       = permit 'list members'

   canOpenGroup: permit 'open group',
-    failure:(client, callback)->
-      @fetchMembershipPolicy (err, policy)->
+    failure:(client, callback) ->
+      @fetchMembershipPolicy (err, policy) ->
         explanation = policy?.explain() ?
                       err?.message ?
                       'No membership policy!'
@@ -881,18 +885,18 @@
         callback clientError, no

-  isMember: (account, callback)->
-    return callback new Error "No account found!"  unless account
+  isMember: (account, callback) ->
+    return callback new KodingError 'No account found!'  unless account
     selector =
       sourceId  : @getId()
       targetId  : account.getId()
       as        : 'member'
-    Relationship.count selector, (err, count)->
+    Relationship.count selector, (err, count) ->
       if err then callback err
       else callback null, (if count is 0 then no else yes)

-  approveMember:(member, roles, callback)->
+  approveMember:(member, roles, callback) ->
     [callback, roles] = [roles, callback]  unless callback
     roles ?= ['member']

@@ -901,36 +905,36 @@
       @updateCounts()
       @emit 'MemberAdded', member  if 'member' in roles

-    queue = roles.map (role)=>=>
+    queue = roles.map (role) => =>
       @addMember member, role, queue.fin.bind queue

     # We were creating group member VMs here before
     # I've deleted them, ask me if you need more information ~ GG
-    dash queue, => kallback()
-
-  each:(selector, rest...)->
+    dash queue, -> kallback()
+
+  each:(selector, rest...) ->
     selector.visibility = 'visible'
     Module::each.call this, selector, rest...

-  fetchRolesHelper: (account, callback)->
+  fetchRolesHelper: (account, callback) ->
     client = connection: delegate : account
-    @fetchMyRoles client, (err, roles)=>
+    @fetchMyRoles client, (err, roles) =>
       if err then callback err
       else if 'member' in roles or 'admin' in roles
         callback null, roles
       else
         options = targetOptions:
           selector: { koding: username: account.profile.nickname }
-        @fetchInvitationRequest {}, options, (err, request)->
+        @fetchInvitationRequest {}, options, (err, request) ->
           if err then callback err
           else unless request? then callback null, ['guest']
           else callback null, ["invitation-#{request.status}"]

-  updateCounts:->
+  updateCounts: ->
     # remove this guest shit if required
-    if @getId().toString() is "51f41f195f07655e560001c1"
+    if @getId().toString() is '51f41f195f07655e560001c1'
       return

     Relationship.count
@@ -938,17 +942,17 @@
       targetName : 'JAccount'
       sourceId   : @getId()
       sourceName : 'JGroup'
-    , (err, count)=>
+    , (err, count) =>
       @update ($set: 'counts.members': count), ->

-  leave: secure (client, options, callback)->
+  leave: secure (client, options, callback) ->

     [callback, options] = [options, callback] unless callback

     if @slug in ['koding', 'guests']
       return callback new KodingError "It's not allowed to leave this group"

-    @fetchMyRoles client, (err, roles)=>
+    @fetchMyRoles client, (err, roles) =>
       return callback err if err

       if 'owner' in roles
@@ -956,33 +960,33 @@

       Joinable = require '../../traits/joinable'

-      kallback = (err)=>
+      kallback = (err) =>
         @updateCounts()
         @cycleChannel()
         callback err

-      queue = roles.map (role)=>=>
-        Joinable::leave.call this, client, {as:role}, (err)->
+      queue = roles.map (role) => =>
+        Joinable::leave.call this, client, { as:role }, (err) ->
           return kallback err if err
           queue.fin()

       dash queue, kallback

   kickMember: permit 'grant permissions',
-    success: (client, accountId, callback)->
-      {connection:{delegate}} = client
+    success: (client, accountId, callback) ->
+      { connection:{ delegate } } = client
       JAccount = require '../account'

       if @slug is 'koding'
         return callback new KodingError 'Koding group is mandatory'

-      JAccount.one _id:accountId, (err, account)=>
+      JAccount.one _id:accountId, (err, account) =>
         return callback err if err

         if client.connection.delegate.getId().equals account._id
           return callback new KodingError 'You cannot kick yourself, try leaving the group!'

-        @fetchRolesByAccount account, (err, roles)=>
+        @fetchRolesByAccount account, (err, roles) =>
           return callback err if err

           if 'owner' in roles
@@ -1005,8 +1009,8 @@
               groupName : client.context.group
             }, callback

-          queue = roles.map (role)=>=>
-            @removeMember account, role, (err)=>
+          queue = roles.map (role) => =>
+            @removeMember account, role, (err) =>
               return callback err  if err
               @updateCounts()
               @cycleChannel()
@@ -1015,10 +1019,10 @@
           dash queue, kallback

   transferOwnership: permit 'grant permissions',
-    success: (client, accountId, callback)->
+    success: (client, accountId, callback) ->
       JAccount = require '../account'

-      {delegate} = client.connection
+      { delegate } = client.connection
       if delegate.getId().equals accountId
         return callback new KodingError 'You cannot transfer ownership to yourself, concentrate and try again!'

@@ -1026,32 +1030,32 @@
         targetId: delegate.getId(),
         sourceId: @getId(),
         as      : 'owner'
-      }, (err, owner)=>
+      }, (err, owner) =>
         return callback err if err
         return callback new KodingError 'You must be the owner to perform this action!' unless owner

-        JAccount.one _id:accountId, (err, account)=>
+        JAccount.one _id:accountId, (err, account) =>
           return callback err if err

-          @fetchRolesByAccount account, (err, newOwnersRoles)=>
+          @fetchRolesByAccount account, (err, newOwnersRoles) =>
             return callback err if err

-            kallback = (err)=>
+            kallback = (err) =>
               @cycleChannel()
               @updateCounts()
               callback err

             # give rights to new owner
-            queue = difference(['member', 'admin'], newOwnersRoles).map (role)=>=>
-              @addMember account, role, (err)->
+            queue = difference(['member', 'admin'], newOwnersRoles).map (role) => =>
+              @addMember account, role, (err) ->
                 return kallback err if err
                 queue.fin()

-            dash queue, =>
+            dash queue, ->
               # transfer ownership
               owner.update $set: targetId: account.getId(), kallback

-  ensureUniquenessOfRoleRelationship:(target, options, fallbackRole, roleUnique, callback)->
+  ensureUniquenessOfRoleRelationship:(target, options, fallbackRole, roleUnique, callback) ->
     unless callback
       callback   = roleUnique
       roleUnique = no
@@ -1059,12 +1063,12 @@
     if 'string' is typeof options
       as = options
     else if options?.as
-      {as} = options
+      { as } = options
     else
       as = fallbackRole

     # remove this
-    if @getId().toString() is "51f41f195f07655e560001c1"
+    if @getId().toString() is '51f41f195f07655e560001c1'
       return callback null

     selector =
@@ -1076,71 +1080,71 @@
     unless roleUnique
       selector.targetId = target.getId()

-    Relationship.count selector, (err, count)->
+    Relationship.count selector, (err, count) ->
       if err then callback err
       else if count > 0 then callback new KodingError 'This relationship already exists'
       else callback null

   oldAddMember = @::addMember
-  addMember:(target, options, callback)->
-    @ensureUniquenessOfRoleRelationship target, options, 'member', (err)=>
+  addMember:(target, options, callback) ->
+    @ensureUniquenessOfRoleRelationship target, options, 'member', (err) =>
       if err then callback err
       else oldAddMember.call this, target, options, callback

   oldAddAdmin = @::addAdmin
-  addAdmin:(target, options, callback)->
-    @ensureUniquenessOfRoleRelationship target, options, 'admin', (err)=>
+  addAdmin:(target, options, callback) ->
+    @ensureUniquenessOfRoleRelationship target, options, 'admin', (err) =>
       if err then callback err
       else oldAddAdmin.call this, target, options, callback

   oldAddOwner = @::addOwner
-  addOwner:(target, options, callback)->
-    @ensureUniquenessOfRoleRelationship target, options, 'owner', yes, (err)=>
+  addOwner:(target, options, callback) ->
+    @ensureUniquenessOfRoleRelationship target, options, 'owner', yes, (err) =>
       if err then callback err
       else oldAddOwner.call this, target, options, callback

   remove_ = @::remove
-  remove: secure (client, callback)->
+  remove: secure (client, callback) ->
     JName = require '../name'

-    @fetchOwner (err, owner)=>
+    @fetchOwner (err, owner) =>
       return callback err if err
       unless owner.getId().equals client.connection.delegate.getId()
         return callback new KodingError 'You must be the owner to perform this action!'

-      removeHelper = (model, err, callback, queue)->
+      removeHelper = (model, err, callback, queue) ->
         return callback err if err
         return queue.next() unless model
-        model.remove (err)=>
+        model.remove (err) ->
           return callback err if err
           queue.next()

-      removeHelperMany = (klass, models, err, callback, queue)->
+      removeHelperMany = (klass, models, err, callback, queue) ->
         return callback err if err
         return queue.next() if not models or models.length < 1
         ids = (model._id for model in models)
-        klass.remove (_id: $in: ids), (err)->
+        klass.remove (_id: $in: ids), (err) ->
           return callback err if err
           queue.next()

       daisy queue = [
-        => JName.one name:@slug, (err, name)->
+        => JName.one name:@slug, (err, name) ->
           removeHelper name, err, callback, queue

-        => @fetchPermissionSet (err, permSet)->
+        => @fetchPermissionSet (err, permSet) ->
           removeHelper permSet, err, callback, queue

-        => @fetchDefaultPermissionSet (err, permSet)->
+        => @fetchDefaultPermissionSet (err, permSet) ->
           removeHelper permSet, err, callback, queue

-        => @fetchMembershipPolicy (err, policy)->
+        => @fetchMembershipPolicy (err, policy) ->
           removeHelper policy, err, callback, queue

-        => @fetchInvitations (err, requests)->
+        => @fetchInvitations (err, requests) ->
           JInvitation = require '../invitation'
           removeHelperMany JInvitation, requests, err, callback, queue

-        => @fetchTags (err, tags)->
+        => @fetchTags (err, tags) ->
           JTag = require '../tag'
           removeHelperMany JTag, tags, err, callback, queue

@@ -1148,15 +1152,15 @@
           @constructor.emit 'GroupDestroyed', this
           queue.next()

-        => remove_.call this, (err)->
+        => remove_.call this, (err) ->
           return callback err if err
           queue.next()

         -> callback null
       ]

-  sendNotificationToAdmins: (event, contents)->
-    @fetchAdmins (err, admins)=>
+  sendNotificationToAdmins: (event, contents) ->
+    @fetchAdmins (err, admins) =>
       unless err
         relationship =  {
           as         : event,
@@ -1173,14 +1177,14 @@
         contents[event]       = contents.member

         next = -> queue.next()
-        queue = admins.map (admin) =>=>
+        queue = admins.map (admin) => =>
           contents.recipient = admin
           @notify admin, event, contents, next

         daisy queue

-  @each$ = (selector, options, callback)->
+  @each$ = (selector, options, callback) ->
     selector.visibility = 'visible'
     @each selector, options, callback

@@ -1191,7 +1195,7 @@
       JPaymentSubscription.one _id: id, (err, subscription) =>
         @addSubscription subscription, callback

-  fetchPermissionSetOrDefault : (callback)->
+  fetchPermissionSetOrDefault : (callback) ->
     @fetchPermissionSet (err, permissionSet) =>
       callback err, null if err
       if permissionSet
@@ -1208,14 +1212,14 @@
         @socialApiAnnouncementChannelId
       }

-    @fetchOwner (err, owner)=>
+    @fetchOwner (err, owner) =>
       return callback err if err?
       unless owner
         return callback { message: "Owner not found for #{@slug} group" }
-      owner.createSocialApiId (err, socialApiId)=>
+      owner.createSocialApiId (err, socialApiId) =>
         return callback err if err?
         # required data for creating a channel
-        privacy = if @slug is "koding" then "public" else "private"
+        privacy = if @slug is 'koding' then 'public' else 'private'

         options =
           creatorId       : socialApiId
@@ -1224,7 +1228,7 @@
         @createGroupChannel client, options, (err, groupChannelId) =>
           return callback err if err?

-          @createAnnouncementChannel client, options, (err, announcementChannelId) =>
+          @createAnnouncementChannel client, options, (err, announcementChannelId) ->
             return callback err if err?

             return callback null, {
@@ -1235,23 +1239,23 @@
             }

-  createGroupChannel:(client, options, callback)->
-    options.name = "public"
-    options.varName = "socialApiChannelId"
-    options.typeConstant = "group"
+  createGroupChannel:(client, options, callback) ->
+    options.name = 'public'
+    options.varName = 'socialApiChannelId'
+    options.typeConstant = 'group'

     return @createSocialAPIChannel client, options, callback

-  createAnnouncementChannel:(client, options, callback)->
-    options.name = if @slug is "koding" then "changelog" else @slug
-    options.varName = "socialApiAnnouncementChannelId"
-    options.typeConstant = "announcement"
+  createAnnouncementChannel:(client, options, callback) ->
+    options.name = if @slug is 'koding' then 'changelog' else @slug
+    options.varName = 'socialApiAnnouncementChannelId'
+    options.typeConstant = 'announcement'

     return @createSocialAPIChannel client, options, callback

-  createSocialAPIChannel:(client, options, callback)->
-    {varName, name, typeConstant, creatorId, privacyConstant} = options
+  createSocialAPIChannel:(client, options, callback) ->
+    { varName, name, typeConstant, creatorId, privacyConstant } = options

     return callback null, @[varName]  if @[varName]

@@ -1262,14 +1266,14 @@
       typeConstant    : typeConstant
       privacyConstant : privacyConstant

-    {doRequest} = require '../socialapi/helper'
-    doRequest "createChannel", client, defaultChannel, (err, channel)=>
+    { doRequest } = require '../socialapi/helper'
+    doRequest 'createChannel', client, defaultChannel, (err, channel) =>
       return callback err if err

       op = $set:{}
       op.$set[varName] = channel.channel.id

-      @update op, (err)->
+      @update op, (err) ->
         return callback err if err
         return callback null, channel.id


social/group: add username info to event when user leave team

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -373,11 +373,13 @@
       requester ?= member
       @constructor.emit 'MemberRemoved', { group: this, member, requester }
       unless @slug is 'guests'
+        username = member.data.profile.nickname
         @sendNotification 'GroupLeft',
           actionType : 'groupLeft'
           actorType  : 'member'
           subject    : ObjectRef(this).data
           member     : ObjectRef(member).data
+          username   : username

   @render        :
     loggedIn     :


JGroup: setPlan: shouldn't allow one to set plan for koding group

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1086,6 +1086,10 @@

       TEAMPLANS = require '../computeproviders/teamplans'

+      if (@getAt 'slug') is 'koding'
+        return callback new KodingError \
+          'Setting a plan on koding is not allowed'
+
       { plan, overrides } = data

       if plan not in (plans = Object.keys(TEAMPLANS).concat 'noplan')


fixed a small issue in the image

fixed a small issue in the image

--- src/javascripts/views/attributes_view.coffee
+++ src/javascripts/views/attributes_view.coffee
@@ -61,7 +61,7 @@

     Image:

-      <input type="file" id="image' class='form-control">
+      <input type="file" id="image" class='form-control'>

For a great source of images that fit the Netrunner theme check out Thredya

@@ -82,7 +82,8 @@
   render: =>
     @$el.html(@template(@model.attributes))
     @$el.find("input, textarea").each (idx, el) =>
-      $(el).val(@model.get(el.id))
+      unless el.id == 'image'
+        $(el).val(@model.get(el.id))
     @$el.find('#unique').prop('checked', @model.get('unique'))
     @$el.find('.strength').hide() unless @hasStrength()
     @$el.find('.mu').hide() unless @hasMU()


lots of little bug fixes, revealed by unit testing

--- dom.coffee
+++ dom.coffee
@@ -167,6 +167,8 @@
 	hasChildNodes: () ->
 		@childNodes.length > 0
 	insertBefore: (newNode, refNode) ->
+		if not refNode?
+			return @appendChild(newNode)
 		if refNode.parentNode isnt @
 			throw Error "Cannot insertBefore a non-child."
 		if newNode.nodeType is Node.DOCUMENT_FRAGMENT_NODE
@@ -183,9 +185,12 @@
 				i = 0
 				for c in @childNodes
 					c._private.childIndex = i++
+		newNode
 	appendChild: (node) ->
+		if node == null
+			return
 		if node.nodeType is Node.DOCUMENT_FRAGMENT_NODE
-			# could be optimized to do a single splice
+			# TODO: could be optimized to do a single splice, if that was found to matter
 			for c in node.childNodes
 				@appendChild(c)
 		else
@@ -194,31 +199,35 @@
 			@childNodes.push node
 	removeChild: (node) ->
 		i = node._private.childIndex
-		if node.parentNode is @ and i > -1
+		if i > -1 and node.parentNode is @
 			node._private.parentNode = null
 			node._private.childIndex = -1
 			@childNodes.splice(i, 1)
+			# re-index all the children
 			i = 0
-			for c in @childNodes
+			for c in @childNodes # TODO: this could probably be done with more precision
 				c._private.childIndex = i++
 		else
 			throw Error "Cannot removeChild a non-child."
+		node
 	replaceChild: (newNode, oldNode) ->
 		if oldNode.parentNode isnt @
 			throw Error "Cannot replaceChild a non-child."
 		i = oldNode._private.childIndex
-		if i > -1
-			if newNode.nodeType is Node.DOCUMENT_FRAGMENT_NODE
-				# could be optimized to do a single splice
-				for c in @childNodes
-					@insertBefore(c, oldNode)
-				@removeChild(oldNode)
-			else
-				newNode._private.parentNode = @
-				newNode._private.childIndex = i
-				oldNode.parentNode = null
-				@childNodes.splice(i, 1, newNode)
+		if i < 0
+			throw Error "DOM tree corruption, childIndex is < 0"
+		if newNode.nodeType is Node.DOCUMENT_FRAGMENT_NODE
+			# TODO: could be optimized to do a single splice
+			for c in @childNodes
+				@insertBefore(c, oldNode)
+			return @removeChild(oldNode)
+		newNode._private.parentNode = @
+		newNode._private.childIndex = i
+		oldNode.parentNode = null
+		oldNode._private.childIndex = -1
+		@childNodes.splice(i, 1, newNode)
 	toString: (pretty=false,deep=true,indentLevel=0) ->
+		# console.log("Node::toString[#{@nodeName}] from #{@nodeValue}")
 		if pretty
 			indent = repeat("  ", indentLevel)
 			newline = "\n"
@@ -694,8 +703,7 @@
 	constructor: (owner) ->
 		super "#document-fragment", null, Node.DOCUMENT_FRAGMENT_NODE, owner
 	toString: (pretty=false, deep=true) ->
-		ret = []
-		r = 0
+		ret = []; r = 0
 		for c in @childNodes
 			ret[r++] = c.toString pretty, deep
 		return ret.join('')
@@ -733,7 +741,7 @@
 			else
 				new Event()
 	createTextNode: (text) ->
-		new Text(text)
+		new Text(text, @)
 	getElementById: (id) ->
 		@_private.idMap[id]

@@ -773,5 +781,6 @@
 	g.Document = Document
 	g.DocumentFragment = DocumentFragment
 	g.NodeList = Array # HACK: for now...
+	g.Event = {} # HACK

 # vim: ft=coffee


Fix to clarify comment

Fix to clarify comment

--- lib/index.coffee
+++ lib/index.coffee
@@ -5,7 +5,7 @@

 ###
 when passed an object, returns an array of its keys.
-when passed an array, returns an array of its indexes.
+when passed an array, returns an array of indexes.

 arrayify({a: 'aa', b: 'bb', c: 'cc'})
 -> ['a', 'b', 'c']


little refactor

little refactor

--- lib/index.coffee
+++ lib/index.coffee
@@ -38,8 +38,6 @@
       { cb       : Args.FUNCTION | Args.Required                          }
       ], arguments)

-    args.filename = stringify args.filename
-
     @list prefix: args.filename, (err, data) ->
       return args.cb err if err
       fileNames = data.Contents.map args.mapFn
@@ -78,7 +76,7 @@
   putGzip: ->
     args = Args([
       [
-        { data   : Args.STRING | Args.Required                           }
+        { data : Args.STRING | Args.Required                             }
         { data : Args.OBJECT | Args.Required, _check : DEFAULT.stringify }
       ],
       { filename : Args.STRING | Args.Required                             }
@@ -132,7 +130,6 @@

     @getFile args.filename, args.headers, (err, res) ->
       chunks = []
-      # res.setEncoding 'utf8' # TODO: warning
       res.on 'data', (chunk) -> chunks.push chunk
       res.on 'end', -> args.cb null, JSON.parse(chunks)
       res.on 'error', args.cb


Only override with user's school if no school on load

--- public/scripts/backbone-schedule/app.coffee
+++ public/scripts/backbone-schedule/app.coffee
@@ -40,7 +40,7 @@
             @.friendsList.fetch
               success: =>
                 @.friendsList.trigger('fetched')
-            if @.school != @.session.get('user').get('school')
+            if not @.school
               @setSchool @.session.get('user').get('school')
             # Mixpanel tracking id user
             user = @.session.get 'user'


fix analytics test

fix analytics test

--- test/lib/analytics.coffee
+++ test/lib/analytics.coffee
@@ -13,9 +13,11 @@

     before ->
       sinon.stub(analytics, 'getUserAgent').returns "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.102 Safari/537.36"
+      @clock = sinon.useFakeTimers();

     after ->
       analytics.getUserAgent.restore()
+      @clock.restore()

     beforeEach ->
       sd.MIXPANEL_ID = 'mix that panel'


Tests: Change timers.

Tests: Change timers.

--- tests/src/ide/ide.coffee
+++ tests/src/ide/ide.coffee
@@ -22,10 +22,10 @@
       .waitForElementVisible   indexSelector, 15000
       .click                   indexSelector
       .click                   indexSelector + ' + .chevron'
-      .waitForElementVisible   'li.open-file', 5000
+      .waitForElementVisible   'li.open-file', 20000
       .click                   'li.open-file'
-      .waitForElementVisible   '.indexhtml',   5000 # Assertion
-      .waitForElementVisible   '.ace_content', 5000 # Assertion
+      .waitForElementVisible   '.indexhtml',   20000 # Assertion
+      .waitForElementVisible   '.ace_content', 20000# Assertion
       .assert.containsText     '.ace_content', 'Hello World from HTML by Koding' # Assertion
       .end()

@@ -48,9 +48,9 @@
       .waitForElementPresent     fileSelector, 20000
       .click                     fileSelector
       .click                     fileSelector + ' + .chevron'
-      .waitForElementVisible     'li.delete', 5000
+      .waitForElementVisible     'li.delete', 20000
       .click                     'li.delete'
-      .waitForElementVisible     '.delete-container', 5000
+      .waitForElementVisible     '.delete-container', 20000
       .click                     '.delete-container button.clean-red'
       .waitForElementNotPresent  fileSelector, 20000
       .end()
@@ -71,12 +71,12 @@
       .waitForElementPresent     fileSelector, 20000
       .click                     fileSelector
       .click                     fileSelector + ' + .chevron'
-      .waitForElementVisible     'li.rename', 5000
+      .waitForElementVisible     'li.rename', 20000
       .click                     'li.rename'
-      .waitForElementVisible     'li.selected .rename-container .hitenterview', 5000
+      .waitForElementVisible     'li.selected .rename-container .hitenterview', 20000
       .clearValue                'li.selected .rename-container .hitenterview'
       .setValue                  'li.selected .rename-container .hitenterview', newFileName + '\n'
-      .waitForElementPresent     newFileSelector, 5000 # Assertion
+      .waitForElementPresent     newFileSelector, 20000 # Assertion
       .end()

@@ -93,9 +93,10 @@
       .waitForElementPresent     fileSelector, 20000
       .click                     fileSelector
       .click                     fileSelector + ' + .chevron'
-      .waitForElementVisible     'li.duplicate', 5000
+      .waitForElementVisible     'li.duplicate', 20000
       .click                     'li.duplicate'
-      .waitForElementVisible     newFile, 5000 # Assertion
+      .pause                     2000
+      .waitForElementPresent     newFile, 20000 # Assertion
       .end()

@@ -143,7 +144,7 @@
     helpers.openChangeTopFolderMenu(browser)

     browser
-      .waitForElementVisible   selectMenuItem, 50000
+      .waitForElementVisible   selectMenuItem, 20000
       .click                   selectMenuItem
       .pause                   2000 # required
       .end()


Activate and focus active pane after compile

--- lib/coffee-compile.coffee
+++ lib/coffee-compile.coffee
@@ -45,6 +45,7 @@
     atom.workspace.openUriInPane(uri, pane, {}).done (coffeeCompileView) ->
       if coffeeCompileView instanceof CoffeeCompileView
         coffeeCompileView.renderCompiled()
+        activePane.activate()

         if atom.config.get('coffee-compile.compileOnSave')
           coffeeCompileView.saveCompiled()


to.be.defined is not a thing

to.be.defined is not a thing

--- test/npm_copy.test.coffee
+++ test/npm_copy.test.coffee
@@ -7,6 +7,6 @@
 describe 'npm-copy', ->
   it 'prints usage', (done) ->
     exec path.resolve(__dirname, '../bin/npm-copy.js'), (err, stdout, stderr) ->
-      expect(err).not.to.be.defined
+      expect(err).not.to.exist
       expect(stdout).to.contain 'usage:'
       done()


Use pdf-view package as true fallback

Use pdf-view package as true fallback

--- lib/latex.coffee
+++ lib/latex.coffee
@@ -117,20 +117,18 @@

   getOpener: ->
     # TODO: Move this to a resolver module? Will get more complex...
-    if atom.config.get('latex.useAtomPdfViewer')
+    OpenerImpl = switch process.platform
+      when 'darwin'
+        if fs.existsSync(atom.config.get('latex.skimPath'))
+          require './openers/skim-opener'
+        else
+          require './openers/preview-opener'
+      when 'win32'
+        if fs.existsSync(atom.config.get('latex.sumatraPath'))
+          require './openers/sumatra-opener'
+    unless OpenerImpl?
       OpenerImpl = require './openers/atompdf-opener'
-    else
-      OpenerImpl = switch process.platform
-        when 'darwin'
-          if fs.existsSync(atom.config.get('latex.skimPath'))
-            require './openers/skim-opener'
-          else
-            require './openers/preview-opener'
-        when 'win32'
-          if fs.existsSync(atom.config.get('latex.sumatraPath'))
-            require './openers/sumatra-opener'
-    return new OpenerImpl() if OpenerImpl?
-    console.info 'Opening PDF files is not yet supported on your platform.' unless atom.inSpecMode()
+    return new OpenerImpl()

   moveResult: (result, filePath) ->
     sourceDir = path.dirname(filePath)


Show public user page after joining.

Show public user page after joining.

--- routes/users.coffee
+++ routes/users.coffee
@@ -25,7 +25,7 @@
         status: Errors.statusFor err
     else
       req.session.username = user.username
-      return res.created "/users/#{user.username}",
+      return res.created "/#{user.username}",
         "Welcome aboard, #{user.username}!",
         user: user


refactor constants

refactor constants

--- examples-coffee/counter/actions/counter.coffee
+++ examples-coffee/counter/actions/counter.coffee
@@ -1,5 +1,5 @@
-INCREMENT_COUNTER = 'INCREMENT_COUNTER'
-DECREMENT_COUNTER = 'DECREMENT_COUNTER'
+module.exports.INCREMENT_COUNTER = INCREMENT_COUNTER = 'INCREMENT_COUNTER'
+module.exports.DECREMENT_COUNTER = DECREMENT_COUNTER = 'DECREMENT_COUNTER'

 increment = ->
   type: INCREMENT_COUNTER
@@ -7,7 +7,5 @@
 decrement = ->
   type: DECREMENT_COUNTER

-module.exports.INCREMENT_COUNTER = INCREMENT_COUNTER
-module.exports.DECREMENT_COUNTER = DECREMENT_COUNTER
 module.exports.increment = increment
 module.exports.decrement = decrement


Store editor in ivar

Store editor in ivar

--- lib/diff-list-view.coffee
+++ lib/diff-list-view.coffee
@@ -13,29 +13,26 @@

   viewForItem: ({oldStart, newStart, oldLines, newLines}) ->
     bufferRow = if newStart > 0 then newStart - 1 else newStart
+    lineText = @editor.lineForBufferRow(bufferRow) ? ''
     $$ ->
       @li class: 'two-lines', =>
-        @div atom.workspace.getActiveEditor()?.lineForBufferRow(bufferRow), class: 'primary-line'
+        @div lineText, class: 'primary-line'
         @div "-#{oldStart},#{oldLines} +#{newStart},#{newLines}", class: 'secondary-line'

   populate: ->
-    if editor = atom.workspace.getActiveEditor()
-      diffs = atom.project.getRepo()?.getLineDiffs(editor.getPath(), editor.getText()) ? []
-      @setItems(diffs)
+    diffs = atom.project.getRepo()?.getLineDiffs(@editor.getPath(), @editor.getText()) ? []
+    @setItems(diffs)

   toggle: ->
     if @hasParent()
       @cancel()
-    else
+    else if @editor = atom.workspace.getActiveEditor()
       @populate()
       @attach()

   confirmed: ({newStart})->
     @cancel()

-    editorView = atom.workspaceView.getActiveView()
-    if editor = editorView?.getEditor?()
-      bufferRow = if newStart > 0 then newStart - 1 else newStart
-      editorView.scrollToBufferPosition([bufferRow, 0], center: true)
-      editor.setCursorBufferPosition([bufferRow, 0])
-      editor.moveCursorToFirstCharacterOfLine()
+    bufferRow = if newStart > 0 then newStart - 1 else newStart
+    @editor.setCursorBufferPosition([bufferRow, 0], autoscroll: true)
+    @editor.moveCursorToFirstCharacterOfLine()


Add strictMatching option

Add strictMatching option

--- lib/fuzzy-provider.coffee
+++ lib/fuzzy-provider.coffee
@@ -132,7 +132,12 @@

     # Merge the scope specific words into the default word list
     wordList = @wordList.concat @getCompletionsForCursorScope()
-    words = fuzzaldrin.filter wordList, prefix
+
+    words =
+      if atom.config.get("autocomplete-plus.strictMatching")
+        @wordList.filter (word) -> word.indexOf(prefix) is 0
+      else
+        fuzzaldrin.filter wordList, prefix

     results = for word in words when word isnt prefix
       new Suggestion this, word: word, prefix: prefix


ace: ocd

ace: ocd

--- client/ace/lib/ace.coffee
+++ client/ace/lib/ace.coffee
@@ -54,7 +54,7 @@
     bindKey : bindKey

-  constructor:(options, file)->
+  constructor: (options, file) ->

     super options, file

@@ -63,14 +63,18 @@
     @appStorage            = appStorageController.storage 'Ace', '1.0.1'

-  setDomElement:(cssClass)->
+  setDomElement: (cssClass) ->
+
     @domElement = $ "

"

-  viewAppended:->
+  viewAppended: ->
+
     super
+
     @hide()
-    @appStorage.fetchStorage (storage)=>
+
+    @appStorage.fetchStorage (storage)=> # XXX: wtf? -og

     if ACE_READY
     then @scriptLoaded()
@@ -79,13 +83,19 @@

   scriptLoaded: ->

-    @fetchContents (err, contents)=>
+    @fetchContents (err, contents) =>
+
       notification?.destroy()
       element = @getElement().querySelector "#editor#{@getId()}"
+
       return  unless element
+
       @editor = ace.edit element
+
       element.classList.remove 'ace-tm' # remove default white theme to avoid flashing
+
       @prepareEditor()
+
       if contents
         @setContents contents
         @lastSavedContents = contents
@@ -119,6 +129,7 @@

   setContent: (content, emitFileContentChangedEvent = yes) ->
+
     @suppressListeners = yes  unless emitFileContentChangedEvent

     @editor.setValue content, -1
@@ -126,13 +137,14 @@
     @suppressListeners = no   unless emitFileContentChangedEvent

-  prepareEditor:->
+  prepareEditor: ->

     @setTheme null, no
     @setSyntax()
     @setEditorListeners()

-    @appStorage.fetchStorage (storage)=>
+    @appStorage.fetchStorage (storage) =>
+
       @setTheme()
       @setUseSoftTabs         @appStorage.getValue('useSoftTabs')         ? yes    ,no
       @setShowGutter          @appStorage.getValue('showGutter')          ? yes    ,no
@@ -148,7 +160,8 @@
       @setEnableAutocomplete  @appStorage.getValue('enableAutocomplete')  ? yes    ,no

-  saveStarted:->
+  saveStarted: ->
+
     @lastContentsSentForSave = @getContents()

@@ -162,13 +175,13 @@
     @askedForSave = no

-  saveAsFinished:(newFile, oldFile)->
+  saveAsFinished: (newFile, oldFile) ->

     @emit 'FileContentRestored'
     @emit 'FileHasBeenSavedAs', @getData()

-  setEditorListeners:->
+  setEditorListeners: ->

     @editor.getSession().selection.on 'changeCursor', (cursor) =>
       return if @suppressListeners
@@ -220,10 +233,12 @@

   isContentChanged: -> @contentChanged

+
   isCurrentContentChanged:-> @getContents() isnt @lastSavedContents

   closeTab: ->
+
     aceView   = @getDelegate()
     {tabView} = aceView.getDelegate()
     tabView.removePane_ tabView.getActivePane()
@@ -233,8 +248,10 @@
   FS REQUESTS
   ###

-  requestSave:->
+  requestSave: ->
+
     contents = @getContents()
+
     unless contents is '' or @isContentChanged()
       if @getDelegate().parent.active
         @notify 'Nothing to save!'
@@ -245,10 +262,14 @@

   requestSaveAs: ->
+
     @emit 'ace.requests.saveAs', @getContents()

-  fetchContents:(callback)->
+
+  fetchContents: (callback) ->
+
     file = @getData()
+
     unless /localfile:/.test file.path
       file.fetchContents callback
     else
@@ -259,44 +280,46 @@
   GETTERS
   ###

-  getContents:-> @editor.getSession().getValue()
-
-
-  getTheme:-> @editor.getTheme().replace 'ace/theme/', ''
-
-
-  getSyntax:-> @syntaxMode
-
-
-  getUseSoftTabs:->
+  getContents: ->
+    @editor.getSession().getValue()
+
+
+  getTheme: ->
+    @editor.getTheme().replace 'ace/theme/', ''
+
+
+  getSyntax: -> @syntaxMode
+
+
+  getUseSoftTabs: ->
     @appStorage.getValue('useSoftTabs') ? @editor.getSession().getUseSoftTabs()

-  getShowGutter:->
+  getShowGutter: ->
     @appStorage.getValue('showGutter') ? @editor.renderer.getShowGutter()

-  getShowPrintMargin:->
+  getShowPrintMargin: ->
     @appStorage.getValue('showPrintMargin') ? @editor.getShowPrintMargin()

-  getHighlightActiveLine:->
+  getHighlightActiveLine: ->
     @appStorage.getValue('highlightActiveLine') ? @editor.getHighlightActiveLine()

-  getShowInvisibles:->
+  getShowInvisibles: ->
     @appStorage.getValue('showInvisibles') ? @editor.getShowInvisibles()

-  getFontSize:->
+  getFontSize: ->
     @appStorage.getValue('fontSize') ? parseInt @$("#editor#{@getId()}").css('font-size') ? 12, 10

-  getTabSize:->
+  getTabSize: ->
     @appStorage.getValue('tabSize') ? @editor.getSession().getTabSize()

-  getUseWordWrap:->
+  getUseWordWrap: ->
     @appStorage.getValue('useWordWrap') ? @editor.getSession().getUseWrapMode()

@@ -308,15 +331,16 @@
     @appStorage.getValue('scrollPastEnd') ? yes

-  getOpenRecentFiles:->
+  getOpenRecentFiles: ->
     @appStorage.getValue('openRecentFiles') ? yes

-  getEnableAutocomplete:->
+  getEnableAutocomplete: ->
     @appStorage.getValue('enableAutocomplete') ? yes

-  getSettings:->
+  getSettings: ->
+
     theme               : @getTheme()
     syntax              : @getSyntax()
     useSoftTabs         : @getUseSoftTabs()
@@ -337,10 +361,11 @@
   SETTERS
   ###

-  setContents:(contents)-> @editor.getSession().setValue contents
-
-
-  setSyntax:(mode)->
+  setContents: (contents) ->
+    @editor.getSession().setValue contents
+
+
+  setSyntax: (mode) ->

     file = @getData()
     mode or= file.syntax
@@ -358,35 +383,37 @@
     @syntaxMode = mode

-  setTheme:(themeName, save = yes)->
+  setTheme: (themeName, save = yes) ->
+
     themeName or= @appStorage.getValue('theme') or 'base16'
+
     @editor.setTheme "ace/theme/#{themeName}"
     return  unless save
     @appStorage.setValue 'theme', themeName, => # do what is necessary here if any - SY

-  setUseSoftTabs:(value, save = yes)->
+  setUseSoftTabs: (value, save = yes) ->

     @editor.getSession().setUseSoftTabs value
     return  unless save
     @appStorage.setValue 'useSoftTabs', value

-  setShowGutter:(value, save = yes)->
+  setShowGutter: (value, save = yes) ->

     @editor.renderer.setShowGutter value
     return  unless save
     @appStorage.setValue 'showGutter', value

-  setShowPrintMargin:(value, save = yes)->
+  setShowPrintMargin: (value, save = yes) ->

     @editor.setShowPrintMargin value
     return  unless save
     @appStorage.setValue 'showPrintMargin', value

-  setHighlightActiveLine:(value, save = yes)->
+  setHighlightActiveLine: (value, save = yes) ->

     @editor.setHighlightActiveLine value
     return  unless save
@@ -396,7 +423,7 @@
   # setHighlightSelectedWord:(value)-> @editor.setHighlightActiveLine value

-  setShowInvisibles:(value, save = yes)->
+  setShowInvisibles: (value, save = yes) ->

     @editor.setShowInvisibles value
     return  unless save
@@ -404,17 +431,20 @@

   setKeyboardHandler: (name = 'default') ->
+
     @appStorage.setValue 'keyboardHandler', name
     handler = if name isnt 'default' then "ace/keyboard/#{name}" else null
     @editor.setKeyboardHandler handler

   setScrollPastEnd: (value = yes) ->
+
     @editor.setOption 'scrollPastEnd', value
     @appStorage.setValue 'scrollPastEnd', value

-  setFontSize:(value, save = yes)->
+  setFontSize: (value, save = yes) ->
+
     return if value is globals.config.oldFontSize

     style           = global.document.createElement 'style'
@@ -431,28 +461,29 @@
     @appStorage.setValue 'fontSize', value

-  setTabSize:(value, save = yes)->
+  setTabSize: (value, save = yes) ->

     @editor.getSession().setTabSize +value
     return  unless save
     @appStorage.setValue 'tabSize', value

-  setUseWordWrap:(value, save = yes)->
+  setUseWordWrap: (value, save = yes) ->

     @editor.getSession().setUseWrapMode value
     return  unless save
     @appStorage.setValue 'useWordWrap', value

-  setReadOnly:(value)-> @editor.setReadOnly value
-
-
-  setOpenRecentFiles:(value, save = yes)->
+  setReadOnly: (value) ->
+    @editor.setReadOnly value
+
+
+  setOpenRecentFiles: (value, save = yes) ->
     @appStorage.setValue 'openRecentFiles', value

-  setEnableAutocomplete:(value, save = yes)->
+  setEnableAutocomplete: (value, save = yes) ->

     @editor.setOptions
       enableBasicAutocompletion: value
@@ -473,7 +504,8 @@
   ###

   notification = null
-  notify:(msg, style, details, duration)->
+
+  notify: (msg, style, details, duration) ->

     notification.destroy() if notification

@@ -513,6 +545,7 @@

   removeModifiedFromTab: ->
+
     aceView      = @parent

     unless aceView
@@ -535,7 +568,9 @@

   showGotoLine: ->
+
     unless @gotoLineModal
+
       @gotoLineModal = new KDModalViewWithForms
         cssClass                : 'goto'
         width                   : 180
@@ -565,5 +600,3 @@
         @focus()

       @gotoLineModal.modalTabs.forms.Go.focusFirstElement()
-
-


prevent empty message

prevent empty message

--- public/js/wireroom.coffee
+++ public/js/wireroom.coffee
@@ -82,6 +82,8 @@
     @messageForm.submit =>
       message = @getMessage()
       nickname = @getNickname()
+      return unless message
+      return unless nickname
       @wireroom.socket.emit "publish",
         "nickname": nickname
         "message": message


No need to actually create a page for cookie test

--- spec/api-session-spec.coffee
+++ spec/api-session-spec.coffee
@@ -1,7 +1,8 @@
-assert  = require 'assert'
-remote  = require 'remote'
-http    = require 'http'
-path    = require 'path'
+assert = require 'assert'
+remote = require 'remote'
+http   = require 'http'
+path   = require 'path'
+app    = remote.require 'app'
 BrowserWindow = remote.require 'browser-window'

 describe 'session module', ->
@@ -15,7 +16,7 @@

   it 'should get cookies', (done) ->
     server = http.createServer (req, res) ->
-      res.setHeader('Set-Cookie', ['type=dummy'])
+      res.setHeader('Set-Cookie', ['0=0'])
       res.end('finished')
       server.close()

@@ -24,48 +25,37 @@
       {port} = server.address()
       w.loadUrl "#{url}:#{port}"
       w.webContents.on 'did-finish-load', ->
-        w.webContents.session.cookies.get {url: url}, (error, cookies) ->
+        w.webContents.session.cookies.get {url: url}, (error, list) ->
           return done(error) if error
-          assert.equal 'type', cookies[0].name
-          assert.equal 'dummy', cookies[0].value
-          done()
+          for cookie in list when cookie.name is '0'
+            if cookie.value is '0'
+              return done()
+            else
+              return done("cookie value is #{cookie.value} while expecting 0")
+          done('Can not find cookie')

   it 'should over-write the existent cookie', (done) ->
-    w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
-    w.webContents.on 'did-finish-load', ->
-      w.webContents.session.cookies.set {url: url, name: 'type', value: 'dummy2'}, (error) ->
+    app.defaultSession.cookies.set {url: url, name: '1', value: '1'}, (error) ->
+      return done(error) if error
+      app.defaultSession.cookies.get {url: url}, (error, list) ->
         return done(error) if error
-        w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
-          return done(error) if error
-          assert.equal 'type', cookies_list[0].name
-          assert.equal 'dummy2', cookies_list[0].value
-          done()
-
-  it 'should set new cookie', (done) ->
-    w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
-    w.webContents.on 'did-finish-load', ->
-      w.webContents.session.cookies.set {url: url, name: 'key', value: 'dummy2'}, (error) ->
-        return done(error) if error
-        w.webContents.session.cookies.get {url: url}, (error, cookies_list) ->
-          return done(error) if error
-          for cookie in cookies_list
-            if cookie.name is 'key'
-               assert.equal 'dummy2', cookie.value
-               return done()
-          done('Can not find cookie')
+        for cookie in list when cookie.name is '1'
+          if cookie.value is '1'
+            return done()
+          else
+            return done("cookie value is #{cookie.value} while expecting 1")
+        done('Can not find cookie')

   it 'should remove cookies', (done) ->
-    w.loadUrl 'file://' + path.join(fixtures, 'page', 'a.html')
-    w.webContents.on 'did-finish-load', ->
-      w.webContents.session.cookies.set {url: url, name: 'key', value: 'dummy2'}, (error) ->
+    app.defaultSession.cookies.set {url: url, name: '2', value: '2'}, (error) ->
+      return done(error) if error
+      app.defaultSession.cookies.remove {url: url, name: '2'}, (error) ->
         return done(error) if error
-        w.webContents.session.cookies.remove {url: url, name: 'key'}, (error) ->
+        app.defaultSession.cookies.get {url: url}, (error, list) ->
           return done(error) if error
-          w.webContents.session.cookies.get {url: url}, (error, list) ->
-            return done(error) if error
-            for cookie in list when cookie.name is 'key'
-               return done('Cookie not deleted')
-            done()
+          for cookie in list when cookie.name is '2'
+             return done('Cookie not deleted')
+          done()

   describe 'session.clearStorageData(options)', ->
     fixtures = path.resolve __dirname, 'fixtures'


Fixed recursive data types and added a test

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1088,7 +1088,7 @@
         else
           ctx.kindOfTypeName atom.symbol
       if kindOfType instanceof TempKind
-        kindOfType = expectedKind
+        kindOfType = expectedKind or star
       if not kindOfType
         # throw new Error "type name #{atom.symbol} was not defined" unless kind
         malformed ctx, atom, "This type name has not been defined"
@@ -2496,9 +2496,9 @@
         toNormalize.push normalized...
         normalized = []
   if all normalized
-    success: normalized
-  else
-    error: "??Not all normalized??"
+    {success: normalized}
+  else
+    {error: "??Not all normalized??"}

 # normalizeConstraint = (ctx, constraint) ->
 #   if isNormalizedConstraint constraint
@@ -5426,6 +5426,14 @@
         (Person name id) name))"""
   """(name ((Person id: 3) "Mike"))""", "Mike"

+  'recursive data'
+  """
+  Tree (data [a]
+    Val [value: a]
+    Node [child: (Tree a)])
+  """
+  '(Val-value (Node-child (Node (Val 42))))', 42
+
   'late bound function'
   """f (fn [x] (g x))
     g (fn [x] 2)"""


Rewrite command name

Rewrite command name

--- spec/js-refactor-spec.coffee
+++ spec/js-refactor-spec.coffee
@@ -20,10 +20,13 @@
     atom.syntax.loadGrammarSync path.resolve grammarDir, filename

 activatePackage = (callback) ->
-  activationPromise = atom.packages.activatePackage 'js-refactor'
+  [ activationPromise, watcher ] = []
+  atom.packages.activatePackage 'refactor'
   .then ({ mainModule }) ->
-    callback mainModule.watchers[0]
-
+    watcher = mainModule.watchers[0]
+    activationPromise = atom.packages.activatePackage 'js-refactor'
+    .then ->
+      callback activationPromise, watcher

 describe "main", ->

@@ -35,7 +38,8 @@
       { editorView, editor } = openFile 'fibonacci.js'
       editor.setCursorBufferPosition [0, 4]
       loadLanguage()
-      activationPromise = activatePackage (w) ->
+      activatePackage (p, w) ->
+        activationPromise = p
         watcher = w

     it "attaches the views", ->
@@ -68,7 +72,7 @@
     describe "when 'js-refactor:rename' event is triggered", ->

       it "has multi-cursors", ->
-        atom.workspaceView.trigger 'js-refactor:rename'
+        atom.workspaceView.trigger 'refactor:rename'
         waitsForPromise ->
           activationPromise
         runs ->
@@ -77,7 +81,7 @@
     describe "when 'js-refactor:done' event is triggered", ->

       it "has single cursor", ->
-        atom.workspaceView.trigger 'js-refactor:done'
+        atom.workspaceView.trigger 'refactor:done'
         waitsForPromise ->
           activationPromise
         runs ->


Refactor page header generation

Refactor page header generation

--- client/lib/refresh.coffee
+++ client/lib/refresh.coffee
@@ -64,24 +64,34 @@
   before = wiki.getItem(beforeElement)
   pageHandler.put pageElement, {item: item, id: item.id, type: "add", after: before?.id}

+buildPageHeader = ({title,tooltip,header_href,favicon_src})->
+  """
 #{title}
"""
+
 emitHeader = (pageElement, page) ->
   site = $(pageElement).data('site')
-  if site? and site != 'local' and site != 'origin' and site != 'view'
-    $(pageElement)
-      .append """
 #{page.title}
"""
+  loading_a_remote_page = site? and site != 'local' and site != 'origin' and site != 'view'
+  header = ''
+
+  pageHeader = if loading_a_remote_page
+    buildPageHeader
+      tooltip: site
+      header_href: "//#{site}"
+      favicon_src: "http://#{site}/favicon.png"
+      title: page.title
   else
-    $(pageElement)
-      .append(
-        $("""
""").append(
-          $("").attr('href', '/').append(
-            $("")
-              .error((e) ->
-                plugin.get('favicon', (favicon) ->
-                  favicon.create()))
-              .attr('class', 'favicon')
-              .attr('src', '/favicon.png')
-              .attr('height', '32px')
-          ), " #{page.title}"))
+    buildPageHeader
+      tooltip: location.host
+      header_href: "/"
+      favicon_src: "/favicon.png"
+      title: page.title
+
+  $(pageElement).append( pageHeader )
+
+  unless loading_a_remote_page
+    $('img.favicon',pageElement).error (e)->
+      plugin.get 'favicon', (favicon) ->
+        favicon.create()
+
   if (rev = pageElement.attr('id').split('_rev')[1])?
     date = page.journal[page.journal.length-1].date
     $(pageElement).addClass('ghost').data('rev',rev).append $ """


Support where clauses

Support where clauses

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1,5 +1,3 @@
-controls = '\\(\\)\\[\\]\\{\\}'
-
 tokenize = (input) ->
   currentPos = 0
   while input.length > 0
@@ -22,9 +20,10 @@
     currentPos += token.length
     constantLabeling {token, pos}

+controls = '\\(\\)\\[\\]\\{\\}'
+
 noWS = (tokens) ->
   tokens.filter (token) -> token.label isnt 'whitespace'
-

 astize = (tokens) ->
   tree = []
@@ -51,6 +50,7 @@

 leftDelims = ['(', '[', '{']
 rightDelims = [')', ']', '}']
+delims = '(': ')', '[': ']', '{': '}'

 constantLabeling = (atom) ->
   {token} = atom
@@ -67,10 +67,7 @@
 _isCollectionDelim = (atom) ->
   atom.label in ['bracket', 'brace']

-typed = (a, b) ->
-  b.type = a.type
-  b
-
+# TODO: remove
 walk = (ast, cb) ->
   if Array.isArray ast
     ast = cb ast
@@ -79,12 +76,10 @@
         walk node, cb)
   ast

-walkOnly = (ast, cb) ->
-  if Array.isArray ast
-    cb ast
-    for node in ast
-      walk node, cb
-  ast
+# TODO: remove
+typed = (a, b) ->
+  b.type = a.type
+  b

 crawl = (ast, cb, parent) ->
   if Array.isArray ast
@@ -92,15 +87,6 @@
       crawl node, cb, ast)
   else
     cb ast, ast.token, parent
-
-crawlWhile = (ast, cond, cb) ->
-  if Array.isArray ast
-    if cond ast
-      for node in ast
-        crawlWhile node, cond, cb
-  else
-    cb ast, ast.token
-  return

 crouch = (ast, cb) ->
   if Array.isArray ast
@@ -204,7 +190,6 @@
     @cacheScopes = [[]]
     @_assignTos = []
     @scopes = [@_augmentScope builtInContext this] # dangerous passing itself in constructor
-    @_defer = undefined

   macros: ->
     @_macros
@@ -261,6 +246,9 @@
   _scope: ->
     @scopes[@scopes.length - 1]

+  _parentScope: ->
+    @scopes[@scopes.length - 2]
+
   newScope: ->
     @scopes.push @_augmentScope newMap()

@@ -362,14 +350,25 @@
       []

   setDefer: (dependencyName) ->
-    @_defer =
+    @_setDeferIn @_scope(), dependencyName
+
+  setDeferParent: (dependencyName) ->
+    if not @scopes.length >= 2
+      throw new "Deferring parent although this is top level scope"
+    @_setDeferIn @_parentScope(), dependencyName
+
+  _setDeferIn: (scope, dependencyName) ->
+    scope._defer =
       if dependencyName
-        @_defer or dependencyName
+        (@_shouldDeferIn scope) or dependencyName
       else
         dependencyName

   shouldDefer: ->
-    @_defer
+    @_shouldDeferIn @_scope()
+
+  _shouldDeferIn: (scope) ->
+    scope._defer

   addDeferred: (dependencyName, lhs, rhs) ->
     @_scope().deferred.push [dependencyName, lhs, rhs]
@@ -704,7 +703,7 @@
     ctx.setGroupTranslation()
     {precs, assigns} = patternCompile ctx, to, expression, translatedExpression

-    # log "assigning #{ctx._name()}", ctx.shouldDefer()
+    log "ASSIGN #{ctx._name()}", ctx.shouldDefer()
     if ctx.shouldDefer()
       ctx.addDeferred ctx.shouldDefer(), to, expression
       return 'deferred'
@@ -773,57 +772,71 @@
   assigns: assigns ? []

 topLevel = (ctx, form) ->
+  definitionList ctx, pairs _terms form
+
+definitionList = (ctx, pairs) ->
+  compiledPairs = filter _is, (for [lhs, rhs] in pairs
+    definitionPairCompile ctx, lhs, rhs)
+
+  compiledPairs = join compiledPairs, compileDeferred ctx
+  resolveDeferredTypes ctx
+
+  log "yay"
+
+  listOfLines compiledPairs
+
+resolveDeferredTypes = (ctx) ->
+  if _notEmpty ctx.deferredBindings()
+    # TODO: proper dependency analysis to get the smallest circular deps
+    #       now we are just compiling as if they were all mutually recursive
+    names = concatConcatMaps map (({name, type}) -> newMapWith name, type), ctx.deferredBindings()
+    for name, types of values names
+      canonicalType = ctx.freshTypeVariable star
+      for type in types
+        log type.constructor
+        # log "unifying", canonicalType, type
+        unify ctx, canonicalType, type
+        # log "done unifying one"
+    # log "done unifying"
+    for name of values names
+      # log "done"
+      ctx.addType name, substitute ctx.substitution, canonicalType
+      # log "added"
+
+compileDeferred = (ctx) ->
   compiledPairs = []
-  for [lhs, rhs] in pairs _terms form
-    topLevelPairCompile ctx, compiledPairs, lhs, rhs
-
   if _notEmpty ctx.deferred()
     deferredCount = 0
     while (_notEmpty ctx.deferred()) and deferredCount < ctx.deferred().length
       prevSize = ctx.deferred().length
       [dependencyName, lhs, rhs] = deferred = ctx.deferred().shift()
       if ctx.declaration dependencyName
-        topLevelPairCompile ctx, compiledPairs, lhs, rhs
+        compiledPairs.push definitionPairCompile ctx, lhs, rhs
       else
         # If can't compile, defer further
-        ctx.addDeferred deferred
+        ctx.addDeferred deferred...
       if prevSize is ctx.deferred().length
         deferredCount++

+  # defer completely current scope
   if _notEmpty ctx.deferred()
-    log "dependency cycles", ctx.deferred()
-
-  if _notEmpty ctx.deferredBindings()
-    # TODO: proper dependency analysis to get the smallest circular deps
-    names = concatConcatMaps map (({name, type}) -> newMapWith name, type), ctx.deferredBindings()
-    for name, types of values names
-      canonicalType = ctx.freshTypeVariable star
-      for type in types
-        log type.constructor
-        log "unifying", canonicalType, type
-        unify ctx, canonicalType, type
-        log "done unifying one"
-    log "done unifying"
-    for name of values names
-      log "done"
-      ctx.addType name, substitute ctx.substitution, canonicalType
-      log "added"
-
-  log "yay"
-
-  listOfLines compiledPairs
-
-topLevelPairCompile = (ctx, compiledPairs, lhs, rhs) ->
-  log "COMPILING", lhs, rhs
+    for [dependencyName, lhs, rhs] in ctx.deferred()
+      ctx.setDeferParent dependencyName
+
+  compiledPairs
+
+definitionPairCompile = (ctx, lhs, rhs) ->
+  # log "COMPILING", lhs, rhs
   ctx.setName lhs
-  log "deferrement before assign !!!", ctx.shouldDefer()
+  # log "deferrement before assign !!!", ctx.shouldDefer()
   compiled = expressionCompile ctx, rhs
   ctx.resetName()
   if ctx.shouldDefer()
-    log "RESETTING DEFER"
+    # log "RESETTING DEFER"
     ctx.setDefer false
-  else
-    compiledPairs.push compiled
+    undefined
+  else
+    compiled

 builtInMacros =

@@ -852,6 +865,10 @@
       ctx.newLateScope()
       # log "adding types", (map _token, params), paramTypes
       ctx.addTypes (map _token, params), paramTypes
+
+      log "compiling wheres", pairs wheres
+      compiledWheres = definitionList ctx, pairs wheres
+
       # log "types added"
       log "compiling", body
       compiledBody = termCompile ctx, body
@@ -859,10 +876,12 @@
       ctx.closeScope()

       # Syntax - used params in function body
-      # TODO: possibly add to nameCompile instead, or defer to IDE
+      # !! TODO: possibly add to nameCompile instead, or defer to IDE
       isUsedParam = (expression) ->
         (isName expression) and (_token expression) in paramNames
-      map (syntaxNameAs '', 'param'), filterAst isUsedParam, body
+      labelUsedParams = (expression) ->
+        map (syntaxNameAs '', 'param'), filterAst isUsedParam, expression
+      map labelUsedParams, join [body], wheres

       # Arity - before deferring instead go to assignCompile, because this makes the naming of functions special
       if ctx._name()
@@ -880,6 +899,7 @@
           call.tea = typeFn (map _type, paramTypes)..., body.tea

           """λ(function (#{listOf paramNames}) {
+            #{compiledWheres}
             return #{compiledBody};
           }"""
   # data
@@ -2410,6 +2430,7 @@
 # end of Match

 # Simple macros and builtin functions
+# TODO: reimplement the simple macros

 macros =
   'if': (cond, zen, elz) ->
@@ -2496,22 +2517,6 @@

 # end of Simple macros

-# Default scope with builtins
-
-topScopeDefines = ->
-  ids = 'true false & show-list from-nullable'.split(' ')
-    .concat unaryFnMapping.from,
-      binaryOpMapping.from,
-      binaryFnMapping.from,
-      invertedBinaryOpMapping.from,
-      invertedBinaryFnMapping.from,
-      (key for own key of macros),
-      (key for own key of trueMacros)
-  scope = {}
-  for id in ids
-    scope[id] = true
-  scope
-
 # Default type context with builtins

 binaryMathOpType = ['Num', 'Num', 'Num']
@@ -2762,185 +2767,6 @@
   throw "not a forall in freshInstance" unless type instanceof ForAll
   freshes = map ((kind) -> ctx.freshTypeVariable kind), type.kinds
   (substitute freshes, type).type
-
-# Old type inference
-
-assignTypes = (context, expression) ->
-  [s, _, expression] = infer context, expression, 0
-  crouch expression, (node) ->
-    node.tea = subExp s, node.tea if node.tea
-
-inferWheres = (context, pairs, nameIndex) ->
-  # 1st find all classes
-
-  # classEnv = {}
-  # for [name, def] in pairs when def.type is 'class'
-  #   if classEnv[name]
-  #     throw new TypeError "Redefining class #{name}"
-  #   {context} = classDefinition def
-  #   classEnv[name] = [(tokens inside context), []]
-
-  # 1,5th find all instances
-
-  # for [name, def] in pairs when def.type is 'instance'
-  #   {klass} = instanceDefinition def
-  #   if not classEnv[name]
-  #     throw new TypeError "Missing class #{klass} for instance #{name}"
-  #   [supers, instances] = classEnv[klass]
-  #   instances.push  #TODO finish
-
-
-
-  # 2nd find all declarations
-  for [name, def] in pairs when def.type not in ['class', 'instance']
-    [nameIndex, type] = freshOrDeclared def, nameIndex
-    addToMap context, name.token, type
-
-  # 3rd type check
-  for [name, def] in pairs when def.type not in ['class', 'instance']
-    [s1, nameIndex, def] = infer context, def, nameIndex
-    s2 = unify (subExp s1, (inSet context, name.token)), def.tea
-    context = subContext (concatMaps s2, s1), context
-  for [name, def] in pairs
-    name.tea = def.tea = (inSet context, name.token)
-    [name, def]
-
-freshOrDeclared = (def, nameIndex) ->
-  if def.type is 'function'
-    {type} = fnDefinition def
-    if type
-      return readType nameIndex, type
-  type = freshName nameIndex++
-  [nameIndex, type]
-
-readType = (nameIndex, node) ->
-  freshenFree nameIndex, tokens (inside node)[1..].filter isReference
-
-tokens = (words) ->
-  words.map (x) -> x.token
-
-infer = (context, expression, nameIndex) ->
-  switch expression.label
-    when 'numerical'
-      expression.tea = 'Num'
-      [newMap(), nameIndex, expression]
-    when 'string'
-      expression.tea = if /^"/.test expression.token then 'String' else 'Char'
-      [newMap(), nameIndex, expression]
-    else
-      # Reference
-      if (isReference expression) or expression.label in ['keyword', 'const']
-        # TODO: replace free type variables with new unused names in function
-        concreteType = lookupInMap context, expression.token
-        unless concreteType
-          throw new TypeError "Unbound name #{expression.token}"
-        [nextIndex, concreteType] = freshenFree nameIndex, concreteType
-        expression.tea = concreteType
-        [newMap(), nextIndex, expression]
-      # Lambda
-      else if expression.type is 'function'
-        {params, body, wheres} = fnDefinition expression
-        # TODO: more params
-        if !params or !body
-          throw new TypeError "Invalid function declaration"
-        definedParams = inside params
-        if definedParams.length is 0
-          throw new TypeError "Typing lambdas without a param not implemented yet"
-        argName = freshName nameIndex
-        param = definedParams[0]
-        context = concatMaps context, newMapWith param.token, argName
-        [s1, nextIndex, body] = infer context, body, nameIndex + 1
-        expression.tea = (subExp s1, [argName, body.tea])
-        [s1, nextIndex, expression]
-
-      # Call
-      else if (Array.isArray expression) and expression.length > 3
-        [op..., arg] = inside expression
-        [s, nextIndex, tea] = inferCall context, [op, arg], nameIndex
-        expression.tea = tea
-        [s, nextIndex, expression]
-      else
-        throw new TypeError "Other patterns not typable yet"
-
-inferCall = (context, pair, nameIndex) ->
-  [ops, arg] = pair
-  returnName = freshName nameIndex
-  if ops.length >= 2
-    [op..., prevArg] = ops
-    [s1, nextIndex, opTea] = inferCall context, [op, prevArg], nameIndex + 1
-  else
-    [op] = ops
-    [s1, nextIndex, op] = infer context, op, nameIndex + 1
-    opTea = op.tea
-  [s2, nextIndex, arg] = infer (subContext s1, context), arg, nextIndex
-  s3 = unify (subExp s2, opTea), [arg.tea, returnName]
-  [(concatMaps s3, s2, s1), nextIndex, (subExp s3, returnName)]
-
-unifyWith = (subs, pairs) ->
-  if pairs.length is 0
-    subs
-  else
-    [[t1, t2], rest...] = pairs
-    if t1 is t2
-      unifyWith subs, rest
-    else if isTypeVariable t1
-      sub = addToMap newMap(), t1, t2
-      unifyWith (addToMap subs, t1, t2), subPairs sub, rest
-    else if isTypeVariable t2
-      sub = addToMap newMap(), t2, t1
-      unifyWith (addToMap subs, t2, t1), subPairs sub, rest
-    else if (Array.isArray t1) and (Array.isArray t2) and t1.length is t2.length
-      [t1from, t1to] = t1
-      [t2from, t2to] = t2
-      unifyWith subs, [[t1from, t2from], [t1to, t2to]].concat rest
-    else
-      throw new TypeError "Types #{t1}, #{t2} could not be unified", [t1, t2]
-
-subPairs = (subs, pairs) ->
-  for [t1, t2] in pairs
-    [(subExp subs, t1), (subExp subs, t2)]
-
-subExp = (subs, type) ->
-  if Array.isArray type
-    for subType in type
-      subExp subs, subType
-  else
-    if sub = lookupInMap subs, type
-      sub
-    else
-      type
-
-subContext = (subs, context) ->
-  newContext = newMap()
-  for name, t of context.values
-    addToMap newContext, name, (subExp subs, t)
-  newContext
-
-freshenFree = (nameIndex, type) ->
-  if Array.isArray type
-    [nextIndex, subs] = makeFreshForEach nameIndex, findFrees type
-    [nextIndex, (subExp subs, type)]
-  else
-    [nameIndex, type]
-
-makeFreshForEach = (nameIndex, vars) ->
-  subs = newMap()
-  for type in setToArray vars
-    addToMap subs, type, (freshName nameIndex++)
-  [nameIndex, subs]
-
-findFrees = (type) ->
-  if Array.isArray type
-    concatSets (for subType in type
-      findFrees subType)...
-  else
-    if isTypeVariable type
-      newSetWith type
-    else
-      newSet()
-
-isTypeVariable = (name) ->
-  not (Array.isArray name) and name.charCodeAt(0) >= 97

 freshName = (nameIndex) ->
   suffix = if nameIndex > 25 then Math.floor nameIndex / 25 else ''


multiple places to check for kernels, plus fixing kernels without `language`s

--- lib/kernel-manager.coffee
+++ lib/kernel-manager.coffee
@@ -6,7 +6,10 @@
 Kernel = require './kernel'

 module.exports = KernelManager =
-    kernelsDir: path.join(process.env['HOME'], '.ipython/kernels')
+    kernelsDirOptions: [
+        path.join(process.env['HOME'], '.ijupyter/kernels'),
+        path.join(process.env['HOME'], '.ipython/kernels')
+    ]
     runningKernels: {}
     pythonInfo:
         display_name: "Python"
@@ -14,9 +17,10 @@

     getAvailableKernels: ->
         try
-            kernelNames = fs.readdirSync @kernelsDir
+            kernelsDir = _.find @kernelsDirOptions, fs.existsSync
+            kernelNames = fs.readdirSync kernelsDir
             kernels = _.map kernelNames, (name) =>
-                kernelDirPath = path.join(@kernelsDir, name)
+                kernelDirPath = path.join(kernelsDir, name)

                 if fs.statSync(kernelDirPath).isDirectory()
                     kernelFilePath = path.join(kernelDirPath, 'kernel.json')
@@ -41,9 +45,8 @@
             kernelLanguage = kernel.language
             kernelLanguage ?= kernel.display_name

-            return kernel? and
-                   kernel.language? and
-                   language.toLowerCase() == kernel.language.toLowerCase()
+            return kernelLanguage? and
+                   language.toLowerCase() == kernelLanguage.toLowerCase()

         if matchingKernels.length == 0
             return null


Update onDidChangeText -> onDidChange in some specs

--- spec/text-buffer-spec.coffee
+++ spec/text-buffer-spec.coffee
@@ -2264,7 +2264,7 @@
       buffer.setText('\n')
       expect(buffer.isEmpty()).toBeFalsy()

-  describe "::onWillChange", ->
+  describe "::onWillChange(callback)", ->
     it "notifies observers before a transaction, an undo or a redo", ->
       changeCount = 0
       expectedText = ''
@@ -2301,14 +2301,14 @@
       buffer.revertToCheckpoint(checkpoint)
       expect(changeCount).toBe(5)

-  describe "::onDidChangeText(callback)",  ->
+  describe "::onDidChange(callback)",  ->
     beforeEach ->
       filePath = require.resolve('./fixtures/sample.js')
       buffer = TextBuffer.loadSync(filePath)

     it "notifies observers after a transaction, an undo or a redo", ->
       textChanges = []
-      buffer.onDidChangeText ({changes}) -> textChanges.push(changes...)
+      buffer.onDidChange ({changes}) -> textChanges.push(changes...)

       buffer.insert([0, 0], "abc")
       buffer.delete([[0, 0], [0, 1]])
@@ -2402,12 +2402,12 @@

     it "doesn't notify observers after an empty transaction", ->
       didChangeTextSpy = jasmine.createSpy()
-      buffer.onDidChangeText(didChangeTextSpy)
+      buffer.onDidChange(didChangeTextSpy)
       buffer.transact(->)
       expect(didChangeTextSpy).not.toHaveBeenCalled()

     it "doesn't throw an error when clearing the undo stack within a transaction", ->
-      buffer.onDidChangeText(didChangeTextSpy = jasmine.createSpy())
+      buffer.onDidChange(didChangeTextSpy = jasmine.createSpy())
       expect(-> buffer.transact(-> buffer.clearUndoStack())).not.toThrowError()
       expect(didChangeTextSpy).not.toHaveBeenCalled()

@@ -2476,8 +2476,8 @@
               ])
               done()

-    it "provides the correct changes when the buffer is mutated in the onDidChangeText callback", (done) ->
-      buffer.onDidChangeText ({changes}) ->
+    it "provides the correct changes when the buffer is mutated in the onDidChange callback", (done) ->
+      buffer.onDidChange ({changes}) ->
         switch changes[0].newText
           when 'a'
             buffer.insert(changes[0].newRange.end, 'b')


Load summary before comments

Load summary before comments

--- client/publication.coffee
+++ client/publication.coffee
@@ -1,8 +1,8 @@
 do -> # To not pollute the namespace
   Deps.autorun ->
     Meteor.subscribe 'publications-by-id', Session.get 'currentPublicationId'
+    Meteor.subscribe 'summaries-by-publication-and-paragraph', Session.get('currentPublicationId'), Session.get('currentDiscussionParagraph')
     Meteor.subscribe 'comments-by-publication-and-paragraph', Session.get('currentPublicationId'), Session.get('currentDiscussionParagraph')
-    Meteor.subscribe 'summaries-by-publication-and-paragraph', Session.get('currentPublicationId'), Session.get('currentDiscussionParagraph')

   Template.publication.publication = ->
     Publications.findOne Session.get 'currentPublicationId'


test(network): throw correct error if port conflicts

--- packages/network/test/http/index.coffee
+++ packages/network/test/http/index.coffee
@@ -86,7 +86,7 @@
         headers['Content-Type'].should.eql 'application/json'
         type.should.eql 'json'
       finally
-        srv.close()
+        srv?.close()

     they 'escape single and double quotes', ({ssh}) ->
       try
@@ -107,7 +107,7 @@
         headers['Content-Type'].should.eql 'application/json'
         type.should.eql 'json'
       finally
-        await srv.close()
+        await srv?.close()

     they 'honors curl exit code', ({ssh}) ->
       nikita.network.http
@@ -129,7 +129,7 @@
         status_code.should.eql 200
         data.should.eql key: 'value'
       finally
-        await srv.close()
+        await srv?.close()

   describe 'response', ->

@@ -155,7 +155,7 @@
           status_message: 'Not found'
           type: undefined
       finally
-        srv.close()
+        srv?.close()

     they 'code 301 from ipa', ({ssh}) ->
       try
@@ -165,7 +165,7 @@
           url: "http://localhost:#{srv.port}/request_301"
         status_code.should.eql 301
       finally
-        srv.close()
+        srv?.close()

     they 'content type with charset', ({ssh}) ->
       try
@@ -178,4 +178,4 @@
         status_code.should.eql 200
         data.should.eql key: 'value'
       finally
-        srv.close()
+        srv?.close()


log "Watching for changes" only in development

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -139,9 +139,8 @@

   console.log 'Mounting apps...'

-  console.log 'Watching for changes...'
-
   if NODE_ENV is 'development'
+    console.log 'Watching for changes...'
     mountAndReload = createReloadable(app, require)
     modules = _.flatten([
       glob.sync('./react/**/*.js'),


adds rss app

adds rss app

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -133,6 +133,7 @@
   app.use require "../apps/save"
   app.use require "../apps/user"
   app.use require "../apps/channel"
+  app.use require "../apps/rss"

   # Finally 404 and error handling middleware when the request wasn't handled
   # successfully by anything above.


Use the user defined action

Use the user defined action

Use the user defined action for the ember controlActionState

Using r[i] alone was breaking @match routes such as '/team' which would point to a team action when really I wanted the index. This allows me to define it. I have no Idea if this breaks resources.
When i get to point where I am actually using @resources I will loop back around.

--- packages/tower-net/client/states.coffee
+++ packages/tower-net/client/states.coffee
@@ -135,7 +135,10 @@
           Tower.router.root[methodName] = Ember.State.transitionTo(r.join('.'))
           Tower.router.root.eventTransitions[methodName] = r.join('.')

-        s = @createControllerActionState(controllerName, r[i], routeName)
+        myAction = r[i]
+        myAction = route.options.action if route.options.action?
+
+        s = @createControllerActionState(controllerName, myAction, routeName)
         state.setupChild(states, r[i], s)
         state = s


fix calculation for right+bottom margins

--- radar_chart.coffee
+++ radar_chart.coffee
@@ -4,9 +4,9 @@
     # Margins: zero if not set or the same as the opposite margin
     # (you likely want this to keep the chart centered within the widget)
     left = @get('leftMargin') || 0
-    right = if @get('rightMargin')? then @get('rightMargin') else left
+    right = @get('rightMargin') || left
     top = @get('topMargin') || 0
-    bottom = if @get('bottomMargin')? then @get('bottomMargin') else top
+    bottom = @get('bottomMargin') || top

     container = $(@node).parent()
     # Gross hacks. Let's fix this.


Fix critical attribute (it isn't called isCritical)

--- app.coffee
+++ app.coffee
@@ -400,7 +400,7 @@
 				writer.writeAttribute 'name', versionNumber

 				writer.writeAttribute 'accessible', if (isAccessible username, _package.name, versionNumber) then "true" else "false" # TODO: Use proper username
-				writer.writeAttribute 'isCritical', if (/pl/i.test versionNumber) then "true" else "false"
+				writer.writeAttribute 'critical', if (/pl/i.test versionNumber) then "true" else "false"

 				# write <fromversions>
 				if version.fromversions?.length


Make it possible to disable logging

Make it possible to disable logging

--- app.coffee
+++ app.coffee
@@ -3,7 +3,6 @@
   require('nodetime').profile
     accountKey: process.env.NODETIME_ACCOUNT_KEY
     appName: 'Snap backend'
-

 express = require('express')
 exphbs = require('express-handlebars')
@@ -15,6 +14,10 @@

 app.engine('handlebars', exphbs({defaultLayout: 'main'}))
 app.set('view engine', 'handlebars')
+
+if process.env.NO_LOGS? and process.env.NO_LOGS
+  console = {}
+  console.log = () ->

 server.listen port, ()->
   console.log('Server listening at port %d', port)


Update linux ppapi flash version

Update linux ppapi flash version

--- app.coffee
+++ app.coffee
@@ -20,7 +20,7 @@
 # Pepper Flash
 if process.platform == 'linux'
   app.commandLine.appendSwitch 'ppapi-flash-path', path.join(__dirname, 'PepperFlash', 'linux', 'libpepflashplayer.so')
-  app.commandLine.appendSwitch 'ppapi-flash-version', '17.0.0.169'
+  app.commandLine.appendSwitch 'ppapi-flash-version', '17.0.0.188'
 else if process.platform == 'win32'
   app.commandLine.appendSwitch 'ppapi-flash-path', path.join(__dirname, 'PepperFlash', 'win32', 'pepflashplayer32.dll')
   app.commandLine.appendSwitch 'ppapi-flash-version', '17.0.0.188'
@@ -43,8 +43,8 @@
       'web-security': false
       'plugins': true
   mainWindow.loadUrl "file://#{__dirname}/index.html"
-  mainWindow.openDevTools
-    detach: true
+  #mainWindow.openDevTools
+  #  detach: true
   mainWindow.on 'close', ->
     # Save current position and size
     bounds = mainWindow.getBounds()


Add link to github repository to output

Add link to github repository to output

--- app.coffee
+++ app.coffee
@@ -420,7 +420,7 @@
 		writer.writeComment "xml generated in #{(end - start) / 1e3} seconds"
 		writer.writeComment "packages scanned in #{updateTime} seconds"
 		writer.writeComment "last update #{lastUpdate}"
-		writer.writeComment "This list was presented by Tims Package Server #{serverVersion}"
+		writer.writeComment "This list was presented by Tims Package Server #{serverVersion} <https://github.com/wbbaddons/Tims-PackageServer>"
 		do writer.endElement
 		do writer.endDocument
 		res.end (do writer.toString).replace /\{\{packageServerHost\}\}/g, host