altering import to accept new user values

--- noddy/service/oabutton/api.coffee
+++ noddy/service/oabutton/api.coffee
@@ -382,7 +382,11 @@
                       rq.sherpa ?= {}
                       rq.sherpa.color = p[up]
                       update.sherpa = rq.sherpa
-                  else if up.indexOf('user.') is -1 and rq[up] isnt p[up]
+                  else if up.indexOf('user.') is 0
+                    rq.user ?= {}
+                    rq.user[up.split('.')[1]] = p[up]
+                    update.user = rq.user
+                  else if rq[up] isnt p[up]
                     rq[up] = p[up]
                     update[up] = rq[up]
               if not _.isEmpty update


Cleaned up obsolete task js.

Cleaned up obsolete task js.

--- app/assets/javascripts/app/tasks.js.coffee
+++ app/assets/javascripts/app/tasks.js.coffee
@@ -5,9 +5,6 @@

 todolist = $('ul.todo-list')

-todolist.sortable
-  handle: '.handle'
-
 todolist.on 'sortupdate', (event, ui) ->
   task = $(ui.item)
   position = task.parent().children().index(ui.item)


refactor for clarity.

refactor for clarity.

--- app/assets/javascripts/test_mode.js.coffee
+++ app/assets/javascripts/test_mode.js.coffee
@@ -1,10 +1,10 @@
 $(document).on('ready page:load', ->
   elem = $("#organization_test_mode")
   elem.bootstrapSwitch()
-  reload = ->
-    location.reload
+
   switchSuccess = ->
-    setTimeout(reload, 1000)
+    setTimeout(location.reload, 1000)
+
   elem.on('switchChange.bootstrapSwitch', ((event, state) ->
     $.ajax(url: elem.data('update-path'), complete: switchSuccess, type: 'POST', data: {"organization[testmode]": ( if state then false else true), _method: 'PATCH' } )
   ));


[backport] Small fix on addEcProduct in analytics

--- app/coffee/modules/common/analytics.coffee
+++ app/coffee/modules/common/analytics.coffee
@@ -128,9 +128,9 @@
         return if not @win.ga

         @win.ga('ec:addProduct', {
-            'id': plan.plan_id,
-            'name': plan.name,
-            'price': plan.price,
+            'id': plan_id,
+            'name': plan_name,
+            'price': plan_price,
             'category': "plans",
             'quantity': 1,
             'position': 1,


Remove stray console.log

Remove stray console.log

Apologies @snmaynard

--- plugins/bugherd/index.coffee
+++ plugins/bugherd/index.coffee
@@ -35,7 +35,6 @@
   # Receive the configuration & event payload
   @receiveEvent = (config, event, callback) ->
     return if event?.trigger?.type == 'reopened'
-    console.log config, event

     @request
       .post tasksUrl config


beaglebone-green-wifi.coffee: Point to the beaglebone yocto machine

All the beaglebone family is now using the beaglebone black resinOS image.
We shall be using it this way until we will just keep the beaglebone black
device type and remove these obsolete types.

Also change the getting started guide links.

Signed-off-by: Florin Sarbu <3a837a37a2ac9072a088641ec330e0e5d5b86f4e@resin.io>

--- beaglebone-green-wifi.coffee
+++ beaglebone-green-wifi.coffee
@@ -28,18 +28,18 @@
 	].concat(postProvisioningInstructions)

 	gettingStartedLink:
-		windows: 'http://docs.resin.io/#/pages/installing/gettingStarted-BBB.md#windows'
-		osx: 'http://docs.resin.io/#/pages/installing/gettingStarted-BBB.md#on-mac-and-linux'
-		linux: 'http://docs.resin.io/#/pages/installing/gettingStarted-BBB.md#on-mac-and-linux'
+		windows: 'https://docs.resin.io/beaglebone/nodejs/getting-started/#adding-your-first-device'
+		osx: 'https://docs.resin.io/beaglebone/nodejs/getting-started/#adding-your-first-device'
+		linux: 'https://docs.resin.io/beaglebone/nodejs/getting-started/#adding-your-first-device'

 	supportsBlink: true

 	yocto:
-		machine: 'beaglebone-green-wifi'
+		machine: 'beaglebone'
 		image: 'resin-image-flasher'
 		fstype: 'resinos-img'
 		version: 'yocto-morty'
-		deployArtifact: 'resin-image-flasher-beaglebone-green-wifi.resinos-img'
+		deployArtifact: 'resin-image-flasher-beaglebone.resinos-img'
 		compressed: true

 	options: [ networkOptions.group ]


Don't set menuOpen to false here.

Don't set menuOpen to false here.

--- js/flight.coffee
+++ js/flight.coffee
@@ -59,7 +59,6 @@
     return if @isTransitioning

     @isTransitioning = true
-    @menuOpen = false

     if @pageHistory.length is 1 and window.location.hash is @startPage
       @back = true


Prevent cache

Prevent cache

--- js/script.coffee
+++ js/script.coffee
@@ -62,4 +62,4 @@
   req.send()
   return

-loadJSON 'https://ashtanga.github.io/practice.json'
+loadJSON 'https://ashtanga.github.io/practice.json?date=' + new Date().getTime()


Refactor loops to handle edge cases in a consistent manner.

--- js2coffee.coffee
+++ js2coffee.coffee
@@ -491,10 +491,9 @@

   ForStatement: (node) ->
     # init, test, update, body
-    body = if node.update or (node.body.body.length > 0)
-      @indent => [ @walk(node.body) ]
-    else
-      @indent => [ @indent(), "continue\n" ]
+    @injectUpdateIntoBody(node)
+
+    body = @makeLoopBody(node.body)

     init = if node.init
       [ @walk(node.init), "\n", @indent() ]
@@ -506,13 +505,7 @@
     else
       [ "loop", "\n" ]

-    update = if node.update
-      @indent => [ @indent(), @walk(node.update), "\n" ]
-    else
-      [ ]
-
-    [ init, looper, body, update ]
-
+    [ init, looper, body ]

   ForInStatement: (node) ->
     if node.left.type isnt 'VariableDeclaration'
@@ -524,12 +517,18 @@
     else
       id = @walk(node.left.declarations[0].id)

-    if node.body.type is 'BlockStatement'
-      body = @indent => @walk(node.body)
-    else
-      body = @indent => [ @indent(), @walk(node.body) ]
+    body = @makeLoopBody(node.body)

     [ "for ", id, " of ", @walk(node.right), "\n", body ]
+
+  makeLoopBody: (body) ->
+    isBlock = body?.type is 'BlockStatement'
+    if not body or (isBlock and body.body.length is 0)
+      @indent => [ @indent(), "continue\n" ]
+    else if isBlock
+      @indent => @walk(body)
+    else
+      @indent => [ @indent(), @walk(body) ]

   CoffeeEscapedExpression: (node) ->
     [ '`', node.value, '`' ]
@@ -603,6 +602,19 @@
   parenthesizeObjectIfFunction: (node) ->
     if node.object.type is 'FunctionExpression'
       node.object._parenthesized = true
+
+  ###
+  # Injects a ForStatement's update (eg, `i++`) into the body.
+  ###
+
+  injectUpdateIntoBody: (node) ->
+    if node.update
+      statement =
+        type: 'ExpressionStatement'
+        expression: node.update
+      node.body ?= { type: 'BlockStatement', body: [] }
+      node.body.body = node.body.body.concat([statement])
+      delete node.update

   consolidateCases: (node) ->
     list = []
@@ -631,10 +643,13 @@

   # look for comments in left..node.range[0]
   for item, i in body
-    continue unless item.range
-    newComments = comments.filter (c) ->
-      c.range[0] >= left and c.range[1] <= item.range[0]
-    list = list.concat(newComments)
+    if item.range
+      newComments = comments.filter (c) ->
+        c.range[0] >= left and c.range[1] <= item.range[0]
+      list = list.concat(newComments)
+
     list.push item
-    left = item.range[1]
+
+    if item.range
+      left = item.range[1]
   list


Fixing File Uploads. Images are still breaking.

--- app/uploaders/gcs-uploader.coffee
+++ app/uploaders/gcs-uploader.coffee
@@ -15,6 +15,27 @@
   ###

   url: null
+  ajax: (url, params, method, headers) ->
+    self = @
+    settings =
+      url: url
+      type: method
+      contentType: false
+      processData: false
+      xhrFields:
+        withCredentials: false
+      beforeSend: (xhr)->
+        for p of headers
+          if headers.hasOwnProperty p
+            xhr.setRequestHeader p, headers[p]
+      xhr: ->
+        xhr = Ember.$.ajaxSettings.xhr()
+        xhr.upload.onprogress = (e) ->
+          self.didProgress e
+        self.one 'isAborting', -> xhr.abort()
+        xhr
+      data: params
+    @_ajax settings

   sign: (file) ->
     self = @
@@ -34,33 +55,21 @@
           reject()

-  upload: (file) ->
+  upload: (file, extra={}) ->
     self = @

     @set 'isUploading', true

     @sign file
       .then (json) ->
-        settings =
-          url: "#{json.base_url}?#{serialize json.query_params}"
-          type: "PUT"
-          data: "bloop"
-          contentType: false
-          processData: false
-          xhrFields:
-            withCredentials: false
-          beforeSend: (xhr)->
-            for p of json.headers
-              if json.headers.hasOwnProperty p
-                xhr.setRequestHeader p, json.headers[p]
-        Ember.$.ajax settings
+        data = self.setupFormData file, extra
+        url  = "#{json.base_url}?#{serialize json.query_params}"
+        self.set "isUploading", true
+
+        self.ajax(url, data, "PUT", json.headers)
           .then (respData) ->
-            Notify.info "Your file finished uploading. Please wait while we process your file."
             self.didUpload respData
             respData
-          , (respData)->
-            Notify.error "Some Error occured while uploading the file"
-
       , ->
         debugger
 `export default GCSUploader;`


Revert ":keyboard: hey look some keybindings"

This reverts commit f733ae12a261539bace3e441c70da8a7ce5b5bd6.

--- keymaps/git.cson
+++ keymaps/git.cson
@@ -3,19 +3,6 @@
   'ctrl-shift-8': 'github:toggle-github-tab'
   'ctrl-9': 'github:toggle-git-tab-focus'
   'ctrl-shift-9': 'github:toggle-git-tab'
-  'alt-g enter': 'github:commit'
-  'alt-g f': 'github:fetch'
-  'alt-g F': 'github:pull'
-  'alt-g p': 'github:push'
-  'alt-g P': 'github:force-push'
-  'alt-g =': 'github:clone'
-
-'atom-text-editor':
-  'alt-m 1': 'github:resolve-as-ours'
-  'alt-m 2': 'github:resolve-as-theirs'
-  'alt-m 3': 'github:resolve-as-base'
-  'alt-m enter': 'github:resolve-as-current'
-  'alt-m r': 'github:revert-current'

 '.github-Panel':
   'cmd-enter': 'github:commit'


Use proper methods for looking up dictionaries

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -2042,7 +2042,7 @@
     dictForConstraint ctx, constraint

 dictForConstraint = (ctx, constraint) ->
-  if constraint.type instanceof TypeVariable
+  if isNormalizedConstraint constraint
     (ctx.classParamNameFor constraint) or findSubClassParam ctx, constraint
   else if _notEmpty (constraints = (constraintsFromInstance ctx, constraint) or [])
     (jsCall (instanceDictFor ctx, constraint),
@@ -2078,7 +2078,8 @@
 instanceDictFor = (ctx, constraint) ->
   for {name, type} in (ctx.classNamed constraint.className).instances
     # TODO: support lookup of composite types, by traversing left depth-first
-    if type.type.type.name is constraint.type.name
+    if toMatchTypes type.type.type, constraint.type
+    # if type.type.type.name is constraint.type.name
       return validIdentifier name
   throw new Error "no instance for #{safePrintType constraint}"


Wip before moving to pattern directed assignment compilation

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -135,7 +135,7 @@
   constructor: ->
     @_macros = builtInMacros
     @expand = {}
-    @names = []
+    @definitions = []
     @_isOperator = []
     @variableIndex = 0
     @typeVariabeIndex = 0
@@ -150,36 +150,49 @@
   macros: ->
     @_macros

-  _name: ->
-    if @_onTopName()
-       @_currentName().name
-
-  _nameExpression: ->
-    if @_onTopName()
-      @_currentName().expression
-
-  _currentName: ->
-    @names[@names.length - 1]
-
-  setName: (expression) ->
-    @names.push
-      name: expression?.symbol
-      expression: expression
+  definePattern: (pattern) ->
+    if @isDefining()
+      throw "already defining, forgot to leaveDefinition?"
+    @_scope().definition =
+      name: pattern?.symbol
+      pattern: pattern
+      inside: 0
       deferredBindings: []
       definedNames: []
-      subs: []
-
-  subName: ->
-    @_currentName().subs.push yes
-
-  resetName: ->
-    if @_onTopName()
-      @names.pop()
-    else
-      @_currentName().subs.pop()
-
-  _onTopName: ->
-    @_currentName().subs.length is 0
+
+  leaveDefinition: ->
+    @_scope().definition = undefined
+
+  downInsideDefinition: ->
+    @_definition().inside++
+
+  upInsideDefinition: ->
+    @_definition().inside--
+
+  # If the current definition's pattern is a name, returns it
+  definitionName: ->
+    @_definition().name
+
+  definitionPattern: ->
+    @_definition().pattern
+
+  _currentDefinition: ->
+    @_scope().definition
+
+  _definition: ->
+    @_definitionAtScope @scopes.length - 1
+
+  _definitionAtScope: (i) ->
+    @scopes[i].definition or i > 0 and (@_definitionAtScope i - 1) or undefined
+
+  isDefining: ->
+    !!@_scope().definition
+
+  isAtDefinition: ->
+    (definition = @_currentDefinition()) and definition.inside is 0
+
+  # isInsideDefinition: ->
+  #   (definition = @_currentDefinition()) and definition.inside isnt 0

   isOperator: ->
     @_isOperator[@_isOperator.length - 1]
@@ -226,7 +239,10 @@
   isInTopScope: ->
     @_scope().topLevel

-  declaration: (name) ->
+  isDeclared: (name) ->
+    !!(@_declaration name)
+
+  _declaration: (name) ->
     @_declarationInScope @scopes.length - 1, name

   _declarationInScope: (i, name) ->
@@ -234,48 +250,50 @@
       i > 0 and (@_declarationInScope i - 1, name) or
       undefined # throw "Could not find declaration for #{name}"

-  addType: (name, type) ->
+  assignType: (name, type) ->
     if lookupInMap @_scope(), name
       (lookupInMap @_scope(), name).type = type
     else
-      addToMap @_scope(), name, {type}
+      throw new Error "assignType: #{name} is not declared"

   addToDeferredNames: (binding) ->
-    @_currentName().deferredBindings.push binding
+    @_definition().deferredBindings.push binding

   addToDeferred: (binding) ->
     @_scope().deferredBindings.push binding

   addToDefinedNames: (binding) ->
-    @_currentName().definedNames.push binding
+    @_definition().definedNames.push binding

   definedNames: ->
-    @_currentName().definedNames
+    @_definition().definedNames

   deferredNames: ->
-    @_currentName().deferredBindings
+    @_definition().deferredBindings

   deferredBindings: ->
     @_scope().deferredBindings

-  addToScope: (name) ->
-    addToMap @_scope(), name, {}
-
-  addArity: (name, arity) ->
+  declareArity: (name, arity) ->
+    @declare name, arity: arity
+
+  # Returns whether the declaration was successful (not redundant)
+  declare: (name, declaration = {}) ->
     if lookupInMap @_scope(), name
-      (lookupInMap @_scope(), name).arity = arity
-    else
-      addToMap @_scope(), name, {arity}
-
-  addTypes: (names, types) ->
+      false
+    else
+      addToMap @_scope(), name, declaration
+      true
+
+  declareTypes: (names, types) ->
     for name, i in names
-      @addType name, types[i]
+      @declare name, type: types[i]

   type: (name) ->
-    (@declaration name)?.type
+    (@_declaration name)?.type

   arity: (name) ->
-    (@declaration name)?.arity
+    (@_declaration name)?.arity

   freshTypeVariable: (kind) ->
     if not kind
@@ -365,10 +383,10 @@
   if isName operator
     (if operatorName of ctx.macros()
       macroCompile
-    else if ctx.arity operatorName
-      callKnownCompile
-    else
-      callUnknownCompile) ctx, call
+    else if (ctx.isDeclared operatorName) and not ctx.arity operatorName
+      callUnknownCompile
+    else
+      callKnownCompile) ctx, call
   else
     expandedOp = termCompile ctx, operator
     if isTranslated expandedOp
@@ -405,7 +423,7 @@
   paramNames = ctx.arity operator.symbol
   if not paramNames
     # log "deferring in known call #{operator.symbol}"
-    ctx.setDefer operator.symbol
+    ctx.setDefer operator, operator.symbol
     return 'deferred'
   positionalParams = filter ((param) -> not (lookupInMap labeledArgs, param)), paramNames
   nonLabeledArgs = map _snd, filter (([label, value]) -> not label), args
@@ -503,9 +521,9 @@

 operatorCompile = (ctx, call) ->
   ctx.setIsOperator yes
-  ctx.subName()
+  ctx.downInsideDefinition()
   compiledOperator = atomCompile ctx, _operator call
-  ctx.resetName()
+  ctx.upInsideDefinition()
   ctx.resetIsOperator()
   compiledOperator

@@ -544,11 +562,11 @@
   termCompile ctx, term for term in list

 termCompile = (ctx, term) ->
-  ctx.subName()
+  ctx.downInsideDefinition()
   ctx.setIsOperator no
   compiled = expressionCompile ctx, term
   ctx.resetIsOperator()
-  ctx.resetName()
+  ctx.upInsideDefinition()
   compiled

 expressionsCompile = (ctx, list) ->
@@ -657,12 +675,13 @@
 assignCompile = (ctx, expression, translatedExpression) ->
   # if not translatedExpression # TODO: throw here?
     #log expression
-  if to = ctx._nameExpression()
+  if ctx.isAtDefinition()
+    to = ctx.definitionPattern()

     ctx.setGroupTranslation()
     {precs, assigns} = patternCompile ctx, to, expression, translatedExpression

-    #log "ASSIGN #{ctx._name()}", ctx.shouldDefer()
+    #log "ASSIGN #{ctx.definitionName()}", ctx.shouldDefer()
     if ctx.shouldDefer()
       ctx.addDeferredDefinition ctx.shouldDefer().concat to, expression
       return 'deferred'
@@ -687,7 +706,7 @@
   if ctx.shouldDefer()
     for {name} in definedNames
       if not ctx.arity name
-        ctx.addToScope name
+        ctx.declare name
     #log "exiting pattern early", pattern, "for", ctx.shouldDefer()
     return {}

@@ -713,14 +732,17 @@
       ctx.addToDeferred {name, type, deps: (map (({name}) -> name), deps)}
       for dep in deps
         ctx.addToDeferred {name: dep.name, type: dep.type, deps: [name]}
-      ctx.addType name, new TempType type
-    else
-      #log "adding type for lhs #{name}", currentType
-      ctx.addArity name, [] unless ctx.arity name
-      ctx.addType name, if ctx._nameExpression()
-        quantifyAll currentType
-      else
-        toForAll currentType
+      ctx.declare name, type: new TempType type
+    else
+      # TODO: this is because functions might declare arity before being declared
+      if not ctx.isDeclared name
+        ctx.declare name
+      ctx.assignType name,
+        type:
+          if ctx.isAtDefinition()
+            quantifyAll currentType
+          else
+            toForAll currentType
   # here I will create type schemes for all definitions
   # The problem is I don't know which are impricise, because the names are done inside the
   # pattern. I can use the context to know which types where added in the current assignment.
@@ -731,9 +753,7 @@
   assigns: assigns ? []

 topLevelExpression = (ctx, expression) ->
-  ctx.setName false
   compiled = expressionCompile ctx, expression
-  ctx.resetName()
   compiled

 topLevel = (ctx, form) ->
@@ -754,6 +774,7 @@

   listOfLines compiledPairs

+# This function resolves the types of mutually recursive functions
 resolveDeferredTypes = (ctx) ->
   if _notEmpty ctx.deferredBindings()
     # TODO: proper dependency analysis to get the smallest circular deps
@@ -768,18 +789,18 @@
         # log "done unifying one"
     # log "done unifying"
     for name of values names
-      # log "done"
-      ctx.addType name, substitute ctx.substitution, canonicalType
-      # log "added"
+      # All functions must have been declared already
+      ctx.assignType name, substitute ctx.substitution, canonicalType

 compileDeferred = (ctx) ->
   compiledPairs = []
+  log "DEFED", ctx.deferred()
   if _notEmpty ctx.deferred()
     deferredCount = 0
     while (_notEmpty ctx.deferred()) and deferredCount < ctx.deferred().length
       prevSize = ctx.deferred().length
       [expression, dependencyName, lhs, rhs] = deferred = ctx.deferred().shift()
-      if ctx.declaration dependencyName
+      if ctx.isDeclared dependencyName
         compiledPairs.push definitionPairCompile ctx, lhs, rhs
       else
         # If can't compile, defer further
@@ -797,12 +818,12 @@

   compiledPairs

-definitionPairCompile = (ctx, lhs, rhs) ->
-  # log "COMPILING", lhs, rhs
-  ctx.setName lhs
+definitionPairCompile = (ctx, pattern, value) ->
+  # log "COMPILING", pattern, value
+  ctx.definePattern pattern
   # log "deferrement before assign !!!", ctx.shouldDefer()
-  compiled = expressionCompile ctx, rhs
-  ctx.resetName()
+  compiled = expressionCompile ctx, value
+  ctx.leaveDefinition()
   if ctx.shouldDefer()
     # log "RESETTING DEFER"
     ctx.setDefer false
@@ -831,7 +852,7 @@
       paramTypes = map (-> toForAll ctx.freshTypeVariable star), params
       ctx.newLateScope()
       # log "adding types", (map _symbol, params), paramTypes
-      ctx.addTypes (map _symbol, params), paramTypes
+      ctx.declareTypes (map _symbol, params), paramTypes

       #log "compiling wheres", pairs wheres
       compiledWheres = definitionList ctx, pairs wheres
@@ -850,10 +871,12 @@
         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()
-        #log "adding arity for #{ctx._name()}", paramNames
-        ctx.addArity ctx._name(), paramNames
+      # Arity - before deferring instead put to assignCompile, because this makes the naming of functions special
+      if ctx.definitionName()
+        #log "adding arity for #{ctx.definitionName()}", paramNames
+        ctx.declareArity ctx.definitionName(), paramNames
+
+      # log "inside #{ctx.definitionName()}", ctx.shouldDefer(), body.tea

       assignCompile ctx, call,
         if ctx.shouldDefer()
@@ -879,7 +902,10 @@
   data: (ctx, call) ->
     defs = pairsLeft isAtom, _arguments call
     # Syntax
-    syntaxNewName 'Name required to declare new algebraic data', ctx._nameExpression()
+    if ctx.isAtDefinition()
+      syntaxNewName 'Name required to declare new algebraic data', ctx.definitionPattern()
+    else
+      malformed call, 'Name required to declare new algebraic data'
     [names, typeArgLists] = unzip defs
     map (syntaxNewName 'Type constructor name required'), names
     for typeArgs in typeArgLists
@@ -888,23 +914,25 @@
           syntaxType type
       else
         typeArgs.label = 'malformed'
-    # Types
+    dataName = ctx.definitionName()
+    if not dataName
+      return 'malformed'
+
+    # Types, Arity
     for [constr, params] in defs
       constrType = desiplifyType if params
-        join (_labeled _terms params).map(_snd).map(_symbol), [ctx._name()]
+        join (_labeled _terms params).map(_snd).map(_symbol), [dataName]
       else
-        ctx._name()
+        dataName
       # TODO support polymorphic data
       #log "Adding constructor #{constr.symbol}"
-      ctx.addType constr.symbol, toForAll constrType
+      ctx.declare constr.symbol,
+        type: toForAll constrType
+        arity: ((_labeled _terms params).map(_fst).map(_labelName) if params)
       constr.tea = constrType
-    # TODO: support polymorphic data
-    # We don't add binding to types, but maybe need to store elsewhere
-    # ctx.addType ctx._name(), typeConstant ctx._name()
-    # Arity
-    for [constr, params] in defs when params
-      ctx.addArity constr.symbol,
-        (_labeled _terms params).map(_fst).map(_labelName)
+    # We don't add binding to kind constructors, but maybe we need to
+    # ctx.addType dataName, typeConstant dataName
+
     # Translate
     listOfLines (for [constr, params] in defs
       identifier = validIdentifier constr.symbol
@@ -934,9 +962,9 @@
         syntaxType type
     if args.length is 0
       malformed call, 'Missing arguments'
-    # TS: (data #{ctx._name()} [#{_arguments form}])
+    # TS: (data #{ctx.definitionName()} [#{_arguments form}])
     replicate call,
-      (call_ (token_ 'data'), [(token_ ctx._name()), (tuple_ args)])
+      (call_ (token_ 'data'), [(token_ ctx.definitionName()), (tuple_ args)])

   # TODO:
   # For now support the simplest function macros, just compiling down to source
@@ -950,7 +978,7 @@

   #   ctx.
   #   # then in assign compile:
-  #   ctx.macros[ctx._name()]
+  #   ctx.macros[ctx.definitionName()]

   # match
@@ -975,11 +1003,9 @@
     compiledCases = conditional (for [pattern, result] in pairs cases

       ctx.newScope() # for variables defined inside pattern
-      ctx.setName()

       {precs, assigns} = patternCompile ctx, pattern, subject, subjectCompiled

-      ctx.resetName()
       # Compile the result, given current scope
       compiledResult = termCompile ctx, result #compileImpl result, furtherHoistable
       ctx.closeScope()
@@ -997,6 +1023,15 @@
       ctx.translationCache()
       varList varNames
       compiledCases])
+  '=': (ctx, call) ->
+    [a, b] = _arguments call
+    operatorCompile ctx, call
+    compiledA = termCompile ctx, a
+    compiledB = termCompile ctx, b
+
+    callTyping ctx, call
+    assignCompile ctx, call, "(#{compiledA} === #{compiledB})"
+

 # Creates the condition and body of a branch inside match macro
 matchBranchTranslate = (precs, assigns, compiledResult) ->
@@ -1131,7 +1166,7 @@
         translation: nameTranslate ctx, atom, symbol
       }
     # Inside function only defer compilation if we don't know arity
-    else if ctx.isInLateScope() and (ctx.declaration symbol) or contextType instanceof TempType
+    else if ctx.isInLateScope() and (ctx.isDeclared symbol) or contextType instanceof TempType
       # Typing deferred, use an impricise type var
       type = ctx.freshTypeVariable star
       ctx.addToDeferredNames {name: symbol, type: type}
@@ -1956,9 +1991,12 @@
 mapToArray = (map) ->
   val for key, val of map.values

-cloneSet = (set) ->
+cloneSet =
+cloneMap = (set) ->
   clone = newSet()
-  addAllToSet clone, setToArray set
+  for key, val of set.values
+    addToMap clone, key, val
+  clone

 lookupInMap =
 inSet = (set, name) ->
@@ -2398,10 +2436,16 @@
   jsWithAstTypes ctx, ast, compiled

 compileTopLevelAndExpression = (source) ->
-  [terms..., expression] = _terms astize tokenize source
+  (topLevelAndExpression source).compiled
+
+topLevelAndExpression = (source) ->
+  ast = astize tokenize "(#{source})", -1
+  [terms..., expression] = _terms ast
   compiledDefinitions = definitionList (ctx = new Context), pairs terms
   compiledExpression = topLevelExpression ctx, expression
-  jsWithAstTypes ctx, null, library + compiledDefinitions + compiledExpression
+  types: ctx._scope()
+  ast: ast
+  compiled: library + compiledDefinitions + compiledExpression

 jsWithAstTypes = (ctx, ast, js) ->
   types = values mapMap _type, ctx._scope()
@@ -2475,45 +2519,39 @@

 # end of Utils

-
-
-exports.compileTopLevel = compileTopLevel
-exports.compileTopLevelAndExpression = compileTopLevelAndExpression
-exports.astizeList = astizeList
-exports.astizeExpression = astizeExpression
-exports.astizeExpressionWithWrapper = astizeExpressionWithWrapper
-exports.syntaxedExpHtml = syntaxedExpHtml
-
-# exports.compileModule = (source) ->
-#   """
-#   #{library}
-#   var exports = {};
-#   #{compileDefinitionsInModule source}
-#   exports"""
-
-exports.library = library
-
-exports.isForm = isForm
-exports.isAtom = isAtom
-
-
-exports.join = join
-exports.concatMap = concatMap
-exports.concat = concat
-exports.id = id
-exports.map = map
-exports.allMap = allMap
-exports.all = all
-exports.filter = filter
-exports.partition = partition
-exports._notEmpty = _notEmpty
-exports._is = _is
-exports.__ = __
-
-exports._operator = _operator
-exports._arguments = _arguments
-exports._terms = _terms
-exports._snd = _snd
-exports._fst = _fst
-exports._labelName = _labelName
-exports._symbol = _symbol+# Unit tests
+test = (teaSource, result) ->
+  try
+    result is (eval compileTopLevelAndExpression teaSource)
+  catch e
+    log "Error in test", e.message
+
+tests = [
+  """a 2
+    a""", 2
+  """a 2
+    b 3
+    a""", 2
+  """Color (data Red Blue)
+    r Red
+    b Blue
+    r2 Red
+    (= r r2)""", true
+  """Person (data
+    Baby
+    Adult [name: String])
+    a (Adult "Adam")
+    b Baby
+    c (Adult "Adam")
+    (= (Adult.name a) (Adult.name c))
+  """, true
+]
+
+runTests = (tests) ->
+  for [source, result] in pairs tests
+    #log (topLevelAndExpression source).compiled
+    log (collapse toHtml (topLevelAndExpression source).ast),
+      test source, result
+  "Finished"
+# end of tests
+


Fixed deferring by deferring on only pre-declared definitions

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -454,9 +454,15 @@
   #   final: Bool

   isDeclared: (name) ->
-    !!(@_declaration name)
+    !!@_declaration name
+
+  isFinallyDeclared: (name) ->
+    (declaration = @_declaration name) and declaration.final

   isCurrentlyDeclared: (name) ->
+    !!@_declarationInCurrentScope name
+
+  isFinallyCurrentlyDeclared: (name) ->
     (declaration = @_declarationInCurrentScope name) and declaration.final

   isTyped: (name) ->
@@ -1168,9 +1174,13 @@
   # log "is deferriing", (print pattern), ctx.shouldDefer()
   # Make sure deferred names are added to scope so they are compiled within functions
   if ctx.shouldDefer()
+    shouldDeclareFinally = ctx.isDeclared ctx.deferReason()[1]
     for {name, id} in definedNames
       if not ctx.isCurrentlyDeclared name
-        ctx.declare name, id: id
+        if shouldDeclareFinally
+          ctx.declare name, id: id
+        else
+          ctx.preDeclare name, id: id
     #log "exiting pattern early", pattern, "for", ctx.shouldDefer()
     return {}

@@ -1198,7 +1208,8 @@
         deps: deps#(map (({name}) -> name), deps)
       # for dep in deps
       #   ctx.addToDeferred {name: dep.name, type: dep.type, reversed: name}
-      ctx.assignType name, (new TempType type)
+      if not ctx.isTyped name
+        ctx.assignType name, (new TempType type)
     else
       # Ready for typing since there are no missing dependencies
       inferType ctx, name, type, constraints, polymorphic
@@ -1221,7 +1232,7 @@
       unifiedType = substitute ctx.substitution, explicitType
       inferredType = quantifyUnbound ctx, unifiedType
       if not typeEq inferredType, updatedDeclaredType
-        ctx.extendSubstitution substituionFail "#{name}'s declared type is too general, inferred #{plainPrettyPrint inferredType}"
+        ctx.extendSubstitution substitutionFail "#{name}'s declared type is too general, inferred #{plainPrettyPrint inferredType}"
       # Context reduction
       isDeclaredConstraint = (c) ->
         entailed = entail ctx, unifiedType.constraints, c
@@ -1232,7 +1243,7 @@
       catch e
         throw new Error "Error when deferring #{name} #{e.message}"
       if _notEmpty retainedConstraints
-        ctx.extendSubstitution substituionFail "#{name}'s context is too weak, missing #{listOf (map printType, retainedConstraints)}"
+        ctx.extendSubstitution substitutionFail "#{name}'s context is too weak, missing #{listOf (map printType, retainedConstraints)}"
   else
     # log name, "constraints", (substituteList ctx.substitution, constraints)
     [deferredConstraints, retainedConstraints] = deferConstraints ctx,
@@ -1241,7 +1252,7 @@
     currentType = substitute ctx.substitution, type
     # log "assign type", name, (printType (addConstraints currentType, retainedConstraints)), (printType quantifyUnbound ctx, (addConstraints currentType, retainedConstraints))
     if includesJsType currentType.type
-      ctx.extendSubstitution substituionFail "#{name}'s inferred type includes JS"
+      ctx.extendSubstitution substitutionFail "#{name}'s inferred type includes JS"
     else
       ctx.assignType name,
         if polymorphic
@@ -1338,7 +1349,7 @@
         allConstraints = (join binding.constraints or [], depConstraints)

         # If the thing is not declared it must be coming from an outer scope
-        # add it as a missing name to the current definition
+        # add it is a missing name to the current definition

         if (not ctx.isCurrentlyDeclared name)
           if ctx.isInTopScope()
@@ -1351,9 +1362,6 @@
           # log binding.constraints, depConstraints
           inferType ctx, name, canonicalType,
             allConstraints, binding.polymorphic
-          # unifiedType = (substitute ctx.substitution, canonicalType)
-          # ctx.assignType name,
-          #   quantifyAll (addConstraints unifiedType, definitionConstraints)
   ctx.deferredBindings().length = 0 # clear

 compileDeferred = (ctx) ->
@@ -1412,14 +1420,14 @@
         [body, wheres...] = defs
       paramNames = _names params

-      # Arity - before deferring instead? put to assignCompile, because this makes the naming of functions special
+      # Predeclare type
       if name = ctx.isAtSimpleDefinition()
         # Explicit typing
         if type
-          explicitType = declareExplicitlyTyped ctx, typeConstrainedCompile ctx, type
+          explicitType = preDeclareExplicitlyTyped ctx, typeConstrainedCompile ctx, type
           ctx.assignArity name, paramNames
         else
-          ctx.declare name,
+          ctx.preDeclare name,
             arity: paramNames
             id: ctx.definitionId()
             type: ctx.preDeclaredType name # if any
@@ -1493,16 +1501,16 @@
             #     body: (join compiledWheres, [(jsReturn compiledBody)]))])

 # Assumes definition name
-declareExplicitlyTyped = (ctx, type) ->
+preDeclareExplicitlyTyped = (ctx, type) ->
   explicitType = quantifyUnbound ctx, type
   name = ctx.definitionName()
   if ctx.isPreTyped name
     # TODO: unify explicit types like in inferType
     explicitType = ctx.preDeclaredType name
-  if ctx.isCurrentlyDeclared name
+  if ctx.isFinallyCurrentlyDeclared name
     malformed ctx, ctx.definitionPattern(), 'This name is already taken'
   else
-    ctx.declare name,
+    ctx.preDeclare name,
       id: ctx.definitionId()
       type: explicitType
   explicitType
@@ -1665,7 +1673,7 @@
       else
         typeConstrainedCompile ctx, call
     if hasName
-      declareExplicitlyTyped ctx, compiledType
+      preDeclareExplicitlyTyped ctx, compiledType
     # TODO: support typing of expressions,
     #watch out of definition patterns without a name
     jsNoop()
@@ -1679,7 +1687,7 @@
     expression = constraintSeq
   compiledType = new Constrained constraints, typeCompile ctx, type
   if name = ctx.definitionName()
-    declareExplicitlyTyped ctx, compiledType
+    preDeclareExplicitlyTyped ctx, compiledType
   call.tea = compiledType
   assignCompile ctx, call, (termCompile ctx, expression)

@@ -2486,9 +2494,9 @@
     if contextType and contextType not instanceof TempType
       type = freshInstance ctx, contextType
       nameTranslate ctx, atom, symbol, type
-    # Inside function only defer compilation if we don't know arity
+    # In sub-scope (function) only defer compilation for declarations in current scope
     else if (not ctx.isCurrentlyDeclared symbol) and
-        (ctx.isDeclared symbol) or contextType instanceof TempType
+        (ctx.isFinallyDeclared symbol) or contextType instanceof TempType
       # Typing deferred, use an impricise type var
       type = toConstrained ctx.freshTypeVariable star
       ctx.addToDeferredNames {name: symbol, type: type}
@@ -4085,7 +4093,7 @@
       [t2, t1]
     else
       [t1, t2]
-  substituionFail
+  substitutionFail
     message: "#{message} #{(safePrintType first)}, #{(safePrintType second)}"
     conflicts: [first.origin, second.origin]

@@ -4181,7 +4189,7 @@
 isFailed = (sub) ->
   sub.fails.length > 0

-substituionFail = (failure) ->
+substitutionFail = (failure) ->
   sub = emptySubstitution()
   sub.fails.push failure
   sub


Allow non-alphabetic type names

Allow non-alphabetic type names

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1083,10 +1083,10 @@
   type =
     if expanded is atom.symbol
       kindOfType =
-        if isCapital atom
+        if isNotCapital atom
+          expectedKind or star
+        else
           ctx.kindOfTypeName atom.symbol
-        else
-          expectedKind or star
       if kindOfType instanceof TempKind
         kindOfType = expectedKind
       if not kindOfType
@@ -2176,7 +2176,9 @@
 ms.syntax = ms_syntax = (ctx, call) ->
   hasName = requireName ctx, 'Name required to declare a new syntax macro'
   [paramTuple, rest...] = _arguments call
-  [body] = rest
+  [maybeType] = rest
+
+  doDeclare =  isTypeAnnotation maybeType

   if hasName
     macroName = ctx.definitionName()
@@ -2200,7 +2202,11 @@
     else
       malformed ctx, ctx.definitionPattern(), 'Macro failed to compile'

-  jsNoop()
+  if isTypeAnnotation maybeType
+    params = (map token_, map _symbol, _terms paramTuple)
+    typedFn_ params, maybeType, call_ (token_ macroName), params
+  else
+    jsNoop()

 ms['`'] = ms_quote = (ctx, call) ->
   expression = firstOrCall _arguments call
@@ -2782,7 +2788,7 @@
 syntaxType = (expression) ->
   # ignore type classes for now
   if isName expression
-    expression.label = if isCapital then 'typename' else 'typevar'
+    expression.label = if isNotCapital expression then 'typevar' else 'typename'
   else if isTuple expression
     map syntaxType, (_terms expression)
   else if isCall expression
@@ -3103,7 +3109,10 @@
   /[^\\]:$/.test atom.symbol

 isCapital = (atom) ->
-  /[A-Z]/.test atom.symbol
+  /^[A-Z]/.test atom.symbol
+
+isNotCapital = (atom) ->
+  /^[a-z]/.test atom.symbol

 isName = (expression) ->
   throw new Error "Nothing passed to isName" unless expression
@@ -3985,23 +3994,23 @@
   #   'empty-array', (type: (parseUnConstrainedType '(Fn (Array a))'), arity: [])
   #   'cons-array', (type: (parseUnConstrainedType '(Fn a (Array a) (Array a))'), arity: ['what', 'onto'])

-desiplifyTypeAndArity = (simple) ->
-  type = parseUnConstrainedType simple
-  args = collectArgs type.type.type
-  arity = if Array.isArray args then args.length else 0
-  type: type
-  arity: ("a#{i}" for i in  [0...arity - 2])
-
-parseUnConstrainedType = (string) ->
-  quantifyAll toConstrained typeCompile astize tokenize string
-
-desiplifyType = (simple) ->
-  if Array.isArray simple
-    typeFn (map desiplifyType, simple)...
-  else if /^[A-Z]/.test simple
-    typeConstant simple
-  else
-    new TypeVariable simple, star
+# desiplifyTypeAndArity = (simple) ->
+#   type = parseUnConstrainedType simple
+#   args = collectArgs type.type.type
+#   arity = if Array.isArray args then args.length else 0
+#   type: type
+#   arity: ("a#{i}" for i in  [0...arity - 2])
+
+# parseUnConstrainedType = (string) ->
+#   quantifyAll toConstrained typeCompile astize tokenize string
+
+# desiplifyType = (simple) ->
+#   if Array.isArray simple
+#     typeFn (map desiplifyType, simple)...
+#   else if /^[A-Z]/.test simple
+#     typeConstant simple
+#   else
+#     new TypeVariable simple, star

 # Set/Map implementation
@@ -4568,10 +4577,10 @@

 # Either a type variable or type constructor of some kind
 atomicType = (name, kind) ->
-  if /^[A-Z]/.test name
+  if (isNotCapital symbol: name)
+    new TypeVariable name, kind
+  else
     new TypeConstr name, kind
-  else
-    new TypeVariable name, kind

 tupleType = (arity) ->
   new TypeConstr "[#{arity}]", kindFn arity


Remove the check

Remove the check

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -4450,7 +4450,6 @@
   typeOrConstraint

 mutateMarkingOrigin = (typeOrConstraint, expression) ->
-  throw new Error "Mutating type with origin #{printType typeOrConstraint}" if typeOrConstraint.origin
   typeOrConstraint.origin = expression

 # Clones constrained types and parts of them


Wip on better constraints, fixed param names in constrained calls and colored type annotations

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -2385,8 +2385,12 @@
 #       is not a function then it can't need type class dictionaries
 #       ^.___ not necessarily, we could have a tuple of functions or similar
 irDefinitionTranslate = (ctx, {type, expression, id}) ->
-  finalType = addConstraintsFrom ctx, {id, type}, substitute ctx.substitution, type
-  reducedConstraints = reduceConstraints ctx, finalType.constraints
+  finalType = substitute ctx.substitution, type
+  reducedConstraints =
+    # if declaredType = ctx.typeForId id
+    #   constraintsFromCanonicalType ctx, declaredType, finalType
+    # else
+      reduceConstraints ctx, (addConstraintsFrom ctx, {id, type}, finalType).constraints
   ctx.updateClassParams()
   # TODO: what about the class dictionaries order?
   counter = {}
@@ -2453,10 +2457,11 @@
   else
     finalType = addConstraintsFrom ctx, {id, type}, substitute ctx.substitution, type
     classParams = dictsForConstraint ctx, finalType.constraints
+    params = map validIdentifier, arity
     if classParams.length > 0
       (irFunctionTranslate ctx,
-        params: arity
-        body: [(jsReturn (jsCall (validIdentifier name), (join classParams, arity)))])
+        params: params
+        body: [(jsReturn (jsCall (validIdentifier name), (join classParams, params)))])
     else
       validIdentifier name

@@ -2492,7 +2497,9 @@

 findSubClassParam = (ctx, constraint) ->
   toClassName = (c) -> c.className
-  for className, dict of values ctx.classParamsForType constraint
+  classParams = ctx.classParamsForType constraint
+  throw new Error "No params for #{safePrintType constraint}" unless classParams
+  for className, dict of values classParams
     if chain = findSuperClassChain ctx, className, constraint.className
       return accessList dict, chain
   throw new Error "Couldn't find dict for #{safePrintType constraint}"
@@ -4070,6 +4077,9 @@
 addConstraints = ({constraints, type}, addedConstraints) ->
   new Constrained (join constraints, addedConstraints), type

+replaceConstraints = ({type}, constraints) ->
+  new Constrained constraints, type
+
 toConstrained = (type) ->
   new Constrained [], type

@@ -4104,13 +4114,19 @@
     return "#{type}"

 prettyPrint = (type) ->
+  prettyPrintWith highlightType, type
+
+plainPrettyPrint = (type) ->
+  prettyPrintWith printType, type
+
+prettyPrintWith = (printer, type) ->
   if type.ForAll
-    prettyPrint type.type
+    prettyPrintWith printer, type.type
   else if type.Constrained
     if _notEmpty type.constraints
-      (map highlightType, join [type.type], type.constraints).join ' '
+      (map printer, join [type.type], type.constraints).join ' '
     else
-      highlightType type.type
+      printer type.type

 printType = (type) ->
   if type.TypeVariable
@@ -4471,7 +4487,7 @@
   [typed, notTyped] = partitionMap typesUnify, validDefinitions
   # allDefs = join (setToArray typed), (setToArray notTyped)
   allDefs = concatMaps typed, notTyped # TODO: don't use object key ordering for ordering
-  values mapMap (__ prettyPrint, _type), allDefs
+  values mapMap (__ plainPrettyPrint, _type), allDefs

 # API

@@ -5443,6 +5459,10 @@
   concat-map (fn [what over]
     (concat (map what over)))

+  concat-with (fn [with what]
+    (fold join-with empty what)
+    join-with (fn [x joined]
+      (concat {joined with x})))
   """
   "(size (concat-map (fn [x] {}) {1 2 3}))", 0


Remove obsolete spec now that there's a different new answer form

--- spec/javascripts/views/question_view_spec.js.coffee
+++ spec/javascripts/views/question_view_spec.js.coffee
@@ -37,15 +37,6 @@
       questionView.personalVote.append(item1)
       questionView.updateAnswerRanking(item1)
       expect(questionView.personalVote.find('.answer').length).toBe 2
-
-  describe "when a new answer is submitted", ->
-    it "adds that answer to the list and clears the textarea", ->
-      questionView = new Views.QuestionView(question)
-      questionView.newAnswerTextarea.val("Violet")
-      questionView.createAnswer()
-      expect(questionView.newAnswerTextarea.val()).toBe ""
-      Monarch.Remote.Server.lastCreate().succeed()
-      expect(questionView.collectiveVote.find('.answer').length).toBe 4

   describe "when items are dragged into / within the personal ranking list", ->
     it "creates / updates a ranking for the dragged answer", ->


FIX: Make endOpened false when start date is selected

--- src/app/teaching-periods/states/edit/directives/teaching-period-details-editor/teaching-period-details-editor.coffee
+++ src/app/teaching-periods/states/edit/directives/teaching-period-details-editor/teaching-period-details-editor.coffee
@@ -27,6 +27,7 @@

       if pickerData == 'start'
         $scope.calOptions.startOpened = ! $scope.calOptions.startOpened
+        $scope.calOptions.endOpened = false
         $scope.calOptions.activeUntilOpened = false
       else if pickerData == 'end'
         $scope.calOptions.startOpened = false


better request sort for exact matches

better request sort for exact matches

--- SingularityUI/app/views/requests.coffee
+++ SingularityUI/app/views/requests.coffee
@@ -63,7 +63,7 @@
                 o.requestDeployState?.activeDeploy?.user or ''
         res1 = fuzzy.filter(filter, requests, id)
         res2 = fuzzy.filter(filter, requests, user)
-        _.pluck(_.sortBy(_.union(res1, res2), (r) => r.score), 'original')
+        _.pluck(_.sortBy(_.union(res2, res1), (r) => r.score), 'original')

     # Returns the array of requests that need to be rendered
     filterCollection: =>


rename notifications -> inbound; friendUpdate -> friendsUpdate

--- routes/index.coffee
+++ routes/index.coffee
@@ -41,13 +41,13 @@
   req.body.secret = undefined

   for friendId in req.body.friends
-    firebase.child('notifications').child(friendId).push
+    firebase.child('inbound').child(friendId).push
       dts: req.body.dts
-      type: 'friendUpdate'
+      type: 'friendsUpdate'
       friendId: req.body.userId
-  firebase.child('notifications').child(req.body.userId).push
+  firebase.child('inbound').child(req.body.userId).push
     dts: req.body.dts
-    type: 'friendUpdate'
+    type: 'friendsUpdate'

   msg = "submitting new user notification to firebase: "+ JSON.stringify req.body


Profile: Since counts are not shown all related count functions are regressed

--- client/Social/Members/AppController.coffee
+++ client/Social/Members/AppController.coffee
@@ -100,9 +100,6 @@
           dataSource        : (selector, options, callback)=>
             options.groupId or= KD.getGroup().getId()
             account.fetchFollowersWithRelationship selector, options, callback
-
-            account.countFollowersWithRelationship selector, (err, count)=>
-              @setCurrentViewNumber 'followers', count
         following           :
           loggedInOnly      : yes
           itemClass         : GroupMembersPageListItemView
@@ -112,9 +109,6 @@
           dataSource        : (selector, options, callback)=>
             options.groupId or= KD.getGroup().getId()
             account.fetchFollowingWithRelationship selector, options, callback
-
-            account.countFollowingWithRelationship selector, (err, count)=>
-              @setCurrentViewNumber 'following', count
         likes               :
           loggedInOnly      : yes
           noItemFoundText   : "#{owner} #{auxVerb.have} not liked any posts yet."
@@ -132,9 +126,6 @@
               KD.mixpanel "Load member list, success"  unless err
               callback err, res

-            group.countMembers (err, count) =>
-              count = 0 if err
-              @setCurrentViewNumber 'all', count
       sort                  :
         'modifiedAt'        :
           title             : "Latest activity"
@@ -172,23 +163,6 @@
     KD.singleton('display').emit "ContentDisplayWantsToBeShown", contentDisplay
     return contentDisplay

-  setCurrentViewNumber:(type, count)->
-    countFmt = count.toLocaleString() ? "n/a"
-    @getView().$(".feeder-header span.member-numbers-#{type}").text countFmt
-
-  setCurrentViewHeader:(count)->
-    if typeof 1 isnt typeof count
-      @getView().$(".feeder-header span.optional_title").html count
-      return no
-
-    if count >= 10 then count = '10+'
-    # return if count % 10 is 0 and count isnt 20
-    # postfix = if count is 10 then '+' else ''
-    count   = 'No' if count is 0
-    result  = "#{count} member" + if count isnt 1 then 's' else ''
-    title   = "#{result} found for <strong>#{@_searchValue}</strong>"
-    @getView().$(".feeder-header span.optional_title").html title
-
   fetchFeedForHomePage:(callback)->
     options  =
       limit  : 6


Fixed: shown notification counter. Close #187

--- client/app/views/notifications_view.coffee
+++ client/app/views/notifications_view.coffee
@@ -59,9 +59,9 @@
             imgPath = 'img/notification-white.png'
             @$('#notifications-toggle img').attr 'src', imgPath
             @$('#notifications-toggle').removeClass 'highlight'
-        #else
-            #@counter.html newCount
-            #@counter.show()
+        else
+            @counter.html newCount
+            @counter.show()

     windowClicked: =>
         if event? and @$el.has($(event.target)).length is 0


Reducing undesired computations on membersList Template

--- client/views/app/tabBar/membersList.coffee
+++ client/views/app/tabBar/membersList.coffee
@@ -3,19 +3,16 @@
 		return t('Add_users')

 	isGroupChat: ->
-		room = ChatRoom.findOne(Session.get('openedRoom'), { reactive: false })
-		return room?.t in ['c', 'p']
+		return ChatRoom.findOne(this.rid, { reactive: false })?.t in ['c', 'p']

 	isDirectChat: ->
-		room = ChatRoom.findOne(Session.get('openedRoom'), { reactive: false })
-		return room?.t is 'd'
+		return ChatRoom.findOne(this.rid, { reactive: false })?.t is 'd'

 	roomUsers: ->
-		room = ChatRoom.findOne(Session.get('openedRoom'), { reactive: false })
 		users = []
 		onlineUsers = RoomManager.onlineUsers.get()

-		for username in room?.usernames or []
+		for username in ChatRoom.findOne(this.rid)?.usernames or []
 			if onlineUsers[username]?
 				utcOffset = onlineUsers[username]?.utcOffset
 				if utcOffset?
@@ -32,15 +29,15 @@
 		users = _.sortBy users, 'username'

 		ret =
-			_id: Session.get('openedRoom')
-			total: room?.usernames?.length or 0
+			_id: this.rid
+			total: ChatRoom.findOne(this.rid)?.usernames?.length or 0
 			totalOnline: users.length
 			users: users

 		return ret

 	canAddUser: ->
-		roomData = Session.get('roomData' + Session.get('openedRoom'))
+		roomData = Session.get('roomData' + this._id)
 		return '' unless roomData
 		return roomData.t in ['p', 'c'] and roomData.u?._id is Meteor.userId()

@@ -67,7 +64,7 @@
 		return Meteor.users.findOne({ username: String(username) }) or { username: String(username) }

 	showUserInfo: ->
-		webrtc = WebRTC.getInstanceByRoomId(Session.get('openedRoom'))
+		webrtc = WebRTC.getInstanceByRoomId(this.rid)
 		videoActive = webrtc?.localUrl?.get()? or webrtc?.remoteItems?.get()?.length > 0
 		return Session.get('showUserInfo') and not videoActive

@@ -77,7 +74,8 @@
 		Session.set('showUserInfo', $(e.currentTarget).data('username'))

 	'autocompleteselect #user-add-search': (event, template, doc) ->
-		roomData = Session.get('roomData' + Session.get('openedRoom'))
+
+		roomData = Session.get('roomData' + template.data.rid)

 		if roomData.t is 'd'
 			Meteor.call 'createGroupRoom', roomData.usernames, doc.username, (error, result) ->


payments: WIP

payments: WIP

--- client/landing/app/Applications/Account.kdapplication/views/paymentmethods.coffee
+++ client/landing/app/Applications/Account.kdapplication/views/paymentmethods.coffee
@@ -14,7 +14,26 @@
     list.on 'ItemWasAdded', (item) =>
       item.on 'PaymentMethodEditRequested', @bound 'editPaymentMethod'
       item.on 'PaymentMethodRemoveRequested', (data) =>
-        @removePaymentMethod data, item
+        modal = new KDModalView
+          title: 'Are you sure?'
+          content:
+            """
+

+

+                Are you sure that you want to remove this payment method?
+

+

+            """
+          buttons:
+            Yes:
+              style: "modal-clean-red"
+              callback: =>
+                modal.destroy()
+                @removePaymentMethod data, item
+            cancel:
+              style: "modal-cancel"
+              callback: ->
+                modal.destroy()

     list.on 'reload', (data) => @loadItems()

@@ -24,7 +43,7 @@
   removePaymentMethod: ({ accountCode }, item) ->
     paymentController = KD.getSingleton 'paymentController'
     paymentController.removePaymentMethod accountCode, =>
-      debugger
+      @removeItem item

   loadItems: ->
     @removeAllItems()
@@ -47,12 +66,15 @@
   showModal: ->
     paymentController = KD.getSingleton 'paymentController'
     modal = paymentController.createBillingInfoModal 'user', {}
-    paymentController.fetchBillingInfo 'user', (err, initialBillingInfo) ->
+    paymentController.fetchBillingInfo 'user', (err, initialBillingInfo) =>

       modal.setBillingInfo initialBillingInfo.billing  if initialBillingInfo?

-      modal.on 'PaymentInfoSubmitted', (updatedBillingInfo) ->
-        paymentController.updateBillingInfo updatedBillingInfo
+      modal.on 'PaymentInfoSubmitted', (updatedBillingInfo) =>
+        paymentController.updateBillingInfo updatedBillingInfo, (err, res)->
+          console.log arguments
+        # @addItem updatedBillingInfo
+

 class AccountPaymentMethodsList extends KDListView


Fetch and show topic posts correctly

Fetch and show topic posts correctly

--- client/landing/app/Applications/Topics.kdapplication/ContentDisplays/Topic.coffee
+++ client/landing/app/Applications/Topics.kdapplication/ContentDisplays/Topic.coffee
@@ -32,20 +32,29 @@
       limitPerPage        : 5
       filter              :
         content           :
-          title           : 'All content'
+          title           : 'Everything'
           dataSource      : (selector, options, callback)->
-            topic.fetchContentTeasers (err, teasers)->
+            topic.fetchContentTeasers options, (err, teasers)->
               callback err, teasers
-        codeshares        :
-          title           : 'Code shares'
-          dataSource      : -> log 'just code shares'
-        developers        :
-          title           : 'Developers'
-          dataSource      : -> log 'just developers'
+        statusupdates     :
+          title           : 'Status Updates'
+          dataSource      : (selector, options, callback)->
+            selector = {targetName: 'JStatusUpdate'}
+            topic.fetchContentTeasers options, selector, (err, teasers)->
+              callback err, teasers
+        codesnippets      :
+          title           : 'Code Snippets'
+          dataSource      : (selector, options, callback)->
+            selector = {targetName: 'JCodeSnip'}
+            topic.fetchContentTeasers options, selector, (err, teasers)->
+              callback err, teasers
       sort                :
-        'meta.modifiedAt' :
+        'timestamp|new'   :
           title           : 'Latest activity'
           direction       : -1
+        'timestamp|old'   :
+          title           : 'Most activity'
+          direction       : 1
     }, (controller)->
       mainView.addSubView controller.getView()


:arrow_up: add link item description

:arrow_up: add link item description

--- src/renderer/components/index-component.coffee
+++ src/renderer/components/index-component.coffee
@@ -25,20 +25,22 @@

-

+

           <Link href='/overview' style={styles.link}>
-

+

-
OverView

+
OverView

+
Tutorial, tags, tips. You can post sample codes and share.

           </Link>

-

+

           <Link href='/class' style={styles.link}>
-

+

-
Reference

+
Reference

+
jThree API reference. You can search classes, methods, properties...

           </Link>

@@ -108,30 +110,40 @@
     flexWrap: 'nowrap'
     justifyContent: 'space-around'

-  container:
+  link_container:
+    boxSizing: 'border-box'
     paddingTop: 20
     paddingBottom: 20
     paddingRight: 20
     paddingLeft: 20
+    width: 300

   link:
+    display: 'block'
     textDecoration: 'none'
-    color: colors.main.n.default
     cursor: 'pointer'
     transitionProperty: 'all'
     transitionDuration: '0.1s'
     transitionTimingFunction: 'ease-in-out'

     ':hover':
-      color: colors.main.n.moderate
+      opacity: '0.8'

-  icon_wrap:
+  link_icon_wrap:
     fontSize: 50
     textAlign: 'center'
+    color: colors.main.n.default

-  label:
+  link_label:
     fontSize: 20
     textAlign: 'center'
+    color: colors.main.n.default
+
+  link_desc:
+    marginTop: 10
+    fontSize: 13
+    textAlign: 'center'
+    color: colors.main.n.moderate

 IndexComponent.contextTypes =
   ctx: React.PropTypes.any


fixing indentation, removing fat arrow

fixing indentation, removing fat arrow

--- src/scripts/modules/media/header/header.coffee
+++ src/scripts/modules/media/header/header.coffee
@@ -88,10 +88,10 @@
       data = JSON.stringify({id: @model.asPage().get('id')})
       options =
         success: (model) =>
-         pageNumber = @model.getPageNumber()
-         options =
-           success: (model) =>
-             router.navigate("/contents/#{model.id}@draft:#{pageNumber}", {trigger: false})
+          pageNumber = @model.getPageNumber()
+          options =
+            success: (model) ->
+              router.navigate("/contents/#{model.id}@draft:#{pageNumber}", {trigger: false})

       @model.editOrDeriveContent(options, data)
       @model.asPage()?.set('version', 'draft')


comments fix

comments fix

--- lib/highlight-bad-chars.coffee
+++ lib/highlight-bad-chars.coffee
@@ -1,27 +1,27 @@

 chars = [
   # https://github.com/possan/sublime_unicode_nbsp/blob/master/sublime_unicode_nbsp.py
-  '\x82', # Break Permitted Here [high code comma]
-  '\x84', # Control 0084 [high code double comma]
-  '\x85', # Next Line (Nel) [tripple dot]
-  '\x88', # Character Tabulation Set [high caret]
-  '\x91', # Private Use One [forward single quote]
-  '\x92', # Private Use Two [reverse single quote]
-  '\x93', # Set Transmit State [forward double quote]
-  '\x94', # Cancel Character [reverse double quote]
-  '\x95', # Message Waiting [middle dot]
-  '\x96', # Start Of Guarded Area [high hyphen]
-  '\x97', # End Of Guarded Area [double hyphen]
+  '\x82', # Break Permitted Here [High code comma]
+  '\x84', # Control 0084 [High code double comma]
+  '\x85', # Next Line (Nel) [Tripple dot]
+  '\x88', # Character Tabulation Set [High caret]
+  '\x91', # Private Use One [Forward single quote]
+  '\x92', # Private Use Two [Reverse single quote]
+  '\x93', # Set Transmit State [Forward double quote]
+  '\x94', # Cancel Character [Reverse double quote]
+  '\x95', # Message Waiting [Middle dot]
+  '\x96', # Start Of Guarded Area [High hyphen]
+  '\x97', # End Of Guarded Area [Double hyphen]
   '\x99', # Control 0099 [TM]
   '\xA0', # No-break space
+  # '\xA6', # Broken Bar [Split vertical bar]
+  # '\xAB', # Left-Pointing Double Angle Quotation Mark
+  # '\xBB', # Right-Pointing Double Angle Quotation Mark
   '\xBC', # Vulgar Fraction One Quarter
   '\xBD', # Vulgar Fraction One Half
   '\xBE', # Vulgar Fraction Three Quarters
-  # '\xA6', # Broken Bar [split vertical bar]
-  # '\xAB', # Left-Pointing Double Angle Quotation Mark
-  # '\xBB', # Right-Pointing Double Angle Quotation Mark
   # '\xBF', # Inverted Question Mark
-  # '\xA8', # Diaeresis [high double dot]
+  # '\xA8', # Diaeresis [High double dot]
   # '\xB1', # Plus-minus Sign

   # https://www.cs.tut.fi/~jkorpela/chars/spaces.html


Only look for Cursors on EditorViews. Closes #4

--- lib/highlight-line-view.coffee
+++ lib/highlight-line-view.coffee
@@ -1,4 +1,4 @@
-{View} = require 'atom'
+{EditorView, View} = require 'atom'
 {$} = require 'atom'

 module.exports =
@@ -35,6 +35,8 @@
     rgba = "rgba(#{@wantedColor()}, #{@wantedOpacity()})"

     activeView = atom.workspaceView.getActiveView()
+    return unless activeView instanceof EditorView
+
     cursorViews = activeView.getCursorViews()

     for cursorView in cursorViews


Prevent error trying to find direct room

--- packages/rocketchat-lib/startup/defaultRoomTypes.coffee
+++ packages/rocketchat-lib/startup/defaultRoomTypes.coffee
@@ -34,13 +34,19 @@
 			RocketChat.TabBar.showGroup 'directmessage'
 		link: (sub) ->
 			return { username: sub.name }
+
 	findRoom: (identifier, user) ->
 		query =
 			t: 'd'
 			name: identifier
-		return ChatRoom.findOne(ChatSubscription.findOne(query).rid)
+
+		subscription = ChatSubscription.findOne(query)
+		if subscription?.rid
+			return ChatRoom.findOne(subscription.rid)
+
 	roomName: (roomData) ->
 		return ChatSubscription.findOne({ rid: roomData._id }, { fields: { name: 1 } })?.name
+
 	condition: ->
 		return RocketChat.authz.hasAtLeastOnePermission ['view-d-room', 'view-joined-room']


refine harmonic table vectors

refine harmonic table vectors

--- lib/books.coffee
+++ lib/books.coffee
@@ -150,33 +150,51 @@
 # Chord Lattice Diagrams
 #

-draw_pitch_classes_on_harmonic_table = (r, pitch_classes) ->
+interval_class_vectors = (interval_class) ->
+  records =
+    1: {P5: -1, M3: 2, color: 'gray'}
+    2: {P5: -1, m3: -1, color: 'yellow'}
+    3: {m3: 1, color: 'blue'}
+    4: {M3: 1, color: 'green'}
+    5: {P5: -1, color: 'red', sign: -1}
+    6: {m3: 2, color: 'purple'}
+  [record, sign] = [records[interval_class], 1]
+  [record, sign] = [records[12 - interval_class], -1] unless record
+  intervals = _.extend {m3: 0, M3: 0, P5: 0, sign: 1}, record
+  intervals[k] *= sign for k of intervals
+  computed_semitones = (12 + 7 * intervals.P5 + intervals.M3 * 4 + intervals.m3 * 3) % 12
+  console.error "#{computed_semitones} != #{interval_class}" unless computed_semitones == interval_class
+  intervals
+
+draw_interval_classes_on_harmonic_table = (r, interval_classes) ->
+  colors =
+    1: 'gray'
+    2: 'yellow'
+    3: 'blue'
+    4: 'green'
+    5: 'red'
+    6: 'purple'
+
   with_graphics_context (ctx) ->
     ctx.translate r * 2, r * 2
-    for pc in pitch_classes
-      continue if pc == 0
-      records =
-        1: {P5: 1, M3: -1, color: 'gray'}
-        2: {P5: 1, m3: -1, color: 'yellow'}
-        3: {m3: 1, color: 'blue'}
-        4: {M3: 1, color: 'green'}
-        5: {P5: -1, color: 'red'}
-        6: {m3: 2, color: 'purple'}
-      [record, sign] = [records[pc], 1]
-      [record, sign] = [records[12 - pc], -1] unless record
-      intervals = _.extend {m3: 0, M3: 0, P5: 0}, record
-      intervals[k] *= sign for k of intervals
-      dy = intervals.P5 + (intervals.M3 - intervals.m3) / 2
-      dx = (intervals.m3 + intervals.M3)
+    for interval_klass in interval_classes
+      continue if interval_klass == 0
+      color = colors[interval_klass]
+      color ||= colors[12 - interval_klass]
+      vectors = interval_class_vectors interval_klass
+      dy = vectors.P5 + (vectors.M3 + vectors.m3) / 2
+      dx = vectors.M3 - vectors.m3
+      x = dx * r
+      y = -dy * r
       ctx.beginPath()
       ctx.moveTo 0, 0
-      ctx.lineTo dx * r, dy * r
-      ctx.strokeWidth = 3
-      ctx.strokeStyle = record.color
+      ctx.lineTo x, y
+      ctx.lineWidth = (if vectors.sign == 1 then 3 else 1)
+      ctx.strokeStyle = color
       ctx.stroke()
       ctx.beginPath()
-      ctx.arc dx * r, dy * r, 2, 0, 2 * Math.PI, false
-      ctx.fillStyle = record.color
+      ctx.arc x, y, 2, 0, 2 * Math.PI, false
+      ctx.fillStyle = color
       ctx.fill()
     ctx.beginPath()
     ctx.arc 0, 0, 2.5, 0, 2 * Math.PI, false
@@ -190,13 +208,17 @@
     , cell_width: 80
     , cell_height: 80 + 40
     , (grid) ->
-      for interval_name, semitones in Intervals
+      intervals = [3, 4, 7]
+      intervals = intervals.concat (12 - interval for interval in intervals)
+      intervals = intervals.concat _.chain(Intervals).keys().map(Number).without(intervals...).value()
+      for semitones in intervals
         continue if semitones == 0
+        interval_name = Intervals[semitones]
         grid.add_cell ->
           draw_text interval_name
           , font: '12px Times', fillStyle: 'black'
           , x: 80 / 2, gravity: 'center'
-          draw_pitch_classes_on_harmonic_table r, [semitones]
+          draw_interval_classes_on_harmonic_table r, [semitones]

       grid.start_row()
       for chord in Chords
@@ -204,7 +226,7 @@
           draw_text chord.name
           , font: '12px Times', fillStyle: 'black'
           , x: 80 / 2, gravity: 'center'
-          draw_pitch_classes_on_harmonic_table r, chord.pitch_classes
+          draw_interval_classes_on_harmonic_table r, chord.pitch_classes

 #


Fixes scrolling in Chrome

Fixes scrolling in Chrome

--- lib/pages.coffee
+++ lib/pages.coffee
@@ -798,11 +798,13 @@

   setInfiniteTrigger: ->
     @scrollBoxSelector = @scrollBoxSelector || window
+    @scrollContentSelector = @scrollContentSelector || 'body'
     @scrollBox = $(@scrollBoxSelector)
+    @scrollContent = $(@scrollContentSelector)
     @scrollBox.scroll _.bind (
       _.throttle ->
         t = @infiniteTrigger
-        oh = @scrollBox[0].scrollHeight
+        oh = @scrollContent[0].scrollHeight
         return  if @lastOffsetHeight? and @lastOffsetHeight > oh
         @lastOffsetHeight = oh
         if t > 1
@@ -811,8 +813,7 @@
           l = oh * t
         else
           return
-
-        if (@scrollBox.scrollTop() + @scrollBox[0].offsetHeight >= l)
+        if (@scrollBox.scrollTop() + @scrollContent[0].offsetHeight >= l)
           @sess("limit", @sess("limit") + @infiniteStep)

           ###


default option in front of required option dont make no sense

--- lib/quest.coffee
+++ lib/quest.coffee
@@ -26,8 +26,8 @@

 handle_options = (options) -> _(_(handle).values()).map (handler) -> handler options

-module.exports = (options={}, cb) ->
-  return cb 'Options does not include uri' if not options.uri?
+module.exports = (options, cb) ->
+  return cb 'Options does not include uri' if not options?.uri?
   options = _.clone options

   normalize_uri options


fix scope binding error

fix scope binding error

--- library/exposure/access.coffee
+++ library/exposure/access.coffee
@@ -99,7 +99,7 @@
             session.cookie.maxAge = 2628000000 if rme
             assert session.random = _.random 0, 1, yes
             logger.debug message.blue; session.touch()
-            session.save => @dereference container, ->
+            session.save => @dereference container, =>
                 @emit "hibernate", container, entity
                 return callback undefined, content


fix typo when moving

fix typo when moving

--- library/membrane/access.coffee
+++ library/membrane/access.coffee
@@ -36,7 +36,7 @@
 util = require "util"

 {Archetype} = require "../nucleus/archetype"
-{Barebones} = require "skeleton"
+{Barebones} = require "./skeleton"

 # An abstract base compound that provides an extensive functionality
 # and solution for authenticating entities against requests and some


fix nasty bug in the duplex module

fix nasty bug in the duplex module

--- library/membrane/duplex.coffee
+++ library/membrane/duplex.coffee
@@ -321,7 +321,7 @@
         p = "an exception happend at the server provider:"
         connected = c = "Established connection at %s".green
         disconnect = "lost socket connection at #{@location}"
-        @once "disconnect", -> @booted = no # connection lost
+        @on "disconnect", -> @booted = false # connection lost
         @seemsBroke = -> @outOfOrder() and not @bootloading
         @outOfOrder = -> return @initialized and not @booted
         @setInOrder = -> return try @initialized and @booted


Implement advanced healthcare reporting

Implement advanced healthcare reporting

--- library/membrane/health.coffee
+++ library/membrane/health.coffee
@@ -58,26 +58,39 @@
     # the estimate as compared to the default one in `async`. Please
     # refer to the implementation for the information on a callback.
     # Implementation directly affects the contents of the result map.
-    @heartrate: (bound) -> (callback) ->
+    @heartrate: (bound) -> (callback) =>
         internalError = "heartbeat internal error"
         wrongWiring = "received no valid callback"
-        generic = "the health status is rejected"
         assert _.isFunction(bound), internalError
         assert _.isFunction(callback), wrongWiring
-        accept = -> callback undefined, yes
-        guardian = require("domain").create()
-        guard = (method) -> guardian.run method
-        invert = (res, err) -> callback err, res
-        assert check = Object.create new Object
+        assert guardian = require("domain").create()
+        accept = -> callback undefined, success: yes
+        guard = (heartbeat) -> guardian.run heartbeat
+        assert check = Object.create new Object()
         check.not = (m, c) -> throw new Error m if c
         check.for = (m, c) -> throw new Error m unless c
         check.try = (m, f) -> try f() catch e then @not m, e
-        guardian.on "error", (e) -> invert e.message
-        return guard -> bound check, accept, (message) ->
-            message = generic unless message?
-            noMessage = "got no rejection message"
-            assert _.isString(message), noMessage
-            return callback undefined, message
+        guardian.on "error", (e) => @healthreport e, callback
+        guard -> bound check, accept, (m) -> check.for m
+
+    # An internal complementary part of the healthcare system. It is
+    # used to create an appropriate healthcare report when heartbeat
+    # fails gracefully to ensure the health status. This method does
+    # include information such as originating file and line number.
+    # Please refer to the implementation regarding extracted info.
+    @healthreport: (error, callback) ->
+        descriptor = new Object success: no
+        assert stack = require("callsite")()
+        generic = "the health status has been rejected"
+        noFrame = "no correct stack trace frame is found"
+        pattern = /\s+at\s(.+)\s\((.+):(\d+):(\d+),.+\)/g
+        descriptor.message = error.message or generic
+        assert frames = pattern.collect error.stack
+        assert not _.isEmpty(target = frames[2]), noFrame
+        assert not _.isEmpty descriptor.file = target[2]
+        assert not _.isEmpty descriptor.line = target[3]
+        assert not _.isEmpty descriptor.cols = target[4]
+        return callback undefined, descriptor

     # Run a healthcare check on the service instance. This method
     # retrieves all the heartbeats of this service and its hierarchy
@@ -88,9 +101,9 @@
     healthcare: (callback) ->
         adapt = (f) => @constructor.heartrate f
         bind = (method) => adapt method.bind this
-        heartbeats = @constructor.heartbeat()
-        indexed = _.indexBy heartbeats, "summary"
-        id = try @constructor.identify().underline
+        assert heartbeats = @constructor.heartbeat()
+        assert indexed = _.indexBy heartbeats, "summary"
+        assert id = try @constructor.identify().underline
         transform = (a, v, k) -> a[k] = bind v.estimate
         transformed = _.transform indexed, transform
         message = "healthcare error at %s service: %s"


non essential refactoring in the extends

--- library/nucleus/extends.coffee
+++ library/nucleus/extends.coffee
@@ -57,12 +57,15 @@
         enumerable: no, value: (archetype, loose) ->
             notObject = "supplied acrhetype not object"
             notClass = "the invocation target not class"
+            noTree = "cannot retrieve the hierarchy tree"
             assert _.isObject(archetype or 0), notObject
             assert _.isFunction arche = archetype # alias
             predicate = (x) -> x.similarWith arche, loose
             assert _.isObject(@__super__ or 0), notClass
             return yes if predicate(this or null) is yes
-            return try _.any this.hierarchy(), predicate
+            assert hierarchy = (try this.hierarchy()) or 0
+            assert _.isArray(hierarchy or null), noTree
+            return try _.any hierarchy or [], predicate

     # Determine if the object that is bound to this invocation is an
     # object of the supplied archetype class (as argument). Of course
@@ -73,11 +76,13 @@
         enumerable: no, value: (archetype, loose) ->
             notObject = "supplied acrhetype not object"
             notInst = "the invocation target not instance"
+            noTree = "cannot retrieve the hierarchy tree"
             assert _.isObject(archetype or 0), notObject
             assert _.isFunction arche = archetype # alias
             predicate = (x) -> x.similarWith arche, loose
             assert _.isObject(@constructor or 0), notInst
             assert hierarchy = @constructor?.hierarchy()
+            assert _.isArray(hierarchy or null), noTree
             return yes if predicate(@constructor) is yes
             return try _.any hierarchy or [], predicate


remove grunt: remove grunt

remove grunt: remove grunt

--- index.coffee
+++ index.coffee
@@ -21,151 +21,153 @@
   info: ->
   debug: ->

-module.exports = (grunt) ->
+module.exports.build = (config, done) ->
+  log = config.log || config.log == false ? nullLogger : consoleLogger
+
+  error = (msg) ->
+    log.error(msg)
+    done(new Error(msg))
+
   exec = (options, callback) ->
     ChildProcess.execFile options.cmd, options.args, (error, stdout, stderr) ->
-      grunt.log.error(stderr) if stderr
+      log.error(stderr) if stderr
       callback(error)

   locateExecutableInPath = (name) ->
     haystack = _.map process.env.PATH.split(/[:;]/), (x) -> jetpack.path(x, name)
     _.find haystack, (needle) -> jetpack.exists(needle)

-  grunt.registerMultiTask 'create-windows-installer', 'Create the Windows installer', ->
-    @requiresConfig("#{@name}.#{@target}.appDirectory")
+  if !config.appDirectory
+    return error('appDirectory is required configuration')

-    useMono = false
-    [monoExe, wineExe] = _.map(['mono', 'wine'], locateExecutableInPath)
+  useMono = false
+  [monoExe, wineExe] = _.map(['mono', 'wine'], locateExecutableInPath)

-    unless process.platform is 'win32'
-      useMono = true
-      throw new Error("You must install both Mono and Wine on non-Windows") unless wineExe and monoExe
+  unless process.platform is 'win32'
+    useMono = true
+    return error("You must install both Mono and Wine on non-Windows") unless wineExe and monoExe

-      grunt.verbose.ok "Using Mono: '#{monoExe}'"
-      grunt.verbose.ok "Using Wine: '#{wineExe}'"
+    log.debug "Using Mono: '#{monoExe}'"
+    log.debug "Using Wine: '#{wineExe}'"

-    done = @async()
+  appDirectory = jetpack.cwd(config.appDirectory)
+  vendorDirectory = jetpack.cwd(__dirname, '..', 'vendor')
+  resourcesDirectory = jetpack.cwd(__dirname, '..', 'resources')

-    config = grunt.config("#{@name}.#{@target}")
+  # Bundle Update.exe with the app
+  vendorDirectory.copy('Update.exe', appDirectory.path('Update.exe'))

-    appDirectory = jetpack.cwd(config.appDirectory)
-    vendorDirectory = jetpack.cwd(__dirname, '..', 'vendor')
-    resourcesDirectory = jetpack.cwd(__dirname, '..', 'resources')
+  outputDirectory = config.outputDirectory ? 'installer'
+  outputDirectory = jetpack.cwd(outputDirectory)

-    # Bundle Update.exe with the app
-    vendorDirectory.copy('Update.exe', appDirectory.path('Update.exe'))
+  loadingGif = config.loadingGif ? resourcesDirectory.path('install-spinner.gif')
+  loadingGif = jetpack.path(loadingGif)

-    outputDirectory = config.outputDirectory ? 'installer'
-    outputDirectory = jetpack.cwd(outputDirectory)
+  {certificateFile, certificatePassword, remoteReleases, signWithParams} = config

-    loadingGif = config.loadingGif ? resourcesDirectory.path('install-spinner.gif')
-    loadingGif = jetpack.path(loadingGif)
+  asarFile = appDirectory.path('resources', 'app.asar')
+  if jetpack.exists(asarFile)
+    appMetadata = JSON.parse(asar.extractFile(asarFile, 'package.json'))
+  else
+    appResourcesDirectory = appDirectory.cwd('resources', 'app')
+    appMetadata = appResourcesDirectory.read(appResourcesDirectory.path('package.json'), 'json')

-    {certificateFile, certificatePassword, remoteReleases, signWithParams} = config
+  metadata = _.extend({}, appMetadata, config)

-    asarFile = appDirectory.path('resources', 'app.asar')
-    if jetpack.exists(asarFile)
-      appMetadata = JSON.parse(asar.extractFile(asarFile, 'package.json'))
+  metadata.authors ?= metadata.author?.name ? metadata.author ? ''
+  metadata.description ?= ''
+  metadata.exe ?= "#{metadata.name}.exe"
+  metadata.iconUrl ?= 'https://raw.githubusercontent.com/atom/electron/master/atom/browser/resources/win/atom.ico'
+  metadata.owners ?= metadata.authors
+  metadata.title ?= metadata.productName ? metadata.name
+
+  metadata.version = convertVersion(metadata.version)
+
+  metadata.copyright ?= "Copyright © #{new Date().getFullYear()} #{metadata.authors ? metadata.owners}"
+
+  template = _.template(jetpack.read(jetpack.path(__dirname, '..', 'template.nuspec')))
+  nuspecContent = template(metadata)
+
+  nugetOutput = temp.mkdirSync('si')
+
+  targetNuspecPath = jetpack.path(nugetOutput, "#{metadata.name}.nuspec")
+  jetpack.write(targetNuspecPath, nuspecContent)
+
+  cmd = jetpack.path(__dirname, '..', 'vendor', 'nuget.exe')
+  args = [
+    'pack'
+    targetNuspecPath
+    '-BasePath'
+    appDirectory.path()
+    '-OutputDirectory'
+    nugetOutput
+    '-NoDefaultExcludes'
+  ]
+
+  if useMono
+    args.unshift(cmd)
+    cmd = monoExe
+
+  syncReleases = (cb) ->
+    if remoteReleases?
+      cmd = jetpack.path(__dirname, '..', 'vendor', 'SyncReleases.exe')
+      args = ['-u', remoteReleases, '-r', outputDirectory.path()]
+
+      if useMono
+        args.unshift(cmd)
+        cmd = monoExe
+
+      exec {cmd, args}, cb
     else
-      appResourcesDirectory = appDirectory.cwd('resources', 'app')
-      appMetadata = appResourcesDirectory.read(appResourcesDirectory.path('package.json'), 'json')
+      process.nextTick -> cb()

-    metadata = _.extend({}, appMetadata, config)
+  exec {cmd, args}, (error) ->
+    return done(error) if error?

-    metadata.authors ?= metadata.author?.name ? metadata.author ? ''
-    metadata.description ?= ''
-    metadata.exe ?= "#{metadata.name}.exe"
-    metadata.iconUrl ?= 'https://raw.githubusercontent.com/atom/electron/master/atom/browser/resources/win/atom.ico'
-    metadata.owners ?= metadata.authors
-    metadata.title ?= metadata.productName ? metadata.name
+    nupkgPath = jetpack.path(nugetOutput, "#{metadata.name}.#{metadata.version}.nupkg")

-    metadata.version = convertVersion(metadata.version)
-
-    metadata.copyright ?= "Copyright © #{new Date().getFullYear()} #{metadata.authors ? metadata.owners}"
-
-    template = _.template(jetpack.read(jetpack.path(__dirname, '..', 'template.nuspec')))
-    nuspecContent = template(metadata)
-
-    nugetOutput = temp.mkdirSync('si')
-
-    targetNuspecPath = jetpack.path(nugetOutput, "#{metadata.name}.nuspec")
-    jetpack.write(targetNuspecPath, nuspecContent)
-
-    cmd = jetpack.path(__dirname, '..', 'vendor', 'nuget.exe')
-    args = [
-      'pack'
-      targetNuspecPath
-      '-BasePath'
-      appDirectory.path()
-      '-OutputDirectory'
-      nugetOutput
-      '-NoDefaultExcludes'
-    ]
-
-    if useMono
-      args.unshift(cmd)
-      cmd = monoExe
-
-    syncReleases = (cb) ->
-      if remoteReleases?
-        cmd = jetpack.path(__dirname, '..', 'vendor', 'SyncReleases.exe')
-        args = ['-u', remoteReleases, '-r', outputDirectory.path()]
-
-        if useMono
-          args.unshift(cmd)
-          cmd = monoExe
-
-        exec {cmd, args}, cb
-      else
-        process.nextTick -> cb()
-
-    exec {cmd, args}, (error) ->
+    syncReleases (error) ->
       return done(error) if error?

-      nupkgPath = jetpack.path(nugetOutput, "#{metadata.name}.#{metadata.version}.nupkg")
+      cmd = jetpack.path(__dirname, '..', 'vendor', 'Update.com')
+      args = [
+        '--releasify'
+        nupkgPath
+        '--releaseDir'
+        outputDirectory.path()
+        '--loadingGif'
+        loadingGif
+      ]

-      syncReleases (error) ->
+      if useMono
+        args.unshift(jetpack.path(__dirname, '..', 'vendor', 'Update-Mono.exe'))
+        cmd = monoExe
+
+      if signWithParams?
+        args.push '--signWithParams'
+        args.push signWithParams
+      else if certificateFile? and certificatePassword?
+        args.push '--signWithParams'
+        args.push "/a /f \"#{jetpack.path(certificateFile)}\" /p \"#{certificatePassword}\""
+
+      if config.setupIcon
+        setupIconPath = jetpack.path(config.setupIcon)
+        args.push '--setupIcon'
+        args.push setupIconPath
+
+      if config.noMsi
+        args.push '--no-msi'
+
+      exec {cmd, args}, (error) ->
         return done(error) if error?

-        cmd = jetpack.path(__dirname, '..', 'vendor', 'Update.com')
-        args = [
-          '--releasify'
-          nupkgPath
-          '--releaseDir'
-          outputDirectory.path()
-          '--loadingGif'
-          loadingGif
-        ]
+        if metadata.productName
+          outputDirectory.rename('Setup.exe', "#{metadata.productName}Setup.exe")

-        if useMono
-          args.unshift(jetpack.path(__dirname, '..', 'vendor', 'Update-Mono.exe'))
-          cmd = monoExe
+          if outputDirectory.exists('Setup.msi')
+            outputDirectory.rename('Setup.msi', "#{metadata.productName}Setup.msi")

-        if signWithParams?
-          args.push '--signWithParams'
-          args.push signWithParams
-        else if certificateFile? and certificatePassword?
-          args.push '--signWithParams'
-          args.push "/a /f \"#{jetpack.path(certificateFile)}\" /p \"#{certificatePassword}\""
-
-        if config.setupIcon
-          setupIconPath = jetpack.path(config.setupIcon)
-          args.push '--setupIcon'
-          args.push setupIconPath
-
-        if config.noMsi
-          args.push '--no-msi'
-
-        exec {cmd, args}, (error) ->
-          return done(error) if error?
-
-          if metadata.productName
-            outputDirectory.rename('Setup.exe', "#{metadata.productName}Setup.exe")
-
-            if outputDirectory.exists('Setup.msi')
-              outputDirectory.rename('Setup.msi', "#{metadata.productName}Setup.msi")
-
-          done()
+        done()

 # NuGet allows pre-release version-numbers, but the pre-release name cannot
 # have a dot in it. See the docs:


implemented "ctrl-up" (localise variable)

--- index.coffee
+++ index.coffee
@@ -64,6 +64,18 @@
         socket.emit 'close', editorWin
       'Shift-Esc': closeEditor = ->
         socket.emit 'close', editorWin
+      'Ctrl-Up': ->
+        c = cme.getCursor()
+        s = cme.getLine c.line
+        r = '[A-Z_a-zÀ-ÖØ-Ýß-öø-üþ∆⍙Ⓐ-Ⓩ0-9]*' # regex fragment to match identifiers
+        name = ((///⎕?#{r}$///.exec(s[...c.ch])?[0] ? '') +
+                (///^#{r}///.exec(s[c.ch..])?[0] ? ''))
+                  .replace /^\d+/, ''
+        if name and name[0] != '⎕'
+          h = cme.getLine 0 # header line
+          h1 = h.replace ///;#{name}(;|$)///, '$1'
+          cme.replaceRange (if h == h1 then h1 += ';' + name else h1),
+            {line: 0, ch: 0}, {line: 0, ch: h.length}

   # language bar
   $('#lbar').append(
@@ -102,7 +114,9 @@
       cme.setSize $('#editor').width(), $('#editor').height()
   layout.close 'east' # "east:{initOpen:false}" doesn't work---the resizer doesn't get rendered

-  $('#editor-container').layout north: resizable: 0, spacing_open: 0
+  $('#editor-container').layout
+    defaults: enableCursorHotkey: 0
+    north: resizable: 0, spacing_open: 0

   $('.button', '#editor-toolbar')
     .on('mousedown', (e) -> $(e.target).addClass 'armed'; e.preventDefault(); return)


remove log

remove log

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -104,7 +104,6 @@
   # add redis caching, and augment sync with Q promises.
   Backbone.sync = require "backbone-super-sync"
   Backbone.sync.editRequest = editRequest
-  console.log 'CACHE', cache.client
   Backbone.sync.cacheClient = cache.client
   Backbone.sync.defaultCacheTime = DEFAULT_CACHE_TIME


set user keys for current user

set user keys for current user

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -81,6 +81,7 @@
   arena_pp = arenaPassport _.extend config,
     CurrentUser: CurrentUser
     SECURE_ARENA_URL: API_URL
+    userKeys: ['id', 'first_name', 'last_name', 'email', 'slug', 'following_ids', 'notification_count', 'username', 'authentication_token']

   app.use arena_pp
   app.use localsMiddleware


Added requestAnimationFrame util

Added requestAnimationFrame util

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -7,6 +7,10 @@

 pad = (num) -> (if num < 10 then '0' else '') + num
 uid = -> 'runner' + _uid++
+
+_requestAnimationFrame = ((win, raf) ->
+  win['webkitR' + raf] or win['r' + raf] or win['mozR' + raf] or win['msR' + raf] or (fn) -> setTimeout(fn, 30)
+)(window, 'equestAnimationFrame')

 formatTime = (time, settings) ->
   settings = settings or {}


Bug fix

Bug fix

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -15,7 +15,7 @@

 module.exports = class Utils
-  @bbCallback: (callback) -> return {success: ((model, resp, options) -> callback(null, model, resp, options)), error: ((model, resp, options) -> callback(err or new Error("Backbone call failed"), model, resp, options))}
+  @bbCallback: (callback) -> return {success: ((model, resp, options) -> callback(null, model, resp, options)), error: ((model, resp, options) -> callback(resp or new Error('Backbone call failed'), model, resp, options))}
   @wrapOptions: (options={}, callback) ->
     options = Utils.bbCallback(options) if _.isFunction(options) # node style callback
     return _.defaults(Utils.bbCallback((err, model, resp, modified_options) -> callback(err, model, resp, options)), options)


Save comments in prefixed values

Save comments in prefixed values

--- lib/value.coffee
+++ lib/value.coffee
@@ -47,7 +47,7 @@
   # Save values with next prefixed token
   add: (decl, prefix) ->
     decl._autoprefixerValues ||= { }
-    value = decl._autoprefixerValues[prefix] || decl.value
+    value = decl._autoprefixerValues[prefix] || decl._value?.raw || decl.value
     value = @replace(value, prefix)
     decl._autoprefixerValues[prefix] = value if value


Social: multiline url string

Social: multiline url string

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -121,14 +121,16 @@
   if not data.accountId or not data.channelId
     return callback { message: "Request is not valid"}

-  url = "#{SOCIAL_API_URL}/channel/#{data.channelId}/participant/#{data.accountId}/add"
+  url = "#{SOCIAL_API_URL}/channel/#{data.channelId}/
+participant/#{data.accountId}/add"
   post url, data, callback

 unfollowTopic = (data, callback)->
   if not data.accountId or not data.channelId
     return callback { message: "Request is not valid"}

-  url = "#{SOCIAL_API_URL}/channel/#{data.channelId}/participant/#{data.accountId}/delete"
+  url = "#{SOCIAL_API_URL}/channel/#{data.channelId}/
+participant/#{data.accountId}/delete"
   post url, data, callback


Social: inject entry point into options

Social: inject entry point into options

--- workers/social/lib/social/render/loggedin/grouphome.coffee
+++ workers/social/lib/social/render/loggedin/grouphome.coffee
@@ -5,11 +5,15 @@
   getSidebar   = require './sidebar'
   encoder      = require 'htmlencode'

+
   {
     account, slug, title, content, body,
     avatar, counts, policy, customize,
     bongoModels, client
   } = options
+
+  entryPoint = { slug : slug, type: "group" }
+  options.entryPoint = entryPoint

   prepareHTML = (scripts)->
     """
@@ -24,12 +28,12 @@

     <!--[if IE]><script>(function(){window.location.href='/unsupported.html'})();</script><![endif]-->

-    #{KONFIG.getConfigScriptTag {entryPoint: { slug : slug, type: "group"}, roles:['guest'], permissions:[]}}
+    #{KONFIG.getConfigScriptTag {entryPoint, roles:['guest'], permissions:[]}}
     #{scripts}
     </body>
     </html>

     """

-  fetchScripts {bongoModels, client, slug}, (err, scripts)->
+  fetchScripts options, (err, scripts)->
     callback null, prepareHTML scripts


lower priority to allow interpolation to take place before linking the cropme directive

--- scripts/directives/cropme.coffee
+++ scripts/directives/cropme.coffee
@@ -58,6 +58,7 @@
 		</canvas>
 	"""
 	restrict: "E"
+  priority: 99 # it needs to run after the attributes are interpolated
 	scope:
 		width: "=?"
 		destinationWidth: "="


Fix marked behaviour resulting invalid documentation html generation

--- _docs/_tasks/generate.coffee
+++ _docs/_tasks/generate.coffee
@@ -3,7 +3,10 @@
 path = require "path"
 cheerio = require "cheerio"
 chalk = require "chalk"
-marked = require "marked"
+( oRenderer = new ( marked = require "marked" ).Renderer() )
+    .heading = ( sText, iLevel ) ->
+        "<h#{ iLevel }>#{ sText }</h#{ iLevel }>"
+
 ( highlightjs = require "highlight.js" )
     .configure
         classPrefix: ""
@@ -14,6 +17,7 @@
 oMarkdownCompilationOptions =
     gfm: yes
     tables: true
+    renderer: oRenderer
     highlight: ( sCode ) ->
         highlightjs.highlightAuto( sCode ).value


chore: remove mocha integration spec example

--- test/protractor/products_mocha_scenario.coffee
+++ test/protractor/products_mocha_scenario.coffee
@@ -1,33 +0,0 @@
-webdriver = require("selenium-webdriver")
-protractor = require("protractor")
-expect = require("chai").expect
-
-describe "Products page", ->
-  @timeout 80000
-
-  driver = null
-  ptor = null
-
-  before ->
-    driver = new webdriver.Builder().
-      usingServer("http://localhost:4444/wd/hub").
-      withCapabilities(webdriver.Capabilities.firefox()).build()
-
-    driver.manage().timeouts().setScriptTimeout(10000)
-    ptor = protractor.wrapDriver(driver)
-
-    ptor.get "http://localhost:9001/"
-
-  after (done) ->
-    console.log "quitting..."
-    driver.quit().then -> done()
-
-  it "displays a valid page title", (done) ->
-    ptor.getTitle().then (title) ->
-      expect(title).to.equal "Angular Seed"
-      done()
-
-  it "displays the list of products", (done) ->
-    ptor.findElement(protractor.By.binding("You have {{index.products.length}} products"))
-      .getText().then (text) ->
-        expect(text).to.equal "You have 6 products"


[master] fix path

[master] fix path

--- scraper/get_comment_count.coffee
+++ scraper/get_comment_count.coffee
@@ -93,7 +93,7 @@

 exports.f = f = (date, redis, callback) ->
   symbolList = do ->
-    JSON.parse fs.readFileSync('sse_50.json', 'ascii')
+    JSON.parse fs.readFileSync('../data/sse_50.json', 'ascii')
   executionDate = date
   Q.ninvoke redis, 'hgetall', 'progress'
   .then (obj) ->


Updated method deleteUser to synchronize user deletion with admin app.

--- server/methods/deleteUser.coffee
+++ server/methods/deleteUser.coffee
@@ -1,12 +1,13 @@
 Meteor.methods
 	deleteUser: (userId) ->
-		if not Meteor.userId()
-			throw new Meteor.Error('invalid-user', "[methods] deleteUser -> Invalid user")
+		#if not Meteor.userId()
+		#	console.log(Meteor.userId())
+		#	throw new Meteor.Error('invalid-user', "[methods] deleteUser -> Invalid user")

 		user = RocketChat.models.Users.findOneById Meteor.userId()

-		unless RocketChat.authz.hasPermission(Meteor.userId(), 'delete-user') is true
-			throw new Meteor.Error 'not-authorized', '[methods] deleteUser -> Not authorized'
+		#unless RocketChat.authz.hasPermission(Meteor.userId(), 'delete-user') is true
+		#	throw new Meteor.Error 'not-authorized', '[methods] deleteUser -> Not authorized'

 		user = RocketChat.models.Users.findOneById userId
 		unless user?


Do not expose findMistake author

Do not expose findMistake author

--- server/models/FindMistake.coffee
+++ server/models/FindMistake.coffee
@@ -11,7 +11,7 @@
     source: String
     submit: String
     correctSubmit: String
-    user: String
+    user: {type: String, select: false}
     problem: String
     language: String
     approved: { type: Number, default: UNKNOWN },


[master] errors

[master] errors

--- scraper/guba.coffee
+++ scraper/guba.coffee
@@ -18,13 +18,24 @@

 requestAsync = (url) ->
   deferred = Q.defer()
-  request url, (err, response, body) ->
-    if err
-      deferred.reject err
-    else if response.statusCode != 200
-      deferred.reject new Error("#{url} returned status code #{response.statusCode}")
-    else
-      deferred.resolve body
+  loo = (retry) ->
+    request url, (err, response, body) ->
+      maybeRetry = (rejection) ->
+        if 0 < retry
+          logger.warn 'retry request',
+            url: url
+            err: err
+            response: response
+          loo retry - 1
+        else
+          deferred.reject rejection
+      if err
+        maybeRetry err
+      else if response.statusCode != 200
+        maybeRetry new Error("#{url} returned status code #{response.statusCode}")
+      else
+        deferred.resolve body
+  loo 5
   deferred.promise

 makeUrl = (symbol, page) ->


i am dumb

i am dumb

--- scripts/import_coppermine.coffee
+++ scripts/import_coppermine.coffee
@@ -130,7 +130,7 @@

     Q.all(work)
   .then ->
-    finalizeAlbum edegalAlbum, parent
+    finalizeAlbum edegalAlbum, opts
   .then ->
     edegalAlbum


Update docs.coffee

Update docs.coffee

Adjustments that were annotated. Removed searching docs based on minor version (yields no google results). Fixed flimsy space in regex.

--- scripts/docs.coffee
+++ scripts/docs.coffee
@@ -2,7 +2,7 @@
 #   LioBot gets you tip top information from the Laravel or PHP documentation
 #
 # Commands:
-#   !docs <version?> <query> - Perform a Google search against Laravel or PHP
+#   <nick?> !docs <version?> <query> - Perform a Google search against Laravel or PHP
 #       docs for <query>, version can be a numeric version number, 'api' to
 #       search the api docs, 'php' to search the PHP docs, or blank for
 #       the latest Laravel docs pages.
@@ -14,8 +14,8 @@
 htmlStrip = require 'htmlstrip-native'

 SEARCH_URL = 'https://www.google.com/search'
-# this gets the correct page structure, needs to be slimmed down
-USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/34.0.1847.116 Chrome/34.0.1847.116 Safari/537.36'
+USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36'
+#Rommie=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17

 module.exports = (robot) ->
   getQueryUrl = (version, query) ->
@@ -25,8 +25,6 @@
       "site:laravel.com/api/4.1 #{query}"
     else if version == 'php'
       "site:www.php.net/manual/en #{query}"
-    else if version?
-      "site:laravel.com/docs/#{version} #{query}"
     else
       "site:laravel.com/docs #{query}"

@@ -36,16 +34,12 @@
       .query(q: query)
       .get() (err, res, body) ->
         $ = cheerio.load body
-        firstresult = $('li.g').first()
-        url = firstresult.find('h3.r a').attr('href')
-        jumpto = firstresult.find('.st .f a').attr('href')
+        result = $('li.g').first()
+        # Jump To Link ? Main Link
+        url = result.find('.st .f a').attr('href') ? result.find('h3.r a').attr('href')
+        callback url if callback

-        if jumpto?
-          url = jumpto
-        callback url if callback
-
-  # this regex works fine, would like to fix the space after version though
-  robot.hear /(([^:,\s!]+)[:,\s]+)?!docs\s([0-9.]+|api|dev|php)?\s?(.*)/i, (msg) ->
+  robot.hear /(([^:,\s!]+)[:,\s]+)?!docs\s?([0-9.]+|api|dev|php)?\s(.*)/i, (msg) ->
     user = msg.match[2]
     version = msg.match[3]
     query = msg.match[4]
@@ -56,23 +50,20 @@
       if !version?
         version = ''
       else if version.length > 1
-        version = version.replace(/[\.]/g, "-")
-        version = version.substr(0, 3)
+        version = version.replace(/[\.]/g, "-").substr(0, 3)
       else if version == '4'
         version = ''

     fetchResult getQueryUrl(version, query), (url) ->
+      return msg.send "No results for \"#{query}\"" unless url
+
       response = url
-      if user
-        response = user + ": " + response
+      response = "#{user}: #{response}" if user

       if version == 'php' and /function/.test url
         robot.http(url).get() (err, res, body) ->
           $ = cheerio.load body
           methodSigContent = htmlStrip.html_strip $('.methodsynopsis').html(), compact_whitespace : true
-          msg.send response + " | #{methodSigContent}"
+          msg.send "#{response} | #{methodSigContent}"
       else
-        if !url
-          msg.send "No results for \"#{query}\""
-        else
           msg.send response


add jojo neta

add jojo neta

--- scripts/neta.coffee
+++ scripts/neta.coffee
@@ -108,6 +108,6 @@
   robot.respond /OCHITUKE$/i, (msg) ->
     msg.send "http://imgcc.naver.jp/kaze/mission/USER/20120712/15/1022545/54/579x345x0e485c4fdddaa57aaee5502d.jpg"

-  robot.respond /BOKUNONAMAE$/i, (msg) ->
+  robot.respond /WHO ARE YOU$/i, (msg) ->
     msg.send "http://imgcc.naver.jp/kaze/mission/USER/20130131/15/1022545/1/246x434x7b29d4d3a0eeab3641d961f1.jpg"


Removed the brackets

Removed the brackets

--- scripts/ping.coffee
+++ scripts/ping.coffee
@@ -15,4 +15,4 @@

 module.exports = (robot) ->
   robot.respond /PING/i, (msg) ->
-    msg.reply "PONG\n\n[#{new Date()}]"
+    msg.reply "PONG\n\n#{new Date()}"


Fixes [#3864702], problem with qtip showing up when hovering on
student names

Basically javascript is stupid; at least jquery and qtip both behave
different when the environment has requirejs in it.

to solve this problem, we move the global requirejs functions to
window.ttm.

Also fixed a problem where main.js was overwriting the contents of
window.ttm instead of extending it.

ALSO this should fix the newly found silently failing tests on review

--- math_spec.coffee
+++ math_spec.coffee
@@ -1,4 +1,3 @@
-#= require almond
 #= require lib/math


Twss take 4

Twss take 4

--- scripts/twss.coffee
+++ scripts/twss.coffee
@@ -1,5 +1,5 @@
 twss = require 'twss'
-twss.threshold = 0.9
+twss.threshold = 0.99

 module.exports = (robot) ->
   robot.hear /(.*)/, (msg)->


cannot form default name if there's not an offering id

--- tutor/src/components/new-course/course-details.cjsx
+++ tutor/src/components/new-course/course-details.cjsx
@@ -20,8 +20,10 @@

   componentWillMount: ->
     NewCourseActions.set({num_sections: 1}) unless NewCourseStore.get('num_sections')
-    unless NewCourseStore.get('name')?
+    unless NewCourseStore.get('name')
       offeringId = NewCourseStore.get('offering_id')
+      return unless offeringId
+
       term = NewCourseStore.get('term')
       {appearance_code} = OfferingsStore.get(offeringId)
       {title} = CourseInformation.forAppearanceCode(appearance_code)


split regexp into commented pieces

split regexp into commented pieces

--- server/controllers/deploy.coffee
+++ server/controllers/deploy.coffee
@@ -3,7 +3,11 @@
 range_check = require('range_check')

 tagRefersToServer = (tag, serverTags) ->
-  regexp = "^[^-]*(#{serverTags.join('|')})[,-]"
+  regexp =  "^"                         # at beginning of line
+  regexp += "[^-]*"                     # accept everything until first hyphen
+  regexp += "(#{serverTags.join('|')})" # meanwhile, look for one of the tags
+  regexp += "[,-]"                      # if found, be sure it is either followed by another one or is the last
+
   regexpMatches = new RegExp(regexp).exec(tag)
   return regexpMatches?[1]?