Refactor: rename arg to is_in_edit_mode

Refactor: rename arg to is_in_edit_mode

--- app/assets/javascripts/home.js.coffee
+++ app/assets/javascripts/home.js.coffee
@@ -100,9 +100,9 @@
     element.removeClass('visible')
     element.addClass('hidden')

-set_fields_to_edit_mode = (in_edit_mode) ->
-  set_field_to_edit_mode(user_name(), in_edit_mode)
-  set_field_to_edit_mode(user_title(), in_edit_mode)
+set_fields_to_edit_mode = (is_in_edit_mode) ->
+  set_field_to_edit_mode(user_name(), is_in_edit_mode)
+  set_field_to_edit_mode(user_title(), is_in_edit_mode)
   set_field_to_edit_mode(user_email(), false)           # always 'false' because email is not editable

 set_field_to_edit_mode = (element, is_in_edit_mode) ->


preview map renders saved addr in edit

preview map renders saved addr in edit

--- app/assets/javascripts/maps.js.coffee
+++ app/assets/javascripts/maps.js.coffee
@@ -40,12 +40,20 @@
       zoom: 13,
       mapTypeId: google.maps.MapTypeId.ROADMAP,
       streetViewControl: false,
-      mapTypeControl: false
+      mapTypeControl: false,
+      scrollwheel: false

     preview_marker = new google.maps.Marker
       map: preview_map,
       position: default_latlng,
       visible: false
+
+    if $('#violation_address').val().length > 0
+      saved_latlng = new google.maps.LatLng $('#violation_latitude').val(), $('#violation_longitude').val()
+      preview_map.setCenter saved_latlng
+      preview_map.setZoom 15
+      preview_marker.setPosition saved_latlng
+      preview_marker.setVisible true

     $('#violation_address').on 'keyup', $.debounce(500, ->
       addr = $(this).val()


fixed error where data being passed was null because it was not returned from the api, now the change function checks for non null data before drawing the d3

--- app/scripts/directives/d3Donut.coffee
+++ app/scripts/directives/d3Donut.coffee
@@ -12,10 +12,14 @@
     link: (scope, element, attrs)->

       scope.change = ->
-        scope.percent = (scope.contributor.total_amount / scope.scale)
+        if scope.contributor
+          scope.percent = (scope.contributor.total_amount / scope.scale)
+          # get favicon url from contributor name
+          ApiGet.own "favicon?company=\"#{scope.contributor.name}\"", scope.draw_favicon, this
+          scope.drawD3()

       # on window resize, redraw d3 canvas
-      scope.$watch( (-> angular.element(window)[0].innerWidth), (-> scope.drawD3(); scope.draw_favicon()) )
+      scope.$watch( (-> angular.element(window)[0].innerWidth), (-> scope.change()) )
       window.onresize = (-> scope.$apply())
       # make the canvas once
       canvas = d3.select(element[0]).append("svg")
@@ -30,8 +34,6 @@
             .attr("width", scope.radius)
             .attr("height", scope.radius)
             .attr("transform", "translate(#{scope.radius/2},#{scope.radius/2})")
-      # get favicon url from contributor name
-      ApiGet.own "favicon?company=\"#{scope.contributor.name}\"", scope.draw_favicon, this

       # draw d3 here on the canvas defined above
       scope.drawD3 = ->
@@ -88,9 +90,6 @@
             .call(arcTween, scope.percent * τ)

       # watch for attribute changes and call the changed function
-      scope.$watch 'contributor', scope.change()
-      scope.$watch 'scope', scope.change()
-
-      # initial run
-      scope.drawD3()
+      scope.$watch 'contributor', (-> scope.change())
+      scope.$watch 'scale', (-> scope.change())
   ]


if auth_headers gone, redirect to login page with toast

--- app/services/authenticate-user.coffee
+++ app/services/authenticate-user.coffee
@@ -1,27 +1,33 @@
 null

 ### @ngInject ###
-global.cobudgetApp.factory 'AuthenticateUser', (Records, ipCookie, Toast, $location, $stateParams, $q) ->
+global.cobudgetApp.factory 'AuthenticateUser', (Records, ipCookie, Toast, $location, $stateParams, $q, $auth) ->
   () ->
     deferred = $q.defer()
+
     if ipCookie('currentUserId')
-      Records.memberships.fetchMyMemberships().then (data) ->
-        if groupId = parseInt($stateParams.groupId)
-          if !(_.find data.groups, (group) -> group.id == groupId)
-            Toast.show('The group you were trying to access is private')
-            ipCookie.remove('initialRequestPath')
-            $location.path('/')
-            deferred.reject()
-        if bucketId = parseInt($stateParams.bucketId)
-          bucket = Records.buckets.findOrFetchById(bucketId).then (bucket) ->
-            userIsMemberOfBucketGroup = _.find data.groups, (group) ->
-              group.id == bucket.groupId
-            if !userIsMemberOfBucketGroup
-              Toast.show('The bucket you were trying to access is private')
+      Records.memberships.fetchMyMemberships()
+        .then (data) ->
+          if groupId = parseInt($stateParams.groupId)
+            if !(_.find data.groups, (group) -> group.id == groupId)
+              Toast.show('The group you were trying to access is private')
               ipCookie.remove('initialRequestPath')
               $location.path('/')
               deferred.reject()
-
+          if bucketId = parseInt($stateParams.bucketId)
+            bucket = Records.buckets.findOrFetchById(bucketId).then (bucket) ->
+              userIsMemberOfBucketGroup = _.find data.groups, (group) ->
+                group.id == bucket.groupId
+              if !userIsMemberOfBucketGroup
+                Toast.show('The bucket you were trying to access is private')
+                ipCookie.remove('initialRequestPath')
+                $location.path('/')
+                deferred.reject()
+        .catch (data) ->
+          Toast.show('Please log in to continue')
+          $location.path('/')
+          deferred.reject()
+
         deferred.resolve()
     else
       ipCookie('initialRequestPath', $location.path())


Remove unused serialize

Remove unused serialize

fixes #2

--- lib/caniuse.coffee
+++ lib/caniuse.coffee
@@ -5,61 +5,58 @@
   config:
     showIe:
       title: 'Show IE'
-      type:'boolean'
+      type: 'boolean'
       default: true
     showFirefox:
-      type:'boolean'
+      type: 'boolean'
       default: true
     showChrome:
-      type:'boolean'
+      type: 'boolean'
       default: true
     showSafari:
-      type:'boolean'
-	  default: true
+      type: 'boolean'
+      default: true
     showOpera:
-      type:'boolean'
+      type: 'boolean'
       default: false
     showIosSaf:
       title: 'Show iOS Safari'
-      type:'boolean'
+      type: 'boolean'
       default: true
     showOpMini:
       title: 'Show Opera Mini'
-      type:'boolean'
+      type: 'boolean'
       default: false
     showAndroid:
       title: 'Show Android Browser'
-      type:'boolean'
+      type: 'boolean'
       default: true
     showOpMob:
       title: 'Show Opera Mobile'
-      type:'boolean'
+      type: 'boolean'
       default: false
     showBb:
       title: 'Show Blackberry Browser'
-      type:'boolean'
+      type: 'boolean'
       default: false
     showAndChr:
       title: 'Show Chrome for Android'
-      type:'boolean'
+      type: 'boolean'
       default: true
     showAndFf:
       title: 'Show Firefox for Android'
-      type:'boolean'
+      type: 'boolean'
       default: false
     showIeMob:
       title: 'Show IE Mobile'
-      type:'boolean'
+      type: 'boolean'
       default: false
     showAndUc:
       title: 'Show UC Browser for Android'
-      type:'boolean'
+      type: 'boolean'
       default: false

   activate: (state) ->
     atom.workspaceView.command 'caniuse:show', =>
-      @caniuseView = new CaniuseView(state.atomCaniuseViewState)
+      @caniuseView = new CaniuseView()
       @caniuseView.show()
-
-  serialize: ->
-    caniuseViewState: @caniuseView.serialize()


Locals fix

Locals fix

--- lib/compile.coffee
+++ lib/compile.coffee
@@ -270,7 +270,7 @@
         close = getCloseTag match

         if close
-          """{{#locals "#{expression}"}}\n  #{close.before}\n{{/locals}}\n#{close.after}"""
+          """{{#locals "#{expression}"}}\n  #{close.before.replace /\slocals=/, ' data-locals='}\n{{/locals}}\n#{close.after}"""
         else
           throw new Error 'Parse error! Could not find close tag for locals directive\n\n' + match + '\n\n' + file
       )


handle ink not loaded

handle ink not loaded

--- lib/console.coffee
+++ lib/console.coffee
@@ -1,5 +1,6 @@
 module.exports =
   create: ->
+    return unless @ink?
     if not @c?
       @c = @ink.console.create()
       @c.view.getTitle = -> "Julia"
@@ -11,7 +12,7 @@
       @c.input()
     @c

-  toggle: -> @create().toggle()
+  toggle: -> @create()?.toggle()

   eval: (ed) ->
     if ed.getText()


More cleanups

More cleanups

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -262,49 +262,43 @@
     @view = new VimCommandModeInputView(@)

   execute: (count=1) ->
-    _.times count, =>
-      @findOrBeep (pos) =>
-        @editor.setCursorBufferPosition(pos)
+    @match count, (pos) =>
+      @editor.setCursorBufferPosition(pos)

   select: (count=1) ->
     cur = @editor.getCursorBufferPosition()
-    _.times count, =>
-      @findOrBeep (pos) =>
-        @editor.setSelectedBufferRange([cur, pos])
-        true
+    @match count, (pos) =>
+      @editor.setSelectedBufferRange([cur, pos])
+    [true]

   confirm: (view) =>
+    @scan(view.value)
     @editor.trigger 'vim-mode:search-complete'

-  findOrBeep: (callback)->
-    pos = @findNext(@view.value)
+  match: (count, callback) ->
+    window.matches = @matches
+    window.count = count
+
+    pos = @matches[(count - 1) % @matches.length]
     if pos?
       callback(pos)
     else
       shell.beep()

-  findNext: (term) ->
+  scan: (term) ->
     regexp = new RegExp(term, 'g')
-    result = null
-
-    pos = @editor.getCursorBufferPosition()
+    cur = @editor.getCursorBufferPosition()
     matchPoints = []
-
     iterator = (item) =>
       matchPoints.push(item.range.start)

     @editor.activeEditSession.scan(regexp, iterator)

-    previous = (p for p in matchPoints when p.compare(pos) <= 0)
-    after = (p for p in matchPoints when p.compare(pos) == 1)
-
-    if after.length > 0
-      return after[0]
-    else if previous.length > 0
-      return previous[0]
-    else
-      shell.beep()
-      return null
+    previous = _.filter matchPoints, (point) ->
+      point.compare(cur) <= 0
+    after = _.difference(matchPoints, previous)
+    after.push(previous...)
+    @matches = after

 module.exports = { Motion, CurrentSelection, SelectLeft, SelectRight, MoveLeft,
   MoveRight, MoveUp, MoveDown, MoveToPreviousWord, MoveToNextWord,


runtime: Hide some internal API

runtime: Hide some internal API

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -540,8 +540,6 @@
         @uploadGraph graph, callback

 module.exports =
-    subscribeEdges: subscribeEdges
-    sendPackets: sendPackets
     setupRuntime: setupRuntime
     setupWebsocket: setupWebsocket
     setupSimulator: setupSimulator
@@ -549,5 +547,3 @@
     uploadGraphFromFile: uploadGraphFromFile
     createFlowhubRuntime: createFlowhubRuntime
     registerFlowhubRuntime: registerFlowhubRuntime
-    handleMessage: handleMessage
-    deviceResponseToFbpProtocol: deviceResponseToFbpProtocol # XXX: should be encapsulated


Worker: generate DZIs too.

Worker: generate DZIs too.

But TODO: DeepZoomTools throws an error.

--- lib/worker._coffee
+++ lib/worker._coffee
@@ -20,6 +20,8 @@

 config = require '../config'
 crypto = require 'crypto'
+DeepZoomImage = require 'deepzoomtools'
+DZIParser = require './dziparser'
 FS = require 'fs-extra'
 OS = require 'os'
 Path = require 'path'
@@ -56,14 +58,17 @@
         dir = makeTempDir _

         # Download the content to a file (within our temp dir) named by the ID:
-        src = Path.join dir, content.id
-        echo 'Downloading content to temp dir... id=%j, file=%j', id, src
-        downloadFile content.url, src, _
+        file = Path.join dir, content.id
+        echo 'Downloading content to temp dir... id=%j, file=%j', id, file
+        downloadFile content.url, file, _

-        # TODO
+        echo 'Generating DZI for content... id=%j', id
+        dzi = createDZI file, _

-        # destination = processor.process source, _
-        # dzi = DZIParser.parse destination, _
+        echo 'Parsing the generated DZI... id=%j', id
+        dzi = DZIParser.parse dzi, _
+
+        # TODO: Upload!

         # erro 'Success! Marking content as ready... id=%j', id
         # content.markReady dzi, _
@@ -82,7 +87,6 @@
             FS.remove dir, _ if dir

         echo 'Finished processing content. id=%j', id
-

 ## HELPERS:
@@ -121,6 +125,18 @@

      req.pipe file

+# Automatically derives and returns the name of the destination DZI.
+# TODO: Find some way to report progress here.
+createDZI = (src, _) ->
+    dir = Path.dirname src
+    ext = Path.extname src
+    base = Path.basename src, ext
+    dest = Path.join dir, "#{base}.dzi"
+
+    DeepZoomImage.create _, src, dest
+
+    dest
+

 ## MAIN:


DockController: Set nav item states for already existing nav items

--- client/Main/maincontroller/dockcontroller.coffee
+++ client/Main/maincontroller/dockcontroller.coffee
@@ -152,8 +152,10 @@
       # Listen appManager to update dock items states
       {appManager, kodingAppsController} = KD.singletons

-      kodingAppsController.on "LoadingAppScript", (name)=>
-        @setNavItemState {name}, 'loading'
+      for name of appManager.appControllers
+        @setNavItemState {name}, 'active'
+
+      {appManager, kodingAppsController} = KD.singletons

       appManager.on "AppRegistered", (name, options) =>
         @setNavItemState {name, options}, 'running'


MachineSettingsPopup: Hide terminate button for free, hobyist users [#79416228]

--- client/Main/providers/machinesettingsview.coffee
+++ client/Main/providers/machinesettingsview.coffee
@@ -187,3 +187,7 @@
     @addSubView new KDCustomHTMLView
       cssClass : 'modal-arrow'
       position : top : 20
+
+    computeController.fetchUserPlan (plan)=>
+      @terminateButton.hide()  if plan in ['free', 'hobbyist']
+


Social: Unfollow activity feature is available

--- client/Social/Activity/views/settingsview.coffee
+++ client/Social/Activity/views/settingsview.coffee
@@ -27,11 +27,21 @@

     {socialapi} = KD.singletons
     post = @getData()
-    @addMenuItem 'Follow Post', =>
-      messageId = post.getId()
-      socialapi.channel.pin {messageId}, (err)->
-        return KD.showError err  if err
-        log 'post pinned'
+
+    unless post.followed
+      menuItem = 'Follow Post'
+      fn = socialapi.channel.pin
+      logMessage = 'post pinned'
+    else
+      menuItem = 'Unfollow Post'
+      fn = socialapi.channel.unpin
+      logMessage = 'post unpinned'
+
+    @addMenuItem menuItem, =>
+        messageId = post.getId()
+        fn {messageId}, (err)->
+          return KD.showError err  if err
+          log logMessage

     return @menu


Split platform specific keybindings

Split platform specific keybindings

--- keymaps/image-view.cson
+++ keymaps/image-view.cson
@@ -1,6 +1,13 @@
-'.image-view':
-  'meta-+': 'image-view:zoom-in'
-  'meta-=': 'image-view:zoom-in'
-  'meta--': 'image-view:zoom-out'
-  'meta-_': 'image-view:zoom-out'
-  'meta-0': 'image-view:reset-zoom'
+'.platform-darwin .image-view':
+  'cmd-+': 'image-view:zoom-in'
+  'cmd-=': 'image-view:zoom-in'
+  'cmd--': 'image-view:zoom-out'
+  'cmd-_': 'image-view:zoom-out'
+  'cmd-0': 'image-view:reset-zoom'
+
+'.platform-win32 .image-view':
+  'ctrl-+': 'image-view:zoom-in'
+  'ctrl-=': 'image-view:zoom-in'
+  'ctrl--': 'image-view:zoom-out'
+  'ctrl-_': 'image-view:zoom-out'
+  'ctrl-0': 'image-view:reset-zoom'


Topic Modification: apply styling to tag moderation function

--- workers/social/lib/social/models/tag.coffee
+++ workers/social/lib/social/models/tag.coffee
@@ -275,15 +275,13 @@
   create = (data, creator, callback) =>
     tag = new JTag data
     tag.createSlug (err, slug)->
-      if err then callback err
-      else
-        tag.slug = slug.slug
-        tag.save (err)->
-          if err then callback err
-          else
-            tag.addCreator creator, (err)->
-              if err then callback err
-              else callback null, tag
+      return callback err  if err
+      tag.slug = slug.slug
+      tag.save (err)->
+        return callback err  if err
+        tag.addCreator creator, (err)->
+          return callback err  if err
+          callback null, tag

   checkTagExistence = (tag, callback) =>
     {title, category} = tag


List project categories in latest project block

Signed-off-by: Max Fierke <0706025b2bbcec1ed8d64822f4eccd96314938d0@maxfierke.com>

--- app/assets/javascripts/projects.js.coffee
+++ app/assets/javascripts/projects.js.coffee
@@ -53,6 +53,9 @@
             proj = data.projects[0]
             $lp.find(".project-title a").text(proj.name).prop "href", "/projects/" + proj.id
             $lp.find(".project-shortdesc").text proj.shortDescription
+            $pt = $lp.find(".project-tags")
+            for i of proj.categories
+              $pt.append "
" + proj.categories[i].name + "
"
             $lp.parent().removeClass('hidden')

     init: ->


Typo.

Typo.

--- app/node_modules/xo-services/index.coffee
+++ app/node_modules/xo-services/index.coffee
@@ -95,7 +95,7 @@
         patch: action 'Upload patch', 'pool.patch', argsMapper: (pool) -> {pool}

       host:
-        attach:           action 'Atach host'#, 'host.attach'
+        attach:           action 'Attach host'#, 'host.attach'
         detach:           action 'Detach host', 'host.detach'
         restart:          action 'Restart host', 'host.restart'
         restartToolStack: action 'Restart tool stack', 'host.restart_agent'


pubnub: change error handling and create a new handleMessage method

--- client/Main/realtimecontroller.coffee
+++ client/Main/realtimecontroller.coffee
@@ -194,56 +194,18 @@

       channelInstance = new PubnubChannel name: pubnubChannelName

-      err = @pubnub.subscribe
+      callbackCalled = no
+      @pubnub.subscribe
         channel : pubnubChannelName
-        message : (message, env, channel) =>
-
-          return  unless message
-
-          {eventName, body, eventId} = message
-
-          return  unless eventName and body
-
-          if eventId?
-            return  if @eventCache[eventId]
-
-            # TODO delete this periodically
-            @eventCache[eventId] = yes
-
-
-          # when a user is connected in two browsers, and leaves a channel, in second one
-          # they receive RemovedFromChannel event for their own. Therefore we must unsubscribe
-          # user from all connected devices.
-          if eventName is 'RemovedFromChannel' and body.accountId is KD.whoami().socialApiId
-            return @unsubscribePubnub message.channel
-
-          # no need to emit any events when not subscribed
-          return  unless @channels[channel]
-
-          # instance events are received via public channel. For this reason
-          # if an event name includes "instance-", update the related message channel
-          # An instance event format is like "instance-5dc4ce55-b159-11e4-8329-c485b673ee34.ReplyAdded"
-          if eventName.indexOf("instance-") < 0
-            return @channels[channel].emit eventName, body
-
-          events = eventName.split "."
-          if events.length < 2
-            warn 'could not parse event name', eventName
-            return
-
-          instanceChannel = events[0]
-          eventName = events[1]
-
-          return  unless @channels[instanceChannel]
-
-          @channels[instanceChannel].emit eventName, body
-
-
+        message : (message, env, channel) => @handleMessage message, channel
         connect : =>
           @channels[pubnubChannelName] = channelInstance
           @removeFromForbiddenChannels pubnubChannelName
+          callbackCalled = yes
           callback null, channelInstance
-        error   : (err) => @handleError err
+        error   : (err) =>
+          @handleError err
+          callback err  unless callbackCalled
         reconnect: => @getTimeDiffWithServer()
         # with each channel subscription pubnub resubscribes to every channel
         # and some messages are dropped in this resubscription time interval
@@ -254,7 +216,49 @@
         timetoken: (((new Date()).getTime() - 3000) * 10000) - @timeDiff
         restore : yes

-      return callback err  if err
+
+  handleMessage: (message, channel) ->
+
+    return  unless message
+
+    {eventName, body, eventId} = message
+
+    return  unless eventName and body
+
+    if eventId?
+      return  if @eventCache[eventId]
+
+      # TODO delete this periodically
+      @eventCache[eventId] = yes
+
+
+    # when a user is connected in two browsers, and leaves a channel, in second one
+    # they receive RemovedFromChannel event for their own. Therefore we must unsubscribe
+    # user from all connected devices.
+    if eventName is 'RemovedFromChannel' and body.accountId is KD.whoami().socialApiId
+      return @unsubscribePubnub message.channel
+
+    # no need to emit any events when not subscribed
+    return  unless @channels[channel]
+
+    # instance events are received via public channel. For this reason
+    # if an event name includes "instance-", update the related message channel
+    # An instance event format is like "instance-5dc4ce55-b159-11e4-8329-c485b673ee34.ReplyAdded"
+    if eventName.indexOf("instance-") < 0
+      return @channels[channel].emit eventName, body
+
+    events = eventName.split "."
+    if events.length < 2
+      warn 'could not parse event name', eventName
+      return
+
+    instanceChannel = events[0]
+    eventName = events[1]
+
+    return  unless @channels[instanceChannel]
+
+    @channels[instanceChannel].emit eventName, body
+

   getTimeDiffWithServer: ->
     @pubnub.time (serverTime) =>


Adjust SO poller to sort by 'creation' instead of 'activity'

--- scripts/stackoverflow-poller.coffee
+++ scripts/stackoverflow-poller.coffee
@@ -25,7 +25,7 @@
     @poller    = new Poller(@robot.http(HOST_URL).query(
       site:   "stackoverflow"
       order:  "desc"
-      sort:   "activity"
+      sort:   "creation"
       tagged: "laravel"
       filter: "default"
     ), POLL_INTERVAL)


remove fake dataset tile views thing

remove fake dataset tile views thing

--- client/code/view/dataset/group.coffee
+++ client/code/view/dataset/group.coffee
@@ -16,10 +16,3 @@
   addView: (view) =>
     v = new Cu.View.ViewTile model: view
     @$el.append v.render().el
-
-  xaddViews: ->
-    # Fake for now
-    @$el.append """
-      View Spreadsheet
-      Download CSV
-    """


remove comment

remove comment

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -47,7 +47,6 @@
     'body': '''
       // compose(...functions: [...Function]) => initial => result
       // Create a pipeline of functions to iterate over right to left
-      creates a pipeline of functions with the output of one function connected to the input of the next.
       const compose = (...functions) => initial => functions.reduceRight((accumulator, current) => current(accumulator), initial)
     '''
   'curry':


Add Java snippets

Add Java snippets

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -39,6 +39,15 @@
     @Test(expected=${1:Exception}.class)
     public void ${2:throwsOnSomething}() {$0\n}
     """
+  'JUnit Before':
+    prefix: 'bef'
+    body: """
+    @Before
+    public void setUp() {$0\n}
+    """
+  'Assert':
+    prefix: 'ass'
+    body: "assertThat(${1:expected}, ${2:actual});$0"
 '.source.elixir':
   Context:
     prefix: 'con'


Expand CoffeeScript circle example

Expand CoffeeScript circle example

--- coffeescript/circle.coffee
+++ coffeescript/circle.coffee
@@ -2,6 +2,9 @@
   constructor: (@x=0, @y=0, @radius=1, @color='black') ->
   area: -> Math.PI * @radius * @radius
   circumference: -> 2 * Math.PI * @radius
+  expand: (scale) -> @radius *= scale

 circles = [(new Circle 3, 5, 10, 'blue'), (new Circle)]
-console.log c.area(), c.circumference() for c in circles+console.log c.area(), c.circumference() for c in circles
+circles[1].expand(5)
+console.log c.radius


Ensure there's a test document always.

Ensure there's a test document always.

--- test/test_document.coffee
+++ test/test_document.coffee
@@ -329,12 +329,14 @@

   it "should work with forEach", ->
     count = 0
-    cursor = MyDoc.find {}
-    cursor.forEach (err, doc) ->
-      throw err if err
-      if not doc
-        count.should.be.gte 1
-      count += 1
+    MyDoc.insert _id: 'forEach', (err, doc) ->
+      throw err if err
+      cursor = MyDoc.find {}
+      cursor.forEach (err, doc) ->
+        throw err if err
+        if not doc
+          count.should.be.gte 1
+        count += 1

 describe "Embed", ->


Remove redundant code in event_form

Remove redundant code in event_form

--- client/views/events/event_form.coffee
+++ client/views/events/event_form.coffee
@@ -2,43 +2,6 @@

 DATE_FORMAT = "YYYY-MM-DD"
 TIME_FORMAT = "HH:mm"
-
-# convert undefined, single category to array
-fix_categories = (categories) ->
-  if not _.isArray(categories)
-    if categories?
-      return [categories]
-    else
-      return []
-  return categories
-
-window.events_at_penn.parse_event_from_form = (form) ->
-  event = form.serializeObject()
-  event.categories = fix_categories(event.categories)
-
-  date_start = moment(event.date_start, DATE_FORMAT)
-  time_start = moment(event.time_start, TIME_FORMAT)
-
-  delete event['date_start']
-  delete event['time_start']
-
-  event.from = date_start
-    .hour(time_start.hour())
-    .minute(time_start.minute())
-    .toDate()
-
-  date_end = moment(event.date_end, DATE_FORMAT)
-  time_end = moment(event.time_end, TIME_FORMAT)
-
-  delete event['date_end']
-  delete event['time_end']
-
-  event.to = date_end
-    .hour(time_end.hour())
-    .minute(time_end.minute())
-    .toDate()
-
-  return event

 Template.event_form.events
   'click .filepicker': (e) ->


SidebarMachineBox: Handle Terminating and Terminated states.

--- client/app/lib/activity/sidebar/sidebarmachinebox.coffee
+++ client/app/lib/activity/sidebar/sidebarmachinebox.coffee
@@ -185,7 +185,7 @@

   watchMachineState: ->

-    { Stopping, Running } = Machine.State
+    { Stopping, Terminating, Terminated } = Machine.State

     kd.singletons.computeController.on "public-#{@machine._id}", (event) =>
       state = event.status
@@ -196,3 +196,6 @@
       @machine.status.state = state # FIXME: why it is not setting the state itself?

       switch state
+        when Stopping    then @deselect()
+        when Terminating then @deselect()
+        when Terminated  then @destroy()


add validators did for testsing

add validators did for testsing

--- karma.conf.coffee
+++ karma.conf.coffee
@@ -15,7 +15,8 @@
       'angular.js',
       'angular-mocks.js',
       '../../coolforms.js',
-      'services/*.coffee'
+      'services/*.coffee',
+      'validators/*.coffee'
     ]

     # list of files to exclude


draw tooltip relative to div.graph

draw tooltip relative to div.graph

--- app/assets/javascripts/states/monitoring/helpers/graph.js.coffee
+++ app/assets/javascripts/states/monitoring/helpers/graph.js.coffee
@@ -187,7 +187,7 @@
     return

   if el.data('bs.tooltip').options.title != text
-    d = $(div).position()
+    d = $(div).find(".graph").position()
     tx = d.left + pts[0].canvasx - 5 + "px"
     ty = d.top + pts[0].canvasy - 5 + "px"


rm console.log

rm console.log

--- app/cells/folio/console/atom_form_fields/atom_form_fields.coffee
+++ app/cells/folio/console/atom_form_fields/atom_form_fields.coffee
@@ -56,7 +56,6 @@
     atomFormBySelect($(insertedItem).find('.folio-console-atom-type-select'))

   .on 'change', '.folio-console-atom-type-select', ->
-    console.log(this)
     atomFormBySelect($(this))

   .on 'change', '.folio-console-atom-model-select', ->


Always convert method passed to Travis.ajax to upper case

--- assets/scripts/lib/travis/ajax.coffee
+++ assets/scripts/lib/travis/ajax.coffee
@@ -12,6 +12,7 @@
     @ajax(url, 'post', data: data, success: callback)

   ajax: (url, method, options) ->
+    method = method.toUpperCase()
     endpoint = Travis.config.api_endpoint || ''
     options = options || {}

@@ -25,7 +26,7 @@
     options.contentType = options.contentType || 'application/json; charset=utf-8'
     options.context = this

-    if options.data && method != 'GET' && method != 'get'
+    if options.data && method != 'GET'
       options.data = JSON.stringify(options.data)

     success = options.success || (->)


Moved initialize to top of file

Moved initialize to top of file

--- core/app/backbone/collections/evidence_collection.coffee
+++ core/app/backbone/collections/evidence_collection.coffee
@@ -1,4 +1,8 @@
 class window.EvidenceCollection extends Backbone.Collection
+
+  initialize: (models, opts) ->
+    @type = opts.type
+    @fact = opts.fact

   parse: (data) ->
     results = []
@@ -12,8 +16,4 @@
           console.info "Evidence type not supported: #{item.evidence_type}"
     results

-  initialize: (models, opts) ->
-    @type = opts.type
-    @fact = opts.fact
-
   url: -> "/facts/#{@fact.id}/#{@type}_evidence/combined"


Set sidebar before retrieving currentUser.channels.

--- core/app/backbone/controllers/channels_controller.coffee
+++ core/app/backbone/controllers/channels_controller.coffee
@@ -23,11 +23,11 @@
   commonTopicViewsBeforeFetchOfCurrentUsersChannels: (topic) ->
     FactlinkApp.leftBottomRegion.close()
     @showUserProfile currentUser
+    FactlinkApp.Sidebar.showForTopicsAndActivateCorrectItem(topic, currentUser)

   commonTopicViewsAfterFetchOfCurrentUsersChannels: (topic) ->
     channel = topic.existingChannelFor(currentUser) # implicitly uses currentUser.channels
     window.currentChannel = channel
-    FactlinkApp.Sidebar.showForTopicsAndActivateCorrectItem(topic, currentUser)

   getTopicFacts: (slug_title) ->
     FactlinkApp.mainRegion.show(@channel_views)


scraperwiki.pushSQL is now compatible with the old version

--- shared/code/scraperwiki.coffee
+++ shared/code/scraperwiki.coffee
@@ -119,10 +119,10 @@
   $.ajax options

-scraperwiki.dataset.installTool = (toolName, query) ->
-  ###
-  Installs the specified tool into the current dataset,
-  passing it the optional [query] in scraperwiki.readSettings().sqlQuery
+scraperwiki.dataset.installTool = (query, toolName) ->
+  ###
+  Passes the specified [query] to the specified [toolName],
+  installing it into the current dataset if necessary.
   ###
   parent.scraperwiki.xdm.pushSQL(query, toolName)


fix depreciation

fix depreciation

--- lib/browser-plus.coffee
+++ lib/browser-plus.coffee
@@ -60,7 +60,7 @@
     atom.workspace.open uri, split:side

   getPosition: ->
-    activePane = atom.workspace.paneForItem atom.workspace.getActiveEditor()
+    activePane = atom.workspace.paneForItem atom.workspace.getActiveTextEditor()
     return unless activePane
     paneAxis = activePane.getParent()
     return unless paneAxis


:bug: Fix markers map entry deletion

:bug: Fix markers map entry deletion

--- lib/color-buffer.coffee
+++ lib/color-buffer.coffee
@@ -142,9 +142,10 @@

     toDestroy = @variableMarkers.filter (marker) -> marker not in newMarkers

-    toDestroy.forEach (marker) =>
-      delete @variableMarkersByMarkerId[marker.marker.id]
-      marker.destroy()
+    toDestroy.forEach (marker) -> marker.destroy()
+
+    for id,marker of @variableMarkersByMarkerId when marker not in newMarkers
+      delete @variableMarkersByMarkerId[id]

     @variableMarkers = newMarkers
     @emitter.emit 'did-update-variable-markers', {
@@ -227,9 +228,11 @@

     if @colorMarkers?
       toDestroy = @colorMarkers.filter (marker) -> marker not in newMarkers
-      toDestroy.forEach (marker) =>
-        delete @colorMarkersByMarkerId[marker.marker.id]
-        marker.destroy()
+      toDestroy.forEach (marker) -> marker.destroy()
+
+      for id,marker of @colorMarkersByMarkerId when marker not in newMarkers
+        delete @colorMarkersByMarkerId[id]
+
     else
       toDestroy = []


add proposition methods to storage api

add proposition methods to storage api

--- lib/argumenta/storage.coffee
+++ lib/argumenta/storage.coffee
@@ -1,5 +1,6 @@
-Base       = require '../argumenta/base'
-User       = require '../argumenta/user'
+Base        = require '../argumenta/base'
+User        = require '../argumenta/user'
+Proposition = require '../argumenta/objects/proposition'

 # Storage persists users and objects to a backend store.

@@ -105,4 +106,31 @@
       return cb new @Error "Failed getting all users from store." if err
       return cb null, users

+  # Add an array of propositions to the store.
+  #
+  # @param [Array<Propositions>] propositions The propositions array.
+  # @param [Function]     cb(err) Called on completion or error.
+  # @param [StorageError] err Any error.
+  addPropositions: (propositions, cb) ->
+    for p in propositions
+      unless p instanceof Proposition
+        return cb new @Error("Won't add non-proposition: " + p)
+      unless p.validate()
+        return cb new @Error("Won't add invalid proposition: " + p)
+
+    @store.addPropositions propositions, (err) ->
+      return cb new @Error "Failed adding propositions to the store." if err
+      return cb null
+
+  # Get propositions from the store by hashes.
+  #
+  # @param [Array<String>] hashes Hash ids of the propositions to retrieve.
+  # @param [Function]      cb(err, propositions) Called on completion or error.
+  # @param [StorageError]  err Any error.
+  # @param [Array<Proposition>] propositions The retrieved propositions.
+  getPropositions: (hashes, cb) ->
+    @store.getPropositions hashes, (err, propositions) ->
+      return cb new @Error "Failed getting propositions from the store." if err
+      return cb null, propositions
+
 module.exports = Storage


Confirming only one result after fill SelectView

Fixing TypeError: Cannot read property 'invert' of null on
history.js (History.prototype.abortTransaction) when only one item
is returned.

--- lib/autocomplete-view.coffee
+++ lib/autocomplete-view.coffee
@@ -108,13 +108,13 @@
           if word.charAt(0) isnt '_'
             me.wordList.push({word: word, prefix: prefix, suffix: '', full: full})

-      # select if only one match else show list
-      if me.wordList.length is 1
-        me.confirmSelection()
       me.setItems(me.wordList)
       me.editorView.appendToLinesView(me)
       me.setPosition()
       me.focusFilterEditor()
+      # select if only one match else show list
+      if me.wordList.length is 1
+        me.confirmSelection()

   setPosition: ->
     {left, top} = @editorView.pixelPositionForScreenPosition(@originalCursorPosition)


Big performance fix when building wordlist

--- lib/autocomplete-view.coffee
+++ lib/autocomplete-view.coffee
@@ -219,7 +219,7 @@
     p.start()

     # Merge the scope specific words into the default word list
-    wordList = _.union @wordList, @getCompletionsForCursorScope()
+    wordList = @wordList.concat @getCompletionsForCursorScope()
     words = fuzzaldrin.filter wordList, prefix

     results = for word in words when word isnt prefix


#27 checking for updateCachedDiskContents, removed in 1.19.0

--- lib/file-watcher.coffee
+++ lib/file-watcher.coffee
@@ -83,11 +83,13 @@
     @confirmReload() if @isBufferInConflict()

   forceReload: ->
-    if @useFsWatchFile
+    currBuffer = @editor.getBuffer()
+    # patch - new version of Atom removed updateCachedDiskContents() from buffer
+    if @useFsWatchFile and currBuffer and currBuffer.updateCachedDiskContents !== undefined
       # force a re-read from the file then reload
-      @editor.buffer.updateCachedDiskContents true, => @editor.getBuffer()?.reload()
+      currBuffer.updateCachedDiskContents true, => currBuffer?.reload()
     else
-      @editor.getBuffer()?.reload()
+      currBuffer?.reload()

   confirmReload: ->
     # if the user has selected autoReload we can just reload and exit


:bug: Fix broken scrolling from the minimap

In addition it’s now possible to initiate a dragged scroll from
anywhere in the minimap, not just from from the visible area.

--- lib/minimap-view.coffee
+++ lib/minimap-view.coffee
@@ -53,7 +53,9 @@

   initialize: ->
     @on 'mousewheel', @onMouseWheel
-    @on 'mousedown', @onMouseDown
+    @on 'mousedown', (e) =>
+      @onMouseDown(e)
+      @onDragStart(e)

     @on 'mousedown', '.minimap-visible-area', @onDragStart

@@ -255,7 +257,7 @@
     e.stopPropagation()
     # VisibleArea's center-y
     y = e.pageY - @offsetTop
-    top = @indicator.computeFromCenterY(y / @scaleY)
+    top = @indicator.computeFromCenterY(y) / @scaleY
     # @note: currently, no animation.
     @editorView.scrollTop(top)
     # Fix trigger `mousewheel` event.


overlooked swrapped-selection from jQuery-like naming convention

--- lib/mode-manager.coffee
+++ lib/mode-manager.coffee
@@ -154,8 +154,8 @@
   #   which is the range in visual-mode.
   activateVisualMode: (newSubmode) ->
     @vimState.assertWithException(newSubmode?, "activate visual-mode without submode")
-    for selection in @editor.getSelections() when swrapped = swrap(selection)
-      swrapped.saveProperties() unless swrapped.hasProperties()
+    for selection in @editor.getSelections() when $selection = swrap(selection)
+      $selection.saveProperties() unless $selection.hasProperties()

     @normalizeSelections()


Removed old coffee version.

Removed old coffee version.

--- mdns-native.coffee
+++ mdns-native.coffee
@@ -1,41 +0,0 @@
-os = require 'os'
-# childProcess = require 'child_process'
-
-
-module.exports =
-	test: (testOS)->
-		try
-			child = switch testOS
-				when "linux"
-					console.log "je suis sous linux"
-				when "darwin"
-					childProcess.spawn 'dns-sd', ['-R', name, type, domain, port]
-				else
-					console.warn "Platform not supported"
-		catch
-			console.error "Veuillez installer mDNS"
-
-	publish: (type, domain, port)->
-		name = os.hostname().replace /\.local\.?$/, ''
-		# type = '_coqs-gameserver'
-		# domain = 'local'
-
-		# possible values for process.platform
-		# linux
-		# win32
-		# win64
-		# darwin (osx)
-
-		# dns-sd support can be added to windows using apple's sdk: https://developer.apple.com/bonjour/
-		try
-			child = switch process.platform
-				when "darwin"
-					childProcess.spawn 'dns-sd', ['-R', name, type, domain, port]
-				when "win32","win64"
-					childProcess.spawn 'dns-sd', ['-R', name, type, domain, port]
-				when "linux"
-					childProcess.spawn 'avahi-publish-service', [name, "#{type}._tcp", port]
-				else
-					console.warn "Platform not supported"
-		catch
-			console.error "Veuillez installer mDNS"


`util/search`: improved product selection

--- util/search.coffee
+++ util/search.coffee
@@ -2,6 +2,7 @@

 Q =				require 'q'
 inquirer =		require 'inquirer'
+chalk =			require 'chalk'

 vbb =			require 'vbb'
 util =			require 'vbb-util'
@@ -77,10 +78,21 @@

 parseProducts = (products) ->
 	if products is 'all' then return all
+	if typeof products is 'string' then products = products.split ','
 	result = {}
-	for product in products.split ','
+	for product in products
 		result[product] = true
 	return result
+
+
+
+productColor = (product, text) ->
+	product = util.products[product] or util.products.unknown
+	styles = chalk
+	for style in product.ansi
+		if styles[style]
+			styles = styles[style]
+	return styles text

@@ -90,41 +102,21 @@
 		program.products = parseProducts program.products
 		deferred.resolve program
 		return deferred.promise
+	choices = []
+	for product in util.products.categories
+		continue if product.type is 'unknown'
+		choices.push
+			name: [
+				productColor product.type, product.short
+				chalk.gray product.name
+			].join ' '
+			value:		product.type
+			checked:	if product.type is 'express' then false else true
 	inquirer.prompt [{
 		type:		'checkbox',
 		name:		'products',
 		message:	'Which products do you want to use?',
-		choices:	[
-			{
-				name:		'S-Bahn (suburban)'
-				value:		'suburban'
-				checked:	true
-			}, {
-				name:		'U-Bahn (subway)'
-				value:		'subway'
-				checked:	true
-			}, {
-				name:		'Tram (cable car)'
-				value:		'tram'
-				checked:	true
-			}, {
-				name:		'Bus'
-				value:		'bus'
-				checked:	true
-			}, {
-				name:		'Ferry'
-				value:		'ferry'
-				checked:	true
-			}, {
-				name:		'RE/RB (regional trains)'
-				value:		'regional'
-				checked:	true
-			}, {
-				name:		'ICE/IC/EC (express trains)'
-				value:		'express'
-				checked:	false
-			}
-		]
+		choices:	choices
 	}], (answers) ->
 		program.products = parseProducts answers.products
 		deferred.resolve program


Use new vhost

Use new vhost

--- config/main.dyn-new.coffee
+++ config/main.dyn-new.coffee
@@ -118,7 +118,7 @@
     componentUser: "prod-<component>"
     password    : 'Dtxym6fRJXx4GJz'
     heartbeat   : 10
-    vhost       : '/new'
+    vhost       : 'new'
   broker        :
     port        : brokerPort
     certFile    : "/etc/nginx/ssl/server_new.crt"


Modifications for staging config necessary to get staging running :)

--- config/main.staging.coffee
+++ config/main.staging.coffee
@@ -117,7 +117,7 @@
       mainUri   : "http://koding.com"
       broker    :
         servicesEndpoint: "/-/services/broker"
-        sockJS   : "https://stage-broker-#{version}.in.koding.com/subscribe"
+        sockJS   : "http://stage-broker-#{version}.in.koding.com/subscribe"
       apiUri    : 'https://www.koding.com'
       # Is this correct?
       appsUri   : 'https://koding-apps.s3.amazonaws.com'
@@ -134,11 +134,11 @@
     vhost       : 'new'
   broker        :
     ip          : ""
-    port        : 443
-    certFile    : "/opt/ssl_certs/wildcard.koding.com.cert"
-    keyFile     : "/opt/ssl_certs/wildcard.koding.com.key"
-    useKontrold : yes
-    webProtocol : 'https:'
+    port        : 80
+    certFile    : ""
+    keyFile     : ""
+    useKontrold : no
+    webProtocol : 'http:'
     webHostname : "stage-broker-#{version}.in.koding.com"
     webPort     : null
     authExchange: authExchange


config: run email worker in staging, force recipient

--- config/main.staging.coffee
+++ config/main.staging.coffee
@@ -281,9 +281,9 @@
     cronInstant : '*/10 * * * * *'
     cronDaily   : '0 10 0 * * *'
     run         : no
-    forcedRecipient : undefined
+    forcedRecipient : "kodingtestuser@gmail.com"
   emailSender   :
-    run         : no
+    run         : yes
   guests        :
     # define this to limit the number of guset accounts
     # to be cleaned up per collection cycle.


Any node version for now

Any node version for now

--- lib/skeleton/template.coffee
+++ lib/skeleton/template.coffee
@@ -26,7 +26,7 @@
             "start": "server.js"
           }
         , "engines": {
-            "node": "0.8.0"
+            "node": "*"
           }
       }
     """


Fix detection of cursor movement within tab-stops

--- lib/snippet-expansion.coffee
+++ lib/snippet-expansion.coffee
@@ -25,9 +25,8 @@

   cursorMoved: ({oldBufferPosition, newBufferPosition, textChanged}) ->
     return if @settingTabStop or textChanged
-    oldTabStops = @tabStopsForBufferPosition(oldBufferPosition)
-    newTabStops = @tabStopsForBufferPosition(newBufferPosition)
-    @destroy() unless _.intersection(oldTabStops, newTabStops).length
+    @destroy() unless @tabStopMarkers[@tabStopIndex].some (marker) ->
+      marker.getBufferRange().containsPoint(newBufferPosition)

   cursorDestroyed: -> @destroy() unless @settingTabStop

@@ -80,10 +79,6 @@
     @settingTabStop = false
     markerSelected

-  tabStopsForBufferPosition: (bufferPosition) ->
-    _.intersection(@tabStopMarkers[@tabStopIndex],
-      @editor.findMarkers(containsBufferPosition: bufferPosition))
-
   destroy: ->
     @subscriptions.dispose()
     for markers in @tabStopMarkers


=fixing commit command

=fixing commit command

--- lib/commit.coffee
+++ lib/commit.coffee
@@ -1,13 +1,12 @@
 _ = require 'underscore'
 _.str = require 'underscore.string'
-parse = require('../parse/status').short

 # commit command plugin
 module.exports = (git) ->
 	return (opts) ->
 		files = opts.files || []
-		args = ['--short', transform(opts)..., files...]
-		git.run('commit', args).then(parse)
+		args = [transform(opts)..., files...]
+		git.run('commit', args)

 transform = (opts) ->
 	return [] if not opts
@@ -18,7 +17,7 @@
 			switch k
 				# do not create a commit, but show a list of paths that are to be committed.
 				when 'dryrun' then "--dry-run"
-				when 'all' then "--all"
-				when 'message' then "--message=#{_.str.quote(v)}"
+				when 'all' then "-a"
+				when 'message' then "-m=#{_.str.quote(v)}"
 				else ''
 	.filter _.identity


try default config only if config not found

--- lib/config.coffee
+++ lib/config.coffee
@@ -6,24 +6,25 @@

 {ROOT, EXROOT} = global

-config = {}
+config = null
 configCache = {}
 defaultConfigPath = path.join(ROOT, 'config.cson')
 configPath = path.join(EXROOT, 'config.cson')
-
-# Read saved config
-try
-  fs.accessSync defaultConfigPath, fs.R_OK | fs.W_OK
-  config = CSON.parseCSONFile defaultConfigPath
-catch e
-  warn e

 # Read user config
 try
   fs.accessSync configPath, fs.R_OK | fs.W_OK
   config = CSON.parseCSONFile configPath
-catch e
-  warn e
+
+# Read saved config
+if !config?
+  try
+    fs.accessSync defaultConfigPath, fs.R_OK | fs.W_OK
+    config = CSON.parseCSONFile defaultConfigPath
+
+if !config?
+  config = {}
+  warn 'cannot read config.cson'

 module.exports =
   get: (path, value) ->


oops, left some unneeded comments in

oops, left some unneeded comments in

--- lib/heroku.coffee
+++ lib/heroku.coffee
@@ -4,11 +4,6 @@
   Apps: class AppsApi
     constructor: (@client) ->
     list: (cb) -> @client.get('/apps', cb)
-
-      #### client.app('app-name').get(callback)
-      #### client.app('app-name').maintenance_mode_on(callback)
-      #### client.app('app-name').maintenance_mode_off(callback)
-      #### client.app('app-name').destroy(callback)

   App: class AppApi
     constructor: (@client, @app) ->


Bring back repo url, it's used in status images urls (closes #118)

--- assets/scripts/app/views/repo/show.coffee
+++ assets/scripts/app/views/repo/show.coffee
@@ -182,6 +182,9 @@
         permissions.contains @get('repo.id')
     ).property('Travis.app.currentUser.permissions.length', 'repo.id')

+    urlRepo: (->
+      "https://#{location.host}/#{@get('repo.slug')}"
+    ).property('repo.slug')

     branches: (->
       @get('repo.branches') if @get('active')


Fix bug

Fix bug

--- views/app.cjsx
+++ views/app.cjsx
@@ -56,7 +56,7 @@
         key: num - 1
   handleTabKeyDown: ->
     @setState
-      key: if @state.key then (@state.key + 1) % (components.length + tabbedPlugins.length) else 0
+      key: if @state.key? then (@state.key + 1) % (components.length + tabbedPlugins.length) else 0
   componentDidMount: ->
     window.addEventListener 'keydown', (e) =>
       if e.keyCode is 9


shorter call to jade

shorter call to jade

--- web/app.coffee
+++ web/app.coffee
@@ -1,6 +1,5 @@
 util = require 'util'
 path = require 'path'
-jade = require 'jade'

 # Express app
 express = require 'express'
@@ -62,7 +61,7 @@

   # Jade templates
   app.set 'views', app_path + '/views'
-  app.engine '.jade', jade.__express
+  app.engine 'jade', require('jade').__express
   app.set 'view engine', 'jade'

   # Middlewares


Uncomment assertions

Uncomment assertions

--- spec/app/root-view-spec.coffee
+++ spec/app/root-view-spec.coffee
@@ -79,8 +79,8 @@
           expect(editor2.position().left).toBe expectedColumnWidth
           expect(editor2.outerWidth()).toBe expectedColumnWidth

-          # expect(editor1.has(':focus')).not.toExist()
-          # expect(editor2.has(':focus')).toExist()
+          expect(editor1.has(':focus')).not.toExist()
+          expect(editor2.has(':focus')).toExist()

           # insertion reflected in both buffers
           editor1.buffer.insert([0, 0], 'ABC')


Change load paths for test dependencies

Change load paths for test dependencies

--- spec/barcode_input_spec.coffee
+++ spec/barcode_input_spec.coffee
@@ -94,7 +94,7 @@
   if dom.hasAttribute and dom.hasAttribute('data-barcode-input')
     $(dom).html( $(dom).html() + key )

-html     = fs.readFileSync('./spec/fixtures/browser.html').toString()
+html     = fs.readFileSync('spec/fixtures/browser.html').toString()
 window   = document = $ = null
 reload_browser = ->
   document  = jsdom.jsdom(html)
@@ -104,9 +104,9 @@
   # Provide JSDom with access to the console.
   window.console = console

-  addScript document, './node_modules/jwerty/jwerty.js'
-  addScript document, './vendor/jquery-throttle-debounce/jquery.ba-throttle-debounce.min.js'
-  addScript document, './compiled/jquery.barcode_input.js'
+  addScript document, 'node_modules/jwerty/jwerty.js'
+  addScript document, 'vendor/jquery-throttle-debounce/jquery.ba-throttle-debounce.min.js'
+  addScript document, 'compiled/jquery.barcode_input.js'

 # Selector used to find the element we want to listen to.
 bc_input = '#input'


Remove logging from specs

Remove logging from specs

--- spec/language-mode-spec.coffee
+++ spec/language-mode-spec.coffee
@@ -86,12 +86,10 @@
         expect(languageMode.rowRangeForCommentAtBufferRow(2)).toBeUndefined()

         buffer.setText("//this is a single line comment\n")
-        console.log buffer.getLastRow()
         expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()
         expect(languageMode.rowRangeForCommentAtBufferRow(1)).toBeUndefined()

         buffer.setText("//this is a single line comment")
-        console.log languageMode.isLineCommentedAtBufferRow(0)
         expect(languageMode.rowRangeForCommentAtBufferRow(0)).toBeUndefined()

     describe "suggestedIndentForBufferRow", ->


removed extra comment

removed extra comment

--- lib/utils/retsParsing.coffee
+++ lib/utils/retsParsing.coffee
@@ -22,7 +22,6 @@
     currElementName: null
     parser: new expat.Parser('UTF-8')
     finish: () ->
-      #result.parser.stop()
       result.parser.removeAllListeners()
     status: null


Attempt to fix theme manager specs

Attempt to fix theme manager specs

They work for me!

--- spec/theme-manager-spec.coffee
+++ spec/theme-manager-spec.coffee
@@ -290,6 +290,12 @@
           expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"

   describe "user stylesheet", ->
+    userStylesheetPath = null
+    beforeEach ->
+      userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
+      fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
+      spyOn(atom.styles, 'getUserStyleSheetPath').andReturn userStylesheetPath
+
     describe "when the user stylesheet changes", ->
       beforeEach ->
         jasmine.snapshotDeprecations()
@@ -300,9 +306,6 @@
       it "reloads it", ->
         [styleElementAddedHandler, styleElementRemovedHandler] = []
         [stylesheetRemovedHandler, stylesheetAddedHandler, stylesheetsChangedHandler] = []
-        userStylesheetPath = path.join(temp.mkdirSync("atom"), 'styles.less')
-        fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}')
-        spyOn(atom.styles, 'getUserStyleSheetPath').andReturn userStylesheetPath

         waitsForPromise ->
           themeManager.activateThemes()


fix typo

fix typo

--- routes/index.coffee
+++ routes/index.coffee
@@ -11,7 +11,7 @@
 strategy = new GoogleStrategy
     clientID:     process.env.GOOGLE_CLIENT_ID
     clientSecret: process.env.GOOGLE_CLIENT_SECRET
-    callbackURL: "#{protocol}://#{process.env.DOMAIN or "127.0.0.1:3000"}/auth/google/callback"
+    callbackURL: "#{protocol}://#{process.env.DOMAIN or "127.0.0.1:3000"}/auth/google/return"
     # realm:     process.env.GOOGLE_REALM      or "http://localhost:#{process.env.PORT or 3000}/"
     # returnURL: process.env.GOOGLE_RETURN_URL or "http://localhost:#{process.env.PORT or 3000}/auth/google/return"
   , (accessToken, refreshToken, profile, done) ->


Recurse through pageItems to get paths in a layer.

This does not collect paths in sublayers. If you use sublayers you are a
horrible person and I hate you, and as far as I can tell, they have no
reason to exist.

This should be much faster for documents with many layers.

Also remove some lingering ScriptUI stuff.

--- AI2ASS.coffee
+++ AI2ASS.coffee
@@ -152,32 +152,47 @@

     return ""

+  allThePaths = []
+  recursePageItem = ( pageItem ) ->
+    switch pageItem.typename
+
+      when "CompoundPathItem"
+        for path in pageItem.pathItems
+          recursePageItem path
+
+      when "GroupItem"
+        for subPageItem in pageItem.pageItems
+          recursePageItem subPageItem
+
+      when "PathItem"
+        allThePaths.push pageItem
+
+      else
+        alert pageItem.typename
+
   methods = {
+
+
+
+
     collectActiveLayer: ->
-      outputStr = ""
-
-      for currPath in doc.pathItems
-
-        if currPath.layer.name is currLayer.name
-
-          unless currPath.hidden or currPath.guides or currPath.clipping
-
-            if outputStr.length is 0
-              fgc = manageColor currPath, "fillColor", 1
-              sc = manageColor currPath, "strokeColor", 3
-              outputStr += "{\\pos(0,0)#{fgc}#{sc}\\p#{options.scale}}"
-
-            outputStr += ASS_createDrawingFromPoints currPath.pathPoints
-
-      outputStr[0...-1]
+
+      # PAGEITEMS DOES NOT INCLUDE SUBLAYERS, AND AS FAR AS I CAN TELL,
+      # THERE'S NO WAY TO POSSIBLY TELL FROM JS WHAT ORDER SUBLAYERS ARE
+      # IN RELATIVE TO THE PATHS, COMPOUND PATHS, AND GROUPS WITHIN THE
+      # LAYER, WHICH MEANS IT IS IMPOSSIBLE TO REPRODUCE THE WAY
+      # SUBLAYERS ARE LAYERED. TL;DR IF YOU STICK A LAYER INSIDE ANOTHER
+      # LAYER, FUCK YOU FOREVER.
+
+      for pageItem in currLayer.pageItems
+        recursePageItem pageItem, output
+

     CG_collectActiveLayer: ->
-      outputStr = ""
-
-      for currPath in doc.pathItems
-
-        if currPath.layer.name is currLayer.name
-          outputStr += CG_createDrawingFromPoints currPath.pathPoints
+
+
+      for pageItem in currLayer.pageItems
+        recursePageItem pageItem, output

       outputStr

@@ -207,29 +222,9 @@
       "{innerShadow}\n#{outputStr}"[0...-2]

     collectAllLayers: ->
-      output = {}
-      overall = ""
-
-      for currPath in doc.pathItems
-
-        unless currPath.hidden or currPath.guides or currPath.clipping or not currPath.layer.visible
-          outputStr = ""
-          outputStr += ASS_createDrawingFromPoints currPath.pathPoints
-
-          unless output[currPath.layer.name]
-            fgc = manageColor currPath, "fillColor", 1
-            sc = manageColor currPath, "strokeColor", 3
-            outputStr = "{\\pos(0,0)#{fgc}#{sc}\\p#{options.scale}}#{outputStr}"
-            output[currPath.layer.name] = outputStr
-          else
-            output[currPath.layer.name] += outputStr
-
-      for key, val of output
-        overall += "#{val[0...-1]}\n"
-
-      "{allLayers}\n#{overall}"[0...-2]
+
+      allThePaths = doc.pathItems
+
   }

-  methods[options.method]()
-
-win.show()
+  methods[options.method]( )


forgot to export View in vbox.coffee

forgot to export View in vbox.coffee

--- bokehjs/src/coffee/widget/vbox.coffee
+++ bokehjs/src/coffee/widget/vbox.coffee
@@ -34,4 +34,5 @@
   return {
     "Model" : VBox
     "Collection" : vboxes
+    "View" : VBoxView
   }


Add rounding to resolution.

Add rounding to resolution.

--- views/components/settings/parts/display-config.cjsx
+++ views/components/settings/parts/display-config.cjsx
@@ -188,7 +188,7 @@
          value={@state.gameWidth}
          onChange={@handleSetWebviewWidth.bind @, "webviewWidthRatio"}
          disabled={!@state.useFixedResolution} >
-          <option key={-1} value={@state.gameWidth} hidden>{Math.round(@state.gameWidth/8)}%</option>
+          <option key={-1} value={@state.gameWidth} hidden>{Math.round(@state.gameWidth/800*100)}%</option>
           {
             i = 0
             while i < 4
@@ -203,7 +203,7 @@

           <Input type="number"
            ref="webviewWidth"
-           value={@state.gameWidth}
+           value={Math.round(@state.gameWidth)}
            onChange={@handleSetWebviewWidth.bind @, "webviewWidth"}
            readOnly={!@state.useFixedResolution} />

@@ -211,7 +211,7 @@
           x

-          <Input type="number" value={@state.gameWidth * 480 / 800} readOnly />
+          <Input type="number" value={Math.round(@state.gameWidth * 480 / 800)} readOnly />

           px


removed fetchInvitationsByStatus method

removed fetchInvitationsByStatus method

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -212,8 +212,6 @@
         fetchPermissionSetOrDefault:
           (signature Function)
         fetchUserStatus:
-          (signature Object, Function)
-        fetchInvitationsByStatus:
           (signature Object, Function)
     schema          :
       title         :
@@ -1156,11 +1154,6 @@
         daisy queue

-  fetchInvitationsByStatus: permit 'send invitations',
-    success: (client, options, callback)->
-      return callback {message: "unimplemented feature"}
-
-
   @each$ = (selector, options, callback)->
     selector.visibility = 'visible'
     @each selector, options, callback


move the html generation out from the create method to the save method so that is gets called regardless of whether "new" or "create" is used for instantiation.

--- workers/social/lib/social/models/markdowndoc.coffee
+++ workers/social/lib/social/models/markdowndoc.coffee
@@ -47,14 +47,15 @@
     setOp.checksum = JMarkdownDoc.generateChecksum setOp.content
     Module::update.apply this, arguments

+  save:->
+    @html = @generateHTML @content
+    super
+
   @create = (formData, callback)->
     data = formData
     markdownDoc = null

     daisy queue = [
-      =>
-        data.html = @generateHTML data.content
-        queue.next()
       =>
         data.checksum = @generateChecksum data.content
         queue.next()


comment default options

comment default options

--- Smooth.coffee
+++ Smooth.coffee
@@ -27,9 +27,9 @@
 	CUBIC_TENSION_CATMULL_ROM: 0

 defaultConfig =
-	method: Enum.METHOD_CUBIC
-	cubicTension: Enum.CUBIC_TENSION_DEFAULT
-	clip: Enum.CLIP_CLAMP
+	method: Enum.METHOD_CUBIC						#The interpolation method
+	cubicTension: Enum.CUBIC_TENSION_DEFAULT		#The cubic tension parameter
+	clip: Enum.CLIP_CLAMP 							#The clipping mode

 ###Index clipping functions###


passing in the wrong value for encrypt during updateObject

--- js/src/service/StorageClient.coffee
+++ js/src/service/StorageClient.coffee
@@ -228,13 +228,13 @@
       Promise.resolve(
         @objectApi.getLatestVersionedObjectKey(objectId)
       )
-      .then (versionedObjectKey) =>
+      .then (latestObjectKey) =>
         Promise.resolve(
           @cryptoServiceLoader.getObjectCryptoServiceV2(versionedObjectKey)
         )
         .then (objectCryptoService) =>
           # ToDo: for now, we encrypt the entire object, but we'll need to support encrypting an object in chunks
-          @encrypt(versionedObjectKey, content, objectCryptoService)
+          @encrypt(latestObjectKey.objectId, content, objectCryptoService)
         .then (encrypted) =>
           blockCiphertext = encrypted.body.data[0].block
           @objectApi.setObjectFromBlockCiphertext(versionedObjectKey, blockCiphertext)


Add Menu Item

Add Menu Item

--- menus/go-plus.cson
+++ menus/go-plus.cson
@@ -7,6 +7,7 @@
         { 'label': 'Display Go Information', 'command': 'golang:goinfo' },
         { 'label': 'Get Missing Tools', 'command': 'golang:getmissingtools' },
         { 'label': 'Update Tools', 'command': 'golang:updatetools' },
+        { 'label': 'Go To Definition', 'command': 'golang:godef' },
         { 'label': 'Format File', 'command': 'golang:gofmt' },
         { 'label': 'Vet File', 'command': 'golang:govet' },
         { 'label': 'Lint File', 'command': 'golang:golint' },


add route for shortcut

add route for shortcut

--- node/server.coffee
+++ node/server.coffee
@@ -15,6 +15,9 @@

 gravity.get '/api/v1/post/:id', (req, res) ->
   res.send fabricate 'post', title: 'Main post!'
+
+gravity.get '/api/v1/shortcut/:id', (req, res) ->
+  res.send fabricate 'shortcut'

 gravity.get '/api/v1/related/posts', (req, res) ->
   res.send [fabricate('post', title: 'Related post!'), fabricate('post')]


fixed opinion loader logic

fixed opinion loader logic

--- client/landing/app/CommonViews/opinions/opinionviewheader.coffee
+++ client/landing/app/CommonViews/opinions/opinionviewheader.coffee
@@ -18,7 +18,7 @@
       @onListCount = data.repliesCount
       @hide()

-    @hide() if data.repliesCount is 0
+    @hide() if data.repliesCount < @maxCommentToShow

     list = @getDelegate()

@@ -48,6 +48,8 @@
         @loader.destroy()
         @allItemsLink.destroy()

+
+
     @loader = new KDLoaderView
       cssClass      : "opinion-loader hidden"
       size          :
@@ -75,6 +77,14 @@
     @setClass "in"
     super

+  viewAppended:->
+    @setTemplate @pistachio()
+    @template.update()
+
+    remainingOpinions = @getData().repliesCount-@getDelegate().items.length
+    if (remainingOpinions)<@maxCommentToShow
+        @allItemsLink.updatePartial "View last #{remainingOpinions} #{@getOptions().itemTypeString}"
+
   pistachio:->
     """
       {{> @allItemsLink}}


Ctrl+S - save editors

Ctrl+S - save editors

--- softwareplanet-cms/app/assets/javascripts/admin_scripts/cms/code-editor-ide.js.coffee
+++ softwareplanet-cms/app/assets/javascripts/admin_scripts/cms/code-editor-ide.js.coffee
@@ -56,6 +56,10 @@
     return  unless showing
     showing.CodeMirror.getWrapperElement().style.height = winHeight() + "px"

+  saveEditorsContent = (textarea_name) ->
+    $('.save-src-btn').click()
+    console.log('all sources were saved!');
+

   #constructor: (code_textarea_id, newline_separator) ->
   constructor: (code_textarea_id) ->
@@ -74,6 +78,9 @@
       extraKeys:
         F11: (cm) ->
           setFullScreen cm, not isFullScreen(cm)
+        "Ctrl-S": (cm) ->
+          saveEditorsContent(code_textarea)
+          console.log "saved"
         Esc: (cm) ->
           setFullScreen cm, false  if isFullScreen(cm)
     )


Add babel-polyfill to webpack entry

Add babel-polyfill to webpack entry

--- generators/app/templates/webpack/config.coffee
+++ generators/app/templates/webpack/config.coffee
@@ -10,7 +10,7 @@

 doConfig = ->
   context: path.resolve 'app'
-  entry: app: [ './scripts/main.js' ]
+  entry: app: [ 'babel-polyfill', './scripts/main.js' ]
   resolve:
     extensions: [
       ''


Stop drawing when the mouse leaves the canvas.

The system would just keep drawing when you left the canvas. I added a mouse leave event. This is not ideal, but it *is* less destructive behavior.

--- media/js/blokjes.coffee
+++ media/js/blokjes.coffee
@@ -181,6 +181,8 @@
     else if e.pageX
       canvasDragged e.pageX, e.pageY if canvasMouseDown
     e.preventDefault()
+  .mouseleave (e) ->
+    canvasMouseDown = false

 $(document.body).keypress (e) ->
   char = String.fromCharCode(e.which)


re us5459 Add "SECURITY_EVENT_VIEW" to the list of roles available for editing custom roles

--- sli/admin-tools/admin-rails/app/assets/javascripts/custom_roles.js.coffee
+++ sli/admin-tools/admin-rails/app/assets/javascripts/custom_roles.js.coffee
@@ -1,4 +1,4 @@
-defaultRights = ["READ_GENERAL", "WRITE_GENERAL", "READ_RESTRICTED", "WRITE_RESTRICTED", "READ_STUDENT_GENERAL", "WRITE_STUDENT_GENERAL", "READ_STUDENT_OWNED", "WRITE_STUDENT_OWNED", "READ_STUDENT_RESTRICTED", "WRITE_STUDENT_RESTRICTED", "AGGREGATE_READ", "AGGREGATE_WRITE", "READ_PUBLIC", "WRITE_PUBLIC", "STAFF_CONTEXT", "TEACHER_CONTEXT", "BULK_EXTRACT"]
+defaultRights = ["READ_GENERAL", "WRITE_GENERAL", "READ_RESTRICTED", "WRITE_RESTRICTED", "READ_STUDENT_GENERAL", "WRITE_STUDENT_GENERAL", "READ_STUDENT_OWNED", "WRITE_STUDENT_OWNED", "READ_STUDENT_RESTRICTED", "WRITE_STUDENT_RESTRICTED", "AGGREGATE_READ", "AGGREGATE_WRITE", "READ_PUBLIC", "WRITE_PUBLIC", "STAFF_CONTEXT", "TEACHER_CONTEXT", "BULK_EXTRACT", "SECURITY_EVENT_VIEW"]
 selfRights = ["READ_GENERAL", "WRITE_GENERAL", "READ_RESTRICTED", "WRITE_RESTRICTED", "READ_STUDENT_GENERAL", "WRITE_STUDENT_GENERAL", "READ_STUDENT_OWNED", "WRITE_STUDENT_OWNED", "READ_STUDENT_RESTRICTED", "WRITE_STUDENT_RESTRICTED"]
 ROLE_COL = "td:eq(0)";
 RIGHT_COL = "td:eq(1)";


Update atom-html-preview.coffee

Update atom-html-preview.coffee

--- lib/atom-html-preview.coffee
+++ lib/atom-html-preview.coffee
@@ -75,7 +75,7 @@
       return

     previousActivePane = atom.workspace.getActivePane()
-    atom.workspace.open(uri, split: 'right', searchAllPanes: true).done (htmlPreviewView) ->
+    atom.workspace.open(uri, split: 'right', searchAllPanes: true).then (htmlPreviewView) ->
       if htmlPreviewView instanceof HtmlPreviewView
         htmlPreviewView.renderHTML()
         previousActivePane.activate()


Added notice to #getModel()

Added notice to #getModel()

--- lib/autocomplete-view.coffee
+++ lib/autocomplete-view.coffee
@@ -361,6 +361,8 @@

   ###
    * Why are we doing this again...?
+   * Might be because of autosave:
+   * http://git.io/iF32wA
    * @private
   ###
   getModel: -> null


delete help command message

delete help command message

--- scripts/help.coffee
+++ scripts/help.coffee
@@ -2,8 +2,6 @@
 #   Generates help commands for Hubot.
 #
 # Commands:
-#   hubot help - Displays all of the help commands that Hubot knows about.
-#   hubot help <query> - Displays all help commands that match <query>.
 #
 # URLS:
 #   /hubot/help


Added delete command

Added delete command

--- scripts/mail.coffee
+++ scripts/mail.coffee
@@ -30,8 +30,31 @@
                 context.send "#{robot.brain.userForName(recipient).name}: [From #{mail[0]}, #{moment.unix(mail[1]).fromNow()}] #{mail[2]}"
             delete getMails()[recipient]

-    robot.respond /unmail(\s?.*)/i, (msg) ->
-        # TODO
+    robot.respond /unmail\s?(.*)/i, (msg) ->
+        deleted = 0
+
+        deleteUsingRecipient = (recipient) ->
+            data = getMails()[recipient.toLowerCase()] or []
+            for mail, index in data by -1
+                if mail[0] is msg.message.user.name
+                    data.splice index, 1
+                    ++deleted
+
+        if msg.match[1]
+            deleteUsingRecipient msg.match[1]
+            if deleted is 0
+                msg.reply "There are no outbound mail sent by you towards #{msg.match[1]}."
+            else
+                msg.reply "#{deleted} of your mail(s) towards #{msg.match[1]} has been deleted."
+            return
+
+        for user, mails of getMails()
+            deleteUsingRecipient user
+
+        if deleted is 0
+            msg.reply "There are no outbound mail sent by you."
+        else
+            msg.reply "#{deleted} of your mail(s) has been deleted."

     robot.respond /mail (\S+) (.+)/i, (msg) ->
         [command, recipient, message] = msg.match


No need to provide defaultVM if its not provided kiteController will handle this.

--- client/app/MainApp/fs/fshelper.coffee
+++ client/app/MainApp/fs/fshelper.coffee
@@ -159,7 +159,6 @@

   @createRecursiveFolder = ({ path, vmName }, callback = noop) ->
     return warn "Pass a path to create folders recursively"  unless path
-    vmName or= KD.getSingleton("vmController").getDefaultVmName()

     KD.getSingleton("kiteController").run {
       kiteName    : "os"


Fixed: the form toggled each time a dnd action was performed

--- client/app/views/new_task_form.coffee
+++ client/app/views/new_task_form.coffee
@@ -14,13 +14,14 @@
         @newTaskFormInput = @newTaskForm.find ".description"
         @toggleButton = $('button.toggle-task-form')

-        # When the list is loaded we start the mangement
+        # When the list is loaded the first time, we start handling the form
         @taskList.tasks.on 'reset', (collection) =>
             @initializeForm()
+            @taskList.tasks.off 'reset' # we only want this to be executed once

         # If the list is empty, we need to show the form
         @taskList.tasks.on 'remove', (collection) =>
-            @toggleTaskForm false, true
+            @toggleTaskForm false, true if @taskList.tasks.length == 0

         # whether the user has written something or not in the new task form
         @hasUserTyped = false


Add Yes We Can meme

Add Yes We Can meme

--- scripts/meme.coffee
+++ scripts/meme.coffee
@@ -8,6 +8,7 @@
 #
 # Commands:
 #   hubot meme friday <text> - Meme: Rebecca Black - Friday
+#   hubot meme <text> yes we can - Meme: Barrack Obama - Yes We Can
 #   hubot meme Y U NO <text> - Meme: Y U NO GUY w/ bottom caption
 #   hubot meme I don't always <something> but when i do <text> - Meme: The Most Interesting man in the World
 #   hubot meme <text> (SUCCESS|NAILED IT) - Meme: Success kid w/ top caption
@@ -47,6 +48,9 @@
   robot.respond /meme friday( .+)?/i, id: 'meme.friday', (msg) ->
     friday = if msg.match[1]? then msg.match[1].trim() else 'friday'
     memeGenerator msg, '5NvNaw', "it's #{friday} #{friday}", "gotta get down on #{friday}"
+
+  robot.respond /meme (.*)yes we can(.*)/i, id: 'meme.yes-we-can', (msg) ->
+    memeGenerator msg, 'Q9bYTg', msg.match[1], msg.match[2]

   robot.respond /meme Y U NO (.+)/i, id: 'meme.y-u-no', (msg) ->
     memeGenerator msg, 'NryNmg', 'Y U NO', msg.match[1]


Do not deselect a highlight if we are loading the page with highlight location.

--- client/lib/annotator/annotator.coffee
+++ client/lib/annotator/annotator.coffee
@@ -184,11 +184,18 @@
   onFailedSelection: (event) =>
     super

+    # If this was not triggered by a user event (but by calling checkForEndSelection
+    # after enableAnnotating event) and thus does not have previousMousePosition, we
+    # do not do anything. Otherwise if location contains highlight and we want to
+    # have it selected when the page loads, this would not happen because onFailedSelection
+    # would be called which would deselect the highlight below.
+    return if not event or not event.previousMousePosition
+
     # If click (mousedown coordinates same as mouseup coordinates) is on a highlight, we do not
     # do anything because click event will be made as well, which will select the new highlight.
     # This assures we do not first deselect (and update location to publication location) just
     # to select another highlight immediately afterwards (and update location again to highlight).
-    return if event and event.previousMousePosition and event.previousMousePosition.pageX - event.pageX == 0 and event.previousMousePosition.pageY - event.pageY == 0 and @_inAnyHighlight event.clientX, event.clientY
+    return if event.previousMousePosition.pageX - event.pageX == 0 and event.previousMousePosition.pageY - event.pageY == 0 and @_inAnyHighlight event.clientX, event.clientY

     # Otherwise we deselect any existing selected highlight
     @_selectHighlight null


fix line highlighting

fix line highlighting

--- lib/editor/highlights.coffee
+++ lib/editor/highlights.coffee
@@ -2,7 +2,7 @@
   matchesPath: (ed, path) ->
     ed.getPath() == path ||
       (!ed.getPath() &&
-        ed.getBuffer().id.toString() == path.match(/untitled-(\d*)/)?[1])
+        ed.getBuffer().id == path.match(/untitled-([\d\w]*)/)?[1])

   observeLines: (ls, f) ->
     atom.workspace.observeTextEditors (ed) =>


Better getPath()

Better getPath()

--- lib/fuzzy-finder-view.coffee
+++ lib/fuzzy-finder-view.coffee
@@ -158,7 +158,7 @@
         -(editSession.lastOpened or 1)

     @paths = _.map editSessions, (editSession) =>
-      rootView.project.relativize editSession.buffer.getPath()
+      rootView.project.relativize editSession.getPath()

     @setArray(@paths)


New style uniforms

New style uniforms

The need for type properties in uniforms went away a while ago (r78?)

--- lib/glsl-preview-view.coffee
+++ lib/glsl-preview-view.coffee
@@ -72,12 +72,12 @@
     @clock = new THREE.Clock(true)

     @uniforms = {
-      iGlobalTime: { type: "f", value: 1.0 },
-      iResolution: { type: "v2", value: new THREE.Vector2() },
-      iMouse: { type: "v2", value: new THREE.Vector2() },
-      u_time: { type: "f", value: 1.0 },
-      u_resolution: { type: "v2", value: new THREE.Vector2() },
-      u_mouse: { type: "v2", value: new THREE.Vector2() },
+      iGlobalTime: {value: 0},
+      iResolution: {value: new THREE.Vector2()},
+      iMouse: {value: new THREE.Vector2()},
+      u_time: {value: 0},
+      u_resolution: {value: new THREE.Vector2()},
+      u_mouse: {value: new THREE.Vector2()},
     }

     @mesh1 = null
@@ -385,10 +385,7 @@

     textureId = @_getTextureId(filePath)

-    @uniforms[textureId] = {
-      type: "t"
-      value: texture
-    }
+    @uniforms[textureId] = {value: texture}

   removeTexture: (filePath) =>
     textureId = @_getTextureId(filePath)


:fire: unused

:fire: unused

--- lib/selection-wrapper.coffee
+++ lib/selection-wrapper.coffee
@@ -1,7 +1,3 @@
-# TODO#698 remove when finished
-{inspect} = require 'util'
-p = (args...) -> console.log inspect(args...)
-
 {Range, Point, Disposable} = require 'atom'
 {
   translatePointAndClip


oauth: change getAuth signature

oauth: change getAuth signature

--- workers/social/lib/social/models/oauth.coffee
+++ workers/social/lib/social/models/oauth.coffee
@@ -9,7 +9,7 @@
   @set
     sharedMethods   :
       static        :
-        getUrl      : (signature String, Function)
+        getUrl      : (signature Object, Function)

   @getUrl = secure (client, options, callback)->
     { provider } = options


oauth: fix g+ registration does not work bug

--- workers/social/lib/social/models/oauth.coffee
+++ workers/social/lib/social/models/oauth.coffee
@@ -59,6 +59,8 @@
         @saveTokensAndReturnUrl client, "twitter", callback

   @prependGroupName = (url, groupName) ->
+    return url  if groupName is 'koding'
+
     url = parser.parse url

     return "#{url.protocol}//#{groupName}.#{url.host}#{url.path}"


Fixes #3

Fixes #3

--- web/coffee/login.coffee
+++ web/coffee/login.coffee
@@ -11,7 +11,7 @@
         document.location.href = "problems.html"

 trigger_alert = (message)->
-  $("#error-alert").hide().text(message).show().delay(2000).fadeOut()
+  $("#error-alert").hide().text(message).show().delay(1500).fadeOut()

 login = (e) ->


mouseTrackingView: bugfix: wrong default method

--- coffee/src/views/mouseTrackingView.coffee
+++ coffee/src/views/mouseTrackingView.coffee
@@ -286,7 +286,7 @@

   _percentMouseDisplacement: (options = {}) =>
     startEvent = options.startEvent ? @_mousedownEvent
-    dimensionsFn = options.dimensionsFn ? @_percentContainerMouseDisplacement
+    dimensionsFn = options.dimensionsFn ? @_mouseElementContainerDimensions
     $el = $ options.$el ? options.el ? startEvent.target

     # calculate dimensions from $el, but use options dimensions when available


Fix syntax highlighting lua_opdef

Fix syntax highlighting lua_opdef

--- lib/csound-orchestra-grammar.coffee
+++ lib/csound-orchestra-grammar.coffee
@@ -50,7 +50,6 @@
                 tags[index + 1] -= length
                 scope = 'storage.type.csound'
                 tags.splice index, 0, @registry.startIdForScope(scope), length, @registry.endIdForScope(scope)
-
     tags

 module.exports =
@@ -217,6 +216,39 @@
               match: '\\$\\w+(?:\\.|\\b)'
             }
           ]
+        quotedStrings:
+          patterns: [
+            {
+              name: 'string.quoted.csound'
+              begin: '"'
+              beginCaptures:
+                0:
+                  name: 'punctuation.definition.string.begin.csound'
+              end: '"'
+              endCaptures:
+                0:
+                  name: 'punctuation.definition.string.end.csound'
+              patterns: [
+                {
+                  include: '#macroCalls'
+                }
+                {
+                  name: 'constant.character.escape.csound'
+                  # From
+                  # https://github.com/csound/csound/blob/develop/Opcodes/fout.c#L1405
+                  match: '%\\d*(\\.\\d+)?[cdhilouxX]'
+                }
+                {
+                  name: 'constant.character.escape.csound'
+                  match: '%[!%nNrRtT]|[~^]|\\\\(?:\\\\|[aAbBnNrRtT"]|[0-7]{1,3})'
+                }
+                {
+                  name: 'invalid.illegal.unknown-escape.csound'
+                  match: '\\\\.'
+                }
+              ]
+            }
+          ]
         partialExpressions:
           patterns: [
             { # These must be kept synchronized with the Csound Score grammar.
@@ -275,34 +307,7 @@
               match: '\\d+'
             }
             {
-              name: 'string.quoted.csound'
-              begin: '"'
-              beginCaptures:
-                0:
-                  name: 'punctuation.definition.string.begin.csound'
-              end: '"'
-              endCaptures:
-                0:
-                  name: 'punctuation.definition.string.end.csound'
-              patterns: [
-                {
-                  include: '#macroCalls'
-                }
-                {
-                  name: 'constant.character.escape.csound'
-                  # From
-                  # https://github.com/csound/csound/blob/develop/Opcodes/fout.c#L1405
-                  match: '%\\d*(\\.\\d+)?[cdhilouxX]'
-                }
-                {
-                  name: 'constant.character.escape.csound'
-                  match: '%[!%nNrRtT]|[~^]|\\\\(?:\\\\|[aAbBnNrRtT"]|[0-7]{1,3})'
-                }
-                {
-                  name: 'invalid.illegal.unknown-escape.csound'
-                  match: '\\\\.'
-                }
-              ]
+              include: '#quotedStrings'
             }
             {
               name: 'string.braced.csound'
@@ -370,7 +375,7 @@
               ]
             }
             {
-              begin: '\\b(lua_(?:exec|opdef))[ \\t]*(\\{\\{)'
+              begin: '\\b(lua_exec)[ \\t]*(\\{\\{)'
               beginCaptures:
                 1:
                   name: 'support.function.csound'
@@ -383,6 +388,33 @@
               patterns: [
                 {
                   include: 'source.lua'
+                }
+              ]
+            }
+            {
+              begin: '\\blua_opdef'
+              beginCaptures:
+                0:
+                  name: 'support.function.csound'
+              end: '\\}\\}'
+              endCaptures:
+                0:
+                  name: 'string.braced.csound'
+              patterns: [
+                {
+                  include: '#quotedStrings'
+                }
+                {
+                  begin: '\\{\\{'
+                  beginCaptures:
+                    0:
+                      name: 'string.braced.csound'
+                  end: '(?=\\}\\})'
+                  patterns: [
+                    {
+                      include: 'source.lua'
+                    }
+                  ]
                 }
               ]
             }
@@ -423,7 +455,7 @@
         range = displayBuffer.bufferRangeForScopeAtPosition 'entity.name.function.opcode.csound', event.oldRange.start

         if range
-          index = userDefinedOpcodes.indexOf(editor.getTextInBufferRange range)
+          index = userDefinedOpcodes.indexOf editor.getTextInBufferRange range
           if index >= 0
             userDefinedOpcodes.splice index, 1
             displayBuffer.tokenizedBuffer.invalidateRow row for row in [0...editor.getLineCount()] when !editor.isBufferRowCommented row


Fix #125: improve Android expiry formatting

--- src/jquery.payment.coffee
+++ src/jquery.payment.coffee
@@ -501,10 +501,17 @@
   sep = parts[2] || ''
   year = parts[3] || ''

-  if year.length > 0 || (sep.length > 0 && !(/\ \/?\ ?/.test(sep)))
+  if year.length > 0
     sep = ' / '

-  if mon.length == 1 and mon not in ['0', '1']
+  else if sep is ' /'
+    mon = mon.substring(0, 1)
+    sep = ''
+
+  else if mon.length == 2 or sep.length > 0
+    sep = ' / '
+
+  else if mon.length == 1 and mon not in ['0', '1']
     mon = "0#{mon}"
     sep = ' / '


couple tweaks

couple tweaks

--- models/job.coffee
+++ models/job.coffee
@@ -224,7 +224,7 @@

     <https://jobs.lever.co/help.com/ea972c24-982c-4724-bb4a-11cdf39c262d>

-    At Help.com (http://help.com/), our team of customer service and technology experts is setting out to build the next generation of customer service software. Our goal is to give companies the tools they need to delight their customers at enterprise scale. We want to win the customer service software market by providing companies and their customers with tools that are powerful and simple to use. At its core, Help.com (http://help.com/) is a technology company and we are looking for talented engineers at all levels to join our growing technical team in Austin. We are predominantly in the JavaScript/Node.js ecosystem, but are developing a microservice architecture that gives us immense flexibility in our choice of languages and tools. We've authored code in JavaScript, Java, and even Golang. We are looking for a senior software engineer to assist with backend development for our live chat product. We have a team of strong backend engineers who also dabble in fullstack development and are looking for a passionate backend engineer to help us grow our team and products.
+    At [Help.com](http://help.com/), our team of customer service and technology experts is setting out to build the next generation of customer service software. Our goal is to give companies the tools they need to delight their customers at enterprise scale. We want to win the customer service software market by providing companies and their customers with tools that are powerful and simple to use. At its core, [Help.com](http://help.com/) is a technology company and we are looking for talented engineers at all levels to join our growing technical team in Austin. We are predominantly in the JavaScript/Node.js ecosystem, but are developing a microservice architecture that gives us immense flexibility in our choice of languages and tools. We've authored code in JavaScript, Java, and even Golang. We are looking for a senior software engineer to assist with backend development for our live chat product. We have a team of strong backend engineers who also dabble in fullstack development and are looking for a passionate backend engineer to help us grow our team and products.

     **SOME OF THE FOLLOWING COULD MAKE YOU A GREAT FIT TO WORK AT [HELP.COM](http://help.com/)**


[Editor] Fixed resizing.

[Editor] Fixed resizing.

--- assets/js/view_models/editor.coffee
+++ assets/js/view_models/editor.coffee
@@ -137,6 +137,7 @@

     @session.setUseSoftTabs true
     @session.setTabSize 2
+    @session.setUseWrapMode true

     @displayName = ko.computed =>
       object = @object()
@@ -174,18 +175,18 @@
     @selectedObject = ko.observable null

     @tabs = ko.observableArray []
-    @tabs.subscribe @setSizes
+    @tabs.subscribe => @setSizes()

     @selectedTab = ko.observable null
-
-    @attachListeners()
-    @setLayout()
-    @setSizes()

     element = $('.editor')[0]
     @editor = ace.edit element
     @editor.setTheme 'ace/theme/clouds'
     $(element).css fontSize: '12pt', fontFamily: '"Source Code Pro", sans-serif'
+
+    @attachListeners()
+    @setLayout()
+    @setSizes()

     ko.applyBindings @

@@ -268,6 +269,8 @@
   setLayout: ->
     @layout = @body.layout
       livePaneResizing: true
+      onresize: =>
+        @setSizes()
       west:
         size: '20%'
         slidable: false
@@ -281,14 +284,15 @@
             slidable: false

   setSizes: ->
-    window.setTimeout (->
-      editor = $ '.editor'
-      frame = editor.parent()
-      tabs = $ '.tabs'
-      toolbar = $ '.toolbar'
-      editor.width frame.innerWidth()
-      editor.height frame.innerHeight() - tabs.outerHeight() - toolbar.outerHeight()
-    ), 1
+    editor = $ '.editor'
+    frame = editor.parent()
+    tabs = $ '.tabs'
+    toolbar = $ '.toolbar'
+    console.log frame.innerHeight()
+    editor.width frame.innerWidth()
+    editor.height frame.innerHeight() - tabs.outerHeight() - toolbar.outerHeight()
+    console.log @editor
+    @editor.resize()

   loadSidebar: ->
     @socket.emit 'get_tree', null, (tree) =>


Use environment variables for configuration.

--- server/index.coffee
+++ server/index.coffee
@@ -1,6 +1,13 @@
 config =
   port: process.env.PORT or 3000
   mongodb: if process.env.DB_PORT then process.env.DB_PORT.replace('tcp', 'mongodb') + '/educraft' else process.env.MONGODB
+  config:
+    apiUrl: process.env.API_URL
+    clientId: process.env.API_CLIENT_ID
+    clientSecret: process.env.API_CLIENT_SECRET
+    callbackUrl: process.env.API_CALLBACK_URL
+  session:
+    secret: process.env.API_SESSION_SECRET

 express = require 'express'

@@ -31,8 +38,6 @@
 passport = require 'passport'
 MongoStore = require('connect-mongo')(session)
 bcrypt = require 'bcrypt'
-
-config = require './config.json'

 BdApiStrategy = require('passport-bdapi').Strategy
 passport.use new BdApiStrategy {


#2 more receive sms code

#2 more receive sms code

--- server/nexmo.coffee
+++ server/nexmo.coffee
@@ -3,3 +3,14 @@
 Meteor.methods
   'receive_sms': (values) ->
     console.log values
+
+
+
+Router.route '/receive_sms/:data', ->
+  # NodeJS objects
+  # console.log @request
+  console.log @response
+
+  @response.end 'file download content\n'
+,
+  where: 'server'


Nested templates most likely working

Nested templates most likely working

--- lib/isomorphic/create-routes.coffee
+++ lib/isomorphic/create-routes.coffee
@@ -1,5 +1,8 @@
 Router = require 'react-router'
 filter = require 'lodash/collection/filter'
+sortBy = require 'lodash/collection/sortBy'
+last = require 'lodash/array/last'
+includes = require 'underscore.string/include'

 module.exports = (pages, pagesReq) ->
   templates = {}
@@ -23,10 +26,26 @@
       page.file.dirname isnt "."

   for templateFile in templateFiles
-    parentRoute = templates.root
+    # Find parent template.
+    parentTemplates = filter(templateFiles, (template) ->
+      includes(templateFile.requirePath, template.file.dirname)
+    )
+    parentTemplates = sortBy(parentTemplates, (template) -> template?.file.dirname.length)
+    parentTemplateFile = last(parentTemplates)
+    parentRoute = templates[parentTemplateFile?.file.dirname]
+
+    unless parentRoute
+      parentRoute = templates.root
+
+    #if templateFile.file.dirname isnt "."
+      #parentRoute = templates.root
+    #else
+      #parentRoute = null
+
     templates[templateFile.file.dirname] = Router.createRoute({
       name: templateFile.file.dirname + "-template"
       path: templateFile.path
+      parentRoute: parentRoute
       handler: pagesReq "./" + templateFile.requirePath
     })

@@ -48,24 +67,31 @@
         handler = pagesReq "./" + page.requirePath

     # Determine parent route.
-    # TODO
-    root = templates.root
+    parentRoutes = filter(templateFiles, (templateFile) ->
+      includes(page.requirePath, templateFile.file.dirname)
+    )
+    parentRoutes = sortBy(parentRoutes, (route) -> route?.file.dirname.length)
+    parentTemplateFile = last(parentRoutes)
+    parentRoute = templates[parentTemplateFile?.file.dirname]
+
+    unless parentRoute
+      parentRoute = templates.root

     # If page is an index page *and* in the same directory as a template,
     # create it as the default route.
-    #if page.path.indexOf('/index') > -1 #TODO
-    if page.requirePath is "index.cjsx"
+    if includes(page.path, "/index") and
+        parentRoute.file.dirname is parentTemplateFile.file.dirname
       Router.createDefaultRoute({
         name: page.path
-        parentRoute: root
+        parentRoute: parentRoute
         handler: handler
       })
     else
       Router.createRoute({
         name: page.path
         path: page.path
-        parentRoute: root
+        parentRoute: parentRoute
         handler: handler
       })

-  return root
+  return templates.root


Don't use a zero max age anymore.

Don't use a zero max age anymore.

--- build/tasks/publish-build-task.coffee
+++ build/tasks/publish-build-task.coffee
@@ -249,7 +249,6 @@
       ACL: 'public-read'
       Key: key
       Body: fs.createReadStream(assetPath)
-      CacheControl: 'max-age=0'
     s3.upload uploadParams, (error, data) ->
       if error?
         console.log("Upload release asset #{assetName} to S3 failed", error)


Adjusts the atom packages config file.

Adjusts the atom packages config file.

--- .atom/packages.cson
+++ .atom/packages.cson
@@ -39,7 +39,7 @@
   "linter-sass-lint"
   "linter-twig"
   "linter-ui-default"
-  "markdown-scroll-sync"
+  "markdown-preview-plus"
   "minimap"
   "minimap-autohider"
   "minimap-cursorline"


Machine: share unshare styling minor refac

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -480,9 +480,12 @@
       JMachine::shareWith.call this, options, callback

-  share: secure (client, users, callback)->
-    options = target: users, asUser: yes
-    JMachine::shareWith$.call this, client, options, callback
+
+  share: secure (client, users, callback) ->
+
+    options = target : users, asUser : yes
+
+    @shareWith$ client, options, callback

   unshare: secure (client, users, callback)->

@@ -492,14 +495,19 @@
     {profile:{nickname}}    = delegate

     if users.length is 1 and users[0] is nickname
-      JMachine::shareWith.call this, options, callback
-    else
-      JMachine::shareWith$.call this, client, options, callback
-
-  setAsOwner: secure (client, users, callback)->
-    options = target: users, asUser: yes, asOwner: yes
-    JMachine::shareWith$.call this, client, options, callback
-
-  unsetAsOwner: secure (client, users, callback)->
-    options = target: users, asUser: yes, asOwner: no
-    JMachine::shareWith$.call this, client, options, callback
+    then @shareWith options, callback
+    else @shareWith$ client, options, callback
+
+
+  setAsOwner: secure (client, users, callback) ->
+
+    options = target : users, asUser : yes, asOwner : yes
+
+    @shareWith$ client, options, callback
+
+
+  unsetAsOwner: secure (client, users, callback) ->
+
+    options = target : users, asUser : yes, asOwner : no
+
+    @shareWith$ client, options, callback


Minor changes in the watcher

Minor changes in the watcher

--- library/nucleus/watch.coffee
+++ library/nucleus/watch.coffee
@@ -181,8 +181,8 @@
     watchDirectory: (directory) ->
         notString = "The directory is not a string"
         notExists = "Dir %s does not exist, not watching"
+        assert _.isString(directory), notString
         exists = fs.existsSync directory.toString()
-        throw new Error(notString) unless _.isString directory
         relative = paths.relative process.cwd(), directory
         formats = [notExists.grey, relative.underline]
         return logger.warn formats... unless exists


EmbeddedVideoPlayerWrapper - Fix elements diplaying on video play

--- app/assets/javascripts/martian_components/components/core/embedded_video_player.coffee
+++ app/assets/javascripts/martian_components/components/core/embedded_video_player.coffee
@@ -33,14 +33,15 @@
       @playIcon.show()

     @poster.on 'click', =>
-      @loader.show()
       @playIcon.hide()

       if !@player?
+        @loader.show()
         @player = new YT.Player(@placeholder.attr('id'), @options)
         @wrapper.data 'player', @player

         @player.addEventListener 'onReady', =>
+          @loader.hide()
           @player.playVideo()
           @poster.hide()
       else


サーバルちゃんに元気がなかったのを修正

サーバルちゃんに元気がなかったのを修正

--- scripts/reaction.coffee
+++ scripts/reaction.coffee
@@ -25,7 +25,7 @@
           as_user: false
         client = robot.adapter.client
         arr = [
-          "すごーい",
+          "すごーい！！",
           "フレンズのみんなー！元気ー？",
           "すごーい！あなたは素敵なフレンズなんだね！",
           "おもしろーい！",


fixed coffee format

fixed coffee format

--- scripts/teamcity.coffee
+++ scripts/teamcity.coffee
@@ -160,7 +160,7 @@
                 else
                   msg.send "The requested builds have been killed"

-  robot.respond /tc host, (msg) ->
+  robot.respond /tc host/, (msg) ->
     msg.send "Current configured to talk to #{base_url}"

   robot.respond /show me builds/i, (msg) ->


CSSLoader: Append newly loaded node right next to the replaced node.

--- src/base/CSSLoader/CSSLoader.coffee
+++ src/base/CSSLoader/CSSLoader.coffee
@@ -34,16 +34,21 @@
 		opts = CUI.Element.readOpts _opts, "CSSLoader",
 			theme:
 				check: String
+				default: ""
 			url:
 				mandatory: true
 				check: String

-		# console.error "nodes:", @__getCSSNodes()
+		# console.error "nodes:", @__getCSSNodes(), opts, @getActiveCSS()
 		for oldCssNode in @__getCSSNodes()
 			is_loading = CUI.dom.getAttribute(oldCssNode, "data-cui-loading")
 			if is_loading
 				console.warn("CSSLoader.load. CSS already loading.", opts: opts)
 				return CUI.rejectedPromise()
+
+		active = @getActiveCSS()
+		if active and opts.url == active.url and active.theme == opts.theme
+			return CUI.resolvedPromise()

 		url = opts.url

@@ -70,6 +75,8 @@
 			"data-cui-theme": opts.theme
 			"data-cui-url": opts.url
 			href: css_href
+
+		old_css_nodes = CUI.dom.matchSelector(document.head, "link[name='"+@__cssName+"']")

 		dfr.always =>
 			CUI.dom.removeAttribute(cssNode, "data-cui-loading")
@@ -109,12 +116,13 @@
 						dfr.reject(css_href)
 						return

-				old_css_nodes = []
-				for css_node in CUI.dom.matchSelector(document.head, "link[name='"+@__cssName+"']") # :not([loading])")
-					if css_node != cssNode
+				# old_css_nodes = []
+				for css_node in old_css_nodes # :not([loading])")
+					if css_node == cssNode
+						continue
 						# console.info("CSSLoader.loadTheme: Removing old css node:", CUI.dom.getAttribute(css_node, "href"), "New Node is:", CUI.dom.getAttribute(cssNode, "href"), "Is loading:", CUI.dom.getAttribute(css_node, "loading"))
-						CUI.dom.remove(css_node)
-						old_css_nodes.push(css_node)
+					CUI.dom.remove(css_node)
+						# old_css_nodes.push(css_node)

 				CUI.dom.setAttribute(document.body, "data-cui-theme", opts.theme)

@@ -135,5 +143,8 @@
 				dfr.reject(css_href)
 				return

-		document.head.appendChild(cssNode)
+		if old_css_nodes.length > 0
+			CUI.dom.insertAfter(old_css_nodes[old_css_nodes.length - 1], cssNode)
+		else
+			document.head.appendChild(cssNode)
 		dfr.promise()


fix(category-picker): Update specs for sorting

--- internal_packages/category-picker/spec/category-picker-spec.cjsx
+++ internal_packages/category-picker/spec/category-picker-spec.cjsx
@@ -39,9 +39,10 @@
     @archiveCategory = new Category(id: 'id-456', name: 'archive', displayName: "ArCHIVe", accountId: TEST_ACCOUNT_ID)
     @userCategory = new Category(id: 'id-789', name: null, displayName: "MyCategory", accountId: TEST_ACCOUNT_ID)

-    spyOn(Categories, "forAccount").andReturn NylasTestUtils.mockObservable(
-      [@inboxCategory, @archiveCategory, @userCategory]
-    )
+    observable = NylasTestUtils.mockObservable([@inboxCategory, @archiveCategory, @userCategory])
+    observable.sort = () => observable
+
+    spyOn(Categories, "forAccount").andReturn observable
     spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory
     spyOn(AccountStore, "accountForItems").andReturn @account
     spyOn(Actions, "closePopover")


Sim: Display rating updates.

Sim: Display rating updates.

--- server/bw/battle.coffee
+++ server/bw/battle.coffee
@@ -755,6 +755,7 @@
         @message "#{winnerId}: #{oldRatings[0]} -> #{result[0].rating}"
         @message "#{loserId}: #{oldRatings[1]} -> #{result[1].rating}"
         @emit('ratingsUpdated')
+        @sendUpdates()

   # Proxies arguments the `send` function for all spectators.
   broadcast: ->


Activity: Ticker fixed pos on scroll sanity check

--- client/Social/Activity/AppView.coffee
+++ client/Social/Activity/AppView.coffee
@@ -46,6 +46,8 @@
       topOffset = @tickerBox.$().position().top
       windowController.on 'ScrollHappened', =>
         if document.body.scrollTop > topOffset
+        # sanity check
+        topOffset = @tickerBox.$().position().top  if topOffset < 200
         then @tickerBox.setClass 'fixed'
         else @tickerBox.unsetClass 'fixed'


Исправлен баг с callBack в ImageLoader

Исправлен баг с callBack в ImageLoader

--- utils/ImagesLoader.coffee
+++ utils/ImagesLoader.coffee
@@ -29,10 +29,13 @@
 					loaded++
 					# генерируем событие
 					BO.generate "imageLoaded", total, loaded
+
 					# загрузили все
-					BO.generate "imagesAllLoaded", total, loaded if loaded == total
-					# вызываем каллбак
-					callBack total, loaded if callBack?
+					if loaded == total
+
+						BO.generate "imagesAllLoaded", total, loaded
+						# вызываем каллбак
+						callBack total, loaded if callBack?

 				, (e) ->


Simple annotation for future implementation.

--- cli/src/cli.coffee
+++ cli/src/cli.coffee
@@ -63,5 +63,6 @@

       .describe('rf', 'Use with -d [view|mvc] for deleting the whole view folder')
       .describe('src', 'Use with -n for use a specific theoricus version')
+      # .describe('gitsub', 'Use with --src for automatic git submodule setup')

     ).argv


Test groups

Test groups

--- spec/Measure.coffee
+++ spec/Measure.coffee
@@ -37,9 +37,11 @@

   describe 'with remote test image', ->
     url = 'https://1.gravatar.com/avatar/40a5769da6d979c1ebc47cdec887f24a'
-    it 'should have the correct group', ->
+    it 'should have the correct group', (done) ->
       out.once 'begingroup', (group) ->
         chai.expect(group).to.equal url
+        done()
+      ins.send url
     it 'should find correct dimensions', (done) ->
       @timeout 0
       error.once 'data', (data) ->
@@ -55,9 +57,11 @@

   describe 'with remote JPG image', ->
     url = 'http://bergie.iki.fi/files/flowhub-promo.jpg'
-    it 'should have the correct group', ->
+    it 'should have the correct group', (done) ->
       out.once 'begingroup', (group) ->
         chai.expect(group).to.equal url
+        done()
+      ins.send url
     it 'should find correct dimensions', (done) ->
       @timeout 0
       error.once 'data', (data) ->


:bomb: Deliberately Break The Build

:bomb: Deliberately Break The Build

--- spec/go-spec.coffee
+++ spec/go-spec.coffee
@@ -20,6 +20,7 @@
     it "expands the path", ->
       runs =>
         result = go.buildgopath()
+        expect(false).toBe true
         expect(result).toBeDefined
         expect(result).toBeTruthy
         expect(result).toBe path.join(pathhelper.home(), 'go')