Optimization for fewer database calls

Optimization for fewer database calls

--- bot.iced
+++ bot.iced
@@ -39,9 +39,9 @@
 	await Users_collection.findOne {id: steamID}, defer(err, user)
 	if err
 		console.error err
-		cb undefined
+		cb undefined, undefined
 	registered = if user then true else false
-	cb registered
+	cb registered, user

 bot.on "chatMsg", (sourceID, message, type, chatterID) ->
 	if message is "Me"
@@ -73,13 +73,12 @@
 				bot.sendMessage chatterID, "Reply '+add <AMOUNT> doge' to add dogecoins to your account"
 				bot.sendMessage chatterID, "Tip users with '+tip <STEAM NAME> <AMOUNT> doge'"
 		when "+add"
-			await checkIfRegistered chatterID, defer(registered)
+			await checkIfRegistered chatterID, defer(registered, user)
 			if registered is undefined
 				return bot.sendMessage chatterID, "The database ran into an error"
 			unless registered
 				return bot.sendMessage chatterID, "You must register before you can add funds. Do this by sending '+register'."

-			await Users_collection.findOne {id: chatterID}, defer(err, user)
 			if user
 				for transaction in user.history
 					if transaction.status is "pending" then return bot.sendMessage chatterID, "You already have an +add request pending"
@@ -119,13 +118,12 @@
 					console.error err
 					bot.sendMessage chatterID, "The database ran into an error"
 		when "+finishadd"
-			await checkIfRegistered chatterID, defer(registered)
+			await checkIfRegistered chatterID, defer(registered, user)
 			if registered is undefined
 				return bot.sendMessage chatterID, "The database ran into an error"
 			unless registered
 				return bot.sendMessage chatterID, "You must register before you can add funds. Do this by sending '+register'."

-			await Users_collection.findOne {id: chatterID}, defer(err, user)
 			for transaction in user.history
 				if transaction.status is "pending"
 					break


Removed ;

Removed ;

--- core/app/backbone/collections/fact_relations.coffee
+++ core/app/backbone/collections/fact_relations.coffee
@@ -1,4 +1,4 @@
 class window.FactRelations extends Backbone.Collection
   model: FactRelation,

-  initialize: (model, opts) -> this.fact = opts.fact;
+  initialize: (model, opts) -> this.fact = opts.fact


Created custom view event click:body for FactBody/FactBase

--- core/app/backbone/views/facts/fact_base_view.coffee
+++ core/app/backbone/views/facts/fact_base_view.coffee
@@ -8,7 +8,7 @@

   onRender: ->
     @factWheelRegion.show @wheelView()
-    @factBodyRegion.show new FactBodyView(model:@model)
+    @factBodyRegion.show @bodyView()

   initialize: ->
     @bindTo @model, 'change', =>
@@ -26,6 +26,14 @@

     wheelView

+  bodyView: ->
+    bodyView = new FactBodyView(model:@model)
+
+    @bindTo bodyView, 'click:body', =>
+      @trigger 'click:body'
+
+    bodyView
+
 class FactBodyView extends Backbone.Marionette.ItemView
   template: "facts/fact_body"

@@ -34,6 +42,7 @@
   events:
     "click a.more": "showCompleteDisplaystring"
     "click a.less": "hideCompleteDisplaystring"
+    "click span.js-displaystring": "triggerViewClick"

   onRender: ->
     sometimeWhen(
@@ -54,3 +63,6 @@
   hideCompleteDisplaystring: (e) ->
     @$('.js-displaystring').trunk8 lines: @showLines
     @$('.less').hide()
+
+  triggerViewClick: ->
+    @trigger 'click:body'


Don’t show welcome message on startup

Don’t show welcome message on startup

--- atom/config.cson
+++ atom/config.cson
@@ -12,7 +12,11 @@
     fontFamily: "'SF Mono', Menlo, Consolas, DejaVu Sans Mono, monospace"
     fontSize: 12
     lineHeight: 1.7
+  "linter-ui-default":
+    showPanel: true
   "one-dark-ui":
     tabCloseButton: "Left"
   "one-light-ui":
     tabCloseButton: "Left"
+  welcome:
+    showOnStartup: false


Fix atom font family

Fix atom font family

--- atom/config.cson
+++ atom/config.cson
@@ -12,7 +12,7 @@
   docblockr:
     extend_double_slash: false
   editor:
-    fontFamily: "Andale Mono"
+    fontFamily: "Myrica M"
     fontSize: 13
     invisibles: {}
     softWrap: true


don't add trailing newline

don't add trailing newline

--- atom/config.cson
+++ atom/config.cson
@@ -97,6 +97,8 @@
     useClipboardAsDefaultRegister: true
   welcome:
     showOnStartup: false
+  whitespace:
+    ensureSingleTrailingNewline: false
 ".md.text":
   editor:
     showIndentGuide: false


rest end point will output 24 hours of records by default

--- routes/rest.coffee
+++ routes/rest.coffee
@@ -15,9 +15,11 @@

   recordsFor = (types, since, callback) ->
     query = sensor: $in: types # basic query
-    query.timestamp = "$gt": new Date since if since?

-    envdata.find(query, callback).sort(timestamp: -1).limit 10
+    yesterday = clock.getTime() - 24 * 60 * 60 * 1000
+    query.timestamp = $gt: new Date if since? then since else yesterday
+
+    envdata.find(query, callback).sort(timestamp: -1)

   ###
   Get the latest sheep data


Player goes boom

Player goes boom

--- app/scripts/components/ShipSpawnable.coffee
+++ app/scripts/components/ShipSpawnable.coffee
@@ -43,9 +43,19 @@
     @ship.start()
     @listenTo @ship, 'Hit', ->
       hasLasers = @ship.hasItem 'lasers'
+      Crafty.e('Explosion').explode(
+        x: @ship.x + (@ship.w / 2)
+        y: @ship.y + (@ship.h / 2)
+        radius: @ship.w
+      )
       @ship.destroy()
       @ship = null
-      @loseLife()
-      @spawnShip(hasLasers)
+      Crafty.e('Delay').delay(
+        =>
+          @loseLife()
+          @spawnShip(hasLasers)
+        2000
+        0
+      )
     this


Reduce the console pause delay after collecting info

From 5 seconds to 2 seconds

--- src/lib/interfaces/console.coffee
+++ src/lib/interfaces/console.coffee
@@ -326,7 +326,7 @@
 					userConfig.subscribed = false
 					docpad.updateUserConfig (err) ->
 						return complete(err)  if err
-						balUtil.wait(5000,complete)
+						balUtil.wait(2000,complete)
 					return

 				# Scan configuration to speed up the process


soft-fail on postscript error

soft-fail on postscript error

--- resource/bibtex/reference.coffee
+++ resource/bibtex/reference.coffee
@@ -611,7 +611,10 @@

     @add({name: 'type', value: @referencetype}) if @fields.length == 0

-    @postscript(@, @item)
+    try
+      @postscript(@, @item)
+    catch err
+      debug('Reference.postscript failed:', err)

     for name in Translator.preferences.skipFields
       @remove(name)


dashboard/loading view doesn't need layout

--- app/views/dashboard/loading.coffee
+++ app/views/dashboard/loading.coffee
@@ -1,7 +1,5 @@
 `import Ember from 'ember'`

-View = Ember.View.extend
-  layoutName: 'layouts/dashboard'
-  classNames: ['dashboard']
+View = Ember.View.extend()

 `export default View`


Fixed #297 refreshing a grid whe filters are changed

--- wzk/ui/grid/FilterWatcher.coffee
+++ wzk/ui/grid/FilterWatcher.coffee
@@ -71,6 +71,7 @@
       @query.filter name, val
       @query.offset = 0
       @grid.setQuery @query
+      @grid.refresh()
       @dispatchChanged()

   ###*


adding support for grammar SLD

adding support for grammar SLD

--- src/languages/xml.coffee
+++ src/languages/xml.coffee
@@ -9,14 +9,14 @@
   Supported Grammars
   ###
   grammars: [
-    "XML", "XHTML", "XSD", "XSL", "JSP"
+    "SLD", "XML", "XHTML", "XSD", "XSL", "JSP"
   ]

   ###
   Supported extensions
   ###
   extensions: [
-    'xml', 'xhtml', 'xsd', 'xsl', 'jsp'
+    'sld', 'xml', 'xhtml', 'xsd', 'xsl', 'jsp'
   ]

   defaultBeautifier: "Pretty Diff"


🐛 Hide broken campaign view esports link (#6257)


old auctions code :dizzy_face: :dizzy_face: :dizzy_face:

--- apps/auction_support/routes.coffee
+++ apps/auction_support/routes.coffee
@@ -15,10 +15,8 @@
       if creditCards.length > 0
         req.user.createBidder
           saleId: sale.get('id')
-          success: ->
-            return res.redirect sale.registrationSuccessUrl()
-          error: ->
-            res.backboneError
+          error: res.backboneError
+          success: -> res.redirect sale.registrationSuccessUrl()
       else
         order = new Order()
         res.render 'registration',


Cleanup keymap

Cleanup keymap

--- keymap.cson
+++ keymap.cson
@@ -35,11 +35,6 @@
   'ctrl-}': 'last-cursor-position:next'
   'alt-ctrl-f': 'platformio-ide-terminal:focus'

-  # 'shift-ctrl-c': 'run:stop'
-# '.platform-darwin atom-workspace':
-  # 'cmd-R': 'script:run-with-profile'
-  # 'cmd-ctrl-R': 'script:run-options'
-
 'atom-text-editor':
   'ctrl-alt-f': 'platformio-ide-terminal:focus'
 '.platform-darwin atom-text-editor':
@@ -55,13 +50,3 @@

 '.atom-runner':
   'escape': 'run:close'
-
-  # 'ctrl-alt-K': 'command-pallete:'
-# '.platform-darwin atom-text-editor':
-#   'cmd-R': 'script:run'
-#   'shift-cmd-k': 'script:run-with-profile'
-#   #'shift-enter': 'script:run'
-#   'ctrl-w': 'script:close-view'
-#   'ctrl-c': 'script:kill-process'
-#   'shift-cmd-j': 'script:run-by-line-number'
-#   'shift-cmd-i': 'script:run-options'


closeTabsToLeft/Right -> closeTabsOnLeft/Right.

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -255,8 +255,8 @@
   moveTabToNewWindow: ["Move tab to new window", { background: true }]
   togglePinTab: ["Pin/unpin current tab", { background: true }]

-  closeTabsToLeft: ["Close tabs on the left", {background: true, noRepeat: true}]
-  closeTabsToRight: ["Close tabs on the right", {background: true, noRepeat: true}]
+  closeTabsOnLeft: ["Close tabs on the left", {background: true, noRepeat: true}]
+  closeTabsOnRight: ["Close tabs on the right", {background: true, noRepeat: true}]
   closeOtherTabs: ["Close all other tabs", {background: true, noRepeat: true}]

   moveTabLeft: ["Move tab to the left", { background: true, passCountToFunction: true }]


Removed deprecated displayBuffer property

--- lib/regex-railroad-diagram.coffee
+++ lib/regex-railroad-diagram.coffee
@@ -54,7 +54,7 @@
   bufferRangeForScope: (editor, scope, position=null) ->
     unless issue58
       if position?
-        result = editor.displayBuffer.bufferRangeForScopeAtPosition(scope, position)
+        result = editor.bufferRangeForScopeAtPosition(scope, position)
       else
         result = editor.bufferRangeForScopeAtCursor(scope)
       return result
@@ -80,7 +80,7 @@
     if startTabs
       position.column = position.column - startTabs + startTabs*tabLength

-    result = editor.displayBuffer.bufferRangeForScopeAtPosition(scope, position)
+    result = editor.bufferRangeForScopeAtPosition(scope, position)
     return result unless result

     # this is usually only one row, but if at some point the range would span


PrivateMessage: Add sendPrivateMessage to Activity/AppController

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -61,6 +61,10 @@
     {socialapi} = KD.singletons
     socialapi.message.listReplies {messageId, from, limit}, callback

+  sendPrivateMessage: (options = {}, callback = noop) ->
+
+    (KD.singleton 'socialapi').message.sendPrivateMessage options, callback
+

   fetch: ({channelId, from}, callback = noop) ->


display attachment icon even if message is collapsed

--- client/app/components/message_header.coffee
+++ client/app/components/message_header.coffee
@@ -35,11 +35,11 @@
                 @renderAddress 'from'
                 @renderAddress 'to' if @props.active
                 @renderAddress 'cc' if @props.active
-                if @props.active
-                    div className: 'metas indicators',
-                        if @props.message.get('attachments').length
-                            PopupMessageAttachments
-                                message: @props.message
+                div className: 'metas indicators',
+                    if @props.message.get('attachments').length
+                        PopupMessageAttachments
+                            message: @props.message
+                    if @props.active
                         if MessageFlags.FLAGGED in @props.message.get('flags')
                             i className: 'fa fa-star'
                         if @props.isDraft


client: welcome: welcome modal default options added

--- client/home/lib/welcome/welcomemodal.coffee
+++ client/home/lib/welcome/welcomemodal.coffee
@@ -2,6 +2,15 @@
 HomeWelcome = require './'

 module.exports = class WelcomeModal extends kd.ModalView
+
+  constructor: (options = {}, data) ->
+
+    options.cssClass = 'HomeWelcomeModal'
+    options.width    = 660
+
+    super options, data
+
+

   viewAppended: ->


Use slug.slug instead name.name

Use slug.slug instead name.name

--- client/landing/app/MainApp/mq.config.coffee
+++ client/landing/app/MainApp/mq.config.coffee
@@ -34,7 +34,7 @@
         err = null
         queue = name.slugs.map (slug) => =>
           selector = {}
-          selector[slug.usedAsPath] = name.name
+          selector[slug.usedAsPath] = slug.slug
           @api[slug.constructorName].one? selector, (err, model)->
             if err then callback err
             else


shellSelectorView: add shell description as tooltip

--- coffee/src/views/shell_selector_view.coffee
+++ coffee/src/views/shell_selector_view.coffee
@@ -33,6 +33,7 @@
       new Backbone.Model
         text: Shell.title
         icon: Shell.icon
+        tooltip: title: Shell.description
         shell: Shell.id

     @gridView = new athena.lib.GridView


辛くなってきた

辛くなってきた

--- scripts/line-beacon-listener.coffee
+++ scripts/line-beacon-listener.coffee
@@ -1,8 +1,13 @@
 module.exports = (robot) ->

   robot.router.post "/line-becon", (req, res) ->
+    if not req.body
+      res.end ""
+      robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊ボディなんてねぇよ！！"
+      return
+
     data = if req.body.payload? then JSON.parse req.body.payload else req.body
-    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{req.body.content}"
-    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{data.content}"
+    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{req.body}"
+    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{data}"
     robot.send {room: "C4LEAQHPW"}, "ビーコンに反応あり"
     res.end ""


Revert "Split goEdit into two, so second half can be re-used."

This reverts commit 97944d9320bfa507c24982af4cccdf70271098e2.

--- scripts/controllers/routing.coffee
+++ scripts/controllers/routing.coffee
@@ -70,7 +70,10 @@
     # Also, the route is updated to include this context.
     goEdit: (model, contextModel=null) ->
       # To prevent cyclic dependencies, load the views once the app has loaded.
-      require [ 'cs!views/layouts/workspace/menu' ], (menuLayout) =>
+      require [
+        'cs!views/layouts/workspace/menu'
+        'cs!views/workspace/sidebar/toc'
+        ], (menuLayout, TocView) =>

         @_ensureLayout(menuLayout)

@@ -89,38 +92,35 @@
               contextModel = allContent.get(contextModel)

           # Redirect to workspace if model does not exist
-          if model
-            @_goEdit(model, contextModel)
+          if not model
+            @goWorkspace()
           else
-            @goWorkspace()

-    _goEdit: (model, contextModel=null) ->
-      require [ 'cs!views/workspace/sidebar/toc' ], (TocView) =>
-       # Always show the workspace pane
-       @_showWorkspacePane(TocView)
+            # Always show the workspace pane
+            @_showWorkspacePane(TocView)

-       # load editor views
+            # load editor views

-       # Force the sidebar if a contextModel is passed in
-       if contextModel
-         contextModel.sidebarView((view) => if view then @layout.sidebar.show(view))
-       else if model.sidebarView
-         # Some models do not change the sidebar (like Module)
-         model.sidebarView((view) => if view then @layout.sidebar.show(view))
+            # Force the sidebar if a contextModel is passed in
+            if contextModel
+              contextModel.sidebarView((view) => if view then @layout.sidebar.show(view))
+            else if model.sidebarView
+              # Some models do not change the sidebar (like Module)
+              model.sidebarView((view) => if view then @layout.sidebar.show(view))

-       model.contentView((view) => if view then @layout.content.show(view)) if model.contentView
+            model.contentView((view) => if view then @layout.content.show(view)) if model.contentView

-       # Load the menu's toolbar
-       if model.toolbarView
-         model.toolbarView((view) => if view then @layout.menu.currentView.showToolbar(view))
-       else @layout.menu.currentView.showToolbar()
+            # Load the menu's toolbar
+            if model.toolbarView
+              model.toolbarView((view) => if view then @layout.menu.currentView.showToolbar(view))
+            else @layout.menu.currentView.showToolbar()

-       # URL-escape the `model.id` because a piece of content may have `/` in it (github uses these)
-       contextPath = ''
-       contextPath = "|#{encodeURIComponent(contextModel.id or contextModel.cid)}" if contextModel
+            # URL-escape the `model.id` because a piece of content may have `/` in it (github uses these)
+            contextPath = ''
+            contextPath = "|#{encodeURIComponent(contextModel.id or contextModel.cid)}" if contextModel

-       # Update the URL without triggering the router
-       @navigate("edit/#{encodeURIComponent(model.id or model.cid)}#{contextPath}")
+            # Update the URL without triggering the router
+            @navigate("edit/#{encodeURIComponent(model.id or model.cid)}#{contextPath}")

     goDefault: () ->
       require [ 'cs!views/layouts/workspace/menu' ], (menuLayout) =>


log: log more info

log: log more info

--- client/Terminal/webtermview.coffee
+++ client/Terminal/webtermview.coffee
@@ -122,7 +122,7 @@

     .catch (err) =>
       KD.utils.warnAndLog "terminal: webtermConnect error",
-        {hostnameAlias:@getVMName(), reason:err?.message}
+        {hostnameAlias:@getVMName(), reason:err?.message, options}

       if err.code is "ErrInvalidSession"
         @reconnectionInProgress = false


Fixed: code style

Fixed: code style

--- client/app/libs/PanelRouter.coffee
+++ client/app/libs/PanelRouter.coffee
@@ -81,7 +81,8 @@
             fluxAction = LayoutActionCreator[pattern.fluxAction]

             if not fluxAction?
-                console.warn "`#{pattern.fluxAction}` method not found in layout actions."
+                console.warn "`#{pattern.fluxAction}` method not found in " + \
+                             "layout actions."

             return fluxAction

@@ -91,11 +92,11 @@
     ###
     _processSubRouting: (name, args) ->

-        # remove the last argument which is always `null`, not sure why
+        # removes the last argument which is always `null`, not sure why
         args.pop()

         # next comes the rightPanel url if it exists
-        # or a leftPanel parameter there is not rightPanel
+        # or a leftPanel parameter if there is not rightPanel
         rightPanelString = args.pop()

         # if left panel number of expected params is bigger what is left
@@ -108,7 +109,7 @@

         leftPanelParameters = args

-        # check all the routes for the second part of the URL
+        # checks all the routes for the second part of the URL
         route = _.first _.filter @cachedPatterns, (element) ->
             return element.pattern.test rightPanelString

@@ -121,7 +122,7 @@
         else
             rightPanelInfo = null

-        # normalize the leftPanelInfo
+        # normalizes the leftPanelInfo
         leftPanelInfo = action: name, parameters: leftPanelParameters
         return [leftPanelInfo, rightPanelInfo]

@@ -153,12 +154,15 @@
                 else
                     console.warn '`direction` should be `left`, `right`.'
             else
-                console.warn '`direction` parameter is mandatory when using short call.'
+                console.warn '`direction` parameter is mandatory when ' + \
+                             'using short call.'

         # if the `fullWidth` parameter is set, it ignores the right panel info
-        if (options.leftPanel? or options.direction is 'left') and options.fullWidth
+        isLeftDirection = options.leftPanel? or options.direction is 'left'
+        if isLeftDirection and options.fullWidth
             if options.rightPanel? and options.direction is 'right'
-                console.warn "You shouldn't use the fullWidth option with a right panel"
+                console.warn "You shouldn't use the fullWidth option with " + \
+                             "a right panel"
             rightPanelInfo = null

         # Actual building
@@ -223,7 +227,8 @@
             if panel.parameters
                 for paramInPattern, key in parametersInPattern
                     paramValue = panel.parameters[key]
-                    filledPattern = filledPattern.replace paramInPattern, paramValue
+                    filledPattern = filledPattern.replace paramInPattern, \
+                                                                    paramValue

             return filledPattern
         else


Moved Slack user check before hound check

--- src/scripts/hound.coffee
+++ src/scripts/hound.coffee
@@ -26,6 +26,11 @@
   #     Don’t forget to check out~

   hound = (slackuser, channel, forceHound=false) ->
+    user = Organization.getUserBySlackName slackuser.name
+    if not user
+      Logger.log "#{slackuser.name} couldn't be found while attempting to hound"
+      return
+
     if user.settings.shouldHound
       if not channel.private
         channel.private = !!channel.is_im or !!channel.is_group
@@ -38,11 +43,6 @@
         return
       else if robot.name is slackuser.name
         Logger.log 'Caught myself, don\'t hound the hound.'
-        return
-
-      user = Organization.getUserBySlackName slackuser.name
-      if not user
-        Logger.log "#{slackuser.name} couldn't be found while attempting to hound"
         return

       now = moment.tz TIMEZONE


Use built in html stripper if lynx fails.

--- src/scripts/rally.coffee
+++ src/scripts/rally.coffee
@@ -164,15 +164,19 @@
   else
     #do nothing

+stripHtml = (html, cb) ->
+  return_text = html.replace(/<style.+\/style>/g, '')
+  return_text = return_text.replace(/<br ?\/?>/g, "\n\n").replace(/ /g, ' ').replace(/[ ]+/g, ' ').replace(/%22/g, '"').replace(/&/g, '&').replace(/<\/?.+?>/g, '')
+  return_text = return_text.replace(/>/g, '>').replace(/</g, '<')
+  cb return_text
+
 prettifyDescription = (html_description, cb) ->
   child = exec "echo \"#{html_description}\" | lynx -dump -stdin", (error, stdout, stderr) ->
     return_text = html_description
     if !error
       return_text = stdout
+    else
+      stripHtml return_text, (cleaned) ->
+        return_text = cleaned
     cb return_text

-stripHtml = (html, cb) ->
-  return_text = html.replace(/<style.+\/style>/g, '')
-  return_text = return_text.replace(/<\/?.+?>/g, '').replace(/<br ?\/?>/g, "\n\n").replace(/ /g, ' ').replace(/[ ]+/g, ' ').replace(/%22/g, '"').replace(/&/g, '&')
-  return_text = return_text.replace(/>/g, '>').replace(/</g, '<')
-  cb return_text


re-organization of lib, adding a default logger

Conflicts:
	javascripts/lib.coffee

--- javascripts/lib.coffee
+++ javascripts/lib.coffee
@@ -1,14 +1,24 @@
 #= require almond_wrapper
 #= require underscore-min
 #= require lib/class_mixer
+#= require lib/logger

-window.AP = (object)->
+
+window.ttm ||= {}
+
+ttm.defaults = (provided, defaults)->
+  _.extend({}, defaults, provided)
+
+window.logger ||= window.ttm.Logger.buildProduction(stringify_objects: false)
+
+ttm.AP = (object)->
   str = "#{object.constructor.name}"
   str += "{ "
   for key, value of object
     str += "#{key}: #{value}"
   str += " }"
   str
+
 window.ttm ||= {}
 window.ttm.dashboard ||= {}
 window.ttm.decorators ||= {}
@@ -78,6 +88,3 @@
   return Refinement

-ttm.defaults = (provided, defaults)->
-  _.extend({}, defaults, provided)
-


Fix bug with Player timeout

Fix bug with Player timeout

--- src/server/Player.coffee
+++ src/server/Player.coffee
@@ -32,9 +32,10 @@
 		@client.on('close', @onClose)
 		@client.on('error', @onError)
 		@client.on('data', @onData)
-		@client.on('timeout', @onTimeout)
+		@client.setTimeout(25 * 1000, @onTimeout)
 		@client.setEncoding('utf8')
 		@buffer = ""
+		@isClose = false;
 		@defers = []
 		@client.write('hello\n')
 		@ping = true;
@@ -77,8 +78,10 @@

 	shutdown: () => @client.end();
 	onTimeout: () => @client.end();
-	onError: (error) => console.log("#Socket Error #{error}");
+	onError: (error) => @onClose();
 	onClose: () =>
+		if (@isClose == true) then return;
+		@isClose = true;
 		clearInterval(@timer)
 		@emit('disconnect')
 		for defer in @defers


Changed styles to css since that better matches the naming convention used

--- src/server/config.coffee
+++ src/server/config.coffee
@@ -12,7 +12,7 @@
 	less:
 		file   : "app.css"
 		entry  : "app.less"
-		folder : "styles"
+		folder : "css"

 	# Browserify directory and entry file
 	browserify:


debug

debug

--- src/server/routes.coffee
+++ src/server/routes.coffee
@@ -282,8 +282,8 @@
             if err
                 res.status(200).end()
             else
+                console.log(param)
                 param = unescape(param).split("&")
-                console.log(param)
                 if param is 'INVALID TOKEN'
                     res.status(200).end()
                 else


DSL for test scenarios

DSL for test scenarios

--- spec/command-nested-rules.coffee
+++ spec/command-nested-rules.coffee
@@ -29,6 +29,16 @@

     afterEach ->
       remove(container)
+
+
+    Scenario = (done, container, steps, i) ->
+      if steps[i]
+        container.addEventListener 'solve', callback = ->
+          steps[i]()
+          container.removeEventListener 'solve', callback
+          Scenario(done, container, steps, i + 1)
+      else
+        done()

     describe 'flat', ->

@@ -108,7 +118,7 @@

-      it 'Resolve selector on ::', (done) ->
+      it 'should resolve selector on ::', (done) ->
         rules = [
           {
             type:'ruleset'
@@ -137,43 +147,35 @@

         box1 = container.getElementsByClassName('box')[1]
         vessel0 = container.getElementsByClassName('vessel')[0]
-        TwoElementsMatch = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
-            ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
-            ['eq', ['get$','x','$box2', '.vessel .box$vessel0'], ['number',100]]
-          ])
-          box1.classList.remove('box')
-          container.removeEventListener 'solved', TwoElementsMatch
-          container.addEventListener 'solved', OneChildDoesntMatchAnymore
-        container.addEventListener 'solved', TwoElementsMatch
-        OneChildDoesntMatchAnymore = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
-            ['remove', '.vessel .box$vessel0$box1']
-          ])
-          box1.classList.add('box')
-          container.removeEventListener 'solved', OneChildDoesntMatchAnymore
-          container.addEventListener 'solved', ChildMatchesAgain
-        ChildMatchesAgain = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
-            ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
-          ])
-          container.removeEventListener 'solved', ChildMatchesAgain
-          container.addEventListener 'solved', ParentDoesntMatchAnyMore
-          vessel0.classList.remove('vessel')
-        ParentDoesntMatchAnyMore = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
-            ['remove', '.vessel$vessel0', '.vessel .box$vessel0']
-          ])
-          container.removeEventListener 'solved', ParentDoesntMatchAnyMore
-          container.addEventListener 'solved', ParentMatchesAgain
-          vessel0.classList.add('vessel')
-        ParentMatchesAgain = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
-            ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
-            ['eq', ['get$','x','$box2', '.vessel .box$vessel0'], ['number',100]]
-          ])
-          container.removeEventListener 'solved', ParentMatchesAgain
-          done()
+
+        Scenario done, container, [
+          TwoElementsMatch = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
+              ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
+              ['eq', ['get$','x','$box2', '.vessel .box$vessel0'], ['number',100]]
+            ])
+            box1.classList.remove('box')
+          OneChildDoesntMatchAnymore = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
+              ['remove', '.vessel .box$vessel0$box1']
+            ])
+            box1.classList.add('box')
+          ChildMatchesAgain = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
+              ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
+            ])
+            vessel0.classList.remove('vessel')
+          ParentDoesntMatchAnyMore = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
+              ['remove', '.vessel$vessel0', '.vessel .box$vessel0']
+            ])
+            vessel0.classList.add('vessel')
+          ParentMatchesAgain = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify([
+              ['eq', ['get$','x','$box1', '.vessel .box$vessel0'], ['number',100]]
+              ['eq', ['get$','x','$box2', '.vessel .box$vessel0'], ['number',100]]
+            ])
+        ]
         engine = GSS(container)

         sheet = new GSS.StyleSheet
@@ -259,82 +261,67 @@
         clone.innerHTML = container.innerHTML.replace /\d+/g, (d) ->
           return "1" + d

-
+        Scenario done, container, [

-        TwoElementsMatchSelector = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['lte', ['get$','width','$box2', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]],
-              ['lte', ['get$','width','$box4', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
-            ]
-          newLast = document.createElement('div')
-          newLast.id = 'box5'
-          newLast.className = 'box'
-          container.firstElementChild.appendChild(newLast)
-          container.removeEventListener 'solved', TwoElementsMatchSelector
-          container.addEventListener 'solved', NewElementReplacesAnother
-        container.addEventListener 'solved', TwoElementsMatchSelector
-
-        NewElementReplacesAnother = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ["remove",".group .vessel::parent .box:last-child$vessel1$box4"],
-              ['lte', ['get$','width','$box5', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
-            ]
-          container.firstElementChild.classList.remove('group')
-          container.removeEventListener 'solved', NewElementReplacesAnother
-          container.addEventListener 'solved', ParentDoesntMatchAnymore
-
-        ParentDoesntMatchAnymore = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['remove', '.group .vessel$vessel1', '.group .vessel::parent .box:last-child$vessel1']
-            ]
-          container.firstElementChild.classList.add('group')
-          container.removeEventListener 'solved', ParentDoesntMatchAnymore
-          container.addEventListener 'solved', ParentMatchesAgain
-
-        ParentMatchesAgain = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['lte', ['get$','width','$box2', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]],
-              ['lte', ['get$','width','$box5', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
-            ]
-          container.removeEventListener 'solved', ParentMatchesAgain
-          container.addEventListener 'solved', ParentIsCloned
-          container.appendChild(clone)
-
-        ParentIsCloned = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['lte', ['get$','width','$box12', '.group .vessel::parent .box:last-child$vessel11'], ["number",100]],
-              ['lte', ['get$','width','$box14', '.group .vessel::parent .box:last-child$vessel11'], ["number",100]]
-            ]
-          container.removeEventListener 'solved', ParentIsCloned
-          container.addEventListener 'solved', CloneIsReplaced
-          container.replaceChild(container.firstElementChild, container.lastElementChild)
-
-        CloneIsReplaced = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['remove', '$vessel11', '.group .vessel$vessel11', '.group .vessel::parent .box:last-child$vessel11']
-            ]
-          box2 = container.getElementsByClassName('box')[2]
-          box2.parentNode.removeChild(box2)
-          container.removeEventListener 'solved', CloneIsReplaced
-          container.addEventListener 'solved', ChildIsRemovedAnotherMatches
-
-        ChildIsRemovedAnotherMatches = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['remove', '$box2'],
-              ['lte', ['get$', 'width', '$box1', '.group .vessel::parent .box:last-child$vessel1'],["number",100]],
-            ]
-          container.removeEventListener 'solved', ChildIsRemovedAnotherMatches
-          container.addEventListener 'solved', IntermediateElementIsRemoved
-          vessel = container.getElementsByClassName('vessel')[0]
-          vessel.parentNode.removeChild(vessel)
-
-        IntermediateElementIsRemoved = (e) ->
-          expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
-              ['remove', '$vessel1', '$box1', '.group .vessel$vessel1', '.group .vessel::parent .box:last-child$vessel1'],
-            ]
-          container.removeEventListener 'solved', IntermediateElementIsRemoved
-          container.innerHTML = ""
-          done()
+          TwoElementsMatchSelector = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['lte', ['get$','width','$box2', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]],
+                ['lte', ['get$','width','$box4', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
+              ]
+            newLast = document.createElement('div')
+            newLast.id = 'box5'
+            newLast.className = 'box'
+            container.firstElementChild.appendChild(newLast)
+
+          , NewElementReplacesAnother = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ["remove",".group .vessel::parent .box:last-child$vessel1$box4"],
+                ['lte', ['get$','width','$box5', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
+              ]
+            container.firstElementChild.classList.remove('group')
+
+          , ParentDoesntMatchAnymore = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['remove', '.group .vessel$vessel1', '.group .vessel::parent .box:last-child$vessel1']
+              ]
+            container.firstElementChild.classList.add('group')
+
+          , ParentMatchesAgain = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['lte', ['get$','width','$box2', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]],
+                ['lte', ['get$','width','$box5', '.group .vessel::parent .box:last-child$vessel1'], ["number",100]]
+              ]
+            container.appendChild(clone)
+
+          , ParentIsCloned = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['lte', ['get$','width','$box12', '.group .vessel::parent .box:last-child$vessel11'], ["number",100]],
+                ['lte', ['get$','width','$box14', '.group .vessel::parent .box:last-child$vessel11'], ["number",100]]
+              ]
+            container.replaceChild(container.firstElementChild, container.lastElementChild)
+
+          , CloneIsReplaced = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['remove', '$vessel11', '.group .vessel$vessel11', '.group .vessel::parent .box:last-child$vessel11']
+              ]
+            box2 = container.getElementsByClassName('box')[2]
+            box2.parentNode.removeChild(box2)
+
+          , ChildIsRemovedAnotherMatches = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['remove', '$box2'],
+                ['lte', ['get$', 'width', '$box1', '.group .vessel::parent .box:last-child$vessel1'],["number",100]],
+              ]
+            vessel = container.getElementsByClassName('vessel')[0]
+            vessel.parentNode.removeChild(vessel)
+
+          , IntermediateElementIsRemoved = (e) ->
+            expect(stringify(engine.lastWorkerCommands)).to.eql stringify [
+                ['remove', '$vessel1', '$box1', '.group .vessel$vessel1', '.group .vessel::parent .box:last-child$vessel1'],
+              ]
+            container.innerHTML = ""
+
+        ]

         engine = GSS(container)


Modified html binder

Modified html binder

--- src/binders.coffee
+++ src/binders.coffee
@@ -9,7 +9,12 @@

 # Sets the element's HTML content.
 Rivets.public.binders.html = (el, value) ->
+  value = value.outerHTML if (value instanceof HTMLElement)
+
+  return this.text(el, value) if typeof value? is 'string'
+
   el.innerHTML = if value? then value else ''
+

 # Shows the element when value is true.
 Rivets.public.binders.show = (el, value) ->


Download contests that have only one problem

--- server/cron/downloadContests.coffee
+++ server/cron/downloadContests.coffee
@@ -65,21 +65,28 @@
             order: order*100
         ).upsert()

+    getFirstProblem: (text) ->
+        idRe = new RegExp '<a title="Print This Problem" href="print3.php(\\?id=\\d+&chapterid=(\\d+))"'
+        idRes = idRe.exec text
+        id = idRes[2]
+        href = "view3.php?#{idRes[1]}"
+
+        nameRe = new RegExp '
Задача ([^.]+)\\. ([^<]+)
'
+        nameRes = nameRe.exec text
+        name = nameRes[2]
+        letter = nameRes[1]
+
+        return @makeProblem(nameRes[0], href, id, letter, name)
+
     processContest: (order, fullText, href, cid, name, level) ->
         text = await download(href, @jar)
-        re = new RegExp 'Задача ([^.]+)\\. ([^<]+)'
-        secondProbRes = re.exec text
-        if not secondProbRes
-            logger.warn("Second problem not found in contest ", href)
-        secondProbHref = secondProbRes[1].replace('&','&')
-        secondProb = @makeProblem(secondProbRes[0], secondProbRes[1], secondProbRes[2], secondProbRes[3], secondProbRes[4])

-        text = await download(@baseUrl + secondProbHref, @jar)
+        firstProblem = @getFirstProblem(text)
         re = new RegExp 'Задача ([^.]+)\\. ([^<]+)', 'gm'
         problems = []
         text.replace re, (res, a, b, c, d) =>
             problems.push(@makeProblem(res, a, b, c, d))
-        problems.splice(1, 0, secondProb);
+        problems.splice(0, 0, firstProblem);
         await @addContest(order, cid, name, level, problems)

     run: ->
@@ -146,9 +153,5 @@
     await (new RegionContestDownloader(ROI_CONTESTS, "roi", "Всероссийская", "всероссийской", 40000).run())
     await Table.removeDuplicateChildren()
     logger.info "Will update users"
-    users = await User.findAll()
-    promises = []
-    for user in users
-        promises.push(User.updateUser(user._id))
-    await awaitAll(promises)
+    User.updateAllUsers()
     logger.info "Done downloading contests"


Revert "Update deprecated require"

Revert "Update deprecated require"

This reverts commit 4e86dd766a4b68f28b053bd477923386b1369521.

--- spec/package-manager-spec.coffee
+++ spec/package-manager-spec.coffee
@@ -1,5 +1,5 @@
 path = require 'path'
-{process} = require 'electron'
+process = require 'process'
 PackageManager = require '../lib/package-manager'

 describe "package manager", ->


Remove an unused requirement

Remove an unused requirement

--- spec/transient-emacs-spec.coffee
+++ spec/transient-emacs-spec.coffee
@@ -1,5 +1,4 @@
 transient_emacs = require '../lib/transient-emacs'
-{Pane} = require 'atom'

 # Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs.
 #


Working on constructor-less CoffeeScript control classes.

--- src/control.coffee
+++ src/control.coffee
@@ -143,32 +143,34 @@
 Adding support for constructor-less CoffeeScript control classes.
 ###
 class window.Control2 extends jQuery
-  constructor: ( args... ) ->
-    caller = arguments.callee.caller
-    # Figure out which class' constructor invoked us.
-    ###
-    classFn = if this is window
-        # In the (unfortunately) common case where the jQuery-style static
-        # constructor has been used, we'll need to use the deprecated "caller"
-        # method to find the constructor of the actual class that invoked this
-        # function. Warning: "caller" is not permitted in strict mode.
-        caller
-      else
-        # Simple case
-        this.constructor
-    ###
-    classFn = caller
-    if not ( jQuery.isFunction classFn ) and ( classFn:: ) instanceof Control
-      throw "Control.coffee was invoked some context other than a control class' constructor, which is unsupported."
-    # Ensure the class has been treated to be jQuery- and QuickUI-compatible.
-    makeCompatible classFn unless isCompatible classFn
-    # Get the arguments passed to the class' constructor. This is quite
-    # unorthodox, but lets us keep the required boilerplate as short as possible.
-    args = caller.arguments
+  constructor: ( selector, context ) ->
+
+    # Figure out which class is being instantiated. We can't just look at "this",
+    # because jQuery supports a static constructor form: i.e., you can call
+    # jQuery(...) without "new", in which case "this" will be the window. We
+    # can't just look at the current function, because CoffeeScript doesn't
+    # (yet?) support named functions. So we walk up the call tree to figure out
+    # which function was actually called. This entails using the deprecated
+    # "caller" value, which is not allowed in strict mode.
+    classFn = arguments.callee
+
+    caller = classFn.caller
+    if ( caller:: ) instanceof classFn and caller.__super__ isnt undefined
+      # This function was invoked by the constructor of a subclass created by
+      # CoffeeScript. That constructor, in all likelihood, is the default
+      # constructor generated by CoffeeScript, as QuickUI controls shouldn't do
+      # real work in their constructor; they should use initialize() instead.
+      # We want to instantiate the subclass instead of the general Control class.
+      classFn = caller
+
+      # Ensure the class has been treated to be jQuery- and QuickUI-compatible.
+      if not isCompatible classFn
+        makeCompatible classFn
+
     # Actually create an instance of the init helper class per standard jQuery.
-    new classFn::init args...
-
-# Trigger compatibility.
+    new classFn::init selector, context
+
+# TODO: Remove
 Control2.extend Control

 ###
@@ -357,3 +359,7 @@
     if typeof node != "string" or jQuery.trim( node ).length > 0
       return content # HTML element or text node with non-empty text
   undefined # Didn't find anything significant
+
+
+Control2::extend Control::
+Control2::constructor = Control2


Bugfix.

Bugfix.

--- src/control.coffee
+++ src/control.coffee
@@ -77,6 +77,7 @@
         addUnitsWithinBoundingBoxes: (bboxStrings, level) ->
             bboxCount = bboxStrings.length
             if bboxCount > 4
+                null
                 # TODO: handle case.
             if @selectedPosition.value()?.get('radiusFilter')?
                 return


[➠] Improved `scrolly` (“scrollify”).

[➠] Improved `scrolly` (“scrollify”).

--- vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
@@ -52,34 +52,6 @@

     true

-  scrollByHash: (hash) ->
-    if hash
-      excluded = $.inArray(hash, @options.scrolling.exclude) > -1
-
-      if not excluded
-        data = @roof.outline.getScrollDataByHash hash
-
-        @scrollTo data.target, data.offset
-
-    return
-
-  activateSection: (section) ->
-    section = $ section
-    id      = section.data 'id'
-    alias   = section.data 'alias'
-
-    if alias or id
-      @roof.outline.activateItemById alias or id
-
-      @updateLocationHash alias or id
-
-    return
-
-  updateLocationHash: (id) ->
-    window.location.hash = "/#{id}" if id
-
-    return
-
   index: ->
     if @body.attr 'id' is 'index'
       true
@@ -89,11 +61,14 @@
   # === Events ===

   onWindowLoad: (event) =>
-    setTimeout =>
-      @scrollByHash window.location.hash
+    clearTimeout @timeout

-      do @roof.update
-    , 1
+    @timeout = setTimeout @onWindowLoaded, 500
+
+    return
+
+  onWindowLoaded: =>
+    scrollByHash.call @, window.location.hash

     return

@@ -108,12 +83,12 @@
     return

   onSectionEnter: (section, direction) =>
-    @activateSection section
+    activateSection.call @, section

     return

   onScrollComplete: (section) =>
-    @activateSection section
+    activateSection.call @, section

     return

@@ -159,4 +134,32 @@

       return

+    return
+
+  scrollByHash = (hash) ->
+    if hash
+      excluded = $.inArray(hash, @options.scrolling.exclude) > -1
+
+      if not excluded
+        data = @roof.outline.getScrollDataByHash hash
+
+        @scrollTo data.target, data.offset
+
+    return
+
+  activateSection = (section) ->
+    section = $ section
+    id      = section.data 'id'
+    alias   = section.data 'alias'
+
+    if alias or id
+      @roof.outline.activateItemById alias or id
+
+      updateLocationHash.call @, alias or id
+
+    return
+
+  updateLocationHash = (id) ->
+    window.location.hash = "/#{id}" if id
+
     return


Fixed incorrect menu.checked property reference

--- src/ui/views/menu.coffee
+++ src/ui/views/menu.coffee
@@ -92,7 +92,7 @@
                 }, {
                     type: 'checkbox'
                     label: 'Show username in notifications'
-                    checked: viewstate.showMessageInNotification
+                    checked: viewstate.showUsernameInNotification
                     enabled: viewstate.loggedin && viewstate.showPopUpNotifications
                     click: (it) -> action 'showusernameinnotification', it.checked
                 }


Fixed coffeelint error

Fixed coffeelint error

--- src/reporters/cli-reporter.coffee
+++ src/reporters/cli-reporter.coffee
@@ -26,7 +26,12 @@
           logger.expected "\n" + prettifyResponse(test.expected) + "\n" if test.expected
           logger.actual "\n" + prettifyResponse(test.actual) + "\n\n" if test.actual
       if @stats.tests > 0
-        logger.complete "#{@stats.passes} passing, #{@stats.failures} failing, #{@stats.errors} errors, #{@stats.skipped} skipped, #{@stats.tests} total"
+        logger.complete "#{@stats.passes} passing, " +
+          "#{@stats.failures} failing, " +
+          "#{@stats.errors} errors, " +
+          "#{@stats.skipped} skipped, " +
+          "#{@stats.tests} total"
+
       logger.complete "Tests took #{@stats.duration}ms"
       callback()


fixes negative y-axis bars (#485)

fixes negative y-axis bars (#485)

--- src/viz/types/bar.coffee
+++ src/viz/types/bar.coffee
@@ -69,6 +69,7 @@
   data = []
   oppMethod = vars[opposite]
   oppDomain = oppMethod.scale.viz.domain()
+  oppDomain = oppDomain.reverse() if opposite.indexOf("y") is 0
   if oppDomain[0] <= 0 and oppDomain[1] >= 0
     zero = 0
   else if oppDomain[0] < 0


give containers 5 seconds grace time when stopping them

--- src/decking.coffee
+++ src/decking.coffee
@@ -122,7 +122,7 @@
       isRunning container, (err, running) ->
         if running
           logAction name, "stopping..."
-          container.stop callback
+          container.stop t:5, callback
         else
           logAction name, "skipping (already stopped)"
           callback null
@@ -141,7 +141,7 @@
       isRunning container, (err, running) ->
         if running
           logAction name, "restarting..."
-          container.stop (err) ->
+          container.stop t:5, (err) ->
             container.start callback
         else
           logAction name, "starting..."
@@ -292,7 +292,7 @@
           return command.container.start callback if not running

           # container exists AND is running - stop, restart
-          return command.container.stop (err) ->
+          return command.container.stop t:5, (err) ->
             command.container.start callback

       logAction name, "creating..."
@@ -301,7 +301,7 @@

     stopIterator = (details, callback) ->
       container = docker.getContainer details.name
-      container.stop callback
+      container.stop t:5, callback

     resolveOrder @config, cluster, (list) ->
       async.eachSeries list, fetchIterator, (err) ->
@@ -311,7 +311,7 @@
           # @FIXME hack to avoid ghosts with quick start/stop combos
           setTimeout ->
             async.eachLimit list, 5, stopIterator, done
-          , 500
+          , 1000

   build: (image, done) ->


Export companies class

Export companies class

--- src/filings.coffee
+++ src/filings.coffee
@@ -3,3 +3,4 @@
   FormFour: require('./form-four')
   Connection: require('./connection')
   Transactions: require('./transactions')
+  Companies: require('./companies')


:fire: Remove useless method

:fire: Remove useless method

--- src/zenit-element.coffee
+++ src/zenit-element.coffee
@@ -73,6 +73,4 @@

     this

-  getModel: -> @model
-
 module.exports = ZenitElement = document.registerElement 'zenit-root', prototype: ZenitElement.prototype


Hydrator: reflect high-level hydration tasks in specs.

--- src/OVirtResponseHydrator.coffee
+++ src/OVirtResponseHydrator.coffee
@@ -54,14 +54,19 @@
 #
 # - Save attributes in corresponding property if existed.
 #
-# ### General tasks
-#
+# ### High level objects hydration.
+#
+# - If current node is a root one then current target should be a hydrator
+#   instance target.
 # - If current node is an owner of collections, resource links or actions
 #   (except the case when the node is a resource)then an API node instance
 #   should be created and set as a current target.
-# - If current node is a root one then current target should be a hydrator
-#   instance target.
-# - We should replace node value with current target (if exists).
+# - Node is a resource then new resource object instance should be created.
+# - Export attributes from node hash to current target.
+# - Remove attributes from node hash.
+# - Treat remaining node hash as a properties and export them to the current
+#   target.
+# - Finally we should replace node value with current target (if exists).
 #
 # ### Hydrate collections
 #
@@ -101,9 +106,7 @@
 #     + Delete link if it is an epty array or is undefined.
 #     + Remove special objects element from node children.
 #     + Use collection `rel` attribute as a collection name.
-#     + Detect whether current `xpath` points to root node.
-#     + If current node is a root one export collections to target node.
-#     - Otherwise export collections to the current target (should be an API
+#     - Export collections to the current target (should be an API
 #       node instance).
 #     + Clean current namespace of the `_collections` property.
 #
@@ -120,17 +123,14 @@
 #     + Detect that current node has a resource links.
 #     + Retrive resource links related to `xpath`.
 #     + Remove resource link child elements from target node.
-#     + If current node is a root one then export corresponding
-#       `_resourceLinks` namespace to target.
-#     - Otherwise export resource links to the current target (should be an API
-#       node instance).
+#     - Export corresponding `_resourceLinks` namespace to current target.
 #     + Remove related namespace from `_resourceLinks` property.
 #
 # ### Hydrate resources
 #
 # + Detect resources.
 # - Create a resource object and set as a current target.
-# + Replace node value with hydrated resource.
+# - Proceed with API node hydration procedure.
 #
 # ### Hydrate actions
 #


add isLoading to marker new

add isLoading to marker new

--- scripts/src/map/controllers.coffee
+++ scripts/src/map/controllers.coffee
@@ -159,6 +159,8 @@
         constructor: (@$scope, @$rootScope, @debounce, @$state, @$location, @MapService, @Restangular, @geolocation) ->
                 width = 320
                 height = 240
+
+                @$scope.isLoading = true

                 video = document.querySelector("#video")
                 """
@@ -179,6 +181,7 @@
                 @Restangular.all("scout/marker_category").getList().then((categories) =>
                         @$scope.marker_categories = angular.copy(categories)
                         @$scope.is_marker_categories_loaded = true
+                        @$scope.isLoading = false
                 )

                 @$scope.uploads = {}


这个发布是发布到变色龙平台，为了区别变色龙packages manager 暂时加上H5

--- menus/atom-chameleon.cson
+++ menus/atom-chameleon.cson
@@ -85,7 +85,7 @@
             'command': 'atom-chameleon:publish-application'
           }
           {
-            'label': 'Package'
+            'label': 'Html5 Package'
             'command': 'atom-chameleon:publish-package'
           }
         ]


added comment about query memory usage for toArray

--- app/coffee/PackManager.coffee
+++ app/coffee/PackManager.coffee
@@ -88,6 +88,10 @@

 		needMore = false  # keep track of whether we need to load more data
 		updates = [] # used to accumulate the set of results
+
+		# FIXME: packs are big so we should accumulate the results
+		# incrementally instead of using .toArray() to avoid reading all
+		# of the changes into memory
 		cursor.toArray (err, result) ->
 			unpackedSet = PackManager._unpackResults(result)
 			updates = PackManager._filterAndLimit(updates, unpackedSet, filterFn, limit)
@@ -141,6 +145,9 @@

 		updates = [] # used to accumulate the set of results

+		# FIXME: packs are big so we should accumulate the results
+		# incrementally instead of using .toArray() to avoid reading all
+		# of the changes into memory
 		cursor.toArray (err, result) ->
 			if err?
 				return callback err, result


Let's try to set the exit code on exit.

Let's try to set the exit code on exit.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -34,8 +34,11 @@

 updater = new MarketPlaceStockUpdater options
 updater.run (msg) ->
+  exitCode = 0
   if msg.status
     logger.info msg
-    process.exit 0
-  logger.error msg
-  process.exit 1
+  else
+    logger.error msg
+    exitCode = 1
+  process.on 'exit', ->
+    process.exit exitCode


Finalize bluebird implementation.

Finalize bluebird implementation.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -34,7 +34,7 @@
   logger.bunyanLogger.debug = -> # noop

 ProjectCredentialsConfig.create()
-.then (credentials) =>
+.then (credentials) ->
   options =
     config: credentials.enrichCredentials
       project_key: argv.projectKey
@@ -43,13 +43,13 @@
   getCountry = new GetCountry logger
   createCart = new CreateCart options
   getCountry.run(argv.ipAddress)
-  .then(country) ->
+  .then (country) ->
     createCart.run(country)
-  .catch (err) =>
+  .catch (err) ->
     logger.error err, "Problems while creating the cart."
-    @exitCode = 1
+    process.exit(1)
   .done()
-.catch (err) =>
+.catch (err) ->
   logger.error err, "Problems on getting client credentials from config files."
-  @exitCode = 1
+  process.exit(1)
 .done()


add AppView props

add AppView props

--- src/scripts/views/app-view.coffee
+++ src/scripts/views/app-view.coffee
@@ -6,7 +6,12 @@
 {HeaderView} = require '../views/header-view'

 class AppView extends React.Component
-  @propTypes: {}
+  @propTypes:
+    entries: React.PropTypes.array
+    entry: React.PropTypes.object
+    hasNext: React.PropTypes.bool
+    searchText: React.PropTypes.string
+    searchVisible: React.PropTypes.bool

   constructor: (props) ->
     super props
@@ -14,11 +19,11 @@
     @_onEntryChanged = @_onEntryChanged.bind @
     @_onSearchVisibleChanged = @_onSearchVisibleChanged.bind @
     @state =
-      entries: getEntryViewer().getAll()
-      entry: getEntryViewer().getSelectedEntry()
-      hasNext: false
-      searchText: getEntryViewer().getSearchText()
-      searchVisible: getEntryViewer().getSearchVisible()
+      entries: props.entries ? getEntryViewer().getAll()
+      entry: props.entry ? getEntryViewer().getSelectedEntry()
+      hasNext: props.hasNext ? false
+      searchText: props.searchText ? getEntryViewer().getSearchText()
+      searchVisible: props.searchVisible ? getEntryViewer().getSearchVisible()

   componentDidMount: ->
     emitter = getEntryViewer().getEventEmitter()


Removed create post view.

Removed create post view.

--- src/main/webapp/admin/app/controllers/posts.coffee
+++ src/main/webapp/admin/app/controllers/posts.coffee
@@ -5,58 +5,6 @@
 	"model/post_collection"
 	"views/jade"
 ], (CollectionController, app, Post, PostCollection, jade) ->
-
-	class CreatePostView extends CoffeeBar.TemplateController
-		events:
-			"click .btn-ok": "do_submit"
-			"click .btn-cancel": "do_cancel"
-
-		model: new Post()
-
-		template: jade["posts/create.jade"]
-		template_data: ->
-			model: @model
-			categories: app.categories.toJSON()
-
-		initialize: ->
-			super
-			app.categories.bind "all", @render, @
-
-		on_render: ->
-			# Backbone.ModelBinding.bind(@)
-			console.log "render"
-
-			@$("#title").val("")
-			@$("#author").val("")
-			@$("#text").val("")
-
-			@$("#tags").tagit()
-
-		do_cancel: ->
-			app.router.navigate "/posts", { trigger: true }
-			false
-
-		do_submit: ->
-			catId = @$("select#categorySelect option:selected").val()
-			cat = app.categories.get(catId)
-
-			tags = @$("#tags").tagit("assignedTags").map (tag) ->
-				c = app.tags.select (a) -> a.get("name") == tag
-				if (_.size(c) > 0)
-					_.first(c)
-				else
-					{id: 0, name: tag}
-
-			@model.set
-				title: @$("#title").val()
-				author: @$("#author").val()
-				text: @$("#text").val()
-				category: cat
-				tags: tags
-
-			@model.save()
-			app.router.navigate "/posts", { trigger: true }
-			false

 	class EditPostView extends CoffeeBar.TemplateController
 		events:
@@ -150,7 +98,7 @@
 		app.page new PostsPage

 	app.router.route "/posts/create", "posts", ->
-		app.page new CreatePostView
+		app.page new EditPostView({ model: new Post, template: jade["posts/create.jade"] })

 	app.router.route "/posts/edit/:id", "posts", (id) ->
 		post = new Post({id: id})


Call grammar updated on registry

Call grammar updated on registry

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -54,7 +54,7 @@
   grammarUpdated: (scopeName) ->
     return false unless _.include(@includedGrammarScopes, scopeName)
     @clearRules()
-    atom.syntax.grammarUpdated(@scopeName)
+    @registry.grammarUpdated(@scopeName)
     @emit 'grammar-updated'
     true


Serialize only patches

Serialize only patches

--- src/history.coffee
+++ src/history.coffee
@@ -1,6 +1,6 @@
 Patch = require 'atom-patch'

-SerializationVersion = 3
+SerializationVersion = 4

 class Checkpoint
   constructor: (@id, @snapshot, @isBoundary) ->
@@ -282,15 +282,10 @@
             type: 'group-end'
             snapshot: @delegate.serializeSnapshot(entry.snapshot)
           }
-        when Patch
+        else
           {
             type: 'patch'
             content: entry.serialize()
-          }
-        else
-          {
-            type: 'change'
-            content: @delegate.serializeChange(entry)
           }

   deserializeStack: (stack) ->
@@ -312,5 +307,3 @@
           )
         when 'patch'
           Patch.deserialize(entry.content)
-        when 'change'
-          @delegate.deserializeChange(entry.content)


網易還有很多數據可以取得

網易還有很多數據可以取得

--- src/history.coffee
+++ src/history.coffee
@@ -33,3 +33,11 @@

 module.exports = quotes
+###json版:
+'http://img1.money.126.net/data/hs/kline/day/history/2016/1159915.json?callback=ne3fee324' -H 'DNT: 1'
+http://api.money.126.net/data/feed/1159915?callback=ne238022ffc
+http://img1.money.126.net/data/hs/kline/week/times/1159915.json?callback=ne2ddf44564
+http://img1.money.126.net/data/hs/kline/week/history/2014/1159915.json?callback=neb4dd2a3
+http://img1.money.126.net/data/hs/kline/week/history/2015/1159915.json?callback=ne2a87574d4
+http://img1.money.126.net/data/hs/kline/week/history/2016/1159915.json?callback=ne4b98d328
+###


chore: Remove leftover file

chore: Remove leftover file

This script isn't needed anymore. It was fully replaced by Sphinx extention
in docs/_extensions/generate-cli-docs.coffee

--- scripts/generate-cli-docs.coffee
+++ scripts/generate-cli-docs.coffee
@@ -1,43 +0,0 @@
-# Generates CLI docs for Dredd.
-#
-# Purpose:
-#   Thanks to this we can be sure the CLI docs are always up-to-date.
-#
-# Usage:
-#   The script is a part of the command for building documentation:
-#
-#       $ npm run docs:build
-
-fs = require('fs')
-path = require('path')
-ect = require('ect')
-clone = require('clone')
-
-options = require('../src/options')
-
-
-DOCS_DIR = path.join(__dirname, '..', 'docs')
-TEMPLATE_DOCUMENT = 'usage-cli.md-template'
-OUTPUT_DOCUMENT = 'usage-cli.md'
-
-
-# Turn options into a sorted array
-data = {options: []}
-
-for own name, attributes of options
-  option = clone(attributes)
-  option.description = option.description.trim()
-  option.name = name
-  data.options.push(option)
-
-data.options.sort((o1, o2) ->
-  switch
-    when o1.name < o2.name then -1
-    when o1.name > o2.name then 1
-    else 0
-)
-
-
-renderer = ect({root: DOCS_DIR})
-html = renderer.render(TEMPLATE_DOCUMENT, data)
-fs.writeFileSync(path.join(DOCS_DIR, OUTPUT_DOCUMENT), html)


fix category order

fix category order

--- scripts/import_coppermine.coffee
+++ scripts/import_coppermine.coffee
@@ -46,7 +46,7 @@
   breadcrumb = makeBreadcrumb parent

   # get root category
-  query('SELECT cid, name, description FROM cpg11d_categories WHERE parent = ? ORDER BY pos DESC', [categoryId]).spread (categories) ->
+  query('SELECT cid, name, description FROM cpg11d_categories WHERE parent = ? ORDER BY pos', [categoryId]).spread (categories) ->
     Q.all categories.map (coppermineCategory) ->
       return null if coppermineCategory.cid in CATEGORY_BLACKLIST


Remove weird loading hack

Remove weird loading hack

--- src/smc-webapp/project_files.cjsx
+++ src/smc-webapp/project_files.cjsx
@@ -24,16 +24,11 @@
 ButtonToolbar, Popover, OverlayTrigger, SplitButton, MenuItem, Alert, Checkbox, Breadcrumb, Navbar} =  require('react-bootstrap')
 misc = require('smc-util/misc')
 {ActivityDisplay, DirectoryInput, Icon, ProjectState, COLORS,
-SearchInput, TimeAgo, ErrorDisplay, Space, Tip, LoginLink, Footer, CourseProjectExtraHelp, CopyToClipBoard} = require('./r_misc')
+SearchInput, TimeAgo, ErrorDisplay, Space, Tip, Loading, LoginLink, Footer, CourseProjectExtraHelp, CopyToClipBoard} = require('./r_misc')
 {SMC_Dropwrapper} = require('./smc-dropzone')
 {FileTypeSelector, NewFileButton} = require('./project_new')
 {SiteName} = require('./customize')
 {file_actions} = require('./project_store')
-
-Loading = () ->
-    <div>
-        Loading...
-    </div>

 {BillingPageLink, BillingPageForCourseRedux, PayCourseFee}     = require('./billing')
 {human_readable_size} = misc


Remove clunky tool-tips

Remove clunky tool-tips

--- src/smc-webapp/project_files.cjsx
+++ src/smc-webapp/project_files.cjsx
@@ -357,6 +357,7 @@
         if @props.file_search?.indexOf('.') == -1
           "sagews"

+    # Go to the new file tab if there is no file search
     handle_click : ->
         if not @props.file_search?.length > 0
             @props.actions.set_focused_page('project-new-file')
@@ -365,30 +366,19 @@

     button_text : ->
         ext = @extension()
-        if ext and @props.file_search?.length > 0
+        if not @props.file_search?.length > 0
+            "Create or upload files..."
+        else if ext and @props.file_search.slice(-1) isnt '/'
             "Create #{@props.file_search}.#{ext}"
-        else if not @props.file_search?.length > 0
-            "Create or upload files..."
         else
             "Create #{@props.file_search}"

-    tip_text : ->
-        ext = @extension()
-        if ext == "sagews"
-            "Defaults to sagews. Add an extension to create something else."
-        else if not ext and @props.file_search?.length > 0
-            "Click here to create your file."
-        else
-            "Input a file name above or click the new files page."
-
     render_new_button : ->
-        <Tip title="Create Button" tip={@tip_text()} placement="left">
-            <Button
-                style   = {fontSize:'40px', color:'#888'}
-                onClick = {=>@handle_click()}>
-                <Icon name='plus-circle' /> {@button_text()}
-            </Button>
-        </Tip>
+        <Button
+            style   = {fontSize:'40px', color:'#888'}
+            onClick = {=>@handle_click()}>
+            <Icon name='plus-circle' /> {@button_text()}
+        </Button>

     render : ->
         <div style={textAlign:'center', color:'#888', marginTop:'20px'} >


- added processor

- added processor

--- src/code/crystal/generate.coffee
+++ src/code/crystal/generate.coffee
@@ -173,6 +173,13 @@
 				when 'generators'
 					mod_path += 'gen'
 			mod_path += "/#{mod_name}/#{mod.version}/src"
+
+			# process spec
+			if fs.existsSync "#{mod_path}/proc"
+				for file in readdir "#{mod_path}/proc"
+					project.src.spec = require("#{mod_path}/proc/#{file}")(project.src.spec)
+					if project.src.spec == false
+						throw new Error "Module (#{mod_name}) was unable to process specification."

 			switch mod_type
 				when 'generators'


fix comment on server

fix comment on server

--- server/controllers/messages.coffee
+++ server/controllers/messages.coffee
@@ -435,7 +435,7 @@
         return next err if err
         res.send updatedMessages

-# move several message to trash with one request
+# move several message with one request
 # expect req.account & req.messages
 # aim :
 #   - the conversation should not appears in from


removed the default height setting for the map

--- src/components/store_list.coffee
+++ src/components/store_list.coffee
@@ -70,6 +70,5 @@
 module.exports.render = (stores) ->
   $('#content').empty().append store_list
     stores: stores
-  document.getElementById('map').style.height = "40vh"
   document.getElementById('map').style.position = "relative"
   $('#content').addClass 'results'


some work, eh, I'll try to implement this API tomorrow.

--- src/keybundle.iced
+++ src/keybundle.iced
@@ -2,11 +2,14 @@
 {RSA} = require './rsa'
 K = require('./const').kb
 {make_esc} = require 'iced-error'
+{bufferify} = require './util'

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

 class Encryption
-  constructor : ({@tsenc, @passphrase}) ->
+  constructor : ({@tsenc, passphrase}) ->
+    @passphrase = bufferify passphrase
+    @tsenc or= new triplesec.Encryptor { version : 2, @passphrase }

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

@@ -36,7 +39,13 @@
 class Bundle

   constructor : ({@primary, @subkeys, @userids}) ->
+    @tsenc = null

+  #========================
+  # Public Interface
+
+  # Generate a new key bunlde from scratch.  Make the given number
+  # of subkeys.
   @generate : ({asp, nsubs, userids }, cb) ->
     esc = make_esc cb, "Bundle::generate"
     asp.section "primary"
@@ -49,24 +58,63 @@
     ring = new Bundle { primary, subkeys, userids }
     cb null, ring

-  @import_from_armored_pgp_private : ({raw, passphrase, asp}, cb) ->
+  #------------

+  # The triplesec encoder will be primed (hopefully) with the output
+  # of running Scrypt on the new passphrase, and the user's actual
+  # salt.  We'll need this to encrypt server-stored key, or to derive
+  # the key to encrypt a PGP secret key with s2k/AES-128-CFB.
+  set_enc : (e) -> @tsenc = e
+
+  #------------
+
+  # Start from an armored PGP PUBLIC KEY BLOCK, and parse it into packets.
   @import_from_armored_pgp_public : ({raw, asp}, cb) ->
+
+  #------------
+
+  # Verify a key for sanity, and check its signatures, and that the keys
+  # haven't expired.
+  verify : ({asp}, cb) ->
+
+  #------------
+
+  # After importing the public portion of the key previously,
+  # add the private portions with this call.  And again, verify
+  # signatures.  And check that the public portions agree.
+  add_armored_pgp_private : ({raw, asp}, cb) ->
+
+  #------------
+
+  # Open the private PGP key with the given passphrase
+  # (which is going to be different from our strong keybase passphrase).
+  open_pgp : ({passphrase}, cb) ->
+
+  # Open the private MPIs of the secret key, and check for sanity.
+  # Use the given triplesec.Encryptor / password object.
+  open_keybase : ({asp}, cb) ->

   # The export consists of
   #   1. A PGP message (potentially redacted from upload)
   #   2. A keybase message (Public key only)
-  export_to_server_public_only : ({asp}, cb) ->
+  export_public_to_server : ({asp}, cb) ->

   # A private export consists of:
   #   1. The redacted PGP message
   #   2. The keybase message (Public and private keys)
-  export_to_server_private : ({asp}, cb) ->
+  export_private_to_server : ({asp}, cb) ->

   # Export to a PGP PRIVATE KEY BLOCK, stored in PGP format
-  # We'll need to reencrypt with a derived
-  export_to_client : (cb) ->
+  # We'll need to reencrypt with a derived key
+  export_pgp_private_to_client : ({asp}, cb) ->

+  # Export the PGP PUBLIC KEY BLOCK stored in PGP format
+  # to the client...
+  export_pgp_public_to_client : ({asp}, cb) ->
+
+  # /Public Interface
+  #========================
+
   sign_pgp : ({asp}, cb) ->

   sign_keybase : ({asp}, cb) ->


Fix text selection bug with negative indices

--- src/controller.coffee
+++ src/controller.coffee
@@ -1390,7 +1390,7 @@
     row = Math.max row, 0
     row = Math.min row, textFocusView.lineLength - 1

-    column = Math.round((point.x - textFocusView.bounds[row].x - @view.opts.padding) / @mainCtx.measureText(' ').width)
+    column = Math.max 0, Math.round((point.x - textFocusView.bounds[row].x - @view.opts.padding) / @mainCtx.measureText(' ').width)

     lines = @textFocus.stringify().split('\n')[..row]
     lines[lines.length - 1] = lines[lines.length - 1][...column]


Fix cursor bug

Fix cursor bug

--- src/controller.coffee
+++ src/controller.coffee
@@ -2305,7 +2305,7 @@

   Editor::moveCursorUp = ->
     unless @cursor.prev? then return
-    @cursor = @cursor.prev
+    head = @cursor.prev?.prev

     @highlightFlashShow()


Fix animation bug

Fix animation bug

--- src/controller.coffee
+++ src/controller.coffee
@@ -2505,8 +2505,8 @@

           # Skip anything that's
           # off the screen the whole time.
-          unless 0 < textElement.bounds[0].y - @scrollOffsets.main.y < @mainCanvas.height or
-                 0 < textElement.bounds[0].y - @scrollOffsets.main.y + translationVectors[i].y < @mainCanvas.height
+          unless 0 < textElement.bounds[0].bottom() - @scrollOffsets.main.y + translationVectors[i].y and
+                   textElement.bounds[0].y - @scrollOffsets.main.y + translationVectors[i].y < @mainCanvas.height
             continue

           div = document.createElement 'div'
@@ -2518,7 +2518,7 @@
           div.style.position = 'absolute'

           div.style.left = "#{textElement.bounds[0].x - @scrollOffsets.main.x + translationVectors[i].x}px"
-          div.style.top = "#{textElement.bounds[0].y + @scrollOffsets.main.y + translationVectors[i].y}px"
+          div.style.top = "#{textElement.bounds[0].y - @scrollOffsets.main.y + translationVectors[i].y}px"

           div.className = 'ice-transitioning-element'
           translatingElements.push div
@@ -2528,7 +2528,7 @@
           do (div, textElement) =>
             setTimeout (=>
               div.style.left = "#{textElement.bounds[0].x - @scrollOffsets.main.x}px"
-              div.style.top = "#{textElement.bounds[0].y + @scrollOffsets.main.y}px"
+              div.style.top = "#{textElement.bounds[0].y - @scrollOffsets.main.y}px"
             ), 0

         top = Math.max @aceEditor.getFirstVisibleRow(), 0


added a synchronous copy command

added a synchronous copy command

--- platforms/node/tools/files.coffee
+++ platforms/node/tools/files.coffee
@@ -68,7 +68,26 @@

         fs.readFileSync normpath(name), enc

-
+
+    ##
+    ##
+    cp: (srcFile, destFile) ->
+        buff = new Buffer BUF_LENGTH = 64*1024
+
+        fdr = fs.openSync srcFile, 'r'
+        fdw = fs.openSync destFile, 'w'
+
+        bytesRead = 1
+        pos = 0
+        while bytesRead > 0
+          bytesRead = fs.readSync fdr, buff, 0, BUF_LENGTH, pos
+          fs.writeSync fdw,buff,0,bytesRead
+          pos += bytesRead
+
+        fs.closeSync fdr
+        fs.closeSync fdw
+
+
     ##
     ##
     mv: (old_name, new_name...)->


Preload image after every URL change

Preload image after every URL change

--- src/trix/models/attachment.coffee
+++ src/trix/models/attachment.coffee
@@ -112,7 +112,7 @@

   preloadURL: ->
     url = @getURL()
-    if url? and not @preloadOperation
+    if url? and url isnt @preloadOperation?.url
       @preloadOperation = new Trix.ImagePreloadOperation url
       @preloadOperation.then ({width, height}) =>
         @setAttributes({width, height})


添加一处非空保护

添加一处非空保护

--- src/core/model.coffee
+++ src/core/model.coffee
@@ -1105,14 +1105,14 @@
 	get: (path, loadMode, context) ->
 		alias = @alias

-		if path.charCodeAt(0) is 64 # `@`
+		if path?.charCodeAt(0) is 64 # `@`
 			i = path.indexOf('.')
 			firstPart = if i > 0 then path.substring(0, i) else path
 			firstPart = @get(firstPart.substring(1))
 			path = firstPart + if i > 0 then path.substring(i + 1) else ""

 		aliasLen = alias.length
-		if path and path.substring(0, aliasLen) is alias
+		if path?.substring(0, aliasLen) is alias
 			c = path.charCodeAt(aliasLen)
 			if c is 46 # `.`
 				if path.indexOf(".") > 0


Fix a minor typo

Fix a minor typo

--- app/routes/application.coffee
+++ app/routes/application.coffee
@@ -15,7 +15,7 @@
     store = @get "store"
     allEvents =
       analysis_new: (data)->
-        store.push store.normalize "analyses", data
+        store.push store.normalize "analysis", data

       analysis_updated: (data)->
         risk = data.risk


adds a transient hint for gnome

adds a transient hint for gnome

--- src/ui/views/notifications.coffee
+++ src/ui/views/notifications.coffee
@@ -90,6 +90,8 @@
                       else
                           i18n.__('conversation.new_message:New Message')
                 wait: true
+                hint: "int:transient:1"
+                category: 'im.received'
                 sender: 'com.github.yakyak'
                 sound: !viewstate.muteSoundNotification && (notifierSupportsSound && !viewstate.forceCustomSound)
                 icon: icon if !isNotificationCenter && viewstate.showIconNotification


Guard against null rootView

Guard against null rootView

This will be the case for the config window.

--- src/app/window-event-handler.coffee
+++ src/app/window-event-handler.coffee
@@ -13,7 +13,7 @@
     @subscribe $(window), 'focus', -> $("body").removeClass('is-blurred')
     @subscribe $(window), 'blur',  -> $("body").addClass('is-blurred')
     @subscribe $(window), 'window:open-path', (event, pathToOpen) ->
-      rootView.open(pathToOpen) unless fsUtils.isDirectory(pathToOpen)
+      rootView?.open(pathToOpen) unless fsUtils.isDirectory(pathToOpen)

     @subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen()
     @subscribeToCommand $(window), 'window:close', =>


<controller> Measure - Adding routes (unfinished).

--- server/controllers/routes.coffee
+++ server/controllers/routes.coffee
@@ -22,7 +22,13 @@
     'measureId':      param: measure.fetch
     'driverId':       param: driver.fetch
     'sensorRuleId':   param: sensorRule.fetch
-    'actuatorRuleId': param: actuatorRule.fetch
+    'actuatorRuleId': param: actuatorRule.fetch
+    'minTime':        param: (req, res, next, val) ->
+        req.minTime = new Date(val)
+        next()
+    'maxTime':        param: (req, res, next, val) ->
+        req.maxTime = new Date(val)
+        next()

     'sensors/?':
         get: sensor.all
@@ -31,6 +37,12 @@
     'sensors/:sensorId/measures?':
         # @todo Get by Sensor + Date (opt): get: sensor.getMeasuresByDate
         post: sensor.createMeasure
+        get: sensor.allMeasuresByTimeRange
+
+    'sensors/:sensorId/measures/:measureId?':
+        get: measure.read
+        put: measure.update
+        delete: measure.delete

     'sensors/:sensorId/?':
         get: sensor.read


Disable submitSubmits

Disable submitSubmits

--- server/cron/submitSubmits.coffee
+++ server/cron/submitSubmits.coffee
@@ -98,6 +98,7 @@

 submitSubmits = () ->
+    return
     pendingSubmits = await Submit.findPendingSubmits()
     await Promise.all(pendingSubmits.map(submitOneSubmit))


Fixed bug where SCI/SAP/RELTO labels couldn't be added unless classification also changed

--- server/methods/updateRoom.coffee
+++ server/methods/updateRoom.coffee
@@ -21,7 +21,7 @@
 			Meteor.call 'saveRoomName', rid, name

 		# relabel room if permissions changed
-		if _.difference( room.accessPermissions, accessPermissions ).length > 0
+		if _.difference( accessPermissions, room.accessPermissions ).length > 0
 			Meteor.call 'relabelRoom', rid, accessPermissions

 		# add users to the room that weren't previously in the room


fixing product form validation bug

fixing product form validation bug

--- app/assets/javascripts/mobile/product_form_validation_rules.js.coffee
+++ app/assets/javascripts/mobile/product_form_validation_rules.js.coffee
@@ -31,14 +31,15 @@
                     # quantity is required if unlimited quantity isn't checked
                     # quantity becomes disabled when unlimited quantity is checked

-for _flatrate_shipping_option in gon.flatrate_shipping_options
-    flatrate_shipping_option = "#product_#{_flatrate_shipping_option}_flatrate_shipping_cost"
+if gon.flatrate_shipping_options?
+    for _flatrate_shipping_option in gon.flatrate_shipping_options
+        flatrate_shipping_option = "#product_#{_flatrate_shipping_option}_flatrate_shipping_cost"

-    product_form_validation_rules['fields'][flatrate_shipping_option] =
-        message: "Valid #{GramGoods.capitalize(_flatrate_shipping_option)} Flatrate Shipping Price is required. (e.g. 9.99)"
-        required: 'sometimes'
-        test: (val) ->
-            if val is ''
-                true
-            else
-                happy.is_valid_price(val)
+        product_form_validation_rules['fields'][flatrate_shipping_option] =
+            message: "Valid #{GramGoods.capitalize(_flatrate_shipping_option)} Flatrate Shipping Price is required. (e.g. 9.99)"
+            required: 'sometimes'
+            test: (val) ->
+                if val is ''
+                    true
+                else
+                    happy.is_valid_price(val)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -25,7 +25,8 @@
 # => Sets up a health meter that will be drawn during the enemy overlay event.
 # Since maxHealth wasn't provided, it is set to the value of I.health (500)

-someOtherObject.meter 'he'
+someOtherObject.meter 'turbo'
+# =>

 # now player has all the methods provided by this module


Add a shorthand for method names.

Add a shorthand for method names.

--- src/methods.coffee
+++ src/methods.coffee
@@ -64,7 +64,7 @@
   java:
     lang:
       Class: [
-        o 'newInstance0()Ljava/lang/Object;', (rs) -> #implemented here to avoid reflection
+        o 'newInstance0()L!/!/Object;', (rs) -> #implemented here to avoid reflection
             classname = rs.get_obj(rs.curr_frame().locals[0]).obj.name
             rs.push (oref = rs.init_object(classname))
             rs.method_lookup({'class':classname,'sig':{'name':'<init>'}}).run(rs)
@@ -76,11 +76,11 @@
         ]
       System: [
         o 'setJavaLangAccess()V', (rs) -> # NOP
-        o 'loadLibrary(Ljava/lang/String;)V', (rs) ->
+        o 'loadLibrary(L!/!/String;)V', (rs) ->
             args = rs.curr_frame().locals
             lib = rs.jvm2js_str rs.get_obj args[0]
             error "Attempt to load library '#{lib}' failed: library loads are NYI"
-        o 'adjustPropertiesForBackwardCompatibility(Ljava/util/Properties;)V', (rs) -> #NOP (apple-java specific?)
+        o 'adjustPropertiesForBackwardCompatibility(L!/util/Properties;)V', (rs) -> #NOP (apple-java specific?)
       ]
       Terminator: [
         o 'setup()V', (rs) -> #NOP
@@ -93,7 +93,7 @@
             o 'compareAndSet(II)Z', (rs) -> rs.push 1  # always true
           ]
           AtomicReferenceFieldUpdater: [
-            o 'newUpdater(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;)Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;', (rs) -> rs.push 0 # null
+            o 'newUpdater(L!/lang/Class;L!/lang/Class;L!/lang/String;)L!/!/!/!/!;', (rs) -> rs.push 0 # null
           ]
         locks:
           AbstractQueuedSynchronizer: [
@@ -104,14 +104,14 @@
     nio:
       charset:
         Charset$3: [
-          o 'run()Ljava/lang/Object;', (rs) -> rs.push 0 # null
+          o 'run()L!/lang/Object;', (rs) -> rs.push 0 # null
         ]
       Bits: [
-        o 'byteOrder()Ljava/nio/ByteOrder;', (rs) -> rs.static_get {'class':'java/nio/ByteOrder','sig':{'name':'LITTLE_ENDIAN'}}
+        o 'byteOrder()L!/!/ByteOrder;', (rs) -> rs.static_get {'class':'java/nio/ByteOrder','sig':{'name':'LITTLE_ENDIAN'}}
       ]
     io:
       PrintStream: [
-        o 'write(Ljava/lang/String;)V', (rs) ->
+        o 'write(L!/lang/String;)V', (rs) ->
             args = rs.curr_frame().locals
             str = rs.jvm2js_str(rs.get_obj(args[1]))
             rs.static_get {'class':'java/lang/System','sig':{'name':'out'}}; sysout = rs.pop()
@@ -126,7 +126,7 @@
   sun:
     misc:
       Unsafe: [
-        o 'getUnsafe()Lsun/misc/Unsafe;', (rs) -> # avoid reflection
+        o 'getUnsafe()L!/!/!;', (rs) -> # avoid reflection
             rs.static_get({'class':'sun/misc/Unsafe','sig':{'name':'theUnsafe'}})
       ]

@@ -141,20 +141,20 @@
   java:
     lang:
       Class: [
-        o 'getPrimitiveClass(Ljava/lang/String;)Ljava/lang/Class;', (rs) ->
+        o 'getPrimitiveClass(L!/!/String;)L!/!/!;', (rs) ->
             str = rs.get_obj(rs.curr_frame().locals[0])
             carr = rs.get_obj(str.obj.value).obj.array
             name = (String.fromCharCode(c) for c in carr).join('') # XXX convert to unicode
             rs.push rs.set_obj 'java/lang/Class', { name: name }
-        o 'getClassLoader0()Ljava/lang/ClassLoader;', (rs) -> rs.push 0  # we don't need no stinkin classloaders
-        o 'desiredAssertionStatus0(Ljava/lang/Class;)Z', (rs) -> rs.push 0 # we don't need no stinkin asserts
-        o 'getName0()Ljava/lang/String;', (rs) -> rs.push rs.init_string(rs.get_obj(rs.curr_frame().locals[0]).obj.name)
-        o 'forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;', (rs) ->
+        o 'getClassLoader0()L!/!/ClassLoader;', (rs) -> rs.push 0  # we don't need no stinkin classloaders
+        o 'desiredAssertionStatus0(L!/!/!;)Z', (rs) -> rs.push 0 # we don't need no stinkin asserts
+        o 'getName0()L!/!/String;', (rs) -> rs.push rs.init_string(rs.get_obj(rs.curr_frame().locals[0]).obj.name)
+        o 'forName0(L!/!/String;ZL!/!/ClassLoader;)L!/!/!;', (rs) ->
             jvm_str = rs.get_obj(rs.curr_frame().locals[0])
             classname = rs.jvm2js_str(jvm_str).replace(/\./g,'/')
             throw "Class.forName0: Failed to load #{classname}" unless rs.class_lookup(classname)
             rs.push rs.set_obj 'java/lang/Class', { name:classname }
-        o 'getComponentType()Ljava/lang/Class;', (rs) ->
+        o 'getComponentType()L!/!/!;', (rs) ->
             type = rs.get_obj(rs.curr_frame().locals[0]).obj.name
             component_type = /\[+(.*)/.exec(type)[1]
             rs.push rs.set_obj 'java/lang/Class', name:component_type
@@ -178,7 +178,7 @@
             rs.push util.lshift(sign,63)+util.lshift(exp+1023,52)+sig, null
       ]
       Object: [
-        o 'getClass()Ljava/lang/Class;', (rs) ->
+        o 'getClass()L!/!/Class;', (rs) ->
             _this = rs.get_obj(rs.curr_frame().locals[0])
             rs.push rs.set_obj 'java/lang/Class', { name:util.ext_classname _this.type}
         o 'hashCode()I', (rs) ->
@@ -188,16 +188,16 @@
       ]
       reflect:
         Array: [
-          o 'newArray(Ljava/lang/Class;I)Ljava/lang/Object;', (rs) ->
-            type = rs.get_obj(rs.curr_frame().locals[0]).obj.name
-            len = rs.curr_frame().locals[0]
-            rs.heap_newarray util.int_classname type, len
+          o 'newArray(L!/!/Class;I)L!/!/Object;', (rs) ->
+              type = rs.get_obj(rs.curr_frame().locals[0]).obj.name
+              len = rs.curr_frame().locals[0]
+              rs.heap_newarray util.int_classname type, len
         ]
       StrictMath: [
         o 'pow(DD)D', (rs) -> rs.push Math.pow(rs.cl(0),rs.cl(2)), null
       ]
       String: [
-        o 'intern()Ljava/lang/String;', (rs) ->
+        o 'intern()L!/!/!;', (rs) ->
             str_ref = rs.curr_frame().locals[0]
             js_str = rs.jvm2js_str(rs.get_obj(str_ref))
             unless rs.string_pool[js_str]
@@ -205,7 +205,7 @@
               rs.push rs.string_pool[js_str]
       ]
       System: [
-        o 'arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V', (rs) ->
+        o 'arraycopy(L!/!/Object;IL!/!/Object;II)V', (rs) ->
             args = rs.curr_frame().locals
             src_array = rs.get_obj(args[0]).obj.array
             src_pos = args[1]
@@ -216,7 +216,7 @@
             for i in [src_pos...src_pos+length]
               dest_array[j++] = src_array[i]
         o 'currentTimeMillis()J', (rs) -> rs.push (new Date).getTime(), null
-        o 'initProperties(Ljava/util/Properties;)Ljava/util/Properties;', (rs) ->
+        o 'initProperties(L!/util/Properties;)L!/util/Properties;', (rs) ->
             p_ref = rs.curr_frame().locals[0]
             m = rs.method_lookup({'class':'java/util/Properties','sig':{'name':'setProperty'}})
             # properties to set:
@@ -229,33 +229,33 @@
               m.run(rs)
               rs.pop()  # we don't care about the return value
             rs.push p_ref
-        o 'setIn0(Ljava/io/InputStream;)V', (rs) ->
+        o 'setIn0(L!/io/InputStream;)V', (rs) ->
             rs.push rs.curr_frame().locals[0] # move oref to the stack for static_put
             rs.static_put {'class':'java/lang/System','sig':{'name':'in'}}
-        o 'setOut0(Ljava/io/PrintStream;)V', (rs) ->
+        o 'setOut0(L!/io/PrintStream;)V', (rs) ->
             rs.push rs.curr_frame().locals[0] # move oref to the stack for static_put
             rs.static_put {'class':'java/lang/System','sig':{'name':'out'}}
-        o 'setErr0(Ljava/io/PrintStream;)V', (rs) ->
+        o 'setErr0(L!/io/PrintStream;)V', (rs) ->
             rs.push rs.curr_frame().locals[0] # move oref to the stack for static_put
             rs.static_put {'class':'java/lang/System','sig':{'name':'err'}}
       ]
       Thread: [
-        o 'currentThread()Ljava/lang/Thread;', (rs) -> rs.push rs.set_obj 'java/lang/Thread' # mock thread
+        o 'currentThread()L!/!/!;', (rs) -> rs.push rs.set_obj 'java/lang/Thread' # mock thread
       ]
       Throwable: [
-        o 'fillInStackTrace()Ljava/lang/Throwable;', (rs) ->
+        o 'fillInStackTrace()L!/!/!;', (rs) ->
             #TODO possibly filter out the java calls from our own call stack.
             # at the moment, this is effectively a NOP.
             rs.push rs.curr_frame().locals[0]
       ]
     security:
       AccessController: [
-        o 'doPrivileged(Ljava/security/PrivilegedAction;)Ljava/lang/Object;', doPrivileged
-        o 'doPrivileged(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;', doPrivileged
+        o 'doPrivileged(L!/!/PrivilegedAction;)L!/lang/Object;', doPrivileged
+        o 'doPrivileged(L!/!/PrivilegedExceptionAction;)L!/lang/Object;', doPrivileged
       ]
     io:
       FileSystem: [
-        o 'getFileSystem()Ljava/io/FileSystem;', (rs) -> rs.heap_new('java/io/UnixFileSystem')
+        o 'getFileSystem()L!/!/!;', (rs) -> rs.heap_new('java/io/UnixFileSystem')
       ]
       FileOutputStream: [
         o 'writeBytes([BII)V', (rs) ->
@@ -278,16 +278,27 @@

 flatten_pkg = (pkg) ->
   result = {}
-  for pkg_name, inner_pkg of pkg
-    if inner_pkg instanceof Array
-      for method in inner_pkg
-        {fn_name, fn} = method
-        result["#{pkg_name}::#{fn_name}"] = fn
-    else
-      flattened_inner = flatten_pkg inner_pkg
-      for name, method of flattened_inner
-        fullname = "#{pkg_name}/#{name}"
-        result[fullname] = method
+  pkg_name_arr = []
+  rec_flatten = (pkg) ->
+    for pkg_name, inner_pkg of pkg
+      pkg_name_arr.push pkg_name
+      if inner_pkg instanceof Array
+        for method in inner_pkg
+          {fn_name, fn} = method
+          # expand out the '!'s in the method names
+          fn_name = fn_name.replace /!|;/g, (->
+            depth = 0
+            (c) ->
+              if c == '!' then pkg_name_arr[depth++]
+              else if c == ';' then depth = 0; c
+              else c
+          )()
+          full_name = "#{pkg_name_arr.join '/'}::#{fn_name}"
+          result[full_name] = fn
+      else
+        flattened_inner = rec_flatten inner_pkg
+      pkg_name_arr.pop pkg_name
+  rec_flatten pkg
   result

 trapped_methods = flatten_pkg trapped_methods


Add viewport tag

Add viewport tag

--- server/ssr/renderOnServer.coffee
+++ server/ssr/renderOnServer.coffee
@@ -26,6 +26,7 @@
             <link rel="stylesheet" href="/bundle.css"/>
             <link rel="stylesheet" href="/informatics.css"/>
             <link rel="stylesheet" href="/bootstrap.min.css"/>
+            <meta name="viewport" content="width=device-width, initial-scale=1">
             <script>
                 window.__PRELOADED_STATE__ = ' + JSON.stringify(data) + ';
             </script>


Added a handler for fetching a user id given a name.

--- server/users/user_handler.coffee
+++ server/users/user_handler.coffee
@@ -130,6 +130,14 @@
       res.send results
       res.end()

+  nameToID: (req, res, name) ->
+#    t0 = new Date().getTime()
+#    console.log 'query starts', {nameLower:name.toLowerCase()}
+    User.findOne({nameLower:name.toLowerCase()}, {_id:1}).exec (err, otherUser) ->
+#      console.log 'query ends', new Date().getTime() - t0
+      res.send(otherUser._id.toString()) if otherUser
+      res.end()
+
   post: (req, res) ->
     return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
     return @sendBadInputError(res, 'Must have an anonymous user to post with.') unless req.user
@@ -147,6 +155,7 @@
     return @agreeToCLA(req, res) if args[1] is 'agreeToCLA'
     return @avatar(req, res, args[0]) if args[1] is 'avatar'
     return @getNamesByIds(req, res) if args[1] is 'names'
+    return @nameToID(req, res, args[0]) if args[1] is 'nameToID'
     return @sendNotFoundError(res)

   agreeToCLA: (req, res) ->


Adding an exception to the size0 function.

--- src/natives.coffee
+++ src/natives.coffee
@@ -1358,7 +1358,10 @@
           # Reports this file's size
           o 'size0(Ljava/io/FileDescriptor;)J', (rs, _this, fd_obj) ->
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
-            return gLong.fromNumber(fs.fstatSync(fd).size)
+            try
+              return fs.fstatSync(fd).size
+            catch e
+              rs.java_throw rs.get_bs_class('Ljava/io/IOException;'), 'Bad file descriptor.'
         ]
         FileDispatcher: [
           o 'init()V', (rs) -> # NOP


Optimize by doing more opcode pre-compiling.

--- src/opcodes.coffee
+++ src/opcodes.coffee
@@ -112,12 +112,16 @@
   _execute: (rs) -> rs.put_cl(@index,rs.cl(@index)+@const)

 class root.LoadOpcode extends root.Opcode
+  constructor: (name, params={}) ->
+    params.execute ?=
+      if name.match /[ld]load/
+        (rs) -> rs.push rs.cl(@var_num), null
+      else
+        (rs) -> rs.push rs.cl(@var_num)
+    super name, params
+
   take_args: (code_array) ->
     @var_num = parseInt @name[6]  # sneaky hack, works for name =~ /.load_\d/
-
-  _execute: (rs) ->
-    rs.push rs.cl(@var_num)
-    rs.push null if @name.match /[ld]load/

 class root.LoadVarOpcode extends root.LoadOpcode
   take_args: (code_array, constant_pool, @wide=false) ->
@@ -130,14 +134,16 @@
       @var_num = code_array.get_uint 1

 class root.StoreOpcode extends root.Opcode
+  constructor: (name, params={}) ->
+    params.execute ?=
+      if name.match /[ld]store/
+        (rs) -> rs.put_cl2(@var_num,rs.pop2())
+      else
+        (rs) -> rs.put_cl(@var_num,rs.pop())
+    super name, params
+
   take_args: (code_array) ->
     @var_num = parseInt @name[7]  # sneaky hack, works for name =~ /.store_\d/
-
-  _execute: (rs) ->
-    if @name.match /[ld]store/
-      rs.put_cl2(@var_num,rs.pop2())
-    else
-      rs.put_cl(@var_num,rs.pop())

 class root.StoreVarOpcode extends root.StoreOpcode
   constructor: (name, params) ->