Fix heli chain

Fix heli chain

--- src/lazerscripts/stage1/heli_attack.coffee
+++ src/lazerscripts/stage1/heli_attack.coffee
@@ -61,7 +61,7 @@
       y: .6 * Crafty.viewport.height
       defaultSpeed: options.speed ? 40
       weaponOrigin: [0, 25]
-      chainable: !!options.deathDecoy
+      chainable: !options.deathDecoy
     ).helicopter(
       pointsOnHit: 10
       pointsOnDestroy: 70


Use task helper for determining lateness

The earlier check was marking exercises as non-late as soon as any work
was performed

--- tutor/src/components/student-dashboard/event-info-icon.cjsx
+++ tutor/src/components/student-dashboard/event-info-icon.cjsx
@@ -3,6 +3,7 @@
 S = require '../../helpers/string'
 {TimeStore} = require '../../flux/time'
 moment   = require 'moment'
+TH = require '../../helpers/task'

 module.exports = React.createClass
   displayName: 'EventInfoIcon'
@@ -14,9 +15,7 @@
     due = moment(@props.event.due_at)
     now = TimeStore.getNow()

-    return null if @props.event.type isnt 'homework' or
-      @props.event.complete_exercise_count is @props.event.exercise_count or
-      due.isAfter(now, 'd')
+    return null if due.isAfter(now, 'd') and TH.hasLateWork(@props.event)

     # use 'day' granularity for checking if the due date is today or after today
     status = if due.isSame(now, 'd') then 'incomplete' else 'late'


JGroup: setPlan: remove old plan data if it's set before

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1118,6 +1118,8 @@
       dataToUpdate = { 'config.planOverrides' : data.overrides }

       unless data.overrides
+        # unset old plan definition as well
+        dataToUpdate['config.plan'] = {}
         @update { $unset: dataToUpdate }, callback
       else
         @update { $set: dataToUpdate }, callback


group: make transferOwnership func accessible from backend

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1479,8 +1479,7 @@
       else
         callback()

-
-  transferOwnership: permit
+  transferOwnership$: permit
     advanced: [
       { permission: 'grant permissions' }
       { permission: 'grant permissions', superadmin: yes }
@@ -1490,57 +1489,76 @@
       { delegate } = client.connection
       { accountId, currentPassword, slug } = options

+      clientAccountId = delegate.getId()
+
       return callback new KodingError 'User is not selected!'  unless accountId

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

+      @checkUserPassword delegate, currentPassword, (err) =>
+
+        return callback new KodingError err  if err
+
+        @transferOwnership { clientAccountId, accountId, slug }, callback
+
+
+  transferOwnership: (options, callback) ->
+
+    { clientAccountId, accountId, slug } = options
+
+    return callback new KodingError 'Account is not provided'  unless accountId
+
+    @fetchOwner (err, owner) =>
+
+      return callback err if err
+
+      if clientAccountId and JSON.stringify(clientAccountId) isnt JSON.stringify(owner.getId())
+
+        return callback new KodingError 'You must be the owner to perform this action!'
+
       Relationship.one {
-        targetId: delegate.getId(),
+        targetId: owner.getId()
         sourceId: @getId(),
         as      : 'owner'
-      }, (err, owner) =>
-
-        return callback err if err
-        return callback new KodingError 'You must be the owner to perform this action!' unless owner
-
-        @checkUserPassword delegate, currentPassword, (err) =>
-
-          return callback new KodingError err  if err
-
-          JAccount = require '../account'
-          JAccount.one { _id: accountId }, (err, account) =>
+      }, (err, ownershipRelation) =>
+
+        JAccount = require '../account'
+        JAccount.one { _id: accountId }, (err, account) =>
+
+          return callback err if err
+
+          @fetchRolesByAccount account, (err, newOwnersRoles) =>
+
             return callback err if err

-            unless account.type is 'registered'
-              return callback new KodingError 'You cannot transfer ownership to this account'
-
-            @fetchRolesByAccount account, (err, newOwnersRoles) =>
-              return callback err if err
-
-              kallback = (err) ->
-                callback err
-
-              # give rights to new owner
-              queue = difference(['member', 'admin'], newOwnersRoles).map (role) => (fin) =>
-                @addMember account, role, fin
-
-              async.parallel queue, (err) ->
-                return kallback err  if err
-
-                # notify group for new owner
-                contents =
-                  role: 'owner'
-                  id: accountId
-                  group: slug
-                  adminNick: account.profile.nickname
-
-                JGroup.one { slug }, (err, group) ->
-                  if group
-                    group.sendNotification 'MembershipRoleChanged', contents
-
-                  # transfer ownership
-                  owner.update { $set: { targetId: account.getId() } }, kallback
+            if 'blockedAccount' in newOwnersRoles
+              return callback new KodingError 'You cannot transfer ownership to blocked account'
+
+            kallback = (err) ->
+              callback err
+
+            # give rights to new owner
+            queue = difference(['member', 'admin'], newOwnersRoles).map (role) => (fin) =>
+              @addMember account, role, fin
+
+            async.parallel queue, (err) ->
+              return kallback err  if err
+
+              slug ?= 'koding'
+
+              # notify group for new owner
+              contents =
+                role: 'owner'
+                id: accountId
+                group: slug
+                adminNick: owner.profile.nickname
+
+              JGroup.one { slug }, (err, group) ->
+                if group
+                  group.sendNotification 'MembershipRoleChanged', contents
+
+                ownershipRelation.update { $set: { targetId: account.getId() } }, kallback

   ensureUniquenessOfRoleRelationship:(target, options, fallbackRole, roleUnique, callback) ->
@@ -1590,20 +1608,6 @@
     @ensureUniquenessOfRoleRelationship target, options, 'owner', yes, (err) =>
       if err then callback err
       else oldAddOwner.call this, target, options, callback
-
-
-  checkUserPassword: (account, password, callback) ->
-
-    unless account or password
-      return callback "Couldn't verify user"
-
-    account.fetchUser (err, user) ->
-      return callback "Couldn't verify user"  if err
-
-      unless user.checkPassword password
-        return callback "Your password didn't match with our records"
-      else
-        callback()

   destroy$   : permit


Explicitly specify .js extension in test runner.

--- src/testrunner.coffee
+++ src/testrunner.coffee
@@ -12,7 +12,7 @@
   content = fs.readFileSync filepath, 'utf-8'
   if extension is '.coffee'
     coffee.compile content
-  else
+  else if extension is '.js'
     content

 getSpecFiles = (specs, file) ->


User info is now on "user" property of response

--- src/user/model.coffee
+++ src/user/model.coffee
@@ -32,7 +32,7 @@
   if data.access_token
     api.channel.emit('set.access_token', data.access_token)
   User.endpoints = data.endpoints
-  if data.current_user then User.update(data.current_user) else User.logout()
+  if data.user then User.update(data.user) else User.logout()

 # start out as a blank user
 _.extend(User, BLANK_USER)


Omit non-concept coach courses

Omit non-concept coach courses

--- src/user/model.coffee
+++ src/user/model.coffee
@@ -18,7 +18,8 @@

   update: (data) ->
     _.extend(this, data.user)
-    @courses = _.map data.courses, (course) -> new Course(course)
+    @courses = _.compact _.map data.courses, (course) -> new Course(course) if course.is_concept_coach
+
     @channel.emit('change')
     delete @isLoggingOut


Fix scroll in firefox (by specifying an animation on body and html). Fix callback called twice by adding a counter.

--- src/coffee/bootstrap-tour.coffee
+++ src/coffee/bootstrap-tour.coffee
@@ -446,11 +446,13 @@
       scrollTop = Math.max(0, offsetTop - (windowHeight / 2))

       @_debug "Scroll into view. ScrollTop: #{scrollTop}. Element offset: #{offsetTop}. Window height: #{windowHeight}."
-      $("body").stop().animate
+      counter = 0
+      $("body,html").stop(true,true).animate
         scrollTop: Math.ceil(scrollTop),
         =>
-          callback()
-          @_debug "Scroll into view. Animation end element offset: #{$element.offset().top}. Window height: #{$window.height()}."
+          if ++counter == 2
+            callback()
+            @_debug "Scroll into view. Animation end element offset: #{$element.offset().top}. Window height: #{$window.height()}."

     # Debounced window resize
     _onResize: (callback, timeout) ->


Update to generate and add slug in new product if not present. Update to assign slug from existing product if not present in product being imported.

--- src/coffee/product-import.coffee
+++ src/coffee/product-import.coffee
@@ -2,6 +2,7 @@
 _ = require 'underscore'
 _.mixin require 'underscore-mixins'
 Promise = require 'bluebird'
+slugify = require 'underscore.string/slugify'
 {SphereClient, ProductSync} = require 'sphere-node-sdk'

 class ProductImport
@@ -86,6 +87,9 @@
     posts = _.map productsToProcess, (prodToProcess) =>
       existingProduct = @_isExistingEntry(prodToProcess, existingProducts)
       if existingProduct?
+        if not prodToProcess.slug
+          debug 'slug missing in product to process, assigning same as existing product: %s', existingProduct.slug
+          prodToProcess.slug = existingProduct.slug # to prevent removing slug from existing product.
         synced = @sync.buildActions(prodToProcess, existingProduct)
         if synced.shouldUpdate()
           @client.products.byId(synced.getUpdateId()).update(synced.getUpdatePayload())
@@ -102,8 +106,9 @@
       @_resolveReference(@client.productTypes, 'productType', product.productType, "name=\"#{product.productType?.id}\"")
       @_resolveProductCategories(product.categories)
       @_resolveReference(@client.taxCategories, 'taxCategory', product.taxCategory, "name=\"#{product.taxCategory?.id}\"")
+      @_ensureSlug(product)
     ]
-    .spread (prodTypeId, prodCatsIds, taxCatId) ->
+    .spread (prodTypeId, prodCatsIds, taxCatId, slugs) ->
       if prodTypeId
         product.productType =
           id: prodTypeId
@@ -116,7 +121,29 @@
         product.categories = _.map prodCatsIds, (catId) ->
           id: catId
           typeId: 'category'
+      if slugs
+        product.slug = slugs
       Promise.resolve product
+
+  _ensureSlug: (product) ->
+    new Promise (resolve, reject) =>
+      if product.slug
+        resolve(product.slug)
+      if not product.name
+        reject("Product name is required.")
+      else
+        resolve(@_generateSlug product.name)
+
+  _generateSlug: (name, uniqueToken) ->
+    slugs = _.mapObject name, (val) =>
+      uniqueToken = @_generateUniqueToken unless uniqueToken
+      return slugify(val).concat("-#{uniqueToken}").substring(0, 256)
+    return slugs
+
+  _generateUniqueToken: ->
+    timestamp = new Date().getTime()
+    random = Math.floor(Math.random() * 90 + 10) # two digit random number.
+    return timestamp.concat random # to prevent same timestamp in parallel threads.

   _resolveProductCategories: (cats) ->
     new Promise (resolve) =>


Update methods to update the product references after resolving the references.

--- src/coffee/product-import.coffee
+++ src/coffee/product-import.coffee
@@ -94,17 +94,23 @@

   _prepareNewProduct: (product) ->
     Promise.all [
-      @_resolveReference(@client.productTypes, 'productType', product.productType?, "name=\"#{productTypeRef.id}\"")
+      @_resolveReference(@client.productTypes, 'productType', product.productType?, "name=\"#{product.productType?.id}\"")
       @_resolveProductCategories(product.categories?)
-      @_resolveReference(@client.taxCategories, 'taxCategory', product.taxCategory?, "name=\"#{taxCategoryRef.id}\"")
+      @_resolveReference(@client.taxCategories, 'taxCategory', product.taxCategory?, "name=\"#{product.taxCategory?.id}\"")
     ]
     .spread(prodType, prodCats, taxCat) =>
       if not prodType.isRejected
-        product.productType = prodType.value
+        product.productType =
+          id: prodType.value
+          typeId: 'product-type'
       if not prodCats.isRejected
-        product.categories = prodCats.value
+        product.categories = _.map prodCats.value, (catId) =>
+          id: catId
+          typeId: 'category'
       if not taxCat.isRejected
-        product.taxCategory = taxCat.value
+        product.taxCategory =
+          id: taxCat.value
+          typeId: 'tax-category'

   _resolveProductCategories: (cats) ->
     new Promise (resolve, reject) =>
@@ -124,8 +130,8 @@
       else
         service.where(predicate).fetch()
         .then (result) =>
-          # Todo: Handle multiple response, currently taking first response.
-          @_cache[refKey][ref.id] = result.body.results[0]
-          resolve(result.body.results[0])
+# Todo: Handle multiple response, currently taking first response.
+          @_cache[refKey][ref.id] = result.body.results[0].id
+          resolve(result.body.results[0].id)

 module.exports = ProductImport


Don't require destroying when pane removed.

--- lib/highlighted-area-view.coffee
+++ lib/highlighted-area-view.coffee
@@ -9,14 +9,12 @@
   initialize: ->
     @views = []
     atom.workspaceView.on "selection:changed", @handleSelection
-    atom.workspaceView.on 'pane:item-removed', @destroy

   attach: ->
     atom.workspaceView.prependToBottom(this)

   destroy: =>
     atom.workspaceView.off 'selection:changed', @handleSelection
-    atom.workspaceView.off 'pane:item-removed', @destroy
     @unsubscribe()
     @remove()
     @detach()


Improved implementation of field rename.

--- tests_migrations.coffee
+++ tests_migrations.coffee
@@ -28,14 +28,14 @@
   forward: (db, collectionName, currentSchema, newSchema, callback) =>
     db.collection collectionName, (error, collection) =>
       return callback error if error
-      collection.update {}, {$rename: test: 'renamed'}, {multi: true}, (error, count) =>
+      collection.update {_schema: currentSchema}, {$rename: test: 'renamed'}, {multi: true}, (error, count) =>
         return callback error if error
         super db, collectionName, currentSchema, newSchema, callback

   backward: (db, collectionName, currentSchema, oldSchema, callback) =>
     db.collection collectionName, (error, collection) =>
       return callback error if error
-      collection.update {}, {$rename: renamed: 'test'}, {multi: true}, (error, count) =>
+      collection.update {_schema: currentSchema}, {$rename: renamed: 'test'}, {multi: true}, (error, count) =>
         return callback error if error
         super db, collectionName, currentSchema, oldSchema, callback


Fix WebSocket already open log message typo

--- actioncable/app/assets/javascripts/action_cable/connection.coffee
+++ actioncable/app/assets/javascripts/action_cable/connection.coffee
@@ -20,7 +20,7 @@

   open: =>
     if @isActive()
-      ActionCable.log("Attemped to open WebSocket, but existing socket is #{@getState()}")
+      ActionCable.log("Attempted to open WebSocket, but existing socket is #{@getState()}")
       throw new Error("Existing connection must be closed before opening")
     else
       ActionCable.log("Opening WebSocket, current state is #{@getState()}")


Minor: comment, parameter names

Minor: comment, parameter names

--- src/resources-packaged/ops/javascript/orbeon/xforms/Document.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/Document.coffee
@@ -62,19 +62,19 @@
     # Returns the value of an XForms control.
     # @param {String | HTMLElement} control
     # @param {HTMLElement} form
-    getValue: (control, form) ->
-        Controls.getCurrentValue(Document._findControl(control, form))
+    getValue: (controlIdOrElement, form) ->
+        Controls.getCurrentValue(Document._findControl(controlIdOrElem, form))

     # Set the value of an XForms control.
     # @param {String | HTMLElement} control
     # @param {String} newValue
     # @param {HTMLElement} form
-    setValue: (control, newValue, form) ->
+    setValue: (controlIdOrElement, newValue, form) ->

-        # Cast to String if caller passes a non-string value "by mistake"
+        # Cast to String if caller passes a non-string value "by mistake" (or not, like a Number)
         newValue = newValue.toString()

-        control = Document._findControl(control, form)
+        control = Document._findControl(controlIdOrElem, form)

         if $(control).is('.xforms-output, .xforms-upload')
             throw 'Cannot set the value of an output or upload control'


Remove Refresh and Redirect

Remove Refresh and Redirect

--- app/assets/javascripts/effective_datatables/inline_crud.js.coffee
+++ app/assets/javascripts/effective_datatables/inline_crud.js.coffee
@@ -38,7 +38,6 @@
   EffectiveForm.remote_form_payload = ''
   EffectiveForm.remote_form_commit = ''
   EffectiveForm.remote_form_flash = ''
-  EffectiveForm.remote_form_refresh_datatables = ''

   true

@@ -53,7 +52,6 @@
   EffectiveForm.remote_form_payload = ''
   EffectiveForm.remote_form_commit = ''
   EffectiveForm.remote_form_flash = ''
-  EffectiveForm.remote_form_refresh_datatables = ''
   true

 # Submitting an inline datatables form
@@ -84,7 +82,6 @@
     $tr.fadeOut('slow')

   $table.DataTable().draw()
-  refreshDatatables($table)

 beforeNew = ($action) ->
   $table = $action.closest('table')
@@ -150,9 +147,7 @@
   else
     $table.DataTable().flash('Successfully ' + $action.attr('title'), 'success')

-  unless redirectDatatables($table)
-    $table.DataTable().draw()
-    refreshDatatables($table)
+  $table.DataTable().draw()

 afterError = ($action) ->
   $table = $action.closest('table')
@@ -186,28 +181,6 @@
   if $wrapper.find('.effective-datatables-inline-row').length == 0
     $wrapper.removeClass('effective-datatables-inline-expanded')

-redirectDatatables = ($source) ->
-  return false unless EffectiveForm.remote_form_refresh_datatables.length > 0
-
-  if EffectiveForm.remote_form_refresh_datatables.includes('refresh')
-    if Turbolinks?
-      Turbolinks.visit(window.location.href, { action: 'replace'})
-    else
-      window.location.reload()
-
-    return true
-
-  false
-
-refreshDatatables = ($source) ->
-  return unless EffectiveForm.remote_form_refresh_datatables.length > 0
-
-  $('table.dataTable.initialized').each ->
-    $table = $(this)
-
-    if EffectiveForm.remote_form_refresh_datatables.find((id) -> $table.attr('id').startsWith(id) || id == 'all')
-      $table.DataTable().draw() if $table != $source
-
 # Cancel button clicked. Blow away new tr, or restore edit tr
 # No data will have changed at this point
 $(document).on 'click', ".dataTables_wrapper a[data-role='inline-form-cancel']", (event) ->


Fix the position of the token info tooltip

--- app/assets/javascripts/rglossa/views/cwb/result/table_view.coffee
+++ app/assets/javascripts/rglossa/views/cwb/result/table_view.coffee
@@ -2,4 +2,6 @@

   didInsertElement: ->
     @$('[data-ot]').each (index, token) ->
-      new Opentip(token, $(token).data('ot'), {style: 'dark'})
+      new Opentip token, $(token).data('ot'),
+        style: 'dark'
+        fixed: true


Doesn't round external assignment click rates to 0% or 100%.

--- src/components/scores/table.cjsx
+++ src/components/scores/table.cjsx
@@ -155,9 +155,15 @@
         average =
           ---
       else if heading.type is 'external'
+        p = heading.completion_rate
+        percent = switch
+          when (p < 1 and p > 0.99) then 99 # Don't round to 100% when it's not 100%!
+          when (p > 0 and p < 0.01) then 1  # Don't round to 0% when it's not 0%!
+          when (p > 1) then 100             # Don't let it go over 100%!
+          else Math.round(p * 100)
         average =

-            {(heading.completion_rate * 100).toFixed(0)}% have clicked link
+            {percent}% have clicked link

     if heading.type is 'reading' or heading.type is 'external'


fix account quota XSS vulnerability, fixes CNVS-17656

prevent a malicious course title from XSSing an admin attempting to update
the course's storage quota from the accounts settings Quota tab

test plan:
1. refer to repro steps on CNVS-17656

Change-Id: I3b1dfc5675afc0a1889cb360101c6033cec1517e
Reviewed-on: https://gerrit.instructure.com/46281
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
Product-Review: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Caleb Guanzon <54fa1f30d451e4f3c341a8f3c47c9215fd0be9c6@instructure.com>

--- app/coffeescripts/views/accounts/settings/ManualQuotasView.coffee
+++ app/coffeescripts/views/accounts/settings/ManualQuotasView.coffee
@@ -132,7 +132,7 @@
       @showErrors(errors)

     findSuccess: =>
-      @$link.html(@model.get('name'))
+      @$link.text(@model.get('name'))
       @$link.attr('href', @model.path + '/' + @model.get('id'))

       @$quota.val(@model.get('storage_quota_mb'))


Move buttons to left and show OK first

Move buttons to left and show OK first

--- src/components/tutor-dialog.cjsx
+++ src/components/tutor-dialog.cjsx
@@ -36,10 +36,10 @@
   render: ->
     return null unless @state.show
     buttons = @props.buttons or [
+        <BS.Button key='ok'     className='ok'
+          onClick={_.compose(@props.onOk, @_hide)} bsStyle='primary'>OK</BS.Button>
         <BS.Button key='cancel' className='cancel'
           onClick={_.compose(@props.onCancel,  @_hide)}>Cancel</BS.Button>
-        <BS.Button key='ok'     className='ok'
-          onClick={_.compose(@props.onOk, @_hide)} bsStyle='primary'>OK</BS.Button>
     ]
     classes = ['tutor-dialog']
     classes.push @props.className if @props.className
@@ -48,7 +48,7 @@

         {@props.body}

-

+

         {buttons}

     </BS.Modal>


:european_post_office::put_litter_in_its_place: Updated at https://danielx.net/editor/

--- main.coffee
+++ main.coffee
@@ -51,6 +51,9 @@
   navigator.mediaDevices.getUserMedia
     audio: true
   .then createAudio
+  .catch (e) ->
+    if e.name is "DevicesNotFoundError"
+      alert "No devices found, is your microphone plugged in?"

 # -------------------------------------------------
 # From here on down is our Whimsy.space integration


it works. All tests will fail, but whatevs.

--- microblu-transformer.coffee
+++ microblu-transformer.coffee
@@ -3,20 +3,26 @@

 class MicrobluTransformer
   constructor: (opts={}) ->
-    @path = opts.path || 'microblu.proto'
+    @path = opts.path || __dirname + '/microblu.proto'
     @format = opts.format || 'base64'

-  initialize: =>
     builder = ProtoBuf.loadProtoFile @path
-    @MicrobluProto = builder.build 'Microblu'
+    @MicrobluProto = builder.build 'MicrobluState'

   toProtocolBuffer: (msg, callback=->) =>
     msgProto = new @MicrobluProto msg
     msgProto.encode()
+
+    return callback null, msgProto.toBuffer() if opts.format == 'binary'
     callback null, msgProto.toBuffer().toString @format

-  toJson: (msg, callback) =>
-    msgBuffer = new Buffer msg, @format
+  toJSON: (msg, callback) =>
+
+    if typeof msg == 'string'
+      msgBuffer = new Buffer msg, @format
+    else
+      msgBuffer = new Buffer msg
+
     msgProto = @MicrobluProto.decode msgBuffer

     callback null, JSON.parse msgProto.encodeJSON()


JCredential: split-out fetchByPublicKey function so we can use it for credential checks when needed.

--- workers/social/lib/social/models/computeproviders/credential.coffee
+++ workers/social/lib/social/models/computeproviders/credential.coffee
@@ -86,6 +86,9 @@
         as            : "data"

+
+
+
   failed = (err, callback, rest...)->
     return false  unless err

@@ -122,17 +125,22 @@
               callback null, credential

+  @fetchByPublicKey = (client, publicKey, callback)->
+
+    options =
+      limit         : 1
+      targetOptions : selector : { publicKey }
+
+    {delegate} = client.connection
+    delegate.fetchCredential { }, options, (err, res)->
+      callback err, res
+
+
   @one$: permit 'list credentials',

     success: (client, publicKey, callback)->

-      options =
-        limit         : 1
-        targetOptions : selector : { publicKey }
-
-      {delegate} = client.connection
-      delegate.fetchCredential { }, options, (err, res)->
-        callback err, res
+      @fetchByPublicKey client, publicKey, callback

   @some$: permit 'list credentials',


Using elapsed time in delayed events

Using elapsed time in delayed events

--- src/engine_delay.coffee
+++ src/engine_delay.coffee
@@ -20,7 +20,7 @@
     return

   ###*
-  Execute a callback after a number of s have passed.
+  Execute a callback after a number of seconds have passed.

       engine.delay 5, ->
         engine.add


Fix redis.shard

Fix redis.shard

--- server/redis.coffee
+++ server/redis.coffee
@@ -14,9 +14,10 @@

 determineShardSize = (next) ->
   return next(determineShardSize.SHARD_SIZE)  if determineShardSize.SHARD_SIZE
-  db.config 'get', 'hash-max-zipmap-entries', (err, size) ->
+  db.config 'get', 'hash-max-zipmap-entries', (err, results) ->
     throw err  if err
-    determineShardSize.SHARD_SIZE = size
+    [key, size] = results  if results
+    determineShardSize.SHARD_SIZE = (if size then Number(size) else 1024)
     next(determineShardSize.SHARD_SIZE)

 determineShardSize.SHARD_SIZE = null


Redirect with same protocol as request

Redirect with same protocol as request

Try using // instead of explicit protocol

--- server_setup.coffee
+++ server_setup.coffee
@@ -62,9 +62,9 @@
       domainRegex = new RegExp("(.*\.)?(#{config.mainHostname}|#{config.unsafeContentHostname})")
       domainPrefix = req.host.match(domainRegex)?[1] or ''
       if _.any(unsafePaths, (pathRegex) -> pathRegex.test(req.path)) and (req.host isnt domainPrefix + config.unsafeContentHostname)
-        res.redirect('http://' + domainPrefix + config.unsafeContentHostname + req.path)
+        res.redirect('//' + domainPrefix + config.unsafeContentHostname + req.path)
       else if not _.any(unsafePaths, (pathRegex) -> pathRegex.test(req.path)) and req.host is domainPrefix + config.unsafeContentHostname
-        res.redirect('http://' + domainPrefix + config.mainHostname + req.path)
+        res.redirect('//' + domainPrefix + config.mainHostname + req.path)
       else
         next()


Always output endpoint logs if TRACE_ROUTES is set

--- server_setup.coffee
+++ server_setup.coffee
@@ -105,7 +105,7 @@
     app.use compression filter: (req, res) ->
       return false if req.headers.host is 'codecombat.com'  # CloudFlare will gzip it for us on codecombat.com
       compressible res.getHeader('Content-Type')
-  else if not global.testing
+  else if not global.testing or config.TRACE_ROUTES
     morgan.format('dev', developmentLogging)
     app.use(morgan('dev'))


Restyled finish mark.

Restyled finish mark.

--- maze.coffee
+++ maze.coffee
@@ -214,15 +214,20 @@
             context.stroke()
           if @maze.is_finish([x, y, z])
             # paint finish mark
-            context.beginPath()
-            context.arc(71 * x + 71 / 2, 71 * y + 71 / 2, 21, 0, 2 * Math.PI, false)
-            context.lineWidth = 10
+            context.lineWidth = 1
+            context.strokeStyle = 'grey'
+            context.stroke()
+            context.beginPath()
+            context.arc(71 * x + 35, 71 * y + 35, 13.5, 0, 2 * Math.PI, false)
+            context.stroke()
+            context.beginPath()
+            context.moveTo(71 * x + 35, 71 * y + 15)
+            context.lineTo(71 * x + 35, 71 * y + 55)
+            context.stroke()
+            context.moveTo(71 * x + 15, 71 * y + 35)
+            context.lineTo(71 * x + 55, 71 * y + 35)
+            context.stroke()
             context.strokeStyle = 'black'
-            context.stroke()
-            context.beginPath()
-            context.arc(71 * x + 71 / 2, 71 * y + 71 / 2, 10, 0, 2 * Math.PI, false)
-            context.fillStyle = 'black'
-            context.fill()
           if @maze.passage_exists([[x, y, z], [x, y, z + 1]])
             # paint up arrow
             context.beginPath()


Client: Activity: Feed: Moved ChatListItem menu items to MessageItemMenu component

--- client/activity/lib/components/messageitemmenu/index.coffee
+++ client/activity/lib/components/messageitemmenu/index.coffee
@@ -53,6 +53,57 @@
     @setState isBlockUserModalVisible: no

+  showDeletePostPromptModal: ->
+
+    @setState isDeleting: yes
+
+
+  closeDeletePostModal: (event) ->
+
+    kd.utils.stopDOMEvent event
+    @setState isDeleting: no
+
+
+  showMarkUserAsTrollPromptModal: ->
+
+    @setState isMarkUserAsTrollModalVisible: yes
+
+
+  closeMarkUserAsTrollModal: (event) ->
+
+    kd.utils.stopDOMEvent event
+    @setState isMarkUserAsTrollModalVisible: no
+
+
+  unMarkUserAsTroll: (event) ->
+
+    kd.utils.stopDOMEvent event
+    AppFlux.actions.user.unmarkUserAsTroll @state.account
+    @closeMarkUserAsTrollModal()
+
+
+  editPost: ->
+
+    messageId = @props.message.get '_id'
+
+    ActivityFlux.actions.message.setMessageEditMode messageId, @props.channelId
+
+
+  deletePostButtonHandler: (event) ->
+
+    kd.utils.stopDOMEvent event
+    ActivityFlux.actions.message.removeMessage @props.message.get('id')
+    @closeDeletePostModal()
+
+
+  impersonateUser: (event) ->
+
+    kd.utils.stopDOMEvent event
+    { message } = @props
+
+    AppFlux.actions.user.impersonateUser message.toJS()
+
+
   getBlockUserModalProps: ->

     account            : @state.account
@@ -62,6 +113,27 @@
     onClose            : @bound "closeBlockUserPromptModal"

+  getDeleteItemModalProps: ->
+
+    title              : "Delete post"
+    body               : "Are you sure you want to delete this post?"
+    buttonConfirmTitle : "DELETE"
+    className          : "Modal-DeleteItemPrompt"
+    onConfirm          : @bound "deletePostButtonHandler"
+    onAbort            : @bound "closeDeletePostModal"
+    onClose            : @bound "closeDeletePostModal"
+
+
+  getMarkUserAsTrollModalProps: ->
+
+    account            : @state.account
+    title              : "MARK USER AS TROLL"
+    className          : "MarkUserAsTrollModal"
+    onAbort            : @bound "closeMarkUserAsTrollModal"
+    onClose            : @bound "closeMarkUserAsTrollModal"
+    buttonConfirmTitle : "YES, THIS USER IS DEFINITELY A TROLL"
+
+
   getMenuItems: ->

     if checkFlag('super-admin')
@@ -71,14 +143,41 @@

   getDefaultMenuItems: -> []

+    return [
+      {title: 'Edit Post'  , key: 'editpost'            , onClick: @bound 'editPost'}
+      {title: 'Delete Post', key: 'showdeletepostprompt', onClick: @bound 'showDeletePostPromptModal'}
+    ]
+

   getAdminMenuItems: ->

+    { message } = @props
+    markUserMenuItem =
+      key: 'markuserastroll',
+      title: 'Mark User as Troll',
+      onClick: @bound 'showMarkUserAsTrollPromptModal'
+
+    getMessageOwner message.toJS(), (err, owner) =>
+
+      return showErrorNotification err  if err
+
+      if owner.isExempt
+        markUserMenuItem =
+          key: 'unmarkuserastroll',
+          title: 'Unmark User as Troll',
+          onClick: @bound 'unMarkUserAsTroll'
+
     adminMenuItems = [
+      markUserMenuItem
       {
         title   : 'Block User'
         key     : 'blockuser'
         onClick : @bound 'showBlockUserPromptModal'
+      }
+      {
+        title   : 'Impersonate User'
+        key     : 'impersonateuser'
+        onClick : @bound 'impersonateUser'
       }
     ]

@@ -97,4 +196,12 @@
         <BlockUserModal
           {...@getBlockUserModalProps()}
           isOpen={@state.isBlockUserModalVisible} />
+        <MarkUserAsTrollModal
+          {...@getMarkUserAsTrollModalProps()}
+          isOpen={@state.isMarkUserAsTrollModalVisible} />
+        <ActivityPromptModal
+          {...@getDeleteItemModalProps()}
+          isOpen={@state.isDeleting}>
+          Are you sure you want to delete this post?
+        </ActivityPromptModal>
       </div>


Code refactoring part 2

Code refactoring part 2

--- client/app/lib/commonviews/buttonviewwithprogressbar.coffee
+++ client/app/lib/commonviews/buttonviewwithprogressbar.coffee
@@ -11,16 +11,13 @@

     super options, data

-    o               = @getOptions() or {}
-    buttonOptions   = o.button      or {}
-    progressOptions = o.progress    or {}
-    loaderOptions   = o.loader      or {}
+    o               = @getOptions()        or {}
+    buttonOptions   = o.buttonOptions      or {}
+    progressOptions = o.progressOptions    or {}
+    loaderOptions   = o.loaderOptions      or {}

     @button = new KDButtonView buttonOptions
-
-    @button.click = (event) =>
-      KDButtonView::click.call @button, event
-      @startProgress()
+    @button.setCallback @bound 'handleCallback'

     @addSubView @button

@@ -31,6 +28,14 @@

     @progressBar.addSubView @loader, null, yes
     @addSubView @progressBar
+
+
+  handleCallback: ->
+
+    buttonOptions = @getOption 'buttonOptions' or {}
+    buttonOptions.callback.call()  if buttonOptions.callback
+
+    @startProgress()

   startProgress: ->


Fixed editor value on updated mode for introduction tooltip.

--- client/landing/app/MainApp/sidebar/modals/adminmodal.coffee
+++ client/landing/app/MainApp/sidebar/modals/adminmodal.coffee
@@ -798,7 +798,7 @@
         exec    : =>

   setEditorText: (text = "new KDView({\n  partial: \"\"\n});") ->
-    @aceEditor.getSession().setValue text
+    @aceEditor.getSession().setValue Encoder.htmlDecode @parentData.snippet or text

   switchMode: ->
     {typeSwitch} = @inputs


Fix Settings link

Fix Settings link

--- client/landing/app/MainApp/sidebar/sidebarcontroller.coffee
+++ client/landing/app/MainApp/sidebar/sidebarcontroller.coffee
@@ -66,5 +66,5 @@
         type      : 'admin'
         loggedIn  : yes
         callback  : ->
-          slug = if slug is 'koding' then '/' else "/#{slug}/"
+          slug = if slug in ['koding', ''] then '/' else "/#{slug}/"
           KD.getSingleton('router').handleRoute "#{slug}Dashboard"


Remove cruft

Remove cruft

--- src/lib/cursor.coffee
+++ src/lib/cursor.coffee
@@ -90,33 +90,6 @@
   toModels: (callback) ->
     return callback(new Error "Cannot call toModels on cursor with values for model #{@model_type.model_name}. Values: #{JSONUtils.stringify(@_cursor.$values)}") if @_cursor.$values

-    # a cache candidate
-    # if not (@_cursor.$offset or @_cursor.$limit or @_cursor.$include) and cache = @model_type.cache
-    #   find_size = _.size(@_find)
-    #   if find_size is 0
-    #     return callback(null, model) if not (ids = @_cursor.$ids) and @_cursor.$one and (model = cache.get())
-
-    #   else if find_size is 1 and @_find.id
-    #     if not (ids = @_find.id.$in) and (model = cache.get(@_find.id))
-    #       return callback(null, if @_cursor.$one then model else [model])
-
-    #   if ids
-    #     missing_ids = [] # TODO: fetch delta ids, need to handle sorting, etc
-    #     models = []
-    #     for id in ids
-    #       (missing_ids.push(id); continue) unless model = cache.get(id)
-    #       models.push(model)
-    #       break if @_cursor.$one
-
-    #     if @_cursor.$one
-    #       return callback(null, models[0]) if models.length
-    #     else
-    #       if not missing_ids.length # found everything
-    #         if @_cursor.$sort
-    #           $sort_fields = if _.isArray(@_cursor.$sort) then @_cursor.$sort else [@_cursor.$sort]
-    #           models.sort (model, next_model) => return Utils.jsonFieldCompare(model.attributes, next_model.attributes, $sort_fields)
-    #         return callback(null, models)
-
     @toJSON (err, json) =>
       return callback(err) if err
       return callback(null, null) if @_cursor.$one and not json


updates jasmine tests to correspond to new capa template HTML

--- common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
+++ common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
@@ -16,7 +16,7 @@

     # note that the fixturesPath is set in spec/helper.coffee
     loadFixtures 'problem.html'
-
+
     spyOn Logger, 'log'
     spyOn($.fn, 'load').andCallFake (url, callback) ->
       $(@).html readFixtures('problem_content.html')
@@ -27,13 +27,13 @@
     it 'set the element from html', ->
       @problem999 = new Problem ("

-
@@ -62,7 +62,7 @@
       expect($('section.action input.reset')).toHandleWith 'click', @problem.reset

     it 'bind the show button', ->
-      expect($('section.action input.show')).toHandleWith 'click', @problem.show
+      expect($('section.action button.show')).toHandleWith 'click', @problem.show

     it 'bind the save button', ->
       expect($('section.action input.save')).toHandleWith 'click', @problem.save
@@ -126,14 +126,14 @@

     describe 'when the response is correct', ->
       it 'call render with returned content', ->
-        spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
+        spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
           callback(success: 'correct', contents: 'Correct!')
         @problem.check()
         expect(@problem.el.html()).toEqual 'Correct!'

     describe 'when the response is incorrect', ->
       it 'call render with returned content', ->
-        spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
+        spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
           callback(success: 'incorrect', contents: 'Incorrect!')
         @problem.check()
         expect(@problem.el.html()).toEqual 'Incorrect!'
@@ -159,7 +159,7 @@
     it 'POST to the problem reset page', ->
       spyOn $, 'postWithPrefix'
       @problem.reset()
-      expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_reset',
+      expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_reset',
           { id: 'i4x://edX/101/problem/Problem1' }, jasmine.any(Function)

     it 'render the returned content', ->
@@ -179,7 +179,7 @@

       it 'log the problem_show event', ->
         @problem.show()
-        expect(Logger.log).toHaveBeenCalledWith 'problem_show',
+        expect(Logger.log).toHaveBeenCalledWith 'problem_show',
             problem: 'i4x://edX/101/problem/Problem1'

       it 'fetch the answers', ->
@@ -198,7 +198,7 @@
       it 'toggle the show answer button', ->
         spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {})
         @problem.show()
-        expect($('.show')).toHaveValue 'Hide Answer'
+        expect($('.show .show-label')).toHaveText 'Hide Answer(s)'

       it 'add the showed class to element', ->
         spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {})
@@ -223,7 +223,7 @@
           expect($('label[for="input_1_1_3"]')).toHaveAttr 'correct_answer', 'true'
           expect($('label[for="input_1_2_1"]')).not.toHaveAttr 'correct_answer', 'true'

-    describe 'when the answers are alreay shown', ->
+    describe 'when the answers are already shown', ->
       beforeEach ->
         @problem.el.addClass 'showed'
         @problem.el.prepend '''
@@ -243,7 +243,7 @@

       it 'toggle the show answer button', ->
         @problem.show()
-        expect($('.show')).toHaveValue 'Show Answer'
+        expect($('.show .show-label')).toHaveText 'Show Answer(s)'

       it 'remove the showed class from element', ->
         @problem.show()
@@ -261,7 +261,7 @@
     it 'POST to save problem', ->
       spyOn $, 'postWithPrefix'
       @problem.save()
-      expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_save',
+      expect($.postWithPrefix).toHaveBeenCalledWith '/problem/Problem1/problem_save',
           'foo=1&bar=2', jasmine.any(Function)

     # TODO: figure out why failing


fix property name for community

fix property name for community

--- src/join-request.coffee
+++ src/join-request.coffee
@@ -69,7 +69,7 @@
       res.render 'thanks', viewData

       user.agentName = req.body.agentName.slice 0, 32
-      user.community = req.body.comments.slice 0, 140
+      user.community = req.body.community.slice 0, 140
       user.comments = req.body.comments.slice 0, 140

       robot.brain.data.ingressAgents.push user


Use the internal updateTree instead of the public one

--- github.coffee
+++ github.coffee
@@ -144,7 +144,7 @@

     # Uses the cache if branch has not been changed
     # -------
-    updateTree = (branch) ->
+    _updateTree: (branch) ->
       # Since this method always returns a promise, wrap the result in a deferred
       return (new jQuery.Deferred()).resolve(@currentTree.sha) if branch is @currentTree.branch and @currentTree.sha

@@ -342,7 +342,7 @@
     # Remove a file from the tree
     # -------
     remove: (branch, path) ->
-      updateTree(branch)
+      @_updateTree(branch)
       .then (latestCommit) =>
         @getTree("#{latestCommit}?recursive=true")
         .then (tree) =>
@@ -370,7 +370,7 @@
     # Move a file to a new location
     # -------
     move: (branch, path, newPath) ->
-      updateTree(branch)
+      @_updateTree(branch)
       .then (latestCommit) =>
         @getTree("#{latestCommit}?recursive=true")
         .then (tree) =>


Convert the JSON to a string when sending

because processData is set to false

--- github.coffee
+++ github.coffee
@@ -44,7 +44,7 @@
         }

         processData: false # Don't convert to QueryString
-        data: data
+        data: !raw and data and JSON.stringify(data) or data
         dataType: 'json' unless raw

         beforeSend: (xhr) =>
@@ -395,7 +395,7 @@
     # Write file contents to a given branch and path
     # -------
     write: (branch, path, content, message) ->
-      updateTree(branch)
+      @_updateTree(branch)
       .then (latestCommit) =>
         @postBlob(content)
         .then (blob) =>


Add underbar before bytesRead.

Add underbar before bytesRead.

--- src/lib/packet.coffee
+++ src/lib/packet.coffee
@@ -40,7 +40,7 @@
   # recover from exceptional conditions and generally a good idea to call this
   # method before starting a new series of packet parsing transitions.
   reset: ->
-    @bytesRead = 0
+    @_bytesRead = 0
     @bytesWritten = 0
     @pattern = null
     @callback = null
@@ -152,7 +152,7 @@

   data: (data...)   -> @user = data

-  getBytesRead:     -> @bytesRead
+  getBytesRead:     -> @_bytesRead

   nextField: ->
     pattern       = @pattern[@patternIndex]
@@ -227,7 +227,7 @@
   read: (buffer, offset, length) ->
     offset or= 0
     length or= buffer.length
-    start    = @bytesRead
+    start    = @_bytesRead
     end      = offset + length

     # We set the pattern to null when all the fields have been read, so while
@@ -240,12 +240,12 @@
         begin        = offset
         offset      += advance
         @_skipping  -= advance
-        @bytesRead  += advance
+        @_bytesRead += advance
         if @_stream
           @_stream._write(buffer.slice(begin, begin + advance)) if advance
           @_stream._end() if not @_skipping
         if @_skipping
-          return @bytesRead - start
+          return @_bytesRead - start
         else
           @_skipping = null

@@ -254,24 +254,24 @@
         if part.unpacked
           loop
             b = buffer[offset]
-            @bytesRead++
+            @_bytesRead++
             offset++
             @value[@offset] = b
             @offset += @increment
             break if @offset is @terminal
-            return @bytesRead - start if offset is end
+            return @_bytesRead - start if offset is end

         # Otherwise we're packing bytes into an unsigned integer, the most
         # common case.
         else
           loop
             b = buffer[offset]
-            @bytesRead++
+            @_bytesRead++
             offset++
             @value += Math.pow(256, @offset) * b
             @offset += @increment
             break if @offset == @terminal
-            return @bytesRead - start if offset is end
+            return @_bytesRead - start if offset is end

         # Unpack the field value.
         bytes = value = @value
@@ -378,7 +378,7 @@
           @nextField()
           @nextValue()

-    @bytesRead - start
+    @_bytesRead - start

   close: ->
     @emit "close"


Got rid of user data to callback.

Got rid of user data to callback.

--- src/lib/parser.coffee
+++ src/lib/parser.coffee
@@ -61,9 +61,6 @@
   constructor: (self) ->
     super self
     @writable = true
-
-  # FIXME Outgoing.
-  data: (data...)   -> @_user = data

   # Get the number of bytes read since the last call to `@reset()`.
   getBytesRead:     -> @_bytesRead
@@ -344,7 +341,6 @@

           if @_callback
             @_fields.push(this)
-            @_fields.push(p) for p in @_user or []

             # At one point, you thought you could have  a test for the arity of
             # the function, and if it was not `1`, you'd call the callback


Removed extraneous test export

Removed extraneous test export

--- src/lib/tester.coffee
+++ src/lib/tester.coffee
@@ -1,2 +0,0 @@
-module.exports =
-  message: 'Hello, world'


Fixed a bug in payments js at backend

Fixed a bug in payments js at backend

fixes #6129

--- backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee
+++ backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee
@@ -3,7 +3,7 @@
   order_id = $('#payments').data('order-id')
   class Payment
     constructor: (id) ->
-      @url  = Spree.url("#{Spree.routes.payments_api(order_id)}/#{id}.json")
+      @url  = Spree.url("#{Spree.routes.payments_api(order_id)}/#{id}.json" + '?token=' + Spree.api_key)
       @json = $.getJSON @url.toString(), (data) =>
         @data = data


Allow closed group to become secret w/ parentMembersCanSeeDiscussions set

--- angular/core/components/group_form/group_form.coffee
+++ angular/core/components/group_form/group_form.coffee
@@ -61,6 +61,7 @@
         $scope.group.discussionPrivacyOptions = 'private_only'

     $scope.groupPrivacyChanged = ->
+      $scope.group.parentMembersCanSeeDiscussions = !$scope.group.privacyIsSecret()
       switch $scope.group.groupPrivacy
         when 'open'   then $scope.group.discussionPrivacyOptions = 'public_only'
         when 'closed' then $scope.allowPublicThreadsClicked()


Bugs in change watcher

Bugs in change watcher

--- www-client/src/www/js/debug.coffee
+++ www-client/src/www/js/debug.coffee
@@ -4,9 +4,15 @@
     setInterval checkVersion, 1000

 checkVersion = ->
-    $.ajax '/system/build.txt', {
-        success: (data) ->
-            if window.DEBUG_CLIENT_BUILD and data isnt window.DEBUG_CLIENT_BUILD
-                window.location.reload()
-            window.DEBUG_CLIENT_BUILD = data
-    }
+    $.get '/system/build.txt', (data) ->
+        if window.DEBUG_CLIENT_BUILD and data isnt window.DEBUG_CLIENT_BUILD
+            #First make an ajax request to check if server is ready. (Some builds cause server restarts)
+            app.api 'healthcheck', {
+                success: (data) ->
+                    #All OK. Reload()
+                    window.location.reload()
+                error: ->
+                    window.DEBUG_CLIENT_BUILD = "invalid"
+            }
+        window.DEBUG_CLIENT_BUILD = data
+


Cloud toggle now has @active = false as default

--- app/assets/javascripts/views/clouds/toggle.js.coffee
+++ app/assets/javascripts/views/clouds/toggle.js.coffee
@@ -11,6 +11,8 @@
   }

   initialize: ->
+
+    @active = false

     @fetchNotifications()


clear select of _id if authorized_type is empty on first load

--- app/assets/javascripts/wobauth/authorities.js.coffee
+++ app/assets/javascripts/wobauth/authorities.js.coffee
@@ -1,3 +1,4 @@
+$('#authority_authorizable_id optgroup').find('option').andSelf().hide()
 $(document).on('click', '#authority_authorizable_type', ->
   type = $(this).find("option:selected").val()
   # alert(type)


Remove agencia e conta das chamadas de metodos do terminal

--- Terminal/client/Terminal.coffee
+++ Terminal/client/Terminal.coffee
@@ -34,17 +34,15 @@
 				if AccountCliente.userId()?
 					c.stop()

-					agenciaCliente.call 'depositar', {conta: '1', valor: 120}
-					agenciaCliente.call 'depositar', {conta: '1', valor: 20}
-					agenciaCliente.call 'depositar', {conta: '1', valor: 100}
+					agenciaCliente.call 'depositar', {valor: 120}
+					agenciaCliente.call 'depositar', {valor: 20}
+					agenciaCliente.call 'depositar', {valor: 100}

-					agenciaCliente.call 'sacar', {conta: '1', valor: 40}
+					agenciaCliente.call 'sacar', {valor: 40}

-					agenciaCliente.call 'transferir', {conta: '1', valor: 50, para: {agencia: '1', conta: '2'}}
+					agenciaCliente.call 'transferir', {valor: 50, para: {agencia: '1', conta: '2'}}

-					agenciaCliente.call 'extrato', {conta: '1'}, (err, data) ->
+					agenciaCliente.call 'extrato', {}, (err, data) ->
 						console.log 'conta 1', JSON.stringify(data, null, 2)

-					agenciaCliente.call 'extrato', {conta: '2'}, (err, data) ->
-						console.log 'conta 2', JSON.stringify(data, null, 2)
 		, 2000


removed tws

removed tws

--- client/app/MainApp/filetree/itemsubviews/finderitemrenameview.coffee
+++ client/app/MainApp/filetree/itemsubviews/finderitemrenameview.coffee
@@ -27,6 +27,7 @@
     {{> @input}}
     {{> @cancel}}
     """
+
 class NFinderRenameInput extends KDHitEnterInputView

   click    : -> no


Slightly more robust parsing of url in middleware.

--- src/middleware.coffee
+++ src/middleware.coffee
@@ -1,17 +1,26 @@
-module.exports = (entry, options={}) ->
+{parse} = require 'url'
+
+module.exports = (options={}) ->
+  unless options.entry?
+    throw new Error 'Entry module unspecified'
+
   maxAge = options.maxAge or 0
   bundle = null

   middleware = (req, res, next) ->
     unless bundle?
-      require('./bundle') entry, options, (err, _bundle) ->
+      require('./bundle') options.entry, options, (err, _bundle) ->
         bundle = _bundle
         middleware req, res, next
       return

-    url = req.url.replace /\.\w+$/, ''
+    # parse url to deal with oddness
+    url  = parse req.url, true, true

-    unless (mod = bundle.find url)?
+    # strip extension from module path
+    path = url.pathname.replace /\.\w+$/, ''
+
+    unless (mod = bundle.find path)?
       return next()

     now = new Date().toUTCString()


added conditions

added conditions

--- src/model/statsd.coffee
+++ src/model/statsd.coffee
@@ -36,10 +36,21 @@
   for (var i = 0; i < allowedIds.length; i++) {
     var path = "/render?target=transformNull(summarize(stats.counters." + domain + ".Channels." + allowedIds[i] + ".Statuses.*.count,'1week'))&from=-1weeks&format=json";
     var raw = yield fetchData(path);
+    var failed = function () {
+      if (raw.data[0][0])
+        return raw.data[0][0]
+      return 0;    }
+
+    var successful = function () {
+      if (raw.data1[0][0])
+        return raw.data1[0][0]
+      return 0;
+    }
+
     data.push({
       _id : {"channelID": allowedIds[i] },
-      failed: raw.data[0][0] || 0,
-      successful: raw.data1[0][0] || 0,
+      failed: failed,
+      successful: successful,
       processing:0,
       completed:0,
       completedWErrors:0


Inline path to listSync call

Inline path to listSync call

--- src/module-cache.coffee
+++ src/module-cache.coffee
@@ -11,8 +11,7 @@
   ranges: {}

 loadDependencies = (modulePath, rootPath, rootMetadata, moduleCache) ->
-  nodeModulesPath = path.join(modulePath, 'node_modules')
-  for childPath in fs.listSync(nodeModulesPath)
+  for childPath in fs.listSync(path.join(modulePath, 'node_modules'))
     continue if path.basename(childPath) is '.bin'
     continue if rootPath is modulePath and rootMetadata.packageDependencies?.hasOwnProperty(path.basename(childPath))

@@ -40,7 +39,6 @@
   metadataPath = path.join(modulePath, 'package.json')
   return unless fs.isFileSync(metadataPath)

-  nodeModulesPath = path.join(modulePath, 'node_modules')
   dependencies = JSON.parse(fs.readFileSync(metadataPath))?.dependencies ? {}

   for name, version of dependencies
@@ -65,7 +63,7 @@
   if paths.length > 0 and Object.keys(dependencies).length > 0
     moduleCache.folders.push({paths, dependencies})

-  for childPath in fs.listSync(nodeModulesPath)
+  for childPath in fs.listSync(path.join(modulePath, 'node_modules'))
     continue if path.basename(childPath) is '.bin'
     continue if rootPath is modulePath and rootMetadata.packageDependencies?.hasOwnProperty(path.basename(childPath))


remove unused reference to projector

remove unused reference to projector

--- tests/infrastructure/projector.unit.coffee
+++ tests/infrastructure/projector.unit.coffee
@@ -1,5 +1,3 @@
-
-Projector = Space.eventSourcing.Projector

 describe 'Space.eventSourcing.Projector', ->


Fix list of user auto complete from server

--- packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee
+++ packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee
@@ -25,7 +25,7 @@
 			return console.error err

 		if results.users.length > 0
-			for result in results
+			for result in results.users
 				if records.length < 5
 					records.push
 						_id: result.username


Adds slug to vertical endpoint

Adds slug to vertical endpoint

--- api/apps/verticals/model.coffee
+++ api/apps/verticals/model.coffee
@@ -31,6 +31,7 @@
   featured_article_ids: @array().items(@objectId()).allow(null)
   start_at: @date().allow(null)
   end_at: @date().allow(null)
+  slug: @string().allow('',null)
 ).call Joi

 querySchema = (->


Change out of data message to something more accurate

--- app/controllers/classify.coffee
+++ app/controllers/classify.coffee
@@ -49,7 +49,7 @@
     else
       @html '''

-
Galaxy Zoo is currently down for maintenance—we're looking for more galaxies!

+
Thanks to all your hard work we've finished classifying everything for now. Please check back soon!

       '''
       setTimeout => @$('#classify').removeClass 'hidden'


fix bug

fix bug

--- app/controllers/settings.coffee
+++ app/controllers/settings.coffee
@@ -26,7 +26,6 @@
     url = Config.host + '/user/apple_sync_profile'
     url+='?oauth_token='+ Authorization.getToken()
     if window.cordova
-      @deleteToken()
       if window.device.platform.indexOf('Android')!=-1
         navigator.app.loadUrl url
       else


Fix tmp/restart.txt

Fix tmp/restart.txt

--- src/pow/server.coffee
+++ src/pow/server.coffee
@@ -43,7 +43,9 @@
     sys.pump app.pool.stderr, process.stdout

     fs.watchFile "#{root}/tmp/restart.txt", (curr, prev) ->
-      app.pool.quit()
+      fs.unlink "#{root}/tmp/restart.txt", (err) ->
+        if !err
+          app.pool.quit()

     app


Avoid issue of focus entirely, closes #183

--- app/partials/register-form.cjsx
+++ app/partials/register-form.cjsx
@@ -26,7 +26,6 @@
     email: 'Email address'
     emailConflict: 'An account with this address already exists'
     realName: 'Real name'
-    why: 'Why?'
     whyRealName: 'We’ll use this to give you credit in scientific papers, posters, etc'
     agreeToPrivacyPolicy: 'You agree to our %(link)s (required)'
     privacyPolicy: 'privacy policy'
@@ -41,7 +40,6 @@
   mixins: [PromiseToSetState]

   getInitialState: ->
-    whyRealName: false
     user: null
     badNameChars: null
     nameConflict: null
@@ -141,17 +139,12 @@

           <Translate content="registerForm.realName" />
-          <button type="button" className="secret-button" onClick={@setState.bind this, whyRealName: not @state.whyRealName, null}>
-            <Translate className="form-help info" content="registerForm.why" />
-            {if @state.whyRealName
-              <Tooltip attachment="middle right" targetAttachment="middle left">
-                <Translate content="registerForm.whyRealName" />
-              </Tooltip>}
-          </button>

         <input type="text" ref="realName" className="standard-input full" disabled={@state.user?} />
-
-
+        <Translate component="span" className="form-help info" content="registerForm.whyRealName" />
+
+
+


No CWD on browser

No CWD on browser

--- spec/Network.coffee
+++ spec/Network.coffee
@@ -630,6 +630,7 @@
       n = new noflo.Network g
       chai.expect(n.baseDir).to.equal root
     it 'should fall back to CWD if graph has no baseDir', ->
+      return @skip() if noflo.isBrowser()
       g = new noflo.Graph
       n = new noflo.Network g
       chai.expect(n.baseDir).to.equal process.cwd()


reverted develop config

reverted develop config

--- app/scripts/services/rdf.coffee
+++ app/scripts/services/rdf.coffee
@@ -3,10 +3,372 @@
 angular.module 'app'
   .factory 'Rdf', ->

-    baseUri: ''
+    # baseUri: ''
     subjectTemplate: ''
     propertyLiteralSelection: {}
     propertyLiteralTypes: {}
     selectedClasses: {}
     selectedProperties: {}
-    suggestions: {}
+    # suggestions: {}
+
+    baseUri: 'http://mycompany.com/datasets/'
+    # subjectTemplate: 'products/{ProductID}/{ProductName}'
+    # propertyLiteralSelection: {
+    #   'schema:productID': 'Typed Literal'
+    #   'dicom:ProductName': 'Typed Literal'
+    # }
+    # propertyLiteralTypes: {
+    #   'schema:productID': 'xsd:ID'
+    #   'dicom:ProductName': 'xsd:string'
+    # }
+
+    # selectedClasses : {
+    #   "products":[
+    #     {
+    #       "definition":[],
+    #       "prefixedName":["gr:BusinessEntity"],
+    #       "vocabulary.description":[],
+    #       "vocabulary.title":[],
+    #       "vocabulary.uri":["http://purl.org/goodrelations/v1#"],
+    #       "localName":["BusinessEntity"],
+    #       "label":["Business entity"],
+    #       "score":0.40066153,
+    #       "comment":["An instance of this class represents the legal agent making (or seeking) a particular offering. This can be a legal body or a person. A business entity has at least a primary mailing address and contact details. For this, typical address standards (vCard) and location data (geo, WGS84) can be attached. Note that the location of the business entity is not necessarily the location from which the product or service is being available (e.g. the branch or store). Use gr:Location for stores and branches.\n\t\t\nExample: Siemens Austria AG, Volkswagen Ltd., Peter Miller's Cell phone Shop LLC\n\nCompatibility with schema.org: This class is equivalent to the union of http://schema.org/Person and http://schema.org/Organization."],
+    #       "vocabulary.prefix":["gr"],
+    #       "uri":["http://purl.org/goodrelations/v1#BusinessEntity"]
+    #     },
+    #     {
+    #       "prefixedName":["gr:BusinessEntity2"]
+    #     },
+    #     {
+    #       "prefixedName":["gr:BusinessEntity3"]
+    #     }
+    #   ]
+    # }
+
+    # selectedProperties : {
+    #   "products":{
+    #     "ProductID":{
+    #       "definition":[],
+    #       "prefixedName":["schema:productID"],
+    #       "vocabulary.description":["Search engines including Bing, Google, Yahoo! and Yandex rely on schema.org markup to improve the display of search results, making it easier for people to find the right web pages."],
+    #       "vocabulary.title":["Schema.org vocabulary"],
+    #       "vocabulary.uri":["http://schema.org/"],
+    #       "localName":["productID"],
+    #       "label":["productID"],
+    #       "score":1,
+    #       "comment":["The product identifier, such as ISBN. For example: <meta itemprop='productID' content='isbn:123-456-789'/>."],
+    #       "vocabulary.prefix":["schema"],"uri":["http://schema.org/productID"]
+    #     },
+    #     "ProductName":{
+    #       "definition":[],
+    #       "prefixedName":["dicom:ProductName"],
+    #       "vocabulary.description":[],
+    #       "vocabulary.title":[],
+    #       "vocabulary.uri":["http://purl.org/healthcarevocab/v1#"],
+    #       "localName":["ProductName"],
+    #       "label":["Product Name"],
+    #       "score":1,"comment":[],
+    #       "vocabulary.prefix":["dicom"],
+    #       "uri":["http://purl.org/healthcarevocab/v1#ProductName"]
+    #     }
+    #   }
+    # }
+
+    suggestions:  {
+      "products": {
+          "table": {
+              "name": "products",
+              "recommend": [
+                  {
+                      "definition": [
+                          "This is the largest SuperType and includes any instance offered for sale or performed as a commercial service. Often physical object made by humans that is not a conceptual work or a facility, such as vehicles, cars, trains, aircraft, spaceships, ships, foods, beverages, clothes, drugs, weapons. Products also include the concept of 'state' (e/g/., on/off)"
+                      ],
+                      "prefixedName": [
+                          "umbel:Products"
+                      ],
+                      "vocabulary.description": [],
+                      "vocabulary.title": [],
+                      "vocabulary.uri": [
+                          "http://umbel.org/umbel#"
+                      ],
+                      "localName": [
+                          "Products"
+                      ],
+                      "label": [],
+                      "score": 0.5555555,
+                      "comment": [],
+                      "vocabulary.prefix": [
+                          "umbel"
+                      ],
+                      "uri": [
+                          "http://umbel.org/umbel#Products"
+                      ]
+                  },
+                  {
+                      "definition": [],
+                      "prefixedName": [
+                          "gr:Offering"
+                      ],
+                      "vocabulary.description": [],
+                      "vocabulary.title": [],
+                      "vocabulary.uri": [
+                          "http://purl.org/goodrelations/v1#"
+                      ],
+                      "localName": [
+                          "Offering"
+                      ],
+                      "label": [
+                          "Offering"
+                      ],
+                      "score": 0.44718835,
+                      "comment": [
+                          "An offering represents the public, not necessarily binding, not necessarily exclusive, announcement by a gr:BusinessEntity to provide (or seek) a certain gr:BusinessFunction for a certain gr:ProductOrService to a specified target audience. An offering is specified by the type of product or service or bundle it refers to, what business function is being offered (sales, rental, ...), and a set of commercial properties. It can either refer to \n(1) a clearly specified instance (gr:Individual),\n(2) to a set of anonymous instances of a given type (gr:SomeItems),\n(3) a product model specification (gr:ProductOrServiceModel), see also section 3.3.3 of the GoodRelations Technical Report. \n\nAn offering may be constrained in terms of the eligible type of business partner, countries, quantities, and other commercial properties. The definition of the commercial properties, the type of product offered, and the business function are explained in other parts of this vocabulary in more detail.\n\nExample: Peter Miller offers to repair TV sets made by Siemens, Volkswagen Innsbruck sells a particular instance of a Volkswagen Golf at $10,000.\n\nCompatibility with schema.org: This class is a superclass to http://schema.org/Offer, since gr:Offering can also represent demand."
+                      ],
+                      "vocabulary.prefix": [
+                          "gr"
+                      ],
+                      "uri": [
+                          "http://purl.org/goodrelations/v1#Offering"
+                      ]
+                  },
+                  {
+                      "definition": [],
+                      "prefixedName": [
+                          "gr:BusinessEntity"
+                      ],
+                      "vocabulary.description": [],
+                      "vocabulary.title": [],
+                      "vocabulary.uri": [
+                          "http://purl.org/goodrelations/v1#"
+                      ],
+                      "localName": [
+                          "BusinessEntity"
+                      ],
+                      "label": [
+                          "Business entity"
+                      ],
+                      "score": 0.40066153,
+                      "comment": [
+                          "An instance of this class represents the legal agent making (or seeking) a particular offering. This can be a legal body or a person. A business entity has at least a primary mailing address and contact details. For this, typical address standards (vCard) and location data (geo, WGS84) can be attached. Note that the location of the business entity is not necessarily the location from which the product or service is being available (e.g. the branch or store). Use gr:Location for stores and branches.\n\t\t\nExample: Siemens Austria AG, Volkswagen Ltd., Peter Miller's Cell phone Shop LLC\n\nCompatibility with schema.org: This class is equivalent to the union of http://schema.org/Person and http://schema.org/Organization."
+                      ],
+                      "vocabulary.prefix": [
+                          "gr"
+                      ],
+                      "uri": [
+                          "http://purl.org/goodrelations/v1#BusinessEntity"
+                      ]
+                  }
+              ]
+          },
+          "columns": [
+              {
+                  "name": "ProductID",
+                  "recommend": [
+                      {
+                          "definition": [],
+                          "prefixedName": [
+                              "schema:productID"
+                          ],
+                          "vocabulary.description": [
+                              "Search engines including Bing, Google, Yahoo! and Yandex rely on schema.org markup to improve the display of search results, making it easier for people to find the right web pages."
+                          ],
+                          "vocabulary.title": [
+                              "Schema.org vocabulary"
+                          ],
+                          "vocabulary.uri": [
+                              "http://schema.org/"
+                          ],
+                          "localName": [
+                              "productID"
+                          ],
+                          "label": [
+                              "productID"
+                          ],
+                          "score": 1,
+                          "comment": [
+                              "The product identifier, such as ISBN. For example: <meta itemprop='productID' content='isbn:123-456-789'/>."
+                          ],
+                          "vocabulary.prefix": [
+                              "schema"
+                          ],
+                          "uri": [
+                              "http://schema.org/productID"
+                          ]
+                      }
+                  ]
+              },
+              {
+                  "name": "ProductName",
+                  "recommend": [
+                      {
+                          "definition": [],
+                          "prefixedName": [
+                              "dicom:ProductName"
+                          ],
+                          "vocabulary.description": [],
+                          "vocabulary.title": [],
+                          "vocabulary.uri": [
+                              "http://purl.org/healthcarevocab/v1#"
+                          ],
+                          "localName": [
+                              "ProductName"
+                          ],
+                          "label": [
+                              "Product Name"
+                          ],
+                          "score": 1,
+                          "comment": [],
+                          "vocabulary.prefix": [
+                              "dicom"
+                          ],
+                          "uri": [
+                              "http://purl.org/healthcarevocab/v1#ProductName"
+                          ]
+                      }
+                  ]
+              }
+          ]
+      },
+      "data.csv": {
+          "table": {
+              "name": "data.csv",
+              "recommend": [
+                  {
+                      "definition": [],
+                      "prefixedName": [
+                          "qb:Observation"
+                      ],
+                      "vocabulary.description": [
+                          "This vocabulary allows multi-dimensional data, such as statistics, to be published in RDF."
+                      ],
+                      "vocabulary.title": [],
+                      "vocabulary.uri": [
+                          "http://purl.org/linked-data/cube#"
+                      ],
+                      "localName": [
+                          "Observation"
+                      ],
+                      "label": [
+                          "Observation"
+                      ],
+                      "score": 0.9631673,
+                      "comment": [
+                          "A single observation in the cube, may have one or more associated measured values"
+                      ],
+                      "vocabulary.prefix": [
+                          "qb"
+                      ],
+                      "uri": [
+                          "http://purl.org/linked-data/cube#Observation"
+                      ]
+                  }
+              ]
+          },
+          "columns": [
+              {
+                  "name": "TIME",
+                  "recommend": [
+                      {
+                          "definition": [],
+                          "prefixedName": [
+                              "nsl:time"
+                          ],
+                          "vocabulary.description": [],
+                          "vocabulary.title": [],
+                          "vocabulary.uri": [
+                              "http://purl.org/ontology/storyline/"
+                          ],
+                          "localName": [
+                              "time"
+                          ],
+                          "label": [
+                              "time"
+                          ],
+                          "score": 0.5555555,
+                          "comment": [
+                              "The time of a slot. A Temporal entity, an interval. Allows slots to be ordered temporally."
+                          ],
+                          "vocabulary.prefix": [
+                              "nsl"
+                          ],
+                          "uri": [
+                              "http://purl.org/ontology/storyline/time"
+                          ]
+                      }
+                  ]
+              },
+              {
+                  "name": "UNIT",
+                  "recommend": [
+                      {
+                          "definition": [],
+                          "prefixedName": [
+                              "msr:unit"
+                          ],
+                          "vocabulary.description": [
+                              "The Measurement Ontology is an ontology in which measurements may be rendered"
+                          ],
+                          "vocabulary.title": [
+                              "Measurement Ontology"
+                          ],
+                          "vocabulary.uri": [
+                              "http://www.telegraphis.net/ontology/measurement/measurement#"
+                          ],
+                          "localName": [
+                              "unit"
+                          ],
+                          "label": [
+                              "unit"
+                          ],
+                          "score": 0.7051012,
+                          "comment": [],
+                          "vocabulary.prefix": [
+                              "msr"
+                          ],
+                          "uri": [
+                              "http://www.telegraphis.net/ontology/measurement/measurement#unit"
+                          ]
+                      }
+                  ]
+              },
+              {
+                  "name": "Value",
+                  "recommend": [
+                      {
+                          "definition": [],
+                          "prefixedName": [
+                              "rdf:value"
+                          ],
+                          "vocabulary.description": [
+                              "This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts.",
+                              "This schema describes games with a known state, and few or no random elements."
+                          ],
+                          "vocabulary.title": [
+                              "The RDF Concepts Vocabulary"
+                          ],
+                          "vocabulary.uri": [
+                              "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+                          ],
+                          "localName": [
+                              "value"
+                          ],
+                          "label": [
+                              "value"
+                          ],
+                          "score": 0.7564898,
+                          "comment": [
+                              "Idiomatic property used for structured values."
+                          ],
+                          "vocabulary.prefix": [
+                              "rdf"
+                          ],
+                          "uri": [
+                              "http://www.w3.org/1999/02/22-rdf-syntax-ns#value"
+                          ]
+                      }
+                  ]
+              }
+          ]
+      }
+  }


Fixed bug in the instrumentation target.

The target now works recursively.

--- app/templates/_Gruntfile.coffee
+++ app/templates/_Gruntfile.coffee
@@ -44,7 +44,7 @@
       tasks: ['jshint','mochaTest']

     instrument:
-      files: './lib/*.js'
+      files: './lib/**/*.js'
       options:
         basePath : lcovInstrumentDir


replace_placeholders() gives HTML so use $.html() instead of $.text()

--- bokehjs/src/coffee/tool/inspectors/hover_tool.coffee
+++ bokehjs/src/coffee/tool/inspectors/hover_tool.coffee
@@ -213,7 +213,7 @@
         else
           value = value.replace("$~", "$data_")
           value = Util.replace_placeholders(value, ds, i, vars)
-          td.append($('<span>').text(value))
+          td.append($('<span>').html(value))

         row.append(td)
         table.append(row)


minor refactor to Sunrise class

minor refactor to Sunrise class

--- js/sunrise.coffee
+++ js/sunrise.coffee
@@ -1,11 +1,11 @@
 class Sunrise
   constructor: (moment_instance) ->
-    dst = moment(moment_instance).hour(12).isDST()
+    dst_offset = if moment(moment_instance).hour(12).isDST() then 1 else 0
     hebrew_date = new HebrewDate(moment_instance.toDate())
     this_year_sunrises = window.sunrises["#{hebrew_date.year}"]
     doy = hebrew_date.day_of_year()
     doy += this_year_sunrises.length if doy < 0
-    @sunrise = moment(this_year_sunrises[doy], 'h:mm:ss').add('hours', if dst then 1 else  0).year(moment_instance.year()).month(moment_instance.month()).date(moment_instance.date())
+    @sunrise = moment(this_year_sunrises[doy], 'h:mm:ss').add('hours', dst_offset).year(moment_instance.year()).month(moment_instance.month()).date(moment_instance.date())
   get: -> @sunrise

 window.Sunrise = Sunrise


removed unnecessart shims from marionette in runnder file

--- specs/runner.coffee
+++ specs/runner.coffee
@@ -18,16 +18,10 @@

     'jade': '../vendor/scripts/runtime'
   shim:
+    'marionette':
+      deps: ['backbone']
     'bootstrap':
       deps: ['jquery']
-    'marionette':
-      deps: [
-        'backbone'
-        'backbone.routefilter'
-        'backbone.stickit'
-        'backbone-validation'
-        'bootstrap'
-      ]
     'templates':
       deps: ['jade']


update the img src after upload

update the img src after upload

--- src/scripts/configs/aloha.coffee
+++ src/scripts/configs/aloha.coffee
@@ -77,8 +77,12 @@

       assorted:
         image:
+          # Do not send the image in the POST body (use uploadfield instead)
           uploadSinglepart: false
-          parseresponse: false
+          # Use the body of the response as the URL
+          parseresponse: (xhr) ->
+            return xhr.response
+          # Send files using the `file` field when POSTing
           uploadfield: 'file'
           uploadurl: "#{location.origin}/resources"


Changing the method names to make them a little better

--- src/scripts/elasticsearch.coffee
+++ src/scripts/elasticsearch.coffee
@@ -2,11 +2,11 @@
 #   Get ElasticSearch Cluster Information
 #
 # Commands:
-#   hubot: elasticsearch cluster [cluster] - Gets the cluster information for the given server or alias
+#   hubot: elasticsearch cluster health [cluster] - Gets the cluster health for the given server or alias
 #   hubot: elasticsearch cat nodes [cluster] - Gets the information from the cat nodes endpoint for the given server or alias
 #   hubot: elasticsearch cat indexes [cluster] - Gets the information from the cat indexes endpoint for the given server or alias
 #   hubot: elasticsearch clear cache [cluster] - Clears the cache for the specified cluster
-#   hubot: elasticsearch cluster-settings [cluster] - Gets a list of all of the settings stored for the cluster
+#   hubot: elasticsearch cluster settings [cluster] - Gets a list of all of the settings stored for the cluster
 #   hubot: elasticsearch disable allocation [cluster] - disables shard allocation to allow nodes to be taken offline
 #   hubot: elasticsearch enable allocation [cluster] - renables shard allocation
 #   hubot: elasticsearch show aliases - shows the aliases for the list of ElasticSearch instances
@@ -29,7 +29,7 @@
     if robot.brain.data.elasticsearch_aliases?
       _esAliases = robot.brain.data.elasticsearch_aliases

-  cluster_health = (msg, alias) ->
+  clusterHealth = (msg, alias) ->
     cluster_url = _esAliases[alias]

     if cluster_url == "" || cluster_url == undefined
@@ -43,7 +43,7 @@
           number_of_nodes = json['number_of_nodes']
           msg.send "Cluster: #{cluster_url} \nStatus: #{status} \n Nodes: #{number_of_nodes}"

-  cat_nodes = (msg, alias) ->
+  catNodes = (msg, alias) ->
     cluster_url = _esAliases[alias]

     if cluster_url == "" || cluster_url == undefined
@@ -57,7 +57,7 @@
           list   = [header].concat(lines.sort().reverse()).join("\n")
           msg.send("/code #{list}")

-  cat_indexes = (msg, alias) ->
+  catIndexes = (msg, alias) ->
     cluster_url = _esAliases[alias]

     if cluster_url == "" || cluster_url == undefined
@@ -157,28 +157,28 @@
     if msg.message.user.id is robot.name
       return

-    cat_nodes msg, msg.match[1], (text) ->
+    catNodes msg, msg.match[1], (text) ->
       msg.send text

   robot.hear /elasticsearch cat indexes (.*)/i, (msg) ->
     if msg.message.user.id is robot.name
       return

-    cat_indexes msg, msg.match[1], (text) ->
+    catIndexes msg, msg.match[1], (text) ->
       msg.send text

-  robot.hear /elasticsearch cluster-settings (.*)/i, (msg) ->
+  robot.hear /elasticsearch cluster settings (.*)/i, (msg) ->
     if msg.message.user.id is robot.name
       return

     showClusterSettings msg, msg.match[1], (text) ->
       msg.send(text)

-  robot.hear /elasticsearch cluster (.*)/i, (msg) ->
-    if msg.message.user.id is robot.name
-      return
-
-    cluster_health msg, msg.match[1], (text) ->
+  robot.hear /elasticsearch cluster health (.*)/i, (msg) ->
+    if msg.message.user.id is robot.name
+      return
+
+    clusterHealth msg, msg.match[1], (text) ->
       msg.send text

   robot.hear /elasticsearch show aliases/i, (msg) ->


Refactor perf measurements to be smarter

--- js-library/app/js/jail_iframe/classes/performance_measurement.coffee
+++ js-library/app/js/jail_iframe/classes/performance_measurement.coffee
@@ -27,13 +27,13 @@
     ).join('\n')

 FactlinkJailRoot.core_loaded_promise.then( ->
+  FactlinkJailRoot.delay 1000
+).then( ->
+  console.log document.readyState
   if window.performance && window.performance.timing
     'fetchStart responseEnd domLoading domInteractive domContentLoadedEventEnd domComplete loadEventEnd'
-      .split(' ').forEach (timing_event) ->
-        add_existing_timing_event timing_event, window.performance.timing[timing_event]
-).then( ->
-  FactlinkJailRoot.delay 1000
-).then( ->
+    .split(' ').forEach (timing_event) ->
+      add_existing_timing_event timing_event, window.performance.timing[timing_event]
   if FactlinkJailRoot.can_haz.log_jslib_loading_performance
     console.log get_perf_summary()
 )


local_hub: ubuntu 16.04 on GCP names the NIC ens4 -- formerly eth0

--- src/smc-project/local_hub.coffee
+++ src/smc-project/local_hub.coffee
@@ -112,7 +112,10 @@
         host = 'localhost'
     else
         # what we want for the Google Compute engine deployment
-        host = require('os').networkInterfaces().eth0?[0].address
+        # earlier, there was eth0, but newer Ubuntu's on GCP have ens4
+        nics = require('os').networkInterfaces()
+        mynic = nics.eth0 ? nics.ens4
+        host = mynic?[0].address
     base_url = process.env.SMC_BASE_URL ? ''
     port     = 22
     INFO =


minor further tweaks

minor further tweaks

--- src/smc-webapp/landing_page.cjsx
+++ src/smc-webapp/landing_page.cjsx
@@ -77,7 +77,7 @@
             size = '2x'
         style = misc.copy(@styles[name])
         style.display = 'inline-block'
-        style.padding = '8px'
+        style.padding = '6px'
         style.borderRadius = '50%'
         style.width = '50px'
         style.height=  '50px'
@@ -85,7 +85,7 @@
         style.textAlign = 'center'
         cname = misc.capitalize(name)
         title = <Icon name={name} /> {cname}
-
+
             <Tip placement='bottom' title={title} tip={"Use #{cname} to sign into your CoCalc account instead of an email address and password."}>
                 <Icon name={name} style={style} />
             </Tip>
@@ -98,7 +98,7 @@

     render: ->
         strategies = @props.strategies?.toJS() ? []
-        # strategies = ['facebook', 'google', 'twitter', 'github']   # for testing.
+        ## strategies = ['facebook', 'google', 'twitter', 'github']   # for testing.

             {@render_heading()}


improve interface to worker module

improve interface to worker module


sort commands

sort commands

--- lib/browse.coffee
+++ lib/browse.coffee
@@ -20,14 +20,14 @@
     @subscriptions = new CompositeDisposable

     # Register command that toggles this view
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:.apm-folder": => @apmFolder()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:application-folder": => @appFolder()
     @subscriptions.add atom.commands.add "atom-workspace", "#{name}:configuration-folder": => @browseConfig()
     @subscriptions.add atom.commands.add "atom-workspace", "#{name}:packages-folder": => @browsePackages()
     @subscriptions.add atom.commands.add "atom-workspace", "#{name}:project-folders": => @browseProjects()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-all-open-files": => @revealFiles()
     @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-file": => @revealFile()
-    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-all-open-files": => @revealFiles()
     @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-file-from-tree-view": => @revealFileFromTreeview()
-    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:application-folder": => @appFolder()
-    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:.apm-folder": => @apmFolder()

   deactivate: ->
     @subscriptions?.dispose()


Make route dynamic

Make route dynamic

--- src/routes/index.coffee
+++ src/routes/index.coffee
@@ -30,8 +30,9 @@
 router.post '/wage_theft/report', (req, res) ->
   form = {}

-  for entityKey,entity of req.body
-    for fieldKey, field of req.body
+  for entityKey, entity of req.body
+    for fieldKey, field of entity
+      debug "#{entityKey} #{fieldKey} #{wageTheftReportInfo.mapping[entityKey][fieldKey]}"
       form[wageTheftReportInfo.mapping[entityKey][fieldKey]] = field

   request.post {url: wageTheftReportInfo.post_url, form: form}, (err, httpResponse, body) ->


hubot-spot is very intelligent about versioning

--- src/scripts/spot.coffee
+++ src/scripts/spot.coffee
@@ -29,11 +29,59 @@
 #   hubot last find - Pulls up the most recent find query
 # Authors:
 #   mcminton, andromedado
-VERSION = '1.3.3'
+https = require 'https'
+
+VERSION = '1.3.4'

 URL = "#{process.env.HUBOT_SPOT_URL}"

 CAMPFIRE_CHRONOLOGICAL_DELAY = 700
+
+getCurrentVersion = (callback) ->
+  https.get('https://raw.github.com/1stdibs/hubot-scripts/master/src/scripts/spot.coffee', (res) ->
+    data = ''
+    res.on('data', (d) ->
+      data += d
+    )
+    res.on('end', () ->
+      bits = data.match(/VERSION = '([\d\.]+)'/)
+      version = bits && bits[1]
+      callback(!version, version)
+    )
+  ).on('error', (e) ->
+    callback(e);
+  )
+
+compareVersions = (base, comparator) ->
+  if (base == comparator)
+    return 'up-to-date'
+  re = /^(\d+)(\.(\d+))?(\.(\d+))?/
+  bParts = base.match(re)
+  cParts = comparator.match(re)
+  diff = false
+  if (bParts && cParts)
+    [{k : 1, n : 'major version'}, {k : 3, n : 'minor version'}, {k : 5, n : 'patch', pn : 'patches'}].forEach((obj) ->
+      diff = diff || comparePart(bParts[obj.k], cParts[obj.k], obj.n, obj.pn);
+    )
+  if (!diff)
+    diff = 'different than the repo version: ' + base
+  return diff
+
+comparePart = (b, c, partName, partNamePlural) ->
+  if (b == c)
+    return false
+  diff = Math.abs(Number(c) - Number(b))
+  if (Number(c) > Number(b))
+    stem = 'ahead'
+    suffix = '; the repo should probably be updated.'
+  else
+    stem = 'behind'
+    suffix = '; you should probably update me. https://github.com/1stdibs/hubot-scripts'
+  if (diff == 1)
+    whats = partName
+  else
+    whats = partNamePlural || (partName + 's')
+  return stem + ' by ' + diff + ' ' + whats + suffix

 spotRequest = (message, path, action, options, callback) ->
   message.http("#{URL}#{path}")
@@ -290,6 +338,11 @@
       message.send("Spot volume set to #{body}. :mega:")

   robot.respond /spot version\??/i, (message) ->
-    message.send(':small_blue_diamond: Well, ' + message.message.user.name + ', my Spot version is presently ' + VERSION)
-
-
+    getCurrentVersion((e, repoVersion) ->
+      msg = ':small_blue_diamond: Well, ' + message.message.user.name + ', my Spot version is presently ' + VERSION
+      if (!e)
+        msg += '; I am ' + compareVersions(repoVersion, VERSION)
+      message.send msg
+    )
+
+


Slow down some of the front end refresh times to avoid rate limit issues

--- static/coffee/controllers.coffee
+++ static/coffee/controllers.coffee
@@ -6,10 +6,10 @@

 # Component refresh intervals
-INTERVAL_MESSAGES_NEW = 15000
-INTERVAL_CASES_NEW = 5000
+INTERVAL_MESSAGES_NEW = 30000
+INTERVAL_CASES_NEW = 10000
 INTERVAL_CASE_INFO = 10000
-INTERVAL_CASE_TIMELINE = 10000
+INTERVAL_CASE_TIMELINE = 30000

 INFINITE_SCROLL_MAX_ITEMS = 1000


Prototyping event system

Prototyping event system

--- lib/docpad.coffee
+++ lib/docpad.coffee
@@ -1,5 +1,5 @@
 ###
-Docpad by Benjamin Lupton
+DocPad by Benjamin Lupton
 Intuitive Web Development
 ###

@@ -7,16 +7,21 @@
 fs = require 'fs'
 path = require 'path'
 sys = require 'util'
+child_process = require 'child_process'
+EventEmitter = require('events').EventEmitter
+
 caterpillar = require 'caterpillar'
 util = require 'bal-util'
-child_process = require('child_process')
+_ = require 'underscore'
+
 growl = null
 express = null
 watch = null
 queryEngine = null
-_ = require 'underscore'
+
 PluginLoader = require "#{__dirname}/plugin-loader.coffee"
 require "#{__dirname}/prototypes.coffee"
+
 exec = (commands,options,callback) ->
 	# Sync
 	tasks = new util.Group callback
@@ -33,9 +38,9 @@

 # -------------------------------------
-# Docpad
-
-class Docpad
+# DocPad
+
+class DocPad extends EventEmitter
 	# Configurable
 	config:
 		# Plugins
@@ -45,16 +50,24 @@
 			rest: false
 		plugins: {}

-		# Skeletons
-		skeleton: 'kitchensink',
-		skeletons:
-			kitchensink:
-				repo: 'https://github.com/balupton/kitchensink.docpad.git'
+		# Exchange
+		exchange:
+			# Skeletons
+			skeletons:
+				kitchensink:
+					repo: 'https://github.com/balupton/kitchensink.docpad.git'
+					description: 'A skeleton that includes everything'
+				canvas:
+					repo: 'https://github.com/balupton/canvas.docpad.git'
+					description: 'A blank canvas for docpad'
+			# Plugins
+			plugins: {}

 		# DocPad Paths
 		corePath: "#{__dirname}/.."
 		libPath: "#{__dirname}"
 		mainPath: "#{__dirname}/docpad.coffee"
+		pluginPath: "#{__dirname}/plugin.coffee"

 		# Website Paths
 		rootPath: null
@@ -76,7 +89,7 @@
 		growl: true
 		checkVersion: true

-	# Docpad
+	# DocPad
 	version: null
 	server: null
 	logger: null
@@ -117,7 +130,7 @@
 		config.corePath or= @config.corePath
 		config.rootPath or= process.cwd()

-		# Docpad Configuration
+		# DocPad Configuration
 		docpadPackagePath = "#{config.corePath}/package.json"
 		docpadPackageData = {}
 		if path.existsSync docpadPackagePath
@@ -1065,9 +1078,9 @@

 # API
 docpad =
-	Docpad: Docpad
+	DocPad: DocPad
 	createInstance: (config) ->
-		return new Docpad(config)
+		return new DocPad(config)

 # Export
 module.exports = docpad


Adding needed primitive enhancement to String to support startsWith method

--- lib/docpad.coffee
+++ lib/docpad.coffee
@@ -39,6 +39,8 @@
 		pad(@getUTCMinutes())+':'+
 		pad(@getUTCSeconds())+'Z'

+String::startsWith = (prefix) ->
+	return @indexOf(prefix) is 0

 # -------------------------------------
 # Main


daily

daily

--- lib/export.coffee
+++ lib/export.coffee
@@ -1,17 +0,0 @@
-###
- *
- * export ash
- *
-###
-do (root=@, factory=(-> ash)) ->
-  'use strict'
-  ###
-   * Export ash - umd header
-  ###
-  if 'function' is typeof define and define.amd
-    define factory
-  else if 'object' is typeof exports
-    module.exports = factory()
-  else
-    root['ash'] = factory()
-  return


remove step from game object default events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -13,6 +13,7 @@

   self.bind "update", (elapsedTime) ->
     for event in I.everyEvents
+      {fn, per}
       while (event.lastFired) < I.age + elapsedTime
         sendOrApply(fn)
         event.lastFired += event.period


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -23,8 +23,8 @@

   @name every
   @methodOf TimedEvents#
-  @param {Number} n The number of frames to wait before executing the callback
-  @param {Function} fn The code to execute after the number of frames has passed
+  @param {Number} n Number of frames to wait before executing the callback
+  @param {Function} fn Code to execute after the number of frames has passed
   ###
   every: (n, fn) ->
     if I.age.mod(n) is 0


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -6,7 +6,7 @@

 player.include TimedEvents

-# doSomething
+# doSomething is called every 4 frames
 player.every 4, ->
   doSomething()
 </pre></code>


revert default port to 9001

revert default port to 9001

--- src/tracker/reki.coffee
+++ src/tracker/reki.coffee
@@ -257,6 +257,6 @@
           j+=2
         return simple_response res, {files}

-port = parseInt(process.argv[2]) || 9002
+port = parseInt(process.argv[2]) || 9001
 console.log ('Starting tracker on 127.0.0.1:' + port + '...')
 new Tracker port


Cleaned up the main levels module

Cleaned up the main levels module

--- lib/levels.coffee
+++ lib/levels.coffee
@@ -1,14 +1,10 @@
+levelsConfig     = require './levels-config'
+levelsServices   = require './levels-services'
 workspaceManager = require('./workspace-manager').getInstance()

-levelsConfig     = require('./levels-config')
-levelsServices   = require('./levels-services')
-
-# ------------------------------------------------------------------------------
-
 module.exports =
-
   activate: (state) ->
-    workspaceManager.setUpWorkspace(state)
+    workspaceManager.setUpWorkspace state
     workspaceManager.activateEventHandlers()
     workspaceManager.activateCommandHandlers()

@@ -17,22 +13,13 @@
     workspaceManager.deactivateEventHandlers()
     workspaceManager.deactivateCommandHandlers()

-  ## Configuration -------------------------------------------------------------
-
   config: levelsConfig

-  ## Provided services ---------------------------------------------------------
-
-  provideLevels: levelsServices.provideLevels
-
-  ## Consumed services ---------------------------------------------------------
+  provideLevels: ->
+    levelsServices.provideLevels()

   consumeStatusBar: (statusBar) ->
-    workspaceManager.consumeStatusBar(statusBar)
-
-  ## Serialization -------------------------------------------------------------
+    workspaceManager.consumeStatusBar statusBar

   serialize: ->
-    workspaceManager.serializeWorkspace()
-
-# ------------------------------------------------------------------------------
+    workspaceManager.serializeWorkspace()


:art: simplify

:art: simplify

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -962,9 +962,7 @@
     @rows.filter(isValidRow)

   detectRow: (cursor) ->
-    for row in @getScanRows(cursor)
-      return row
-    null
+    @getScanRows(cursor)[0]

   moveCursor: (cursor) ->
     @countTimes =>


Copy dev dependencies to application directory

--- tasks/build-task.coffee
+++ tasks/build-task.coffee
@@ -30,7 +30,6 @@
       directory = path.join('node_modules', child)
       try
         {name, engines} = grunt.file.readJSON(path.join(directory, 'package.json'))
-        continue if devDependencies[name]?
         if engines?.atom?
           packageDirectories.push(directory)
         else


Remove trailing slash

Remove trailing slash

--- tasks/build-task.coffee
+++ tasks/build-task.coffee
@@ -15,7 +15,7 @@
     if process.platform is 'darwin'
       cp 'atom-shell/Atom.app', shellAppDir
     else if process.platform is 'win32'
-      cp 'atom-shell/', shellAppDir
+      cp 'atom-shell', shellAppDir

     mkdir appDir


Better constantize

Better constantize

--- test/core_object.coffee
+++ test/core_object.coffee
@@ -61,6 +61,6 @@
   equals o.test2, "coolio"

 test "#include string", ->
-
+  window

 module undefined


GlobalNotification: minor fix

GlobalNotification: minor fix

--- client/Main/maincontroller/mainviews/mainview.coffee
+++ client/Main/maincontroller/mainviews/mainview.coffee
@@ -264,7 +264,7 @@
     KD.utils.wait 2000, =>
       KD.remote.api.JSystemStatus.getCurrentSystemStatuses (err, statuses)=>
         if err then log 'current system status:',err
-        else
+        else if statuses and Array.isArray statuses
           {daisy} = Bongo
           queue   = statuses.map (status)=>=>
             @createGlobalNotification status


activity: code cleaning

activity: code cleaning

--- client/Social/Activity/views/activitylistitem.coffee
+++ client/Social/Activity/views/activitylistitem.coffee
@@ -155,37 +155,6 @@
     @unsetClass 'editing'
     list = @getDelegate()
     list.emit 'EditMessageReset'
-
-
-  # setAnchors: ->
-
-  #   @$("article a").each (index, element) ->
-  #     {location: {origin}} = window
-  #     href = element.getAttribute "href"
-  #     return  unless href
-
-  #     beginning = href.substring 0, origin.length
-  #     rest      = href.substring origin.length + 1
-
-  #     if beginning is origin
-  #       element.setAttribute "href", "/#{rest}"
-  #       element.classList.add "internal"
-  #       element.classList.add "teamwork"  if rest.match /^Teamwork/
-  #     else
-  #       element.setAttribute "target", "_blank"
-
-
-  # click: (event) ->
-
-  #   {target} = event
-
-  #   if $(target).is "article a.internal"
-  #     @utils.stopDOMEvent event
-  #     href = target.getAttribute "href"
-
-  #     if target.classList.contains("teamwork") and KD.singleton("appManager").get "Teamwork"
-  #     then window.open "#{window.location.origin}#{href}", "_blank"
-  #     else KD.singleton("router").handleRoute href

   showResend: ->