only return announced info hash

only return announced info hash

--- src/dht-crawler.coffee
+++ src/dht-crawler.coffee
@@ -19,8 +19,8 @@
 	messageTimeout: 60 * 1000
 	pingInterval: 3 * 60 * 1000
 	findInterval: 2 * 60 * 1000
-	infoHashTimeout: 60 * 60 * 1000
-	maxRouteTableLen: 500
+	infoHashTimeout: 30 * 60 * 1000
+	maxRouteTableLen: 1000
 	maxQueryNodesLen: 100
 	maxAnnounceNodesLen: 1000

@@ -93,14 +93,18 @@

 		getAllInfoHashs: () ->
 			date = new Date()
+			allAnnounceInfoHash = []
 			for item in @infoHashTable.entries()
-				infoHash = item[0]
-				torrent = item[1]
-				{
-					infoHash: infoHash
-					queryNodesNum: torrent.queryNodes.estimate()
-					announceNodesNum: torrent.announceNodes.estimate()
-				}
+				announceNodesLen = torrent.announceNodes.estimate()
+				if announceNodesLen > 0
+					infoHash = item[0]
+					torrent = item[1]
+					allAnnounceInfoHash.push {
+						infoHash: infoHash
+						queryNodesNum: torrent.queryNodes.estimate()
+						announceNodesNum: torrent.announceNodes.estimate()
+					}
+			allAnnounceInfoHash

 		getTorrent: (infoHash) ->


HIRE-16-frontend : added missing return statement

--- src/main/java/app/profile/profile.coffee
+++ src/main/java/app/profile/profile.coffee
@@ -64,10 +64,12 @@
     $('.form-group').removeClass('has-warning')
     $document.duScrollTopAnimated(0)

+
   $scope.change = (id) ->
     $('#' + id).addClass('has-warning')

+


activity: clicking on project opens the log

--- salvus/page/activity.coffee
+++ salvus/page/activity.coffee
@@ -220,7 +220,7 @@
         events : [{path:target.data('name'), timestamp:target.data('timestamp')}]
         mark   : 'read'
     if path == '.sagemathcloud.log'
-        history.load_target("projects/#{project_id}")
+        history.load_target("projects/#{project_id}/log")
     else
         history.load_target("projects/#{project_id}/files/#{path}")
         if comment


Only render trailing whitespace indent guides on whitespace-only lines

Fixes #1895

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -1482,10 +1482,12 @@
       html = @buildEmptyLineHtml(showIndentGuide, eolInvisibles, htmlEolInvisibles, indentation, editor, mini)
       line.push(html) if html
     else
+      firstTrailingWhitespacePosition = text.search(/\s*$/)
+      lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
       position = 0
       for token in tokens
         @updateScopeStack(line, scopeStack, token.scopes)
-        hasIndentGuide = not mini and showIndentGuide
+        hasIndentGuide = not mini and showIndentGuide and lineIsWhitespaceOnly
         line.push(token.getValueAsHtml({invisibles, hasIndentGuide}))
         position += token.value.length


Add comment

Add comment

--- src/scripts/models/content/node.coffee
+++ src/scripts/models/content/node.coffee
@@ -1,3 +1,7 @@
+# Representation of individual nodes in a book's tree (table of contents).
+# A Node can represent both a tree (subcollection), or leaf (page).
+# Page Nodes also are used to cache a page's content once loaded.
+
 define (require) ->
   $ = require('jquery')
   Backbone = require('backbone')


Checked for object literal instead of object.

--- src/SchemaUtils.coffee
+++ src/SchemaUtils.coffee
@@ -88,7 +88,7 @@
     model

   findByProject: (collection, projectId, args) ->
-    if Types.isObject(projectId)
+    if Types.isObjectLiteral(projectId)
       args = projectId
       projectId = null
     projectId ?= Projects.getCurrentId()


Whoops, restore old C shape rules

Whoops, restore old C shape rules

--- src/languages/c.coffee
+++ src/languages/c.coffee
@@ -76,35 +76,35 @@
   ['unaryExpression', 'value'], # e.g. `sizeof(a)`
   ['typeName', 'value'], # e.g. `int`
   ['initializer', 'value'], # e.g. `{a, b, c}` when in `int x[] = {a, b, c};`
-  ['castExpression', 'value'], # e.g. `(b)a`
+  ['castExpression', 'value'] # e.g. `(b)a`
 ]

 SHAPE_RULES = [
-  ['jumpStatement', 'block-only'] # e.g. `return 0;`
-  ['declaration', 'block-only'], # e.g. `int a;`
-  ['specialMethodCall', 'block-only'], # e.g. `a(b);`
-  ['additiveExpression', 'value-only'], # e.g. `a + b`
-  ['multiplicativeExpression', 'value-only'], # e.g. `a * b`
+  ['blockItem', 'block-only'], # Any statement, like `return 0;`
+  ['expression', 'value-only'], # Any expression, like `a + b`
   ['postfixExpression', 'block-only'], # e.g. `a(b, c);` OR `a++`
+  ['equalityExpression', 'value-only'], # e.g. `a == b`
+  ['logicalAndExpression', 'value-only'], # e.g. `a && b`
+  ['logicalOrExpression', 'value-only'], # e.g. `a || b`
   ['iterationStatement', 'block-only'], # e.g. `for (int i = 0; i < 10; i++) { }`
   ['selectionStatement', 'block-only'], # e.g. if `(a) { } else { }` OR `switch (a) { }`
   ['assignmentExpression', 'block-only'], # e.g. `a = b;` OR `a = b`
   ['relationalExpression', 'value-only'], # e.g. `a < b`
   ['initDeclarator', 'block-only'], # e.g. `a = b` when inside `int a = b;`
-  ['blockItemList', 'block-only'], # List of commands
-  ['compoundStatement', 'block-only'], # List of commands inside braces
   ['externalDeclaration', 'block-only'], # e.g. `int a = b` when global
   ['structDeclaration', 'block-only'], # e.g. `struct a { }`
   ['declarationSpecifier', 'block-only'], # e.g. `int` when in `int a = b;`
   ['statement', 'block-only'], # Any statement, like `return 0;`
   ['functionDefinition', 'block-only'], # e.g. `int myMethod() { }`
   ['expressionStatement', 'block-only'], # Statement that consists of an expression, like `a = b;`
-  ['expression', 'value-only'], # Any expression, like `a + b`
+  ['additiveExpression', 'value-only'], # e.g. `a + b`
+  ['multiplicativeExpression', 'value-only'], # e.g. `a * b`
+  ['declaration', 'block-only'], # e.g. `int a;`
   ['parameterDeclaration', 'block-only'], # e.g. `int a` when in `int myMethod(int a) { }`
   ['unaryExpression', 'value-only'], # e.g. `sizeof(a)`
   ['typeName', 'value-only'], # e.g. `int`
   ['initializer', 'value-only'], # e.g. `{a, b, c}` when in `int x[] = {a, b, c};`
-  ['castExpression', 'value-only'], # e.g. `(b)a`
+  ['castExpression', 'value-only'] # e.g. `(b)a`
 ]

 config = {
@@ -126,7 +126,7 @@
 }

 # Test to see if a node is a method call
-getMethodName = (method) ->
+getMethodName = (node) ->
   if node.type is 'postfixExpression' and
      # The children of a method call are either
      # `(method) '(' (paramlist) ')'` OR `(method) '(' ')'`


fix #4

fix #4

--- src/lib/faction.coffee
+++ src/lib/faction.coffee
@@ -147,6 +147,9 @@

     isCallingBot: (item) ->

+        # send by self
+        return false if item.markup.SENDER1?.plain is (BotName + ': ')
+
         return true if BotName? and item.text.indexOf('@' + BotName) > -1
         return true if /@shanghaienlbot\d*/gi.test item.text
         return true if /#bot/g.test item.text


Normalize require indentation

Normalize require indentation

--- src/scripts/lib/client/net/socket.coffee
+++ src/scripts/lib/client/net/socket.coffee
@@ -1,5 +1,5 @@
-attr         = require('attr-accessor')
-ByteBuffer   = require('byte-buffer')
+attr = require('attr-accessor')
+ByteBuffer = require('byte-buffer')
 EventEmitter = require('events')

 # Base-class for any socket including signals and host/port management


Change title level for async function documentation

--- src/async/index.coffee
+++ src/async/index.coffee
@@ -1,7 +1,7 @@
 # A bunch of functions to deals with asynchronous process.
 # @toc

-#### parallel
+##### parallel

 # Execute an array of functions `fns` in parallel. The passed-in `callback`
 # will only be called when the all functions have call back.
@@ -15,7 +15,7 @@
   cb = -> count += 1; if count is fns.length then callback?()
   if fns.empty() then callback() else fn cb for fn in fns

-#### queue
+##### queue

 # Execute an array of function `fns` one after the other.
 # The passed-in `callback` will only be called when the queue
@@ -29,7 +29,7 @@
   next = -> if fns.empty() then callback() else fns.shift() next
   next()

-#### chain
+##### chain

 # Execute an array of function `fns` on after the other, like a `queue`,
 # but the different between them lies in the fact that a `chain` pass


Fix function name.

Fix function name.

--- src/map-printer.coffee
+++ src/map-printer.coffee
@@ -133,8 +133,9 @@

         afterPrint: () =>
             if @makingPrint
-                setTimeout(onAfterPrint, 100);
-                return;
+                setTimeout afterPrint, 100
+                return
+
             markers = window.mapView.allMarkers._featureGroup._layers;
             for own id, marker of markers
                 # Remove the printed marker icon


Improving regexp for reuse.

Improving regexp for reuse.

--- src/toaster/filetype/jade/handler.coffee
+++ src/toaster/filetype/jade/handler.coffee
@@ -10,7 +10,7 @@

 module.exports = class Handler

-  @FILTER = /(?:\/)(?:[^\/_]+)\.jade/m
+  @FILTER = /(\/)([^\/_]+)(\.jade)/m

   constructor: (@toaster, @cli, @config, @tree, @dirpath, @realpath) ->
     @getinfo()
@@ -25,7 +25,7 @@

     # compute all necessary release paths
     release_file = path.join @tree.config.output_dir, @filepath
-    release_file = release_file.replace '.jade', '.js'
+    release_file = release_file.replace Handler.FILTER, "$1$2.js"
     output_dir = path.dirname release_file

     relative_path = release_file.replace @tree.toaster.basepath, ''


Fixed jshint error

Fixed jshint error

--- src/model/users.coffee
+++ src/model/users.coffee
@@ -16,7 +16,7 @@
   "weeklyReport":       Boolean
   "settings":           Object
   "token":              String
-  "tokenType":
+  "tokenType":
     type:     String
     enum:     ['newUser', 'existingUser']
     default:  "newUser"


use which instead of keyCode

use which instead of keyCode

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -484,13 +484,13 @@
     new_input = ""
     # if it isn't the year input accept 2 numbers (48-57) or moving right (39)
     if this_label.index() != $(this).closest(".date-input").find("label:last-child").index()
-      if (e.keyCode >= 48 && e.keyCode <= 57) || e.keyCode == 39
+      if (e.which >= 48 && e.which <= 57) || e.which == 39
         if $(this).val().length == 2
           # focus on the next input
           new_input = this_label.next().find("input")
     # if it isn't the day input you can go backwards by backspacing (8) or moving left (37)
     if this_label.index() != $(this).closest(".date-input").find("label:first-child").index()
-      if e.keyCode == 8 || e.keyCode == 37
+      if e.which == 8 || e.which == 37
         if $(this).val().length == 0
           # focus on the next input
           new_input = this_label.prev().find("input")
@@ -499,9 +499,10 @@
       new_input.val("")
       new_input.focus()
       new_input.val(new_input_text)
+
   # only accept numbers(48-47), backspace(8), tab(9), cursor keys left(37) and right(39) and enter for submitting
   $(".date-input input").on 'keypress keydown keyup', (e) ->
-    if !((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105) || e.keyCode == 8 || e.keyCode == 9 || e.keyCode == 37 || e.keyCode == 39 || e.keyCode == 13)
+    if !((e.which >= 48 && e.which <= 57) || (e.which >= 96 && e.which <= 105) || e.which == 8 || e.which == 9 || e.which == 37 || e.which == 39 || e.which == 13)
       e.preventDefault()
       return false


#229: remove unnecessary lines

#229: remove unnecessary lines

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -64,8 +64,6 @@
     previewTabId = id + '_preview_bucket'
     previewTab = $this.find('.preview-tab')
     previewTab.find('a').attr('href', '#'+previewTabId)
-
-   # previewTab.attr('href', '#'+previewTabId)

     #set write-section's id
     writeSec = $this.find('.tab-content>.active')


rm comma

rm comma

--- app/assets/pg/intro/intro.constant.js.coffee
+++ app/assets/pg/intro/intro.constant.js.coffee
@@ -88,5 +88,5 @@
         caption: "",
         image: "http://static.jquestapp.com/images/intro/slack.png",
         type: "image"
-      },
+      }
     ]


Fix a failing test within Pop

Fix a failing test within Pop

--- app/assets/utensils/pop/spec/pop_spec.coffee
+++ app/assets/utensils/pop/spec/pop_spec.coffee
@@ -99,7 +99,7 @@
       expect(@north_pop.cached_markup).toBeNull()

     it 'sets the default container to null', ->
-      expect(@north_pop.container).toBeNull()
+      expect(@north_pop.container).toBe($('body'))

     it 'sets default namespace', ->
       expect(@east_pop.namespace).toEqual('pop')


FIX: Cannot Specify Dates

FIX: Cannot Specify Dates

--- src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee
+++ src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee
@@ -47,15 +47,26 @@
       if $scope.unit.end_date && $scope.unit.end_date.getMonth
         $scope.unit.end_date = "#{$scope.unit.end_date.getFullYear()}-#{$scope.unit.end_date.getMonth() + 1}-#{$scope.unit.end_date.getDate()}"

-      saveData = {
-        name: $scope.unit.name
-        code: $scope.unit.code
-        description: $scope.unit.description
-        teaching_period_id: $scope.unit.teaching_period_id
-        start_date: $scope.unit.start_date
-        end_date: $scope.unit.end_date
-        active: $scope.unit.active
-      }
+      if $scope.unit.teaching_period_id
+        saveData = {
+          name: $scope.unit.name
+          code: $scope.unit.code
+          description: $scope.unit.description
+          teaching_period_id: $scope.unit.teaching_period_id
+          start_date: null
+          end_date: null
+          active: $scope.unit.active
+        }
+      else
+        saveData = {
+          name: $scope.unit.name
+          code: $scope.unit.code
+          description: $scope.unit.description
+          teaching_period_id: $scope.unit.teaching_period_id
+          start_date: $scope.unit.start_date
+          end_date: $scope.unit.end_date
+          active: $scope.unit.active
+        }

       if $scope.unit.id == -1
         Unit.create { unit: saveData },


Removed extraneous Session variable in votebox

--- client/coffeescript/templates/votebox.coffee
+++ client/coffeescript/templates/votebox.coffee
@@ -1,6 +1,5 @@
 _.extend( Template.votebox,
   voted: ->
-    Session.equals("voted_#{@_id}", true) ||
     Session.get('user_id') in @votes?.up.users ||
     Session.get('user_id') in @votes?.down.users
   voted_up: -> Session.get('user_id') in @votes?.up.users
@@ -8,11 +7,9 @@
   score: -> @votes?.up.users.length - @votes?.down.users.length
   events: {
     "click button[name='up_vote']": (event) ->
-      Session.set("voted_#{@_id}",true)
       @votes?.up.users.push(Session.get('user_id'))
       Posts.update(@_id, {$set: {votes: @votes}})
     "click button[name='down_vote']": ->
-      Session.set("voted_#{@_id}",true)
       @votes?.down.users.push(Session.get('user_id'))
       Posts.update(@_id, {$set: {votes: @votes}})
   }


Remove shortcuts list from EditorPane.

Remove shortcuts list from EditorPane.

--- client/ide/workspace/panes/editorpane.coffee
+++ client/ide/workspace/panes/editorpane.coffee
@@ -21,55 +21,6 @@

     @addSubView @aceView = new AceView delegate: @getDelegate(), file
     @aceView.ace.once 'ace.ready', =>
-      # debugger
-      if content is '' and not shortcutsShown
-        shortcutsShown = yes
-        content =
-          """
-          Welcome to the new IDE :)
-          ======================
-
-          Keyboard shortcuts:
-          -------------------
-
-          Editor:
-          -------
-
-          "save",       "Ctrl-S"
-          "saveAs",     "Ctrl-Shift-S"
-          "find",       "Ctrl-F"
-          "replace",    "Ctrl-Shift-F"
-          "preview",    "Ctrl-Shift-P"
-          "fullscreen", "Ctrl-Enter"
-          "gotoLine",   "Ctrl-G"
-          "gotoLineL",  "Ctrl-L"
-          "saveAll",    "Ctrl-Alt-S"
-          "closeTab",   "Ctrl-W"
-          "settings",   "Ctrl-,"
-
-          Workspace:
-          ----------
-
-          'split vertically',   'Ctrl-Alt-v'
-          'split horizontally', 'Ctrl-Alt-h'
-          'merge splitview',    'Ctrl-Alt-m'
-          'create new file',    'Ctrl-Alt-n'
-          'collapse sidebar',   'Ctrl-Alt-c'
-          'expand sidebar',     'Ctrl-Alt-e'
-          'go to left tab',     'Ctrl-Alt-['
-          'go to right tab',    'Ctrl-Alt-]'
-          'go to tab number',   'Ctrl-Alt-1'
-          'go to tab number',   'Ctrl-Alt-2'
-          'go to tab number',   'Ctrl-Alt-3'
-          'go to tab number',   'Ctrl-Alt-4'
-          'go to tab number',   'Ctrl-Alt-5'
-          'go to tab number',   'Ctrl-Alt-6'
-          'go to tab number',   'Ctrl-Alt-7'
-          'go to tab number',   'Ctrl-Alt-8'
-          'go to tab number',   'Ctrl-Alt-9'
-
-          """
-
       @getEditor().setValue content, 1
       @ace.setReadOnly yes  if @getOptions().readOnly


Fixed not saved alert keeps coming up even if document has been saved [#113644621]

--- src/code/client.coffee
+++ src/code/client.coffee
@@ -469,7 +469,7 @@
       metadata: metadata
       saving: null
       saved: false
-      dirty: content?.requiresConversion()
+      dirty: not additionalState.saved and content?.requiresConversion()
     for own key, value of additionalState
       state[key] = value
     @_setWindowTitle metadata?.name


Log an internal error if sandbox evaluation of the CSM compiler failed (syntax errors will be handled by the normal callback function)

--- src/compile.csm.coffee
+++ src/compile.csm.coffee
@@ -27,6 +27,6 @@
       callback result
     onerror: (data,request) ->
       #console.log prefix + source + postfix
-      #console.log "Error"
+      mecha.logInternalError "Error compiling the solid model."
       #console.log data


added more info in failure message in drawers legacy tests

--- testApp/app/controllers/drawers.coffee
+++ testApp/app/controllers/drawers.coffee
@@ -264,8 +264,8 @@
           widthOfDrawerInPixels: 200
         steroids.logger.log "SUCCESS in enabling legacy gesture"
       onFailure: =>
-        steroids.logger.log "FAILURE in testLegacyEnableGesture"
-        navigator.notification.alert "FAILURE in testLegacyEnableGesture"
+        steroids.logger.log "FAILURE in preloading googleview in testLegacyEnableGesture"
+        navigator.notification.alert "FAILURE in preloading googleview for testLegacyEnableGesture"
     }

   @testLegacyEnableGestureShorthand: ->


hack to set the control

hack to set the control

--- components/artwork_item/save_controls.coffee
+++ components/artwork_item/save_controls.coffee
@@ -2,15 +2,23 @@
 { splitTest } = require '../../lib/analytics.coffee'
 sharify = require 'sharify'
 user = CurrentUser.orNull()
+Cookies = require 'cookies-js'

 return module.exports = require './save_controls/view.coffee' unless user

+window.setSaveControls = (path) ->
+  Cookies.set 'save-controls', path
+  location.reload()
+
+window.clearSaveControls = ->
+  Cookies.set 'save-controls', null
+
 if 'Set Management' in user.get('lab_features')
-  splitTestPath = splitTest 'ab:save:controls',
+  splitTestPath = Cookies.get('save-controls') or splitTest 'ab:save:controls',
     'drop down': 1 / 3
     'two button': 1 / 3
     'one button': 1 / 3
-  sharify.data.SAVE_CONTROLS_SPLIT_TEST = null #splitTestPath
+  sharify.data.SAVE_CONTROLS_SPLIT_TEST = splitTestPath

 module.exports = switch splitTestPath
   when 'drop down' then require './save_controls_drop_down/view.coffee'


Fix passwordForm in accountSettings panel

--- client/app/Applications/Account.kdapplication/account/accSettingsPersPassword.coffee
+++ client/app/Applications/Account.kdapplication/account/accSettingsPersPassword.coffee
@@ -59,15 +59,9 @@
       cssClass     : "action-link"
       click        : => @passwordSwappable.swapViews()

-    @passwordSwappable = new AccountsSwappable
+    passwordForm.addSubView @passwordSwappable = new AccountsSwappable
       views    : [passwordInputs, nonPasswordInputs]
       cssClass : "clearfix"
-
-    passwordEdit.on 'click', ->
-      passwordSwappable.swapViews()
-
-    passwordCancel.on 'click', ->
-      passwordSwappable.swapViews()

   passwordDidUpdate:->
     @passwordSwappable.swapViews()
@@ -79,27 +73,3 @@
   saveNewPassword:(formData)->
     KD.remote.api.JUser.changePassword formData.password,(err,docs)=>
       unless err then do @passwordDidUpdate
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


Update hard-coded default port

Update hard-coded default port

--- src/core/config.coffee
+++ src/core/config.coffee
@@ -11,7 +11,7 @@
     irc:
       address: '199.9.253.199'
     server:
-      port: 3001
+      port: 6667

   constructor: (options) ->
     for option, value of options


evaluate user marks

evaluate user marks

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -509,6 +509,7 @@
     return if @TRAINING_SUBJECT is null
     xs = []
     ys = []
+    P = null
     x_sum = null
     y_sum = null
     for priorAsteroid, i in [@TRAINING_SUBJECT.metadata.asteroids...]
@@ -518,13 +519,41 @@
       y_sum += ys[i]
     x_avg = Math.round(x_sum/@numFrames)
     y_avg = Math.round(y_sum/@numFrames)
+    P = {x: x_sum, y: y_sum}
     rad_x = Math.abs( (Math.max.apply null, [xs...]) - (Math.min.apply null, [xs...]) ) * 4
     rad_y = Math.abs( (Math.max.apply null, [ys...]) - (Math.min.apply null, [ys...]) )* 4

     for surface in [@markingSurfaceList...]
       svgElement = surface.addShape 'ellipse', class: "prior-asteroid", opacity: 0.75, cx: x_avg, cy: y_avg, rx: rad_x, ry: rad_y, fill: "none", stroke: "rgb(20,200,20)", 'stroke-width': 4

-
+    @evaluateAnnotations(P)
+
+  evaluateAnnotations: (P_ref) ->
+    xs = []
+    ys = []
+    P = null
+    d = null
+    x_sum = null
+    y_sum = null
+    for sighting in [@setOfSightings...] when sighting.type is "asteroid"
+      for annotation, i in sighting.annotations
+        xs[i] = annotation.x
+        ys[i] = annotation.y
+        x_sum += xs[i]
+        y_sum += ys[i]
+      x_avg = Math.round(x_sum/sighting.annotations.length)
+      y_avg = Math.round(y_sum/sighting.annotations.length)
+      P = {x: x_sum, y: y_sum}
+      d = @dist(P,P_ref)
+
+      if d <= 20
+        console.log 'Awesome job!'
+      else
+        console.log 'You disappoint me.'
+
+  dist: (P1,P2) ->
+    Math.sqrt ( Math.pow(P1.x-P2.x,2) + Math.pow(P1.y-P2.y,2) )
+

   sendClassification: ->
     @finishButton.prop 'disabled', true


Unlink teamMediumComments when deleting teamMedium

--- src/persistence.coffee
+++ src/persistence.coffee
@@ -418,6 +418,19 @@
             result
       ).callback callback

+
+  # Remove comments when deleting teamMedium
+  wrapMethod sdk, 'deleteTeamMedium', (deleteTeamMedium) ->
+    (teamMedium, callback) ->
+      toRemove = teamMedium.teamMediumComments.slice()
+
+      linking.unlinkItems toRemove, lookup
+      deleteTeamMedium.call(this, teamMedium).fail((err) ->
+        linking.linkItems toRemove, lookup
+        err
+      ).callback callback
+
+
   # Remove all records belonging to a team when it is deleted
   wrapMethod sdk, 'deleteTeam', (deleteTeam) ->
     (team, callback) ->


The command history storage variable should default to an empty hash

--- app/javascripts/cs_console.coffee
+++ app/javascripts/cs_console.coffee
@@ -426,7 +426,7 @@
   # saves commands in local storage so history can be persisted between sessions.
   # A historyLabel option can be used to set a custom entry in local storage.
   class CSConsoleHistory
-    storage: ''
+    storage: {}
     currentIndex: 0
     historyLabel: 'cs-console-history'
     cachedHistory: []


fixed a bug in the creation of the info.json file

--- app/routes/algorithmRouter.coffee
+++ app/routes/algorithmRouter.coffee
@@ -222,7 +222,7 @@
                       type: 'rectangle'
                       closed: true
                       segments:[[0,0],[0,150],[350,150],[350,0]]
-        req =
+        testRequest =
           originalUrl: '/' + route
           body:
             images: [
@@ -234,7 +234,7 @@
             highlighter: highlighter
             inputs: inputs

-        executableHelper.preprocess req, QueueHandler.dockerProcessingQueue, 'test',
+        executableHelper.preprocess testRequest, QueueHandler.dockerProcessingQueue, 'test',
           (err, response) ->
             if(err?)
               logger.log 'error', err


remove extraneous interval

remove extraneous interval

--- app/scripts/control/widget.coffee
+++ app/scripts/control/widget.coffee
@@ -6,11 +6,10 @@

 .controller('widgetCtrl', [
   '$scope'
-  '$interval'
   'widgetFactory'
   'robot'

-($scope, $interval, widgetFactory, robot) ->
+($scope, widgetFactory, robot) ->
   $scope.widgets = []
   $scope.mostRecentWidget = {}

@@ -19,6 +18,7 @@

   $scope.addWidget = (peripheralFilter = {id: -1}) ->
     $scope.widgets.push new widgetFactory(robot.peripheral(peripheralFilter), 'linechart')
+    $scope.widgets[$scope.widgets.length-1].update()

   $scope.removeWidget = (widget) ->
     id = widget.id
@@ -32,13 +32,6 @@

   $scope.removeAllWidgets = ->
     $scope.widgets = []
-
-  # update widgets
-  $interval(
-    ->
-      widget.update() for widget in $scope.widgets when widget.render
-    , 300
-    )
 ])

 .directive('draggable',
@@ -53,12 +46,11 @@
     $(jQelm).draggable({
       containment: 'parent'
       start: (event, ui) ->
-        widget.render = false
         for series in widget.data
           series.values = series.values.slice()
       stop: (event, ui) ->
         widget.position = ui.position
-        widget.render = true
+        widget.update()
       })
 )

@@ -70,11 +62,10 @@
     jQelm = $(elm[0])
     $(jQelm).resizable({
       start: (event, ui) ->
-        widget.render = false
         for series in widget.data
           series.values = series.values.slice()
       stop: (event, ui) ->
-        widget.render = true
+        widget.update()
     })
 )

@@ -101,7 +92,6 @@
       update: -> _.each(_data, (element, index, list) ->
         element.values =  element.peripheral.historyPairs())
       url: defaultURL.replace('type', String(type))
-      render: true
       position: null
       options: {
         chart: {


Added onbeforeunload message

Added onbeforeunload message

--- app/src/Xjs/XTechneDesktop.coffee
+++ app/src/Xjs/XTechneDesktop.coffee
@@ -22,6 +22,8 @@
         @displaySurface.classList.add 'xtechneDesktopContainer'
         @displaySurface.classList.add 'hidden'
         @displayContainer.appendChild @displaySurface
+        OS = require 'OS'
+        window.onbeforeunload = () -> "This will reboot/shutdown #{OS.className} without saving your work"
         @initDesktop()

     initDesktop: () ->


emit 'restored' event after complete

emit 'restored' event after complete

--- src/flux/period.coffee
+++ src/flux/period.coffee
@@ -17,6 +17,7 @@

   restored: (periodData, periodId, courseId) ->
     CourseActions.load(courseId)
+    @emit('restored')
     delete @_asyncStatus[periodId]

   _created: (period, courseId) ->


add the simplest form of authentication possible

--- apps/authentication/routes.coffee
+++ apps/authentication/routes.coffee
@@ -3,8 +3,10 @@
     res.render "#{__dirname}/views/login"

   app.post '/sessions/new', (req, res) ->
-    console.log("Username :: ", req.body.username)
-    console.log("Password :: ", req.body.password)
-    res.send("Received : " + req.body.username + " => " + req.body.password)
+    if ("admin" is req.body.username and "geeone" is req.body.password)
+      req.cookies.username = req.body.username
+      res.redirect "/units"
+    else
+      res.redirect "/login"

 module.exports = routes


fix typo

fix typo

--- src/fs/fsConfig.coffee
+++ src/fs/fsConfig.coffee
@@ -1,4 +1,4 @@
-faDefaultConfig =
+fsDefaultConfig =
     dateFormat: 'MM/DD/YYYY'

 angular


uncomment console.log

uncomment console.log

--- assets/javascripts/visuals.coffee
+++ assets/javascripts/visuals.coffee
@@ -335,7 +335,7 @@
     # $("tspan." + klass).css({'background-color': color})

 draw_line_between_nes = (klass,links) ->
-  console.log klass
-  console.log links
-
-
+  # console.log klass
+  # console.log links
+
+


include Cooldown as default module

include Cooldown as default module

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -161,7 +161,7 @@
       I.active = false
   }

-  defaultModules = [Bindable, Bounded, Drawable, Durable]
+  defaultModules = [Bindable, Bounded, Cooldown, Drawable, Durable]
   modules = defaultModules.concat(I.includedModules.invoke('constantize'))
   modules = modules.without(I.excludedModules.invoke('constantize'))


Add missing parenthesis

Add missing parenthesis

--- extension/packages/mode-hints/huffman.coffee
+++ extension/packages/mode-hints/huffman.coffee
@@ -16,7 +16,7 @@
     throw new Error('`alphabet` must consist of at least 2 characters.')

   unless typeof(callback) == "function"
-    throw new TypeError "`callback` must be provided and be a function."
+    throw new TypeError("`callback` must be provided and be a function.")

   # Shallow working copy.


The CSON library requires the underscore-extensions library.

--- src/stdlib/cson.coffee
+++ src/stdlib/cson.coffee
@@ -1,3 +1,4 @@
+require 'underscore-extensions'
 _ = require 'underscore'

 module.exports =


Cache specificities

Cache specificities

--- src/key-binding.coffee
+++ src/key-binding.coffee
@@ -8,6 +8,15 @@
 class KeyBinding
   @parser: null
   @currentIndex: 1
+  @specificities: null
+
+  @calculateSpecificity: (selector) ->
+    @specificities ?= {}
+    value = @specificities[selector]
+    unless value?
+      value = specificity(selector)
+      @specificities[selector] = value
+    value

   @normalizeKeystroke: (keystroke) ->
     normalizedKeystroke = keystroke.split(/\s+/).map (keystroke) =>
@@ -33,7 +42,7 @@
     @command = command
     @keystroke = KeyBinding.normalizeKeystroke(keystroke)
     @selector = selector.replace(/!important/g, '')
-    @specificity = specificity(selector)
+    @specificity = KeyBinding.calculateSpecificity(selector)
     @index = KeyBinding.currentIndex++

   matches: (keystroke) ->


fixed coffeelint errors on workers/social/emailer.coffee

--- workers/social/lib/social/emailer.coffee
+++ workers/social/lib/social/emailer.coffee
@@ -1,16 +1,18 @@
+# due to a bug in coffeelint 1.10.1
+# coffeelint: disable=no_implicit_braces
 module.exports = class Emailer
   nodemailer = require 'nodemailer'

   email = require './config.email'

-  @smtpTransport = nodemailer.createTransport "SMTP",
-    service: "SendGrid"
+  @smtpTransport = nodemailer.createTransport 'SMTP',
+    service: 'SendGrid'
     auth:
-      user: "koding"
-      pass: "DEQl7_Dr"
+      user: 'koding'
+      pass: 'DEQl7_Dr'

-  @send : (options,callback) ->
-    {From,To,Subject,HtmlBody,TextBody,ReplyTo,Bcc} = options
+  @send : (options, callback) ->
+    { From, To, Subject, HtmlBody, TextBody, ReplyTo, Bcc } = options
     mailOptions =
       from    : From or email.defaultFromMail
       to      : To
@@ -30,10 +32,12 @@
           callback error
         else
           callback null, response
-    ,1000/20
+    , 1000 / 20

-  @simulate : (options,callback)->
+  @simulate : (options, callback) ->

     setTimeout ->
       console.log "[SIMULATION] EMAIL SENT TO #{options.To}"
-    ,250
+    , 250
+
+


Fixed testmanager so that it emits update events

--- src/testmanager.coffee
+++ src/testmanager.coffee
@@ -15,7 +15,9 @@
     console.log "Watching directory: ".yellow +  "./#{@testDir}/".green
     chokidar.watch("./#{@testDir}/", ignoreInitial: yes).on 'all', (event, path) =>
       console.log event, path
-      if /\.coffee$/.test path then @scan()
+      if /\.coffee$/.test path
+        @scan()
+        @emit 'update'

   # Copy files from srcDir to destDir
   copy: (srcDir, destDir) ->
@@ -29,7 +31,6 @@

   # Update the files
   scan: (baseDir = process.cwd()) ->
-    console.log "Scanning directory: ".yellow +  "./#{@testDir}/".green
     base = baseDir + "/" + @testDir
     if not fs.existsSync base
       fs.mkdirSync base
@@ -39,7 +40,6 @@
       if fileName.match /\.coffee$/
         dataPath = "#{base}/#{fileName}"
         key = fileName.replace /\.[^/.]+$/, ''
-        console.log "Scanning test file #{dataPath} with key #{key}".red
         coffeeCode = fs.readFileSync(dataPath, encoding:'utf8')
         try
           scriptCode = coffee.compile coffeeCode


:shirt:

:shirt:

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -1499,7 +1499,7 @@

     filePath = file.getPath()
     if file instanceof File
-      directoryPromise = new Promise (resolve, reject) =>
+      directoryPromise = new Promise (resolve, reject) ->
         mkdirp path.dirname(filePath), (error) ->
           if error then reject(error) else resolve()
       destination = filePath


:memo: Fix typo

:memo: Fix typo

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -138,7 +138,7 @@
       @emitter.emit 'did-change-encoding', @getEncoding()
     @subscribe @buffer.onDidDestroy => @destroy()

-    # TODO: remove these thwne we remove the deprecations. They are old events.
+    # TODO: remove these when we remove the deprecations. They are old events.
     @subscribe @buffer.onDidStopChanging => @emit "contents-modified"
     @subscribe @buffer.onDidConflict => @emit "contents-conflicted"
     @subscribe @buffer.onDidChangeModified => @emit "modified-status-changed"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_effect.coffee
+++ src/text_effect.coffee
@@ -20,7 +20,7 @@
 ###

 ###*
-Game
+The default draw

 @name update
 @methodOf TextEffect#


levels and default game states

levels and default game states

--- src/text_screen.coffee
+++ src/text_screen.coffee
@@ -1,15 +1,15 @@
 GameOver = (I={}) ->
-  self = GameState(I).ext
-  drawTitleText = (canvas, titleText, subtitleText) ->
-    canvas.fillColor 'white'
-    canvas.font '24px Helvetica'
+  self = GameState(I).extend
+    drawTitleText = (canvas, titleText, subtitleText) ->
+      canvas.fillColor 'white'
+      canvas.font '24px Helvetica'

-    canvas.centerText
-      y: App.height / 2 - 20
-      text: titleText
+      canvas.centerText
+        y: App.height / 2 - 20
+        text: titleText

-    canvas.font '14px Helvetica'
+      canvas.font '14px Helvetica'

-    canvas.centerText
-      y: App.height / 2
-      text: subtitleText+      canvas.centerText
+        y: App.height / 2
+        text: subtitleText


Use x y positioning for controls

Use x y positioning for controls

--- src/util/render.coffee
+++ src/util/render.coffee
@@ -9,18 +9,23 @@
       background: world.get 'fill'
       height: world.get 'height'
       width: world.get 'width'
+      position: 'absolute'
+      left: world.get 'x'
+      top: world.get 'y'
     }
   render_children = (world) ->
-    world.map_children (child) ->
+    results = world.map_children (child) ->
       return draw(child) if child.get('path')?
       render_world(child)
-
+    name = world.get('name')
+    results.push T.span(name) if name?
+    results
   render_world = (world) ->
     dict = {
       id: world
       class: world.labels(['render', 'world'])
       style: get_style(world)
     }
-    T.div dict, world.bind() -> render_children(world)
+    T.div dict, render_children(world) #world.bind() ->

   render_world(root)


Allow to toggle display of mailbox list in menu

--- client/app/components/menu.coffee
+++ client/app/components/menu.coffee
@@ -25,8 +25,14 @@

         return should

+    getInitialState: ->
+        return displayActiveAccount: true
+
+    componentWillReceiveProps: (props) ->
+        if not Immutable.is(props.selectedAccount, @props.selectedAccount)
+            @setState displayActiveAccount: true
+
     render: ->
-

         if @props.accounts.length
             selectedAccountUrl = @buildUrl
@@ -113,7 +119,7 @@
         isSelected = (not @props.selectedAccount? and key is 0) \
                      or @props.selectedAccount?.get('id') is account.get('id')

-        accountClasses = classer active: isSelected
+        accountClasses = classer active: (isSelected and @state.displayActiveAccount)
         accountID = account.get 'id'
         defaultMailbox = AccountStore.getDefaultMailbox accountID
         unread = @props.unreadCounts.get defaultMailbox?.get 'id'
@@ -132,15 +138,24 @@
                 parameters: [accountID]
                 fullWidth: true # /!\ Hide second panel when switching account

+        toggleActive = =>
+            if isSelected
+                @setState displayActiveAccount: not @state.displayActiveAccount
+            else
+                @setState displayActiveAccount: true
+
         li className: accountClasses, key: key,
-            a href: url, className: 'menu-item account ' + accountClasses,
-                i className: 'fa fa-inbox'
-                if unread > 0
-                    span className: 'badge', unread
-                span
-                    'data-account-id': key,
-                    className: 'item-label',
-                    account.get 'label'
+            a
+                href: url,
+                className: 'menu-item account ' + accountClasses,
+                onClick: toggleActive,
+                    i className: 'fa fa-inbox'
+                    if unread > 0
+                        span className: 'badge', unread
+                    span
+                        'data-account-id': key,
+                        className: 'item-label',
+                        account.get 'label'

             ul className: 'list-unstyled submenu mailbox-list',
                 @props.favoriteMailboxes?.map (mailbox, key) =>


Do not allow register for 0 rating

Do not allow register for 0 rating

--- client/components/Checkins.coffee
+++ client/components/Checkins.coffee
@@ -26,6 +26,9 @@
             await @props.handleReload()
             @setState
                 result: result
+
+    canRegister: () ->
+        @props.myUser.rating > 0

     render: () ->
         wasme = [false, false]
@@ -84,24 +87,31 @@
                                 }

                         }
-

-                            {
-                            for _, i in SESSION_TIMES
-
-                                    {
-                                    if @props.myUser?._id and !wasme[i] and @props.data[i].checkins.length < @props.data[i].max
-                                        <Button bsStyle="primary" onClick={@register(i, @props.myUser?._id)}>
-                                            Зарегистрироваться
-                                        </Button>
-                                    }
-
-                            }
-

+                        {
+                        if @canRegister()
+

+                                {
+                                for _, i in SESSION_TIMES
+
+                                        {
+                                        if @props.myUser?._id and !wasme[i] and @props.data[i].checkins.length < @props.data[i].max
+                                            <Button bsStyle="primary" onClick={@register(i, @props.myUser?._id)}>
+                                                Зарегистрироваться
+                                            </Button>
+                                        }
+
+                                }
+

+                        }

                     {
                     if wasme[0] or wasme[1]
                         <Button bsStyle="info" onClick={@register(null, @props.myUser?._id)}>Отменить регистрацию</Button>
+                    else if !@canRegister()
+                        <Alert bsStyle="danger">
+                            Чтобы зарегистрироваться на занятие, вам надо решить минимум одну задачу.
+                        </Alert>
                     }

             }


Update Checkins.coffee

Update Checkins.coffee

--- client/components/Checkins.coffee
+++ client/components/Checkins.coffee
@@ -66,6 +66,10 @@
             Не забудьте с собой паспорт (если паспорта еще нет, то свидетельство о рождении) -- его могут спросить охранники на входе!
             </p>

+            <Alert bsStyle="danger">
+                27 января и 10 февраля занятий в ННГУ не будет в связи с проведением, соответственно, областной и городской олимпиад.
+            </Alert>
+
             {
             if @state.result?.error
                 <Alert bsStyle="danger">


Render epigraph different from problem

Render epigraph different from problem

--- client/components/Material.coffee
+++ client/components/Material.coffee
@@ -20,6 +20,8 @@
         `<Level {...props} />`
     else if props.material.type == 'contest'
         `<Contest {...props} />`
+    else if props.material.type == 'epigraph'
+        `<Page {...props} />`
     else
         `<Problem {...props} />`


Fix typo

Fix typo

--- client/components/Register.coffee
+++ client/components/Register.coffee
@@ -209,7 +209,7 @@
                     <FieldGroup
                         id="informaticsClass"
                         label={"Класс" + (@state.informaticsData &&
-                        "в #{@state.informaticsData.currentYearStart}-#{@state.informaticsData.currentYearStart+1} учебном году")}
+                        " в #{@state.informaticsData.currentYearStart}-#{@state.informaticsData.currentYearStart+1} учебном году")}
                         type="text"
                         value={@state.informaticsData?.class || ""}
                         disabled/>


Remove no-longer-required template require().

--- src/modal/Modal.coffee
+++ src/modal/Modal.coffee
@@ -4,7 +4,6 @@
 ###

 Pane      = require '../pane/Pane'
-template  = require './modal.template'
 backdrop  = require './backdrop'
 vars      = require '../vars'
 Promise    = require 'stout-core/promise/Promise'


Remove trailing whitespace

Remove trailing whitespace

--- storage/lib/xml.coffee
+++ storage/lib/xml.coffee
@@ -16,6 +16,6 @@
         @push @post
         cb()

-module.exports =
+module.exports =
     transform: (pre, post, mapper) ->
         new XmlStream pre, post, mapper


[IMPAC-868] Changed the status filter from PAID to FORECAST

--- src/components/widgets/accounts-invoices-list/accounts-invoices-list.directive.coffee
+++ src/components/widgets/accounts-invoices-list/accounts-invoices-list.directive.coffee
@@ -6,7 +6,7 @@

   setInitialParams = ->
     params = { include: 'contact', fields: { contacts: 'name' }, sort: w.sortParamater, currency: w.metadata.currency, filter: {} }
-    params.filter = { 'status.not': 'PAID' } if $scope.hideForecast
+    params.filter = { 'status.not': 'FORECAST' } if $scope.hideForecast
     return params

   w = $scope.widget


Also remove suffix from sabine (tie) and maarek, since ship name differentiates them.

--- coffeescripts/cards-common.coffee
+++ coffeescripts/cards-common.coffee
@@ -3627,7 +3627,7 @@
         }
         {
             name: "Maarek Stele (TIE Defender)"
-            canonical_name: 'maarekstele-swx52'
+            canonical_name: 'maarekstele'
             id: 193
             unique: true
             faction: "Galactic Empire"
@@ -4069,7 +4069,7 @@
         {
             name: 'Sabine Wren (TIE Fighter)'
             id: 223
-            canonical_name: "sabinewren-swx59"
+            canonical_name: "sabinewren"
             unique: true
             faction: 'Rebel Alliance'
             ship: 'TIE Fighter'


BG standup alert for demo

BG standup alert for demo

--- src/philips-hue.coffee
+++ src/philips-hue.coffee
@@ -180,6 +180,12 @@
       return handleError msg, err if err
       robot.logger.debug status

+  robot.hear /:standupbg:/, (msg) ->
+    alertState = lightState.create().alertShort()
+    api.setGroupLightState 4, alertState, (err, status) ->
+      return handleError msg, err if err
+      robot.logger.debug status
+
   robot.respond /hue @(\w+) (on|off)/i, (msg) ->
     [group, state] = msg.match[1..2]
     msg.send "Setting light group #{group} to #{state}"


This is an API-side bug, remove workaround

--- components/GetPortalStates.coffee
+++ components/GetPortalStates.coffee
@@ -9,11 +9,6 @@
 loginPath = '/_ah/login'
 xsrfPath = '/xsrftoken'
 updateInterval = 60 * 60 * 12 * 1000
-
-# FIXME: Query on removed portals causes failure for Ingress API call. List removed portals here
-removedPortals = [
-  'b5f1d7ad29ec4ba7a19f4187a5931dce.16'
-]

 getRequestOptions = (method, host, path) ->
   return options =
@@ -54,10 +49,6 @@
     'Cookie': cookie
     'X-XsrfToken': xsrf
     'Content-Type': 'application/json'
-
-  for p in removedPortals
-    continue if portals.indexOf(p) is -1
-    portals.splice portals.indexOf(p), 1

   data =
     params: [portals]


ActivityAppView: Cleared activity counter when clicked to show new activities button on list header.

--- client/landing/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
@@ -17,9 +17,7 @@
     @showNewItemsLink = new KDCustomHTMLView
       cssClass    : "new-updates"
       partial     : "0 new items. Update"
-      click       : =>
-        @updateShowNewItemsLink yes
-        mainController.emit "ShouldResetNavigationTitleLink"
+      click       : => @updateShowNewItemsLink yes

     @headerTitle = new KDCustomHTMLView
       partial     : "Latest Activity"


change test endings

change test endings

--- zechat/static/test_conversation.coffee
+++ zechat/static/test_conversation.coffee
@@ -19,9 +19,8 @@
     .then (app) =>
       identity = JSON.parse(local_storage.getItem('identity'))
       expect(identity.fingerprint.length).toEqual(40)
-    .finally ->
+    .done ->
       test_done()
-    .done()

   it 'should post identity to server', (test_done) ->
     identity_json = JSON.stringify(
@@ -37,9 +36,8 @@
       return zc.waitfor(-> identity.get('public_url'))
     .then (public_url) =>
       expect(public_url).toContain('/id/' + FIX.FINGERPRINT)
-    .finally ->
+    .done ->
       test_done()
-    .done()

   it 'should begin a new conversation', (test_done) ->
     identity_a_json = JSON.stringify(
@@ -83,10 +81,8 @@
       throw(err) if err != 'timeout'
       expect('timed out').toBe(false)

-    .finally ->
+    .done ->
       test_done()
-
-    .done()

   it 'should send a message and receive it back', (test_done) ->
     identity_json = JSON.stringify(
@@ -120,10 +116,8 @@
         return
       throw(err)

-    .finally =>
+    .done =>
       test_done()
-
-    .done()

   it 'should read offline messages', (test_done) ->
     sender_app = new Backbone.Marionette.Application
@@ -169,7 +163,5 @@
         return
       throw(err)

-    .finally =>
+    .done =>
       test_done()
-
-    .done()


more work

more work

--- lib/sails-migrations/schema_migration.coffee
+++ lib/sails-migrations/schema_migration.coffee
@@ -5,7 +5,7 @@
 SailsIntegration = require('./sails_integration')
 _ = require('lodash')

-class SchemaMigration extends Waterline.Collection
+SchemaMigration = Waterline.Collection.extend({
   tableName: TABLE_NAME
   migrate: 'safe'
   autoCreatedAt: false
@@ -17,47 +17,44 @@
       required: true
       index: true
       #null: true TODO: how do we validate this?
+})

-  @getInstance: (adapter, cb)->
-    options = {adapters:{}}
-    options.adapters["adapter"] = adapter
-    SchemaMigration::adapter = "adapter"
-    new SchemaMigration(options, cb)
+SchemaMigration.getInstance = (adapter, cb)->
+  options = {adapters: {}}
+  options.adapters["adapter"] = adapter
+  SchemaMigration::adapter = "adapter"
+  new SchemaMigration(options, cb)

-  @create: (adapter, attributes, cb)->
-    @getInstance(adapter, (err, Model)->
+SchemaMigration.create = (adapter, attributes, cb)->
+  @getInstance(adapter, (err, Model)->
+    return cb(err) if err
+    Model.create(attributes).exec(->
+      console.log("bbbbbbbbbbcccccccccc", arguments)
+      cb()
+    )
+  )
+
+SchemaMigration.define = (adapter, cb)->
+  @getInstance(adapter, (err, Model)->
+    return cb(err) if err
+    Model.define(Model.attributes, cb)
+  )
+
+SchemaMigration.getAllVersions = (adapter, cb)->
+  @getInstance(adapter, (err, Model)=>
+    Model.find().exec((err, models)=>
       return cb(err) if err
-      console.log(Model.create.toString())
-      Model.create(attributes,()->
-        console.log("bbbbbbbbbbcccccccccc", arguments)
-        cb()
-      ).exec(->
-        console.log("bbbbbbbbbbcccccccccc", arguments)
-        cb()
-      )
+      cb(null, _.pluck(models, 'version'))
     )
+  )

-  @define: (adapter, cb)->
-    @getInstance(adapter, (err, Model)->
+SchemaMigration.deleteAllByVersion = (adapter, version, cb)->
+  @getInstance(adapter, (err, Model)=>
+    return cb(err) if err
+    Model.find().where({version: version}).exec((err, models)=>
       return cb(err) if err
-      Model.define(Model.attributes, cb)
+      models[0].destroy(cb)
     )
-
-  @getAllVersions: (adapter, cb)->
-    @getInstance(adapter, (err, Model)=>
-      Model.find().exec( (err, models)=>
-        return cb(err) if err
-        cb(null, _.pluck(models, 'version'))
-      )
-    )
-
-  @deleteAllByVersion: (adapter, version, cb)->
-    @getInstance(adapter, (err, Model)=>
-      return cb(err) if err
-      Model.find().where({version: version}).exec((err, models)=>
-        return cb(err) if err
-        models[0].destroy(cb)
-      )
-    )
+  )

 module.exports = SchemaMigration


New methods

New methods

added .prev() and .next() methods

--- src/quo.element.coffee
+++ src/quo.element.coffee
@@ -43,3 +43,12 @@

     $$.fn.remove = ->
         @each -> @parentNode.removeChild this  if @parentNode?
+
+    $$.fn.next = -> _getSibling.call @, "nextSibling"
+
+    $$.fn.prev = -> _getSibling.call @, "previousSibling"
+
+    _getSibling = (command) ->
+      element = @[0][command]
+      element = element[command] while element and element.nodeType isnt 1
+      $$ element


Fix task poller timeout constant ignored bug

--- SingularityUI/app/views/TaskPoller.coffee
+++ SingularityUI/app/views/TaskPoller.coffee
@@ -11,7 +11,9 @@
 interval = (a, b) -> setInterval(b, a)  # f u javascript
 timeout = (a, b) -> setTimeout(b, a)

-TIMEOUT = 5 * 60 * 1000
+TIMEOUT_MINUTES = 1 # Modify this
+TIMEOUT_SECONDS = TIMEOUT_MINUTES * 60 # Don't modify this (unless you want a timeout less than a minute)
+TIMEOUT_MILLISECONDS = TIMEOUT_SECONDS * 1000 # Don't modify this

 POLLING_TYPES = ['autoTail', 'browse-to-sandbox']

@@ -52,13 +54,13 @@
                 @history.fetch()
                 @activeTasks.fetch()

-        @taskTimeout = timeout 60000, =>
+        @taskTimeout = timeout TIMEOUT_MILLISECONDS, =>
             @stopTaskPolling()
             vex.close()
             vex.dialog.alert
                 message: taskPollingFailureTemplate
                     autoTailFilename: if @pollingType is 'autoTail' then @autoTailFilename else ''
-                    timeout: Math.floor(TIMEOUT / 60000)
+                    timeout: TIMEOUT_MINUTES
                 buttons: [
                     $.extend _.clone(vex.dialog.buttons.YES), text: 'OK'
                 ]


Remove comment

Remove comment

--- example/index.cjsx
+++ example/index.cjsx
@@ -1,10 +1,6 @@
 React = require "react"

 TabFactory = require "../src/factory.cjsx"
-
-# initialize factory
-
-# initialize factory end

 # components
 tabMixin =


MOAR GOB. :v:

MOAR GOB. :v:

--- src/scripts/gob.coffee
+++ src/scripts/gob.coffee
@@ -8,7 +8,26 @@
   "http://bite-prod.s3.amazonaws.com/wp-content/uploads/2012/05/queen_reveal.gif",
   "http://bite-prod.s3.amazonaws.com/wp-content/uploads/2012/05/scotch.gif",
   "http://farm1.static.flickr.com/223/511011836_56ae92ec1a_o.gif",
-  "http://cdn.nextround.net/wp-content/uploads/2010/03/gob-bluth-gif-6.gif"
+  "http://cdn.nextround.net/wp-content/uploads/2010/03/gob-bluth-gif-6.gif",
+  "http://farm1.static.flickr.com/206/510999823_23796e531c_o.gif",
+  "http://farm1.static.flickr.com/209/510999843_8243c5d8c2_o.gif",
+  "http://farm1.static.flickr.com/200/511028609_77e4eb3619_o.gif",
+  "http://farm1.static.flickr.com/224/511001748_881f933034_o.gif",
+  "http://farm1.static.flickr.com/209/511032209_4675bf163e_o.gif",
+  "http://farm1.static.flickr.com/212/511032213_65f7cd9f12_o.gif",
+  "http://25.media.tumblr.com/tumblr_m4rb3j8o9l1qgoi9lo1_500.gif",
+  "http://24.media.tumblr.com/tumblr_m3gd8b0Vm71qbhh43o1_500.gif",
+  "http://25.media.tumblr.com/tumblr_m0y41dR5Rg1qf0kb5o1_r1_400.gif",
+  "http://25.media.tumblr.com/tumblr_m1pl69N19a1qf0kb5o1_400.gif",
+  "http://24.media.tumblr.com/tumblr_lyp0cn0ZVh1r69h01o1_r2_250.gif",
+  "http://25.media.tumblr.com/tumblr_lyiyhyMJbt1qgoi9lo1_500.gif",
+  "http://24.media.tumblr.com/tumblr_lu9m4mCoVB1qk5u7ao1_400.gif",
+  "http://25.media.tumblr.com/tumblr_lpabn5sAXF1qldcnvo1_500.gif",
+  "http://25.media.tumblr.com/tumblr_lpbjdhqbyF1qa7lwzo1_500.gif",
+  "http://25.media.tumblr.com/tumblr_lmq1fewvEi1qb34nxo1_500.gif",
+  "http://media.tumblr.com/tumblr_m5hknk8g841qzblt6.gif",
+  "http://25.media.tumblr.com/tumblr_lljt1gEqIs1qerndjo1_400.gif",
+  "http://24.media.tumblr.com/tumblr_lka9b7SinV1qhivy6o1_500.gif"
 ]

 module.exports = (robot) ->


reverse when no other filters or sorts

reverse when no other filters or sorts

--- SingularityUI/app/views/requests.coffee
+++ SingularityUI/app/views/requests.coffee
@@ -121,6 +121,9 @@

             if not @sortAscending
                 requests = requests.reverse()
+
+        if not @sortAttribute? and not @searchFilter?
+            requests.reverse()

         if @state in ['all', 'active', 'activeDeploy', 'noDeploy']
             for request in requests


Add test for undefined second argument

Add test for undefined second argument

--- test/elvis-test.coffee
+++ test/elvis-test.coffee
@@ -112,6 +112,11 @@
       expect(element.tagName).to.equal('DIV')
       expect(element.innerHTML).to.equal('foo bar')

+    it 'undefined as second argument', ->
+      element = el('div', undefined)
+      expect(element.tagName).to.equal('DIV')
+      expect(element.innerHTML).to.equal('')
+
     it 'element text as array of text', ->
       element = el('div', [ 'foo', ' ', 'bar' ])
       expect(element.tagName).to.equal('DIV')


* update testing

* update testing

--- test/index-test.coffee
+++ test/index-test.coffee
@@ -252,7 +252,7 @@
       expect(fnSync).to.be.calledOnce
       expect(fnSync).to.be.calledOn task
       Task.unregister('/HiFn').should.be.ok
-    it.only 'should define the function with alias simply as a new task', ->
+    it 'should define the function with alias simply as a new task', ->
       fnSync = sinon.spy -> 'hi'
       Task.defineFunction ['HiFnTask', 'hhhh', 'hah'], fnSync
       task = Task 'hhhh'


test(karma): Updated karma preprocessors

--- test/karma.conf.coffee
+++ test/karma.conf.coffee
@@ -79,8 +79,8 @@
     logLevel: config.LOG_INFO
     browsers: ["PhantomJS"]
     preprocessors:
-      "../**/*.coffee": "coffee"
-      "**/*.html": "html2js"
+      "../**/*.coffee": ["coffee"]
+      "**/*.html": ["ng-html2js"]

     plugins: ["karma-*"]


This should have been fixed in a previous commit.

--- test/system/cli.coffee
+++ test/system/cli.coffee
@@ -192,7 +192,7 @@
             expect(stdout).to.match /created: .vile.yml/i
             expect(stdout).to.match /vile-language/i
             expect(stdout).to.match /vile-stat/i
-            expect(stdout).to.match /vile-eslint/i
+            expect(stdout).to.match /vile-escomplex/i
             expect(stdout).to.match /vile-rubocop/i
             expect(stdout).to.match /vile-rubycritic/i
             expect(stdout).to.match /vile-tslint/i


Add webkit hack

Add webkit hack

--- app/assets/javascripts/models/base.coffee
+++ app/assets/javascripts/models/base.coffee
@@ -14,10 +14,18 @@

     data[@snake_name + "s"] = added_attrs

-    path = @route + "/save_all.json"
+    # TODO REMOVE THIS AFTER WEBKIT BUG FIX. https://github.com/thoughtbot/capybara-webkit/issues/553
+    # This conditonal is for testing but there is no easy fix at the moment.
+    # Put passes through data.  Patch dosn't.
+    if (userAgent = window?.navigator?.userAgent).match /capybara-webkit/ || userAgent.match /PhantomJS/
+      path = @route + "/save_all.json"
+      method = 'PUT'
+    else
+      path = @route + "/save_all.json"
+      method = 'PATCH'

     $.ajax
-      type: "PATCH"
+      type: method
       url: App.BaseUrl + "/" + path
       data: data

@@ -124,8 +132,6 @@
       model.assign_attributes(attrs)
       model._clear_errors()
       model._update_data_vals_on_page()
-      # TODO in demo app
-      # model.mark_dirty_or_clean()

   #overridable hook
   @after_save_all_error: (xhr) ->


Corrige el bug del inicio de sesion

Corrige el bug del inicio de sesion

--- app/assets/javascripts/sessions.js.coffee
+++ app/assets/javascripts/sessions.js.coffee
@@ -1,8 +1,8 @@
 Session = (->
   _post = (form) ->
     $.post('/login', form)
-    .done ->
-    	Turbolinks.visit('/home')
+    .done ->
+      Turbolinks.visit('/home')
     .fail ->
       Gutenberg.Alert.info '', 'Combinación de correo electrónico y contraseña incorrecta.'

@@ -10,17 +10,17 @@
 )

 Sessions = (->
-	SELECTOR = "form[action='/users/sign_in']"
-	JQUERY_OBJECT = $ SELECTOR
+  SELECTOR = "#new_user"
+  JQUERY_OBJECT = $ SELECTOR

-	create: ->
-	  JQUERY_OBJECT.on 'submit', (e) ->
-	    e.preventDefault()
-	    Session().post($(@).serializeArray())
+  create: ->
+    JQUERY_OBJECT.on 'submit', (e) ->
+      e.preventDefault()
+      Session().post($(@).serializeArray())
 )

 SessionsRouter = ((pathname) ->
-	# Actions
+  # Actions
   postSession = Sessions().create

   # Routes


Guard against null file

Guard against null file

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -326,7 +326,7 @@
         @reload() unless @isModified()

   # Public: Returns the {String} encoding of this buffer.
-  getEncoding: -> @encoding ? @file.getEncoding()
+  getEncoding: -> @encoding ? @file?.getEncoding()

   # Public: Get the path of the associated file.
   #


Update createCheckpoint callsites to use new API

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -1239,7 +1239,7 @@
   #
   # Returns a checkpoint value.
   createCheckpoint: ->
-    @history.createCheckpoint(@createMarkerSnapshot(), false)
+    @history.createCheckpoint(markerSnapshot: @createMarkerSnapshot(), isBarrier: false)

   # Public: Revert the buffer to the state it was in when the given
   # checkpoint was created.
@@ -1682,7 +1682,7 @@
         (percentDone, patch) =>
           if patch and patch.getChangeCount() > 0
             changeEvent = new CompositeChangeEvent(@buffer, patch)
-            checkpoint = @history.createCheckpoint(@createMarkerSnapshot(), true)
+            checkpoint = @history.createCheckpoint(markerSnapshot: @createMarkerSnapshot(), isBarrier: true)
             @emitter.emit('will-reload')
             @emitter.emit('will-change', changeEvent)
       )
@@ -1719,7 +1719,7 @@
         if patch
           if patch.getChangeCount() > 0
             changeEvent = new CompositeChangeEvent(@buffer, patch)
-            checkpoint = @history.createCheckpoint(@createMarkerSnapshot(), true)
+            checkpoint = @history.createCheckpoint(markerSnapshot: @createMarkerSnapshot(), isBarrier: true)
             @emitter.emit('will-reload')
             @emitter.emit('will-change', changeEvent)
           else if options?.discardChanges


Avoid redundant DisplayLayer resets in TextEditor.update

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -222,6 +222,7 @@
       @backgroundWorkHandle = null

   update: (params) ->
+    currentSoftWrapColumn = @getSoftWrapColumn()
     displayLayerParams = {}

     for param in Object.keys(params)
@@ -272,12 +273,16 @@
         when 'softWrapAtPreferredLineLength'
           if value isnt @softWrapAtPreferredLineLength
             @softWrapAtPreferredLineLength = value
-            displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped()
+            softWrapColumn = @getSoftWrapColumn()
+            if softWrapColumn isnt currentSoftWrapColumn
+              displayLayerParams.softWrapColumn = softWrapColumn

         when 'preferredLineLength'
           if value isnt @preferredLineLength
             @preferredLineLength = value
-            displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped()
+            softWrapColumn = @getSoftWrapColumn()
+            if softWrapColumn isnt currentSoftWrapColumn
+              displayLayerParams.softWrapColumn = softWrapColumn

         when 'mini'
           if value isnt @mini
@@ -322,12 +327,16 @@
         when 'editorWidthInChars'
           if value > 0 and value isnt @editorWidthInChars
             @editorWidthInChars = value
-            displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped()
+            softWrapColumn = @getSoftWrapColumn()
+            if softWrapColumn isnt currentSoftWrapColumn
+              displayLayerParams.softWrapColumn = softWrapColumn

         when 'width'
           if value isnt @width
             @width = value
-            displayLayerParams.softWrapColumn = @getSoftWrapColumn() if @isSoftWrapped()
+            softWrapColumn = @getSoftWrapColumn()
+            if softWrapColumn isnt currentSoftWrapColumn
+              displayLayerParams.softWrapColumn = softWrapColumn

         when 'scrollPastEnd'
           if value isnt @scrollPastEnd


Only create EditorComponent once per editor

--- src/text-editor.coffee
+++ src/text-editor.coffee
@@ -3547,9 +3547,12 @@

   # Get the Element for the editor.
   getElement: ->
-    TextEditorComponent ?= require('./text-editor-component')
-    new TextEditorComponent({model: this})
-    @component.element
+    if @component?
+      @component.element
+    else
+      TextEditorComponent ?= require('./text-editor-component')
+      new TextEditorComponent({model: this})
+      @component.element

   # Essential: Retrieves the greyed out placeholder of a mini editor.
   #


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_effect.coffee
+++ src/text_effect.coffee
@@ -1,29 +1,47 @@
 TextEffect = (I={}) ->
   Object.reverseMerge I,
+    color: Color('green')
     duration: 40
-    font: 'VT323'
-    points: 500
+    font: '20px Helvetica'
+    text: '100'
+    textShadow: Color('black')
     alpha: 1
-
+    rotation: 0
+    rotationalVelocity: 0
+    velocity: Point(0, -1)
+
   self = GameObject(I)

-  self.bind "update", ->
-    I.y -= 1
+  self.bind "update", ->
+    I.rotation += I.rotationalVelocity
+
+    I.x += I.velocity.x
+    I.y += I.velocity.y
+
     I.alpha = 1 - (I.age / I.duration)

   self.unbind "draw"
-  self.bind "afterTransform", (canvas) ->
-    canvas.font "20px #{I.font}"
+  self.bind "draw", (canvas) ->
+    unless I.color.channels
+      I.color = Color(I.color)
+
+    unless I.textShadow.channels
+      I.textShadow = Color(I.textShadow)
+
+    I.color.a = I.alpha
+    I.textShadow.a = I.alpha
+
+    canvas.font I.font
     canvas.drawText
-      color: "rgba(0, 0, 0, #{I.alpha})"
-      x: I.x + 1
-      y: I.y + 1
-      text: I.points
+      color: I.textShadow
+      x: 1
+      y: 1
+      text: I.text

     canvas.drawText
-      color: "rgba(255, 255, 255, #{I.alpha})"
-      x: I.x
-      y: I.y
-      text: I.points
+      color: I.color
+      x: 0
+      y: 0
+      text: I.text

   return self


Replace add icon png with icon font

Replace add icon png with icon font

--- app/js/jail_iframe/classes/buttons.coffee
+++ app/js/jail_iframe/classes/buttons.coffee
@@ -122,11 +122,11 @@
   content: """

-
+

-
-        AgreeUnsureDisagree
+
+

Loading...


Individual data now updates with change of rep in input bar

--- app/scripts/controllers/individual.coffee
+++ app/scripts/controllers/individual.coffee
@@ -18,6 +18,14 @@
 ######################
 # Define API Methods
 ######################
+    $scope.$watch "selected.rep1", (newVal, oldVal)->
+      $scope.selected_watcher_functions('rep1', newVal.bioguide_id)
+
+    $scope.selected_watcher_functions = (rep, bioguide_id)->
+      $scope.get_transparencydata_id($scope.selected.rep1.bioguide_id)
+      ApiGet.littleSis "entities/bioguide_id/#{$scope.selected.rep1.bioguide_id}.json?", $scope.callback_littleSis_id, this, $scope.selected.rep1.bioguide_id
+      ApiGet.nyt "members/#{$scope.selected.rep1.bioguide_id}", $scope.callback_nyt, this, $scope.selected.rep1.bioguide_id
+

     $scope.get_transparencydata_id = (bioguide_id)->
       $scope.reps[bioguide_id] = $scope.reps[bioguide_id] or {}
@@ -88,8 +96,5 @@
 ## Initial Calls
 ##############

-    $scope.get_transparencydata_id($scope.selected.rep1.bioguide_id)
-    ApiGet.littleSis "entities/bioguide_id/#{$scope.selected.rep1.bioguide_id}.json?", $scope.callback_littleSis_id, this, $scope.selected.rep1.bioguide_id
-    ApiGet.nyt "members/#{$scope.selected.rep1.bioguide_id}", $scope.callback_nyt, this, $scope.selected.rep1.bioguide_id

   ])


Make DuelStatsView slightly less likely to break

--- app/views/play/level/DuelStatsView.coffee
+++ app/views/play/level/DuelStatsView.coffee
@@ -56,6 +56,7 @@
     @avatars ?= {}
     return if @avatars[team]
     thang = _.find @options.thangs, id: heroID
+    return unless thang
     @avatars[team] = avatar = new ThangAvatarView thang: thang, includeName: false, supermodel: @supermodel
     @$find(team, '.thang-avatar-placeholder').replaceWith avatar.$el
     avatar.render()
@@ -68,8 +69,8 @@

   update: ->
     for player in @players
-      thang = _.find @options.thangs, id: @avatars[player.team].thang.id
-      @updateHealth thang
+      if thang = (_.find @options.thangs, id: @avatars?[player.team]?.thang?.id)
+        @updateHealth thang
     @updatePower() if @showsPower

   updateHealth: (thang) ->
@@ -94,7 +95,8 @@
     powers = humans: 0, ogres: 0
     setPowerTeams = []
     for player in @players
-      hero = _.find @options.thangs, id: @avatars[player.team].thang.id
+      hero = _.find @options.thangs, id: @avatars?[player.team]?.thang?.id
+      continue unless hero
       if hero.teamPower? and powers[hero.team]?
         powers[hero.team] = hero.teamPower
         setPowerTeams.push hero.team


More notifications

More notifications

--- bin/recipes/config.workshop.template.cson
+++ bin/recipes/config.workshop.template.cson
@@ -1,4 +1,7 @@
 version: "0.1.9"
+notifications:
+  email: {}
+  slack: {}
 liquibase:
   working_directory: ""
   notifications:


Fix query in case the table is not found

--- admin/static/coffee/tables/table.coffee
+++ admin/static/coffee/tables/table.coffee
@@ -50,7 +50,7 @@
                                     ).map (name) ->
                                         id: r.db(system_db).table('server_config').filter({name: name}).nth(0)("uuid")
                                         name: name
-
+                                id: table("uuid")
                             ).do( (table) ->
                                 r.branch( # We must be sure that the table is ready before retrieving the indexes
                                     table("num_available_shards").eq(table("num_shards")), #TODO Is that a sufficient condition?
@@ -65,11 +65,10 @@
                                     }),
                                     table.merge({indexes: null})
                                 )
-                            )
+                            ).without('shards')
                         )
                     )
-                ).without('shards').merge
-                    id: r.row 'uuid'
+                )

             @timer = driver.run query, 5000, (error, result) =>
                 ###
@@ -188,7 +187,7 @@
             @
         remove: =>
             driver.stop_timer @timer
-            @table_view.remove()
+            @table_view?.remove()
             super()

     class @TableMainView extends Backbone.View


Kibosh the log

Kibosh the log

--- app/assets/javascripts/events.js.coffee
+++ app/assets/javascripts/events.js.coffee
@@ -52,7 +52,6 @@
   things = {}

   $('#filters .btn-group').each((index, group)->
-    console.log($(group).find('.btn-primary').data('value'));
     things[$(group).data('flag')] = $(group).find('.btn-primary').data('value')
     true
   )


Calculate coordinates of relationship endpoints

--- app/assets/javascripts/graphs.js.coffee
+++ app/assets/javascripts/graphs.js.coffee
@@ -54,11 +54,20 @@
   $('.entity').on 'dialogdrag', (event, ui) ->
     drawRelationshipsFromEntity(event.currentTarget)

-entityCoordinates = (entity_id) ->
+entityCoordinates = (entity_id, xloc, yloc) ->
   e = $('#entity' + entity_id).parent()
-  x = e.offset().left + e.width() / 2
-  y = e.offset().top  + e.height() / 2
+  x = Math.round(e.offset().left + e.width() * xloc)
+  y = Math.round(e.offset().top  + e.height() * yloc)
   return {x:x, y:y}
+
+entityCoordinate = (entity_id, side) ->
+  e = $('#entity' + entity_id).parent()
+  switch side
+    when "left"   then coord = e.offset().left
+    when "right"  then coord = e.offset().left + e.width()
+    when "top"    then coord = e.offset().top
+    when "bottom" then coord = e.offset().top + e.height()
+  return Math.round(coord)

 drawRelationshipsFromEntity = (entity_tag) ->
   relationship_starts = JSON.parse(entity_tag.dataset.relationship_starts)
@@ -75,9 +84,50 @@
     drawRelationshipsFromEntity(e)

 drawRelationship = (relationship, entity1, entity2) ->
-  coord1 = entityCoordinates(entity1)
-  coord2 = entityCoordinates(entity2)
-  $('#relationship' + relationship).attr('d', "M #{coord1.x} #{coord1.y} L #{coord2.x} #{coord2.y}")
+  p1 = {}
+  p2 = {}
+
+  center1 = entityCoordinates(entity1, 0.5, 0.5)
+  center2 = entityCoordinates(entity2, 0.5, 0.5)
+
+  SYMBOL_SIZE = 40
+
+  if vertical(center1, center2)
+    if center1.y < center2.y
+      p1.side = "bottom"
+      p2.side = "top"
+    else
+      p1.side = "top"
+      p2.side = "bottom"
+
+    p1.y = entityCoordinate(entity1, p1.side)
+    p2.y = entityCoordinate(entity2, p2.side)
+
+    p1.x = interpolate(center1.y, center1.x, center2.y, center2.x, p1.y)
+    p2.x = interpolate(center1.y, center1.x, center2.y, center2.x, p2.y)
+
+  else #if horizontal
+    if center1.x < center2.x
+      p1.side = "right"
+      p2.side = "left"
+    else
+      p1.side = "left"
+      p2.side = "right"
+
+    p1.x = entityCoordinate(entity1, p1.side)
+    p2.x = entityCoordinate(entity2, p2.side)
+
+    p1.y = interpolate(center1.x, center1.y, center2.x, center2.y, p1.x)
+    p2.y = interpolate(center1.x, center1.y, center2.x, center2.y, p2.x)
+
+  $('#relationship' + relationship).attr('d', "M #{p1.x} #{p1.y} L #{p2.x} #{p2.y}")
+
+vertical = (coord1, coord2) ->
+  return Math.abs(coord1.y - coord2.y) > Math.abs(coord1.x - coord2.x)
+
+# Calculate y3 to pair with given x3 and to make (x3,y3) fall on the line from (x1,y1) to (x2,y2)
+interpolate = (x1,y1,x2,y2,x3) ->
+  return Math.round((x3-x1)/(x2-x1)*(y2-y1)+y1)

 $(document).ready ->
   makeEntitiesDraggable()


Remove div and tag view tools from toolbar

[Finishes #60559628]

--- app/assets/javascripts/papers.js.coffee
+++ app/assets/javascripts/papers.js.coffee
@@ -30,10 +30,10 @@
         toolbar: [
           [ 'Styles', 'Format', 'FontSize' ]
           [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ]
-          [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote', 'CreateDiv', 'Table']
+          [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote', 'Table' ]
           [ 'PasteFromWord' ],
-          [ 'Link', 'Unlink', 'Anchor']
-          [ 'Find', 'Replace', '-', 'Scayt', '-', 'ShowBlocks' ]
+          [ 'Link', 'Unlink', 'Anchor' ]
+          [ 'Find', 'Replace', '-', 'Scayt' ]
         ]

   $('#save_button').on 'click', (e) ->


Fixed wrong percentage calculation on taskboard.

Now user stories without tasks not counting as completed user stories.

--- app/coffee/controllers/taskboard.coffee
+++ app/coffee/controllers/taskboard.coffee
@@ -75,7 +75,9 @@
             hasTasks = false

             for statusId, tasks of statuses
-                hasTasks = true
+                if tasks.length > 0
+                    hasTasks = true
+
                 if $scope.constants.taskStatuses[statusId].is_closed
                     completedTasks += tasks.length
                 else if tasks.length > 0


don’t load common.coffee’s dependencies in a chunk

closes: CNVS-35721

when I converted some of those other bundles to not use AMD requires,
it introudced some race conditions where the dependecies they needed,
which were dependecies from common.coffe were not loaded yet because
this was loading in a seperate chunk

test plan:
everything for the common bundle should be in
one file. it shouldn’t load a separate chunk for
it’s dependencies. look in the network panel

Change-Id: Id6e1caeca8c39ac2f96ce9b0e9a98defda54087d
Reviewed-on: https://gerrit.instructure.com/105511
Tested-by: Jenkins
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
Product-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>
QA-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>

--- app/coffeescripts/bundles/common.coffee
+++ app/coffeescripts/bundles/common.coffee
@@ -1,4 +1,4 @@
-require [
+define [
   # true modules that we use in this file
   'jquery'
   'underscore'


synchronous option for coffeescript, both can run in a fiber because it's not much overhead if not used

--- packages/tower-command/server/console.coffee
+++ packages/tower-command/server/console.coffee
@@ -52,8 +52,8 @@

     client  = repl.context

-    client.reload = ->
-      Tower.ModelCursor.include Tower.ModelCursorSync
+    client.reload = =>
+      Tower.ModelCursor.include Tower.ModelCursorSync if @program.synchronous
       app = Tower.Application.instance()
       app.initialize()
       app.stack()
@@ -92,6 +92,7 @@
     process.nextTick client.reload

   runCoffee: ->
+    Tower.ModelCursor.include Tower.ModelCursorSync if @program.synchronous
     app = Tower.Application.instance()
     app.initialize()
     app.stack()
@@ -145,17 +146,19 @@
         return
       repl.setPrompt REPL_PROMPT
       backlog = ''
-      try
-        $_ = global.$_
-        returnValue = CoffeeScript.eval "$_=(#{code}\n)", {
-          filename: 'repl'
-          modulename: 'repl'
-        }
-        if returnValue is undefined
-          global.$_ = $_
-        process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
-      catch err
-        error err
+      Fiber(->
+        try
+          $_ = global.$_
+          returnValue = CoffeeScript.eval "$_=(#{code}\n)", {
+            filename: 'repl'
+            modulename: 'repl'
+          }
+          if returnValue is undefined
+            global.$_ = $_
+          process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
+        catch err
+          error err
+      ).run()
       repl.prompt()

     ## Autocompletion


config gulp

config gulp

--- gulp/config.coffee
+++ gulp/config.coffee
@@ -20,7 +20,7 @@

         AVAILABLE_PLATFORMS: ["ios", "android"]

-        API_URL: 'http://localhost:3000/'
+        API_URL: 'http://localhost:3000/api/v1'

         # The name of your angular app you're going to use in `angular.module("")`
         ANGULAR_APP_NAME: "ionicstarter"
@@ -141,6 +141,7 @@
     # The filtered globals will be available under GulpConfig.PUBLIC_GLOBALS.
     @_PUBLIC_GLOBALS_KEYS = [
       "ANGULAR_APP_NAME"
+      "API_URL"
       "BUNDLE_NAME"
       "BUNDLE_VERSION"
       "CODE_VERSION"


fix errors with save dialog

fix errors with save dialog

--- client/app/lib/util/showSaveDialog.coffee
+++ client/app/lib/util/showSaveDialog.coffee
@@ -4,12 +4,13 @@
 KDInputView = kd.InputView
 KDLabelView = kd.LabelView
 KDView = kd.View
+IDEFinderItem = require '../../../ide/lib/finder/idefinderitem'

 module.exports = (container, callback = kd.noop, options = {}) ->

   container.addSubView dialog = new KDDialogView
-    cssClass      : kd.curry "save-as-dialog", options.cssClass
+    cssClass      : kd.utils.curry "save-as-dialog", options.cssClass
     overlay       : yes
     container     : container
     height        : "auto"
@@ -46,7 +47,7 @@

   finderController = kd.singletons['appManager'].get('Finder').create
     addAppTitle       : no
-    treeItemClass     : IDE.FinderItem
+    treeItemClass     : IDEFinderItem
     nodeIdPath        : 'path'
     nodeParentIdPath  : 'parentPath'
     foldersOnly       : yes


CoffeeScript formatting

CoffeeScript formatting

--- public/scripts/backbone-schedule/main.coffee
+++ public/scripts/backbone-schedule/main.coffee
@@ -44,11 +44,11 @@

 require(
   [
-    'app',
-    'jQuery',
-    'Underscore',
-    'Backbone',
-    'jQueryUI',
+    'app'
+    'jQuery'
+    'Underscore'
+    'Backbone'
+    'jQueryUI'
     'jQueryCookie'
     'Bootstrap'
   ], (Shark, $) ->


Hide/Restore screens on logout/login

Hide/Restore screens on logout/login

--- client/lanes/screens/Definitions.coffee
+++ client/lanes/screens/Definitions.coffee
@@ -105,6 +105,12 @@
         @findWhere( active: true )

     initialize: (models, options = {}) ->
+        Lanes.current_user.on "change:isLoggedIn", (user) =>
+            if user.isLoggedIn
+                for screen_id in Lanes.current_user.options?.initial_screens || []
+                    Lanes.Screens.Definitions.all.get(screen_id)?.display()
+            else
+                @reset()
         this.on( 'change:active add', this.onActiveChange )

     remove: (model) ->


adds for_sale to whitelist

adds for_sale to whitelist

--- components/artwork_filter/booleans.coffee
+++ components/artwork_filter/booleans.coffee
@@ -1,3 +1,4 @@
 module.exports = [
   'price_range'
+  'for_sale'
 ]


[grunt] use more logical name for Nunjucks paths option

--- tasks/templates.coffee
+++ tasks/templates.coffee
@@ -18,23 +18,23 @@
   # ======

   options =
-    autoescape          : false
-    data                : grunt.config('data')
-    nunjucksEnv         : grunt.config('path.source.templates')
+    autoescape         : false
+    data               : grunt.config('data')
+    paths              : grunt.config('path.source.templates')
     files:
-      cwd               : grunt.config('path.source.templates')
-      src               : ['{,**/}*.{nj,html}', '!{,**/}_*.{nj,html}']
-      dest              : grunt.config('path.build.templates')
-      ext               : '.html'
-      matter            : grunt.config('file.temp.data.matter')
+      cwd              : grunt.config('path.source.templates')
+      src              : ['{,**/}*.{nj,html}', '!{,**/}_*.{nj,html}']
+      dest             : grunt.config('path.build.templates')
+      ext              : '.html'
+      matter           : grunt.config('file.temp.data.matter')
     humanReadableUrls:
-      enabled           : true
-      exclude           : /^(index|\d{3})$/
+      enabled          : true
+      exclude          : /^(index|\d{3})$/
     i18n:
-      locales           : grunt.config('i18n.locales')
-      baseLocale        : grunt.config('i18n.baseLocale')
-      baseLocaleAsRoot  : true
-      gettext           : grunt.config('i18n.gettext')
+      locales          : grunt.config('i18n.locales')
+      baseLocale       : grunt.config('i18n.baseLocale')
+      baseLocaleAsRoot : true
+      gettext          : grunt.config('i18n.gettext')

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

@@ -54,7 +54,7 @@
     @config "nunjucks.#{currentLocale}",

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


Modified controller template to use coffeescript classes

--- controller/templates/_controller.coffee
+++ controller/templates/_controller.coffee
@@ -8,9 +8,20 @@
  # @description
  #
 ###
+<% if (coffeeClasses) { %>
+class <% ctrlName %>
+ constructor: <% if (!controllerAs) { %>(@$scope) <% } %>->
+   @ctrlName = '<%= ctrlName %>'<% } else { %>$scope.<%= lowerCamel %> = {}
+   $scope.<%= lowerCamel %>.ctrlName = '<%= ctrlName %>'<% } %>
+
+angular
+  .module('<% if (parentModuleName) { %><%= parentModuleName %>.<% } %><%= moduleName %>')
+  .controller '<%= ctrlName %>', [<% if (!controllerAs) { %>'$scope'<% } %>, <%= ctrlName %>]
+<% } else { %>
 angular
   .module '<% if (parentModuleName) { %><%= parentModuleName %>.<% } %><%= moduleName %>'
   .controller '<%= ctrlName %>', <% if (!controllerAs) { %>($scope) <% } %>->
     <% if (controllerAs) { %>vm = @
     vm.ctrlName = '<%= ctrlName %>'<% } else { %>$scope.<%= lowerCamel %> = {}
     $scope.<%= lowerCamel %>.ctrlName = '<%= ctrlName %>'<% } %>
+<% } %>


stop printing 'click'

stop printing 'click'

--- resources/assets/lib/play-detail-menu.coffee
+++ resources/assets/lib/play-detail-menu.coffee
@@ -24,7 +24,6 @@
   # TODO: extract for sharing with other components
   refs = {}
   document.addEventListener 'click', (event) ->
-    console.log 'click'
     for own _uuid, ref of refs
       ref event


fixed bug where time changes were taking effect 1 day late

--- js/schedule.coffee
+++ js/schedule.coffee
@@ -20,9 +20,8 @@
     $(".#{day} .selihot").addClass('hidden').html('')
     $(".#{day} .placeholder").addClass('hidden')
     $(".#{day} .date").html(day_iterator.format("D MMM"))
-    date = day_iterator.toDate()
-    zmanim = SunCalc.getTimes(date, window.config.latitude, window.config.longitude)
-    hebrew_date = new HebrewDate(date)
+    hebrew_date = new HebrewDate(day_iterator.toDate())
+    zmanim = SunCalc.getTimes(moment(day_iterator).toDate().setHours(12), window.config.latitude, window.config.longitude)
     show_event(day, event, hebrew_date) for event in events
     if hebrew_date.isYomKippur() || hebrew_date.isRoshHashana()
       shaharit_is_fixed_at(day, 7, 0)


Update test

Update test

--- desktop/apps/fair/test/templates.coffee
+++ desktop/apps/fair/test/templates.coffee
@@ -27,6 +27,7 @@
     APP_URL: 'http://localhost:5000'
     API_URL: 'http://localhost:5000'
     MOBILE_URL: 'http://localhost:5000'
+    WEBFONT_URL: 'http://webfonts.artsy.net/'
     NODE_ENV: 'test'
   jade.compile(
     fs.readFileSync(filename),
@@ -46,6 +47,7 @@
         PROFILE: fabricate 'fair_profile'
         FAIR: fabricate 'fair', filter_genes: []
         FACEBOOK_APP_NAMESPACE: 'namespace'
+        WEBFONT_URL: 'http://webfonts.artsy.net/'
       fair = new Fair (sd.FAIR)
       profile = new Profile (sd.PROFILE)
       template = render('index')


write: dont follow link

write: dont follow link

--- test/core/write.coffee
+++ test/core/write.coffee
@@ -130,6 +130,30 @@
           return next err if err
           content.should.eql 'hello'
           next()
+
+  describe 'link', ->
+
+    they 'dont follow link by default', (ssh, next) ->
+      mecano
+        ssh: ssh
+      .write
+        content: 'ko'
+        destination: "#{scratch}/target"
+      .link
+        source: "#{scratch}/link"
+        destination: "#{scratch}/target"
+      .write
+        content: 'ok'
+        destination: "#{scratch}/link"
+      .call (_, callback) ->
+        fs.readFile ssh, "#{scratch}/link", 'ascii', (err, data) ->
+          data.should.eql 'ok'
+          fs.readFile ssh, "#{scratch}/target", 'ascii', (err, data) ->
+            data.should.eql 'ko'
+            callback()
+      .then next
+
+

   describe 'ownerships and permissions', ->


add random values in test of created documents

--- test/data_tests.coffee
+++ test/data_tests.coffee
@@ -20,6 +20,11 @@

 parseBody = (response, body) ->
     if typeof body is "object" then body else JSON.parse body
+
+randomString = (length=32) ->
+    string = ""
+    string += Math.random().toString(36).substr(2) while string.length < length
+    string.substr 0, length

 # Clear DB, create a new one, then init data for tests.
 before (done) ->
@@ -112,9 +117,12 @@

     describe "Create a new Document with a given id", ->
         before cleanRequest
+        after ->
+            delete @randomValue

         it "When I send a request to create a document with id 987", (done) ->
-            client.post 'data/987/', {"value":"created value"}, \
+            @randomValue = randomString()
+            client.post 'data/987/', {"value":@randomValue}, \
                         (error, response, body) =>
                 response.statusCode.should.equal 201
                 @body = parseBody response, body
@@ -123,11 +131,27 @@
         it "Then { _id: '987' } should be returned", ->
             @body.should.have.property '_id', '987'

+        it "Then the Document with id 987 should exist in Database", (done) ->
+            client.get "data/exist/987/", (error, response, body) =>
+                @body = parseBody response, body
+                @body.exist.should.be.true
+                done()
+
+        it "Then the Document in DB should equal the sent Document", (done) ->
+            client.get "data/987/", (error, response, body) =>
+                @body = parseBody response, body
+                @body.should.have.property 'value', @randomValue
+                done()
+
     describe "Create a new Document without an id", ->
         before cleanRequest
+        after ->
+            delete @randomValue
+            delete @_id

         it "When I send a request to create a document without an id", (done) ->
-            client.post 'data/', {"value":"created value"}, \
+            @randomValue = randomString()
+            client.post 'data/', {"value":@randomValue}, \
                         (error, response, body) =>
                 response.statusCode.should.equal(201)
                 @body = parseBody response, body
@@ -135,4 +159,16 @@

         it "Then the id of the new document should be returned", ->
             @body.should.have.property '_id'
+            @_id = @body._id

+        it "Then the Document should exist in Database", (done) ->
+            client.get "data/exist/" + @_id + "/", (error, response, body) =>
+                @body = parseBody response, body
+                @body.exist.should.be.true
+                done()
+
+        it "Then the Document in DB should equal the sent Document", (done) ->
+            client.get "data/" + @_id + "/", (error, response, body) =>
+                @body = parseBody response, body
+                @body.should.have.property 'value', @randomValue
+                done()


quick typo fixes

quick typo fixes

--- source/javascripts/data/WizardContent.coffee
+++ source/javascripts/data/WizardContent.coffee
@@ -77,6 +77,11 @@

Copyedit an article. Browse Wikipedia until you find an article that you would like to improve, and make some edits to improve the language or formatting.

Illustrate an article. Find an opportunity to improve an article by creating and uploading an original photograph or video.

'
+        ]
+      }
+      {
+        content: [
+          '
For most courses, the Critique an article and Add to an article exercises provide a nice foundation for the main writing project. These have been selected by default.
'
         ]
       }
     ]
@@ -145,7 +150,7 @@
     title: 'Research and planning'
     formTitle: 'How should students plan their articles?'
     infoTitle: 'About research and planning'
-    instructions:  "Students often wait until the last minute to do their research, or choose sources unsuited for Wikipedia. That's why we recommend asking students to put together a bibliography of materials they want to use in editing the article, which can then be assessed by you and other Wikipedians."
+    instructions:  "Students often wait until the last minute to do their research, or choose sources unsuitable for Wikipedia. That's why we recommend asking students to put together a bibliography of materials they want to use in editing the article, which can then be assessed by you and other Wikipedians."
     sections: [
       {
         title: ''


加入include module时不会merge特殊成员和会实现module的interface测试

--- test/moduleSpec.coffee
+++ test/moduleSpec.coffee
@@ -6,7 +6,7 @@
     M = require("../may.js")

     describe '$module(obj)', ->
-        it "should return given object self", ->
+        it "should return given object itself", ->
             obj = {}
             M.$module(obj).should.eql obj

@@ -22,7 +22,7 @@

             o.should.have.property(member, m[member]) for member of m

-        it "should merge methodized method to obj when option.methodize be true", ->
+        it "should merge methodized method to obj if option.methodize set be true", ->
             sayHello =  (man) ->
                     "hello " + man.name
             m =
@@ -37,7 +37,7 @@
             #check methodized
             o.sayHello().should.eql sayHello(o)

-        it "should call the onincluded with obj when included if the module own it", ->
+        it "should call the onIncluded() after included", ->
             spy = sinon.spy()

             m =
@@ -49,7 +49,7 @@
             assert spy.calledOn o
             assert spy.calledWith o

-        it "should call the delegate onincluded with given option.context when included if the module own it", ->
+        it "should call the onIncluded() on passing binding context after included", ->
             spy = sinon.spy()

             m =
@@ -65,4 +65,33 @@
             assert spy.calledOn o
             assert spy.calledWith a

+        it "should not merge specific member, such as init method, meta member which name starts with __, onIncluded callback", ->
+            m =
+                onIncluded: ->
+                __interface__: []
+                init: ->
+                member1: {}

+            o = {}
+            M.$include(o, m)
+
+            o.should.not.have.property(member) for member in ["onIncluded", "__interface__", "init"]
+            o.should.have.property("member1")
+
+        it "should implementation all of interfaces from module", ->
+            interfaces = [{}, {}]
+
+            m =
+                __interfaces__: interfaces
+
+            o = {}
+
+            M.$include(o, m)
+
+            o.should.have.property("__interfaces__")
+            o.__interfaces__.should.contain inter for inter in interfaces
+
+
+
+
+


Feedback item tests

Feedback item tests

--- test/nodes/file.coffee
+++ test/nodes/file.coffee
@@ -285,3 +285,33 @@
           expect(resp).to.eql(@previewUrls)
           done()

+  describe 'feedback items', ->
+    beforeEach ->
+      nock(@config.apiBase)
+        .get("#{@config.apiPath}#{@file.nodePath}/feedback_items")
+        .reply(200, require('../fixtures/file/feedback_items'))
+
+    it 'does not error', (done) ->
+      @file.feedbackItems (err, resp) ->
+        expect(err).to.be(null)
+        done()
+
+    it 'returns an array response', (done) ->
+      @file.feedbackItems (err, resp) ->
+        expect(resp).to.be.an('array')
+        expect(resp.length).to.be(1)
+        expect(resp[0].id).to.be(1)
+        done()
+
+    it 'is aliased to #feedback', (done) ->
+      @file.feedback (err, resp) ->
+        expect(err).to.be(null)
+        expect(resp).to.be.an('array')
+        done()
+
+    describe 'with a promise', ->
+      it 'resolves', (done) ->
+        @file.feedbackItems().then (resp) ->
+          expect(resp).to.be.an('array')
+          expect(resp.length).to.be(1)
+          done()


Oscillator

Oscillator

--- test/oscillator.coffee
+++ test/oscillator.coffee
@@ -1,6 +1,17 @@
 module "Oscillator"

-test "various "
+test "various values", ->
+  one = 1
+
+  # Test for equality of two objects
+  equals one, 1
+
+test "testing boolean values", ->
+  someFunction = ->
+    return true
+
+  # Test if someFunction returns true
+  ok someFunction()

 # Clear out the module
 module()


new feature lookupLocal: raw context-object lookup

--- lib/Context.coffee
+++ lib/Context.coffee
@@ -31,7 +31,7 @@

             @_status = []

-            @_hiddenKeys.push 'data', 'parent', 'children', 'permissions', 'lookup', 'configure', 'init', 'boot', 'booting', 'booted', 'start', 'started', 'running', 'suspend', 'suspended', 'resume', 'resumed', 'shutdown', 'stop', 'stopped', 'error', 'delegate'
+            @_hiddenKeys.push 'data', 'parent', 'children', 'permissions', 'lookup', 'lookupLocal', 'configure', 'init', 'boot', 'booting', 'booted', 'start', 'started', 'running', 'suspend', 'suspended', 'resume', 'resumed', 'shutdown', 'stop', 'stopped', 'error', 'delegate'

         ##
@@ -506,6 +506,28 @@
             @logger.fine 'lookup(%s) failed for %s', name, identity.id
             done new Error 'Context not found: '+name

+        ##
+        ##
+        ##
+        lookupLocal: (name, fn)->
+            ## myself
+            if name is @id
+                return fn null, @
+
+            ## children
+            if (base = name.split('.').shift()) is @id
+                base = (name = name.substr base.length + 1).split('.').shift()
+
+            for child in @children
+                if child.id is base
+                    return child.lookupLocal name, fn
+
+            ## parent
+            if @parent?.lookup
+                return @parent.lookupLocal name, fn
+
+            ##
+            fn new Error 'Context not found: '+name

         ##
         ## delegates a method call down the hirarchy


more tests

more tests

--- test/phabs_test.coffee
+++ test/phabs_test.coffee
@@ -223,6 +223,38 @@

     context 'when the task is present', ->

+      context 'phab open', ->
+        beforeEach ->
+          do nock.disableNetConnect
+          nock(process.env.PHABRICATOR_URL)
+          .get('/api/maniphest.info')
+          .reply(200, { result: {
+            status: 'open',
+            priority: 'Low',
+            name: 'Test task',
+            ownerPHID: 'PHID-USER-42'
+            } })
+          .get('/api/user.query')
+          .reply(200, { result: [{ userName: 'toto' }]})
+          .get('/api/maniphest.update')
+          .reply(200, { result: { statusName: 'Open' } })
+
+        afterEach ->
+          nock.cleanAll()
+
+        context 'phab is open', ->
+          hubot 'phab T42', 'user_with_phid'
+          hubot 'phab is open', 'user_with_phid'
+          it 'reports the status as open', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'
+
+        context 'phab open', ->
+          hubot 'phab T42', 'user_with_phid'
+          hubot 'phab open', 'user_with_phid'
+          it 'reports the status as open', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'
+
+
       context 'phab T42 is open', ->
         beforeEach ->
           do nock.disableNetConnect
@@ -233,9 +265,15 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 is open'
-        it 'reports the status as open', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'
+        context 'phab open', ->
+          hubot 'phab open'
+          it 'warns the user that there is no active task in memory', ->
+            expect(hubotResponse()).to.eql "Sorry, you don't have any task active right now."
+
+        context 'phab T42 is open', ->
+          hubot 'phab T42 is open'
+          it 'reports the status as open', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'

       context 'phab T42 open', ->
         beforeEach ->
@@ -247,9 +285,10 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 open'
-        it 'reports the status as open', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'
+        context 'phab T42 open', ->
+          hubot 'phab T42 open'
+          it 'reports the status as open', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Open.'

       context 'phab T42 resolved', ->
         beforeEach ->
@@ -261,9 +300,10 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 resolved'
-        it 'reports the status as resolved', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Resolved.'
+        context 'phab T42 resolved', ->
+          hubot 'phab T42 resolved'
+          it 'reports the status as resolved', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Resolved.'

       context 'phab T42 wontfix', ->
         beforeEach ->
@@ -275,9 +315,10 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 wontfix'
-        it 'reports the status as wontfix', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Wontfix.'
+        context 'phab T42 wontfix', ->
+          hubot 'phab T42 wontfix'
+          it 'reports the status as wontfix', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Wontfix.'

       context 'phab T42 invalid', ->
         beforeEach ->
@@ -289,9 +330,10 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 invalid'
-        it 'reports the status as invalid', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Invalid.'
+        context 'phab T42 invalid', ->
+          hubot 'phab T42 invalid'
+          it 'reports the status as invalid', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Invalid.'

       context 'phab T42 spite', ->
         beforeEach ->
@@ -303,11 +345,12 @@
         afterEach ->
           nock.cleanAll()

-        hubot 'phab T42 spite'
-        it 'reports the status as spite', ->
-          expect(hubotResponse()).to.eql 'Ok, T42 now has status Spite.'
-
-  context 'user changes status for a task', ->
+        context 'phab T42 spite', ->
+          hubot 'phab T42 spite'
+          it 'reports the status as spite', ->
+            expect(hubotResponse()).to.eql 'Ok, T42 now has status Spite.'
+
+  context 'user changes priority for a task', ->
     context 'when the task is unknown', ->
       beforeEach ->
         do nock.disableNetConnect
@@ -334,6 +377,11 @@

         afterEach ->
           nock.cleanAll()
+
+        context 'phab broken', ->
+          hubot 'phab broken'
+          it 'warns the user that there is no active task in memory', ->
+            expect(hubotResponse()).to.eql "Sorry, you don't have any task active right now."

         context 'phab T42 is broken', ->
           hubot 'phab T42 is broken'