re-open team after someone left it

re-open team after someone left it

--- both/methods/shift/shiftSchedule.coffee
+++ both/methods/shift/shiftSchedule.coffee
@@ -40,7 +40,7 @@
 									'teams.$.pending': _id: participant._id
 								$addToSet: 'teams.$.declined': participant

-						Meteor.call 'closeTeam', shiftId, teamId
+						Meteor.call 'openTeam', shiftId, teamId

 	approveRequest: (shiftId, teamId, userId) ->
 		shift = Shifts.findOne shiftId, fields: teams: 1, tagId: 1, projectId: 1


Chat: call correct format content method

--- client/Social/Activity/views/privatemessage/listitem.coffee
+++ client/Social/Activity/views/privatemessage/listitem.coffee
@@ -54,7 +54,7 @@
         {{> @author}} {{> @timeView }} {{> @timeAgoView}} {{> @likeView}}
       </div>
       {{> @editWidgetWrapper}}
-      {article{@formatContent #(body)}}
+      {article{KD.utils.formatContent #(body)}}
       {{> @embedBox}}
     </div>
     """


JStackTemplate::clone helper to clone and create a new stack template with same data

--- workers/social/lib/social/models/computeproviders/stacktemplate.coffee
+++ workers/social/lib/social/models/computeproviders/stacktemplate.coffee
@@ -48,6 +48,8 @@
           (signature String, Function)
         update        :
           (signature Object, Function)
+        clone         :
+          (signature Function)

     sharedEvents      :
       static          : [ ]
@@ -145,6 +147,7 @@
         if err
         then callback new KodingError 'Failed to save stack template', err
         else callback null, stackTemplate
+

   @some$: permit 'list stack templates',

@@ -240,6 +243,37 @@
         data.template.details.lastUpdaterId = delegate.getId()

       @update { $set: data }, (err) => callback err, this
+
+
+  clone: permit
+
+    advanced: [
+      { permission: 'update own stack template', validateWith: Validators.own }
+      { permission: 'update stack template' }
+    ]
+
+    success: (client, callback) ->
+
+      cloneData         =
+        title           : @getAt 'title'
+        description     : @getAt 'description'
+
+        config          : @getAt 'config'
+        machines        : @getAt 'machines'
+        credentials     : @getAt 'credentials'
+
+        template        : @getAt 'template.content'
+        rawContent      : @getAt 'template.rawContent'
+        templateDetails : @getAt 'template.details'
+
+      cloneData.config           ?= {}
+      cloneData.config.clonedFrom = @getId()
+
+      # TODO make sure to clone custom credentials as well ~ GG
+
+      JStackTemplate.create client, cloneData, (err, cloneStackTemplate) ->
+        if err then callback new KodingError 'Clone failed', err
+        else callback null, cloneStackTemplate

 # Base StackTemplate example for koding group


rollbar: add concerns; mixpanel: minor fix

--- client/ide/filetree/controllers/findertreecontroller.coffee
+++ client/ide/filetree/controllers/findertreecontroller.coffee
@@ -140,10 +140,10 @@
       unless silence
         if err?.message?.match /permission denied/i
           message = "Permission denied!"
-          KD.logToExternal "Couldn't fetch files, permission denied"
+          KD.logToExternal "filetree: Couldn't fetch files, permission denied"
         else
           message = "Couldn't fetch files! Click to retry"
-          KD.logToExternalWithTime "Couldn't fetch files"
+          KD.logToExternalWithTime "filetree: Couldn't fetch files"
         @notify message, 'clickable', \
                 """Sorry, a problem occured while communicating with servers,
                    please try again later.""", yes


fixed coffeelint errors on workers/social/lib/social/models/payment/product.coffee

--- workers/social/lib/social/models/payment/product.coffee
+++ workers/social/lib/social/models/payment/product.coffee
@@ -1,3 +1,4 @@
+# coffeelint: disable=no_implicit_braces
 JPaymentBase = require './base'

 module.exports = class JPaymentProduct extends JPaymentBase
@@ -87,13 +88,13 @@
       tags
     }

-    product.save (err) =>
+    product.save (err) ->
       return callback err  if err

       product.savePlanToRecurly (err, plan) ->
         return callback err  if err

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

           group.addProduct product, (err) ->
@@ -115,3 +116,5 @@
       recurly.createPlan planData, callback

     else process.nextTick -> callback null
+
+


Decode redirections.

Decode redirections.

--- background.coffee
+++ background.coffee
@@ -98,11 +98,26 @@
     chrome.pageAction.hide sender.tab.id
   false # We will not be calling sendResponse.

-open = ({ url }, sender) ->
-  chrome.tabs.getAllInWindow null, (tabs) ->
-    chrome.tabs.getSelected null, (tab) ->
-      chrome.tabs.create url: url, index: tab.index + 1, openerTabId: tab.id
-  false # We will not be calling sendResponse.
+open = do ->
+  removeRedirection = do ->
+    matcher = new RegExp "[&?].*\=(https?%3A%2F%2F[a-zA-Z0-9][^&]*)", "i"
+
+    (url) ->
+      match = matcher.exec url
+      if match and match[1]
+        try
+          decodeURIComponent match[1]
+        catch
+          console.error "Failed to URI decode: #{match[1]}"
+          url
+      else
+        url
+
+  ({ url }, sender) ->
+    chrome.tabs.getAllInWindow null, (tabs) ->
+      chrome.tabs.getSelected null, (tab) ->
+        chrome.tabs.create url: removeRedirection(url), index: tab.index + 1, openerTabId: tab.id
+    false # We will not be calling sendResponse.

 do ->
   handlers =


NEW: exportedStructure

NEW: exportedStructure

--- source/Art/Engine/Core/ElementBase.coffee
+++ source/Art/Engine/Core/ElementBase.coffee
@@ -1,5 +1,4 @@
 Atomic = require 'art-atomic'
-Foundation = require 'art-foundation'
 {elementFactory} = require "./ElementFactory"
 EventedEpochedObject = require './EventedEpochedObject'

@@ -12,7 +11,10 @@
   inspectLean
   compact
   isObject
-} = Foundation
+  object
+  w
+} = require 'art-standard-lib'
+{Bitmap} = require 'art-canvas'

 ###
 ElementBase adds:
@@ -191,8 +193,16 @@

     inspectedString: -> @inspectedName

-  inspectedPropsNotToInclude = ["children", "name", "on"]
-  inspectedPropsFirst = ["key", "instanceId", "location", "size", "currentLocation", "currentSize"]
+  inspectedPropsNotToInclude = w rawDNI = "pages children name on parent"
+  inspectedPropsFirst = w "key instanceId location size currentLocation currentSize"
+  exportedPropsFirst = w "key location size"
+  dontExportProps = w "#{rawDNI} currentLocation currentSize currentPadding elementToParentMatrix"
+  exportProp = (value) ->
+    if value.constructor == Bitmap
+      ["Bitmap", value.size.exportedValue]
+    else
+      value && value.initializer ? value.exportedValue ? value.plainObjects ? value
+
   @getter
     inspectedPropsMaps: ->
       props = {}
@@ -200,19 +210,37 @@
         props[k] = value

       for k, {internalName, virtual, defaultValue} of @metaProperties when !virtual and
-          k not in inspectedPropsNotToInclude and
-          !EpochedObject.propsEq defaultValue, value = @[internalName]
-        props[k] = value
+          !(k in inspectedPropsNotToInclude) and
+          (!ElementBase.propsEq defaultValue, value = @[internalName]) and
+          k != "parent"
+
+        props[k] = exportProp value

       props

-    debugStructure: ->
+    exportedProps: ->
+      out = object @metaProperties,
+        into: object exportedPropsFirst,
+          when: (v, k) => present @[k]
+          with: (v, k) => exportProp @[k]
+
+        when: ({internalName, virtual, defaultValue}, k) =>
+          !virtual and
+          !(k in dontExportProps) and
+          !ElementBase.propsEq defaultValue, @[internalName]
+
+        with: ({internalName}) => exportProp @[internalName]
+      unless @parent
+        out.size ||= exportProp @currentSize
+      out
+
+    exportedStructure: ->
       result = [
-        @shortNamespacePath
-        @inspectedPropsMaps
+        @class.getName()
+        @exportedProps
       ]
       if @hasChildren
-        result = result.concat (child.debugStructure for child in @children)
+        result = result.concat (child.exportedStructure for child in @children)
       result

     plainObjectProps: ->


Add support for end_of_line

Add support for end_of_line

--- src/brave-mouse/validate.coffee
+++ src/brave-mouse/validate.coffee
@@ -2,6 +2,7 @@

 editorconfig = require 'editorconfig'
 detectIndent = require 'detect-indent'
+detectNewline = require 'detect-newline'

 module.exports = (filePath, callback) ->
 	editorconfig.parse(filePath)
@@ -29,6 +30,18 @@
 						expected: editorconfigProperties.indent_size
 						is: indentation.amount

+			if editorconfigProperties.end_of_line
+				newline = detectNewline fileContents
+
+				newline = 'lf' if newline is '\n'
+				newline = 'crlf' if newline is '\r\n'
+
+				if newline isnt editorconfigProperties.end_of_line and
+				newline
+					results.end_of_line =
+						expected: editorconfigProperties.end_of_line
+						is: newline
+
 			results = true if Object.keys(results).length is 0

 			callback null, results


Handle room deletion notifications

Handle room deletion notifications

--- src/coffee/control/index.coffee
+++ src/coffee/control/index.coffee
@@ -10,13 +10,9 @@
     $scope.notifications = {}

     leftRoom = (userId, roomId) ->
-      console.log userId+' left the room'
-      console.log 'i am '+me._id
       if userId == me._id
-        console.log 'i left a room'
         rooms.splice getRoomIndex(roomId), 1
         if $state.params._id == roomId
-          console.log 'but i\'m still there'
           $state.go 'index.chatter'
       else
         idx = getRoomIndex(roomId)
@@ -32,6 +28,10 @@
           leftRoom(message.userId, message.roomId)
         else if message.type == 'room-renamed'
           room.name = message.name
+        else if message.type == 'room-deleted'
+          rooms.splice getRoomIndex(room._id), 1
+          if $state.params._id == room._id
+            $state.go 'index.chatter'
         else
           if $state.params._id != room._id
             $scope.notifications[room._id]++


fix bug in manifest doc

fix bug in manifest doc

--- lib/generators/transponder/install/templates/manifest.coffee
+++ lib/generators/transponder/install/templates/manifest.coffee
@@ -2,7 +2,7 @@
   # fill in your manifest here
   # example:
   # if you want to trigger a service on your entire app
-  # $('body').trigger '<%= full_name.downcase %>:services:service_name'
+  # $('body').trigger '<%= file_name.downcase %>:services:service_name'
   #
   # If you want a more fine grained control for
   # different pages you can add a class to your body
@@ -13,12 +13,12 @@
   #
   # You now have a more fine grained control in
   # your manifest file
-  # $('body.posts.show').trigger '<%= full_name.downcase %>:services:service_name'
+  # $('body.posts.show').trigger '<%= file_name.downcase %>:services:service_name'
   #
   # if you need to trigger the same services on multiple pages
   # $('body.posts.show,
   #    body.dashboard.show,
-  #    body.photos.index').trigger '<%= full_name.downcase %>:services:service_name'
+  #    body.photos.index').trigger '<%= file_name.downcase %>:services:service_name'
   #

 run_ready = ->


ENHANCE: Add analytics for adding/removing comments

--- src/app/projects/partials/directives/view-comments-directive.coffee
+++ src/app/projects/partials/directives/view-comments-directive.coffee
@@ -9,7 +9,7 @@
   scope:
     project: "=project"
     task: "=task"
-  controller: ($scope, $modal, $state, TaskFeedback, TaskComment, Task, Project, taskService, alertService, projectService) ->
+  controller: ($scope, $modal, $state, TaskFeedback, TaskComment, Task, Project, taskService, alertService, projectService, analyticsService) ->
     #
     # Comment code
     #
@@ -36,6 +36,7 @@
             $scope.task.comments = []
           $scope.task.comments.unshift response
           $scope.comment.text = ""
+          analyticsService.event "View Task Comments", "Add new comment"
         (response) ->
           alertService.add("danger", response.data.error, 2000)

@@ -43,6 +44,7 @@
       TaskComment.delete { project_id: $scope.project.project_id, task_definition_id: $scope.task.task_definition_id, id: id },
         (response) ->
           $scope.task.comments = $scope.task.comments.filter (e) -> e.id != id
+          analyticsService.event "View Task Comments", "Delete existing comment"
         (response) ->
           alertService.add("danger", response.data.error, 2000)
-)+)


remove console.logs

remove console.logs

--- BackofficeBundle/Resources/public/coffee/tinyMCE/activateTinyMCE.coffee
+++ BackofficeBundle/Resources/public/coffee/tinyMCE/activateTinyMCE.coffee
@@ -12,13 +12,9 @@
           return
         ed.on 'postProcess', (e) ->
           if e.set
-            console.log "beforebbcode2" + e.content
             e.content = self.bbcodeToHtml e.content
-            console.log "afterbbcode2" + e.content
           if e.get
-            console.log "beforehtml2" + e.content
             e.content = self.htmlToBBcode e.content
-            console.log "afterhtml2" + e.content
           return
         ed.on 'submit', (e) ->
           e.content = self.htmlToBBcode e.content
@@ -32,9 +28,7 @@

       punbbConvert: (string, replacementList) ->
         string = tinymce.trim(string)
-        console.log string
         rep = (re, str) ->
-          console.log re + '  :  ' + str
           string = string.replace(new RegExp(re,'gi'), str)
           return
         for regex, str of replacementList


Correcting removing input/output links from a given node.

--- src/main/webapp/lib/extensions/Node.coffee
+++ src/main/webapp/lib/extensions/Node.coffee
@@ -92,9 +92,9 @@
   @get('type') is 'S'

 window.beats.Node::remove_input_output = (link) ->
-  if @has('inputs') and @get('inputs').size > 0
+  if @has('inputs') and @get('inputs').get('input').length > 0
     @get('inputs').set 'input', @inputs().filter (i) -> i.link() isnt link
-  if @has('outputs') and @get('outputs').size > 0
+  if @has('outputs') and @get('outputs').get('output').length > 0
     @get('outputs').set 'output', @outputs().filter (o) -> o.link() isnt link

 window.beats.Node::set_input = (link) ->


Forward disconnects

Forward disconnects

--- src/components/ReadGroup.coffee
+++ src/components/ReadGroup.coffee
@@ -16,5 +16,7 @@
       @outPorts.out.send @groups.join ':'
     @inPorts.in.on 'endgroup', =>
       @groups.pop()
+    @inPorts.in.on 'disconnect', =>
+      @outPorts.out.disconnect()

 exports.getComponent = -> new ReadGroup


Workspace: Fixed typo.

Workspace: Fixed typo.

--- client/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -95,7 +95,7 @@
       @displayBroadcastMessage message.data

     @broadcastMessage
-      title     : "#{@nickname} has joined the session"
+      title     : "#{@nickname} has joined to the session"
       sender    : @nickname

     @on "AllPanesAddedToPanel", (panel, panes) ->


Update calls to res.send to avoid use of deprecated res.send(body, status)

--- server/controllers/events.coffee
+++ server/controllers/events.coffee
@@ -115,12 +115,12 @@
 module.exports.delete = (req, res) ->
     req.event.destroy (err) ->
         if err?
-            res.send error: "Server error while deleting the event", 500
+            res.status(500).send error: "Server error while deleting the event"
         else if req.query.sendMails is 'true'
             MailHandler.sendDeleteNotification req.event, ->
                 res.send success: true
         else
-            res.send success: true, 200
+            res.send success: true

 module.exports.public = (req, res, next) ->


Suggestions lists show all items when clicked

--- views/coffee/general.coffee
+++ views/coffee/general.coffee
@@ -5,11 +5,26 @@
 ###

 setupTypeaheads = ->
-  $("input[data-provide='typeahead']").
+  typeaheads = $("input[data-provide='typeahead']")
+  typeaheads.
     after('<i class="icon icon-chevron-down drop-down" />').
     click (event) ->
+      # Save default matcher
+      unless $(this).data('typeahead_matcher')
+        $(this).data('typeahead_matcher', $(this).data('typeahead').matcher)
+      # Set matcher that accept all items so that the suggestions list
+      # shows everything when the field is clicked
+      $(this).data('typeahead').matcher = -> true
+      # Prepare and show suggestions list
       $(this).typeahead("lookup").typeahead("show")
-  $('i.icon.drop-down').on 'click', (event) ->
+      # Select all text within the field
+      $(this).select()
+    .keydown (event) ->
+      # Restore fefault matcher if user starts using keyboard
+      if $(this).data('typeahead_matcher')
+        $(this).data('typeahead').matcher = $(this).data('typeahead_matcher')
+  # Setup click event for drop-down icon
+  $('i.icon.drop-down').click (event) ->
     typeahead = $(this).prevAll("input[data-provide='typeahead']")
     typeahead.trigger('focus').trigger('click')


Fixed form send.

Fixed form send.

--- src/Ecentinela/ComiconvBundle/Resources/public/js/input.coffee
+++ src/Ecentinela/ComiconvBundle/Resources/public/js/input.coffee
@@ -1,7 +1,7 @@
 # input controller
 Input = can.Control
     # show contact form
-    '#modal .btn click': ($el, e) ->
+    '#modal .btn-primary click': ($el, e) ->
         $modal = $el.closest '#modal'
         $modal.modal 'hide'


Add enableLogs to KD to enable logging even in production

--- client/Framework/core/KD.coffee
+++ client/Framework/core/KD.coffee
@@ -25,6 +25,12 @@

 # KD Global
 KD = @KD or {}
+
+noop  = ->
+
+KD.log   = log   = noop
+KD.warn  = warn  = noop
+KD.error = error = noop

 @KD = $.extend (KD), do ->

@@ -151,17 +157,15 @@
       dataType : 'jsonp'
       success : (data)->
         inflated = JSONH.unpack data
-        console.log 'success', inflated
-        console.log Date.now()-start
+        KD.log 'success', inflated
+        KD.log Date.now()-start

-noop  = ->
+  enableLogs:->
+    KD.log   = log   = if console?.log   then console.log.bind(console)   else noop
+    KD.warn  = warn  = if console?.warn  then console.warn.bind(console)  else noop
+    KD.error = error = if console?.error then console.error.bind(console) else noop
+    return "Logs are enabled now."

-if KD.config?.suppressLogs
-  # assign all these to noop:
-  console.log = console.error = console.warn = console.trace = noop
-
-KD.log   = log   = if console?.log   then console.log.bind(console)   else noop
-KD.warn  = warn  = if console?.warn  then console.warn.bind(console)  else noop
-KD.error = error = if console?.error then console.error.bind(console) else noop
+KD.enableLogs() if not KD.config?.suppressLogs

 prettyPrint = noop


kite: use semver

kite: use semver

--- client/Main/kite/newkite.coffee
+++ client/Main/kite/newkite.coffee
@@ -69,7 +69,7 @@
         username       : "#{KD.nick()}"
         environment    : "#{KD.config.environment}"
         name           : "browser"
-        version        : "#{KD.config.version}"
+        version        : "1.0.#{KD.config.version}"
         region         : "browser"
         hostname       : "browser"
         id             : uniqueID


payment: expose validation methods of form.

--- client/Main/payment/form.coffee
+++ client/Main/payment/form.coffee
@@ -130,6 +130,21 @@
       cardNumber.setClass type.toLowerCase()

+  showValidationErrorsOnInputs: (error) ->
+
+    { cardNumber, cardCVC, cardName, cardMonth, cardYear } = @form.inputs
+
+    switch error.param
+      when 'number'
+        cardNumber.setValidationResult 'checkCC', 'Card number is not valid'
+      when 'exp_year'
+        cardYear.setValidationResult 'checkYear', 'Year is not valid'
+      when 'exp_month'
+        cardMonth.setValidationResult 'checkMonth', 'Month is not valid'
+      when 'cvc'
+        cardCVC.setValidationResult 'checkCVC', 'CVC is not valid'
+
+
   handlePaymentProviderLoaded: ({ provider }) ->

     @state.providerLoaded = yes


Ace: saveall refac fixed

Ace: saveall refac fixed

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -640,7 +640,7 @@

     @forEachSubViewInIDEViews_ 'editor', (editorPane) ->
       {ace} = editorPane.aceView
-      ace.once 'FileContentSynced', ->
+      ace.once 'FileContentRestored', ->
         ace.removeModifiedFromTab editorPane.aceView

       editorPane.emit 'SaveRequested'


AppController: Make IDE readonly initially.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -863,6 +863,9 @@

       @finderPane.on 'ChangeHappened', @bound 'syncChange'

+      unless @amIHost
+        @makeReadOnly()  if @permissions.get(nickname) is 'read'
+

   setCollaborativeReferences: ->


Separate editability of page's content from book's

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -24,6 +24,8 @@

       hasContent: () ->
         return (_.isString(@model.get('content')) or _.isString(@model.get('currentPage.content')))
+
+      editable: () -> @isEditable()

     editable:
       '.media-body':
@@ -65,6 +67,12 @@
           <button class="btn-link ui-toggle" title="Show/Hide Solution"></button>
         </div>''')

+    isEditable: () ->
+      if @model.isBook()
+        return @model.get('currentPage')?.isEditable()
+
+      return @model.isEditable()
+
     toggleSolution: (e) ->
       $solution = $(e.currentTarget).closest('.solution')
       $solution.toggleClass('ui-solution-visible')


Clear popover when clicking outside of it

--- src/scripts/modules/popover/popover.coffee
+++ src/scripts/modules/popover/popover.coffee
@@ -6,7 +6,7 @@
   'bootstrapPopover'
 ], ($, _, Backbone) ->

-  return class PopoverView extends Backbone.View
+  class PopoverView extends Backbone.View
     @popovers: []

     initialize: (params) ->
@@ -18,6 +18,9 @@

       @$parent = params.owner.popover(@options)
       @constructor.popovers.push(@$parent)
+
+      # Stop propogation of 'click' events so popover doesn't get auto-closed
+      @$parent.on 'click', (e) -> e.stopPropagation()

       # Attach event handler to close open popovers on show
       @$parent.on 'show.bs.popover', (e) =>
@@ -77,3 +80,13 @@
       @$parent.off() # Remove event handlers from popover
       @$parent.popover('destroy')
       @$parent = null
+
+  # Close popovers when clicking on the document
+  $(document).click (e) ->
+    $el = $(document.elementFromPoint(e.pageX, e.pageY))
+
+    # Don't clear the popover if clicking in it
+    if not $el.parents().hasClass('popover')
+      PopoverView.hidePopovers()
+
+  return PopoverView


scrollTop on body stopped working

scrollTop on body stopped working

Not sure when.

--- resources/assets/coffee/osu_common.coffee
+++ resources/assets/coffee/osu_common.coffee
@@ -48,7 +48,7 @@

   bottomPage: ->
-    document.body.clientHeight == (document.body.scrollHeight - document.body.scrollTop)
+    window.innerHeight == (document.body.scrollHeight - window.pageYOffset)

   ajaxError: (xhr) ->


Update the versions of Ruby and other small things


Show a list of Vendors in add button menu of add Credential

--- client/Account/views/credentials.coffee
+++ client/Account/views/credentials.coffee
@@ -113,12 +113,28 @@
     super

     view = @getView().parent
+    vendorList = { }
+
+    Object.keys(Vendors).forEach (vendor)=>
+      vendorList[Vendors[vendor].title] =
+        callback : =>
+          @_addButtonMenu.destroy()
+          @showAddCredentialFormFor vendor

     view.addSubView addButton = new KDButtonView
       style     : "solid green small account-header-button"
       iconClass : "plus"
       iconOnly  : yes
-      callback  : => new KDNotificationView title : "Coming soon."
+      callback  : =>
+        @_addButtonMenu = new KDContextMenu
+          delegate    : addButton
+          y           : addButton.getY() + 35
+          x           : addButton.getX() - 142
+          width       : 200
+          arrow       :
+            margin    : -4
+            placement : "top"
+        , vendorList

 class AccountCredentialList extends KDListView

@@ -162,4 +178,4 @@
   viewAppended: JView::viewAppended

   pistachio:->
-    "{{#(vendor)}} - {{#(title)}} -- {{> @deleteButton}}"
+    "{{#(vendor)}} - {{#(title)}} -- {{> @deleteButton}} -- {{#(owner)}}"


Apps: Handle routes correctly

Apps: Handle routes correctly

--- client/Social/Apps/AppController.coffee
+++ client/Social/Apps/AppController.coffee
@@ -1,12 +1,12 @@
 class AppsAppController extends AppController
+
+  handler = (callback)-> KD.singleton('appManager').open 'Apps', callback

   KD.registerAppClass this,
     name         : "Apps"
-    # route        : "/:name?/Apps"
     routes       :
-      "/:name?/Apps" : -> log arg
-      "/:name?/Apps/:username" : ({params : {username}})-> log username, 'sade username'
-      "/:name?/Apps/:username/:appName" : ({params : {username, appName}})-> log username, appName
+      "/:name?/Apps"             : handler
+      "/:name?/Apps/:lala/:app?" : (arg)-> handler (app)-> app.handleRoute arg
     hiddenHandle : yes
     version      : "1.0"
     navItem      :
@@ -138,6 +138,17 @@
     @utils.wait 100, => @feedController?.changeActiveSort "meta.modifiedAt"

+  handleRoute:(route)->
+
+    {app, lala} = route.params
+    {JApp}      = KD.remote.api
+    if app
+      log "slug:", slug = "#{lala}/#{app}"
+      JApp.one {slug}, (err, app)=>
+        log "FOUND THIS JAPP", err, app
+
+    log "HANDLING", route
+
   createContentDisplay:(app, callback)->

     contentDisplay = @showContentDisplay app


bug fix

bug fix

--- client/app/MainApp/book/bookview.coffee
+++ client/app/MainApp/book/bookview.coffee
@@ -16,7 +16,7 @@
     options.cssClass = "book"
     super options, data

-    @mainView = @getOptions().delegate
+    @mainView = @getDelegate()

     @currentIndex = 0

@@ -116,14 +116,12 @@
     return page

   changePageFromRoute:(route)->
-    for index, page of __bookPages
-      if page.routeURL == route
-        @fillPage index
+    @fillPage index for index, page of __bookPages when page.routeURL is route

   openFileWithPage:(file)->
     user = KD.nick()
     fileName = "/home/#{user}#{file}"
-    KD.singletons.appManager.openFile(FSHelper.createFileFromPath(fileName))
+    KD.getSingleton("appManager").openFile(FSHelper.createFileFromPath(fileName))

   fillPrevPage:->
     return if @currentIndex - 1 < 0
@@ -156,7 +154,7 @@
     if @pointer then @destroyPointer()

     # check if page has tutorial
-    if @page.data.howToSteps.length < 1
+    if @page.getData().howToSteps.length < 1
       @showMeButton.hide()
     else
       @showMeButton.show()
@@ -172,8 +170,8 @@

     @mainView.addSubView @pointer

-    if @page.data.menuItem
-      @navigateCursorToMenuItem(@page.data.menuItem)
+    if @page.getData().menuItem
+      @navigateCursorToMenuItem(@page.getData().menuItem)
       @setClass 'aside'
     else
       @continueNextMove()
@@ -184,57 +182,59 @@
       # open side bar
       @mainView.sidebar.animateLeftNavIn()
       # click menu item
-      @selectedMenuItem[0].$().click()
+      @selectedMenuItem.$().click()
       @clickAnimation()
       # head to next move
       @utils.wait 600, =>
         @continueNextMove()

-    @selectedMenuItem = @mainView.sidebar.nav.items.filter (x) -> x.name is menuItem
-    selectedMenuItemOffset = @selectedMenuItem[0].$().offset()
+    filteredMenu = @mainView.sidebar.nav.items.filter (x) -> x.name is menuItem
+    @selectedMenuItem = filteredMenu[0]
+    selectedMenuItemOffset = @selectedMenuItem.$().offset()

     @pointer.$().offset selectedMenuItemOffset

   continueNextMove:->
-    steps = @page.data.howToSteps
-
-    if @page.data.section is 3 and @page.data.parent is 0
+    steps = @page.getData().howToSteps
+    {section, parent} = @page.getData()
+
+    if section is 3 and parent is 0
       if steps[0] is 'enterNewStatusUpdate'
         @navigateToStatusUpdateInput()

-    if @page.data.section is 1 and @page.data.parent is 5
+    if section is 1 and parent is 5
       if steps[0] is 'showFileTreeFolderAndFileMenu'
         @clickFolderOnFileTree('Develop')

-    if @page.data.section is 3 and @page.data.parent is 5
+    if section is 3 and parent is 5
       if steps[0] is 'showVMMenu'
         @showVMMenu()

-    if @page.data.section is 4 and @page.data.parent is 5
+    if section is 4 and parent is 5
       if steps[0] is 'openVMTerminal'
         @showVMTerminal()

-    if @page.data.section is 5 and @page.data.parent is 5
+    if section is 5 and parent is 5
       if steps[0] is 'showRecentFiles'
         @showRecentFilesMenu()

-    if @page.data.section is 6 and @page.data.parent is 5
+    if section is 6 and parent is 5
       if steps[0] is 'showNewVMMenu'
         @showNewVMMenu()

-    if @page.data.section is 8 and @page.data.parent is 0
+    if section is 8 and parent is 0
       if steps[0] is 'showConversationsPanel'
         @showConversationsPanel()

-    if @page.data.section is 7 and @page.data.parent is 5
+    if section is 7 and parent is 5
       if steps[0] is 'changeIndexFile'
         @changeIndexFile()

-    if @page.data.section is 10 and @page.data.parent is 5
+    if section is 10 and parent is 5
       if steps[0] is 'showAceSettings'
         @showAceSettings()

-    if steps[0] is 'showAccountPage'
+    if steps.first is 'showAccountPage'
       @destroyPointer()

   navigateToStatusUpdateInput:->
@@ -290,7 +290,7 @@
     user = KD.nick()
     userVmName = "[koding~#{user}~0]/home/#{user}"
     @utils.wait 500, =>
-      @defaultVm = KD.singletons.finderController.treeController.nodes[userVmName]
+      @defaultVm = KD.getSingleton("finderController").treeController.nodes[userVmName]
       @defaultVm.setClass('selected')
       # find file tree's menu position
       vmOffset = @defaultVm.$(".chevron").offset()
@@ -379,7 +379,7 @@
       # click animation
       @clickAnimation()
       # show conv. panel
-      KD.singletons.chatPanel.showPanel()
+      KD.getSingleton("chatPanel").showPanel()
       @utils.wait 1000, =>
         @startNewConversation()

@@ -392,14 +392,14 @@
     @pointer.once 'transitionend', =>
       # click animation
       @clickAnimation()
-      KD.singletons.chatPanel.header.newConversationButton.$().click()
+      KD.getSingleton("chatPanel").header.newConversationButton.$().click()
       new KDNotificationView
         title     : " Type your friends name"
         duration  : 3000
       @destroyPointer()

     # find + button on panel
-    offsetTo = KD.singletons.chatPanel.header.newConversationButton.$().offset()
+    offsetTo = KD.getSingleton("chatPanel").header.newConversationButton.$().offset()
     # navigate cursor
     @pointer.$().offset offsetTo

@@ -412,7 +412,7 @@
     user = KD.nick()
     userVmName = "[koding~#{user}~0]/home/#{user}"
     @utils.wait 500, =>
-      @defaultVm = KD.singletons.finderController.treeController.nodes[userVmName]
+      @defaultVm = KD.getSingleton("finderController").treeController.nodes[userVmName]
       # find file tree's menu position
       vmOffset = @defaultVm.$(".icon").offset()
       @mainView.sidebar.animateLeftNavOut()
@@ -426,14 +426,14 @@
       user = KD.nick()
       @utils.wait 1200, =>
         @clickAnimation()
-        KD.singletons.finderController.treeController.expandFolder(@webFolderItem)
+        KD.getSingleton("finderController").treeController.expandFolder(@webFolderItem)
         @webFolderItem.setClass 'selected'
         @findAndOpenIndexFile()

     # find user Web folder location
     user = KD.nick()
     webFolder = "[koding~#{user}~0]/home/#{user}/Web"
-    @webFolderItem = KD.singletons.finderController.treeController.nodes[webFolder]
+    @webFolderItem = KD.getSingleton("finderController").treeController.nodes[webFolder]
     offsetTo = @webFolderItem.$().offset()
     # navigate to folder
     @pointer.$().offset offsetTo
@@ -455,7 +455,7 @@
       # find index.html position
       user = KD.nick()
       indexFile = "[koding~#{user}~0]/home/#{user}/Web/index.html"
-      @indexFileItem = KD.singletons.finderController.treeController.nodes[indexFile]
+      @indexFileItem = KD.getSingleton("finderController").treeController.nodes[indexFile]
       # move cursor to index.html position
       offsetTo = @indexFileItem.$().offset()
       @pointer.$().offset offsetTo
@@ -474,7 +474,7 @@
     # highlight
     user = KD.nick()
     aceViewName = "/home/#{user}/Web/index.html"
-    @aceView = KD.singletons.appManager.frontApp.mainView.aceViews[aceViewName]
+    @aceView = KD.getSingleton("appManager").frontApp.mainView.aceViews[aceViewName]
     # find 'Hello World!'
     range = @aceView.ace.editor.find('<h1>')
     # get cursor position to ace


Added: message when there is no email for mailbox/imap folder

--- client/app/components/email-list.coffee
+++ client/app/components/email-list.coffee
@@ -18,14 +18,17 @@

     render: ->
         div id: 'email-list',
-            ul className: 'list-unstyled',
-                @props.emails.map (email, key) =>
-                    # only displays initial email of a thread
-                    if email.inReplyTo.length is 0
-                        isActive = @props.openEmail? and
-                                   @props.openEmail.id is email.id
-                        @getEmailRender email, key, isActive
-                .toJS()
+            if @props.emails.count() is 0
+                'No email in this box.'
+            else
+                ul className: 'list-unstyled',
+                    @props.emails.map (email, key) =>
+                        # only displays initial email of a thread
+                        if email.inReplyTo.length is 0
+                            isActive = @props.openEmail? and
+                                       @props.openEmail.id is email.id
+                            @getEmailRender email, key, isActive
+                    .toJS()

     getEmailRender: (email, key, isActive) ->
         classes = classer


Minor fix.

Minor fix.

--- src/main.coffee
+++ src/main.coffee
@@ -27,7 +27,7 @@

 #=====================================================================

-# $readFile = $Promise.promisify $fs.readFile
+$readFile = $Promise.promisify $fs.readFile

 $httpListenSuccess = ->
   $debug "Web server listening on #{@niceAddress()}"


fix login

fix login

--- src/main.coffee
+++ src/main.coffee
@@ -23,7 +23,7 @@
     creds = =>
       prom = login(@mainWindow)
       # reinstate app window when login finishes
-      prom.then -> loadAppWindow()
+      prom.then => @loadAppWindow()
       auth: -> prom
     @client.connect(creds).then @clientConnectionSuccess, @clientConnectionError
     @client.on 'chat_message', @clientonchatmessage
@@ -87,7 +87,8 @@
     segments.pop()
     conversation = @model.conversationCurrent
     dfr = @client.sendchatmessage conversation, segments, null
-  loadAppWindow: -> @mainWindow.loadUrl 'file://' + __dirname + '/ui/index.html' if @mainWindow
+  loadAppWindow: ->
+    @mainWindow.loadUrl 'file://' + __dirname + '/ui/index.html' if @mainWindow
   refresh: -> @mainWindow.webContents.send 'model:update', @model if @mainWindow
   clientConnectionSuccess: =>
     self = @client.init.self_entity


cleanup main

cleanup main

--- src/main.coffee
+++ src/main.coffee
@@ -14,22 +14,21 @@
 # TODO: server-side include underscore, underscore.string, jquery

 {my} = require './my'
-if my.online
+sys = require 'sys'
+
+if not my.online
+  rx = require './render/rx_mock'
+else
   _.mixin(_.str.exports())
   if my.reactive_debug
     rx = require '../../reactive-coffee/src/reactive'
     console.log "WARNING: Loading local copy of reactive-coffee"
   else
     rx = require 'reactive-coffee'
-else
-  rx = require './render/rx_mock'
-sys = require 'sys'

 # Dependencies

-{god} = require './god'
 {game} = require './game'
-{layout} = require './layout'
 {render} = require './render'

 world = game(rx, {file: 'example', level: 0})


set uom attributes before adding event listener

--- client/skr/models/mixins/SkuLine.coffee
+++ client/skr/models/mixins/SkuLine.coffee
@@ -24,12 +24,12 @@
         _.extend( klass::associations ||= {}, ASSOCIATIONS)

     initialize: ->
+        @uom.size = @uom_size
+        @uom.code = @uom_code
         @on('change:sku', @onSkuChange)
         @on('change:uom', @onUomChange)
         @on('change:location_id', @onLocationChange)
         @uom_choices.on("add", @onUomsLoad, this)
-        @uom.size = @uom_size
-        @uom.code = @uom_code

     onLocationChange: ->
         if @location_id


Activate packages asynchronously

Activate packages asynchronously

--- spec/keybinding-resolver-view-spec.coffee
+++ spec/keybinding-resolver-view-spec.coffee
@@ -4,7 +4,9 @@
 describe "KeybindingResolverView", ->
   beforeEach ->
     atom.workspaceView = new WorkspaceView
-    atom.packages.activatePackage('keybinding-resolver', immediate: true)
+
+    waitsForPromise ->
+      atom.packages.activatePackage('keybinding-resolver')

   describe "when the keybinding-resolver:toggle event is triggered", ->
     it "attaches and then detaches the view", ->


minor text change

minor text change

--- scripts/TM-Github.coffee
+++ scripts/TM-Github.coffee
@@ -43,7 +43,7 @@
       res.reply 'In a bit, the compiled node_modules will be at the https://github.com/tm-build/TM_4_0_Windows repo'

   robot.respond /deploy to azure/i,(res) ->
-    res.reply "About to trigger a deploy to azure"
+    res.reply "About to trigger a deploy to azure..."
     options =
       url    : 'https://ci.appveyor.com/api/builds',
       headers:


test/stacks: get url when private stack is created

--- client/test/lib/dashboard/stacks.coffee
+++ client/test/lib/dashboard/stacks.coffee
@@ -3,6 +3,7 @@
 utils = require '../utils/utils.js'
 stackEditorUrl = "#{helpers.getUrl(yes)}/Home/stacks"
 async = require 'async'
+stackSelector = null

 module.exports =
@@ -32,6 +33,10 @@

       (next) ->
         teamsHelpers.createDefaultStackTemplate browser, (res) ->
+          # remove main url from result
+          # to get '/Stack-Editor/machineId'
+          res = res.substring helpers.getUrl(yes).length
+          stackSelector = res
           next null, res
     ]


Add "Commit message me" and "YOLO" responders

--- scripts/nostalgia.coffee
+++ scripts/nostalgia.coffee
@@ -12,6 +12,7 @@
 #   nostalgiabot End Guess Who - End the game of Guess Who!
 #   nostalgiabot Hacker me - Get a 100% real quote from a professional hacker.
 #   nostalgiabot BS me - Get a technobable quote that sounds almost real.
+#   nostalgiabot Commit message me - Generate your next commit message
 #   nostalgiabot stats - See how memorable everyone is
 #
 # Author:
@@ -93,9 +94,20 @@
         else
             res.send "\"#{data.quote}\" - l33t h4xx0r"

+commitMessageRespond = (res) ->
+    commitMessageUrl = "http://www.whatthecommit.com/index.txt"
+    request.get {uri:"#{commitMessageUrl}", json: true}, (err, r, data) ->
+        if err
+            res.send "Too busy coding to generate a message"
+        else
+            res.send "#{data}"
+
 bsRespond = (res) ->
     # From http://www.atrixnet.com/bs-generator.html
     res.send "\"" + toTitleCase generateBS() + "\" - Lead Synergist"
+
+yoloRespond = (res) ->
+    res.send "alias yolo='git commit -am \"DEAL WITH IT\" && git push -f origin master'"

 statsRespond = (res) ->
     stats = "Memories made:\n"
@@ -176,6 +188,8 @@

     robot.respond /Hacker me/i, hackerRespond
     robot.respond /BS me/i, bsRespond
+    robot.respond /Commit message me/i, commitMessageRespond
+    robot.respond /YOLO/i, yoloRespond

     robot.respond /Who do you remember\??/i, (res) ->
         res.send Object.keys(memories)


Minor: slight improvement to isInternetExplorer()

--- src/misc.coffee
+++ src/misc.coffee
@@ -16,4 +16,4 @@
 	(typeof s is 'string') or (s instanceof String)

 Fiesta.isInternetExplorer = ->
-	window.navigator.userAgent.indexOf('MSIE') isnt -1
+	navigator.appName is 'Microsoft Internet Explorer'


Revert "Remove require"

Revert "Remove require"

This reverts commit e2b38774a9fc3f9f7588dbbdc78b350a024b6535.

--- src/msgc.coffee
+++ src/msgc.coffee
@@ -1,3 +1,5 @@
+{Robot, Adapter, TextMessage, EnterMessage, LeaveMessage, CatchAllMessage} = require "hubot"
+
 class Msgc extends Adapter

   constructor: ->


r/w updates

r/w updates

--- grovepi.coffee
+++ grovepi.coffee
@@ -27,14 +27,16 @@
 		wire = new i2c @address, device: "/dev/i2c-1"
 		@wire = wire  if debug.mode

-	send: ( cmd, data, callback ) ->
+
+
+	send = ( cmd, data, callback ) ->
 		writeCmd = if Array.isArray data then 'writeBytes' else 'writeByte'
 		wire[writeCmd] cmd, data, ( error ) ->
 			callback()
 			debug.log "Send", cmd, data
 			debug.log "ERROR:", error if error

-	receive: ( port, args... ) ->
+	receive = ( port, args... ) ->
 		if args[1]
 			size = args[0]
 			callback = args[1]
@@ -50,11 +52,7 @@

 	write: ( type, port, data, callback ) ->
 		data = [port].concat data
-		switch type
-			when 'digital'
-				@send CMD.digital.write, data, callback
-			when 'analog'
-				@send CMD.analog.write, data, callback
+		send CMD[type].write, data, callback

 	read: ( type, args... ) ->
 		switch type


Including origin in websocket connection

--- src/quip.coffee
+++ src/quip.coffee
@@ -90,7 +90,7 @@
     @robot.logger.info "Connecting..."
     return if @connected
     return @robot.logger.error "No Socket URL" unless @socketUrl
-    @ws = new WebSocket @socketUrl
+    @ws = new WebSocket @socketUrl, { origin: 'https://quip.com' }
     @ws.on "open", =>
       @robot.logger.info "Opened"
       @connected = true


Fixed editable artist

Fixed editable artist

--- public/dreamcatcher/controllers/ib_browser_controller.coffee
+++ public/dreamcatcher/controllers/ib_browser_controller.coffee
@@ -237,7 +237,7 @@
   #- ArtistList -#

   '#artistList tr.artist click': (el) ->
-    @artist = $("h2:first",el).text()
+    @artist = $("input.editable[type='text']:first",el).val()
     @model.getAlbums {artist: @artist, section: @section, category: @category}, @callback('displayScreen', 'albumList')


Add additional space to two-sided symbol

--- src/symbol/default/common/two-sided.coffee
+++ src/symbol/default/common/two-sided.coffee
@@ -8,6 +8,7 @@

   width = icon.width
   height = icon.height
+  space = icon.space ? 0

   pinLength2 = symbol.alignToGrid(settings.pinLength ? (if decorated then 5 else 2.5), 'ceil')
   pinLength1 = (2*symbol.alignToGrid(width/2 + pinLength2, 'ceil') - width) / 2
@@ -18,12 +19,12 @@
   symbol
     .attribute 'refDes',
       x: 0
-      y: -height/2 - settings.space.attribute
+      y: -height/2 - space - settings.space.attribute
       halign: 'center'
       valign: 'bottom'
     .attribute 'name',
       x: 0
-      y: Math.max(height, pinAreaHeight)/2 + settings.space.attribute
+      y: Math.max(height, pinAreaHeight)/2 + space + settings.space.attribute
       halign: 'center'
       valign: 'top'
   icon.draw 0, 0


fixed require host problem for ipv4

fixed require host problem for ipv4

--- node_modules_koding/domainer/lib/reseller/DNSManager.coffee
+++ node_modules_koding/domainer/lib/reseller/DNSManager.coffee
@@ -64,6 +64,9 @@
         host          : params.host
         ttl           : params.ttl

+    if params.host == ""
+      options.parameters.host = params.host
+
     @makeRequestToResellerApi options, (err, result)-> callback err, result

   updateDNSRecord:(params, callback)->
@@ -86,4 +89,4 @@
         "host"          : params.oldData.host
         "ttl"           : params.oldData.ttl

-    @makeRequestToResellerApi options, (err, result)-> callback err, result+    @makeRequestToResellerApi options, (err, result)-> callback err, result


use separate method to count empty lines

--- src/sloc.coffee
+++ src/sloc.coffee
@@ -125,6 +125,9 @@
     \s*     # zero or more spaces
     $       # end of line
   ///
+
+getEmptyLinesCount = (lines) ->
+  (i for l,i in lines when whiteSpaceLine.test l).length

 slocModule = (code, lang) ->

@@ -177,9 +180,7 @@

   lines = code.split '\n'
   loc   = lines.length
-  nloc  = (for l,i in lines when whiteSpaceLine.test l
-            nullLineNumbers.push i; l
-          ).length
+  nloc  = getEmptyLinesCount lines

   start               = false
   cCounter            = 0


Add helper method to get chocolatey atom.exe path

--- src/test.coffee
+++ src/test.coffee
@@ -25,21 +25,32 @@

   showHelp: (argv) -> @parseOptions(argv).showHelp()

+  getChocolateyAtomPath: ->
+    if process.env.ALLUSERSPROFILE
+      atomCommand = path.join(process.env.ALLUSERSPROFILE, 'chocolatey', 'bin', 'atom.exe')
+      return atomCommand if fs.existsSync(atomCommand)
+
+    if process.env.CHOCOLATEYINSTALL
+      atomCommand = path.join(process.env.CHOCOLATEYINSTALL, 'bin', 'atom.exe')
+      return atomCommand if fs.existsSync(atomCommand)
+
+    null
+
   run: (options) ->
     {callback} = options
     args = @parseOptions(options.commandArgs)
-    env = process.env
+    {env} = process

-    atomCommand = args.argv.path ? 'atom'
+    if args.argv.path
+      atomCommand = args.argv.path
+    else if process.platform is 'win32'
+      atomCommand = @getChocolateyAtomPath()
+    atomCommand = 'atom' unless fs.existsSync(atomCommand)
+
     packagePath = process.cwd()
     testArgs = ['--dev', '--test', "--spec-directory=#{path.join(packagePath, 'spec')}"]

     if process.platform is 'win32'
-      unless args.argv.path?
-        atomCommand = path.join(env.ALLUSERSPROFILE, 'chocolatey', 'bin', 'atom.exe') if env.ALLUSERSPROFILE? and env.ALLUSERSPROFILE.trim() isnt ''
-        atomCommand = path.join(env.CHOCOLATEYINSTALL, 'bin', 'atom.exe') if env.CHOCOLATEYINSTALL? and env.CHOCOLATEYINSTALL.trim() isnt ''
-        atomCommand = 'atom' unless fs.existsSync(atomCommand)
-
       testArgs.unshift('--shimgen-waitforexit')
       logFile = temp.openSync(suffix: '.log', prefix: "#{path.basename(packagePath)}-")
       fs.closeSync(logFile.fd)


Use binder.priority to sort bindings in the view before getting bound. [#409]

--- src/view.coffee
+++ src/view.coffee
@@ -104,6 +104,9 @@

     parse el for el in @els

+    @bindings.sort (a, b) ->
+      (b.binder.priority or 0) - (a.binder.priority or 0)
+
     return

   # Returns an array of bindings where the supplied function evaluates to true.


Small fix

Small fix

--- src/components/widgets-settings/width/width.directive.coffee
+++ src/components/widgets-settings/width/width.directive.coffee
@@ -31,8 +31,8 @@
   w.toggleExpanded = ->
     $scope.expanded = !$scope.expanded
     # false because we want to resize the widget without waiting for the response from the dashboarding API
-    ImpacWidgetsSvc.updateWidgetSettings(w,false)
-
+    ImpacWidgetsSvc.updateWidgetSettings(w,false,true)
+
     hideOnResize($scope.contentElements)

     if $scope.expanded


opt: error stack

opt: error stack

--- src/yaku.coffee
+++ src/yaku.coffee
@@ -210,11 +210,9 @@
 	@onUnhandledRejection: (reason, p) ->
 		if typeof console == $object
 			hStack = ''
-			sStack = ''
 			if isLongStackTrace and p[$handlerStack]
 				while p
 					hStack = p[$handlerStack] + hStack
-					sStack = p[$settlerStack]
 					p = p[$prePromise]

 			stack = if reason
@@ -223,8 +221,8 @@
 				reason

 			console.error (
-				'Unhandled rejection Error:' +
-				stack + sStack + hStack
+				'Unhandled rejection Error: ' +
+				stack + hStack
 			).replace ///.+#{__filename}.+\n///g, ''

 		return


Use button:0 argument for click in order

Without the argument, React Router will not trigger since it will think it's a right button click

--- test/components/reference-book.spec.coffee
+++ test/components/reference-book.spec.coffee
@@ -72,12 +72,16 @@
     expect(nextControl.href).to.contain(SECOND_PAGE_ID)
     page = ReactTestUtils.findRenderedComponentWithType(@state.book, Page)

-    commonActions.click(nextControl)

-    # expect(page.context.router.getCurrentParams().cnxId)
-    #   .to.equal(SECOND_PAGE_ID)
+    ReferenceBookPageActions.loaded(PAGE, SECOND_PAGE_ID)
+    # button:0 is a mystery argument needed by ReactRouter, taken from their specs
+    commonActions.click(nextControl, {button: 0})

-    # expect(@state.div.querySelector('.page-wrapper > .next').href)
-    #   .to.contain(THIRD_PAGE_ID)
-    # expect(@state.div.querySelector('.page-wrapper > .prev').href)
-    #   .to.contain(FIRST_PAGE_ID)
+    expect(page.context.router.getCurrentParams().cnxId)
+      .to.equal(SECOND_PAGE_ID)
+
+    expect(@state.div.querySelector('.page-wrapper > .next').href)
+      .to.contain(THIRD_PAGE_ID)
+
+    expect(@state.div.querySelector('.page-wrapper > .prev').href)
+      .to.contain(FIRST_PAGE_ID)


undo typing

undo typing

--- extension/content.coffee
+++ extension/content.coffee
@@ -3,6 +3,7 @@
 tabsView = undefined
 controlInput = undefined
 tabsterActive = false
+buffer = null

 baseKeys = ['a', 's', 'd', 'f', 'h', 'j', 'k', 'l']
 keys = []
@@ -38,7 +39,7 @@
 		tabsView.appendChild(tabView)
 		tabView.addEventListener('click', tabsterSwitchTab.bind(this, tab.id), false)

-	overflow.className += " visible"
+	overflow.classList.add("visible")
 	tabsterActive = true

 tabsterSwitchTab = (id) ->
@@ -49,23 +50,31 @@
 	)

 tabsterClose = () ->
-	overflow.className = 'tabster-overflow'
+	overflow.classList.remove("visible")
 	tabsterActive = false
+
+tabsterUndo = () ->
+	buffer = null
+	tabs = document.querySelectorAll(".tabster-tab.tabster-hit")
+	for tab in tabs
+		tab.classList.remove('tabster-hit')

 handleKeyEvents = (e) ->
 	return e unless (tabsterActive)
 	e.preventDefault()
 	if 27 == e.keyCode
-		tabsterClose()
+		if buffer
+			tabsterUndo()
+		else
+			tabsterClose()
 	key = String.fromCharCode(e.keyCode).toLowerCase()
 	if key in baseKeys
 		updateTabs(key)

 addEvents = () ->
-	document.addEventListener('keyup', handleKeyEvents, false)
+	document.addEventListener 'keyup', handleKeyEvents, false

-buffer = []
 updateTabs = (key) ->
 	tabs = document.querySelectorAll(".tabster-tab")
 	if buffer
@@ -74,7 +83,7 @@
 				buffer = null
 				return tab.click()

-	possibleHits = document.querySelectorAll(".tabster-first-key-#{key}")
+	possibleHits = document.querySelectorAll ".tabster-first-key-#{key}"
 	buffer = possibleHits
 	for tab in possibleHits
-		tab.className += ' tabster-hit'
+		tab.classList.add 'tabster-hit'


Scrolling to top after collapsing the historic listing changes

--- app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee
+++ app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee
@@ -11,4 +11,6 @@
     this.set('citesListingsExpanded', false)
     $('#cites_listings').
       find('.historic').hide('slow')
-    window.scrollTo($('#cites_listings', 300).prev())
+    $("html, body").animate
+      scrollTop: $("#cites_listings").offset().top
+      , 1000


Another comment on componentsTagging

Another comment on componentsTagging

--- components.coffee
+++ components.coffee
@@ -680,6 +680,8 @@
 componentDebugTaggingFlag = true
 $$ = (elemType, props, children...) ->
     # If componentsTagging is on, we want to wrap each component in a div to include the tooltip-like tags.
+    # If the component is a TableRow, we hide the tag and only show a border around it. We do this since
+    # TableRow seems to be a very commonly used component.
     if componentDebugTagging and elemType[0] != '_' and elemType of J.components and (not props or 'data-component-tag' not of props)
         if componentDebugTaggingFlag
             componentDebugTaggingFlag = false


Passing newly processed urls via message back to results controller, not recrawling previously scanned urls

--- coffeescripts/background.coffee
+++ coffeescripts/background.coffee
@@ -49,6 +49,9 @@
   delete window.pendingUrls[data.url]
   window.crawledUrls[data.url] = page

+  message = method: "addScannedPage", page: { url: data.url, data: page }
+  chrome.runtime.sendMessage message, (resp) -> console.debug resp
+
   parseAndCrawlDocument data.url, data.responseText if helpers.isHTML data.contentType
   true

@@ -59,6 +62,12 @@

   _.each links, (link, index) ->
     fullUrl = helpers.convertToAbsolute url, link.href
+
+    if window.crawledUrls[fullUrl]?
+      window.crawledUrls[fullUrl].appearsOn.push url
+    else
+      task = new WorkerTask 'javascripts/background_worker.js', { url: fullUrl }, crawlLinksRecursively
+      window.workerPool.addWorkerTask task

 # Launch listener - open main window
 chrome.app.runtime.onLaunched.addListener ->


Teamwork: Implemented import action for dashboard.

--- client/app/Applications/Teamwork.kdapplication/Views/teamworkdashboard.coffee
+++ client/app/Applications/Teamwork.kdapplication/Views/teamworkdashboard.coffee
@@ -28,16 +28,19 @@
       cssClass    : "tw-dashboard-button"
       callback    : => @handleJoinSession()

-    @importInput  = new KDInputView
+    @importInput  = new KDHitEnterInputView
       cssClass    : "tw-dashboard-input"
       placeholder : "Url to import your VM"
-      callback    : ->
+      validate    :
+        rules     : required: yes
+        messages  : required: "Enter URL to import content."
+      callback    : => @handleImport()

     @importButton = new KDButtonView
       iconOnly    : yes
       iconClass   : "import"
       cssClass    : "tw-dashboard-button"
-      callback    : ->
+      callback    : => @handleImport()

     @playgrounds  = new KDCustomHTMLView
       cssClass    : "tw-playgrounds"


Logging; consistent and concise normal-mode logging.

--- content_scripts/mode_key_handler.coffee
+++ content_scripts/mode_key_handler.coffee
@@ -20,7 +20,7 @@

   # Reset the key state, optionally retaining the count provided.
   reset: (@countPrefix = 0) ->
-    bgLog "Clearing key state, set count=#{@countPrefix}."
+    bgLog "Clearing key state: #{@countPrefix} (#{@name})"
     @keyState = [@keyMapping]

   constructor: (options) ->
@@ -88,7 +88,7 @@
     @countPrefix == 0 and @keyState.length == 1 and keyChar in (@passKeys ? "")

   handleKeyChar: (keyChar) ->
-    bgLog "Handling key #{keyChar}, mode=#{@name}."
+    bgLog "Handle key #{keyChar} (#{@name})"
     # A count prefix applies only so long a keyChar is mapped in @keyState[0]; e.g. 7gj should be 1j.
     @countPrefix = 0 unless keyChar of @keyState[0]
     # Advance the key state.  The new key state is the current mappings of keyChar, plus @keyMapping.
@@ -96,7 +96,7 @@
     command = (mapping for mapping in @keyState when "command" of mapping)[0]
     if command
       count = if 0 < @countPrefix then @countPrefix else 1
-      bgLog "Calling mode=#{@name}, command=#{command.command}, count=#{count}."
+      bgLog "Call #{command.command}[#{count}] (#{@mode})"
       @reset()
       @commandHandler {command, count}
     false # Suppress event.


フォーマットを微調整

フォーマットを微調整

--- public/javascripts/src/bell.cjsx
+++ public/javascripts/src/bell.cjsx
@@ -12,15 +12,15 @@
 ThemeManager = new Mui.Styles.ThemeManager()

 module.exports = React.createClass
+  childContextTypes:
+    muiTheme: React.PropTypes.object
   getInitialState: ->
     keyword  : ""
-    teamId  : undefined
+    teamId   : undefined
     keywords : []
     teams    : []
   getChildContext: ->
     muiTheme: ThemeManager.getCurrentTheme()
-  childContextTypes:
-    muiTheme: React.PropTypes.object
   getStyles: ->
     root:
       margin    : "0 auto"


Replaces default refresh on working periods. Fixes #1259.

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -181,7 +181,7 @@
   $(document).on 'cocoon:after-insert', (e, i) ->
     $('input[data-map-editor]').each ->
       $(this).mapeditor()
-    $('#parameters *[data-intervention-updater]').each ->
+    $('#working-periods *[data-intervention-updater]').each ->
       E.interventions.refresh $(this),
         success: (stat, status, request) ->
           E.interventions.updateAvailabilityInstant($(".nested-fields.working-period:first-child input.intervention-started-at").first().val())


Client: Teams: Using group.slug instead of client.context.group for approve and deny post options

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -737,7 +737,7 @@

   , (client, callback) ->

-    { r: { user } } = client
+    { r: { user, group } } = client

     # An owner cannot approve their own machine
     if isOwner user, this
@@ -748,7 +748,7 @@
       'users.id' : user._id
     }, { $set : { 'users.$.approved' : yes } }
     , (err) =>
-      options = { action: 'approve', @uid, group: client?.context?.group, machineId: @getId() }
+      options = { action: 'approve', @uid, group: group.slug, machineId: @getId() }
       client.connection.delegate.sendNotification 'MachineShareActionTaken', options
       callback err

@@ -762,7 +762,7 @@

   , (client, callback) ->

-    { r: { user } } = client
+    { r: { user, group } } = client

     # An owner cannot deny their own machine
     if isOwner user, this
@@ -775,7 +775,7 @@
       permanent : yes

     @shareWith options, (err) =>
-      options               = { action: 'deny', @uid, group: client?.context?.group, machineId: @getId() }
+      options               = { action: 'deny', @uid, group: group.slug, machineId: @getId() }
       [ owner ]             = @users.filter (user) -> return user.owner
       { notifyByUsernames } = require '../notify'


JMachine: guessNextLabel: ignore Terminated machines while calculating the next label

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -150,12 +150,13 @@
     slug = slugify slug

     JMachine.count {
-      users        :
-        $elemMatch :
-          id       : user.getId()
-      groups       :
-        $elemMatch :
-          id       : group.getId()
+      'status.state' : { $ne: 'Terminated' }
+      users          :
+        $elemMatch   :
+          id         : user.getId()
+      groups         :
+        $elemMatch   :
+          id         : group.getId()
       slug
     }, (err, count) ->


bug fix for css reloading causing unstyled page flash

--- app/assets/javascripts/flammarion_rails/actions.coffee
+++ app/assets/javascripts/flammarion_rails/actions.coffee
@@ -6,6 +6,25 @@
 history.pushState(null, null, document.URL)
 window.addEventListener 'popstate', ->
   history.pushState(null, null, document.URL)
+
+# Page
+########################################
+# Note: allow to skip css reloading which causes unstyled page sudden burst
+
+extract_first_tag = (html, tag) ->
+  start_match = ///<#{tag}.*>///.exec(html)
+  end_match = html.indexOf("</#{tag}>")
+  html.substring(start_match.index + start_match[0].length, end_match)
+
+ws.onmessage_actions.page = (event) ->
+  head = extract_first_tag(ws_data.body, 'head')
+  head = head.replace(/\s\/>/g, ">").replace(/'/g, '"')
+  body = extract_first_tag(ws_data.body, 'body')
+  unless head == document.head.innerHTML
+    $('head').html(head)
+  $('body').html(body)
+  $(window).scrollTop(0)
+  $.ready()

 # NProgress
 ########################################


Update application.js.coffee

Update application.js.coffee

--- app/assets/javascripts/jquest_pg/application.js.coffee
+++ app/assets/javascripts/jquest_pg/application.js.coffee
@@ -1,15 +1,3 @@
-# This is a manifest file that'll be compiled into application.js, which will include all the files
-# listed below.
-#
-# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
-# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
-#
-# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-# compiled file.
-#
-# Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
-# about supported directives.
-#
 #= require_tree .
 angular.module 'jquest'
   .run (Menu)->


Subtile fade ins amirite

Subtile fade ins amirite

--- app/assets/javascripts/videos/infinitescroll.js.coffee
+++ app/assets/javascripts/videos/infinitescroll.js.coffee
@@ -29,9 +29,9 @@
   $(document.body).append(goUpDiv)
   goBackUp = every 200, () ->
     if $(window).scrollTop() > $(window).height()
-      goUpDiv.removeClass('hide')
+      goUpDiv.fadeIn()
     else
-      goUpDiv.addClass('hide')
+      goUpDiv.fadeOut()

       $(document).keypress (e) ->
         return unless e.target.tagName.toLowerCase() == 'body' and (e.which == 107 or e.which == 106)


resolve `cid of undefined` error in collaborator picker.

fixes CNVS-4506

test plan:
  * create a class with between 50-100 students;
  * create a new collaboration in the class, and include a
    member from the last page of users as a collaborator;
  * reload the page, edit the collaboration, and attempt to
    scroll to the second page of available users. verify
    that no javascript error is thrown.

Change-Id: I64562c14630a462f2182c27b92e90fb24b7f9cf2
Reviewed-on: https://gerrit.instructure.com/18674
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Cam Theriault <b4133c36b6d893d0872cc09e87b536d16aa2d241@instructure.com>
Reviewed-by: Jon Willesen <eb5ce5e6a76c243326fecfa94534101600f87bd9@instructure.com>
Product-Review: Zach Pendleton <514dbb4d54d4f29e454990df7d075678f43f92aa@instructure.com>

--- app/coffeescripts/views/collaborations/ListView.coffee
+++ app/coffeescripts/views/collaborations/ListView.coffee
@@ -94,14 +94,18 @@
       @hasFocus     = true
       @collection.remove(id)

-    # Public: Filter out the given members.
+    # Public: Filter out the given members. We wrap this in a setTimeout to
+    # allow Backbone to catch up with itself; without it, the occassional
+    # `cid of undefined` error crops up.
     #
     # models - An array of models to filter out of the collection.
     #
     # Returns nothing.
     updateFilter: (models) ->
-      @filteredMembers = flatten([@filteredMembers, models])
-      each(@filteredMembers, (m) => @collection.remove(m, silent: true))
+      setTimeout =>
+        @filteredMembers = flatten([@filteredMembers, models])
+        each(@filteredMembers, (m) => @collection.remove(m, silent: true))
+      , 0

     # Public: Remove the given model from the filter.
     #


Fix menu canvas & navigation render in visualization-story

--- app/frontend/javascripts/visualization-story.js.coffee
+++ app/frontend/javascripts/visualization-story.js.coffee
@@ -11,6 +11,8 @@
     @visualizationCanvas.setup @nodes, @relations, @parameters
     $('.visualization-graph-component').css 'margin-left', -230 # translate left half the width of Story Info panel
     @visualizationCanvas.render()
+    @visualizationNavigation.render()
+    @visualizationActions.render @parameters
     # Setup Visualization Events
     @bindVisualizationEvents()
     # Trigger synced event for Stories


fix assertion

fix assertion

--- apps/artwork_2/components/partner/test/template.coffee
+++ apps/artwork_2/components/partner/test/template.coffee
@@ -27,7 +27,7 @@
     $ = cheerio.load(@html)

     it 'should not display zero followers count', ->
-      $('.artwork-partner__metadata__actions__followers').should.not.exist
+      $('.artwork-partner__metadata__actions__followers').should.have.lengthOf 0

   describe 'partner with follows', ->
     @artwork = fabricate 'artwork'


Connects to the API server

Connects to the API server

--- test/api.coffee
+++ test/api.coffee
@@ -4,8 +4,12 @@
 assert = chai.assert

 Api = require('../lib/api')
+WebSocket = require('ws')

 describe 'Api', ->
-  it 'should initialize', ->
+  it 'should start and provide a WS server', ->
     api = new Api
-    api.start+    api.start =>
+
+    client = new WebSocket("ws://localhost:3001")
+


Tests:Environments: Use helper for seeUpgradeModal test.

--- tests/src/environments/environments.coffee
+++ tests/src/environments/environments.coffee
@@ -17,6 +17,17 @@
       .click                   vmSelector + ' span'
       .waitForElementVisible   modalSelector, 20000 # Assertion

+
+seeUpgradeModal = (browser) ->
+
+    sidebarTitle = '[testpath=main-sidebar] .activity-sidebar .vms .sidebar-title'
+
+    browser
+      .waitForElementVisible   '[testpath=main-sidebar]', 20000
+      .waitForElementVisible   sidebarTitle, 20000
+      .moveToElement           sidebarTitle + ' a.buy-vm', 10, 10
+      .click                   sidebarTitle + ' a.buy-vm'
+      .waitForElementVisible   '.computeplan-modal.free-plan .kdmodal-inner', 20000 # Assertion

 module.exports =

@@ -70,16 +81,7 @@

   seeUpgradeModal: (browser) ->

-    plusSelector = '[testpath=main-sidebar] .activity-sidebar .vms .sidebar-title'
-
     helpers.beginTest(browser)
     helpers.waitForVMRunning(browser)
-
-    browser
-      .waitForElementVisible   '[testpath=main-sidebar]', 20000
-      .waitForElementVisible   plusSelector, 20000
-      .moveToElement           plusSelector + ' a.buy-vm', 10, 10
-      .click                   plusSelector + ' a.buy-vm'
-      .waitForElementVisible   '.computeplan-modal.free-plan .kdmodal-inner', 20000 # Assertion
-      .end()
-
+    seeUpgradeModal(browser)
+    browser.end()


Fix find greyhound check

Fix find greyhound check

--- scripts/adopt.coffee
+++ scripts/adopt.coffee
@@ -6,7 +6,8 @@
   fs.readFile file, 'utf8', (err, data) ->
     return callback err if err

-    if data.search ///#{greyhound}:///g is -1
+    m = data.match ///^#{greyhound}:$///m
+    if m is null
       return callback "Sorry, couldn't find #{greyhound} 😕"

     err = null


properly fix the renaming test

properly fix the renaming test

--- test/integration/dataset.coffee
+++ test/integration/dataset.coffee
@@ -87,24 +87,10 @@
             browser.type @input, randomname + '\n', ->
               done()

-        before (done) ->
-          browser.elementByCssIfExists '#editable-input', (err, wrapper) =>
-            @wrapper = wrapper
-            browser.elementByCssIfExists '#editable-input input', (err, input) =>
-              @input = input
-              browser.elementByCssIfExists '#subnav-path .editable', (err, a) =>
-                @a = a
-                done()
-
-        before (done) ->
-          # short pause while jQuery hides stuff and Selenium finishes typing
-          setTimeout done, 750
-
-        it 'hides the input box and shows the title', (done) ->
-          browser.isVisible @wrapper, (err, inputVisible) =>
-            inputVisible.should.be.false
-            browser.isVisible @a, (err, aVisible) =>
-              aVisible.should.be.true
+        it 'hides the input box and shows the new title', (done) =>
+          browser.waitForVisibleByCss '#subnav-path .editable', 4000, (err) =>
+            browser.isVisible 'css selector', '#editable-input', (err, inputVisible) ->
+              inputVisible.should.be.false
               done()

         it 'has updated the title', (done) ->


adjusted the left-facing tooltip to clear the mouse cursor - most prevalent on PC

--- public/dreamcatcher/controllers/application_controller.coffee
+++ public/dreamcatcher/controllers/application_controller.coffee
@@ -24,6 +24,7 @@
       showBody: ' - '
       positionLeft: true
       fade: 250
+      top: 20
     }
     ###
     TODO:


jackie chan thmumbs up

jackie chan thmumbs up

--- scripts/seal-of-approval.coffee
+++ scripts/seal-of-approval.coffee
@@ -29,7 +29,8 @@
  "http://mlkshk.com/r/CYHO.gif",
  "http://i.imgur.com/uM5NJ.gif",
  "http://iforce.co.nz/i/0gi03qyg.ydq.gif",
- "http://i.imgur.com/N2FEP.gif"
+ "http://i.imgur.com/N2FEP.gif",
+ "http://mlkshk.com/r/HB8K.gif"
 ]

 module.exports = (robot) ->


Refactor welcome-to-zithub

Refactor welcome-to-zithub

--- scripts/welcome-to-zihub.coffee
+++ scripts/welcome-to-zihub.coffee
@@ -37,8 +37,8 @@
   robot.brain.on 'loaded', =>
     robot.brain.data.nicks ||= []

-  saluteWithRandomGif = (res) ->
-    msg = new hubot.TextMessage(res.message.user, robot.name + ' gif me hello')
+  saluteWithRandomGif = (user) ->
+    msg = new hubot.TextMessage(user, robot.name + ' gif me hello')
     robot.receive msg

   robot.enter (res) ->
@@ -50,4 +50,4 @@
         return
       add_nicks user.name
       robot.messageRoom user.name, welcomeMsg(user.name)
-      saluteWithRandomGif res
+      saluteWithRandomGif user


Failing test for deleting an entry

Failing test for deleting an entry

--- test/routes/time_entries.coffee
+++ test/routes/time_entries.coffee
@@ -74,3 +74,21 @@
       timeEntriesCreated.push te
       te.validate().should.be.true
       done()
+
+  it 'should delete a time entry', (done)->
+    ops = _.clone options
+    ops.body =
+      start: new Date('June 18, 2013')
+      end: new Date('June 22, 2013')
+      message: 'I will be deleted very soon!'
+      projectId: testProject.id
+      userId: testUser.id
+    teb = new TimeEntry ops.body
+    teb.validate().should.be.true
+    request.post (base '/time_entries'), ops, (e,r,b)->
+      r.statusCode.should.be.equal 200
+      request.del (base "/time_entries/#{b.id}"), _.clone options, (e,r,b)->
+        r.statusCode.should.be.equal 200
+        request (base "/time_entries/#{b.id}"), _.clone options, (e,r,b)->
+          r.statusCode.should.be.equal 404
+          done()


fix pause bug

fix pause bug

--- public/src/youtube/youtube-player/youtube-player-model.coffee
+++ public/src/youtube/youtube-player/youtube-player-model.coffee
@@ -28,7 +28,7 @@
           this.setTimer(this.savedPos, i)
         else
           this.clearTimer()
-          this.savePos = this.getCurrentTime()
+          this.savedPos = this.getCurrentTime()
           console.log('paused: savedPos: ' + this.savedPos)
       )


Remove redundant prefixing

Remove redundant prefixing

--- js-library/app/js/jail_iframe/classes/control_iframe.coffee
+++ js-library/app/js/jail_iframe/classes/control_iframe.coffee
@@ -17,7 +17,7 @@
     @doc.write('<!DOCTYPE html><title></title>')
     @doc.close()
     style = @doc.createElement('style')
-    style.appendChild(@doc.createTextNode(jail_window.FrameCss))
+    style.appendChild(@doc.createTextNode(FrameCss))
     #explicitly set variables on jail_window aren't implicitly in scope in IE11 in the jail frame's code; need to explicitly resolve.
     @doc.head.appendChild(style)
     @frameBody = @doc.body


Connection#isAlive

Connection#isAlive

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

   open: =>
-    if @webSocket and not @isClosed()
+    if @isAlive()
       console.log("[cable] Attemped to open WebSocket, but existing socket is #{@getState()}", Date.now())
       throw new Error("Existing connection must be closed before opening")
     else
@@ -44,8 +44,8 @@

   # Private

-  isClosed: ->
-    @isState("closing", "closed")
+  isAlive: ->
+    not @isState("closing", "closed")

   isState: (states...) ->
     @getState() in states


payment: initial subscription transaction lock implementation

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -77,6 +77,9 @@
         default     : {}
       paymentMethodId: String
       tags          : (require './schema').tags
+      transactionLock:
+        type        : Boolean
+        default     : no
     relationships   :
       linkedSubscription:
         targetType  : this
@@ -210,29 +213,35 @@
       callback null, nonce.nonce

   debit: ({ pack, multiplyFactor, shouldCreateNonce }, callback) ->
-
-    multiplyFactor    ?= 1
-    shouldCreateNonce ?= no
-
-    @checkUsage pack, multiplyFactor, (err, usage) =>
-      return callback err  if err
-
-      { quantities } = pack
-
-      op = $set: (Object.keys quantities)
-        .reduce( (memo, key) =>
-          memo["usage.#{ key }"] =
-            (@usage[key] ? 0) + quantities[key] * multiplyFactor
-          memo
-        , {})
-
-      @update op, (err) =>
+    return callback new KodingError "Your subscription is currently locked"  if @transactionLock
+
+    @update $set: transactionLock: yes, (err) =>
+      return callback err  if err
+
+      multiplyFactor    ?= 1
+      shouldCreateNonce ?= no
+
+      @checkUsage pack, multiplyFactor, (err, usage) =>
         return callback err  if err

-        if shouldCreateNonce
-          @createFulfillmentNonce pack, (multiplyFactor > 0), callback
-        else
-          callback null
+        { quantities } = pack
+
+        op = $set: (Object.keys quantities)
+          .reduce( (memo, key) =>
+            memo["usage.#{ key }"] =
+              (@usage[key] ? 0) + quantities[key] * multiplyFactor
+            memo
+          , {})
+
+        op.$set.transactionLock = no
+
+        @update op, (err) =>
+          return callback err  if err
+
+          if shouldCreateNonce
+            @createFulfillmentNonce pack, (multiplyFactor > 0), callback
+          else
+            callback null

   debit$: secure (client, options, callback) ->
     { delegate } = client.connection


Support rails/ujs and jquery/ujs

Support rails/ujs and jquery/ujs

--- app/assets/javascripts/effective_datatables/inline_crud.js.coffee
+++ app/assets/javascripts/effective_datatables/inline_crud.js.coffee
@@ -1,15 +1,34 @@
 # To achieve inline crud, we use rails' data-remote links, and override their behaviour when inside a datatable
 # This works with EffectiveForm.remote_form which is part of the effective_bootstrap gem.

+# https://github.com/rails/jquery-ujs/wiki/ajax
+# https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers
+
+$(document).on 'ajax:before', '.dataTables_wrapper .col-actions', (event) ->
+  $action = $(event.target)
+  $table = $(event.target).closest('table')
+
+  return true if ('' + $action.data('inline')) == 'false'
+
+  $params = $.param(
+    {
+      _datatable_id: $table.attr('id'),
+      _datatable_attributes: $table.data('attributes'),
+      _datatable_action: true
+    }
+  )
+
+  $action.attr('data-params', $params)
+  true
+
 # We click the New/Edit/Action button from the col-actions
-$(document).on 'ajax:beforeSend', '.dataTables_wrapper .col-actions', (e, xhr, settings) ->
-  $action = $(e.target)
-  $table = $(e.target).closest('table')
-
-  return true if ('' + $action.data('inline')) == 'false'
-
-  $params = $.param({_datatable_id: $table.attr('id'), _datatable_attributes: $table.data('attributes'), _datatable_action: true })
-  settings.url += (if settings.url.indexOf('?') == -1 then '?' else '&') + $params
+$(document).on 'ajax:beforeSend', '.dataTables_wrapper .col-actions', (event, xhr, settings) ->
+  [xhr, settings] = event.detail if event.detail # rails/ujs
+
+  $action = $(event.target)
+  $table = $(event.target).closest('table')
+
+  return true if ('' + $action.data('inline')) == 'false'

   if $action.closest('.effective-datatables-inline-row,table.dataTable').hasClass('effective-datatables-inline-row')
     # Nothing.
@@ -22,6 +41,8 @@

 # We have either completed the resource action, or fetched the inline form to load.
 $(document).on 'ajax:success', '.dataTables_wrapper .col-actions', (event, data) ->
+  [data, status, xhr] = event.detail if event.detail # rails/ujs
+
   $action = $(event.target)

   return true if ('' + $action.data('inline')) == 'false'
@@ -54,12 +75,22 @@
   EffectiveForm.remote_form_flash = ''
   true

-# Submitting an inline datatables form
-$(document).on 'ajax:beforeSend', '.dataTables_wrapper .col-inline-form', (e, xhr, settings) ->
-  $table = $(e.target).closest('table')
-
-  $params = $.param({_datatable_id: $table.attr('id'), _datatable_attributes: $table.data('attributes') })
-  settings.url += (if settings.url.indexOf('?') == -1 then '?' else '&') + $params
+## Now for the fetched form. We add the datatables params attributes
+
+$(document).on 'ajax:before', '.dataTables_wrapper .col-inline-form', (event) ->
+  $action = $(event.target)
+  $form = $action.closest('form')
+  $table = $action.closest('table')
+
+  if $form.find('input[name=_datatable_id]').length == 0
+    $('<input>').attr(
+      {type: 'hidden', name: '_datatable_id', value: $table.attr('id')}
+    ).appendTo($form)
+
+  if $form.find('input[name=_datatable_attributes]').length == 0
+    $('<input>').attr(
+      {type: 'hidden', name: '_datatable_attributes', value: $table.data('attributes')}
+    ).appendTo($form)

   true


reverted changes made to the channels controller

--- app/assets/javascripts/ems/controllers/channels_controller.coffee
+++ app/assets/javascripts/ems/controllers/channels_controller.coffee
@@ -35,14 +35,10 @@
       # This console log should print out a set containing 1 category object. However it unfortunately returns an empty
       # AssociationSet. When looking at the XHR return from the server I can clearly see the JSON object being returned
       # It just doesn't seem to be added the the channels association set of categories.
-      console?.log @get('channel.categories')
-
-      setTimeout(=>
-        console?.log @get('channel.categories')
-      , 1000)
-
+      console?.log @get('channel').get('categories')
       # This console log prints out a Batman.Set containing all the channels associated to this category. All seems to
       # be working here.
+      console?.log category.get('channels')

   update: ->
     @get('channel').save (err) =>


kite: zap whitespace

kite: zap whitespace

--- client/app/MainApp/kite/kite.coffee
+++ client/app/MainApp/kite/kite.coffee
@@ -35,7 +35,7 @@
     @channel.ping                       = @bound 'pingChannel'
     @channel.setStartPinging            = @bound 'setStartPinging'
     @channel.setStopPinging             = @bound 'setStopPinging'
-
+
     @channel.on 'message'               , @bound 'handleChannelMessage'
     @channel.on 'message'               , @bound 'handleMessageArrived'
     @channel.on 'publish'               , @bound 'handleChannelPublish'
@@ -65,7 +65,7 @@

   handleMessageArrived: ->
     clearTimeout @unresponsiveTimeoutId
-
+
     @unresponded = 0

     @pingTimeoutId = setTimeout =>
@@ -75,14 +75,14 @@
   handleChannelMessage: (args) ->

     {method} = args
-
+
     callback = switch method
       when 'ready'            then @bound 'handleReady'
       when 'error'            then @bound 'handleError'
       when 'pong'             then @bound 'handlePong'
       when 'cycleChannel'     then @bound 'cycleChannel'
       else (@localStore.get method) ? ->
-
+
     callback.apply this, @unscrub args

   handleChannelPublish: ->


fix typo

fix typo

--- zechat/static/crypto.coffee
+++ zechat/static/crypto.coffee
@@ -66,8 +66,8 @@
     return deferred.promise

   encrypt: (data) ->
-    decrypted = @create_rsa().encryptOAEP(data)
-    return Q(hex2b64(decrypted))
+    encrypted = @create_rsa().encryptOAEP(data)
+    return Q(hex2b64(encrypted))

   decrypt: (data) ->
     try


keep more nonce bits

keep more nonce bits

--- zechat/static/crypto.coffee
+++ zechat/static/crypto.coffee
@@ -48,10 +48,9 @@

   nonce: ->
     now = zc.nacl.encode_latin1(""+Date.now())
-    hash = zc.nacl.crypto_hash(zc.u8cat(@last_nonce, now))
-    new_nonce = hash.subarray(0, @NONCE_SIZE)
+    new_nonce = zc.nacl.crypto_hash(zc.u8cat(@last_nonce, now))
     @last_nonce = new_nonce
-    return new_nonce
+    return new_nonce.subarray(0, @NONCE_SIZE)

   encrypt: (message, sender_b64, recipient_pub_b64) ->
     sender = zc.secret_key(sender_b64)


Fix link color

Fix link color

--- resources/assets/coffee/react/beatmap-discussions/post.coffee
+++ resources/assets/coffee/react/beatmap-discussions/post.coffee
@@ -127,7 +127,9 @@
             className: "#{bn}__info #{bn}__info--edited"
             dangerouslySetInnerHTML:
               __html: osu.trans 'beatmaps.discussions.edited',
-                editor: laroute.link_to_route('users.show', @props.lastEditor.username, user: @props.lastEditor.id)
+                editor: osu.link laroute.route('users.show', user: @props.lastEditor.id),
+                  @props.lastEditor.username
+                  classNames: ["#{bn}__info-user"]
                 update_time: osu.timeago @props.post.updated_at

       if @props.canBeEdited


Login: login link copies simplified

Login: login link copies simplified

--- client/landing/Login/AppView.coffee
+++ client/landing/Login/AppView.coffee
@@ -23,40 +23,33 @@
     loginHandler                  = handler.bind null, '/Login'
     registerHandler               = handler.bind null, '/Register'
     recoverHandler                = handler.bind null, '/Recover'
-    resendMailConfirmationHandler = handler.bind null, '/ResendToken'

     @logo = new KDCustomHTMLView
-      tagName     : "div"
       cssClass    : "logo"
-      partial     : "Koding"
+      partial     : "Koding"
       click       : homeHandler

     @backToLoginLink = new KDCustomHTMLView
-      tagName   : "a"
-      partial   : "Go ahead and login"
-      click     : loginHandler
+      tagName     : "a"
+      partial     : "Sign In"
+      click       : loginHandler

     @goToRecoverLink = new KDCustomHTMLView
       tagName     : "a"
-      partial     : "Recover password"
+      partial     : "Forgot your password?"
       testPath    : "landing-recover-password"
       click       : recoverHandler

     @goToRegisterLink = new KDCustomHTMLView
       tagName     : "a"
-      partial     : "Register an account"
+      partial     : "Create Account"
       click       : registerHandler

-    @goToResendMailConfirmationLink = new KDCustomHTMLView
-      tagName     : "a"
-      partial     : "Resend"
-      click       : resendMailConfirmationHandler
-
-    @loginOptions = new LoginOptions
-      cssClass : "login-options-holder log"
-
-    @registerOptions = new RegisterOptions
-      cssClass : "login-options-holder reg"
+    # @loginOptions = new LoginOptions
+    #   cssClass : "login-options-holder log"
+
+    # @registerOptions = new RegisterOptions
+    #   cssClass : "login-options-holder reg"

     @loginForm = new LoginInlineForm
       cssClass : "login-form"
@@ -173,12 +166,13 @@

-
Not a member? {{> @goToRegisterLink}}

-
Already a member? {{> @backToLoginLink}}

-
Trouble logging in? {{> @goToRecoverLink}}

-
Didn't receive confirmation email? {{> @goToResendMailConfirmationLink}}

-
Terms of service / Privacy policy

+

+
{{> @goToRecoverLink}}

{{> @goToRegisterLink}}•{{> @backToLoginLink}}

+

+
+      Terms of service•Privacy policy•photo by some motherf*cker
+
     """

   doReset:({recoveryToken, password, clientId})->


PUBDEV-2339 PUBDEV-2337 Persist column type changes into source frame

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -1255,7 +1255,7 @@
         catch columnKeyError
           return go columnKeyError

-        _.requestExec "(:= #{frame} (#{method} (cols #{frame} #{columnIndex})) #{columnIndex} [0:#{result.rows}])", (error, result) ->
+        _.requestExec "(assign #{frame} (:= #{frame} (#{method} (cols #{frame} #{columnIndex})) #{columnIndex} [0:#{result.rows}]))", (error, result) ->
           if error
             go error
           else


Make dump() log to the browser console as well

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -975,7 +975,9 @@
       .fail onFail

   dumpFuture = (result, go) ->
-    go null, render_ (result or {}), -> Flow.ObjectBrowser 'dump', result
+    debug result
+    go null, render_ (result or {}), ->
+      Flow.ObjectBrowser 'dump', result

   dump = (f) ->
     if f?.isFuture


Fix preview mode

Fix preview mode

--- app/assets/javascripts/tenon/features/tenon_content/pop_out.js.coffee
+++ app/assets/javascripts/tenon/features/tenon_content/pop_out.js.coffee
@@ -8,7 +8,7 @@
     e.preventDefault();
     $link = $(e.currentTarget)
     $template = $(JST['tenon/templates/tenon_content/popped_out']())
-    $wrap = $(e.currentTarget).next('.tn-tc-wrap')
+    $wrap = $link.closest('.tn-tc-main-actions').next('.tn-tc-wrap')
     $wrap.find('.tn-tc-pop-out-close').data('place', $link)
     $wrap.appendTo($template.find('.tn-tc-sizer'))
     $template.appendTo('body')
@@ -31,7 +31,7 @@
     $link.closest('.tn-tc-wrap')
       .css('width', '')
       .removeClass('mobile-breakpoint')
-      .insertAfter($link.data('place'))
+      .insertAfter($link.data('place').closest('.tn-tc-main-actions'))
       .trigger('tenon.content.popped')
     $('.tn-tc-popped-out').remove();


Guard console output with debug flag

Guard console output with debug flag

--- app/assets/javascripts/interaction_web_tools/chat.coffee
+++ app/assets/javascripts/interaction_web_tools/chat.coffee
@@ -14,6 +14,8 @@
     @queuedMessages = []
     @endpoint = '/interaction_web_tools/events'
     @chatUI = $('#chat-ui')
+    if window.location.href.indexOf('debug=1') > -1
+      @debug = true

   open: =>
     @chatUI.toggleClass('active')
@@ -60,6 +62,7 @@
       @renderMessages data.events

   queueMessage: (message) ->
+    console.log "add " + message + " to " + @queuedMessages if @debug
     @queuedMessages.push(message)

   dismissWelcome: ->
@@ -67,12 +70,13 @@

   dequeueMessages: ->
     $.each @queuedMessages, (i,message) =>
+    console.log "dequeue messages " + @queuedMessages if @debug
       @sendMessage(message)
     @queuedMessages = []

   renderMessages: (messages) ->
-    console.log "messages recieved for render", messages
     typing = $.grep messages, (el) -> el.type == 'typingIndicator' && el.content == true
+    console.log "messages recieved for render", messages if @debug
     @displayIndicator("agent") if typing.length

     messages = $.grep messages, (el) -> el.type == 'text'


remove old tutorial

remove old tutorial

--- games/edit.coffee
+++ games/edit.coffee
@@ -1,118 +0,0 @@
-#
-# edit.coffee
-#
-# The followup Hour of Node Tutorial
-#
-# Role: explain how to create and share your own levels
-#
-# Responsible to Teach:
-#
-# - Edit / Save Controls
-# - Renaming the Level
-# - Customize Name and Color
-# - Select a Sprite
-# - Click to Create a Sprite
-#
-# TODO:
-# - Changing the Kinds [popup]
-# - Editable and Obstruction [checkbox]
-# - Display and Change Direction [popup] N/S/E/W
-
-exports.game = {
-  name: 'BETA: Click "Edit" to Modify Levels'
-  assume: 'baseline'
-  comment: "The followup Hour of NODE tutorial"
-  author: {name: 'Ernest Prabhakar', url: 'https://github.com/drernie'}
-  license: {
-    name: 'Creative Commons Attribution 4.0 International'
-    url: 'http://creativecommons.org/licenses/by/4.0/'
-  }
-
-  levels: [
-    {
-      name: 'Click "Edit" to Modify; "Save" and "Run" to Share'
-      comment: '
-      Can edit the level name, sprite name, and sprite color. (DEVELOP)
-      Must first solve the puzzle to validate it. (TEST)
-      Can then share it from the post-level splash screen. (DEPLOY)
-      Affirms the importance of good integration testing!
-      '
-      edit_mode: true
-      bricks: 2
-      goal: { clicks: 1, bricks: 2, ticks: 5 }
-      sprites: [
-        { kind: 'gate', actions: {bump: ['_victory']}, position: [4,0] }
-        {
-          kind: 'turtle'
-          actions: { run: ['forward'], bump: ['right'] }
-        }
-      ]
-    }
-    {
-      name: 'Click Turtle You Want To Program'
-      comment: '
-      Can select multiple turtles which act independently.
-      This is a primitive form of parallel processing.
-      Optimal solution is to move the blocking turtle.
-      '
-      edit_mode: true
-      bricks: 2
-      goal: { clicks: 1, bricks: 3, ticks: 5 }
-      sprites: [
-        { kind: 'gate', actions: {bump: ['_victory']}, position: [4,0] }
-        {
-          kind: 'turtle'
-          name: 'yu'
-          position: [2,0]
-          direction: [0, 1]
-          fill: 'purple'
-          actions: { run: [], bump: [] }
-        }
-        {
-          kind: 'turtle'
-          actions: { run: ['forward'], bump: ['right'] }
-        }
-      ]
-    }
-    {
-      name: 'Click Blue Pond to Add and Select Logs'
-      editing: true
-      comment: '
-      Can create arbitrary sprites and program them if in edit mode.
-      '
-      goal: { clicks: 1, bricks: 2, ticks: 11 }
-      bricks: 1
-      sprites: [
-        { kind: 'gate', actions: {bump: ['_victory']}, position: [4,4] }
-        {
-          kind: 'turtle'
-          actions: {
-            run: ['forward']
-            bump: ['right']
-          }
-        }
-      ]
-    }
-    {
-      name: 'Create and Share Your Own Level'
-      comment: '
-      Encourage students to express themselves.
-      Track the solution and use that for the new goal metrics.
-      After completion, can share via email or social media.
-      Will run on our app via a custom URL.
-      '
-      goal: { clicks: 99, bricks: 99, ticks: 99 }
-      bricks: 2
-      sprites: [
-        { kind: 'gate', actions: {bump: ['_victory']}, position: [7,7] }
-        {
-          kind: 'turtle'
-          actions: {
-            run: ['forward']
-            bump: ['right']
-          }
-        }
-      ]
-    }
-  ]
-}


EDSC-9: Fix code to detect null maps

EDSC-9: Fix code to detect null maps

--- app/assets/javascripts/models/ui/granules_list.js.coffee
+++ app/assets/javascripts/models/ui/granules_list.js.coffee
@@ -38,6 +38,7 @@
       # generally hosing the workspace
       unless map?
         setTimeout(@_constructWithDom, 0)
+        return

       @_map = map.map
       @_map.on 'edsc.focusgranule', @_onFocusGranule


OX-645 renamed boolean in skeleton

OX-645 renamed boolean in skeleton

--- app/assets/javascripts/oxalis/geometries/skeleton.coffee
+++ app/assets/javascripts/oxalis/geometries/skeleton.coffee
@@ -528,10 +528,10 @@
     @showInactiveTrees = not @showInactiveTrees
     @setInactiveTreeVisibility(@showInactiveTrees)

-  setInactiveTreeVisibility : (boolean) ->
+  setInactiveTreeVisibility : (visible) ->
     for mesh in @getMeshes()
       if mesh != @activeNodeParticle
-        mesh.visible = boolean
+        mesh.visible = visible
     index = @getIndexFromTreeId(@route.getTree().treeId)
     @routes[index].visible = true
     @nodes[index].visible = true
@@ -558,13 +558,13 @@
     hsvColor.h = (hsvColor.h + 0.5) % 1
     ColorConverter.setHSV(new THREE.Color(), hsvColor.h, hsvColor.s, hsvColor.v).getHex()

-  setSizeAttenuation : (boolean) ->
-
-    @mode = if boolean then constants.MODE_ARBITRARY else constants.MODE_PLANE_TRACING
+  setSizeAttenuation : (sizeAttenuation) ->
+
+    @mode = if sizeAttenuation then constants.MODE_ARBITRARY else constants.MODE_PLANE_TRACING
     for particleSystem in @nodes
-      particleSystem.material.sizeAttenuation = boolean
+      particleSystem.material.sizeAttenuation = sizeAttenuation
       particleSystem.material.needsUpdate = true
-    @branches.material.sizeAttenuation = boolean
+    @branches.material.sizeAttenuation = sizeAttenuation
     @branches.material.needsUpdate = true
-    @activeNodeParticle.material.sizeAttenuation = boolean
+    @activeNodeParticle.material.sizeAttenuation = sizeAttenuation
     @activeNodeParticle.material.needsUpdate = true


null check error in pdf view

null check error in pdf view

--- services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
@@ -369,7 +369,7 @@
 				scope.$on 'pdf:error', (event, error) ->
 					return if error == 'cancelled'
 					# check if too many retries or file is missing
-					if scope.loadCount > 3 || error.match(/^Missing PDF/i) || error.match(/^loading/i)
+					if scope.loadCount > 3 || error?.match(/^Missing PDF/i) || error?.match(/^loading/i)
 						scope.$emit 'pdf:error:display'
 						return
 					if scope.loadSuccess


another pull load_models from the right place

--- bokehjs/src/coffee/server/usercontext/usercontext.coffee
+++ bokehjs/src/coffee/server/usercontext/usercontext.coffee
@@ -7,13 +7,13 @@
     "./wrappertemplate",
     "common/has_parent",
     "common/build_views",
+    "common/load_models",
 ],  (base, serverutils, continuum_view,
     userdocstemplate, documentationtemplate,
-    wrappertemplate, HasParent, build_views
+    wrappertemplate, HasParent, build_views, load_models
     ) ->
   exports = {}
   ContinuumView = continuum_view.View
-  load_models = base.load_models
   utility = serverutils.utility

   class DocView extends ContinuumView