+ nonExported1stChar * add the skipReadOnly, isExported arguments to mergeTo function * exportTo function will call the mergeTo function directly.

--- src/abstract.coffee
+++ src/abstract.coffee
@@ -8,6 +8,8 @@
 getkeys         = Object.keys

 module.exports  = class AbstractPropertyManager
+
+  nonExported1stChar: '$'

   constrcutor: ->
     @initialize.apply @, arguments
@@ -42,19 +44,23 @@
     @assignPropertyTo(@, options, name, value, attrs, skipDefaultValue)
     return

-  mergeTo: (dest, aExclude, skipDefaultValue)->
+  mergeTo: (dest, aExclude, skipDefault, skipReadOnly, isExported)->
     if isArray dest
       aExclude = dest
       dest = {}
     else if isBoolean dest
-      skipDefaultValue = dest
+      isExported = skipDefault
+      skipReadOnly = aExclude
+      skipDefault = dest
       aExclude = []
       dest = {}

     if isString aExclude
       aExclude = [aExclude]
     else if isBoolean aExclude
-      skipDefaultValue = aExclude
+      isExported = skipReadOnly
+      skipReadOnly = skipDefault
+      skipDefault = aExclude
       aExclude = []
     else if not isArray aExclude
       aExclude = []
@@ -65,31 +71,14 @@
     for k,v of vAttrs
       continue if k in aExclude
       continue if v and v.name and (v.name in aExclude)
+      continue if skipReadOnly and v.writable is false and !v.set
       if !dest.hasOwnProperty(k)
-        @assignPropertyTo(dest, @, k, @[k], vAttrs, skipDefaultValue)
+        @assignPropertyTo(dest, @, k, @[k], vAttrs, skipDefault, isExported)
     dest

   exportTo: (dest, aExclude, skipDefault, skipReadOnly)->
-    if isString aExclude
-      aExclude = [aExclude]
-    else if isBoolean aExclude
-      skipReadOnly = skipDefault
-      skipDefault = aExclude
-      aExclude = []
-    else if not isArray aExclude
-      aExclude = []
-    dest?= {}
-    skipDefault?= true
-
-    vAttrs = @getProperties()
-    for k,v of vAttrs
-      continue if k[0] is '$'
-      continue if k in aExclude
-      continue if v and v.name and (v.name in aExclude)
-      continue if skipReadOnly and v.writable is false and !v.set
-      if !dest.hasOwnProperty(k)
-        @assignPropertyTo(dest, @, k, @[k], vAttrs, skipDefault, true)
-    dest
+    skipDefault?=true
+    @mergeTo(dest, aExclude, skipDefault, skipReadOnly, true)

   toObject: (options)->
     @exportTo(options)
@@ -104,7 +93,7 @@

     vAttrs = @getProperties()
     for k,v of vAttrs
-      continue if !vAttrs.hasOwnProperty(k) or (k in aExclude)
+      continue if k in aExclude
       continue if v and v.name and (v.name in aExclude)
       @assignPropertyTo(dest, @, k, @[k], vAttrs)
     dest._assign(@) if isFunction dest._assign


handle process exit

handle process exit

--- lib/connection/local.coffee
+++ lib/connection/local.coffee
@@ -45,6 +45,7 @@
     @pipeStreams proc
     @monitorExit proc
     client.attach proc
+    proc.onExit -> client.detach()
     proc

   connect: (proc, sock) ->


insertItemBefore base implementation fixed


display-commands

display-commands

--- src/config/inspector.coffee
+++ src/config/inspector.coffee
@@ -1,4 +1,8 @@
 {my} = require('../my')
+
+COMMANDS = 'commands'
+EXECUTING = 'executing'
+STRATEGY = 'strategy'

 BUTTON_AUTHORITY = {
     fill: my.color.button
@@ -18,6 +22,11 @@
     click: (world, args) -> world.send world.get('value')
   }

+display_commands = (name, signals) ->
+  my.assert signals, "no current program"
+  names = Object.keys signals
+  display_program(COMMANDS, names)
+
 display_program = (name, children) ->
   children = children.all() unless _.isArray(children)
   children.unshift {name: name, fill: "white", stroke: "white"}
@@ -57,16 +66,14 @@
     programs = current.get('programs')

     signals = programs.get('signals')
-    my.assert signals, "no current program"
-    names = Object.keys signals
-    world.replace_child display_program('commands', names)
+    world.replace_child display_commands(COMMANDS, signals)

     program = programs.get('program')
     my.assert program, "no current program"
-    world.replace_child display_program('executing', program)
-    set_selection world.find_child('executing'), programs.get('counter')
+    world.replace_child display_program(EXECUTING , program)
+    set_selection world.find_child(EXECUTING ), programs.get('counter')

-    strategy = world.find_child('strategy')
+    strategy = world.find_child(STRATEGY)
     strategy.authority = world.make_world ROW_AUTHORITY
     display_strategy strategy, programs

@@ -99,9 +106,9 @@
           c = world.get('current'); "#{c.get('v_i')}x#{c.get('v_j')}"}
       ]
     }
-    'commands'
-    'executing'
-    {_LABEL: 'strategy'}
+    COMMANDS
+    EXECUTING
+    {_LABEL: STRATEGY}
   ]

 }


Make sure new/edit exists before calling them on create/update.

--- lib/generators/rails_script/install/templates/base.js.coffee
+++ lib/generators/rails_script/install/templates/base.js.coffee
@@ -6,10 +6,10 @@

   create: ->
-    $this.new()
-    return
+    if typeof $this.new == 'function'
+      return $this.new()

   update: ->
-    $this.edit()
-    return+    if typeof $this.edit == 'function'
+      return $this.edit()


Fix: Avoid possible error.

Fix: Avoid possible error.

--- views/index.cjsx
+++ views/index.cjsx
@@ -247,22 +247,27 @@

   # API for IPC
   showBattleWithTimestamp: (timestamp, callback) ->
-    start = timestamp - 2000
-    end = timestamp + 2000
-    list = appdata.searchPacket start, end
-    if list.length == 1
-      try
-        packet = appdata.loadPacketSync list[0]
-        @updateBattlePacket packet
-        remote.getCurrentWindow().show()
-      catch error
-        console.error error
-        message __ "Unknown error"
-    if list.length <= 0
-      message = __ "Battle not found"
-    if list.length >= 2
-      message = __ "Multiple battle found"
-    callback(message)
+    if timestamp?
+      start = timestamp - 2000
+      end = timestamp + 2000
+      list = appdata.searchPacket start, end
+      if not list?
+        message = __ "Unknown error"
+      else if list.length == 1
+        try
+          packet = appdata.loadPacketSync list[0]
+          @updateBattlePacket packet
+          remote.getCurrentWindow().show()
+        catch error
+          console.error error
+          message __ "Unknown error"
+      else if list.length <= 0
+        message = __ "Battle not found"
+      else if list.length >= 2
+        message = __ "Multiple battle found"
+    else
+      message __ "Unknown error"
+    callback?(message)

   # API for Component <OptionArea />
   #   packet=null: using last battle and set `shouldAutoShow` to true.


Use isFileSync instead of existsSync

Use isFileSync instead of existsSync

--- lib/markdown-preview.coffee
+++ lib/markdown-preview.coffee
@@ -21,7 +21,7 @@
       console.warn("Cannot render markdown for '#{editor.getUri() ? 'untitled'}'")
       return

-    unless fs.existsSync(editor.getPath())
+    unless fs.isFileSync(editor.getPath())
       console.warn("Cannot render markdown for '#{editor.getPath() ? 'untitled'}'")
       return


link-tooltip: use an anchor tag to normalize urls

--- src/modules/link-tooltip.coffee
+++ src/modules/link-tooltip.coffee
@@ -1,8 +1,8 @@
-Quill   = require('../quill')
-Tooltip = require('./tooltip')
-_       = Quill.require('lodash')
-dom     = Quill.require('dom')
-
+Quill    = require('../quill')
+Tooltip  = require('./tooltip')
+_        = Quill.require('lodash')
+dom      = Quill.require('dom')
+anchorEl = document.createElement('a')

 class LinkTooltip extends Tooltip
   @DEFAULTS:
@@ -119,7 +119,8 @@

   _normalizeURL: (url) ->
     url = 'http://' + url unless /^(https?:\/\/|mailto:)/.test(url)
-    return url
+    anchorEl.href = url
+    return anchorEl.href

   _suggestURL: (range) ->
     text = @quill.getText(range)


clear results and console after reset

clear results and console after reset

--- lib/package/commands.coffee
+++ lib/package/commands.coffee
@@ -32,7 +32,10 @@
           juno.runtime.evaluation.toggleMeta 'methods'
       'julia-client:reset-workspace': =>
         if juno.connection.client.isActive()
-          juno.connection.client.rpc('clear-workspace')
+          editor = atom.workspace.getActiveTextEditor()
+          atom.commands.dispatch atom.views.getView(editor), 'inline-results:clear-all'
+          juno.connection.client.rpc('clear-workspace').then ->
+            juno.runtime.console.reset()
         else
           boot()
       'julia:select-block': =>


Removed null-check which caused a javascript error with updated jquery library. Works fine without the check and other forks have removed it too.

--- app/assets/javascripts/s3_direct_upload.js.coffee
+++ app/assets/javascripts/s3_direct_upload.js.coffee
@@ -38,8 +38,6 @@
     $uploadForm.fileupload

       add: (e, data) ->
-        return unless $uploadForm.is(e.originalEvent.target.form) or e.originalEvent.target.form is null
-
         file = data.files[0]
         file.unique_id = Math.random().toString(36).substr(2,16)

@@ -142,7 +140,7 @@
     if result # Use the S3 response to set the URL to avoid character encodings bugs
       content.url            = $(result).find("Location").text()
       content.key            = $(result).find("Key").text()
-    else # IE <= 9 retu      rn a null result object so we use the file object instead
+    else # IE <= 9 return a null result object so we use the file object instead
       domain                 = $uploadForm.attr('action')
       content.url            = domain + $uploadForm.find('input[name=key]').val().replace('/${filename}', '') + encodeURIComponent('/' + file.name)
       content.key            = $uploadForm.find('input[name=key]').val().replace('/${filename}', '') + '/' + file.name;


fix JSONstringifyWithCycles

fix JSONstringifyWithCycles

--- services/web/public/coffee/ide/editor/directives/aceEditor/undo/UndoManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/undo/UndoManager.coffee
@@ -237,7 +237,7 @@
 					seen = []
 					return JSON.stringify o, (k,v) ->
 						if (typeof v == 'object')
-							if ( !seen.indexOf(v) )
+							if ( seen.indexOf(v) >= 0 )
 								return '__cycle__'
 							seen.push(v);
 						return v


When showing a user's vote, scope the search to the current question

--- app/assets/javascripts/views/question_page.coffee
+++ app/assets/javascripts/views/question_page.coffee
@@ -167,7 +167,7 @@
     @fetchPromise.onSuccess =>
       @highlightLeftNavLink(@individualRankingsLink)

-      vote = Vote.find({userId})
+      vote = @question.votes().find({userId})
       @column1Header.text("Individual Rankings")

       @showAllVotes()


re-enable line wrapping...

re-enable line wrapping...

--- salvus/page/worksheet-cm.coffee
+++ salvus/page/worksheet-cm.coffee
@@ -36,7 +36,7 @@
         firstLineNumber: 0
         indentUnit   : 4
         tabSize      : 4
-        lineWrapping : false
+        lineWrapping : true
         undoDepth    : 200
         autofocus    : false
         gutters      : ['CodeMirror-linenumbers', 'worksheet-cm-cell-gutter']


test(e2e): Fix variable scope.

test(e2e): Fix variable scope.

--- test/e2e/steps/core_steps.coffee
+++ test/e2e/steps/core_steps.coffee
@@ -66,8 +66,8 @@
           @lastRun.error = error
           done()

-        @child.stderr.on 'data', (chunk) ->
-          lastRun.stderr += chunk.toString()
+        @child.stderr.on 'data', (chunk) =>
+          @lastRun.stderr += chunk.toString()

         @child.stdout.on 'data', (chunk) =>
           @lastRun.stdout += chunk.toString()


Improved tests for #1627.

Improved tests for #1627.

--- test/assignment.coffee
+++ test/assignment.coffee
@@ -277,17 +277,21 @@
   eq nonce, c

 test "#1627: prohibit conditional assignment of undefined variables", ->
-  nonce = {}
+  throws (-> CoffeeScript.compile "x ?= 10"),        null, "prohibit (x ?= 10)"
+  throws (-> CoffeeScript.compile "x ||= 10"),       null, "prohibit (x ||= 10)"
+  throws (-> CoffeeScript.compile "x or= 10"),       null, "prohibit (x or= 10)"
+  throws (-> CoffeeScript.compile "do -> x ?= 10"),  null, "prohibit (do -> x ?= 10)"
+  throws (-> CoffeeScript.compile "do -> x ||= 10"), null, "prohibit (do -> x ||= 10)"
+  throws (-> CoffeeScript.compile "do -> x or= 10"), null, "prohibit (do -> x or= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; x ?= 10"),        "allow (x = null; x ?= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; x ||= 10"),       "allow (x = null; x ||= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; x or= 10"),       "allow (x = null; x or= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ?= 10"),  "allow (x = null; do -> x ?= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ||= 10"), "allow (x = null; do -> x ||= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; do -> x or= 10"), "allow (x = null; do -> x or= 10)"

-  eq nonce, (try CoffeeScript.compile "x ?= 10"; false catch e then nonce), "prohibit (x ?= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; x ?= 10"); nonce), "allow (x = null; x ?= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; (-> x ?= 10)()"); nonce), "allow (x = null; (-> x ?= 10)())"
-  eq nonce, (try CoffeeScript.compile "x ||= 10"; false catch e then nonce), "prohibit (x ||= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; x ||= 10"); nonce), "allow (x = null; x ||= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; (-> x ||= 10)()"); nonce), "allow (x = null; (-> x ||= 10)())"
-  eq nonce, (try CoffeeScript.compile "x or= 10"; false catch e then nonce), "prohibit (x or= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; x or= 10"); nonce), "allow (x = null; x or= 10)"
-  eq nonce, (try CoffeeScript.compile("x = null; (-> x or= 10)()"); nonce), "allow (x = null; (-> x or= 10)())"
+  throws (-> CoffeeScript.compile "-> -> -> x ?= 10"), null, "prohibit (-> -> -> x ?= 10)"
+  doesNotThrow (-> CoffeeScript.compile "x = null; -> -> -> x ?= 10"), "allow (x = null; -> -> -> x ?= 10)"

 test "#1348, #1216: existential assignment compilation", ->
   nonce = {}


* remove debug print code

* remove debug print code

--- test/cache-test.coffee
+++ test/cache-test.coffee
@@ -79,7 +79,6 @@
       count = 0
       vCache.on 'del', (k,v)->
         ++count
-        console.log k,v
         v.should.be.equal pairs[k]
       vCache.free()
       count.should.be.equal Object.keys(pairs).length


Delete uploaded file if it still exists after adding the slide

--- routes/api.coffee
+++ routes/api.coffee
@@ -106,11 +106,11 @@
     user.addSlide data, (err) ->
       if err
         req.flash 'error', err
-        fs.unlink req.file.path
       if user == req.user
         res.redirect '/admin/cc'
       else
         res.redirect '/admin/admin'
+      fs.unlink req.file.path if fs.existsSync path
       users.save()

 router.post '/deleteSlide', (req, res) ->


Use relative require path

Use relative require path

--- lib/package-generator.coffee
+++ lib/package-generator.coffee
@@ -1,4 +1,4 @@
-PackageGeneratorView = require 'package-generator/lib/package-generator-view'
+PackageGeneratorView = require './package-generator-view'

 module.exports =
   view: null


further removing jQuery... muahah

further removing jQuery... muahah

--- scripts/notes.coffee
+++ scripts/notes.coffee
@@ -155,16 +155,24 @@

   constructor: () ->
-    @container = $('
', class: 'noteList')
+
+    @container = document.createElement "div"
+    @container.setAttribute 'class', 'noteList'

     @noteWidgets = []
-    $('
', text: 'My Notes').appendTo @container
-    @newButton = $('<input/>', {type: 'submit', value: 'New Note'})
-    @newButton.appendTo(@container)
+
+    @container.innerHTML = "
My Notes
"
+
+    @newButton = document.createElement "input"
+    @newButton.setAttribute "type", "submit"
+    @newButton.setAttribute "value", "New Note"
+
+    @container.appendChild @newButton
+
     @noteList = $('
').appendTo @container

   getNoteList: -> @noteList[0]
-  getNewNoteButton: -> @newButton[0]
+  getNewNoteButton: -> @newButton

   addNote: (noteWidget) ->
     @noteList.append noteWidget
@@ -174,7 +182,7 @@
     @noteWidgets = []
     @noteList.empty()

-  asWidget: -> @container[0]
+  asWidget: -> @container

 class NoteListItemPresenter extends Presenter
   # Presenter to handle the management of a Note List Item
@@ -212,23 +220,26 @@
   # NoteListItemDisplay is EXTRA nothing special.

   constructor: () ->
-    @container = $('
')
-    @noteLabel = $('').appendTo @container
-
-    deleteParams =
-      class: 'delete'
-      text: 'x'
-
-    @deleteButton = $('', deleteParams)
-    @deleteButton.appendTo @container
-
-  getListItem: -> @noteLabel[0]
-
-  getDeleteButton: -> @deleteButton[0]
-
-  setText: (text) -> @noteLabel.text text
-
-  asWidget: -> @container[0]
+
+    @noteLabel = document.createElement "span"
+
+    @container = document.createElement "li"
+    @container.appendChild @noteLabel
+
+
+    @deleteButton = document.createElement "span"
+    @deleteButton.setAttribute 'class', 'delete'
+    @deleteButton.innerText = 'x'
+
+    @container.appendChild @deleteButton
+
+  getListItem: -> @noteLabel
+
+  getDeleteButton: -> @deleteButton
+
+  setText: (text) -> @noteLabel.innerText = text
+
+  asWidget: -> @container

 class NotificationPresenter extends Presenter
   # Simple Notification Window that will listen to 'notify' and display the message


Fix access to git's stdout on `grunt publish`

This should have gone into a2ecb81 but was missed due to lack of testing.

--- grunt/tasks/gittasks.coffee
+++ grunt/tasks/gittasks.coffee
@@ -46,7 +46,7 @@
         return

       gitconfig = {}
-      result.trim().split('\n').forEach (entry) ->
+      result.stdout.trim().split('\n').forEach (entry) ->
         [key, val...] = entry.split ' '
         gitconfig[key] = val.join(' ').trim()
       grunt.config 'gh-pages.options.user.name', gitconfig['user.name']


public worksheet view: get rid of button bar

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -886,6 +886,7 @@

         # This approach to public "editor"/viewer types is temporary.
         if extra_opts.public_access
+            opts.read_only = true
             if filename_extension_notilde(filename) == 'html'
                 if opts.content.indexOf("#ipython_notebook") != -1
                     editor = new JupyterNBViewer(@, filename, opts.content)
@@ -1386,7 +1387,6 @@
 class CodeMirrorEditor extends FileEditor
     constructor: (@editor, @filename, content, opts) ->
         editor_settings = flux.getStore('account').get_editor_settings()
-
         opts = @opts = defaults opts,
             mode                      : required
             geometry                  : undefined  # (default=full screen);
@@ -2222,7 +2222,7 @@

     # add a textedit toolbar to the editor
     init_sagews_edit_buttons: () =>
-        if @opts.readonly  # no editing button bar needed for read-only files
+        if @opts.read_only  # no editing button bar needed for read-only files
             return

         if IS_MOBILE  # no edit button bar on mobile either -- too big (for now at least)


try different message format

try different message format

--- scripts/steam.coffee
+++ scripts/steam.coffee
@@ -34,7 +34,7 @@
   robot.respond /daily deal|сделка дня/i, (msg) ->
     getItems msg, location, parseDeals, 1, (deal) ->
       if deal.url
-        msg.send "#{deal.discount} // #{deal.url} (#{deal.image})"
+        msg.send "#{deal.discount} // #{deal.image} // #{deal.url}"
       else
         msg.send "Сегодня сделки дня нет"


add check of HTTP status code

add check of HTTP status code

--- test/data_tests.coffee
+++ test/data_tests.coffee
@@ -34,6 +34,7 @@
                 (done) ->
             client.get "data/exist/123/", (error, response, body) =>
                 response.should.be.json
+                response.statusCode.should.equal(200)
                 @body = JSON.parse body
                 done()

@@ -46,6 +47,7 @@
                 (done) ->
             client.get "data/exist/321/", (error, response, body) =>
                 response.should.be.json
+                response.statusCode.should.equal(200)
                 @body = JSON.parse body
                 done()

@@ -69,6 +71,7 @@
         it "When I send a request to get Note with id 321", (done) ->
             client.get 'data/321/', (error, response, body) =>
                 response.should.be.json
+                response.statusCode.should.equal(200)
                 @body = JSON.parse body
                 done()


renamed 'app' to 'server' so it's more clear

--- server/server.coffee
+++ server/server.coffee
@@ -14,7 +14,7 @@
 mw = require('./middleware')

 # Module variables
-app = express()
+server = express()
 isShuttingDown = false
 FATAL_EXIT_CODE = 13

@@ -23,7 +23,7 @@
 #
 module.exports.init = (options, callback) ->
   initMiddleware()
-  router.buildRoutes(app, options.routes)
+  router.buildRoutes(server, options.routes)
   initLibs(callback)

 #
@@ -33,9 +33,9 @@
 module.exports.start = (options, callback) ->
   port = 3000
   port = options.port if (options && options.port)
-  app.listen port, undefined, (callback) ->
-    if (app.settings.env != 'test')
-      console.log("server listening on port #{port} in #{app.settings.env} mode")
+  server.listen port, undefined, (callback) ->
+    if (server.settings.env != 'test')
+      console.log("server listening on port #{port} in #{server.settings.env} mode")

 stop = module.exports.stop = (exitCode = 0) ->
@@ -59,32 +59,32 @@
 # Initialize middleware stack
 #
 initMiddleware = ->
-  app.configure ->
-    app.set('views', rendr.entryPath + '/views')
-    app.set('view engine', 'coffee')
-    app.engine('coffee', require('./view_engine'))
-    app.use(express.logger())
-    app.use(express.compress())
-    app.use(express.bodyParser())
-    app.use(express.cookieParser())
-    app.use(express.methodOverride())
-    app.use(express.static(rendr.entryPath + '/../public'))
-    app.use(mw.startRequest())
-    app.use(mw.createAppInstance())
-    # app.use(mw.getAccessToken())
-    # app.use(mw.userConfig())
-    app.use(app.router)
-    # app.use(mw.logResponse())
-    app.use('/api', apiProxy)
+  server.configure ->
+    server.set('views', rendr.entryPath + '/views')
+    server.set('view engine', 'coffee')
+    server.engine('coffee', require('./view_engine'))
+    server.use(express.logger())
+    server.use(express.compress())
+    server.use(express.bodyParser())
+    server.use(express.cookieParser())
+    server.use(express.methodOverride())
+    server.use(express.static(rendr.entryPath + '/../public'))
+    server.use(mw.startRequest())
+    server.use(mw.createAppInstance())
+    # server.use(mw.getAccessToken())
+    # server.use(mw.userConfig())
+    server.use(server.router)
+    # server.use(mw.logResponse())
+    server.use('/api', apiProxy)

-  app.configure 'test', ->
-    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }))
+  server.configure 'test', ->
+    server.use(express.errorHandler({ dumpExceptions: true, showStack: true }))

-  app.configure 'development', ->
-    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }))
+  server.configure 'development', ->
+    server.use(express.errorHandler({ dumpExceptions: true, showStack: true }))

-  app.configure 'production', ->
-    app.use(express.errorHandler())
+  server.configure 'production', ->
+    server.use(express.errorHandler())

 #
 # Initialize our libraries


add region filter for location search

add region filter for location search

--- source/js/lib/search_widget.coffee
+++ source/js/lib/search_widget.coffee
@@ -4,6 +4,8 @@
       options.manual_style = true
       options.address_params ?= {}
       options.address_params.region_code = "F"
+      options.location_params ?= {}
+      options.location_params.region_code = "F"
       super(element,"d1707a90-fd84-012c-d9c3-00e08121877f",options)
       @prefix = options.prefix
       @on "address:select", (value,data)=>


disable already selected context

disable already selected context

--- resources/assets/coffee/admin.coffee
+++ resources/assets/coffee/admin.coffee
@@ -61,7 +61,9 @@
     roles = $('#roles')
     context_id = $('#context_id')
     permissions = $('#permissions')
-    #This is the right way..wird error come up if I use this method..so i'm converting this to the shitty .click on every new element
+    $('.remove-permission').each ->
+      $(context_id).find('option[value='+$(this).data('value')+']').attr('disabled', 'disabled')
+
     $(permissions).on 'click', '.remove-permission', (e) ->
       hub.remove_permission(e, this)
       hub.init_select()


Fully functioning index spec.

Fully functioning index spec.

--- spec/controllers/index_spec.coffee
+++ spec/controllers/index_spec.coffee
@@ -1,16 +1,17 @@
 vows         = require('../spec_helper').vows
 client       = require('../spec_helper').client
-assert       = require('../spec_helper').assert
-assertStatus = require('../spec_helper').assertStatus
+tobi         = require('../spec_helper').tobi
+jsonHeaders  = require('../spec_helper').headers.jsonHeaders

 vows
 	.describe('index')
 	.addBatch

     'when requesting the index':
-      topic: -> client.get('/')
+      topic: ->
+        tobi.get('/', @callback)

-      'should respond with a 200 ok': (response) ->
-        assertStatus(200)
+      'should respond with a 200 ok': (response, $) ->
+        response.should.have.status(200)

 	.export(module)


Feeder: Member feed callback silent fail fix

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1451,6 +1451,7 @@
       JAccount = require '../account'
       graph.fetchMembers options, (err, results)=>
         if err then return callback err
+        else if results.length < 1 then return callback null, []
         else
           tempRes = []
           collectContents = race (i, res, fin)=>


Scriptblock: write if statement in a better way

--- workers/social/lib/social/render/scriptblock.coffee
+++ workers/social/lib/social/render/scriptblock.coffee
@@ -95,7 +95,7 @@
   kallback = ->
     {delegate} = options.client.connection

-    if delegate and  typeof delegate.fetchSubscriptions is 'function'
+    if 'function' is typeof delegate?.fetchSubscriptions
       selector = {}
       fetchOptions = targetOptions:{ tags: $nin: ["nosync"] }


More progress on Model specs.

More progress on Model specs.

--- spec/spec/RickshawModelSpec.coffee
+++ spec/spec/RickshawModelSpec.coffee
@@ -1,4 +1,9 @@
 describe "Rickshaw.Model", ->
+
+  # =================
+  # = Instantiation =
+  # =================
+
   describe "Instantiation", ->
     beforeEach ->
       @Todo = new Class({
@@ -12,16 +17,13 @@
       it "Has no data", ->
         expect( @todo.data ).toEqual( {} )

-      it "Sets data", ->
-        @todo.set( "foo", "bar" )
-        expect( @todo.data ).toEqual({
-          "foo": "bar"
-        })
+      it "Has no id", ->
+        expect( @todo.id ).toBeUndefined()

-      it "Gets undefined data", ->
-        expect( @todo.get( "foo" ) ).toBeUndefined()
+      it "Is not dirty", ->
+        expect( @todo.isDirty() ).toBe( false )

-    describe "With data", ->
+    describe "With data and id", ->
       beforeEach ->
         @todo = new @Todo({
           id: 123
@@ -29,9 +31,72 @@
           baz: true
         })

+      it "Has data", ->
+        expect( @todo.data ).toEqual({
+          id: 123
+          foo: "bar"
+          baz: true
+        })
+
+      it "Sets id on instantiation", ->
+        expect( @todo.id ).toEqual( 123 )
+
+      it "Is not dirty", ->
+        expect( @todo.isDirty() ).toBe( false )
+
     describe "With data and no id property", ->
       beforeEach ->
         @todo = new @Todo({
           foo: "bar"
           baz: true
         })
+
+      it "Has data", ->
+        expect( @todo.data ).toEqual({
+          foo: "bar"
+          baz: true
+        })
+
+      it "Has no id", ->
+        expect( @todo.id ).toBeUndefined()
+
+      it "Is not dirty", ->
+        expect( @todo.isDirty() ).toBe( false )
+
+  # ===========
+  # = Getting =
+  # ===========
+
+  describe "Getting", ->
+    beforeEach ->
+      @Todo = new Class({
+        Extends: Rickshaw.Model
+      })
+
+    describe "With no data", ->
+      beforeEach ->
+        @todo = new @Todo()
+
+      it "Gets empty data", ->
+        expect( @todo.data ).toEqual( {} )
+
+      it "Gets undefined property", ->
+        expect( @todo.get( "foo" ) ).toBeUndefined()
+
+    describe "With data and id", ->
+      beforeEach ->
+        @todo = new @Todo({
+          id: 123
+          foo: "bar"
+          baz: true
+        })
+
+      it "Gets properties", ->
+        expect( @todo.get( "foo" ) ).toEqual( "bar" )
+
+      it "Gets all data", ->
+        expect( @todo.data ).toEqual({
+          id: 123
+          foo: "bar"
+          baz: true
+        })


Don't keep track of we have loaded view or not, require.cache does this for us.

--- src/core/environment.coffee
+++ src/core/environment.coffee
@@ -31,7 +31,6 @@
     @contentPlugins = []

     @pluginsLoaded = false
-    @viewsLoaded = false

     @contentsPath = @resolvePath @config.contents
     @templatesPath = @resolvePath @config.templates
@@ -152,14 +151,12 @@

   loadViews: (callback) ->
     ### Loads files found in the *@config.views* directory and registers them as views. ###
-    return callback() if @viewsLoaded or not @config.views?
+    return callback() if not @config.views?
     async.waterfall [
       (callback) => fs.readdir @resolvePath(@config.views), callback
       (filenames, callback) =>
         modules = filenames.map (filename) => "#{ @config.views }/#{ filename }"
-        async.forEach modules, @loadViewModule.bind(this), (error) =>
-          @viewsLoaded = true if not error?
-          callback error
+        async.forEach modules, @loadViewModule.bind(this), callback
     ], callback

   getContents: (callback) ->


Use querySelectorAll to fetch title from opf

This works in chrome and firefox. Jquery could not find the title node
in firefox, reason not known at present.

--- scripts/gh-book/opf-file.coffee
+++ scripts/gh-book/opf-file.coffee
@@ -324,7 +324,10 @@
       # For the structure of the TOC file see `OPF_TEMPLATE`
       bookId = @$xml.find("##{@$xml.get 'unique-identifier'}").text()

-      title = @$xml.find('title').text()
+      # Explicitly use querySelectorAll, because firefox fails to find the
+      # title if you just use jQuery.find().
+      titles = @$xml[0].querySelectorAll('title')
+      title = titles.length and $(titles[0]).text() or ''

       # The manifest contains all the items in the spine
       # but the spine element says which order they are in


Don't try to link to the application

Don't try to link to the application

This doesn't actually work.

--- scripts/govuk_app_owners.coffee
+++ scripts/govuk_app_owners.coffee
@@ -10,4 +10,4 @@
       .get() (err, response, body) ->
         if response.statusCode == 200
           data = JSON.parse(body)
-          res.reply "<#{data.links.html_url}|#{data.app_name}> is owned by <#{data.team}>"
+          res.reply "#{data.app_name} is owned by <#{data.team}>"


Ignore "co" at the beginning of response

--- scripts/co.coffee
+++ scripts/co.coffee
@@ -18,5 +18,5 @@
   ]

   robot.hear /\bco\b/im, (res) ->
-    return if res.message.text.match(/@co/)
+    return if res.message.text.match(/^co \w/)
     res.reply res.random leaveReplies


bind => on

bind => on

--- src/bindable.coffee
+++ src/bindable.coffee
@@ -22,7 +22,7 @@
 Bindable = (I={}, self) ->
   eventCallbacks = {}

-  bind: ()->
+  bind: (args...) ->
     self.on.apply(arguments)

   unbind: ->


[BETA] For WebSQL Support

[BETA] For WebSQL Support

--- src/device.module.db.coffee
+++ src/device.module.db.coffee
@@ -7,13 +7,6 @@
 ###

 Device.DB = do(dvc = Device) ->
-  ERROR = lng.Constants.ERROR
-  CONFIG =
-    name: "lungo_db"
-    version: "1.0"
-    size: 65536
-    schema: []
-
   db = null

   ###
@@ -21,13 +14,20 @@
   @method init
   @param {object} Configuration for the Database
   ###
-  init = (db_config) ->
-    CONFIG = lng.Core.mix(CONFIG, db_config)
-    db = openDatabase(CONFIG.name, CONFIG.version, CONFIG.name, CONFIG.size)
+  init = (name, version, size, schema) ->
+    db = openDatabase name, version, name, size
     if db
-      _createSchema()
+      schema_len = schema.length
+      return unless schema_len
+      i = 0
+      while i < schema_len
+        current = schema[i]
+        _regenerateTable current
+        _createTable current.name, current.fields
+        i++
+
     else
-      throw new Error(ERROR.DATABASE)
+      throw new Error "[ERROR] Device.DB: DB unnecesible"

   ###
@@ -96,26 +96,12 @@
   @param {Function} Callback when the process is complete
   ###
   execute = (sql, callback) ->
-    lng.Core.log 1, "lng.Data.Sql >> " + sql
     db.transaction (transaction) ->
       transaction.executeSql sql, [], ((transaction, rs) ->
         _callbackResponse callback, rs
       ), (transaction, error) ->
         transaction.executedQuery = sql
         _throwError.apply null, arguments
-
-
-  _createSchema = ->
-    schema = CONFIG.schema
-    schema_len = schema.length
-    return  unless schema_len
-    i = 0
-
-    while i < schema_len
-      current = schema[i]
-      _regenerateTable current
-      _createTable current.name, current.fields
-      i++

   _createTable = (table, fields) ->
     sql_fields = ""
@@ -156,7 +142,7 @@
     execute "INSERT INTO " + table + " (" + fields + ") VALUES (" + values + ")"

   _throwError = (transaction, error) ->
-    throw new Error(ERROR.DATABASE_TRANSACTION + error.code + ": " + error.message + " \n Executed query: " + transaction.executedQuery)
+    throw new Error("[ERROR] Device.DB " + error.code + ": " + error.message + " \n Executed query: " + transaction.executedQuery)

   init: init
   select: select


Update welcome message

Update welcome message

--- scripts/welcome-to-zihub.coffee
+++ scripts/welcome-to-zihub.coffee
@@ -24,7 +24,7 @@

 Te recomiendo que antes de nada revises tu perfil y te pongas un avatar (nos gusta ver la cara a la gente para conocernos cuando coincidamos en algún sarao).

-Luego puedes presentarte en el canal #presentaciones para que sepan que has llegado.
+Luego puedes presentarte en el canal #presentaciones para que sepan que has llegado, quién eres y a qué te dedicas.

 Por aquí usamos la regla de los dos pies, así que echa un vistazo a los canales y únete a los de tu interés. En el momento que veas que no te aportan nada o que tu no puedes aportar nada puedes (debes) abandonar el canal y aquí no ha pasado nada.


package linter 257 name changed in atom

package linter 257 name changed in atom

--- .atom/config.cson
+++ .atom/config.cson
@@ -5,7 +5,8 @@
     showOnStartup: false
   core:
     disabledPackages: [
-      "linter-python-pep257"
+      "linter-chktex"
+      "linter-pep257"
     ]
   editor:
     invisibles: {}


0.41a

0.41a

-Added blinking when alert triggered

--- Eva.widget/index.coffee
+++ Eva.widget/index.coffee
@@ -355,14 +355,14 @@
         $(domEl).find('.TrashSize').text("#{Trashvalues}")

 #   Dealing with warnings
-    if parseInt(Batterievalues[1]) < 20
+    if parseInt(Batterievalues[1]) < 100
         Bwarning = 1
         colorChange(".a3", "rgba(256,0,0,1)")
     else
         Bwarning = 0
         colorChange(".a3", "rgba(10,10,10,1)")

-    if CPUUsage/CPUAmount>90
+    if CPUUsage/CPUAmount > 0
         Cwarning = 1
         colorChange("#CPUCell", "rgba(256,0,0,1)")
     else
@@ -373,8 +373,13 @@
         warning = 1
     else warning = 0

+    ok = date.getSeconds()%2
     if warning == 1
         warning_on()
+        if ok == 1
+            colorChange(".a0", "rgba(256,0,0,1)")
+        else
+            colorChange(".a0", "rgba(128,0,0,1)")
     else
         warning_off()


a little polish

a little polish

--- src/scripts/geolocate-ip.coffee
+++ src/scripts/geolocate-ip.coffee
@@ -26,4 +26,4 @@
           geolocation_json = JSON.parse(body)
           msg.send "I'm pretty sure #{geolocation_json.ip} is from #{geolocation_json.city}, #{geolocation_json.country_name}."
         else
-          msg.send "Somethign didn't work trying to geolocate#{target_ip} using #{api_url}. :frowning:"
+          msg.send "Something didn't work trying to geolocate#{target_ip} using #{api_url}. :frowning:"


Make better test

Make better test

--- spec/ascii-art-spec.coffee
+++ spec/ascii-art-spec.coffee
@@ -1,3 +1,4 @@
+{WorkspaceView} = require 'atom'
 AsciiArt = require '../lib/ascii-art'

 # Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs.
@@ -6,9 +7,15 @@
 # or `fdescribe`). Remove the `f` to unfocus the block.

 describe "AsciiArt", ->
+  promise = null
   beforeEach ->
+    atom.workspaceView = new WorkspaceView()
+    atom.workspace = atom.workspaceView.model
+    promise = atom.packages.activatePackage('ascii-art')
     waitsForPromise ->
-      atom.packages.activatePackage('ascii-art')
+      atom.workspace.open()

-  it "has one valid test", ->
-    expect("life").toBe "easy"
+  it "converts", ->
+    atom.workspaceView.trigger 'ascii-art:convert'
+    waitsForPromise ->
+      promise


sagews: editing a cell should clear the “executed already” flag, so grey not blue

--- src/smc-webapp/sagews.coffee
+++ src/smc-webapp/sagews.coffee
@@ -42,6 +42,8 @@

 class SynchronizedWorksheet extends SynchronizedDocument2
     constructor: (@editor, @opts) ->
+        #window.w = @
+
         # these two lines are assumed, at least by the history browser
         @codemirror  = @editor.codemirror
         @codemirror1 = @editor.codemirror1
@@ -88,10 +90,7 @@
                 if changeObj.origin == 'undo'
                     return
                 if changeObj.origin? and changeObj.origin != 'setValue'
-                    line = changeObj.from.line
-                    mark = @find_input_mark(line)
-                    if mark?
-                        @remove_cell_flag(mark, FLAGS.this_session)
+                    @remove_this_session_flags_from_changeObj_range(changeObj)

                 if changeObj.origin == 'paste'
                     changeObj.cancel()
@@ -1954,6 +1953,26 @@
                 uuids[z.text.slice(1,37)] = true
             return false
         return uuids
+
+    remove_this_session_from_line: (n) =>
+        s = @get_input_line_flagstring(n)
+        if s? and FLAGS.this_session in s
+            s = s.replace(new RegExp(FLAGS.this_session, "g"), "")
+            @set_input_line_flagstring(n, s)
+
+    remove_this_session_flags_from_range: (start, end) =>
+        {start} = @current_input_block(start)
+        n = start
+        @codemirror.eachLine start, end+1, (line) =>
+            if line.text[0] == MARKERS.cell
+                @remove_this_session_from_line(n)
+            n += 1
+            return false
+
+    remove_this_session_flags_from_changeObj_range: (changeObj) =>
+        @remove_this_session_flags_from_range(changeObj.from.line, changeObj.to.line)
+        if changeObj.next?
+            @remove_cell_flags_from_changeObj(changeObj.next)

     remove_cell_flags_from_changeObj: (changeObj, flags, uuids) =>
         if not uuids?


Re authorize streams on reconnect

Re authorize streams on reconnect

--- server/stream/streamBroadcast.coffee
+++ server/stream/streamBroadcast.coffee
@@ -1,6 +1,19 @@
+logger = new Logger 'StreamBroadcast',
+	sections:
+		connection: 'Connection'
+		auth: 'Auth'
+		stream: 'Stream'
+
+
+authorizeConnection = (connection, record) ->
+	logger.auth.info "Authorizing with localhost:#{record.extraInformation.port}"
+	connection.call 'broadcastAuth', record._id, InstanceStatus.id(), (err, ok) ->
+		connection.broadcastAuth = ok
+		logger.auth.info "broadcastAuth with localhost:#{record.extraInformation.port}", ok
+
 @connections = {}
 @startStreamBroadcast = (streams) ->
-	console.log 'startStreamBroadcast'
+	logger.info 'startStreamBroadcast'

 	# connections = {}

@@ -9,15 +22,15 @@
 			if record.extraInformation.port is process.env.PORT or connections[record.extraInformation.port]?
 				return

-			console.log 'connecting in', "localhost:#{record.extraInformation.port}"
+			logger.connection.info 'connecting in', "localhost:#{record.extraInformation.port}"
 			connections[record.extraInformation.port] = DDP.connect("localhost:#{record.extraInformation.port}", {_dontPrintErrors: true})
-			connections[record.extraInformation.port].call 'broadcastAuth', record._id, InstanceStatus.id(), (err, ok) ->
-				connections[record.extraInformation.port].broadcastAuth = ok
-				console.log "broadcastAuth with localhost:#{record.extraInformation.port}", ok
+			authorizeConnection(connections[record.extraInformation.port], record);
+			connections[record.extraInformation.port].onReconnect = ->
+				authorizeConnection(connections[record.extraInformation.port], record);

 		removed: (record) ->
 			if connections[record.extraInformation.port]? and not InstanceStatus.getCollection().findOne({'extraInformation.port': record.extraInformation.port})?
-				console.log 'disconnecting from', "localhost:#{record.extraInformation.port}"
+				logger.connection.info 'disconnecting from', "localhost:#{record.extraInformation.port}"
 				connections[record.extraInformation.port].disconnect()
 				delete connections[record.extraInformation.port]

@@ -27,26 +40,26 @@
 				if connection.status().connected is true
 					connection.call 'stream', streamName, args, (error, response) ->
 						if error?
-							console.log "Stream broadcast error", error
+							logger.error "Stream broadcast error", error

 						switch response
 							when 'self-not-authorized'
-								console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} to self is not authorized".red
-								console.log "    -> connection authorized".red, connection.broadcastAuth
-								console.log "    -> connection status".red, connection.status()
-								console.log "    -> arguments".red, args
+								logger.stream.error "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} to self is not authorized".red
+								logger.stream.debug "    -> connection authorized".red, connection.broadcastAuth
+								logger.stream.debug "    -> connection status".red, connection.status()
+								logger.stream.debug "    -> arguments".red, args

 							when 'not-authorized'
-								console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} not authorized".red
-								console.log "    -> connection authorized".red, connection.broadcastAuth
-								console.log "    -> connection status".red, connection.status()
-								console.log "    -> arguments".red, args
+								logger.stream.error "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} not authorized".red
+								logger.stream.debug "    -> connection authorized".red, connection.broadcastAuth
+								logger.stream.debug "    -> connection status".red, connection.status()
+								logger.stream.debug "    -> arguments".red, args

 							when 'stream-not-exists'
-								console.log "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} does not exists".red
-								console.log "    -> connection authorized".red, connection.broadcastAuth
-								console.log "    -> connection status".red, connection.status()
-								console.log "    -> arguments".red, args
+								logger.stream.error "Stream broadcast from:#{process.env.PORT} to:#{connection._stream.endpoint} with name #{streamName} does not exists".red
+								logger.stream.debug "    -> connection authorized".red, connection.broadcastAuth
+								logger.stream.debug "    -> connection status".red, connection.status()
+								logger.stream.debug "    -> arguments".red, args

 	Meteor.methods


Reenable changing description

Reenable changing description

--- src/smc-webapp/course/main.cjsx
+++ src/smc-webapp/course/main.cjsx
@@ -626,7 +626,7 @@
                 @configure_project_users(student_project_id, student_id, do_not_invite_student_by_email)
                 @configure_project_visibility(student_project_id)
                 @configure_project_title(student_project_id, student_id)
-                #@configure_project_description(student_project_id, student_id)
+                @configure_project_description(student_project_id, student_id)

         delete_project: (student_id) =>
             store = get_store()


time: button size constant

time: button size constant

--- src/smc-webapp/editor_time.cjsx
+++ src/smc-webapp/editor_time.cjsx
@@ -98,17 +98,17 @@
         @setInterval((=> @forceUpdate()), 1000)

     render_start_button: ->
-        <Button bsSize='large'  bsStyle='primary' onClick={=>@props.click_button('start')}>
+        <Button bsStyle='primary' onClick={=>@props.click_button('start')} style={width:'8em'}>
             <Icon name='play'/> Start
         </Button>

     render_stop_button: ->
-        <Button bsSize='large' bsStyle='warning' onClick={=>@props.click_button('stop')}>
+        <Button bsStyle='warning' onClick={=>@props.click_button('stop')}>
             <Icon name='stop'/> Stop
         </Button>

     render_pause_button: ->
-        <Button bsSize='large' bsStyle='info' onClick={=>@props.click_button('pause')}>
+        <Button bsStyle='info' onClick={=>@props.click_button('pause')} style={width:'8em'}>
             <Icon name='pause'/> Pause
         </Button>


Reduce linter warnings (config)

Reduce linter warnings (config)

--- modules/config/index.coffee
+++ modules/config/index.coffee
@@ -5,7 +5,7 @@
 Commands = require './commands'

 # DB Model
-Guild = Core.db.createModel "Guild", {
+Guild = Core.db.createModel 'Guild', {
   id: type.string()
   discordId: type.string()
   prefix: type.string()
@@ -70,7 +70,8 @@

     # Custom Prefixes
     Object.getPrototypeOf(Core.commands).getPrefix = (msg)->
-      return Promise.resolve Core.settings.prefix if msg.content.indexOf(Core.settings.prefix) is 0
+      if msg.content.indexOf(Core.settings.prefix) is 0
+        return Promise.resolve Core.settings.prefix
       d = await Core.guilds.getGuild(msg.guild)
       Promise.resolve d.data.prefix or Core.settings.prefix


修复 RadioGroup 值被强转为String的bug

修复 RadioGroup 值被强转为String的bug

--- src/widget/edit/radio.coffee
+++ src/widget/edit/radio.coffee
@@ -20,13 +20,12 @@
 		valueProperty: null
 		textProperty: null

-
 	_initDom: (dom)->
 		super(dom)
 		selector = @
 		$(dom).delegate(">item", "click", ()->
 			if selector._readOnly then return
-			value = $(this).find("input").attr("value")
+			value=selector._getDomValue(this)
 			selector._setValue(value);
 			selector._select(value)
 		)
@@ -35,61 +34,64 @@
 		super()
 		itemsDom = @_getItemsDom()
 		if itemsDom
-			$fly(@_dom).empty()
-			$fly(@_dom).append(itemsDom)
+			$fly(@_dom).empty().append(itemsDom)
 		value = @_value
 		@_select(value)

 	_select: (value)->
 		if typeof value == "undefined"
 			return
-		$(@_dom).find("[value='" + value + "']")[0].checked = true;
+		dom = $(@_dom).find("[value='" + value + "']")
+		if dom.length > 0
+			dom[0].checked = true
+
+	_getDomValue:(itemDom)->
+		text=$(itemDom).find("label").text()
+		item=null
+		textProperty= @_textProperty
+
+		attrBinding = @_elementAttrBindings?["items"]
+		if attrBinding
+			raw = attrBinding.expression.raw
+			entityList=attrBinding.scope.get(raw)
+			entityList && entityList.each((entity)->
+				if entity.get(textProperty) is text
+					item=entity
+					return false
+			)
+		if item
+			return item.get(@_valueProperty)

 	_getItemsDom: ()->
 		attrBinding = @_elementAttrBindings?["items"]
 		@_name ?= ("name_" + cola.sequenceNo());
 		if attrBinding
+			textProperty = "item"
+			valueProperty = "item"
 			if @_textProperty
-				cText = "item." + @_textProperty
-			else
-				cText = "item"
+				textProperty += "." + @_textProperty
+			if @_valueProperty
+				valueProperty += "." + @_valueProperty
+			raw = attrBinding.expression.raw

-			if @_valueProperty
-				cValue = "item." + @_valueProperty
-			else
-				cValue = "item"
-			raw = attrBinding.expression.raw
 			itemsDom = cola.xRender({
 				tagName: "item",
 				"c-repeat": "item in " + raw,
+				"c-caption": textProperty,
 				content: [
 					{
-						tagName: "input", type: "radio",
-						name: @_name, "c-value": cValue
+						tagName: "input",
+						name: @_name,
+						type:"radio",
+						"c-value": valueProperty
 					},
 					{
 						tagName: "label",
-						"c-bind": cText
+						"c-bind": textProperty
 					}
 				]
 			}, attrBinding.scope)

-		else
-			itemsDom = document.createDocumentFragment();
-			for item in @_items
-				itemsDom.appendChild({
-					tagName: "item",
-					"c-repeat": "item in " + raw,
-					content: [
-						{
-							tagName: "input", type: "radio",
-							name: @_name, value: item.value
-						},
-						{
-							tagName: "label"
-						}
-					]
-				})

 		return itemsDom


AddManagedVMModal::createMachine: creates a JMachine for given kite data

--- client/app/lib/providers/addmanagedvmmodal.coffee
+++ client/app/lib/providers/addmanagedvmmodal.coffee
@@ -148,6 +148,25 @@
         addTo @container,
           instructions : INSTALL_INSTRUCTIONS
           list         : data
+  createMachine: (kite)->
+
+    { computeController, router } = kd.singletons
+
+    stack = computeController.stacks.first._id
+
+    computeController.create {
+      provider    : 'managed'
+      queryString : generateQueryString kite.kite
+      ipAddress   : getIp kite.url
+      stack
+    }, (err, machine) =>
+
+      unless showError err
+
+        kd.utils.defer ->
+          router.handleRoute "/IDE/#{machine.slug}"
+
+        @destroy()

   queryKites: ->


ComputeController::destroy: after destroy of managed vms quit current IDE

--- client/app/lib/providers/computecontroller.coffee
+++ client/app/lib/providers/computecontroller.coffee
@@ -379,20 +379,17 @@

       if machine?.provider is 'managed'

-        options =
+        options     =
           machineId : machine._id
           provider  : machine.provider

-        @emit "MachineBeingDestroyed", machine
-
         remote.api.ComputeProvider.remove options, (err)=>
           return  if err

-          # this need to be done automatically? ~ GG
-          kd.singletons.mainView.activitySidebar.removeMachineNode machine
-
           @_clearTrialCounts machine
-          @reset yes
+          @reset yes, ->
+            kd.singletons.appManager.tell 'IDE', 'quit'
+            kd.singletons.router.handleRoute '/IDE'

         return


Tests: IDEView: Added ::createTerminal.

Tests: IDEView: Added ::createTerminal.

--- client/ide/test/views/tabview/ideview.test.coffee
+++ client/ide/test/views/tabview/ideview.test.coffee
@@ -1,13 +1,24 @@
 kd                    = require 'kd'
+mock                  = require '../../../../mocks/mockingjay'
 expect                = require 'expect'
 FSFile                = require 'app/util/fs/fsfile'
 FSHelper              = require 'app/util/fs/fshelper'
 IDEView               = require 'ide/views/tabview/ideview'
+AppController         = require 'app/appcontroller'
 IDEEditorPane         = require 'ide/workspace/panes/ideeditorpane'
 IDETailerPane         = require 'ide/workspace/panes/idetailerpane'
+IDETerminalPane       = require 'ide/workspace/panes/ideterminalpane'
 IDEApplicationTabView = require 'ide/views/tabview/ideapplicationtabview'

 ideView = null
+
+
+initSpies = ->
+
+  expect.spyOn IDEView.prototype, 'updateStatusBar'
+  expect.spyOn IDEView.prototype, 'bindListeners'
+  expect.spyOn IDEView.prototype, 'trimUntitledFileName'
+  expect.spyOn IDEView.prototype, 'handlePaneRemoved'

 createEditorPane = (paneClass) ->
@@ -15,11 +26,6 @@
   file    = FSHelper.createFileInstance path: '/foo/bar'
   content = 'Foo bar baz waz here'
   options = { name: 'Foo Bar' }
-
-  expect.spyOn IDEView.prototype, 'updateStatusBar'
-  expect.spyOn IDEView.prototype, 'bindListeners'
-  spy = expect.spyOn IDEView.prototype, 'trimUntitledFileName'
-  expect.spyOn IDEView.prototype, 'handlePaneRemoved'

   clazz      = paneClass or IDEEditorPane
   ideView    = new IDEView
@@ -35,7 +41,10 @@
 describe 'IDEView', ->

-  beforeEach -> ideView = new IDEView
+  beforeEach ->
+
+    initSpies()
+    ideView = new IDEView

   afterEach -> expect.restoreSpies()
@@ -91,7 +100,6 @@
       expect(ideView.handlePaneRemoved).toHaveBeenCalled()

-
     it 'should create tail icon if the view is an instance of an IDETailerPane', ->

       { ideView, editorPane, pane } = createEditorPane IDETailerPane
@@ -101,3 +109,20 @@
       expect(subViews.length).toBe 2
       expect(subViews.last).toBeA kd.CustomHTMLView
       expect(subViews.last.options.cssClass).toBe 'tail-icon'
+
+
+  describe '::createTerminal', ->
+
+    it 'should create a terminal pane and append it', ->
+
+      app = new AppController
+      app.workspaceData = { rootPath: '/root/path' }
+
+      mock.appManager.getFrontApp.toReturnPassedParam app
+
+      pane = ideView.createTerminal { machine: mock.getMockMachine() }
+
+      expect(pane).toBeA kd.TabPaneView
+      expect(pane.view).toBeA IDETerminalPane
+      expect(pane.options.name).toBe 'Terminal'
+      expect(pane.view.options.path).toBe '/root/path'


Forward relevant events onto query

Forward relevant events onto query

--- client/lanes/models/query/CollectionResult.coffee
+++ client/lanes/models/query/CollectionResult.coffee
@@ -1,12 +1,16 @@
 class Lanes.Models.Query.CollectionResult

     constructor: (@query) ->
+        @collection.on('add remove reset', =>
+            @query.trigger('change')
+        )
         this

     rowAt: (index, options = {}) ->
         model = @collection.at(index)
         for field, i in @query.fields.models when (not options.visibleOnly or field.visible)
             if field.format then field.format(model[field.id], model, @query) else model[field.id]
+
     allRows: (options) ->
         rows = (@rowAt(i, options) for i in [0...@length])
         _.Promise.resolve(rows)


fixed routes tests

fixed routes tests

--- test/server/routesSpec.coffee
+++ test/server/routesSpec.coffee
@@ -6,56 +6,82 @@

 dir =  path.normalize __dirname + '../../../server'

-describe 'Application Routes', ->
-  module = require(dir + '/routes')
+describe 'Routes', ->

-  assertRestfulForResource = (resource) ->
-    api =
-      user:
-        showMe: sinon.spy()
-        updateMe: sinon.spy()
-        destroyMe: sinon.spy()
-        index: sinon.spy()
-      role: sinon.spy()
-      setting: sinon.spy()
-      activity: sinon.spy()
-      category: sinon.spy()
-      environment: sinon.spy()
-
-      system: sinon.spy()
+  assertRestfulForResource = (resource, security, controllerName) ->
+    module = require(dir + '/routes')

     app =
       get: sinon.spy()
       post: sinon.spy()
       del: sinon.spy()
       put: sinon.spy()
+      middleware:
+        publicAction: sinon.spy()
+        userAction: sinon.spy()
+        adminAction: sinon.spy()

-    security =
-      auth: sinon.spy()
-      models: sinon.spy()
-    router = module(app, security.auth, api)
+      controllers:
+        user:
+          showMe: sinon.spy()
+          updateMe: sinon.spy()
+          destroyMe: sinon.spy()
+          index: sinon.spy()
+        role: sinon.spy()
+        setting: sinon.spy()
+        activity: sinon.spy()
+        category: sinon.spy()
+        environment: sinon.spy()

-    assert app.get.calledWith('/api/' + resource), "Get failed"
-    assert app.del.calledWith('/api/' + resource + '/:id'), "Del failed"
-    assert app.put.calledWith('/api/' + resource + '/:id'), "Put failed"
-    assert app.post.calledWith('/api/' + resource), "Post failed"
+    rest =
+      routeResource: sinon.spy()
+
+    securityFilter = app.middleware.publicAction
+    if security is 'user'
+      securityFilter = app.middleware.userAction
+    else if security is 'admin'
+      securityFilter = app.middleware.adminAction
+
+    module.configure app, rest
+
+    assert rest.routeResource.calledWith(resource, app)
+    , 'routeResource not called for ' + resource
+
+    assert rest.routeResource.calledWith(resource, app, securityFilter)
+    , 'routeResource ' + resource + ' not called with correct security filter'
+
+    assert rest.routeResource.calledWith(resource, app, securityFilter, app.controllers[controllerName])
+    , 'routeResource ' + resource + ' not called on correct controller'

   it 'exports a RESTful role resource', (done) ->
-    assertRestfulForResource 'roles'
+    assertRestfulForResource 'roles', 'user', 'role'
     done()

   it 'exports a RESTful users resource', (done) ->
-    assertRestfulForResource 'users'
+    assertRestfulForResource 'users', 'user', 'user'
     done()

   it 'exports a RESTful settings resource', (done) ->
-    assertRestfulForResource 'settings'
+    assertRestfulForResource 'settings', 'user', 'setting'
     done()

   it 'exports a RESTful activities resource', (done) ->
-    assertRestfulForResource 'activities'
+    assertRestfulForResource 'activities', 'user', 'activity'
     done()

   it 'exports a Restful categories resource', (done) ->
-    assertRestfulForResource 'categories'
-    done()+    assertRestfulForResource 'categories', 'user', 'category'
+    done()
+
+  it 'exports a Restful systems resource', (done) ->
+    assertRestfulForResource 'systems', 'user', 'system'
+    done()
+
+  it 'exports a Restful environments resource', (done) ->
+    assertRestfulForResource 'environments', 'user', 'environment'
+    done()
+
+  it 'exports a Restful files resource', (done) ->
+    assertRestfulForResource 'files', 'user', 'file'
+    done()
+


Clean up, more friendly towards object state.

--- lib/atom-html-preview-view.coffee
+++ lib/atom-html-preview-view.coffee
@@ -1,8 +1,9 @@
-path                  = require 'path'
 fs                    = require 'fs'
 {CompositeDisposable, Disposable} = require 'atom'
 {$, $$$, ScrollView}  = require 'atom-space-pen-views'
 _                     = require 'underscore-plus'
+path                  = require 'path'
+os                    = require 'os'

 module.exports =
 class AtomHtmlPreviewView extends ScrollView
@@ -23,6 +24,7 @@

     if @editorId?
       @resolveEditor(@editorId)
+      @tmpPath = @getPath() # after resolveEditor
     else
       if atom.workspace?
         @subscribeToFilePath(filePath)
@@ -93,20 +95,21 @@
       @renderHTMLCode()

   save: ->
-    outPath = path.resolve "/tmp/" + @editor.getTitle() + ".tmp"
-    # console.log outPath
-    out = @editor.getText()
+    # Temp file path
+    outPath = path.resolve os.tmpdir() + @editor.getTitle()
+    # Add base tag; allow relative links to work despite being loaded
+    # as the src of an iframe
+    out = "<base href=\"" + @getPath() + "\">" + @editor.getText()
     fs.writeFileSync outPath, out
-    return outPath
+    @tmpPath = outPath

   renderHTMLCode: (text) ->
-    outPath = @getPath()
-    if not atom.config.get("atom-html-preview.triggerOnSave") and @editor.getPath()? then outPath = @save() # @editor.save()
+    if not atom.config.get("atom-html-preview.triggerOnSave") and @editor.getPath()? then @save()
     iframe = document.createElement("iframe")
     # Fix from @kwaak (https://github.com/webBoxio/atom-html-preview/issues/1/#issuecomment-49639162)
     # Allows for the use of relative resources (scripts, styles)
     iframe.setAttribute("sandbox", "allow-scripts allow-same-origin")
-    iframe.src = outPath
+    iframe.src = @tmpPath
     @html $ iframe
     # @trigger('atom-html-preview:html-changed')
     atom.commands.dispatch 'atom-html-preview', 'html-changed'


Documented Processes class.

Documented Processes class.

--- www/src/theoricus/core/processes.coffee
+++ www/src/theoricus/core/processes.coffee
@@ -1,3 +1,8 @@
+###*
+  Core module
+  @module core
+###
+
 Router = require 'theoricus/core/router'
 Process = require 'theoricus/core/process'
 _ = require 'lodash'
@@ -9,6 +14,11 @@
   # utils

   # variables
+  ###*
+  Block the url state to be changed. Useful if there is a current {{#crossLink "Process"}}{{/crossLink}} being executed.
+
+  @property {Boolean} locked
+  ###
   locked: false
   disable_transitions: null

@@ -16,19 +26,25 @@
   dead_processes: []
   pending_processes: []

-  # EXEC ORDER
-  # --------------------------------------------------------------------------
-  # 1. _on_router_change
-  # 2. _filter_pending_processes
-  # 3. _filter_dead_processes
-  # 4. _destroy_dead_processes - one by one, waiting or not foll callback
-  #   4.1 Timing can be sync/async
-  # 5. _run_pending_process - one by one, waiting or not foll callback
-  #   5.1 timing can be sync/async
-  # --------------------------------------------------------------------------
-
-  ###
-  @param [theoricus.Theoricus] @the   Shortcut for app's instance
+  ###*
+  Responsible for handling the page/url change. It removes last Process, runs new Process dependencies, and then add the required Process.
+
+  __Execution order__
+
+  1. `_on_router_change`
+
+  2. `_filter_pending_processes`
+
+  3. `_filter_dead_processes`
+
+  4. `_destroy_dead_processes` - one by one, waiting or not for callback (timing can be sync/async)
+
+  6. `_run_pending_process` - one by one, waiting or not for callback (timing can be sync/async)
+
+  @class Processes
+  @constructor
+  @param @the {Theoricus} Shortcut for app's instance.
+  @param @Routes {Object} App Routes
   ###
   constructor:( @the, @Routes )->
     Factory = @the.factory
@@ -40,12 +56,12 @@
     $(document).ready =>
       @router = new Router @the, @Routes, @_on_router_change

-  ###
-  1st
-
-  Triggered on router chance
-
-  @param [theoricus.core.Router] route
+  ###*
+  Executed when the route changes, it creates a {{#crossLink "Process"}}{{/crossLink}} to manipulate the route, removes the current process, and run the new process alongside its dependencies.
+
+  @method _on_router_change
+  @param route {Route} Route containing the controller and url state information.
+  @param url {String} Current url state.
   ###
   _on_router_change:( route, url )=>
     if @locked
@@ -72,6 +88,10 @@

   @param [theoricus.core.Process] process
   ###
+  ###*
+
+
+  ###
   _filter_pending_processes:( process, after_filter )->

     @pending_processes.push process
@@ -99,7 +119,13 @@
     else
       do after_filter

-  # try to finds the dependency in many ways
+  ###*
+  Finds the dependency of the given {{#crossLink "Process"}}{{/crossLink}}
+
+  @method _find_dependency
+  @param process {Process} Processto find the dependency.
+  @param after_find {Function} Callback to be called after the dependency has been found.
+  ###
   _find_dependency:( process, after_find )->
     dependency = process.dependency

@@ -124,12 +150,11 @@
     after_find null

-  ###
-  3th
-
-  Check which of the routes needs to stay active in order to render
-  current process.
-  The ones that doesn't, are pushed to dead_processes
+  ###*
+  Check which of the processes needs to stay active in order to render current process.
+  The ones that doesn't, are pushed to dead_processes.
+
+  @method _filter_dead_processes
   ###
   _filter_dead_processes:()->
     @dead_processes = []
@@ -148,11 +173,10 @@
       else
         @dead_processes.push active

-  ###
-  4th
-
-  Destroy dead processes one by one ( passing the next destroy as callback )
-  then run the pending proccess
+  ###*
+  Destroy the dead processes (doesn't need to be active) one by one, then run the pending process.
+
+  @method _destroy_dead_processes
   ###
   _destroy_dead_processes:()=>
     if @dead_processes.length
@@ -165,15 +189,15 @@
     else
       @_run_pending_processes()

-  ###
-  5th
-  Execute run method of pending processes that are not active
+  ###*
+  Run the processes that are not active yet.
+
+  @method _run_pending_processes
   ###
   _run_pending_processes:()=>
     if @pending_processes.length

       process = @pending_processes.pop()
-      search  = route: match: process.route.match
       found = _.find @active_processes, (found_process)->
         return found_process.route.match is process.route.match


removed getprofilehandlerhelper form testhelper/index

--- servers/testhelper/index.coffee
+++ servers/testhelper/index.coffee
@@ -334,17 +334,6 @@
     return requestParams

-  @generateGetProfileRequestParams = (opts = {}) ->
-
-    url                  = generateUrl { route : "-/profile/#{opts.email}" }
-    defaultRequestParams = generateDefaultRequestParams { url }
-    requestParams        = deepObjectExtend defaultRequestParams, opts
-    # after deep extending object, encodes body param to a query string
-    requestParams.body   = querystring.stringify requestParams.body
-
-    return requestParams
-
-
 module.exports = {
   generateUrl
   deepObjectExtend


small re-ordering

small re-ordering

--- src/ui/views/contextmenu.coffee
+++ src/ui/views/contextmenu.coffee
@@ -23,26 +23,8 @@
             download win, params.srcURL
     }
     {
-        label: 'Copy Image Link'
-        visible: canShowCopyImgLink
-        click: (item, win) ->
-            if process.platform == 'darwin'
-                clipboard.writeBookmark params.srcURL, params.srcURL
-            else
-                clipboard.writeText params.srcURL
-    }
-    {
-        label: "Copy Link"
-        visible: canShowCopyLink
-        click: () ->
-            if process.platform == 'darwin'
-                clipboard.writeBookmark params.linkText, params.linkText
-            else
-                clipboard.writeText params.linkText
-    }
-    {
         type: 'separator'
-    } if canShowSaveImg || canShowCopyImgLink || canShowCopyLink
+    } if canShowSaveImg
     {
         label: 'Undo'
         role: 'undo'
@@ -69,6 +51,24 @@
         visible: true
     }
     {
+        label: "Copy Link"
+        visible: canShowCopyLink
+        click: () ->
+            if process.platform == 'darwin'
+                clipboard.writeBookmark params.linkText, params.linkText
+            else
+                clipboard.writeText params.linkText
+    }
+    {
+        label: 'Copy Image Link'
+        visible: canShowCopyImgLink
+        click: (item, win) ->
+            if process.platform == 'darwin'
+                clipboard.writeBookmark params.srcURL, params.srcURL
+            else
+                clipboard.writeText params.srcURL
+    }
+    {
         label: 'Paste'
         role: 'paste' if params.isEditable
         visible: (hasPasteableContent || params.isEditable)


Fix the check for exported on module in access violation

--- src/compiler.coffee
+++ src/compiler.coffee
@@ -6134,7 +6134,7 @@
       if not module
         throw new Error "missing module #{checkedModuleName}
          that should have been compiled for #{moduleName}"
-      if not module.exported
+      if not module.typedModulePath.exported
         return checkedModuleName
   false


Disable echo in atom.cmd

Disable echo in atom.cmd

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -68,6 +68,7 @@
     atomCommandPath = path.join(binFolder, 'atom.cmd')
     relativeExePath = path.relative(binFolder, process.execPath)
     atomCommand = """
+      @echo off
       "%~dp0\\#{relativeExePath}" %*
     """
     fs.writeFile(atomCommandPath, atomCommand, callback)


Use correct variable name for sh text

Use correct variable name for sh text

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -116,7 +116,7 @@
     atomCommand = "@echo off\r\n\"%~dp0\\#{relativeAtomPath}\" %*"

     relativeAtomShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'atom.sh'))
-    atomCommand = "#!/bin/sh\r\n\"$0\\#{relativeAtomPath}\" \"$@\""
+    atomShCommand = "#!/bin/sh\r\n\"$0\\#{relativeAtomPath}\" \"$@\""

     apmCommandPath = path.join(binFolder, 'apm.cmd')
     relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'node_modules', 'atom-package-manager', 'bin', 'apm.cmd'))


Stars now treated as array for the constellation.

--- src/game/states/game.coffee
+++ src/game/states/game.coffee
@@ -47,26 +47,24 @@
 class Game

   @player = null
-  @successTxt = null

   create: ->
     #setup game window
     x = @game.width / 3
     y = @game.height / 2
-    @starx = @game.width / 2
-    @stary = @game.height / 2

     #add Sprites
     @game.add.sprite 0, 0, 'Plough'
-    @star = @add.sprite @starx, @stary, 'unlitstar'
+    #@star = @add.sprite @starx, @stary, 'unlitstar'
     @player = @add.sprite x, y, 'player'
-
+    @constellation = []
+    @printed = []

     #Plot empty stars
     @drawConstellation(LEVELS[2])

     #add sounds
-    @soundSputnik = @game.add.audio 'soundSputnik'
+    #@soundSputnik = @game.add.audio 'soundSputnik'

     #setup game input/output
@@ -80,24 +78,24 @@
     @player.body.fixedRotation = true
     @player.body.setZeroDamping()

-    @printed = false

   update: ->
      @player.body.setZeroVelocity()

-     @xdistance = Math.abs(@player.x - @star.x)
-     @ydistance = Math.abs(@player.y - @star.y)
+     for star, i in @constellation
+     	 @xdistance = Math.abs(@player.x - star.x)
+     	 @ydistance = Math.abs(@player.y - star.y)

-     if @xdistance < 10 && @ydistance < 10
-        if not @printed
-     	   @star.destroy()
-     	   @star = @add.sprite @starx, @stary, 'litstar'
-     	   @printed = true
-     else
-        if @printed
-     	   @star.destroy()
-     	   @star = @add.sprite @starx, @stary, 'unlitstar'
-     	   @printed = false
+     	 if @xdistance < 10 && @ydistance < 10
+     	    if not @printed[i]
+     	       star.destroy()
+     	       star = @add.sprite star.x, star.y, 'litstar'
+     	       @printed[i] = true
+     	 else
+     	    if @printed[i]
+     	       star.destroy()
+     	       star = @add.sprite star.x, star.y, 'unlitstar'
+     	       @printed[i] = false

      if @cursors.left.isDown
         @player.body.moveLeft(200)
@@ -115,10 +113,9 @@

   drawConstellation: (level) ->
-    level.name
-    for star in level.starsArray
-        @add.sprite star.x, star.y, 'litstar'
-
-
+     console.log @constellation
+     for star in level.starsArray
+        @constellation.push(@add.sprite star.x, star.y, 'unlitstar')
+        @printed.push(false)

 module.exports = Game


added namespaceNames, but I think I'm just going to make namespaces and modules into maps

--- src/Runtime/Neptune.coffee
+++ src/Runtime/Neptune.coffee
@@ -25,6 +25,7 @@
   @namespace: null
   @allNamespaces: {}
   @namespaces: []
+  @namespaceNames: []
   @modules: []
   @moduleNames: []
   @_name: "Base"
@@ -34,8 +35,7 @@
     @modules = []
     @moduleNames = []
     @namespaces = []
-    @namespace[name] = @
-    @namespace.namespaces.push @
+    @namespaceNames = []
     @

   @getNamespacePath: -> @namespacePath
@@ -61,6 +61,15 @@
       name = namespace.name
     @_setChildNamespaceProps name, namespace
     @allNamespaces[@namespacePath] = namespace.initAsSubNamespace name, @
+
+    if @[name]
+      @namespaces[@namespaces.indexOf @[name]] = namespace
+    else
+      @namespaceNames.push name
+      @namespaces.push namespace
+
+    @[name] = namespace
+
     namespace

   isFunction = (f) -> typeof f == "function"


Availability checking not working

Availability checking not working

--- lib/models/localhost-proxy.coffee
+++ lib/models/localhost-proxy.coffee
@@ -4,25 +4,34 @@
 module.exports = class LocalhostProxy
   constructor: (port) ->
     @port = port
-    @bound = false
     @remoteHost = 'http://159.203.117.55'
+    @desiredPorts = ['3000', '4000', '8000', '9393']

   start: ->
-    @withAvailablePort((available) =>
-      if !!available
-        @bound = true
-        httpProxy.createProxyServer({target: @remoteHost + ':' + @port}).listen(3000, 'localhost')
+    @withAvailablePort((ports) =>
+      console.log ports
+      server = httpProxy.createProxyServer({target: @remoteHost + ':' + @port})
+
+      for port in @desiredPorts
+        console.log 'Port: ' + port + ' Available: ' + !!ports[port]
+        if !!ports[port]
+          server.listen(parseInt(port), 'localhost')
     )

   withAvailablePort: (callback) ->
-    try
-      server = net.createServer()
-      server.listen 3000, 'localhost'
+    ports = {}

-      server.on 'error', (e) ->
-        callback false
-      server.on 'listening', (e) ->
-        server.close()
-        callback true
-    catch error
-      callback false
+    for port in @desiredPorts
+      try
+        server = net.createServer()
+        server.listen parseInt(port), 'localhost'
+
+        server.on 'error', (e) ->
+          ports[port] = false
+        server.on 'listening', (e) ->
+          server.close()
+          ports[port] = true
+      catch error
+        ports[port] = false
+
+    callback(ports)


修复 日历控件无法根据日期获得dom的bug

修复 日历控件无法根据日期获得dom的bug

--- src/widget/base/calendar.coffee
+++ src/widget/base/calendar.coffee
@@ -161,7 +161,7 @@

 			return
 		getDateCellDom: (date)->
-			value = new XDate(date).toString(cola.setting("defaultDateFormat"))
+			value = new XDate(date).toString("yyyy-MM-dd")
 			return $(@_dom).find("td[cell-date='#{value}']")

 		doRefreshCell: (cell, row, column) ->


Do not open nav items in tabs. Fixes #302.

--- core/htdocs_source/src/pods/openxpki/route.coffee
+++ core/htdocs_source/src/pods/openxpki/route.coffee
@@ -15,6 +15,7 @@
         structure: null
         status: null
         tabs: []
+        navEntries: []

     beforeModel: (req) ->
         source = @get "source"
@@ -24,9 +25,15 @@
             @sendAjax data: page: "bootstrap!structure"

     model: (req) ->
+        navEntries = @get "source.navEntries"
         data = page: req.model_id
         data.limit = req.limit if req.limit
         data.startat = req.startat if req.startat
+
+        entries = navEntries.reduce (p, n) ->
+            p.concat(n, n.entries||[])
+        , []
+        data.target = "top" if entries.findBy "key", req.model_id

         source = @get "source"
         source.set "page", req.model_id


Add use strict atom snippet

Add use strict atom snippet

--- .config/atom/snippets.cson
+++ .config/atom/snippets.cson
@@ -29,6 +29,9 @@
   'fun':
     'prefix': 'fun'
     'body': 'function() {\n  $1\n};'
+  'use-strict':
+    'prefix': 'us'
+    'body': '\'use strict\';'

 # Each scope (e.g. '.source.coffee' above) can only be declared once.
 #


more wokr

more wokr


more cleaning

more cleaning

--- server/lib.coffee
+++ server/lib.coffee
@@ -2,5 +2,4 @@
   People.find()

 Meteor.onConnection (data)->
-  console.log data
   People.insert data


Remove unused import in ActionsManager

Remove unused import in ActionsManager

--- src/actions_manager.coffee
+++ src/actions_manager.coffee
@@ -2,10 +2,9 @@
   'settings'
   'reporter'
   'runnable'
-  'helpers/url_helper'
   'validator'
   'analytics_url'
-], (Settings, Reporter, Runnable, URLHelper, Validator, AnalyticsUrl) ->
+], (Settings, Reporter, Runnable, Validator, AnalyticsUrl) ->
   class ActionsManager
     ActionsManager::[key] = method for key, method of Runnable


Compiler-produced AST always includes CSS

--- spec/compiler.coffee
+++ spec/compiler.coffee
@@ -41,6 +41,7 @@
       constraints: [
         ["eq", ["get", "#b1[right]"], ["get", "#b2[left]"]]
       ]
+      css: ''
     result = null
     it 'should be able to produce correct AST', ->
       result = parser.compile statement


Use requestAnimationFrame for async ops. Correct flicker.

--- src/component/ComponentView.coffee
+++ src/component/ComponentView.coffee
@@ -100,7 +100,7 @@
 makeTransitionFunc = (func, transitionClass, removeClass, state, evt, test) ->
   (time) ->
     promise = new Promise()
-    nextTick =>
+    requestAnimationFrame =>
       # Start the transition if the view is rendered and the test function
       # return true.
       if @rendered and test.call(@)
@@ -121,7 +121,7 @@

         # Set the new transition timer.
         @_transitionTimer = setTimeout =>
-          @_removeTransitionClasses()
+          @_transitionTimer = null
           Promise.resolve promise, @[func].call(@)
         , (time or 0)

@@ -159,10 +159,11 @@
 makeVisibilityFunc = (visibility, evt, test, testRejectionMsg) ->
   ->
     promise = new Promise()
-    nextTick =>
+    requestAnimationFrame =>
       if @rendered
         if test.call @
-          if @transitioning
+          @_removeTransitionClasses()
+          if @_transitionTimer
             @_stopTransition("Transition canceled by #{evt} event.")
           @['_' + evt]()
           @context.visibility = visibility


Cleaned up ajax call, added optional dataSummary() call.

--- vendor/assets/javascripts/simple_datatables.js.coffee
+++ vendor/assets/javascripts/simple_datatables.js.coffee
@@ -73,4 +73,13 @@
       op = "_contains"
     data.push({name: "search["+searchcolumns.join("_or_")+op+"]", value: sSearch});

-  $.ajax( { "dataType": 'json', "type": "GET", "url": sSource, "data": data, "success": fnCallback } );
+  $.ajax({
+    "dataType": 'json',
+    "type": "GET",
+    "url": sSource,
+    "data": data,
+    "success": (data, textStatus, jqXHR) ->
+      fnCallback(data, textStatus, jqXHR);
+      if (typeof(dataSummary) == typeof(Function))
+        dataSummary()
+  });


fix trailingNewline values in splitting line

--- src/document.coffee
+++ src/document.coffee
@@ -79,8 +79,13 @@
   splitLine: (line, offset) ->
     [lineNode1, lineNode2] = ScribeUtils.splitNode(line.node, offset, true)
     line.node = lineNode1
+    trailingNewline = line.trailingNewline
+    line.trailingNewline = true
     this.updateLine(line)
-    return this.insertLineBefore(lineNode2, line.next)
+    newLine = this.insertLineBefore(lineNode2, line.next)
+    newLine.trailingNewline = trailingNewline
+    newLine.resetContent()
+    return newLine

   toDelta: ->
     lines = @lines.toArray()


A much more sophisticated insert command. Currently it has a major problem in that it can either insert before the current row or after the current row and therefore cannot insert at either the end of the document or the beginning of the document respectively

--- web/scripts/index.coffee
+++ web/scripts/index.coffee
@@ -27,10 +27,11 @@
     setUpInsertCommands: ->
         selector = $('#commandToInsert')
         for command of @commands
-            selector.append($("<option/>", {
-                value: command,
-                text: command
-                }))
+            selector.append $ "<option/>",
+                {
+                    value: command,
+                    text: command
+                }
         return

     displaySelectInputFields: (event) ->
@@ -39,7 +40,7 @@
         inputsDiv = $('#insertInputs')
         inputsDiv.empty()
         for i in [1..numberOfInputs] by 1
-            inputsDiv.append('<input type="text" size="5">')
+            inputsDiv.append("<input id='#{i}' type='text' size='5'>")
         return

     button: (func) ->
@@ -85,9 +86,16 @@
         return

     insertLine: (text, currentRow) ->
-        insertField = $('#lineToInsert')
-        toInsert = insertField.val()
-        insertField.val('')
+        command = $('#commandToInsert').find(':selected').text()
+        numberOfInputs = @commands[command]
+        inputs = []
+        inputsDiv = $('#insertInputs')
+        for i in [1..numberOfInputs] by 1
+            inputs[i - 1] = inputsDiv.find("##{1}").val()
+
+        # Possibly do some input sanitizing here.
+
+        toInsert = "#{command}(#{inputs.join()});"
         text.insertLines currentRow, [toInsert]
         return


Update index.coffee

Update index.coffee

Fixed typo

--- src/index.coffee
+++ src/index.coffee
@@ -126,7 +126,7 @@
     if options.allowHtml
       $elem.html(trans)
     else
-      if $elem.filter(otpions.interpolateSelector).length
+      if $elem.filter(options.interpolateSelector).length
         trans = trans.replace /{{([^{}]*)}}/g, (aa, bb) ->
           return t(bb)
       $elem.text(trans)


* add overwrite option to getContent/getContentSync

--- src/index.coffee
+++ src/index.coffee
@@ -231,7 +231,7 @@
   getContentSync: (aOptions)->
     aOptions = {} unless isObject aOptions
     aOptions.buffer = true
-    aOptions.overwrite = false
+    aOptions.overwrite = false unless aOptions.overwrite?
     result = @loadContentSync(aOptions)
     if aOptions.skipSize > 0 and isFunction result.slice
       result = result.slice(aOptions.skipSize)
@@ -242,7 +242,7 @@
       done = aOptions
     aOptions = {} unless isObject aOptions
     aOptions.buffer = true
-    aOptions.overwrite = false
+    aOptions.overwrite = false unless aOptions.overwrite?
     @loadContent aOptions, (err, result)->
       if result and aOptions.skipSize > 0 and isFunction result.slice
         result = result.slice(aOptions.skipSize)


fix broken test

fix broken test

--- src/index.coffee
+++ src/index.coffee
@@ -1,5 +1,5 @@
 leveldb = exports = module.exports = require '../build/leveldb.node'
-leveldb.version = '0.5.0'
+leveldb.version = '0.5.1'

 leveldb.createClient = ->
   client = new leveldb.DB


Make sure to not suppress errors.

Make sure to not suppress errors.

--- src/index.coffee
+++ src/index.coffee
@@ -1,6 +1,6 @@
 Promise = require 'zousan'

-Promise.suppressUncaughtRejectionError = true
+Promise.suppressUncaughtRejectionError = false

 class PromiseInspection
   constructor: ({@state, @value, @reason}) ->


Make Variable Private

Make Variable Private

--- src/index.coffee
+++ src/index.coffee
@@ -143,7 +143,7 @@

   setProjectToken: (projectTitle) ->
     projectTitle = @defaultProjectToken if (not projectTitle instanceof String) or (not projectTitle.length>0)
-    @projectToken = projectTitle
+    @_projectToken = projectTitle

   ###
   This will log a user interaction both in the Geordi


test hooks

test hooks

--- src/index.coffee
+++ src/index.coffee
@@ -19,6 +19,22 @@
     </div>
   '''
   replace: true # default: true
+  created: ->
+    console.log 'on created'
+  beforeCompile: ->
+    console.log 'on before compile'
+  compiled: ->
+    console.log 'on compiled'
+  ready: ->
+    console.log 'on ready'
+  attached: ->
+    console.log 'on attached'
+  detached: ->
+    console.log 'on detached'
+  beforeDestroy: ->
+    console.log 'on before destroy'
+  destroyed: ->
+    console.log 'on destroyed'

 tick = ->
   app.decriment()


persist as string instead of Locale object

--- src/index.coffee
+++ src/index.coffee
@@ -6,7 +6,7 @@
   (req, res, next) ->
     locales = new Locales req.headers["accept-language"]

-    req.locale = locales.best supported
+    req.locale = String locales.best supported
     do next

 class app.Locale


Removing deprecated raw api's after hubot-slack upgrade

--- src/index.coffee
+++ src/index.coffee
@@ -71,26 +71,22 @@
     message.attachments = _(message.attachments).difference removals
     return message

-  matchJiraTicket: (message) ->
-    if message.match?
-      matches = message.match Config.ticket.regexGlobal
+  matchJiraTicket: (context) ->
+    if context.match?
+      matches = context.match Config.ticket.regexGlobal
       unless matches and matches[0]
-        urlMatch = message.match Config.jira.urlRegex
+        urlMatch = context.match Config.jira.urlRegex
         if urlMatch and urlMatch[1]
           matches = [ urlMatch[1] ]
-    else if message.message?.rawText?.match?
-      matches = message.message.rawText.match Config.ticket.regexGlobal

     if matches and matches[0]
       return matches
-    else
-      if message.message?.rawMessage?.attachments?
-        attachments = message.message.rawMessage.attachments
-        for attachment in attachments
-          if attachment.text?
-            matches = attachment.text.match Config.ticket.regexGlobal
-            if matches and matches[0]
-              return matches
+    else if context.message?.attachments?
+      attachments = context.message.attachments
+      for attachment in attachments when attachment.text?
+        matches = attachment.text.match Config.ticket.regexGlobal
+        if matches and matches[0]
+          return matches
     return false

   prepareResponseForJiraTickets: (msg) ->
@@ -477,8 +473,7 @@

     #Create
     @robot.respond Config.commands.regex, (msg) =>
-      message = msg.message.rawText or msg.message.text
-      [ __, project, command, summary ] = message.match Config.commands.regex
+      [ __, project, command, summary ] = msg.match
       room = project or @adapter.getRoomName msg
       project = Config.maps.projects[room.toLowerCase()]
       type = Config.maps.types[command.toLowerCase()]


Fix comments

Fix comments

--- src/index.coffee
+++ src/index.coffee
@@ -7,10 +7,10 @@
 # APP SETUP
 #

-app = express() # Add Connect Assets
-app.use assets() # Set the public folder as static assets
-app.use express.static(process.cwd() + '/public') # Set View Engine
-app.set 'view engine', 'jade' # Configrue template
+app = express() # Create Express
+app.use assets() # Add Connect Assets
+app.use express.static(process.cwd() + '/public') # Set the public folder as static assets
+app.set 'view engine', 'jade' # Set View Engine

 # Set default lang
 lang = 'pl'


Allow to interpolate data-t, fix #13

Allow to interpolate data-t, fix #13

--- src/index.coffee
+++ src/index.coffee
@@ -102,13 +102,14 @@
   _.each $elem.attr(), (v, k) ->
     return if _.isEmpty(v) || k == selectorAttr
     if S(k).endsWith(options.attrSuffix)
-      attr = S(k).chompRight(options.attrSuffix).s
+      isData = options.useAttr && k == /^\[(.*?)\]$/.exec(options.selector)?[1]
+      attr = if isData then k else S(k).chompRight(options.attrSuffix).s
       trans = t(v)
       if interpolate
         trans = v.replace /{{([^{}]*)}}/g, (aa, bb) ->
           return t(bb)
       $elem.attr(attr, trans)
-      $elem.attr(k, null) if options.removeAttr
+      $elem.attr(k, null) if options.removeAttr && !isData
   $elem.attr(selectorAttr, null) if selectorAttr? && options.removeAttr
   $elem.attr(selectorInterpolateAttr, null) if selectorInterpolateAttr?

@@ -123,13 +124,16 @@
   if options.replace
     $elem.replaceWith trans
   else
+    interpolateAttr = /^\[(.*?)\]$/.exec(options.interpolateSelector)?[1]
+    interpolate = $elem.filter(options.interpolateSelector).length
+    if interpolate
+      trans = trans.replace /{{([^{}]*)}}/g, (aa, bb) ->
+        return t(bb)
     if options.allowHtml
       $elem.html(trans)
     else
-      if $elem.filter(options.interpolateSelector).length
-        trans = trans.replace /{{([^{}]*)}}/g, (aa, bb) ->
-          return t(bb)
       $elem.text(trans)
+    $elem.attr(interpolateAttr, null) if options.removeAttr && interpolate

 getPath = (fpath, locale, options) ->
   filepath = path.relative(options.baseDir, options.file)
@@ -170,10 +174,10 @@
   $ = cheerio.load(html, {decodeEntities: false})
   translateConditionalComments $, $.root(), locale, options, t if options.translateConditionalComments
   elems = $(options.selector)
+  $(options.attrSelector).each ->
+    translateAttributes $(this), options, t
   elems.each ->
     translateElem $, this, options, t
-  $(options.attrSelector).each ->
-    translateAttributes $(this), options, t
   if options.file && options.fixPaths
     fixPaths $, locale, options
   $.html()


update factoids url

update factoids url

also allow triggering on singular

--- src/factoids.coffee
+++ src/factoids.coffee
@@ -73,9 +73,9 @@
     else
       msg.reply 'Not a factoid'

-  robot.respond /factoids/i, (msg) =>
+  robot.respond /factoids?/i, (msg) =>
     url = process.env.HUBOT_BASE_URL or "http://not-yet-set/"
-    msg.reply "#{url.replace /\/$/, ''}/hubot/factoids"
+    msg.reply "#{url.replace /\/$/, ''}/#{robot.name}/factoids"

   robot.respond /alias (.{3,}) = (.{3,})/i, (msg) =>
     who = msg.message.user.name


make count of words before breaking a little dynamic until better solution arrives

--- src/frinkiac.coffee
+++ src/frinkiac.coffee
@@ -35,12 +35,29 @@
 getImageUrl = (episode, timestamp, caption) ->
   "https://frinkiac.com/meme/#{episode}/#{timestamp}.jpg?lines=#{encode(caption)}"

+getLongestWordLength = (words) ->
+  longestWordLength = 0
+  words.forEach (word) ->
+    longestWordLength = word.length if word.length > longestWordLength
+  longestWordLength
+
+getNumberOfWordsBeforeBreaking = (words) ->
+  longestWordLength = getLongestWordLength(words)
+  if longestWordLength <= 5
+    wordsBeforeBreaking = 5
+  else if 5 < longestWordLength <= 8
+    wordsBeforeBreaking = 4
+  else
+    wordsBeforeBreaking = 3
+  wordsBeforeBreaking
+
 addLineBreaks = (str) ->
-  wordCount = 4
   newString = ''
-  str.split(' ').forEach (word, i) ->
+  words = str.split(' ')
+  wordsBeforeBreaking = getNumberOfWordsBeforeBreaking(words)
+  words.forEach (word, i) ->
     i++
-    delimiter = if i % wordCount then ' ' else '\n'
+    delimiter = if i % wordsBeforeBreaking then ' ' else '\n'
     newString += word + delimiter
   newString


Add failing test to demonstrate problem

Add failing test to demonstrate problem

--- spec/package-detail-view-spec.coffee
+++ spec/package-detail-view-spec.coffee
@@ -3,6 +3,7 @@

 PackageDetailView = require '../lib/package-detail-view'
 PackageManager = require '../lib/package-manager'
+AtomIoClient = require '../lib/atom-io-client'

 describe "PackageDetailView", ->
   packageManager = null
@@ -47,13 +48,30 @@
     expect(view.loadingMessage[0].classList.contains('hidden')).not.toBe(true)
     expect(packageManager.client.package).toHaveBeenCalled()

-  it "shows an error when package metadata cannot be loaded", ->
+  it "shows an error when package metadata cannot be loaded via the API", ->
     packageManager.client = createClientSpy()
     packageManager.client.package.andCallFake (name, cb) ->
-      error = new Error('API or cache error')
+      error = new Error('API error')
       cb(error, null)

     view = new PackageDetailView({name: 'nonexistent-package'}, packageManager)
+
+    expect(view.errorMessage[0].classList.contains('hidden')).not.toBe(true)
+    expect(view.loadingMessage[0].classList.contains('hidden')).toBe(true)
+    expect(view.find('.package-card').length).toBe(0)
+
+  it "shows an error when package metadata cannot be loaded from the cache and the network is unavailable", ->
+    spyOn(AtomIoClient.prototype, 'online').andReturn(false)
+    spyOn(AtomIoClient.prototype, 'request').andCallThrough()
+    spyOn(AtomIoClient.prototype, 'fetchFromCache').andCallFake (path, opts, cb) ->
+      # this is the special case which happens when the data is not in the cache
+      # and there's no connectivity
+      cb(null, {})
+
+    view = new PackageDetailView({name: 'some-package'}, packageManager)
+
+    expect(AtomIoClient.prototype.fetchFromCache).toHaveBeenCalled()
+    expect(AtomIoClient.prototype.request).not.toHaveBeenCalled()

     expect(view.errorMessage[0].classList.contains('hidden')).not.toBe(true)
     expect(view.loadingMessage[0].classList.contains('hidden')).toBe(true)


include n parameter when packing

include n parameter when packing

--- app/coffee/PackManager.coffee
+++ app/coffee/PackManager.coffee
@@ -286,6 +286,7 @@
 			if top?	&& top.pack.length < PackManager.MAX_COUNT && top.sz + sz < PackManager.MAX_SIZE
 				top.pack = top.pack.concat {v: d.v, meta: d.meta,  op: d.op, _id: d._id}
 				top.sz += sz
+				top.n += 1
 				top.v_end = d.v
 				top.meta.end_ts = d.meta.end_ts
 				return
@@ -295,6 +296,7 @@
 				top.pack = [ {v: d.v, meta: d.meta,  op: d.op, _id: d._id} ]
 				top.meta = { start_ts: d.meta.start_ts, end_ts: d.meta.end_ts }
 				top.sz = sz
+				top.n = 1
 				top.v_end = d.v
 				delete top.op
 				delete top._id


Fixed #2036 (making it less likely that the mistake will ercur, anyway).

--- app/lib/DefaultScripts.coffee
+++ app/lib/DefaultScripts.coffee
@@ -8,7 +8,7 @@
         focus:
           bounds: [{x: 0, y: 0}, {x: 80, y: 68}]
           target: "Hero Placeholder"
-          zoom: 2
+          zoom: 0.5
       sound:
         music:
           file: "/music/music_level_2"