Use the new split*() methods on Pane model in WorkspaceView specs

--- spec/workspace-view-spec.coffee
+++ spec/workspace-view-spec.coffee
@@ -42,7 +42,7 @@
         runs ->
           editorView1 = atom.workspaceView.getActiveView()
           buffer = editorView1.getEditor().getBuffer()
-          editorView1.splitRight()
+          editorView1.getPaneView().getModel().splitRight(copyActiveItem: true)
           expect(atom.workspaceView.getActivePaneView()).toBe atom.workspaceView.getPaneViews()[1]

           simulateReload()
@@ -196,7 +196,8 @@
       atom.workspaceView.attachToDom()
       rightEditorView = atom.workspaceView.getActiveView()
       rightEditorView.getEditor().setText("\t  \n")
-      leftEditorView = rightEditorView.splitLeft()
+      rightEditorView.getPaneView().getModel().splitLeft(copyActiveItem: true)
+      leftEditorView = atom.workspaceView.getActiveView()
       expect(rightEditorView.find(".line:first").text()).toBe "    "
       expect(leftEditorView.find(".line:first").text()).toBe "    "

@@ -207,14 +208,16 @@
       expect(rightEditorView.find(".line:first").text()).toBe withInvisiblesShowing
       expect(leftEditorView.find(".line:first").text()).toBe withInvisiblesShowing

-      lowerLeftEditorView = leftEditorView.splitDown()
+      leftEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
+      lowerLeftEditorView = atom.workspaceView.getActiveView()
       expect(lowerLeftEditorView.find(".line:first").text()).toBe withInvisiblesShowing

       atom.workspaceView.trigger "window:toggle-invisibles"
       expect(rightEditorView.find(".line:first").text()).toBe "    "
       expect(leftEditorView.find(".line:first").text()).toBe "    "

-      lowerRightEditorView = rightEditorView.splitDown()
+      rightEditorView.getPaneView().getModel().splitDown(copyActiveItem: true)
+      lowerRightEditorView = atom.workspaceView.getActiveView()
       expect(lowerRightEditorView.find(".line:first").text()).toBe "    "

   describe ".eachEditorView(callback)", ->
@@ -241,7 +244,7 @@
       atom.workspaceView.eachEditorView(callback)
       count = 0
       callbackEditor = null
-      atom.workspaceView.getActiveView().splitRight()
+      atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
       expect(count).toBe 1
       expect(callbackEditor).toBe atom.workspaceView.getActiveView()

@@ -259,10 +262,10 @@

       subscription = atom.workspaceView.eachEditorView(callback)
       expect(count).toBe 1
-      atom.workspaceView.getActiveView().splitRight()
+      atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
       expect(count).toBe 2
       subscription.off()
-      atom.workspaceView.getActiveView().splitRight()
+      atom.workspaceView.getActiveView().getPaneView().getModel().splitRight(copyActiveItem: true)
       expect(count).toBe 2

   describe "core:close", ->
@@ -271,7 +274,7 @@

       paneView1 = atom.workspaceView.getActivePaneView()
       editorView = atom.workspaceView.getActiveView()
-      editorView.splitRight()
+      editorView.getPaneView().getModel().splitRight(copyActiveItem: true)
       paneView2 = atom.workspaceView.getActivePaneView()

       expect(paneView1).not.toBe paneView2


Call hideLazyLoader method of list controller

--- client/admin/lib/views/members/teammemberscommonview.coffee
+++ client/admin/lib/views/members/teammemberscommonview.coffee
@@ -136,7 +136,7 @@
     if err?.message?.indexOf('No account found') > -1
       @search yes
     else
-      @listController.lazyLoader.hide()
+      @listController.hideLazyLoader()
       kd.warn err


activity: payload checks

activity: payload checks

--- client/app/lib/commonviews/linkviews/profilelinkview.coffee
+++ client/app/lib/commonviews/linkviews/profilelinkview.coffee
@@ -45,7 +45,7 @@
   updateHref: ->
     { payload } = @getOptions()
     nickname = @getData().profile?.nickname
-    href = if payload then "/Admin/Integrations/Configure/#{payload.channelIntegrationId}"
+    href = if payload?.channelIntegrationId then "/Admin/Integrations/Configure/#{payload.channelIntegrationId}"
     else if nickname then "/#{nickname}"

     @setAttribute "href", href  if href


managed: Fixed className callback bug

managed: Fixed className callback bug

The MachineSettingsAdvancedView.createButton method's className parameter
was being used as the callback method name as well - so when I changed
the className in a prior commit, it broke the handler usage.

This commit corrects that issue, by adding a new "callbackName"
parameter, and applies its usage to the two `@createButton` uses.

--- client/app/lib/providers/machinesettingsadvancedview.coffee
+++ client/app/lib/providers/machinesettingsadvancedview.coffee
@@ -12,7 +12,7 @@

     @machine = data

-    reinitButton   = @createButton 'Reinitialize your VM', 'reinit', 'This will take your VM back to its original state. (Note: you will lose all your data)'
+    reinitButton   = @createButton 'reinit', 'Reinitialize your VM', 'reinit', 'This will take your VM back to its original state. (Note: you will lose all your data)'
     terminateClass = 'terminate'
     terminateTitle = 'Terminate your VM'
     terminateText  = 'This will delete your VM completely. (Note: you will lose all your data)'
@@ -23,14 +23,14 @@
       terminateTitle = 'Disconnect your VM'
       terminateText  = 'Remove the connection between your Machine and Koding.'

-    terminateButton = @createButton terminateTitle, terminateClass, terminateText
+    terminateButton = @createButton 'terminate', terminateTitle, terminateClass, terminateText

-  createButton: (title, className, desc) ->
+  createButton: (callbackName, title, className, desc) ->

     @addSubView new KDCustomHTMLView
       cssClass : "big-icon advanced #{className}"
-      click    : (e) => @handleButtonClick e, className
+      click    : (e) => @handleButtonClick e, callbackName
       partial  : """


Убрал из определения IE8 с включенным режимом совместимости с IE7

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -15,7 +15,7 @@
    Конструктор
   ###
   constructor: (images, options = {}) ->
-    if not isStorage
+    if not document.querySelectorAll
       # throw "Please upgrade your browser to view chocolate"
       return false


Do not start the livereload server when running individual tasks.

--- app/templates/gulpfile.coffee
+++ app/templates/gulpfile.coffee
@@ -67,7 +67,7 @@
 		.pipe(rename(suffix: '.min'))
 		.pipe(minifycss())
 		.pipe(gulp.dest(config.dest_css))
-		.pipe livereload(server)
+		.pipe livereload(server, auto:false)

 # compile client-side coffeescript, concat, & minify js
@@ -80,7 +80,7 @@
 		.pipe(rename(suffix: '.min'))
 		.pipe(uglify())
 		.pipe(gulp.dest(config.dest_client_scripts))
-		.pipe livereload(server)
+		.pipe livereload(server, auto:false)

 # compile server-side coffeescript
 gulp.task 'server_scripts', ->
@@ -90,7 +90,7 @@
 		# .pipe(jshint())
 		# .pipe(jshint.reporter('default'))
 		.pipe(gulp.dest(config.dest_server_scripts))
-		.pipe livereload(server)
+		.pipe livereload(server, auto:false)

 # # concat & minify plugins
@@ -118,14 +118,14 @@
 	gulp.src(config.src_bower)
 		# .pipe(embedlr())
 		.pipe(gulp.dest(config.dest_bower))
-		.pipe livereload(server)
+		.pipe livereload(server, auto:false)

 # watch html
 gulp.task 'views', ->
 	gulp.src(config.src_views)
 		# .pipe(embedlr())
 		.pipe(gulp.dest(config.dest_views))
-		.pipe livereload(server)
+		.pipe livereload(server, auto:false)

 # clean '.dist/'


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -26,7 +26,7 @@
   ###*
   @name clampToBounds
   @methodOf Clampable#
-  @param
+  @param {}
   ###
   clampToBounds: (bounds) ->
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height


Tweaked feedback text for VICS82

Tweaked feedback text for VICS82

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -170,16 +170,16 @@
       lensed_quasar:
         option_1: "Typically, lensed quasar systems show either two ('doubles') or four ('quads') small lensed features, which look like stars. Mark each of the two, or four, quasars that you see!"
         option_2: "See how the 'multiple images' of the background quasar are arranged in symmetrical patterns around the lens galaxy. Mark each one! You might have to zoom in, using the Quick Dashboard."
-        option_3: "Most lensed quasars look blue, but the more distant ones look fainter, and yellow or red (having been 'redshifted' by the expansion of the universe)."
+        option_3: "Quasars can have a wide variety of colours in infrared images, as you'll see from the many images that contain unlensed quasars at their centres."
         option_4: "Quasars look different from other galaxies, because we are not seeing starlight but rather the light from supermassive black holes in their centres. These monsters often outshine the light from the rest of the galaxy."
         option_5: "We expect lensed quasars to be about 10 times rarer than lensed galaxies, but they are really useful. You can read more about what we use gravitational lenses for on the Science page."
         option_6: "You can read more about lensed quasars in the Spotters Guide."
       lensed_galaxy:
-        option_1: "The most common background galaxies in the universe (those little blobs you see everywhere) are faint, blue, and star-forming, so usually (but not always!), lensed galaxies appear blue."
-        option_2: "Unlike most little blue galaxies you see, lensed galaxies appear stretched and curved around the lens."
+        option_1: "The most common background galaxies in the universe are faint, blue, and star-forming, so lensed galaxies often (but not always!) appear blue-ish."
+        option_2: "Unlike most galaxies you see in these images, lensed galaxies appear stretched and curved around a lensing object."
         option_3: "The lensed features in these systems are typically only a galaxy diameter or two away from the centre of the lens. You might have to zoom in, with the Quick Dashboard!"
         option_4: "Look for a faint “counter-image” with the same colour on the opposite side of the lens to the arc. Sometimes these are too faint to see though. Mark the counter-image too, if you can!"
-        option_5: "The galaxy acting as a lens is most likely to be a bright, smooth, yellow or red elliptical galaxy, since these are the most massive galaxies."
+        option_5: "The galaxy acting as a lens is most likely to be a bright, smooth, orange elliptical galaxy, since these are the most massive galaxies."
         option_6: "Very occasionally, if the cosmic alignment is very precise, the galaxy behind the lens will appear as an almost exactly circular Einstein Ring."
         option_7: "You can read more about lensed galaxies in the Spotters Guide."
       missed:


FAQ on lens positioning in centre of images

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -111,7 +111,7 @@
       details: "Check out The Spotter's Guide  for detailed descriptions and reference images of Real Lenses and False Positives.  You can use the Spotter's Guide as a reference throughout your time on Space Warps."
     identify:
       header: "Identifying gravitational lenses"
-      details: "The group of orange galaxies is a gravitational lens. It is bending and magnifying the light from a faint galaxy, lying far behind, into a blue arc that surrounds the lensing galaxy."
+      details: "The group of orange galaxies in the center of the image is a gravitational lens. It is bending and magnifying the light from a faint galaxy, lying far behind, into a blue arc that surrounds the lensing galaxy."
     mark:
       header: "Marking lensed features"
       details: "If you see something that is being lensed, mark it. In this case, click on the arc."
@@ -254,13 +254,15 @@
       header: "Interface"
       questions: """

What is my main task?

-
The main task for the current project is to inspect the images on the classification page, look for a gravitational lens and mark any one of the lensed images within a lens system in an image. Lens systems are rare. Most of the images won't have any lenses, a few images will have a lens and in extremely rare cases, there might be more than one lens in an image. So, watch out!

+
The main task for the current project is to inspect each image on the classification page, look for a gravitational lens, and mark any of the lensed features you see in the image. Lens systems are rare: most of the images won't contain any lenses, but a few images will have a lens and in extremely rare cases, there might be more than one lens in an image. So, watch out!

Should I try and be inclusive, or discerning?

During a first pass through the images, when the website has a blue background, we don't want to miss any lenses: if in doubt, mark them. However, when we are trying to refine a list of candidates to identify the best ones (when the site has an orange background), we need to be more skeptical: only mark the features that you really think are due to lensing. The Spotter's Guide can help you make your judgement.

I marked a simulated lens but was told that I missed it. What's the problem?

We'd like you to mark any lensed object that you see i.e. you can mark one or all of the curved arcs, or multiple quasars. Sometimes the site will tell you that you missed a simulated lens, when you actually marked something nearby the lensed object, e.g. the marker might have been placed on the lens galaxy itself instead of the lensed features.

What do I do if I see more than one lensed image per lens system?

You should place a marker on at least one lensed feature that you see per lens system. If you see an arc, mark it and preferably, mark its counter-arc if you can see it. If you see a pair of quasars (compact objects) either side of a lensing galaxy, mark both of them preferably. You only need to mark one lensed feature for your identification to be registered, but you can mark multiple features if you wish.

+
Are the lenses all in the middle of the images?

+
The images were selected to all contain objects that could either be lenses (like massive orange galaxies, or groups of galaxies), or would make interesting background sources (like quasars). The images were made so that these objects all lie at the centres of the images - so it's most likely (although not guaranteed) that if a lens is present, it will be in the middle of the field.

When should I use the Quick Dashboard?

Many lensed images are faint and very close to the bright orange lensing galaxies. You can switch to the Quick Dashboard to play with different settings or zoom/pan to get a detailed view near the lensing galaxy and be more confident of not missing a faint lens.

I missed a lens! How do I go back?


ごめんなさい

ごめんなさい

--- scripts/idobata-talk.coffee
+++ scripts/idobata-talk.coffee
@@ -56,6 +56,10 @@
       "…大変ね"
       "西に向かって懺悔してからissueを閉じなさいっ！"
     ]
+
+  robot.hear /ごめん|すみません/i, (msg) ->
+    msg.send "分かればいいのよ"
+
   # respond
   robot.respond /嫌い？$/i, (msg) ->
     words = [


Simplify the time, don't remove seconds from things 8m or longer

--- js/libs/time.coffee
+++ js/libs/time.coffee
@@ -39,13 +39,9 @@
     minutes = Math.floor(seconds / 60)
     hours = Math.floor(minutes / 60)

-    if hours > 8
-      "#{hours}h"
-    else if hours > 0
+    if hours > 0
       "#{hours}h #{minutes % 60}m"
-    else if minutes > 8
-      "#{minutes}m"
-    else if minutes > 0
+    else if minutes > 1
       "#{minutes}m #{seconds % 60}s"
     else
-      "#{seconds}s"
+      "#{seconds % 60}s"


test-hiraokaの削除

test-hiraokaの削除

--- scripts/test-hiraoka.coffee
+++ scripts/test-hiraoka.coffee
@@ -1,22 +0,0 @@
-# Description:
-#   AAを表示するbot
-# Author:
-#   raoka0000
-
-module.exports = (robot) ->
-  robot.respond /(hiraoka)/i, (msg) ->
-    text = """
-    　　　　　　　　　　　_
-    　　　　　　　　／"'￣フ／)　　　　　　　 、
-    　　　　　　　,/ ,--、 ￣､__フ　　　　 ／/
-    　　　　　　 ,ヘｌ⌒ﾉ 　　＞　　　　,／　/＿
-    　　　　　　( ＿l_"_ニ_　く＿　 ／）　／　／
-          ,＞　　　　　 フ､　　　　､､＞
-    　　　　　　　 <"　（　　　　　　フ　_＿＞
-    　　　　　　　　ヽ　 ＼､､　＿フ' ノ
-    　　　　　　　　　＼、＿＿､､,_ノ゛
-    　　　　　　　　　　 　　 〉ﾆ〉ﾆ〉
-    　　　　　　　　　 　 ,､_/ﾆ/ﾆ/
-    　　　　　　　　　　∠ｌ∠ｌ､ニ＞
-    """
-    msg.send text


fix badge, debug stmnt

fix badge, debug stmnt

--- src/logging.coffee
+++ src/logging.coffee
@@ -6,7 +6,7 @@
 ############################################################################################################
 CND                       = require 'cnd'
 rpr                       = CND.rpr
-badge                     = 'PIPESTREAMS/EXPERIMENTS/PULL-STREAM-EXAMPLES-PULL'
+badge                     = 'PIPESTREAMS/LOGGING'
 log                       = CND.get_logger 'plain',     badge
 info                      = CND.get_logger 'info',      badge
 whisper                   = CND.get_logger 'whisper',   badge
@@ -54,7 +54,6 @@
 @get_logger = ( letter, color ) ->
   transform_nr = 0
   return ( transform ) =>
-    debug '34984', transform
     transform_nr   += +1
     prefix          = "#{CND[ color ] CND.reverse '  '} #{CND[ color ] letter + transform_nr}"
     source_ref      = @_get_source_ref 1, prefix, color


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/camera.coffee
+++ test/camera.coffee
@@ -6,6 +6,8 @@
 test "overlay", 1, ->
   object = GameObject()

-  c = Came
+  camera = Camera()
+
+  c
 # Clear out the module
 module()


More freedom with schedule.

More freedom with schedule.

--- scripts/common.coffee
+++ scripts/common.coffee
@@ -11,7 +11,7 @@

 module.exports = (robot) ->
     robot.respond /schedule$/i, (msg) ->
-        msg.send "Our current schedule is Monday, Wednesday & Friday from about 9am until 1pm GMT."
+        msg.send "Our current schedule is Monday, Wednesday & Friday from about 9am. Casts are usually between 2-4 hours, work and game depending."

     robot.respond /social$/i, (msg) ->
         msg.send "You can find me on Twitter at http://twitter.com/masonest_ and on Facebook at http://facebook.com/masonest"


Fix the test method

Fix the test method

--- scripts/custom.coffee
+++ scripts/custom.coffee
@@ -16,4 +16,4 @@
   # Super simple example: If the robot detects the word "thank you",
   # it just responds it with "you're welcome".
   robot.hear /(.*)thank you(.*)/i, (res) ->
-    robot.messageRoom room, "you're welcome."+    res.send "you're welcome."


less robust since carson broke it

less robust since carson broke it

--- scripts/trello.coffee
+++ scripts/trello.coffee
@@ -61,44 +61,18 @@

   robot.hear /^http(s?):\/\/(.*)/i, (msg) ->
     url = msg.match[0]
-    msg.send 'this is the url: ' + url
     unless process.env.TRELLO_API_KEY?
       msg.send "Please specify the Trello API key in TRELLO_API_KEY"
       return
     unless process.env.TRELLO_TOKEN?
       msg.send "Please specify the Trello token in TRELLO_TOKEN"
       return
-    msg.send 'going for it...'
-    jsdom = require 'jsdom'
-    msg.send 'i have required the jsdom lib'
-    jsdom.env(
-      html: url
-      scripts: [
-        'http://code.jquery.com/jquery-1.7.2.min.js'
-      ]
-      done: (errors, window) ->
-        msg.send 'i have finished doing whatever loading thing i need to do'
-        unless errors
-          $ = window.$
-          title = $('title').text()
-          msg.send 'i have the title: ' + title
+    args =
+      name: title
+      idList: list
+      desc: url

-          if title
-            title = title
-            list = '510acfdfeca4af654e004e84'
-          else
-            title = url
-            list = '510be43bbfd03ea75700314b'
-          msg.send 'ready for my args'
-          args =
-            name: title
-            idList: list
-            desc: url
-
-          trelloIt url, args, msg
-    )
-
-    msg.send 'i am the end'
+    trelloIt url, args, msg

 trelloIt = (subject, args, msg) ->
   Trello = require("node-trello");


Release mode bug fixed

Release mode bug fixed

--- release.coffee
+++ release.coffee
@@ -2,7 +2,7 @@

 groundskeeper = require 'groundskeeper'

-{log} = Neft
+{utils, log} = Neft

 RELEASE_NAMESPACES_TO_REMOVE = [
 	'assert', 'Object.freeze', 'Object.seal', 'Object.preventExtensions'


Now wrapping HTMLInputElement.value as a property.

--- src/dom/advice.coffee
+++ src/dom/advice.coffee
@@ -213,3 +213,4 @@
     wrapProperty(dom.HTMLTableCellElement.prototype, 'headers')

     wrapProperty(dom.HTMLInputElement.prototype, 'checked')
+    wrapProperty(dom.HTMLInputElement.prototype, 'value')


Don't draw axis label when rule coords are NaN

This happens when there is no data, so ranges don't work and
thus we can't compute coords. I think we should be able to
draw axis label despite this, but for now at least don't draw
it in some random location (which appears as if there was some
garbage painted on canvas, e.g. misplaced ticks).

--- bokehjs/src/coffee/models/axes/axis.coffee
+++ bokehjs/src/coffee/models/axes/axis.coffee
@@ -283,14 +283,20 @@
     @visuals.axis_label_text.set_value(ctx)
     _apply_location_heuristics(ctx, side, orient)

+    x = sx+nx*standoff+nx*xoff
+    y = sy+ny*standoff+ny*yoff
+
+    if isNaN(x) or isNaN(y)
+      return
+
     if angle
-      ctx.translate(sx+nx*standoff+nx*xoff, sy+ny*standoff+ny*yoff)
+      ctx.translate(x, y)
       ctx.rotate(angle)
       ctx.fillText(label, 0, 0)
       ctx.rotate(-angle)
-      ctx.translate(-sx-nx*standoff+nx*xoff, -sy-ny*standoff+ny*yoff)
+      ctx.translate(-x, -y)
     else
-      ctx.fillText(label, sx+nx*standoff+nx*xoff, sy+ny*standoff+ny*yoff)
+      ctx.fillText(label, x, y)

 class Axis extends GuideRenderer.Model
   default_view: AxisView


Express: Moving requires out of the exported function call.

--- server/express/lib/server.coffee
+++ server/express/lib/server.coffee
@@ -4,32 +4,39 @@
 # for setting arguments, and spawning servers.  In a complex system
 # you would probably want to replace the CLI/Farm with your own code,
 # and use server.coffee directly.
+#
+#### Dependencies ####
+# anything not in the standard library is included in the repo, or
+# can be installed with an:
+#     npm install
+mkdirp = require('mkdirp')
+express = require('express')
+fs = require('fs')
+path = require('path')
+http = require('http')
+hbs = require('hbs')
+random = require('./random_id')
+passportImport = require('passport')
+OpenIDstrat = require('passport-openid').Strategy
+defargs = require('./defaultargs')
+# pageFactory can be easily replaced here by requiring your own page handler
+# factory, which gets called with the argv object, and then has get and put
+# methods that accept the same arguments and callbacks. That would be the
+# easiest way to use the Smallest Federated Wiki with a database backend.
+pageFactory = require('./page')

 # Set export objects for node and coffee to a function that generates a sfw server.
 module.exports = exports = (argv) ->
-  #### Dependencies ####
-  # anything not in the standard library is included in the repo, or
-  # can be installed with an:
-  #     npm install
-  mkdirp = require('mkdirp')
-  express = require('express')
-  fs = require('fs')
-  path = require('path')
-  http = require('http')
-  hbs = require('hbs')
-  random = require('./random_id')
-  passportImport = require('passport')
-  OpenIDstrat = require('passport-openid').Strategy
   # Create the main application object, app.
   app = express.createServer()
   # defaultargs.coffee exports a function that takes the argv object
   # that is passed in and then does its
   # best to supply sane defaults for any arguments that are missing.
-  argv = require('./defaultargs')(argv)
+  argv = defargs(argv)
   # Construct authentication handler.
   passport = new passportImport.Passport()
   # Tell pagehandler where to find data, and default data.
-  app.pagehandler = pagehandler = require('./page')(argv)
+  app.pagehandler = pagehandler = pageFactory(argv)

   #### Setting up Authentication ####
   # The owner of a server is simply the open id url that the wiki


Fix getting names separated with comma or space

--- lib/dashing-contrib/assets/widgets/switcher/switcher.coffee
+++ lib/dashing-contrib/assets/widgets/switcher/switcher.coffee
@@ -12,7 +12,7 @@
     names = $('[data-switcher-dashboards]').first().attr('data-switcher-dashboards') || ''
     if names.length > 1
       # Get names separated with comma or space
-      @dashboardNames = (name.trim() for name in names.sub(' ', ',').split(','))
+      @dashboardNames = (name.trim() for name in names.split(/[ ,]+/).filter(Boolean))

   start: (interval=60000) ->
     self = @


Teamwork: New dashboard's tab handle is hidden.

--- client/Teamwork/Views/teamworktabview.coffee
+++ client/Teamwork/Views/teamworktabview.coffee
@@ -179,7 +179,6 @@
   createTabFromFirebaseData: (data) ->
     {sessionKey, indexKey} = data
     switch data.type
-      when "dashboard" then @createDashboard()
       when "terminal"  then @createTerminal     sessionKey, indexKey
       when "browser"   then @createPreview      sessionKey, indexKey
       when "drawing"   then @createDrawingBoard sessionKey, indexKey
@@ -194,6 +193,7 @@
     @dashboard = new KDTabPaneView
       title    : "Dashboard"
       indexKey : "dashboard"
+      hiddenHandle: yes

     dashboard  = new TeamworkDashboard
       delegate : @workspace.getDelegate()


avatararea: avatarpopup code cleanup

avatararea: avatarpopup code cleanup

--- client/app/lib/avatararea/avatarpopup.coffee
+++ client/app/lib/avatararea/avatarpopup.coffee
@@ -6,45 +6,37 @@

 module.exports = class AvatarPopup extends KDView

-  constructor:->
+  constructor: (options = {}, data)->

-    super
+    options.cssClass = kd.utils.curry 'avatararea-popup', options.cssClass

-    mainController = kd.getSingleton "mainController"
-    mainController.on "accountChanged.to.loggedIn", @bound 'accountChanged'
+    super options, data

-    @_windowController = kd.getSingleton('windowController')
+    @addSubView @avatarPopupContent = new KDView cssClass : 'content'
+
     @listenWindowResize()

+
   show:->
+
+    { mainController, windowController } = kd.singletons
     kd.utils.killWait @loaderTimeout
     @_windowDidResize()
-    @_windowController.addLayer this
-    kd.getSingleton('mainController').emit "AvatarPopupIsActive"
-    @setClass "active"
+    windowController.addLayer this
+    mainController.emit 'AvatarPopupIsActive'
+    @setClass 'active'
+
     return this

+
   hide:->
-    kd.getSingleton('mainController').emit "AvatarPopupIsInactive"
-    @unsetClass "active"
+
+    { mainController } = kd.singletons
+    mainController.emit 'AvatarPopupIsInactive'
+    @unsetClass 'active'
+
     return this

-  viewAppended:->
-
-    @setClass "avatararea-popup"
-    @addSubView @avatarPopupTab = new KDView cssClass : 'tab', partial : ''
-    @setPopupListener()
-
-    @addSubView @avatarPopupContent = new KDView cssClass : 'content hidden'
-    @addSubView @notLoggedInWarning = new KDView
-      height   : "auto"
-      cssClass : "content sublink"
-      partial  : @notLoggedInMessage or "Login required."
-
-    @accountChanged()  if isLoggedIn()
-
-  setPopupListener:->
-    @avatarPopupTab.on 'click', (event)=> @hide()

   _windowDidResize:->
     if @listController


EditorPane: Return if collaborativestring does not exist.

--- client/ide/workspace/panes/editorpane.coffee
+++ client/ide/workspace/panes/editorpane.coffee
@@ -183,6 +183,8 @@

     string = @rtm.getFromModel @getFile().path

+    return unless string
+
     @rtm.bindRealtimeListeners string, 'string'

     @rtm.on 'TextInsertedIntoString', (changedString, change) =>


Use Collapse component vs own logic

Use Collapse component vs own logic

--- client/lanes/components/shared/FieldSet.cjsx
+++ client/lanes/components/shared/FieldSet.cjsx
@@ -1,58 +1,35 @@
 class Lanes.Components.FieldSet extends Lanes.React.Component

     getDefaultProps: ->
-        speed: 0.4
+        expanded: true

     propTypes:
         title: React.PropTypes.string.isRequired
-        speed: React.PropTypes.number
-        collapsed: React.PropTypes.bool
+        expanded: React.PropTypes.bool

     getInitialState: ->
-        state = {
-            expanded: !@props.collapsed,
-            icon: if @props.collapsed then 'plus' else 'minus'
-        }
-        state.height = 30 if @props.collapsed
-        state
+        expanded: @props.expanded

-    getClientHeight: ->
-        _.max(
-            _.pluck(@refs.body.getDOMNode().children, 'clientHeight')
-        ) + 45
-
+    componentWillReceiveProps: (nextProps) ->
+        @setState(expanded: nextProps.expanded) if nextProps.expanded?

     toggleExpanded: ->
-        if @state.expanded
-            if ! @state.hasExpanded
-                @setState( hasExpanded: true, height: @getClientHeight() )
-                _.defer @toggleExpanded
-                return
-            @setState expanded: false, height: 30
-        else
-            @setState expanded: true, height: @getClientHeight()
-
-        _.delay( =>
-            if @isMounted()
-                @setState(icon: if @state.expanded then 'minus' else 'plus')
-        , @props.speed * 1000)
+        @setState(expanded: not @state.expanded)

     render: ->
         colProps = _.omit(@props, 'name')
         <BS.Col {...colProps}>
             <fieldset className={
                 _.classnames("collapsible", @props.className, @state.icon
-                {expanded: @state.expanded, collapsed: !@state.expanded})
-            }
-            style={
-                maxHeight: @state.height
-                transition: "max-height #{@props.speed}s ease-in-out";
+                    {expanded: @state.expanded, collapsed: !@state.expanded})
             }>
                 <legend onClick={@toggleExpanded}>
                     {@props.title}
                 </legend>
-

-                    {@props.children}
-

+                <BS.Collapse in={@state.expanded}>
+

+                        {@props.children}
+

+                </BS.Collapse>
             </fieldset>
         </BS.Col>


make same bug fix in live artist url

make same bug fix in live artist url

--- apps/artist/client/views/biography.coffee
+++ apps/artist/client/views/biography.coffee
@@ -7,9 +7,10 @@

   initialize: ->
     @model.related().articles.fetch
-      biography_for_artist_id: @model.get('_id')
       cache: true
-      data: limit: 50
+      data:
+        limit: 1
+        biography_for_artist_id: @model.get('_id')
       success: (@articles) => @render()

   render: ->


Add cmd-y for redo

Add cmd-y for redo

--- src/code/mixins/app-view.coffee
+++ src/code/mixins/app-view.coffee
@@ -78,7 +78,7 @@
       return if not (y or z)
       if e.metaKey
         undo = z and not e.shiftKey
-        redo = z and e.shiftKey
+        redo = (z and e.shiftKey) or y
       else if e.ctrlKey
         undo = z
         redo = y


Take the min of grav and spring force to get total force

--- js/particles.coffee
+++ js/particles.coffee
@@ -61,9 +61,10 @@
     dist_sq = Math.max(difference.mag_sq(), 25)

     velocity = @vel.mag()
-    g_force = 100000 * MOUSE.mass * @mass / dist_sq
+    g_force = 10000000 * MOUSE.mass * @mass / dist_sq
     spring_force = 10000 * Math.sqrt(dist_sq)
-    spring_and_g_force_vector = Vector.unit(difference).s_mult(spring_force + g_force)
+    spring_and_g_force_vector = Vector.unit(difference)
+      .s_mult(Math.min(spring_force, g_force))

     damp_force_vector = Vector.s_mult(@vel, -10)


Minor improvement

Minor improvement

--- src/cmd/which.coffee
+++ src/cmd/which.coffee
@@ -7,8 +7,7 @@
   """

 exports.cmd = ->
-  for z in locals()
-    if z.active
-      echo fs.BuildPath install2, z.path
-      return
+  for z in locals() when z.active
+    echo fs.BuildPath install2, z.path
+    return
   echo junction.link


Start incorporating inDocument tests into main test suite. (This could have been done ages ago, but since we're mucking about in the unit tests, this seems like a good time to do it.)

--- src/inDocument.coffee
+++ src/inDocument.coffee
@@ -38,7 +38,7 @@
     # Invoke callback immediately for controls already in document,
     # queue a callback for those which are not.
     callbacks = []
-    for element, i in @each
+    for element, i in @each()
       if isElementInDocument element
         callback.call @constructor element  # Element already in document
       else


docs(build option) compile.htmlImports.client.enable add todo comments

--- src/plugins/gulp-compile-html-imports.coffee
+++ src/plugins/gulp-compile-html-imports.coffee
@@ -14,6 +14,9 @@
 # ===================
 Regx =
 	htmlImports:
+		# TODO
+		# • exclude imports in comments
+		# • fix multiple imports on the same line
 		/\bimport\s+(?:(.+)\s+from\s+)?[\'"`]([^`"\']+\.html)[`"\'](?=\n|\s?;|\s(?!\S))(\s*;)?/g

 	htmlImport: (statement) ->


prompt for steroids update instead of npm install when node_modules not present

--- src/steroids/ApplicationConfigUpdater.coffee
+++ src/steroids/ApplicationConfigUpdater.coffee
@@ -455,7 +455,7 @@
         Directory #{chalk.bold("node_modules")} not found in project root. Steroid requires
         certain npm dependencies to work. Please run

-          #{chalk.bold("npm install")}
+          #{chalk.bold("steroids update")}

         in your project root now to install the required dependencies.


properly using style dropdown and falling back on input box if other value specified

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -300,10 +300,11 @@
       @$settings.form_id.find('input').val(@survey.settings.get('form_id'))
       @$settings.version.find('input').val(@survey.settings.get('version'))

-      _style_val = @survey.settings.get('style')
+      _style_val = @survey.settings.get('style') || ""

       if @$settings.style.find('select option')
           .filter(((i, opt)-> opt.value is _style_val)).length is 0
+        # user has specified a style other than the available styles
         _inp = $("<input>", {type: 'text'})
         @$settings.style.find('select').replaceWith(_inp)
         _inp.val(_style_val)


Update ranges tracker.

Update ranges tracker.

--- services/document-updater/app/coffee/RangesTracker.coffee
+++ services/document-updater/app/coffee/RangesTracker.coffee
@@ -95,6 +95,20 @@
 					change = c
 					break
 			return change
+
+		getChanges: (change_ids) ->
+			changes_response = []
+			ids_map = {}
+
+			for change_id in change_ids
+				ids_map[change_id] = true
+
+			for change in @changes
+				if ids_map[change.id]
+					delete ids_map[change.id]
+					changes_response.push change
+
+			return changes_response

 		removeChangeId: (change_id) ->
 			change = @getChange(change_id)


Update range tracker.

Update range tracker.

--- services/document-updater/app/coffee/RangesTracker.coffee
+++ services/document-updater/app/coffee/RangesTracker.coffee
@@ -108,13 +108,16 @@
 			for change_id in change_to_remove_ids
 				remove_change_id[change_id] = true

-			while (i--)
-				if remove_change_id[@changes[i].id]
-					delete remove_change_id[@changes[i].id]
-					removed_change = @changes.splice(i, 1)[0]
-					@_markAsDirty removed_change, "change", "removed"
-					if Object.keys(remove_change_id).length == 0
-						break
+			remaining_changes = []
+
+			for change in @changes
+				if remove_change_id[change.id]
+					delete remove_change_id[change.id]
+					@_markAsDirty change, "change", "removed"
+				else
+					remaining_changes.push change
+
+			@changes = remaining_changes

 		validate: (text) ->
 			for change in @changes


remove old unused ioredis keepalive option

--- services/document-updater/config/settings.defaults.coffee
+++ services/document-updater/config/settings.defaults.coffee
@@ -44,8 +44,6 @@
 			key_schema:
 				projectHistoryOps: ({project_id}) -> "ProjectHistory:Ops:{#{project_id}}"
 				projectHistoryFirstOpTimestamp: ({project_id}) -> "ProjectHistory:FirstOpTimestamp:{#{project_id}}"
-			redisOptions:
-				keepAlive: 100

 		lock:
 			port: process.env["LOCK_REDIS_PORT"] or process.env["REDIS_PORT"] or "6379"


Fix grammatical error in comment

Fix grammatical error in comment

--- test/gyp.coffee
+++ test/gyp.coffee
@@ -8,7 +8,7 @@
 gruntFailStub.warn = gruntFailStub.fatal = (e, errcode) ->
 	gruntError = e

-# Silent some Grunt output.
+# Silence some Grunt output.
 gruntLogStub = {}
 gruntLogStub.header = ->
 gruntLogStub.writeln = -> return { success: -> }


S64703: Tweaking tests to work with grid as default view.

--- test/spec/iterationtrackingboard/IterationTrackingBoardAppSpec.coffee
+++ test/spec/iterationtrackingboard/IterationTrackingBoardAppSpec.coffee
@@ -69,6 +69,9 @@
       stub

   beforeEach ->
+    @defaultToggleState = Rally.ui.gridboard.GridBoard.prototype.toggleState
+    Rally.ui.gridboard.GridBoard.prototype.toggleState = 'board' # tests assume board is default view
+
     @ajax.whenReading('project').respondWith {
       TeamMembers: []
       Editors: []
@@ -80,6 +83,7 @@

   afterEach ->
     @app?.destroy()
+    Rally.ui.gridboard.GridBoard.prototype.toggleState = @defaultToggleState

   it 'resets view on scope change', ->
     @createApp().then =>


:bug: Fix broken plugin since highlight-selected update

Fixes #5

--- lib/minimap-highlight-selected-view.coffee
+++ lib/minimap-highlight-selected-view.coffee
@@ -11,7 +11,7 @@

     getActiveTextEditor: -> @getActiveMinimap()?.getTextEditor()

-    ['markBufferRange', 'scanInBufferRange', 'getEofBufferPosition', 'getSelections', 'getLastSelection', 'bufferRangeForBufferRow', 'getTextInBufferRange'].forEach (key) ->
+    ['markBufferRange', 'scanInBufferRange', 'getEofBufferPosition', 'getSelections', 'getLastSelection', 'bufferRangeForBufferRow', 'getTextInBufferRange', 'onDidChangeSelectionRange'].forEach (key) ->
       FakeEditor::[key] = -> @getActiveTextEditor()[key](arguments...)

     ['decorateMarker'].forEach (key) ->
@@ -19,8 +19,8 @@

   class MinimapHighlightSelectedView extends HighlightedAreaView
     constructor: (minimap) ->
+      @fakeEditor = new FakeEditor(minimap)
       super
-      @fakeEditor = new FakeEditor(minimap)

     getActiveEditor: -> @fakeEditor


Forward up.fragment.config.mainTargets with up.util.delegate()

--- lib/assets/javascripts/unpoly/fragment.coffee
+++ lib/assets/javascripts/unpoly/fragment.coffee
@@ -118,10 +118,7 @@

   # Users who are not using layers will prefer settings default targets
   # as up.fragment.config.mainTargets instead of up.layer.config.any.mainTargets.
-  Object.defineProperty(config, 'mainTargets'
-    get: -> up.layer.config.any.mainTargets
-    set: (value) -> up.layer.config.any.mainTargets = value
-  )
+  u.delegate config, 'mainTargets', -> up.layer.config.any

   reset = ->
     config.reset()


Prevent parse message urls if option parseUrls is false in message

--- packages/rocketchat-lib/server/functions/sendMessage.coffee
+++ packages/rocketchat-lib/server/functions/sendMessage.coffee
@@ -10,8 +10,9 @@

 	message.rid = room._id

-	if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g
-		message.urls = urls.map (url) -> url: url
+	if not message.parseUrls is false
+		if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]+)?\??([-\+=&!:;%@\/\.\,\w]+)?#?([\w]+)?)?/g
+			message.urls = urls.map (url) -> url: url

 	message = RocketChat.callbacks.run 'beforeSaveMessage', message


Filled out additional missing types for testing expression equality

--- javascripts/lib/math/expression_equality.coffee
+++ javascripts/lib/math/expression_equality.coffee
@@ -25,6 +25,35 @@
       logger.instrument(name: "buildIsEqual function", fn: isEqualFunction)

+    # Addition
+    ref.forType(comps.addition, {
+      isEqual: (buildIsEqual(comps.addition))
+      })
+
+
+    # Blank
+    ref.forType(comps.blank, {
+      isEqual: (buildIsEqual(comps.blank))
+      })
+
+
+    # Division
+    ref.forType(comps.division, {
+      isEqual: (buildIsEqual(comps.division))
+      })
+
+
+
+    # Exponentiation
+    ref.forType(comps.exponentiation, {
+      isEqual: (buildIsEqual(comps.exponentiation)),
+      _simpleIsEqual: (other)->
+        ref.refine(@base()).isEqual(other.base()) and
+          ref.refine(@power()).isEqual(other.power())
+      })
+
+
+    # Expression
     ref.forType(comps.expression, {
       isExpressionEqual: (other)->
         logger.info("isExpressionEqual", @unrefined(), other)
@@ -45,6 +74,15 @@
           @isExpressionEqual(other)
     })

+
+
+    # Multiplication
+    ref.forType(comps.multiplication, {
+      isEqual: (buildIsEqual(comps.multiplication))
+      })
+
+
+    # Number
     ref.forType(comps.number, {
       isEqual: (buildIsEqual(comps.number)),
       _simpleIsEqual: (other)->
@@ -79,7 +117,15 @@
     ref.forDefault({
       isEqual: -> console.log(@); throw "NOT IMPLEMENTED"
     })
+    # Number
+    ref.forType(comps.pi, {
+      isEqual: (buildIsEqual(comps.pi))
+    })

+    # Subtraction
+    ref.forType(comps.subtraction, {
+      isEqual: (buildIsEqual(comps.subtraction))
+    })

     class ExpressionEquality
       initialize: (@first)->


don’t update workflows listing in show action

--- lib/gush/control/assets/javascripts/gush.coffee
+++ lib/gush/control/assets/javascripts/gush.coffee
@@ -25,7 +25,7 @@
         $("table.nodes tbody").append(job.render())

   registerWorkersSocket: ->
-    workersSocket = new EventSource("/subscribe/workers.status");
+    workersSocket = new EventSource("/subscribe/workers.status")

     workersSocket.onopen    = @_onOpen
     workersSocket.onerror   = @_onError
@@ -33,7 +33,7 @@
     workersSocket.onclose   = @_onClose

   registerWorkflowsSocket: ->
-    workflowsSocket = new EventSource("/subscribe/workflows.status");
+    workflowsSocket = new EventSource("/subscribe/workflows.status")

     workflowsSocket.onopen    = @_onOpen
     workflowsSocket.onerror   = @_onError
@@ -106,10 +106,10 @@
   _onWorkflowStatusChange: (message) =>
     message = JSON.parse(message.data)
     workflow = @workflows[message.workflow_id]
-
-    workflow.changeStatus(message.status)
-    workflow.updateDates(message)
-    $("table.workflows").find("##{message.workflow_id}").replaceWith(workflow.render())
+    if workflow
+      workflow.changeStatus(message.status)
+      workflow.updateDates(message)
+      $("table.workflows").find("##{message.workflow_id}").replaceWith(workflow.render())

   _onMachineStatusMessage: (message) =>
       message = JSON.parse(message.data)


fix broken test

fix broken test

--- Src/coffeescript/cql-execution/test/util/comparison.coffee
+++ Src/coffeescript/cql-execution/test/util/comparison.coffee
@@ -115,7 +115,7 @@
     equivalent('123', new Code('123', 'test', '2016')).should.be.false()

   it 'should consider codes with different versions to be equivalent', ->
-    equivalent(new Code('1234', 'System', '2016', 'Display Name'), new Code('1234', 'First Code System', '2017', undefined)).should.be.true()
+    equivalent(new Code('1234', 'System', '2016', 'Display Name'), new Code('1234', 'System', '2017', undefined)).should.be.true()

   it 'should detect equivalency between code and list of codes', ->
     equivalent(new Code('1234', 'System', 'version2017', 'Display Name'), [new Code('1234', 'System', 'version2017', undefined), new Code('1', '2', '3', undefined)]).should.be.true()


sidebar/flux: apply correct visibility filter to stacks

--- client/app/lib/flux/sidebar/getters.coffee
+++ client/app/lib/flux/sidebar/getters.coffee
@@ -18,7 +18,10 @@
     stackFilters = filters.get 'stack'

     stacks
-      .filter (stack) -> not stackFilters.has stack.get 'baseStackId'
+      .filter (stack) ->
+        if stackFilter = stackFilters.get id = stack.get 'baseStackId'
+          # check for id is for backwards compatibility. ~Umut
+          return stackFilter in ['visible', id]
       .map (stack) ->
         templateTitle = templates.getIn [stack.get('baseStackId'), 'title']
         stack = stack.set 'title', _.unescape templateTitle  if templateTitle


pricing: update team plan resource quotas

--- client/landing/Intro/views/teamplan.coffee
+++ client/landing/Intro/views/teamplan.coffee
@@ -13,14 +13,6 @@

     @resourcePackSlider = new IntroPlanSelection
       title             : "Resource Pack"
-      description       : """
-        1 Resource pack contains
-
4xCPU
-        2xGB RAM
-        50GB Disk
-
10xTotal VMs
-        1xAlways on VMs
-        """
       unitPrice         : unitPrices.resourcePack
       amountSuffix      : "x"
       slider            :
@@ -64,11 +56,11 @@
     @updateContent()

   resourcePackUnits =
-    cpu             : 1
-    ram             : 1
-    disk            : 50
-    totalVMs        : 10
+    cpu             : 2
+    ram             : 2
+    disk            : 10
     alwaysOn        : 1
+    totalVMs        : 2

   updateContent: ->
     @total = (@resourceQuantity * unitPrices.resourcePack) + (@userQuantity * unitPrices.user)


Fix containment

Fix containment

--- client/templates/meeting/meeting.js.coffee
+++ client/templates/meeting/meeting.js.coffee
@@ -15,6 +15,7 @@
     delay: 75
     distance: 4
     handle: ".sortable-handle"
+    containment: "parent"
     cursor: "move"
     tolerance: "pointer"
     forceHelperSize: true


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -226,6 +226,7 @@
             y: target.y + yw
             xw: xw
             yw: yw
+          )
         else
           error "Bounds object isn't a rectangle"


Removed not needed item.

Removed not needed item.

--- app/assets/javascripts/app/controllers/_default_navbar.coffee
+++ app/assets/javascripts/app/controllers/_default_navbar.coffee
@@ -12,9 +12,7 @@
 }, 'NavBarRight' )

 App.Config.set( 'Admin', { prio: 9000, parent: '', name: 'Admin', translate: true, target: '#manage', icon: 'cog', role: ['Admin'] }, 'NavBarRight' )
-#App.Config.set( 'Reporting', { prio: 8000, parent: '', name: 'Reporing', translate: true, target: '#report', icon: 'report', role: ['Admin'] }, 'NavBarRight' )
 App.Config.set( 'New', { prio: 20000, parent: '', name: 'New', translate: true, target: '#new', class: 'add' }, 'NavBarRight' )
-
 App.Config.set( 'Misc', { prio: 90000, parent: '', name: 'Tools', translate: true, target: '#tools', child: true, class: 'tools' }, 'NavBar' )
 # only for testing
 #App.Config.set( 'Misc1', { prio: 1600, parent: '#tools', name: 'Test 1', target: '#test1', role: [ 'Admin' ] }, 'NavBar' )


cleanup

cleanup

--- app/assets/javascripts/states/main/views/nav_search.js.coffee
+++ app/assets/javascripts/states/main/views/nav_search.js.coffee
@@ -5,16 +5,14 @@
     reuse: true
     template: "main/nav_search"

-    app_events: {
+    app_events:
       "search:set_query": (query) ->
         @set_query(query)

       "before:transition": ->
         @set_query("")

-    }
-
-    events: {
+    events:
       "submit form": (e) ->
         e.preventDefault()
         @set_query($("form input").val())
@@ -23,8 +21,6 @@
         else
           @transition "inventory"

-    }
-
     set_query: (q) ->
       @query = q
       $("div.navbar form.navbar-search input").val(q)


Adds async and fb version madness

Adds async and fb version madness

--- api/apps/articles/model/save.coffee
+++ api/apps/articles/model/save.coffee
@@ -13,7 +13,6 @@
 url = require 'url'
 Q = require 'bluebird-q'
 request = require 'superagent'
-requestBluebird = require 'superagent-bluebird-promise'
 Backbone = require 'backbone'
 { Image } = require 'artsy-backbone-mixins'
 debug = require('debug') 'api'
@@ -252,12 +251,17 @@
     full: url: crop(imageSrc, { width: 1200, height: 706 } )
     thumb: url: crop(imageSrc, { width: 900, height: 530 } )
   cleanArticlesInSailthru article.slugs
-  postFacebookAPI article
-  # postSailthruAPI article, tags, images, ->
-  #   console.log 'made the api callback'
-  cb()
-
-postFacebookAPI = (article) ->
+  async.parallel [
+    (callback) ->
+      postFacebookAPI article, callback
+    (callback) ->
+      postSailthruAPI article, tags, images, callback
+  ], (err, results) ->
+    console.log results
+    console.log err
+    cb()
+
+postFacebookAPI = (article, cb) ->
   html = "

 <meta charset=\"utf-8\">
@@ -312,14 +316,15 @@

 "
-  requestBluebird
-    .post "https://graph.facebook.com/#{FB_PAGE_ID}/instant_articles"
+  request
+    .post "https://graph.facebook.com/v2.7/#{FB_PAGE_ID}/instant_articles"
     .send
       access_token: INSTANT_ARTICLE_ACCESS_TOKEN
       development_mode: true
       html_source: html
     .end (err, response) =>
       console.log response
+      cb()

 postSailthruAPI = (article, tags, images, cbAPI) ->
   html = if article.send_body then getTextSections(article) else ''
@@ -342,7 +347,6 @@
     debug err if err
     cbAPI()

-
 cleanArticlesInSailthru = (slugs = []) =>
   if slugs.length > 1
     slugs.forEach (slug, i) =>


Remove unnecessary url

Remove unnecessary url

--- app/coffee/modules/resources.coffee
+++ app/coffee/modules/resources.coffee
@@ -69,7 +69,6 @@
     "users-change-password-from-recovery": "/api/v1/users/change_password_from_recovery"
     "users-change-password": "/api/v1/users/change_password"
     "resolver": "/api/v1/resolver"
-    "wiki-attachment": "/media/attachment-files/%s/wikipage/%s"
     "userstory-statuses": "/api/v1/userstory-statuses"
     "points": "/api/v1/points"
     "task-statuses": "/api/v1/task-statuses"


:penguin: Add commands for ctrl-home and ctrl-end.

--- keymaps/linux.cson
+++ keymaps/linux.cson
@@ -67,6 +67,8 @@
   'ctrl-shift-right': 'editor:select-to-end-of-word'
   'ctrl-backspace': 'editor:backspace-to-beginning-of-word'
   'ctrl-delete': 'editor:delete-to-end-of-word'
+  'ctrl-home': 'core:move-to-top'
+  'ctrl-end': 'core:move-to-bottom'

   # Sublime Parity
   'ctrl-a': 'core:select-all'


KDFormView: code style

KDFormView: code style

I think that #getElement is more readable than #$()[0] :)

--- components/forms/KDFormView.coffee
+++ components/forms/KDFormView.coffee
@@ -83,7 +83,7 @@

   getCallback:-> @formCallback

-  reset:-> @$()[0].reset()
+  reset:-> @getElement().reset()

   submit:(event)->


Add direct messaging functionality

Add direct messaging functionality

--- src/matteruser.coffee
+++ src/matteruser.coffee
@@ -61,6 +61,8 @@
             real_name: "#{user.first_name} #{user.last_name}"
             email_address: user.email
             mm: {}
+        # Preserve the DM channel ID if it exists
+        newUser.mm.dm_channel_id = @robot.brain.userForId(user.id).mm?.dm_channel_id
         for key, value of user
             newUser.mm[key] = value
         if user.id of @robot.brain.data.users
@@ -89,6 +91,39 @@

     send: (envelope, strings...) ->
         @client.postMessage(str, envelope.room) for str in strings
+        # Check if the target room is also a user's username
+        user = @robot.brain.userForName(envelope.room)
+
+        # If it's not, continue as normal
+        unless user
+            @client.postMessage(str, envelope.room) for str in strings
+            return
+
+        # If it is, we assume they want to DM that user
+        # Message their DM channel ID if it already exists.
+        if user.mm?.dm_channel_id?
+            @client.postMessage(str, user.mm.dm_channel_id) for str in strings
+            return
+
+        # Otherwise, create a new DM channel ID and message it.
+        @client.getUserDirectMessageChannel user.id, (data) =>
+
+          # If there's no error, store the DM channel ID and send the message
+          unless data.error
+              user.mm.dm_channel_id = data.id
+              @client.postMessage(str, data.id) for str in strings
+              return
+
+          # Mattermost's API returns a 500 error if a DM channel already exists
+          # We can look through all the channels and find the one that only
+          # contains us and the target user and has a total of 2 members
+          for channel, details of @client.getAllChannels()
+              @client.getChannelInfo channel, 2, (info) =>
+                  return if info.member_count is not 2
+                  for member in info.members
+                      if member.username is envelope.room
+                          user.mm.dm_channel_id = info.id
+                          @client.postMessage(str, info.id) for str in strings

     reply: (envelope, strings...) ->
         @robot.logger.debug "Reply"
@@ -109,7 +144,9 @@
         user.room = msg.channel_id

         text = mmPost.message
-        text = "#{@robot.name} #{text}" if msg.props.channel_type == 'D' and !///^#{@robot.name} ///i.test(text) # Direct message
+        if msg.props.channel_type == 'D' and !///^#{@robot.name} ///i.test(text) # Direct message
+          text = "#{@robot.name} #{text}"
+          user.mm.dm_channel_id = msg.channel_id

         @receive new TextMessage user, text, msg.id
         @robot.logger.debug "Message sent to hubot brain."


refactor(middleware): Use recommended es6-promise polyfill method

--- src/middleware.coffee
+++ src/middleware.coffee
@@ -1,5 +1,5 @@
 async = require 'async'
-Promise = global.Promise || require('es6-promise').Promise
+require('es6-promise').polyfill()

 class Middleware
   # We use this recursively, and using nextTick recursively is deprecated in node 0.10.


replace 'fieldhints' with 'selector'

replace 'fieldhints' with 'selector'

--- src/mkts-table.coffee
+++ src/mkts-table.coffee
@@ -188,12 +188,12 @@
 @fieldalignvertical = ( me, text ) ->
   unless ( match = text.match /^(.+?):([^:]+)$/ )?
     throw new Error "(MKTS/TABLE µ5229) expected something like 'C3:top' for mkts-table/fieldalignvertical, got #{rpr text}"
-  [ _, fieldhints, value, ] = match
+  [ _, selector, value, ] = match
   #.........................................................................................................
   unless value in [ 'top', 'bottom', 'center', 'spread', ]
     throw new Error "(MKTS/TABLE µ1876) expected one of 'top', 'bottom', 'center', 'spread' for mkts-table/fieldalignvertical, got #{rpr value}"
   #.........................................................................................................
-  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, fieldhints
+  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, selector
     ### TAINT ad-hoc fail message production, use method ###
     if fail? then _record me, "#{fail} (#{jr {field_designation}})"
     else          me.valigns[ field_designation ] = value
@@ -204,12 +204,12 @@
 @fieldalignhorizontal = ( me, text ) ->
   unless ( match = text.match /^(.+?):([^:]+)$/ )?
     throw new Error "(MKTS/TABLE µ5229) expected something like 'C3:left' for mkts-table/fieldalignhorizontal, got #{rpr text}"
-  [ _, fieldhints, value, ] = match
+  [ _, selector, value, ] = match
   #.........................................................................................................
   unless value in [ 'left', 'right', 'center', 'justified', ]
     throw new Error "(MKTS/TABLE µ1876) expected one of 'left', 'right', 'center', 'justified' for mkts-table/fieldalignhorizontal, got #{rpr value}"
   #.........................................................................................................
-  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, fieldhints
+  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, selector
     ### TAINT ad-hoc fail message production, use method ###
     if fail? then _record me, "#{fail} (#{jr {field_designation}})"
     else          me.haligns[ field_designation ] = value
@@ -285,13 +285,13 @@
     throw new Error "(MKTS/TABLE µ1225) expected a text for fieldborder, got a #{rpr type}"
   unless ( groups = fieldborder.match /^(.+):(.+):(.*)$/ )?
     throw new Error "(MKTS/TABLE µ2582) expected a fieldborder like 'a1:left:sDashed,sThick', got #{rpr fieldborder}"
-  [ _, fieldhints, edges, style, ] = groups
+  [ _, selector, edges, style, ] = groups
   #.........................................................................................................
   edges       = ( _.trim() for _ in edges.split ',' )
   edges       = [ 'top', 'left', 'bottom', 'right', ] if '*' in edges
   fieldnames  = []
   #.........................................................................................................
-  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, fieldhints
+  for [ fail, field_designation, ] from @_walk_fails_and_field_designations_from_selector me, selector
     ### TAINT ad-hoc fail message production, use method ###
     if fail? then _record me, "#{fail} (#{jr {field_designation}})"
     else          fieldnames.push field_designation


Bug fix in VMs selection.

Bug fix in VMs selection.

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -137,8 +137,8 @@
         unless angular.isFunction fn
           throw new Error "invalid action #{action}"

-        for UUID of selected_VMs
-          fn UUID
+        for UUID, selected of selected_VMs
+          fn UUID if selected

         # Unselects all VMs.
         $scope.selectVMs false


webapp: changing switch time for welcome-to-kucalc banner to expected time

--- src/smc-webapp/redux_account.coffee
+++ src/smc-webapp/redux_account.coffee
@@ -266,7 +266,7 @@
         if not sgi2?           # not set means there is no timestamp → show banner
             return true
         sgi2_dt = new Date(sgi2)
-        start_dt = new Date('2017-08-26T13:00:00.000Z')
+        start_dt = new Date('2017-08-25T19:00:00.000Z')
         return start_dt < webapp_client.server_time() and sgi2_dt < start_dt

 # Register account store


erasing pixels works once more

erasing pixels works once more

--- web-editor/app.coffee
+++ web-editor/app.coffee
@@ -153,7 +153,7 @@
     # the element as "e03" for row 0, column 3
     [ row, column] = @coordinates_from  event
     # The brush should be the opposite of the pixel currently underneath the cursor
-    brush = 1 - character_set.selected_character().pixel_at( row, column)
+    @brush = 1 - character_set.selected_character().pixel_at( row, column)
     # If the pixel is cleared ( transparent, background color) then go in to
     # "set" mode for setting pixels until the mouse button is released
     $('#editor').find('td').on 'mousemove', @when_dragged


remove hellobar message method

remove hellobar message method

--- server/methods.coffee
+++ server/methods.coffee
@@ -34,7 +34,6 @@
   startApp: Cluster.startApp
   stopInstance: Cluster.stopInstance
   clearInstance: Cluster.clearInstance
-  setHellobarMessage: Cluster.setHellobarMessage
   saveApp: Cluster.saveApp
   deleteApp: Cluster.deleteApp


react native 0.17.0

react native 0.17.0

--- natal.coffee
+++ natal.coffee
@@ -24,7 +24,7 @@
 camelRx         = /([a-z])([A-Z])/g
 projNameRx      = /\$PROJECT_NAME\$/g
 projNameHyphRx  = /\$PROJECT_NAME_HYPHENATED\$/g
-rnVersion       = '0.14.2'
+rnVersion       = '0.17.0'
 rnPackagerPort  = 8081
 podMinVersion   = '0.38.2'
 process.title   = 'natal'


 properly encapsulate attrib names within double quotes. fixes peilli… (#44)

*  properly encapsulate attrib names within double quotes. fixes peillis/helpapp#4560

*  comment

--- src/widgets/facets/termfacet.coffee
+++ src/widgets/facets/termfacet.coffee
@@ -55,7 +55,8 @@
       self.selected = {}

     # The filtering by click
-    @element.on 'click', "a[data-facet='#{@name}']", (e) ->
+    # attr name within " in case a ' is inside
+    @element.on 'click', "a[data-facet=\"#{@name}\"]", (e) ->
       e.preventDefault()

       value = $(this).data 'value'


VMSettings: General: Hide on/off toggle for managed machines.

--- client/app/lib/providers/machinesettingsgeneralview.coffee
+++ client/app/lib/providers/machinesettingsgeneralview.coffee
@@ -136,6 +136,7 @@
       cssClass          : 'AppModal-form'
       fields            :
         statusToggle    :
+          cssClass      : if @machine.isManaged() then 'hidden'
           label         : 'On/Off'
           defaultValue  : running
           itemClass     : KodingSwitch


Credentials: on check only save newly selected credentials

--- client/new-stack-editor/lib/controllers/credentials.coffee
+++ client/new-stack-editor/lib/controllers/credentials.coffee
@@ -1,4 +1,7 @@
+debug = (require 'debug') 'nse:controller:credentials'
+
 kd = require 'kd'
+_ = require 'lodash'
 JView = require 'app/jview'
 Events = require '../events'
 BaseController = require './base'
@@ -37,15 +40,14 @@
   check: (callback) ->

     stackTemplate = @getData()
-    credentials = Object.keys(stackTemplate.credentials).filter (provider) ->
-      provider isnt 'custom'
+    selectedCredentials = @getSelectedCredentials()
+    templateCredentials = stackTemplate.getCredentialProviders()

-    if credentials.length is 0
-      if Object.keys(selectedCredentials = @getSelectedCredentials()).length
-        @handleSaveChanges selectedCredentials, callback
-      else
-        @emit Events.WarnAboutMissingCredentials
-        callback { error: 'Missing Credentials' }
+    if @isSelectionChanged() and _.size selectedCredentials
+      @handleSaveChanges selectedCredentials, callback
+    else if templateCredentials.length is 0
+      @emit Events.WarnAboutMissingCredentials
+      callback { error: 'Missing Credentials' }
     else
       callback null


event: allow app string to contain hyphens

--- schemas.coffee
+++ schemas.coffee
@@ -31,7 +31,7 @@
 event =
   # LEGACY START
   # This should not be optional
-  app: Joi.string().min(1).max(100).token().optional()
+  app: Joi.string().min(1).max(100).regex(/^[\w\-]+$/).optional()
   # LEGACY END
   inviterId: id.optional()
   event: Joi.string().min(1).max(100).token() # Arbitrary min and max


Grid spacing properties changed

Grid spacing properties changed

--- item/types/grid.coffee
+++ item/types/grid.coffee
@@ -3,36 +3,51 @@
 expect = require 'expect'
 utils = require 'utils'

-module.exports = (Scope, Impl) -> class Grid extends Scope.Item
-	@__name__ = 'Grid'
+module.exports = (Scope, Impl) ->
+	self = null

-	utils.defProp @::, 'columns', 'e', ->
-		Impl.getGridColumns @_globalId
-	, (val) ->
-		expect(val).toBe.greaterThan 0
-		Impl.setGridColumns @_globalId, val
+	Spacing = Object.create null

-	utils.defProp @::, 'rows', 'e', ->
-		Impl.getGridRows @_globalId
-	, (val) ->
-		expect(val).toBe.greaterThan 0
-		Impl.setGridRows @_globalId, val
-
-	utils.defProp @::, 'columnSpacing', 'e', ->
-		Impl.getGridColumnSpacing @_globalId
+	utils.defProp Spacing, 'column', 'e', ->
+		Impl.getGridColumnSpacing self._globalId
 	, (val) ->
 		expect(val).toBe.float()
-		Impl.setGridColumnSpacing @_globalId, val
+		Impl.setGridColumnSpacing self._globalId, val

-	utils.defProp @::, 'rowSpacing', 'e', ->
-		Impl.getGridRowSpacing @_globalId
+	utils.defProp Spacing, 'row', 'e', ->
+		Impl.getGridRowSpacing self._globalId
 	, (val) ->
 		expect(val).toBe.float()
-		Impl.setGridRowSpacing @_globalId, val
+		Impl.setGridRowSpacing self._globalId, val

-	utils.defProp @::, 'spacing', 'e', ->
-		(@columnSpacing + @rowSpacing) / 2
-	, (val) ->
-		expect(val).toBe.float()
-		@columnSpacing = val
-		@rowSpacing = val+	Spacing.valueOf = ->
+		(@column + @row) / 2
+
+	Object.freeze Spacing
+
+	class Grid extends Scope.Item
+		@__name__ = 'Grid'
+
+		utils.defProp @::, 'columns', 'e', ->
+			Impl.getGridColumns @_globalId
+		, (val) ->
+			expect(val).toBe.greaterThan 0
+			Impl.setGridColumns @_globalId, val
+
+		utils.defProp @::, 'rows', 'e', ->
+			Impl.getGridRows @_globalId
+		, (val) ->
+			expect(val).toBe.greaterThan 0
+			Impl.setGridRows @_globalId, val
+
+		utils.defProp @::, 'spacing', 'e', ->
+			self = @
+			Spacing
+		, (val) ->
+			self = @
+
+			if utils.isObject val
+				utils.merge Spacing, val
+			else
+				Spacing.column = val
+				Spacing.row = val


try helpers

try helpers

--- jasmine-harness.coffee
+++ jasmine-harness.coffee
@@ -6,11 +6,9 @@
 html = require './spec/lib/jasmine-html.js'
 tap = require './spec/lib/jasmine.tap_reporter.js'

-
-# helper = require('./spec/SpecHelper')
-# mock = require('./spec/Mock')
-# attach helper
-# attach mock
+# expose helpers
+attach require('./spec/SpecHelper')
+attach require('./spec/Mock')

 # insert test files here
 # require('./spec/BaconSpec')


Return the real owner_type

Return the real owner_type

--- components/inquiry_questionnaire/test/views/specialist.coffee
+++ components/inquiry_questionnaire/test/views/specialist.coffee
@@ -8,7 +8,7 @@

 describe 'Specialist', setup ->
   beforeEach ->
-    @representative = owner: fabricate 'profile', name: 'Foo Bar'
+    @representative = owner_type: 'Admin', owner: fabricate 'profile', name: 'Foo Bar'

     sinon.stub Backbone, 'sync'
       .onCall 0


Allow cmd and ctrl clicks to open links in new tabs

--- components/iframe_popover/index.coffee
+++ components/iframe_popover/index.coffee
@@ -10,6 +10,8 @@
   Backbone.history.start(pushState: true) unless Backbone.History.started

 onClick = (e) ->
+  return if e.metaKey or e.ctrlKey
+
   e.preventDefault()
   _.defer =>
     href = $(this).attr('href')


KDOnOffSwitch: stopDOMEvent on click by default

--- components/inputs/KDOnOffSwitch.coffee
+++ components/inputs/KDOnOffSwitch.coffee
@@ -58,6 +58,8 @@
     @emit 'SwitchStateChanged', @getValue()
     @getCallback().call @, @getValue() if @getCallback()?

+  click: KD.utils.stopDOMEvent
+
   mouseDown:(event)->
     if $(event.target).is('a.on')
       @setValue on


proxy jpg to blog backend

proxy jpg to blog backend

https://sentry.io/sharelatex-1/sl-web-server-prod/issues/212236471/

--- services/web/app/coffee/Features/Blog/BlogController.coffee
+++ services/web/app/coffee/Features/Blog/BlogController.coffee
@@ -10,7 +10,7 @@
 		url = req.url?.toLowerCase()
 		blogUrl = "#{settings.apis.blog.url}#{url}"

-		extensionsToProxy = [".png", ".xml", ".jpeg", ".json", ".zip", ".eps", ".gif"]
+		extensionsToProxy = [".png", ".xml", ".jpeg", ".jpeg", ".jpg", ".zip", ".eps", ".gif"]

 		shouldProxy = _.find extensionsToProxy, (extension)->
 			url.indexOf(extension) != -1


disable import-combine fleets

disable import-combine fleets

--- views/importTab.cjsx
+++ views/importTab.cjsx
@@ -88,22 +88,30 @@
     try
       importCode = JSON.parse importCode
       deck = {}
-      for fleets in importCode
-        continue if fleets is []
-        for ship in fleets
-          ship[0] = parseInt ship[0]
-          if ship.length is 4
-            ship.push []
-        if !checkData(fleets)
-          toggleModal __('Error'), __('Incorrect code.')
-        else
-          deck.ships = fleets
-          deck.details = []
-          for item in getDetails fleets
-            deck.details.push item
-          deck.comment = ''
-          deck.tags = ''
-          @props.handleAddData inputTitle, deck
+      flag = true
+      for fleets, index in importCode
+        continue if index is 0
+        if fleets isnt []
+          flag = false
+      if flag
+        for fleets in importCode
+          continue if fleets is []
+          for ship in fleets
+            ship[0] = parseInt ship[0]
+            if ship.length is 4
+              ship.push []
+          if !checkData(fleets)
+            toggleModal __('Error'), __('Incorrect code.')
+          else
+            deck.ships = fleets
+            deck.details = []
+            for item in getDetails fleets
+              deck.details.push item
+            deck.comment = ''
+            deck.tags = ''
+            @props.handleAddData inputTitle, deck
+      else
+        toggleModal __('Error'), '不支持联合舰队导入'
     catch e
       throw e
     @setState


Trigger events

Trigger events

--- source/app/organism/aside.coffee
+++ source/app/organism/aside.coffee
@@ -21,14 +21,16 @@
     super
     @el.bind Atoms.Core.Constants.ANIMATION.END, @_onAnimationEnd

-
   in: ->
     unless @el then @render()
     @el.addClass "active"
     @el.attr "data-state", "in"

   out: ->
-    @el?.removeClass "active"
+    if @el?.hasClass "active" then @el.attr "data-state", "out"

   _onAnimationEnd: (event) =>
     state = @el.attr "data-state"
+    @trigger state
+    @el.removeAttr "data-state"
+    @el.removeClass "active" if state is "out"


Optional trailing slash for landing

Optional trailing slash for landing

--- apps/pro_buyer/client/router.coffee
+++ apps/pro_buyer/client/router.coffee
@@ -6,7 +6,7 @@

 module.exports = class ProfessionalBuyerRouter extends Router
   routes:
-    'professional-buyer': 'landing'
+    'professional-buyer(/)': 'landing'
     'professional-buyer/complete': 'complete'

   initialize: ->


Changed the order of method declarations

--- src/DivSugar.coffee
+++ src/DivSugar.coffee
@@ -86,6 +86,12 @@

   generateId: -> "_divsugar_id_#{++@_id}"

+  getImageSize: (src, callback) ->
+    image = new Image()
+    image.src = src
+    image.onload = -> callback(image.width, image.height)
+    return @
+
   createScene: (args...) ->
     div = document.createElement 'div'

@@ -106,10 +112,4 @@

     return div

-  getImageSize: (src, callback) ->
-    image = new Image()
-    image.src = src
-    image.onload = -> callback(image.width, image.height)
-    return @
-
 (window.DivSugar = DivSugar)._initialize()


max_worker_processes and work_mem

max_worker_processes and work_mem

--- source/javascripts/pgtune.coffee
+++ source/javascripts/pgtune.coffee
@@ -202,7 +202,7 @@
     if @dbVersion >= 9.5
       cpuNum = parseInt($('#pgtCPUValue').val(), 10) || 1
       if cpuNum > 1
-        parallelForWorkMem = cpuNum
+        parallelForWorkMem = Math.ceil(cpuNum / 2)
         gConfig['max_worker_processes'] = cpuNum
         if @dbVersion >= 9.6
           gConfig['max_parallel_workers_per_gather'] = Math.ceil(cpuNum / 2)
@@ -210,8 +210,8 @@
           gConfig['max_parallel_workers'] = cpuNum

     # work_mem is assigned any time a query calls for a sort, or a hash, or any other structure that needs a space allocation, which can happen multiple times per query. So you're better off assuming max_connections * 2 or max_connections * 3 is the amount of RAM that will actually use in reality. At the very least, you need to subtract shared_buffers from the amount you're distributing to connections in work_mem.
-    # The other thing to consider is that there's no reason to run on the edge of available memory. If you do that, there's a very high risk the out-of-memory killer will come along and start killing PostgreSQL backends. Always leave a buffer of some kind in case of spikes in memory usage. So your maximum amount of memory available in work_mem should be ((RAM - shared_buffers) / 2 / (max_connections * 3 * max_worker_processes)).
-    workMem = (memoryInKB - gConfig['shared_buffers']) / (gConfig['max_connections'] * 3 * parallelForWorkMem) / 2
+    # The other thing to consider is that there's no reason to run on the edge of available memory. If you do that, there's a very high risk the out-of-memory killer will come along and start killing PostgreSQL backends. Always leave a buffer of some kind in case of spikes in memory usage. So your maximum amount of memory available in work_mem should be ((RAM - shared_buffers) / (max_connections * 3 ) / (max_worker_processes / 2) / 2).
+    workMem = (memoryInKB - gConfig['shared_buffers']) / (gConfig['max_connections'] * 3) / parallelForWorkMem / 2
     gConfig['work_mem'] = {
       web: Math.floor(workMem),
       oltp: Math.floor(workMem),


Boasting a bit :)

Boasting a bit :)

--- src/dahelpers.coffee
+++ src/dahelpers.coffee
@@ -7,8 +7,8 @@
 #
 # These are da helpers to help you out.
 #
-# Miscellaneous general-purpose helper methods for JavaScript in browsers and
-# on NodeJS.
+# A growing collection of miscellaneous general-purpose helper methods for
+# JavaScript in browsers and on NodeJS.
 #
 # ::TOC::
 #


Remove debug console.logs

Remove debug console.logs

--- assets/scripts/app/views/log.coffee
+++ assets/scripts/app/views/log.coffee
@@ -221,11 +221,6 @@
     logUrl: (->
       if item = @get('controller.currentItem')
         if repo = item.get('repo')
-
-          console.log item+''
-          console.log repo+''
-          console.log @get('controller')+''
-
           name = if item.constructor == Travis.Build
             'build'
           else


fix typo

fix typo

--- lib/command.coffee
+++ lib/command.coffee
@@ -50,4 +50,4 @@

     if program.tasks
       log.info "Available tasks:"
-      log.info "--". key for key, val of shakeConfig when typeof val is 'function'+      log.info "--", key for key, val of shakeConfig when typeof val is 'function'


put back @config.servers to match 98ec21baeb07eaf89d5b4856c62ea78d5bb1515f

--- lib/context.coffee
+++ lib/context.coffee
@@ -5,7 +5,7 @@

 class Context extends EventEmitter
   constructor: (contexts, @config)->
-    delete @config.servers
+    # delete @config.servers
     @_contexts = contexts
     options = {}
     # options.cache = true


Refactor focusFrame.

Refactor focusFrame.

Only the `flashFrame` part needs to be guarded against the DOM being
ready.  So we can take the `flashFrame` part out as a regular function.

Fixes #2023 (although I don't fully understand why that's happening).

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -269,9 +269,7 @@
         Marks.setPreviousPosition()
         window.scrollTo scrollX, scrollY

-#
-# Called from the backend in order to change frame focus.
-#
+flashFrame = ->
 DomUtils.documentReady ->
   # Create a shadow DOM wrapping the frame so the page's styles don't interfere with ours.
   highlightedFrameElement = DomUtils.createElement "div"
@@ -287,21 +285,24 @@
   _frameEl.className = "vimiumReset vimiumHighlightedFrame"
   _shadowDOM.appendChild _frameEl

-  window.focusThisFrame = (request) ->
-    if window.innerWidth < 3 or window.innerHeight < 3
-      # This frame is too small to focus. Cancel and tell the background frame to focus the next one instead.
-      # This affects sites like Google Inbox, which have many tiny iframes. See #1317.
-      # Here we're assuming that there is at least one frame large enough to focus.
-      chrome.runtime.sendMessage({ handler: "nextFrame", frameId: frameId })
-      return
-    window.focus()
-    shouldHighlight = request.highlight
-    shouldHighlight ||= request.highlightOnlyIfNotTop and not DomUtils.isTopFrame()
-    if shouldHighlight
-      document.documentElement.appendChild highlightedFrameElement
-      setTimeout (-> highlightedFrameElement.remove()), 200
-
-window.focusThisFrame = ->
+  flashFrame = ->
+    document.documentElement.appendChild highlightedFrameElement
+    setTimeout (-> highlightedFrameElement.remove()), 200
+
+#
+# Called from the backend in order to change frame focus.
+#
+focusThisFrame = (request) ->
+  if window.innerWidth < 3 or window.innerHeight < 3
+    # This frame is too small to focus. Cancel and tell the background frame to focus the next one instead.
+    # This affects sites like Google Inbox, which have many tiny iframes. See #1317.
+    # Here we're assuming that there is at least one frame large enough to focus.
+    chrome.runtime.sendMessage({ handler: "nextFrame", frameId: frameId })
+    return
+  window.focus()
+  shouldHighlight = request.highlight
+  shouldHighlight ||= request.highlightOnlyIfNotTop and not DomUtils.isTopFrame()
+  flashFrame() if shouldHighlight

 extend window,
   scrollToBottom: ->


Restoring 'Loading' flash to order cycle index

--- app/assets/javascripts/admin/resources/services/order_cycles.js.coffee
+++ app/assets/javascripts/admin/resources/services/order_cycles.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource, StatusMessage) ->
+angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource, RequestMonitor, StatusMessage) ->
   new class OrderCycles
     all: []
     byID: {}
@@ -8,11 +8,10 @@
       if $injector.has('orderCycles')
         @load($injector.get('orderCycles'))

-    index: (params={}, callback=null) ->
-      OrderCycleResource.index params, (data) =>
-        @load(data)
-        (callback || angular.noop)(data)
-        data
+    index: (params={}) ->
+      request = OrderCycleResource.index params, (data) => @load(data)
+      RequestMonitor.load(request.$promise)
+      request

     load: (orderCycles) ->
       for orderCycle in orderCycles when orderCycle.id not in Object.keys(@byID)


Switch frameboxes to thin outline

Switch frameboxes to thin outline


Do quote conversion *after* accent conversion

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -94,10 +94,6 @@
   .replace /\\end\s*{(problem|theorem|conjecture|lemma|corollary)}/g, '
'
   .replace /\\begin\s*{(proof|pf)}/g, 'Proof: '
   .replace /\\end\s*{(proof|pf)}/g, ' $\\Box$'
-  .replace /``/g, '“'
-  .replace /''/g, '”'
-  .replace /`/g, '‘'
-  .replace /'/g, '’'
   .replace /\\"{(.)}/g, '&$1uml;'
   .replace /\\"(.)/g, '&$1uml;'
   .replace /\\'{(.)}/g, '&$1acute;'
@@ -119,6 +115,11 @@
   .replace /\\u\s*{a}/g, 'ă'
   .replace /\\v\s*{a}/g, 'ǎ'
   .replace /\\H\s*{o}/g, 'ő'
+  .replace /``/g, '“'
+  .replace /''/g, '”'
+  #.replace /''|"/g, '”'  ## " replacement wreaks havoc with HTML
+  .replace /`/g, '‘'
+  .replace /'/g, '’'
   .replace /\\&/g, '&'
   .replace /\\([{}])/g, '$1'
   .replace /~/g, ' '
@@ -215,7 +216,7 @@
       .replace /&/g, '&'
       .replace /</g, '<'
       .replace />/g, '>'
-      "#{latex}"
+      """#{latex}"""
   if math?
     text.replace /MATH(\d+)ENDMATH/g, (match, p1) ->
       replacer math[p1]


Note about ` and '

Note about ` and '

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -88,6 +88,7 @@
   .replace /\\end\s*{(problem|theorem|conjecture|lemma|corollary)}/g, '</blockquote>'
   .replace /``/g, '“'
   .replace /''/g, '”'
+  ## This following break math mode currently...
   #.replace /`/g, '‘'
   #.replace /'/g, '’'
   .replace /\\"{(.)}/g, '&$1uml;'


braces = 0 when starting a $ block

braces = 0 when starting a $ block

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -20,17 +20,19 @@
     #console.log match
     switch match[0]
       when '$'
-        if start?
+        if start?  ## already in $ block
           if match.index > start+1  ## not opening $$
-            if braces == 0
+            if braces == 0  ## ignore $ nested within braces e.g. \text{$x$}
               blocks.push
                 start: start
                 end: match.index
               start = null
-        else
+        else  ## not in $ block
           if blocks.length > 0 and blocks[blocks.length-1].end+1 == match.index
+            ## second $ terminator
             blocks[blocks.length-1].end = match.index  ## closing $$
-          else
+          else  ## starting $ block
+            braces = 0
             start = match.index
       when '{'
         braces += 1


:bug: Make Helpers::parse sync

:bug: Make Helpers::parse sync

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -52,34 +52,33 @@
   # We place priority on `lineStart` and `lineEnd` over `line.`
   # We place priority on `colStart` and `colEnd` over `col.`
   parse: (data, rawRegex, options = {baseReduction: 1}) ->
-    new Promise (resolve) ->
-      toReturn = []
-      if xcache.has(rawRegex)
-        regex = xcache.get(rawRegex)
-      else
-        xcache.set(rawRegex, regex = XRegExp(rawRegex))
-      for line in data
-        match = XRegExp.exec(line, regex)
-        if match
-          options.baseReduction = 1 if not options.baseReduction
-          lineStart = 0
-          lineStart = match.line - options.baseReduction if match.line
-          lineStart = match.lineStart - options.baseReduction if match.lineStart
-          colStart = 0
-          colStart = match.col - options.baseReduction if match.col
-          colStart = match.colStart - options.baseReduction if match.colStart
-          lineEnd = 0
-          lineEnd = match.line - options.baseReduction if match.line
-          lineEnd = match.lineEnd - options.baseReduction if match.lineEnd
-          colEnd = 0
-          colEnd = match.col - options.baseReduction if match.col
-          colEnd = match.colEnd - options.baseReduction if match.colEnd
-          filePath = match.file
-          filePath = options.filePath if options.filePath
-          toReturn.push(
-            type: match.type,
-            text: match.message,
-            filePath: filePath,
-            range: [[lineStart, colStart], [lineEnd, colEnd]]
-          )
-      resolve(toReturn)
+    toReturn = []
+    if xcache.has(rawRegex)
+      regex = xcache.get(rawRegex)
+    else
+      xcache.set(rawRegex, regex = XRegExp(rawRegex))
+    for line in data
+      match = XRegExp.exec(line, regex)
+      if match
+        options.baseReduction = 1 if not options.baseReduction
+        lineStart = 0
+        lineStart = match.line - options.baseReduction if match.line
+        lineStart = match.lineStart - options.baseReduction if match.lineStart
+        colStart = 0
+        colStart = match.col - options.baseReduction if match.col
+        colStart = match.colStart - options.baseReduction if match.colStart
+        lineEnd = 0
+        lineEnd = match.line - options.baseReduction if match.line
+        lineEnd = match.lineEnd - options.baseReduction if match.lineEnd
+        colEnd = 0
+        colEnd = match.col - options.baseReduction if match.col
+        colEnd = match.colEnd - options.baseReduction if match.colEnd
+        filePath = match.file
+        filePath = options.filePath if options.filePath
+        toReturn.push(
+          type: match.type,
+          text: match.message,
+          filePath: filePath,
+          range: [[lineStart, colStart], [lineEnd, colEnd]]
+        )
+    return toReturn


Implement minimap creation observer method for v4

--- lib/main-v4.coffee
+++ lib/main-v4.coffee
@@ -30,6 +30,16 @@

   minimapForEditor: (editor) -> @editorsMinimaps[editor.id]

+  observeMinimaps: (iterator) ->
+    return unless iterator?
+    iterator({view: minimap}) for id,minimap of @editorsMinimaps
+    createdCallback = (minimap) -> iterator(minimap)
+    disposable = @onDidCreateMinimap(createdCallback)
+    disposable.off = ->
+      deprecate('Use Disposable::dispose instead')
+      disposable.dispose()
+    disposable
+
   initSubscriptions: ->
     Minimap ?= require './minimap'

@@ -40,4 +50,6 @@
       editorElement = atom.views.getView(textEditor)
       minimapElement = atom.views.getView(minimap)

+      @emitter.emit('did-create-minimap')
+
       minimapElement.attach()


Create command options naming uniformed. label, whitespace, style, dark.


Remove unused message data.

Remove unused message data.

The raw query is not used by this message handler, so don't send it.

--- pages/hud.coffee
+++ pages/hud.coffee
@@ -21,7 +21,6 @@

     UIComponentServer.postMessage
       name: "hideFindMode"
-      query: findMode.rawQuery
       exitEventIsEnter: event.keyCode == keyCodes.enter
       exitEventIsEscape: KeyboardUtils.isEscape event


activity: define `CommentListViewController::reply` method

--- client/Social/Activity/views/comments/commentlistviewcontroller.coffee
+++ client/Social/Activity/views/comments/commentlistviewcontroller.coffee
@@ -54,22 +54,6 @@
       @_removedBefore = no
       @fetchRelativeComments 10, meta.createdAt

-    listView.on "CommentSubmitted", (reply)->
-      model = listView.getData()
-      listView.emit "BackgroundActivityStarted"
-      model.reply reply, (err, reply)=>
-        # listView.emit "AllCommentsLinkWasClicked"
-        if not KD.getSingleton('activityController').flags?.liveUpdates
-          listView.addItem reply
-          listView.emit "OwnCommentHasArrived"
-        else
-          listView.emit "OwnCommentWasSubmitted"
-        listView.emit "BackgroundActivityFinished"
-
-      KD.mixpanel "Comment activity, success"
-      KD.getSingleton("badgeController").checkBadge
-        property : "comments", relType : "commenter", source : "JNewStatusUpdate", targetSelf : 1
-
   fetchCommentsByRange:(from,to,callback)->
     [to,callback] = [callback,to] unless callback
     query = {from,to}
@@ -112,3 +96,26 @@
   replaceAllComments:(comments)->
     @removeAllItems()
     @instantiateListItems comments
+
+
+  reply: (body, callback = noop) ->
+
+    listView = @getListView()
+    activity = listView.getData()
+
+    listView.emit "BackgroundActivityStarted"
+
+    KD.singleton("appManager").tell "Activity", "reply", {activity, body}, (err, reply) =>
+
+      return KD.showError err  if err
+
+      if not KD.getSingleton('activityController').flags?.liveUpdates
+        listView.addItem reply
+        listView.emit "OwnCommentHasArrived"
+      else
+        listView.emit "OwnCommentWasSubmitted"
+      listView.emit "BackgroundActivityFinished"
+
+    KD.mixpanel "Comment activity, success"
+    KD.getSingleton("badgeController").checkBadge
+      property: "comments", relType: "commenter", source: "JNewStatusUpdate", targetSelf: 1


code readability fix

code readability fix

--- client/landing/app/Applications/Ace.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Ace.kdapplication/AppController.coffee
@@ -1,8 +1,9 @@
 class AceAppController extends AppController

-  compileCondition = (view)->
-    ace = view.getActiveAceView()
-    KodingAppsController.getManifestFromPath ace.getData().path
+  canCompile = (view)->
+    ace      = view.getActiveAceView()
+    manifest = KodingAppsController.getManifestFromPath ace.getData().path
+    return if manifest then yes else no

   KD.registerAppClass this,
     name          : "Ace"


ace: Added "Open Recent" to app settings menu.

--- client/landing/app/Applications/Ace.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Ace.kdapplication/AppController.coffee
@@ -30,6 +30,14 @@
         title     : "Preview"
         eventName : "preview"
       }
+      {
+        type      : "separator"
+      }
+      {
+        title     : "Open Recent"
+        eventName : "recents"
+        closeMenuWhenClicked: no
+      }
     ]
     # mimeTypes    : "text"


Workspace: Fixed session not active state, it was broken by broadcasted messages.

--- client/landing/app/CommonViews/workspace/collaborativeworkspace.coffee
+++ client/landing/app/CommonViews/workspace/collaborativeworkspace.coffee
@@ -30,7 +30,7 @@
   bindRemoteEvents: ->
     @workspaceRef.once "value", (snapshot) =>
       if @getOptions().sessionKey
-        unless snapshot.val()
+        unless snapshot.val()?.keys
           @showNotActiveView()
           return false


card placeholder

card placeholder

--- mrfogg-front/app/coffee/controllers/main.coffee
+++ mrfogg-front/app/coffee/controllers/main.coffee
@@ -78,7 +78,6 @@
         classes = task.status
         if task.current
             classes = classes+" current"
-        console.log classes
         return classes

     $scope.taskToggleStatus = (task) ->
@@ -178,6 +177,7 @@

     onSuccess = (data) ->
         $scope.loadedCards = data._attrs
+        $scope.isCardPlaceHolderVisible = $scope.loadedCards.length == 0

     onError = (data) ->
         $rootScope.error = true


:art: Clean up SymbolProvider spec

:art: Clean up SymbolProvider spec

--- spec/symbol-provider-spec.coffee
+++ spec/symbol-provider-spec.coffee
@@ -144,35 +144,25 @@
       atom.config.set('autocomplete-plus.includeCompletionsFromAllBuffers', true)

       waitsForPromise ->
-        atom.packages.activatePackage("language-coffee-script").then ->
-          atom.workspace.open("sample.coffee").then (e) ->
-            editor = e
-
-      runs ->
-        provider = autocompleteManager.providerManager.fuzzyProvider
+        Promise.all [
+          atom.packages.activatePackage("language-coffee-script")
+          atom.workspace.open("sample.coffee").then (e) -> editor = e
+        ]
+
+      runs -> advanceClock 1

     afterEach ->
       atom.config.set('autocomplete-plus.includeCompletionsFromAllBuffers', false)

     it "outputs unique suggestions", ->
-      results = null
-      waitsForPromise ->
-        promise = provider.getSuggestions({editor, prefix: 'qu', bufferPosition: new Point(7, 0)})
-        advanceClock 1
-        promise.then (r) -> results = r
-
-      runs ->
-        expect(results).toHaveLength 1
+      editor.setCursorBufferPosition([7, 0])
+      results = suggestionsForPrefix(provider, editor, 'qu')
+      expect(results).toHaveLength 1

     it "outputs suggestions from the other buffer", ->
-      results = null
-      waitsForPromise ->
-        promise = provider.getSuggestions({editor, prefix: 'item', bufferPosition: new Point(7, 0)})
-        advanceClock 1
-        promise.then (r) -> results = r
-
-      runs ->
-        expect(results[0].text).toBe 'items'
+      editor.setCursorBufferPosition([7, 0])
+      results = suggestionsForPrefix(provider, editor, 'item')
+      expect(results[0]).toBe 'items'

   describe "when the completionConfig changes between scopes", ->
     beforeEach ->


make sure atom uses 'which' command to check for pros installation on unix systems -Alex

--- lib/proscli.coffee
+++ lib/proscli.coffee
@@ -79,7 +79,9 @@
       cb obj.code, mapResponse fmt, obj

     if cliVer != null and not force then respond cliVer
-    @execute cmd: ['where', 'pros'], nosb: nosb, cb: (c, o) =>
+    which = ['which', 'pros']
+    if navigator.platform is 'Win32' then which[0] = 'where'
+    @execute cmd: which, nosb: nosb, cb: (c, o) =>
       if c != 0
         # console.log o
         cliVer = {code: 2}


The database versionUpdate is now correct

So far, chrome was not supporting the onupgradeneeded event when opening
a database. In the new version of chrome (25) it seems to cause some
problem regarding the loading of the database.

We solve this issue by using the onupgradeneeded  event which is the
normalized way to update an indexedDB database.

--- src.coffee/storageManager.coffee
+++ src.coffee/storageManager.coffee
@@ -14,69 +14,66 @@
     @ready = false
     console.log "StorageManager ready"

-  openDB : () ->
+  openDB : () =>
     try
-      request = indexedDB.open @dbName
+      request = indexedDB.open @dbName, @version
       request.onsuccess = (event) =>
         @db = event.target.result
-        @checkVersion()
+        if parseInt(@version, 10) is parseInt(@db.version, 10)
+          console.log "data store ready. Version: #{@db.version}"
+          @SE.setDb @db
+          @ready = true
+          @executeQueue()
         return

       request.onfailure = @onerror
+
+      request.onupgradeneeded = (event) =>
+        @db = event.target.result
+        @updateVersion()
+
+
     catch error
       console.log error.message
       console.log "Error while initializing database manager"
     return

-  checkVersion : () ->
+  updateVersion : () =>
     try
-      if parseInt(@version, 10) isnt parseInt(@db.version, 10)
-        setVersionrequest = @db.setVersion @version
-        setVersionrequest.onfailure = @onerror
+      console.log "creating/updating database #{@dbName}"
+      if not @db.objectStoreNames.contains "temporary"
+        temporary = @db.createObjectStore "temporary", { keyPath: "pageId" }
+        temporary.createIndex("URL", "URL")
+        temporary.createIndex("timestamp", "timestamp")
+        #temporary.createIndex("j", "j", { unique: false, multiEntry: true })

-        setVersionrequest.onsuccess = (event) =>
-          console.log "creating/updating database #{@dbName}"
-          if not @db.objectStoreNames.contains "temporary"
-            temporary = @db.createObjectStore "temporary", { keyPath: "pageId" }
-            temporary.createIndex("URL", "URL")
-            temporary.createIndex("timestamp", "timestamp")
-            #temporary.createIndex("j", "j", { unique: false, multiEntry: true })
-
-          if not @db.objectStoreNames.contains "parameters"
-            parameters = @db.createObjectStore "parameters", { keyPath: "parameterId" }
-
-          if not @db.objectStoreNames.contains "labels"
-            labels = @db.createObjectStore "labels", { keyPath: "labelId", autoIncrement: true }
-            labels.put {labelText: "Home"}
-            labels.put {labelText: "Work"}
-            console.log "initialized location labels"
-
-          if not @db.objectStoreNames.contains "userStudySessions"
-            userStudySessions = @db.createObjectStore "userStudySessions", { keyPath: "userStudySessionId" }
-
-          if not @db.objectStoreNames.contains "userActions"
-            userActions = @db.createObjectStore "userActions", { keyPath: "userActionId" }
-            userActions.createIndex("_pageId", "_pageId")
-
-          if not @db.objectStoreNames.contains "screenshots"
-            screenshots = @db.createObjectStore "screenshots", { keyPath: "screenshotId" }
-            screenshots.createIndex("_pageId", "_pageId")
-
-          event.target.transaction.oncomplete = () =>
-            console.log "database created/updated and ready"
-            @SE.setDb @db
-            @ready = true
-            @executeQueue()
-            return
-
-          event.target.transaction.onerror = @onerror
-
-          return
-      else
-        console.log "data store ready"
-        @SE.setDb @db
-        @ready = true
-        @executeQueue()
+      if not @db.objectStoreNames.contains "parameters"
+        parameters = @db.createObjectStore "parameters", { keyPath: "parameterId" }
+
+      if not @db.objectStoreNames.contains "labels"
+        labels = @db.createObjectStore "labels", { keyPath: "labelId", autoIncrement: true }
+        labels.put {labelText: "Home"}
+        labels.put {labelText: "Work"}
+        console.log "initialized location labels"
+
+      if not @db.objectStoreNames.contains "userStudySessions"
+        userStudySessions = @db.createObjectStore "userStudySessions", { keyPath: "userStudySessionId" }
+
+      if not @db.objectStoreNames.contains "userActions"
+        userActions = @db.createObjectStore "userActions", { keyPath: "userActionId" }
+        userActions.createIndex("_pageId", "_pageId")
+
+      if not @db.objectStoreNames.contains "screenshots"
+        screenshots = @db.createObjectStore "screenshots", { keyPath: "screenshotId" }
+        screenshots.createIndex("_pageId", "_pageId")
+
+      event.target.transaction.oncomplete = () =>
+        console.log "database created/updated and ready"
+        return
+
+      event.target.transaction.onerror = @onerror
+
+      return
     catch error
       console.log error.message
       console.log "error while creating database"


Enable integration tests.

Enable integration tests.

--- src/spec/integration.spec.coffee
+++ src/spec/integration.spec.coffee
@@ -8,7 +8,7 @@

 jasmine.getEnv().defaultTimeoutInterval = 10000

-xdescribe 'integration tests', ->
+describe 'integration tests', ->

   CHANNEL_KEY = 'OrderXmlFileExport'
   CHANNEL_ROLE = 'OrderExport'


Optimize loadPath function

Optimize loadPath function

--- lib/session.coffee
+++ lib/session.coffee
@@ -77,10 +77,11 @@

 loadParameters = (sessionContext, callback) ->
-  if not sessionContext.toLoad?.length
+  if not sessionContext.toLoad?.size
     return callback()

-  db.fetchDevice(sessionContext.deviceId, sessionContext.timestamp, sessionContext.toLoad, (err, parameters, loaded) ->
+  toLoad = Array.from(sessionContext.toLoad.entries())
+  db.fetchDevice(sessionContext.deviceId, sessionContext.timestamp, toLoad, (err, parameters, loaded) ->
     return callback(err) if err

     if not parameters?
@@ -142,6 +143,9 @@
   for e in rpcReq.event
     params.push([['Events', e.replace(' ', '_')], timestamp,
       {object: [timestamp, 0], writable: [timestamp, 0], value: [timestamp, [timestamp, 'xsd:dateTime']]}])
+
+  # Preload DeviceID params
+  loadPath(sessionContext, ['DeviceID', '*'])

   for p in params
     loadPath(sessionContext, p[0])
@@ -1225,8 +1229,10 @@

 loadPath = (sessionContext, path, depth) ->
-  return true if sessionContext.new
-  depth ?= (1 << path.length) - 1
+  depth = depth or (1 << path.length) - 1
+  return true if sessionContext.new or not depth
+
+  sessionContext.toLoad ?= new Map()

   # Trim trailing wildcards
   trimWildcard = path.length
@@ -1234,14 +1240,17 @@
   path = path.slice(0, trimWildcard) if trimWildcard < path.length

   for i in [0..path.length] by 1
-    for sup in sessionContext.deviceData.paths.find(path.slice(0, i), true, false)
-      v = sessionContext.deviceData.loaded.get(sup)
-      depth &= depth ^ sessionContext.deviceData.loaded.get(sup)
-
-    return true if depth == 0
-
-  sessionContext.toLoad ?= []
-  sessionContext.toLoad.push([path, depth])
+    d = if i == path.length then 99 else i
+    for sup in sessionContext.deviceData.paths.find(path.slice(0, i), true, false, d)
+      v = sessionContext.deviceData.loaded.get(sup) | sessionContext.toLoad.get(sup)
+      if sup.length > i
+        v &= (1 << i) - 1
+      depth &= depth ^ v
+      return true if depth == 0
+
+  path = sessionContext.deviceData.paths.add(path)
+  depth |= sessionContext.toLoad.get(path)
+  sessionContext.toLoad.set(path, depth)
   return false


Fix issue causing unnecessary GPN requests

--- lib/session.coffee
+++ lib/session.coffee
@@ -1183,7 +1183,9 @@
           virtualParameterDeclarations.push(d) if d
       else
         if declareTimestamp > currentTimestamp and declareTimestamp > leafTimestamp
-          if leafIsObject
+          if currentPath == leafParam
+            syncState.refreshAttributes.exist.add(leafParam)
+          else if leafIsObject
             syncState.gpn.add(leafParam)
             if leafTimestamp > 0
               f = 1 << leafParam.length


Don’t need all this stuff

Don’t need all this stuff

--- src/shape-tool.coffee
+++ src/shape-tool.coffee
@@ -4,7 +4,8 @@

 module.exports =
 class ShapeTool
-  constructor: (@svgDocument, {@selectionModel, @selectionView, @toolLayer}={}) ->
+  constructor: (@svgDocument, {@selectionModel}={}) ->
+    @objectRoot = @svgDocument

   activate: (@shapeType) ->
     @svgDocument.on 'mousedown', @onMouseDown


Revert "Merge pull request #686 from sheldonkwok/master"

This reverts commit 42825e990cc345cb977877d074ec12eec690818a, reversing
changes made to 2d096f9726a88d73297609fc35f3459c916acacd.

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -398,7 +398,3 @@
   '" +': 'vim-mode:register-prefix'
   '" %': 'vim-mode:register-prefix'
   '" _': 'vim-mode:register-prefix'
-
-'.tree-view':
-  'ctrl-w v': 'tree-view:open-selected-entry-right'
-  'ctrl-w s': 'tree-view:open-selected-entry-down'