Add --version option

Add --version option

--- src/cli.coffee
+++ src/cli.coffee
@@ -5,8 +5,9 @@

 module.exports = ->
   cli = optimist.describe('h', 'Show this message').alias('h', 'help')
+                .describe('o', 'File path to write the HTML output to').alias('o', 'output').string('o')
                 .describe('s', 'Scope name of the grammar to use').alias('s', 'scope').string('s')
-                .describe('o', 'File path to write the HTML output to').alias('o', 'output').string('o')
+                .describe('v', 'Output the version').alias('v', 'version').boolean('s')
   optimist.usage """
     Usage: highlights [options] [file]

@@ -17,6 +18,11 @@

   if cli.argv.help
     cli.showHelp()
+    return
+
+  if cli.argv.version
+    {version} = require '../package.json'
+    console.log(version)
     return

   [filePath] = cli.argv._


GameObject.Effect

GameObject.Effect

--- test/tweening.coffee
+++ test/tweening.coffee
@@ -11,7 +11,7 @@
     o.update(1)
     o.trigger "afterUpdate", 1

-    equals o.I.x, i
+    equals o.I.x, i +

 # Clear out the module
 module()


Removed unnecessary Q.fcall

Removed unnecessary Q.fcall

--- src/time-manager.coffee
+++ src/time-manager.coffee
@@ -31,7 +31,7 @@

 			winston.silly "begin tick '#{target.name} #{target.constructor.name}' #{target.x},#{target.y}"

-			Q.fcall -> target.tick()
+			Q target.tick()
 			.then (cost = 0) =>
 				rate = _.result target, 'tickRate'


sending all events to particles

sending all events to particles

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -30,5 +30,5 @@
   @param {Function} fn Code to execute after n frames has passed
   ###
   every: (n, fn) ->
-    while I.
+    while I.everyEv
       fn()


remove step from game object default events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -44,4 +44,4 @@
       lastFired: I.age

   sendOrApply: (fn) ->
-    if t+    if typeof fn is


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Title Screen class sets up a simple game title sc
+The Title Screen class sets up a simple game title screen using the

 By default, images are loaded asynchronously. A proxy object is
 returned immediately. Even though it has a draw method it will not


change unwrap implementation to play nicer with browser selections

--- src/dom.coffee
+++ src/dom.coffee
@@ -121,12 +121,13 @@
       curNode = nextSibling

   unwrap: (node) ->
-    next = node.firstChild
+    ret = node.firstChild
+    next = node.nextSibling
     _.each(_.clone(node.childNodes), (child) ->
-      node.parentNode.insertBefore(child, node)
+      node.parentNode.insertBefore(child, next)
     )
     node.parentNode.removeChild(node)
-    return next
+    return ret

   wrap: (wrapper, node) ->
     node.parentNode.insertBefore(wrapper, node)


removed unused logger

removed unused logger

--- src/utils/logger.coffee
+++ src/utils/logger.coffee
@@ -1,12 +0,0 @@
-module.exports =
-  class Logger
-
-    setConsole: (name) ->
-      @console = document.getElementById(name)
-
-    # quick & dirty logger
-    log: (msg) ->
-      if typeof @console isnt "undefined"
-        @console.innerHTML = msg
-      else
-        console.log msg


Don’t fall back to a random wrong Electron version, just blow up

Signed-off-by: Max Brunsfeld <78036c9b69b887700d5846f26a788d53b201ffbb@github.com>

--- src/command.coffee
+++ src/command.coffee
@@ -90,8 +90,9 @@
         version = @normalizeVersion(version)
         @installedAtomVersion = version if semver.valid(version)

-      # TODO Remove ATOM_NODE_VERSION env var support after a couple releases
-      @electronVersion = process.env.ATOM_ELECTRON_VERSION ? process.env.ATOM_NODE_VERSION ? electronVersion ? '0.22.0'
+      @electronVersion = process.env.ATOM_ELECTRON_VERSION ? electronVersion
+      unless @electronVersion?
+        throw new Error('Could not determine Electron version')

       callback()


Add a more thorough check in metainfo_listener

This works around a bug where the metainfo_listener gets called with a raw data chunk, no element info. Either its not
getting unregistered properly or it is getting re-registered.

--- src/decoder.coffee
+++ src/decoder.coffee
@@ -101,7 +101,7 @@
       @metainfo_done = false

       @metainfo_listener = (event) =>
-        if event.element.tag == 0x00020010
+        if event && event.element && event.element.tag == 0x00020010
           @metainfo_ts = event.vr.value()
           log.debug {ts: @metainfo_ts}, "metainfo transfer syntax found"
       @on 'data', @metainfo_listener


Support specifying a directory to apm develop

This will be the folder that the repository will be cloned into.

--- src/develop.coffee
+++ src/develop.coffee
@@ -25,12 +25,15 @@
     options = optimist(argv)

     options.usage """
-      Usage: apm develop <package_name>
+      Usage: apm develop <package_name> [<directory>]

-      Clone the given package's Git repository to ~/github/<package_name>,
+      Clone the given package's Git repository to the directory specified,
       install its dependencies, and link it for development to
-      ~/.atom/packages/dev/<package_name>. The default folder to clone packages
-      into can be overridden using the ATOM_REPOS_HOME environment variable.
+      ~/.atom/packages/dev/<package_name>.
+
+      If no directory is specified then the repository is cloned to
+      ~/github/<package_name>. The default folder to clone packages into can
+      be overridden using the ATOM_REPOS_HOME environment variable.

       Once this command completes you can open a dev window from atom using
       cmd-shift-o to run the package out of the newly cloned repository.
@@ -84,7 +87,8 @@

   run: (options) ->
     packageName = options.commandArgs.shift()
-    packageDirectory = path.join(config.getReposDirectory(), packageName)
+    packageDirectory = options.commandArgs.shift() ? path.join(config.getReposDirectory(), packageName)
+    packageDirectory = path.resolve(packageDirectory)

     if fs.existsSync(packageDirectory)
       @linkPackage(packageDirectory, options)


Hide crop form when switching format

Hide crop form when switching format

--- BackofficeBundle/Resources/public/coffee/mediatheque/SuperboxView.coffee
+++ BackofficeBundle/Resources/public/coffee/mediatheque/SuperboxView.coffee
@@ -106,9 +106,10 @@
           currentView.addSelect2OnForm()

   changeView: (e) ->
+    $('#crop-group').hide()
+    $(".media-override-format-form", @$el).hide()
     superboxViewParam['jcrop_api'].destroy() if superboxViewParam['jcrop_api'] != undefined
     $('.media_crop_preview img', @$el).hide()
-    $(".media-override-format-form", @$el).hide()
     format = e.currentTarget.value
     $('.superbox-current-img', @$el).append('


make harder

make harder

--- src/Landscape.coffee
+++ src/Landscape.coffee
@@ -193,7 +193,7 @@
     player.runner.dot.height = player.runner.dot.y - player.runner.y - 8

   addCollect:(min)->
-    obj = if @position % 100 == 0 and @game.rnd.frac() < 0.2
+    obj = if @position % 100 == 0 && @game.rnd.frac() < 0.4 || @game.rnd.frac() < 0.1
       @game.add.sprite(900, 0, 'bomb')
     else
       @game.add.sprite(900, 0, 'coin')


Fixed NewCase callback

Fixed NewCase callback

--- src/fogbugz.coffee
+++ src/fogbugz.coffee
@@ -48,7 +48,7 @@
 	command += CaseOptions(options)

 	CallApi(command, token, (err, result) ->
-		if err then callback(new Error('Error making new case: ' + err.message)) else callback(result['case'][0])
+		if err then callback(new Error('Error making new case: ' + err.message)) else callback(null, result['case'][0])
 	)

 EditCase = (options, token, callback) ->


I mean, I should run the specs first

I mean, I should run the specs first

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -148,10 +148,10 @@
   AtomModifiers.has(keystroke) or AtomModifierRegex.test(keystroke)

 exports.keydownEvent = (key, options) ->
-  return exports.keyboardEvent(key, 'keydown', options)
+  return keyboardEvent(key, 'keydown', options)

 exports.keyupEvent = (key, options) ->
-  return exports.keyboardEvent(key, 'keyup', options)
+  return keyboardEvent(key, 'keyup', options)

 keyboardEvent = (key, eventType, {ctrl, shift, alt, cmd, keyCode, target, location}={}) ->
   event = document.createEvent('KeyboardEvent')


Parse keystroke directly

Parse keystroke directly

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -1,5 +1,5 @@
 {specificity} = require 'clear-cut'
-[parser, fs, loophole, pegjs] = []
+[fs, loophole, pegjs] = []

 AtomModifiers = new Set
 AtomModifiers.add(modifier) for modifier in ['ctrl', 'alt', 'shift', 'cmd']
@@ -228,17 +228,14 @@
   keystroke.join('-')

 parseKeystroke = (keystroke) ->
-  unless parser?
-    try
-      parser = require './keystroke'
-    catch e
-      fs ?= require 'fs'
-      loophole ?= require 'loophole'
-      pegjs ?= require 'pegjs'
-      keystrokeGrammar = fs.readFileSync(require.resolve('./keystroke.pegjs'), 'utf8')
-      loophole.allowUnsafeEval => parser = pegjs.buildParser(keystrokeGrammar)
-
-  parser.parse(keystroke)
+  keys = []
+  keyStart = 0
+  for character, index in keystroke when character is '-'
+    if index > keyStart
+      keys.push(keystroke.substring(keyStart, index))
+      keyStart = index + 1
+  keys.push(keystroke.substring(keyStart)) if keyStart < keystroke.length
+  keys

 charCodeFromKeyIdentifier = (keyIdentifier) ->
   parseInt(keyIdentifier[2..], 16) if keyIdentifier.indexOf('U+') is 0


DRY Visual Studio flag determination

DRY Visual Studio flag determination

--- src/install.coffee
+++ src/install.coffee
@@ -59,19 +59,14 @@
         callback("#{stdout}\n#{stderr}")

   installModule: (options, pack, modulePath, callback) ->
-    vsArgs = null
-    if config.isWin32()
-      vsArgs = "--msvs_version=2010" if config.isVs2010Installed()
-      vsArgs = "--msvs_version=2012" if config.isVs2012Installed()
-
-      throw new Error("You must have either VS2010 or VS2012 installed") unless vsArgs
-
     installArgs = ['--userconfig', config.getUserConfigPath(), 'install']
     installArgs.push(modulePath)
     installArgs.push("--target=#{config.getNodeVersion()}")
     installArgs.push('--arch=ia32')
     installArgs.push('--silent') if options.argv.silent
-    installArgs.push(vsArgs) if vsArgs?
+
+    if vsArgs = @getVisualStudioFlags()
+      installArgs.push(vsArgs)

     env = _.extend({}, process.env, HOME: @atomNodeDirectory)
     env.USERPROFILE = env.HOME if config.isWin32()
@@ -101,6 +96,17 @@

         callback("#{stdout}\n#{stderr}")

+  # Private
+  getVisualStudioFlags: ->
+    return null unless config.isWin32()
+
+    if config.isVs2010Installed()
+      "--msvs_version=2010"
+    else if config.isVs2012Installed()
+      "--msvs_version=2012"
+    else
+      throw new Error("You must have either VS2010 or VS2012 installed")
+
   installModules: (options, callback) =>
     process.stdout.write 'Installing modules '

@@ -117,7 +123,10 @@
     installArgs.push("--target=#{config.getNodeVersion()}")
     installArgs.push('--arch=ia32')
     installArgs.push('--silent') if options.argv.silent
-    installArgs.push('--msvs_version=2012') if config.isWin32()
+
+    if vsArgs = @getVisualStudioFlags()
+      installArgs.push(vsArgs)
+
     env = _.extend({}, process.env, HOME: @atomNodeDirectory)
     env.USERPROFILE = env.HOME if config.isWin32()
     installOptions = {env}


Omit try

Omit try

--- src/add/index.coffee
+++ src/add/index.coffee
@@ -13,6 +13,6 @@
 do require './opener'

 require './validate'
-try require './users'
+require './users'

 evloop.start()


Remove clientOnly option which isn't used

--- timestampable.coffee
+++ timestampable.coffee
@@ -10,8 +10,7 @@

 behaviour = (options = {}) ->

-  {clientOnly, createdAt, createdBy, updatedAt, updatedBy} =
-    _.defaults options, defaults
+  {createdAt, createdBy, updatedAt, updatedBy} = _.defaults options, defaults

   if ss?
     SimpleSchema = ss.SimpleSchema


Highlight braced loops in scores

Highlight braced loops in scores

--- grammars/csound-score.cson
+++ grammars/csound-score.cson
@@ -9,44 +9,68 @@
     include: 'source.csound#commentsAndMacroCalls'
   }
   {
-    name: 'meta.statement.csound-score'
-    begin: '([abefimq-tv-z]|[nN][pP]?)|([{}])'
+    name: 'keyword.control.csound-score'
+    match: '[abefimq-tv-z]|[nN][pP]?'
+  }
+  {
+    include: 'source.csound#numbers'
+  }
+  {
+    name: 'string.quoted.csound-score'
+    begin: '"'
     beginCaptures:
-      1:
-        name: 'keyword.control.csound-score'
-      2:
-        name: 'punctuation.csound-score'
-    end: '\\n'
+      0:
+        name: 'punctuation.definition.string.begin.csound-score'
+    end: '"'
+    endCaptures:
+      0:
+        name: 'punctuation.definition.string.end.csound-score'
     patterns: [
       {
-        include: 'source.csound#commentsAndMacroCalls'
+        include: 'source.csound#macroCalls'
+      }
+    ]
+  }
+  {
+    name: 'meta.braced-loop.csound-score'
+    begin: '{'
+    beginCaptures:
+      0:
+        name: 'punctuation.csound-score'
+    end: '}'
+    endCaptures:
+      0:
+        name: 'punctuation.csound-score'
+    patterns: [
+      {
+        name: 'meta.braced-loop-details.csound-score'
+        begin: '\\d+'
+        beginCaptures:
+          0:
+            name: 'constant.numeric.integer.decimal.csound-score'
+        end: '(?=})'
+        patterns: [
+          {
+            name: 'meta.braced-loop-macro-name.csound-score'
+            begin: '[A-Z_a-z]\\w*\\b'
+            beginCaptures:
+              0:
+                name: 'entity.name.function.preprocessor.csound-score'
+            end: '(?=})'
+            patterns: [
+              {
+                include: '$self'
+              }
+            ]
+          }
+          {
+            include: '#comments'
+          }
+        ]
       }
       {
-        include: '#partialExpressions'
+        include: '#comments'
       }
     ]
   }
 ]
-repository:
-  partialExpressions:
-    patterns: [
-      {
-        include: 'source.csound#numbers'
-      }
-      {
-        name: 'string.quoted.csound-score'
-        begin: '"'
-        beginCaptures:
-          0:
-            name: 'punctuation.definition.string.begin.csound-score'
-        end: '"'
-        endCaptures:
-          0:
-            name: 'punctuation.definition.string.end.csound-score'
-        patterns: [
-          {
-            include: 'source.csound#macroCalls'
-          }
-        ]
-      }
-    ]


reordered and removed `livereload: false`

--- grunt/contrib-watch.coffee
+++ grunt/contrib-watch.coffee
@@ -19,8 +19,13 @@
       tasks: [
         'compass:dev'
       ]
+    css:
+      files: [
+        '<%= compass.dev.options.sassDir %>/styles.css'
+        '<%= compass.dev.options.imagesDir %>/**/*.png'
+      ]
       options:
-        livereload: false
+        livereload: true
     jade:
       files: [
         '*.jade'
@@ -31,12 +36,5 @@
       ]
       options:
         livereload: true
-    css:
-      files: [
-        '<%= compass.dev.options.sassDir %>/styles.css'
-        '<%= compass.dev.options.imagesDir %>/**/*.png'
-      ]
-      options:
-        livereload: true

   grunt.loadNpmTasks 'grunt-contrib-watch'


Added tests for Bacon.fromPromise 'abort on unsub' feature

--- spec/PromiseSpec.coffee
+++ spec/PromiseSpec.coffee
@@ -10,6 +10,7 @@
     calls = calls + 1
 }
 _ = Bacon._
+nop = ->

 describe "Bacon.fromPromise", ->
   it "should produce value and end on success", ->
@@ -30,4 +31,18 @@
     dispose()
     success("a")
     expect(events).toEqual([])
+
+  it "should abort ajax promise on unsub", ->
+    isAborted = false
+    promise.abort = ->
+      isAborted = true
+    dispose = Bacon.fromPromise(promise).subscribe(nop)
+    dispose()
+    delete promise.abort
+    expect(isAborted).toEqual(true)

+  it "should not abort non-ajax promise", ->
+    isAborted = false
+    dispose = Bacon.fromPromise(promise).subscribe(nop)
+    dispose()
+    expect(isAborted).toEqual(false)


WIP Add test for ensuring that set/unset operations take place after load

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -1756,3 +1756,34 @@

           expect(atom.config.set('foo.bar.str_options', 'One')).toBe false
           expect(atom.config.get('foo.bar.str_options')).toEqual 'two'
+  describe "when .set/.unset is called prior to .loadUserConfig", ->
+    console.log 'this test'
+    beforeEach ->
+      fs.writeFileSync config.configFilePath, """
+        '*':
+          foo:
+            bar: 'baz'
+          do:
+            ray: 'me'
+      """
+
+    it "ensures that all settings are loaded correctly", ->
+      console.log 'test start'
+      config.unset('foo.bar')
+      expect(config.save).not.toHaveBeenCalled()
+      config.set('foo.qux', 'boo')
+      expect(config.save).not.toHaveBeenCalled()
+      expect(config.get('foo.qux')).toBeUndefined()
+      expect(config.get('do.ray')).toBeUndefined()
+
+      console.log 'loadUserConfig'
+      config.loadUserConfig()
+
+      waitsFor -> config.get('foo.bar') is undefined
+      runs ->
+        expect(config.save).toHaveBeenCalled()
+        expect(config.get('foo.bar')).toBeUndefined()
+        expect(config.get('foo.qux')).toBe('boo')
+        expect(config.get('do.ray')).toBe('me')
+
+      console.log 'end test'


Fixed home path

Fixed home path

--- .metalsmith/plugins/popularapi.coffee
+++ .metalsmith/plugins/popularapi.coffee
@@ -23,7 +23,7 @@

 # Load secrets from the home directory
-secrets = require(path.join "/", process.env.USER, ".kdlearn", "secret_config.json").analytics
+secrets = require(path.join process.env.HOME, ".kdlearn", "secret_config.json").analytics

 # Create a new file in the files object.
@@ -58,7 +58,7 @@
 queryAnalytics = (opts={}, callback) ->
   authClient = new google.auth.JWT(
     secrets.email,
-    path.join("/", process.env.USER, ".kdlearn", secrets["key-file"]),
+    path.join(process.env.HOME, ".kdlearn", secrets["key-file"]),
     secrets.key,
     ['https://www.googleapis.com/auth/analytics.readonly']
   )


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -18,6 +18,7 @@
         width
       } = meterData

+      if I
       ratio = I[name] / I["max#{name.capitalize()}"]

       if showName || text


rm cruft

rm cruft

--- src/methods.coffee
+++ src/methods.coffee
@@ -498,5 +498,3 @@
       @run_bytecode runtime_state, padding
     cf = runtime_state.curr_frame()
     debug "#{padding}stack: [#{pa cf.stack}], local: [#{pa cf.locals}] (method end)"
-
-  resume: (runtime_state, pc) ->


Constants streamlined: MAX and MIN are numbers, Limit instead of Infinity

--- src/minimax.coffee
+++ src/minimax.coffee
@@ -1,6 +1,6 @@
 # MINIMAX

-[MAX, MIN] = ['MAX', 'MIN']
+[MAX, MIN] = [1, 2]

 # Action :: Any

@@ -12,8 +12,10 @@
 #   play : Action -> State
 # }

+Limit = 2000000000 # two billion, faster than using Infinity
+
 class MinimaxAgent
-  constructor: (@depth = Infinity) ->
+  constructor: (@depth = Limit) ->
     @rootAgent = MAX

   # nextAction :: (state:State) -> Action
@@ -22,7 +24,7 @@
     [_, bestAction] = @minimax state
     bestAction

-  minimax: (state, α = -Infinity, β = +Infinity, ply = 0) ->
+  minimax: (state, α = -Limit, β = +Limit, ply = 0) ->
     isTerminal = state.isTerminal()
     ++ply if not isTerminal and state.nextAgent() is @rootAgent
     if ply > @depth or isTerminal
@@ -33,7 +35,7 @@
       @mini state, α, β, ply

   maxi: (state, α, β, ply) ->
-    [v, a] = [-Infinity, null]
+    [v, a] = [-Limit, null]
     for action in state.possibleActions()
       successor = state.play action
       [nextValue, _] = @minimax successor, α, β, ply
@@ -44,7 +46,7 @@
     [v, a]

   mini: (state, α, β, ply) ->
-    [v, a] = [+Infinity, null]
+    [v, a] = [+Limit, null]
     for action in state.possibleActions()
       successor = state.play action
       [nextValue, _] = @minimax successor, α, β, ply
@@ -54,4 +56,4 @@
       β = Math.min β, v
     [v, a]

-module.exports = { MAX, MIN, MinimaxAgent }
+module.exports = { MAX, MIN, Limit, MinimaxAgent }


trap the system properties, for speed and convenience

--- src/natives.coffee
+++ src/natives.coffee
@@ -13,6 +13,22 @@
 # things assigned to root will be available outside this module
 root = exports ? this.natives = {}

+system_properties = {
+  'java.home':'third_party/java_home/', 'file.encoding':'US_ASCII','java.vendor':'DoppioVM',
+  'java.version': '1.6', 'java.vendor.url': 'https://github.com/int3/doppio',
+  'java.class.version': '50.0', 'java.class.path': '.',
+  'line.separator':'\n', 'file.separator':'/', 'path.separator':':',
+  'user.dir':'.','user.home':'.','user.name':'DoppioUser',
+  'os.name':'Doppio', 'os.arch': 'js', 'os.version': '0',
+  'sun.boot.class.path': 'third_party/classes:third_party/java_home/lib/rt.jar',
+  'java.awt.headless': 'true',
+  'useJavaUtilZip': 'true'  # hack for sun6javac, avoid ZipFileIndex shenanigans
+}
+
+get_property = (rs, jvm_key, _default) ->
+  val = system_properties[rs.jvm2js_str(jvm_key)]
+  if val? then rs.init_string(val, true) else _default
+
 # convenience function. idea taken from coffeescript's grammar
 o = (fn_name, fn) -> fn_name: fn_name, fn: fn

@@ -26,6 +42,8 @@
       System: [
         o 'loadLibrary(L!/!/String;)V', (rs) -> # NOP, because we don't support loading external libraries
         o 'adjustPropertiesForBackwardCompatibility(L!/util/Properties;)V', (rs) -> # NOP (apple-java specific)
+        o 'getProperty(L!/!/String;)L!/!/String;', get_property
+        o 'getProperty(L!/!/String;L!/!/String;)L!/!/String;', get_property
       ]
       Terminator: [
         o 'setup()V', (rs) -> # NOP, because we don't support threads
@@ -87,19 +105,6 @@
   rs.push action unless m.access_flags.static
   m.run(rs,m.access_flags.virtual)
   rs.pop()
-
-# properties to set:
-#  java.version,java.vendor.url,java.class.version,java.class.path,os.arch,os.version
-system_properties = {
-  'java.home':'third_party/java_home/', 'file.encoding':'US_ASCII','java.vendor':'DoppioVM',
-  'line.separator':'\n', 'file.separator':'/', 'path.separator':':',
-  'user.dir':'.','user.home':'.','user.name':'DoppioUser',
-  'os.name':'Doppio',
-  'sun.boot.class.path': 'third_party/classes:third_party/java_home/lib/rt.jar',
-  # this doesn't actually exist in our classes.jar, but no other GraphicsEnvironment does either
-  'java.awt.graphicsenv': 'sun.awt.X11GraphicsEnvironment',
-  'useJavaUtilZip': 'true'  # hack for sun6javac, avoid ZipFileIndex shenanigans
-}

 get_field_from_offset = (rs, cls, offset) ->
   classname = cls.this_class.toClassString()
@@ -323,15 +328,7 @@
               dest.array[j++] = src.array[i]
         o 'currentTimeMillis()J', (rs) -> gLong.fromNumber((new Date).getTime())
         o 'identityHashCode(L!/!/Object;)I', (x) -> x.ref
-        o 'initProperties(L!/util/Properties;)L!/util/Properties;', (rs, props) ->
-            m = rs.method_lookup
-              class: 'java/util/Properties'
-              sig: 'setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;'
-            for k,v of system_properties
-              rs.push props, rs.init_string(k,true), rs.init_string(v,true)
-              m.run(rs)
-              rs.pop()  # we don't care about the return value
-            props
+        o 'initProperties(L!/util/Properties;)L!/util/Properties;', (rs, props) -> # NOP, we trap the getProperty call
         o 'nanoTime()J', (rs) ->
             # we don't actually have nanosecond precision
             gLong.fromNumber((new Date).getTime()).multiply(gLong.fromNumber(1000000))


Add package name to Grim.deprecate call for configDefaults

--- src/package.coffee
+++ src/package.coffee
@@ -161,9 +161,9 @@
       if @mainModule.config? and typeof @mainModule.config is 'object'
         atom.config.setSchema @name, {type: 'object', properties: @mainModule.config}
       else if includeDeprecatedAPIs and @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object'
-        deprecate """Use a config schema instead. See the configuration section
+        deprecate("""Use a config schema instead. See the configuration section
         of https://atom.io/docs/latest/hacking-atom-package-word-count and
-        https://atom.io/docs/api/latest/Config for more details"""
+        https://atom.io/docs/api/latest/Config for more details""", {packageName: @name})
         atom.config.setDefaults(@name, @mainModule.configDefaults)
       @mainModule.activateConfig?()
     @configActivated = true


fix search to search text in html, not data

--- app/scripts/alchemy/core/search.coffee
+++ app/scripts/alchemy/core/search.coffee
@@ -25,11 +25,10 @@

             d3.selectAll("text").attr("style", ->
                 "display: inline;" if input != "")
-
             d3.selectAll(".node")
               .classed("inactive", (node) ->
-
-                hidden = node.caption
+                DOMnode = d3.select(@)
+                hidden = DOMnode.text()
                              .toLowerCase()
                              .indexOf(input) < 0


adding new default config

adding new default config

--- app/scripts/alchemy/defaultConf.coffee
+++ app/scripts/alchemy/defaultConf.coffee
@@ -79,6 +79,7 @@
     edgeStyle: (d)->
         null
     edgeTypes: null
+    curvedEdges: false

     # Search
     search: true


Use `response.success`

Use `response.success`

--- src/request.coffee
+++ src/request.coffee
@@ -49,9 +49,9 @@
   _stateChange: ->
     return unless @xhr.readyState is XMLHttpRequest.DONE

-    @response = new Response(@xhr)
+    @response = new Response @xhr

-    if @xhr.status in [200..299]
+    if @response.success
       @_emitter.emit "success", @response
     else
       @_emitter.emit "error", @response


Removing If-Modified-Since which is causing issues

--- src/request.coffee
+++ src/request.coffee
@@ -110,14 +110,6 @@
     # Send the ETag if re-requesting a URL
     if cacheHandler.get(method, path)
       headers['If-None-Match'] = cacheHandler.get(method, path).eTag
-    else
-      # The browser will sneak in a 'If-Modified-Since' header if the GET has been requested before
-      # but for some reason the cached response does not seem to be available
-      # in the jqXHR object.
-      # So, the first time a URL is requested set this date to 0 so we always get a response the 1st time
-      # a URL is requested.
-      headers['If-Modified-Since'] = 'Thu, 01 Jan 1970 00:00:00 GMT'
-

     if (clientOptions.token) or (clientOptions.username and clientOptions.password)
       if clientOptions.token


it's important to test your code, corey

it's important to test your code, corey

--- src/require.coffee
+++ src/require.coffee
@@ -31,9 +31,9 @@
 # cb   - The Function that will actually run the code.
 define  = (args...) ->
   defines.push ->
-    file = args[0]
+    file = args[0] if args.length > 1
     cb = args[1] or args[0]
-    exports = if file then __modules[file] else {}
+    exports = if file? then __modules[file] else {}
     module = exports: exports
     cb.call exports, require, exports, module
     module.exports or exports


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -10,4 +10,4 @@
     Object.extend(I.clampData, data)

   clampToBounds: (bounds) ->
-    bounds ||= Rectangle x: 0, y: 0, A+    bounds ||= Rectangle x: 0, y: 0, App.width, App.height


first => head

first => head

--- infowrap-filepicker.coffee
+++ infowrap-filepicker.coffee
@@ -361,7 +361,7 @@
     api.writeUrl = (targetFpFile, url, opt) ->
       defer = $q.defer()
       opt = opt or {}
-      cleanUrl = _.first(url.split('?'))
+      cleanUrl = _.head(url.split('?'))
       api.log(cleanUrl)

       filepicker.writeUrl targetFpFile, cleanUrl, opt, (fpfile) ->


:art: Add some whitespace as a separator between tests

--- spec/helper-spec.coffee
+++ spec/helper-spec.coffee
@@ -3,6 +3,7 @@
 testFile = __dirname + '/fixtures/test.txt'
 testContents = fs.readFileSync(testFile).toString()
 describe 'linter helpers', ->
+
   describe '::exec*', ->
     it 'cries when no argument is passed', ->
       expect( -> helpers.exec()).toThrow()
@@ -35,6 +36,7 @@
       waitsForPromise ->
         helpers.exec(__dirname + '/fixtures/stderr.sh', []).catch (message) ->
           expect(message).toBe("STDERR\n")
+
   describe '::parse', ->
     it 'cries when no argument is passed', ->
       expect ->
@@ -55,6 +57,7 @@
       )]
       results = helpers.parse(input, regex)
       expect(results).toEqual(output)
+
   describe '::findFile', ->
     it 'cries wen no argument is passed', ->
       expect ->


bug fix

bug fix

--- src/ritsbus.coffee
+++ src/ritsbus.coffee
@@ -42,7 +42,7 @@
     to = "minakusa"
     toName = "南草津"
     now = new Date
-    console.log options = msg.match[2].replace(/^\s+/,"").split(/\s/)
+    options = msg.match[2].replace(/^\s+/,"").split(/\s/)

     # 何分後のバスを検索するか取得
     extensionMinutes = getExtensionMinutes(options)
@@ -99,8 +99,8 @@
   #デフォルトは7分後からのバスを表示
   extensionMinutes = 7
   for opt in options
-    if /\d*/.test(opt)
-      console.log extensionMinutes = parseInt(opt.match(/\d*/), 10)
+    if /\d+/.test(opt)
+      extensionMinutes = parseInt(opt.match(/\d+/), 10)
   return extensionMinutes

 # 経由地判定


rewire all events when replacing

rewire all events when replacing

--- src/xml.coffee
+++ src/xml.coffee
@@ -25,20 +25,31 @@
         tag.builder ?= @builder
         tag.parent  ?= this

+        self = this
         listeners = {}
-        pipe = (event) =>
-            tag.on? event, listeners[event] = =>
-                @emit event, arguments...
-        dispose = (el) =>
-            return unless el is this or el is tag
-            @removeListener('remove', dispose)
+        pipe = (event) ->
+            tag.on? event, listeners[event] = ->
+                self.emit event, arguments...
+        dispose = (el) ->
+            return unless el is self or el is tag
+            self.removeListener('repipe', repipe)
+            self.removeListener('remove', dispose)
             tag.removeListener?('remove', dispose)
             for event in EVENTS
-                tag.removeListener?(event, listeners[event])
-            delete listeners
-        pipe event for event in EVENTS
-        tag.once?('remove', dispose)
-        @once('remove', dispose)
+                if (listener = listeners[event])?
+                    tag.removeListener?(event, listener)
+            listeners = {}
+        wire = ->
+            pipe event for event in EVENTS
+            tag.once?('remove', dispose)
+            self.once('remove', dispose)
+            self.once('repipe', repipe)
+        repipe = (replacement) ->
+            dispose(self)
+            self = replacement
+            wire()
+        # enough preparation, lets do it:
+        wire()

         @emit 'add', this, tag
         @emit 'new', tag
@@ -221,10 +232,17 @@
         add_tag.call(this, tag, callback)
         this

-    replace: (tag) =>
-        # FIXME should happen smthing smart?
-        # should both instances become one? when yes, how?
+    replace: (rawtag) =>
+        tag = @builder?.query 'tag', this, rawtag
+        tag = rawtag unless tag? or @builder?
+        # repipe all events to the new tag
+        for events in Object.keys(@_events ? {}).map((e) => [e,@listeners(e)])
+            for [event, listeners] in events
+                for listener in listeners ? []
+                    tag.on(event, listener) if typeof listener is 'function'
+        @emit 'repipe', tag
         @emit 'replace', this, tag
+        @removeAllListeners()
         this

     remove: () =>


add and remove are now conditional

add and remove are now conditional

--- src/communist.coffee
+++ src/communist.coffee
@@ -62,11 +62,12 @@
 	close : () ->
 		@_worker.terminate()
 		true
-	add : (method, func, cb=()->true)->
-		@send("_add",method,(func.toString()),cb)
-		true
-	remove : (method,cb=()->true)->
-		@send("_rm",method,cb)
-		true
+	unless fun
+		add : (method, func, cb=()->true)->
+			@send("_add",method,(func.toString()),cb)
+			true
+		remove : (method,cb=()->true)->
+			@send("_rm",method,cb)
+			true
 	true
 window.Communist = Communist


more park cleanup

more park cleanup

--- src/runtime.coffee
+++ src/runtime.coffee
@@ -294,7 +294,7 @@
     thread.$park_timeout = Infinity

     # Yield to the unparked thread if it should be unblocked
-    @yield(thread) if thread.$park_count <= 0
+    @yield(thread) unless @parked thread

   parked: (thread) -> thread.$park_count > 0


leibniz birth year

leibniz birth year

--- src/service.coffee
+++ src/service.coffee
@@ -30,7 +30,7 @@
       process.exit(1)

-    url = @options.url || "http://localhost:1337"
+    url = @options.url || "http://localhost:1646"
     # We construct full urls by concatenating @url and the path,
     # so make sure that @url does not end in a slash.
     if url[url.length-1] == "/"


Not ready for these yet.

Not ready for these yet.

--- src/startup.coffee
+++ src/startup.coffee
@@ -22,8 +22,10 @@
 atom.storage = new Storage
 atom.keybinder = new KeyBinder
 atom.settings = new Settings
-atom.extensions = {}
-atom.extensionManager = new ExtensionManager
+
+# Ignore extensions for now
+#atom.extensions = {}
+#atom.extensionManager = new ExtensionManager

 atom.app = new App
 # atom.open, atom.close, etc.


Adds selector binding for unroll support

--- app/assets/javascripts/backend/golumn/helpers/knockout_helpers.js.coffee
+++ app/assets/javascripts/backend/golumn/helpers/knockout_helpers.js.coffee
@@ -39,4 +39,15 @@
         $(element).modal 'hide'
       return

+  ko.bindingHandlers.selector =
+    init: (element, valueAccessor) ->
+      $el = $(element)
+      $el.on 'selector:change', ->
+        valueAccessor().id $("input[name=#{$el.attr('id')}]").val()
+        valueAccessor().name $el.val()
+
+    update: (element, valueAccessor) ->
+      return
+
+
 ) ko, jQuery


Preventing fitting of selectors when there are none

--- app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee
+++ app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee
@@ -48,14 +48,15 @@
           available -= selector.width
           selector.fits = true if available > 0
       else
-        for i in [scope.allSelectors.length-1..0]
-          selector = scope.allSelectors[i]
-          if !selector.fits
-            continue
-          else
-            if available < 0
-              selector.fits = false
-              available += selector.width
+        if scope.allSelectors.length > 0
+          for i in [scope.allSelectors.length-1..0]
+            selector = scope.allSelectors[i]
+            if !selector.fits
+              continue
+            else
+              if available < 0
+                selector.fits = false
+                available += selector.width
       scope.fitting = false

     scope.$watchCollection "allSelectors", ->


refactoring: just make query params available to all classes for now

--- lib/assets/javascripts/oojspec/runner.js.coffee
+++ lib/assets/javascripts/oojspec/runner.js.coffee
@@ -11,6 +11,9 @@
     @_registerEventHandlers()
     @_initializeStats()
     @params = _.parseParams()
+    # avoid too much parameters between methods, acts like a context:
+    @params.events = @events
+    @params.assertions = @assertions

   _registerEventHandlers: ->
     @assertions = buster.assertions
@@ -40,13 +43,13 @@
   runSpecs: =>
     @reporter = buster.reporters.html.create detectCssPath: false
     @reporter.listen @events
-    d.processDsl @events for d in @descriptions
+    d.processDsl @params for d in @descriptions
     @events.emit 'suite:start', name: "Specs"
     @_runNextDescription()

   _runNextDescription: =>
     (@events.emit 'suite:end', @stats; return) unless @descriptions.length
-    @descriptions.shift().run @assertions, @_runNextDescription
+    @descriptions.shift().run @params, @_runNextDescription

   describe: (description, block)=>
     @stats.contexts++ # only root descriptions will be count
@@ -63,7 +66,8 @@
       @block = @description
       @description = @block.description or @block.name

-  processDsl: (@events, @binding, @bare)->
+  processDsl: (@params, @binding, @bare)->
+    @events = params.events
     @dsl = new DescribeDsl
     (@block.runSpecs or @block.prototype?.runSpecs) and @detectBindingError()

@@ -77,7 +81,7 @@
     @removeDsl() unless @bare
     @bare or= @binding.bare

-    d.processDsl @events, @binding, @bare for d in @dsl._examples_ when d instanceof Description
+    d.processDsl @params, @binding, @bare for d in @dsl._examples_ when d instanceof Description

   detectBindingError: ->
     try
@@ -93,7 +97,7 @@

   removeDsl: -> delete @binding[p] for p in RESERVED_FOR_DESCRIPTION_DSL; return

-  run: (@assertions, @onFinish, @beforeBlocks = [], @afterBlocks = [])->
+  run: (@params, @onFinish, @beforeBlocks = [], @afterBlocks = [])->
     @events.emit 'context:start', name: @description
     if @bindingError
       @events.emit 'test:error', name: @description, error: @bindingError
@@ -111,7 +115,7 @@
     @onFinish error

   runAround: (befores, afters, onFinish, block)->
-    new AroundBlock(befores, afters, block).run @events, @assertions, @binding, @bare, onFinish
+    new AroundBlock(befores, afters, block).run @params, @binding, @bare, onFinish

   processDescriptionBlock: (onFinish)=>
     @runAround @dsl._beforeAllBlocks_, @dsl._afterAllBlocks_, onFinish, (@onExamplesFinished)=>
@@ -123,9 +127,9 @@
     (@reportDeferred(nextStep.description); @runNextStep(); return) if nextStep.pending
     nextTick =
       if nextStep instanceof Description then =>
-        nextStep.run @assertions, @runNextStep, @dsl._beforeBlocks_, @dsl._afterBlocks_
+        nextStep.run @params, @runNextStep, @dsl._beforeBlocks_, @dsl._afterBlocks_
       else => # ExampleWithHooks
-        nextStep.run @events, @assertions, @binding, @bare, @onExampleFinished
+        nextStep.run @params, @binding, @bare, @onExampleFinished
     setTimeout nextTick, 0

   onExampleFinished: (error)=>
@@ -178,7 +182,8 @@
 class AroundBlock
   constructor: (@beforeBlocks, @afterBlocks, @block)->

-  run: (@events, @assertions, @binding, @bare, @onFinish)->
+  run: (@params, @binding, @bare, @onFinish)->
+    @events = @params.events
     @runGroup @beforeBlocks, ((e)=> @onBeforeError e), (wasSuccessful)=>
       if wasSuccessful
         @runMainBlock @block, (error)=>
@@ -199,7 +204,7 @@
       onFinish error

   runGroup: (group, onError, onFinish)->
-    new ExampleGroupWithoutHooks(@assertions, @binding, @bare, group, onFinish, onError).run()
+    new ExampleGroupWithoutHooks(@params, @binding, @bare, group, onFinish, onError).run()

   onBeforeError: (error)-> error.source = "before hook"; @registerError error
   onAfterError:  (error)-> error.source = "after hook";  @registerError error
@@ -208,7 +213,7 @@

 class ExampleWithHooks extends AroundBlock
   constructor: (@description, @beforeBlocks, @afterBlocks, @block)->
-  runMainBlock: (block, onFinish)-> new Example(block).run @assertions, @binding, @bare, onFinish
+  runMainBlock: (block, onFinish)-> new Example(block).run @params, @binding, @bare, onFinish
   onAfterHooks: ->
     @handleResult()
     super
@@ -229,7 +234,8 @@
     @events.emit 'test:error', name: @description, error: @error

 class ExampleGroupWithoutHooks
-  constructor: (@assertions, @binding, @bare, @blocks, @onFinish, @onError)-> @nextIndex = 0
+  constructor: (@params, @binding, @bare, @blocks, @onFinish, @onError)->
+    @nextIndex = 0

   run: ->
     @wasSuccessful = true
@@ -238,7 +244,7 @@
   nextTick: =>
     (@onFinish(@wasSuccessful); return) unless @nextIndex < @blocks.length
     block = @blocks[@nextIndex++]
-    new Example(block).run @assertions, @binding, @bare, (error)=>
+    new Example(block).run @params, @binding, @bare, (error)=>
       (@wasSuccessful = false; @onError error) if error
       setTimeout @nextTick, 0

@@ -246,9 +252,9 @@
   TICK = 10 # ms
   constructor: (@exampleBlock)-> @describeDsl = {}

-  run: (@assertions, @binding, @bare, @onFinish)->
-    @dsl = new ExampleDsl(@assertions.assert, @assertions.expect, @assertions.fail, \
-                          @assertions.refute)
+  run: (@params, @binding, @bare, @onFinish)->
+    a = @params.assertions
+    @dsl = new ExampleDsl(a.assert, a.expect, a.fail, a.refute)
     if @binding and not @bare
       for m in RESERVED_FOR_DESCRIPTION_DSL
         @describeDsl[m] = b if b = @binding[m]


Change .get to .all

Change .get to .all

Change relates to routing POST requests. This probably will not be
included in timbits, but thought I would commit my code change
regardless.

--- src/timbits.coffee
+++ src/timbits.coffee
@@ -49,24 +49,16 @@
 	@server.configure 'production', =>
 		@server.use express.errorHandler()

-	# route post requests to get
-	@server.post '*', (req, res) =>
-		delete req.body.submit # remove submit type
-		for attrname of req.body # merge post and get params
-			req.query[attrname] = req.body[attrname]
-		if req.url.indexOf('?') != -1 then req.url = req.url.substring(0, req.url.indexOf('?')) # remove querystring if necessary
-		res.redirect "#{req.url}" + if req.query? then "?#{querystring.stringify(req.query)}" else "" # append new querystring to request url
-
 	# route root to help page
-	@server.get '/', (req, res) =>
+	@server.all '/', (req, res) ->
 		res.redirect '/timbits/help'

 	# route help page
-	@server.get '/timbits/help', (req, res) =>
+	@server.all '/timbits/help', (req, res) =>
 		res.send ck.render(views.help, {box: @box} )

 	# route master test page
-	@server.get '/timbits/test', (req, res) =>
+	@server.all '/timbits/test', (req, res) =>
 		res.setHeader 'Content-Type', 'text/html; charset=UTF-8'
 		master = ''
 		pending = Object.keys(@box).length
@@ -87,6 +79,14 @@
 			if file.match(/\.(coffee|js)$/)?
 				@add file.substring(0, file.lastIndexOf(".")), require("#{timbit_path}/#{file}")

+		# route remaining post requests to get
+		@server.post '*', (req, res) ->
+			delete req.body.submit # remove submit type
+			for attrname of req.body # merge post and get params
+				req.query[attrname] = req.body[attrname]
+			if req.url.indexOf('?') != -1 then req.url = req.url.substring(0, req.url.indexOf('?')) # remove old querystring if necessary
+			res.redirect "#{req.url}" + if req.query? then "?#{querystring.stringify(req.query)}" else "" # append new querystring to request url
+
 	# starts the server
 	try
 		@server.listen process.env.PORT || process.env.C9_PORT || config.port
@@ -112,7 +112,7 @@
 	@box[name] = timbit

 	# configure help
-	@server.get ("/#{name}/help"), (req, res) ->
+	@server.all ("/#{name}/help"), (req, res) ->
 		renderHelp = ->
 			res.send ck.render(views.timbit_help, timbit)
 		timbit.listviews (views) ->
@@ -120,12 +120,12 @@
 			renderHelp()

 	# configure test
-	@server.get ("/#{name}/test"), (req, res) ->
+	@server.all ("/#{name}/test"), (req, res) ->
 		timbit.test "http://#{req.headers.host}", timbit, (results) ->
 			res.send ck.render(views.timbit_test, results)

 	# configure the route
-	@server.get ("/#{name}/:view?"), (req, res) ->
+	@server.all ("/#{name}/:view?"), (req, res) ->
 		try
 			# initialize current request context
 			context = {}


apps: Removed accidentally pushed code.

apps: Removed accidentally pushed code.

--- client/app/Applications/StartTab.kdapplication/views/appthumbview.coffee
+++ client/app/Applications/StartTab.kdapplication/views/appthumbview.coffee
@@ -35,9 +35,6 @@
       if icns and icns[String size]
         thumb = "#{resourceRoot}/#{icns[String size]}"
         break
-
-    if location.hostname is "localhost"
-      thumb = "/images/default.app.thumb.png"

     @img = new KDCustomHTMLView
       tagName     : "img"


fix(container): made options hash optional

--- src/container.coffee
+++ src/container.coffee
@@ -4,7 +4,7 @@
 #
 # @param [Object] options The main configuration object for container
 #
-Container = (options) ->
+Container = (options = {}) ->
   'use strict'

   # Provide the constructor function for the container object.


Allow injection everywhere

Allow injection everywhere

--- src/udefine.coffee
+++ src/udefine.coffee
@@ -7,18 +7,21 @@
 hasModule = module? and module.exports?
 exportObject = {}

+# Safe way to test against an object without array being a false positive
 isObject = (obj) -> typeof obj is 'object' and not Array.isArray(obj)

 # Root object hook
 do (root = if hasModule then exportObject else this) ->
   rootExport = if hasModule then {} else root

+  # Helper function to resolve a module (either function or object)
   resolveModule = (factory, deps) ->
     if typeof factory is 'function'
       factory.apply @, deps
     else
       factory

+  # Main entry point
   root.udefine or= (name, deps, factory) ->
     throw new Error 'A udefine module needs to have a name' unless name?

@@ -44,7 +47,6 @@
             requireArr.push root.udefine.commonjs[dep]

         # Common JS
-
         result = module.exports = resolveModule factory, requireArr
       else
         # Usual browser environment
@@ -57,12 +59,13 @@
           root.udefine.globals[name] = result

-      # Inject result into defined namespace
-      if Object.hasOwnProperty.call root.udefine.inject, name
-        injectName = root.udefine.inject[name].name
-        injectRoot = root.udefine.inject[name].root
+    # Inject result into defined namespace
+    if Object.hasOwnProperty.call root.udefine.inject, name
+      injectName = root.udefine.inject[name].name
+      injectRoot = root.udefine.inject[name].root
+
+      root.udefine.inject(injectRoot, injectName)(result)

-        root.udefine.inject(injectRoot, injectName)(result)
     result

   # Helper function to inject function/object into any object


Remove unused fs import from io.coffee

Remove unused fs import from io.coffee

--- src/io.coffee
+++ src/io.coffee
@@ -1,6 +1,5 @@
 rawBody = require 'raw-body'
 When = require 'when'
-fs = require 'fs'

 # It should work for any version of when.js
 nodefn = try


Adds initial API spec test for /turer

Adds initial API spec test for /turer

--- test/api-spec.coffee
+++ test/api-spec.coffee
@@ -27,4 +27,12 @@
       .get('/?api_key=dnt')
       .expect(200, done)

-
+describe.skip '/turer', ->
+  describe 'HTTP GET', ->
+    it 'should return objects', (done) ->
+      app.set 'debug', true
+      request(app)
+        .get('/turer/?api_key=dnt')
+        #.expect(200, done)
+        .end (err, res) ->
+          console.log res.body


Delete tmp directory before each CLI spec

--- test/cli-spec.coffee
+++ test/cli-spec.coffee
@@ -2,11 +2,16 @@
 {exec} = require 'child_process'
 fs = require 'fs'
 os = require 'os'
+path = require 'path'
+rimraf = require 'rimraf'

 compDirs = require './util/compareDirectories'
 compFiles = require './util/compareFiles'

 describe 'command line interface', ->
+  beforeEach ->
+    rimraf.sync path.join(__dirname, '..', 'tmp')
+
   it 'should create archive from directory', (done) ->
     exec 'node bin/asar p test/input/packthis/ tmp/packthis-cli.asar', (error, stdout, stderr) ->
       done compFiles 'tmp/packthis-cli.asar', 'test/expected/packthis.asar'


cooldown finilazation

cooldown finilazation

--- test/cooldown.coffee
+++ test/cooldown.coffee
@@ -98,7 +98,7 @@

   equals obj.I.age, 1, "should successfully update"

-t
+test "use"

 test "initialize property to 0 if no current value", ->
   obj = GameObject()


Accept a --verbose argument in apm ci

Accept a --verbose argument in apm ci

--- src/ci.coffee
+++ src/ci.coffee
@@ -31,13 +31,16 @@
       but cannot be used to install new packages or dependencies.
     """

-  installDependencies: (callback) =>
+    options.alias('h', 'help').describe('help', 'Print this usage message')
+    options.boolean('verbose').default('verbose', false).describe('verbose', 'Show verbose debug information')
+
+  installDependencies: (options, callback) =>
     async.waterfall [
-      (cb) => @installNode(cb)
-      (cb) => @installModules(cb)
+      (cb) => @installNode(options, cb)
+      (cb) => @installModules(options, cb)
     ], callback

-  installNode: (callback) =>
+  installNode: (options, callback) =>
     installNodeArgs = ['install']
     installNodeArgs.push(@getNpmBuildFlags()...)
     installNodeArgs.push("--ensure")
@@ -57,7 +60,7 @@
     proxy = @npm.config.get('https-proxy') or @npm.config.get('proxy') or env.HTTPS_PROXY or env.HTTP_PROXY
     installNodeArgs.push("--proxy=#{proxy}") if proxy

-    opts = {env, cwd: @atomDirectory}
+    opts = {env, cwd: @atomDirectory, streaming: options.argv.verbose?}

     @fork @atomNodeGypPath, installNodeArgs, opts, (code, stderr='', stdout='') ->
       if code is 0
@@ -65,8 +68,12 @@
       else
         callback("#{stdout}\n#{stderr}")

-  installModules: (callback) ->
-    process.stdout.write 'Installing locked modules '
+  installModules: (options, callback) ->
+    process.stdout.write 'Installing locked modules'
+    if options.argv.verbose?
+      process.stdout.write '\n'
+    else
+      process.stdout.write ' '

     installArgs = [
       'ci'
@@ -74,6 +81,7 @@
       '--userconfig', config.getUserConfigPath()
       @getNpmBuildFlags()...
     ]
+    installArgs.push('--verbose') if options.argv.verbose?

     if vsArgs = @getVisualStudioFlags()
       installArgs.push(vsArgs)
@@ -82,19 +90,19 @@
     @updateWindowsEnv(env) if config.isWin32()
     @addNodeBinToEnv(env)
     @addProxyToEnv(env)
-    installOptions = {env}
+    installOptions = {env, streaming: options.argv.verbose?}

     @fork @atomNpmPath, installArgs, installOptions, (args...) =>
       @logCommandResults(callback, args...)

   run: (options) ->
     {callback} = options
-    options = @parseOptions(options.commandArgs)
+    opts = @parseOptions(options.commandArgs)

     commands = []
     commands.push (callback) => config.loadNpm (error, @npm) => callback(error)
     commands.push (cb) => @loadInstalledAtomMetadata(cb)
-    commands.push (cb) => @installDependencies(cb)
+    commands.push (cb) => @installDependencies(opts, cb)

     iteratee = (item, next) -> item(next)
     async.mapSeries commands, iteratee, (err) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/flickerable.coffee
+++ test/flickerable.coffee
@@ -20,7 +20,7 @@
     frequency: 20

   equals player.I.flickerAlpha, 0.5
-  equals player.I.flickerFrequency, 0.1
+  equals player.I.flickerFrequency, 20
   equals player.I.flickerDuration, 2

   enemy = GameObject()


fix special day

fix special day

--- routes/middleware.coffee
+++ routes/middleware.coffee
@@ -1,37 +1,50 @@
+moment = require "moment"
+moment.locale("zh-cn")
+daily = require "../model/daily"
 middleware = {}

 middleware.showDay = (req, res) ->
-  daily = require "../model/daily"
-  moment = require "moment"
-  moment.locale("zh-cn")
-  daily.getDay req.params.date, (err, storysArr)->
+  getDay req.params.date, (err, storysArr)->
     if err
       if err.message == "DayNotFound"
         return res.status(404).send "Day Not Found"
       else
         return res.status(500).send err.message
-
     storysArr_new = []
     for story in storysArr
       storysArr_new.push
         url: "/story/" + story.id
         image: story.image
         title: story.title
-    beforeDay = moment(req.params.date, "YYYYMMDD").add(-1, 'd').format("YYYYMMDD")
+    beforeDay = moment(story.date, "YYYYMMDD").add(-1, 'd').format("YYYYMMDD")
     daily.randOne beforeDay, (err, randObj)->
-      storysArr_new.push
-        url: "/day/" + beforeDay
-        image: randObj.image
-        title: moment(beforeDay, "YYYYMMDD").format("YYYY.MM.DD dddd")
+      unless err
+        storysArr_new.push
+          url: "/day/" + beforeDay
+          image: randObj.image
+          title: moment(beforeDay, "YYYYMMDD").format("YYYY.MM.DD dddd")
       time = Date.now() - res.socket._idleStart
-      if req.params.date == moment().format("YYYYMMDD")
+      if story.date == moment().format("YYYYMMDD")
         date = "今日热闻"
       else
-        date = moment(req.params.date, "YYYYMMDD").format("YYYY.MM.DD dddd")
+        date = moment(story.date, "YYYYMMDD").format("YYYY.MM.DD dddd")
       res.render "day",
         css: "day"
         date: date
         storys: storysArr_new
         time: time

+getDay = (date, cb)->
+  beforeDay = moment(date, "YYYYMMDD").add(-1, 'd').format("YYYYMMDD")
+  daily.getDay date, (err, storysArr)->
+    if err
+      if err.message == "DayNotFound"
+        daily.getDay beforeDay, (err, storysArr)->
+          return cb err if err
+          return cb null, storysArr
+      else
+        return cb err
+    else
+      return cb null, storysArr
+
 module.exports = middleware


showing post button on showentry after focus

--- app/coffee/showentry.coffee
+++ app/coffee/showentry.coffee
@@ -23,6 +23,10 @@
 $(document).ready ->
   tagsController = new TagsController('.showTags', 'show')
   $('.gallery .lightbox a').lightBox({containerResizeSpeed: 0})
+
+  $('#comment_submit').hide()
+  $('#comment_body').focus ->
+    $('#comment_submit').fadeIn(250)

   $('#comment_body').keyup ->
     fitToContent(this, 0)


not really  bothered if null or undefined in struct decorator

--- test/struct_spec.coffee
+++ test/struct_spec.coffee
@@ -129,10 +129,10 @@
       struct.setThing('blob')
       expect( struct.thing() ).to.eql('BLOB')

-    it "does nothing if set to null", ->
+    it "ignores the decorator if set to null", ->
       struct = new TestStruct()
       struct.setThing(null)
-      expect( struct.thing() ).to.eql(null)
+      expect( struct.thing() ).to.eql(undefined)

     it "works on null if the flag is set", ->
       TestStruct.attributes 'array'


add post functionality

add post functionality

--- express/routes/rooms.coffee
+++ express/routes/rooms.coffee
@@ -2,6 +2,20 @@
 BSON = require('mongodb').BSONPure;
 async = require 'async'
 ObjectId = require('mongoose').Types.ObjectId
+
+exports.post = (req, res) ->
+    roomData = req.body
+    console.log req.user.hubs
+    roomData.hub = req.user.hubs[0]
+    console.log roomData
+    room = new models.Room(roomData)
+
+    room.save((err, data) ->
+            if(err)
+                res.json 500, err
+            else
+                res.json 200, data
+        )

 exports.get = (req, res) ->
     if req.params.room_id


This is power of CompactSpaces with `g g space G` to compact whole buffer. #279

--- keymaps/vim-mode-plus.cson
+++ keymaps/vim-mode-plus.cson
@@ -44,38 +44,38 @@
 # except insert
 # -------------------------
 'atom-text-editor.vim-mode-plus:not(.insert-mode)':
-  'h':         'vim-mode-plus:move-left'
-  'left':      'vim-mode-plus:move-left'
+  'h': 'vim-mode-plus:move-left'
+  'left': 'vim-mode-plus:move-left'
   'backspace': 'core:move-left'
-  'l':         'vim-mode-plus:move-right'
-  'space':     'vim-mode-plus:move-right'
-  'right':     'vim-mode-plus:move-right'
-  'k':         'vim-mode-plus:move-up'
-  'up':        'vim-mode-plus:move-up'
-  'j':         'vim-mode-plus:move-down'
-  'down':      'vim-mode-plus:move-down'
-
-  'w':     'vim-mode-plus:move-to-next-word'
+  'l': 'vim-mode-plus:move-right'
+  'space': 'vim-mode-plus:move-right'
+  'right': 'vim-mode-plus:move-right'
+  'k': 'vim-mode-plus:move-up'
+  'up': 'vim-mode-plus:move-up'
+  'j': 'vim-mode-plus:move-down'
+  'down': 'vim-mode-plus:move-down'
+
+  'w': 'vim-mode-plus:move-to-next-word'
   # 'w':     'vim-mode-plus:move-to-next-alphanumeric-word'
-  'W':     'vim-mode-plus:move-to-next-whole-word'
-  'e':     'vim-mode-plus:move-to-end-of-word'
+  'W': 'vim-mode-plus:move-to-next-whole-word'
+  'e': 'vim-mode-plus:move-to-end-of-word'
   # 'e': 'vim-mode-plus:move-to-end-of-alphanumeric-word'
-  'E':     'vim-mode-plus:move-to-end-of-whole-word'
-  'b':     'vim-mode-plus:move-to-previous-word'
+  'E': 'vim-mode-plus:move-to-end-of-whole-word'
+  'b': 'vim-mode-plus:move-to-previous-word'
   # 'b':     'vim-mode-plus:move-to-previous-alphanumeric-word'
-  'B':     'vim-mode-plus:move-to-previous-whole-word'
-  '}':     'vim-mode-plus:move-to-next-paragraph'
-  '{':     'vim-mode-plus:move-to-previous-paragraph'
-  '0':     'vim-mode-plus:move-to-beginning-of-line'
-  '|':     'vim-mode-plus:move-to-column'
-  'home':  'vim-mode-plus:move-to-beginning-of-line'
-  '^':     'vim-mode-plus:move-to-first-character-of-line'
-  '_':     'vim-mode-plus:move-to-first-character-of-line-and-down'
-  '$':     'vim-mode-plus:move-to-last-character-of-line'
-  'end':   'vim-mode-plus:move-to-last-character-of-line'
-  'g _':   'vim-mode-plus:move-to-last-nonblank-character-of-line-and-down'
-  '-':     'vim-mode-plus:move-to-first-character-of-line-up'
-  '+':     'vim-mode-plus:move-to-first-character-of-line-down'
+  'B': 'vim-mode-plus:move-to-previous-whole-word'
+  '}': 'vim-mode-plus:move-to-next-paragraph'
+  '{': 'vim-mode-plus:move-to-previous-paragraph'
+  '0': 'vim-mode-plus:move-to-beginning-of-line'
+  '|': 'vim-mode-plus:move-to-column'
+  'home': 'vim-mode-plus:move-to-beginning-of-line'
+  '^': 'vim-mode-plus:move-to-first-character-of-line'
+  '_': 'vim-mode-plus:move-to-first-character-of-line-and-down'
+  '$': 'vim-mode-plus:move-to-last-character-of-line'
+  'end': 'vim-mode-plus:move-to-last-character-of-line'
+  'g _': 'vim-mode-plus:move-to-last-nonblank-character-of-line-and-down'
+  '-': 'vim-mode-plus:move-to-first-character-of-line-up'
+  '+': 'vim-mode-plus:move-to-first-character-of-line-down'
   'enter': 'vim-mode-plus:move-to-first-character-of-line-down'

   'ctrl-u': 'vim-mode-plus:scroll-half-screen-up'
@@ -86,13 +86,13 @@
   'ctrl-y': 'vim-mode-plus:scroll-up'

   'z enter': 'vim-mode-plus:scroll-cursor-to-top'
-  'z t':     'vim-mode-plus:scroll-cursor-to-top-leave'
-  'z .':     'vim-mode-plus:scroll-cursor-to-middle'
-  'z z':     'vim-mode-plus:scroll-cursor-to-middle-leave'
-  'z -':     'vim-mode-plus:scroll-cursor-to-bottom'
-  'z b':     'vim-mode-plus:scroll-cursor-to-bottom-leave'
-  'z s':     'vim-mode-plus:scroll-cursor-to-left'
-  'z e':     'vim-mode-plus:scroll-cursor-to-right'
+  'z t': 'vim-mode-plus:scroll-cursor-to-top-leave'
+  'z .': 'vim-mode-plus:scroll-cursor-to-middle'
+  'z z': 'vim-mode-plus:scroll-cursor-to-middle-leave'
+  'z -': 'vim-mode-plus:scroll-cursor-to-bottom'
+  'z b': 'vim-mode-plus:scroll-cursor-to-bottom-leave'
+  'z s': 'vim-mode-plus:scroll-cursor-to-left'
+  'z e': 'vim-mode-plus:scroll-cursor-to-right'

   'z M': 'editor:fold-all'
   'z R': 'editor:unfold-all'
@@ -100,11 +100,11 @@
   'z o': 'editor:unfold-current-row'
   'z a': 'vim-mode-plus:toggle-fold'

-  'G':   'vim-mode-plus:move-to-last-line'
+  'G': 'vim-mode-plus:move-to-last-line'
   'g g': 'vim-mode-plus:move-to-first-line'
-  'H':   'vim-mode-plus:move-to-top-of-screen'
-  'L':   'vim-mode-plus:move-to-bottom-of-screen'
-  'M':   'vim-mode-plus:move-to-middle-of-screen'
+  'H': 'vim-mode-plus:move-to-top-of-screen'
+  'L': 'vim-mode-plus:move-to-bottom-of-screen'
+  'M': 'vim-mode-plus:move-to-middle-of-screen'

   'd': 'vim-mode-plus:delete'
   'D': 'vim-mode-plus:delete-to-last-character-of-line'
@@ -128,14 +128,14 @@
   # 'g p': 'vim-mode-plus:put-after-and-select'

   # String transformation
-  '~':     'vim-mode-plus:toggle-case-and-move-right'
-  'g ~':   'vim-mode-plus:toggle-case'
-  'g U':   'vim-mode-plus:upper-case'
-  'g u':   'vim-mode-plus:lower-case'
-  'g c':   'vim-mode-plus:camel-case'
-  'g /':   'vim-mode-plus:toggle-line-comments'
-  'g -':   'vim-mode-plus:dash-case'
-  'g space':   'vim-mode-plus:compact-spaces'
+  '~': 'vim-mode-plus:toggle-case-and-move-right'
+  'g ~': 'vim-mode-plus:toggle-case'
+  'g U': 'vim-mode-plus:upper-case'
+  'g u': 'vim-mode-plus:lower-case'
+  'g c': 'vim-mode-plus:camel-case'
+  'g /': 'vim-mode-plus:toggle-line-comments'
+  'g -': 'vim-mode-plus:dash-case'
+  'g space': 'vim-mode-plus:compact-spaces'
   # 'g _': 'vim-mode-plus:snake-case'
   # 'g r':   'vim-mode-plus:reverse'
   # 'ctrl-s': 'vim-mode-plus:transform-string-by-select-list'
@@ -147,37 +147,37 @@
   'g ctrl-x': 'vim-mode-plus:decrement-number' # experimental

   'ctrl-w ctrl-h': 'window:focus-pane-on-left'
-  'ctrl-w h':      'window:focus-pane-on-left'
-  'ctrl-w left':   'window:focus-pane-on-left'
+  'ctrl-w h': 'window:focus-pane-on-left'
+  'ctrl-w left': 'window:focus-pane-on-left'
   'ctrl-w ctrl-l': 'window:focus-pane-on-right'
-  'ctrl-w l':      'window:focus-pane-on-right'
-  'ctrl-w right':  'window:focus-pane-on-right'
+  'ctrl-w l': 'window:focus-pane-on-right'
+  'ctrl-w right': 'window:focus-pane-on-right'
   'ctrl-w ctrl-k': 'window:focus-pane-above'
-  'ctrl-w k':      'window:focus-pane-above'
-  'ctrl-w up':     'window:focus-pane-above'
+  'ctrl-w k': 'window:focus-pane-above'
+  'ctrl-w up': 'window:focus-pane-above'
   'ctrl-w ctrl-j': 'window:focus-pane-below'
-  'ctrl-w j':      'window:focus-pane-below'
-  'ctrl-w down':   'window:focus-pane-below'
+  'ctrl-w j': 'window:focus-pane-below'
+  'ctrl-w down': 'window:focus-pane-below'
   'ctrl-w ctrl-w': 'window:focus-next-pane'
-  'ctrl-w w':      'window:focus-next-pane'
+  'ctrl-w w': 'window:focus-next-pane'
   'ctrl-w ctrl-p': 'window:focus-previous-pane'
-  'ctrl-w p':      'window:focus-previous-pane'
+  'ctrl-w p': 'window:focus-previous-pane'

   # From v1.6.0
   'ctrl-w ctrl-v': 'pane:split-right-and-copy-active-item'
-  'ctrl-w v':      'pane:split-right-and-copy-active-item'
+  'ctrl-w v': 'pane:split-right-and-copy-active-item'
   'ctrl-w ctrl-s': 'pane:split-down-and-copy-active-item'
-  'ctrl-w s':      'pane:split-down-and-copy-active-item'
+  'ctrl-w s': 'pane:split-down-and-copy-active-item'

   'ctrl-w z': 'vim-mode-plus:maximize-pane'
   'cmd-enter': 'vim-mode-plus:maximize-pane'

   'ctrl-w ctrl-c': 'pane:close'
-  'ctrl-w c':      'pane:close'
+  'ctrl-w c': 'pane:close'
   'ctrl-w ctrl-q': 'core:close'
-  'ctrl-w q':      'core:close'
-  'g t':           'pane:show-next-item'
-  'g T':           'pane:show-previous-item'
+  'ctrl-w q': 'core:close'
+  'g t': 'pane:show-next-item'
+  'g T': 'pane:show-previous-item'

   'f': 'vim-mode-plus:find'
   'F': 'vim-mode-plus:find-backwards'
@@ -207,8 +207,8 @@
   '8': 'vim-mode-plus:set-count-8'
   '9': 'vim-mode-plus:set-count-9'

-  'm':  'vim-mode-plus:start-save-mark'
-  '`':  'vim-mode-plus:start-move-to-mark'
+  'm': 'vim-mode-plus:start-save-mark'
+  '`': 'vim-mode-plus:start-move-to-mark'
   "'": 'vim-mode-plus:start-move-to-mark-line'

   # 'ctrl-cmd-k': 'vim-mode-plus:move-up-to-edge'
@@ -278,8 +278,8 @@
 # normal
 # -------------------------
 'atom-text-editor.vim-mode-plus.normal-mode':
-  'i':      'vim-mode-plus:activate-insert-mode'
-  'g i':    'vim-mode-plus:insert-at-last-insert'
+  'i': 'vim-mode-plus:activate-insert-mode'
+  'g i': 'vim-mode-plus:insert-at-last-insert'

   # 'g I': 'vim-mode-plus:insert-at-start-of-target'
   # 'g A': 'vim-mode-plus:insert-at-end-of-target'
@@ -287,25 +287,25 @@
   # 'g [':    'vim-mode-plus:insert-at-previous-fold-start'
   # 'g ]':    'vim-mode-plus:insert-at-next-fold-start'

-  'R':      'vim-mode-plus:activate-replace-mode'
-  'v':      'vim-mode-plus:activate-characterwise-visual-mode'
-  'V':      'vim-mode-plus:activate-linewise-visual-mode'
+  'R': 'vim-mode-plus:activate-replace-mode'
+  'v': 'vim-mode-plus:activate-characterwise-visual-mode'
+  'V': 'vim-mode-plus:activate-linewise-visual-mode'
   'ctrl-v': 'vim-mode-plus:activate-blockwise-visual-mode'
-  'g v':    'vim-mode-plus:select-previous-selection'
+  'g v': 'vim-mode-plus:select-previous-selection'
   # 'g c':    'vim-mode-plus:select-latest-change'
-  'u':      'vim-mode-plus:undo'
+  'u': 'vim-mode-plus:undo'
   'ctrl-r': 'vim-mode-plus:redo'
-  'O':      'vim-mode-plus:insert-above-with-newline'
-  'o':      'vim-mode-plus:insert-below-with-newline'
-  'a':      'vim-mode-plus:insert-after'
-  'A':      'vim-mode-plus:insert-after-end-of-line'
-  'x':      'vim-mode-plus:delete-right'
-  'X':      'vim-mode-plus:delete-left'
-  's':      'vim-mode-plus:substitute'
-  '.':      'vim-mode-plus:repeat'
+  'O': 'vim-mode-plus:insert-above-with-newline'
+  'o': 'vim-mode-plus:insert-below-with-newline'
+  'a': 'vim-mode-plus:insert-after'
+  'A': 'vim-mode-plus:insert-after-end-of-line'
+  'x': 'vim-mode-plus:delete-right'
+  'X': 'vim-mode-plus:delete-left'
+  's': 'vim-mode-plus:substitute'
+  '.': 'vim-mode-plus:repeat'
   'ctrl-]': 'symbols-view:go-to-declaration'
   'ctrl-t': 'symbols-view:return-from-declaration'
-  '"':      'vim-mode-plus:set-register-name'
+  '"': 'vim-mode-plus:set-register-name'

   # 'y s': 'vim-mode-plus:surround'
   # 'y s w': 'vim-mode-plus:surround-word'
@@ -329,21 +329,21 @@
   'u': 'vim-mode-plus:lower-case'

   # Text object inner-, a- order
-  'i w':  'vim-mode-plus:inner-word'
-  'a w':  'vim-mode-plus:a-word'
-
-  'i W':  'vim-mode-plus:inner-whole-word'
-  'a W':  'vim-mode-plus:a-whole-word'
+  'i w': 'vim-mode-plus:inner-word'
+  'a w': 'vim-mode-plus:a-word'
+
+  'i W': 'vim-mode-plus:inner-whole-word'
+  'a W': 'vim-mode-plus:a-whole-word'

   # 'i w':  'vim-mode-plus:inner-smart-word'
   # 'a w':  'vim-mode-plus:a-smart-word'

   # [FIXME?] overridden Vim's sentence text object
-  'i s':  'vim-mode-plus:inner-any-pair'
-  'a s':  'vim-mode-plus:a-any-pair'
-
-  'i "':  'vim-mode-plus:inner-double-quote'
-  'a "':  'vim-mode-plus:a-double-quote'
+  'i s': 'vim-mode-plus:inner-any-pair'
+  'a s': 'vim-mode-plus:a-any-pair'
+
+  'i "': 'vim-mode-plus:inner-double-quote'
+  'a "': 'vim-mode-plus:a-double-quote'

   "i '": 'vim-mode-plus:inner-single-quote'
   "a '": 'vim-mode-plus:a-single-quote'
@@ -351,21 +351,21 @@
   "i q": 'vim-mode-plus:inner-any-quote'
   "a q": 'vim-mode-plus:a-any-quote'

-  'i `':  'vim-mode-plus:inner-back-tick'
-  'a `':  'vim-mode-plus:a-back-tick'
-
-  'i {':  'vim-mode-plus:inner-curly-bracket'
-  'i }':  'vim-mode-plus:inner-curly-bracket'
-  'a {':  'vim-mode-plus:a-curly-bracket'
-  'a }':  'vim-mode-plus:a-curly-bracket'
-
-  'i B':  'vim-mode-plus:inner-curly-bracket'
-  'a B':  'vim-mode-plus:a-curly-bracket'
-
-  'i <':  'vim-mode-plus:inner-angle-bracket'
-  'i >':  'vim-mode-plus:inner-angle-bracket'
-  'a <':  'vim-mode-plus:a-angle-bracket'
-  'a >':  'vim-mode-plus:a-angle-bracket'
+  'i `': 'vim-mode-plus:inner-back-tick'
+  'a `': 'vim-mode-plus:a-back-tick'
+
+  'i {': 'vim-mode-plus:inner-curly-bracket'
+  'i }': 'vim-mode-plus:inner-curly-bracket'
+  'a {': 'vim-mode-plus:a-curly-bracket'
+  'a }': 'vim-mode-plus:a-curly-bracket'
+
+  'i B': 'vim-mode-plus:inner-curly-bracket'
+  'a B': 'vim-mode-plus:a-curly-bracket'
+
+  'i <': 'vim-mode-plus:inner-angle-bracket'
+  'i >': 'vim-mode-plus:inner-angle-bracket'
+  'a <': 'vim-mode-plus:a-angle-bracket'
+  'a >': 'vim-mode-plus:a-angle-bracket'

   # allow-forwarding family
   # 'i }':  'vim-mode-plus:inner-curly-bracket-allow-forwarding'
@@ -377,35 +377,35 @@
   # 'i )':  'vim-mode-plus:inner-parenthesis-allow-forwarding'
   # 'a )':  'vim-mode-plus:a-parenthesis-allow-forwarding'

-  'i t':  'vim-mode-plus:inner-tag'
-  'a t':  'vim-mode-plus:a-tag'
-
-  'i [':  'vim-mode-plus:inner-square-bracket'
-  'i ]':  'vim-mode-plus:inner-square-bracket'
-  'a [':  'vim-mode-plus:a-square-bracket'
-  'a ]':  'vim-mode-plus:a-square-bracket'
-
-  'i (':  'vim-mode-plus:inner-parenthesis'
-  'i )':  'vim-mode-plus:inner-parenthesis'
-  'i b':  'vim-mode-plus:inner-parenthesis'
-  'a (':  'vim-mode-plus:a-parenthesis'
-  'a )':  'vim-mode-plus:a-parenthesis'
-  'a b':  'vim-mode-plus:a-parenthesis'
-
-  'i p':  'vim-mode-plus:inner-paragraph'
-  'a p':  'vim-mode-plus:a-paragraph'
-
-  'i /':  'vim-mode-plus:inner-comment'
-  'a /':  'vim-mode-plus:a-comment'
-
-  'i i':  'vim-mode-plus:inner-indentation'
-  'a i':  'vim-mode-plus:a-indentation'
-
-  'i z':  'vim-mode-plus:inner-fold'
-  'a z':  'vim-mode-plus:a-fold'
-
-  'i f':  'vim-mode-plus:inner-function'
-  'a f':  'vim-mode-plus:a-function'
+  'i t': 'vim-mode-plus:inner-tag'
+  'a t': 'vim-mode-plus:a-tag'
+
+  'i [': 'vim-mode-plus:inner-square-bracket'
+  'i ]': 'vim-mode-plus:inner-square-bracket'
+  'a [': 'vim-mode-plus:a-square-bracket'
+  'a ]': 'vim-mode-plus:a-square-bracket'
+
+  'i (': 'vim-mode-plus:inner-parenthesis'
+  'i )': 'vim-mode-plus:inner-parenthesis'
+  'i b': 'vim-mode-plus:inner-parenthesis'
+  'a (': 'vim-mode-plus:a-parenthesis'
+  'a )': 'vim-mode-plus:a-parenthesis'
+  'a b': 'vim-mode-plus:a-parenthesis'
+
+  'i p': 'vim-mode-plus:inner-paragraph'
+  'a p': 'vim-mode-plus:a-paragraph'
+
+  'i /': 'vim-mode-plus:inner-comment'
+  'a /': 'vim-mode-plus:a-comment'
+
+  'i i': 'vim-mode-plus:inner-indentation'
+  'a i': 'vim-mode-plus:a-indentation'
+
+  'i z': 'vim-mode-plus:inner-fold'
+  'a z': 'vim-mode-plus:a-fold'
+
+  'i f': 'vim-mode-plus:inner-function'
+  'a f': 'vim-mode-plus:a-function'

   'i l': 'vim-mode-plus:inner-current-line'
   'a l': 'vim-mode-plus:a-current-line'
@@ -457,11 +457,11 @@
 # -------------------------
 'atom-text-editor.vim-mode-plus-search':
   'ctrl-r ctrl-w': 'vim-mode-plus:search-set-cursor-word'
-  'ctrl-v':    'vim-mode-plus:search-activate-literal-mode'
-  'ctrl-c':    'vim-mode-plus:search-cancel'
-  'ctrl-[':    'vim-mode-plus:search-cancel'
+  'ctrl-v': 'vim-mode-plus:search-activate-literal-mode'
+  'ctrl-c': 'vim-mode-plus:search-cancel'
+  'ctrl-[': 'vim-mode-plus:search-cancel'
   'shift-tab': 'vim-mode-plus:search-visit-prev'
-  'tab':       'vim-mode-plus:search-visit-next'
+  'tab': 'vim-mode-plus:search-visit-next'

 # If you want to map normal char to special operation.
 # Use `not(.literal-mode)` selector like below.


peillis/helpapp#3455 cosmetic

peillis/helpapp#3455 cosmetic

--- test/test_client.coffee
+++ test/test_client.coffee
@@ -35,10 +35,10 @@
       lt: 99

 # Test doofinder
-describe 'doofinder client', ->
+describe 'doofinder client\'s ', ->

   # Tests the client's stuff
-  context 'makeQueryString can ', ->
+  context 'makeQueryString method can ', ->

     it 'handle several types', ->
       # Client for two types by constructor (made make multiple type params)
@@ -137,7 +137,7 @@
       querystring = client.makeQueryString()
       querystring.should.be.equal 'hashid=ffffffffffffffffffffffffffffffff&sort=price'

-  context 'sanitizeQuery can ', ->
+  context 'sanitizeQuery method can ', ->

     before () ->
       @client = new doofinder.Client mock.request.hashid, mock.request.api_key
@@ -255,7 +255,7 @@

     describe 'hit', ->

-      it 'basic hit with query', (done) ->
+      it 'sends dfid, hashid and query parameters', (done) ->
         response =
           field: "value"
         scope = nock('http://fooserver')
@@ -270,7 +270,7 @@

     describe 'options', ->

-      it 'options', (done) ->
+      it 'hits the right url', (done) ->
         response =
           field: "value"
         scope = nock('http://fooserver')


bugfix post request. no qs.stringify for non objects

--- modules/http/platforms/node/tools/index.coffee
+++ modules/http/platforms/node/tools/index.coffee
@@ -5,57 +5,57 @@
 qs = require 'querystring'
 formidable = require 'formidable'

-module.exports = tools =
+module.exports = tools =

     ##
     ##
     Agent: http.Agent
-
+
     ##
     ##
     request: ()->
         http.request.apply http, arguments

-
+
     ##
     ##
     get: (options, fn)->
-
+
         tools.parseOptions options, (err, options)->
-
+
             http.get options, (res)->
-
-                tools.readResponse res, fn
-
+
+                tools.readResponse res, fn
+
     ##
     ##
     post: (options, data, fn)->
-
-        data = qs.stringify data
-
+        if typeof data is 'object'
+            data = '?'+qs.stringify data
+
         tools.parseOptions options, (err, options)->
-
+
             options.method ?= 'POST'
             options.headers ?= {}
             options.headers['Content-Type'] = 'application/x-www-form-urlencoded'
             options.headers['Content-Length'] = data.length
-
+
             #console.log options
-
+
             req = http.request options, (res)->
-
+
                 tools.readResponse res, fn
-
+
             req.write data
-
+
     ##
     ##
     parseOptions: (options, fn)->
-
+
         if typeof options is 'string'
             options =
                 url: options
-
+
         if options.url
             #console.log url.parse options.url
             {auth, hostname, port, path} = url.parse options.url
@@ -64,141 +64,138 @@
             options.host = hostname
             options.port = port
             options.path = path
-
+
         fn null, options

     ##
     ##
     parseData: (req, fn)->
-
+
         fn ?= (err, data)->
             return data
-
-        if req.body
+
+        if req.body
             return fn null, req.body
-
+
         if typeof req is 'string'
             return fn null, qs.parse req
-
+
         data = req.url.split('?')[1] || ''
-
+
         if req.method is 'POST'
             data += '&' if data.length
-
-            req.on 'data', (chunk)=>
+
+            req.on 'data', (chunk)=>
                 data += chunk if chunk
-
+
             req.on 'end', ()=>
                 fn null, req.body = qs.parse data
-
+
         else
-            fn null, req.body = qs.parse data
-
+            fn null, req.body = qs.parse data
+
     ##
     ##
     readResponse: (res, fn)->
-        data = ''
-
+        data = ''
+
         res.on 'data', (chunk)->
             data += chunk
-
+
         res.on 'end', ()->
             fn null, data, res
-
+
         res.on 'error', fn

-
+
     ##
     ##
     upload: (req, res, handler, done)->
-
-        ##
-        handler.data = data =
+
+        ##
+        handler.data = data =
             total: 0
             received: 0
             file: ''
-
-
+
+
         ## formidable - nothing more to say!
-
-
+
+
         ##
         form = formidable.IncomingForm()
-
+
         if handler.maxSize && parseInt(req.headers['content-length']) > handler.maxSize
             return done new Error 'limit exceeded'
-
+
         form.uploadDir = floyd.system.appdir+'/.floyd/tmp/'
-
+
         curr = 0
         file = null
         sec = 0
-        progress = ()=>
-
+        progress = ()=>
+
             if handler.progress && data.total && data.file
                 now = +new Date()
                 data.progress = (parseInt data.received * 100 / data.total)
-
+
                 if data.file isnt file || data.progress is 100 || data.progress >= curr + 5 || now > sec + 1000
-
+
                     sec = now
                     curr = data.progress
                     file = data.file
-
+
                     data.state = 'uploading'
-
+
                     handler.progress data
-
-
+
+
         ## progress
-
+
         ##
         form.on 'fileBegin', (field, file)=>
-
+
             if file.type.toLowerCase().match handler.accept
                 data.file = file.name
-
+
                 progress()
-
-            else
+
+            else
                 handler.error new Error 'invalid type:'+file.name
-
-
+
+
         ##
         form.on 'progress', (received, total)=>
-
+
             data.received = received
             data.total = total
-
+
             progress()
-
-
+
+
         ## collect files
-
+
         files = []
-
+
         ##
         form.on 'file', (field, file)=>
-
+
             if file.type.toLowerCase().match handler.accept
-
+
                 files.push file
-
+
                 if handler.file
-                    handler.file
+                    handler.file
                         name: file.name
                         size: file.size
                     , data, field
-
+
                 progress()
-
-
+
+
         ## fire!
-
-        ##
-        form.parse req, (err, fields)=>
+
+        ##
+        form.parse req, (err, fields)=>
             done err, files, fields
-
-
-


Remove file that never should have been there


more migration stuff (for updating periodically)

--- salvus/bup_server.coffee
+++ salvus/bup_server.coffee
@@ -3357,10 +3357,14 @@
             test_limit  : undefined # if given, only migrate first this many projects.
             query_limit : undefined
             max_age_h   : 24   # max age of projects to update, in hours
+            oldest      : undefined # if given, take all projects with time at least this, ignoring max_age_h
             cb          : undefined
         dbg = (m) => winston.debug("migrate_missing: #{m}")
         projects = undefined
-        oldest   = (new Date() - 0) - opts.max_age_h*60*60*1000
+        if opts.oldest
+            oldest = opts.oldest - 0
+        else
+            oldest   = (new Date() - 0) - opts.max_age_h*60*60*1000
         errors = {}
         async.series([
             (cb) =>
@@ -3411,6 +3415,36 @@
             opts.cb?(err)
         )

+    migrate_update_recent_loop: (opts) =>
+        opts = defaults opts,
+            limit       : 10
+            max_age_h   : 5   # start auto-update loop with all projects from this long ago.
+            sleep_m     : 10   # how long in minutes to sleep between each update loop
+            cb          : undefined
+        cycle = 0
+        oldest = new Date() - opts.max_age_h*60*60*1000
+        f = () =>
+            cycle += 1
+            winston.debug("CYCLE: #{cycle}")
+            last_start = new Date() - 0
+            winston.debug("running update to get everything from #{(new Date() - oldest)/1000/60/60} hours ago")
+            @migrate_update_recent
+                oldest : oldest
+                limit  : opts.limit
+                cb     : (err) =>
+                    winston.debug("Finished cycle #{cycle}")
+                    if err
+                        winston.debug("migrate_update_recent_loop ERROR: #{err}")
+                        opts.cb?(err)
+                    else
+                        oldest = last_start
+                        winston.debug("sleeping #{opts.sleep_m} minutes before looping again...")
+                        setTimeout(f, opts.sleep_m*60*1000)
+        f()
+
+
+
+
 ###########################
 ## Client -- code below mainly sets up a connection to a given storage server
 ###########################


ordiering date time desc

ordiering date time desc

--- BackofficeBundle/Resources/public/coffee/table/TableviewCollectionView.coffee
+++ BackofficeBundle/Resources/public/coffee/table/TableviewCollectionView.coffee
@@ -24,11 +24,17 @@
       cid: @cid
     )
     $('.js-widget-title', @$el).text @title
+    ordering = true
+    if 'logs' == @elements.get('collection_name')
+      ordering = false
+      logs = @elements.get(@elements.get('collection_name'))
+      logs.sort (a, b) ->
+        return new Date(b['date_time']) - new Date(a['date_time'])
     for element of @elements.get(@elements.get('collection_name'))
       @addElementToView (@elements.get(@elements.get('collection_name'))[element])
     $('#tableviewCollectionTable').dataTable(
       searching: false
-      ordering: true
+      ordering: ordering
       lengthChange: false
     )
     return


change atom config

change atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,11 +1,17 @@
 "*":
+  "atom-ide-ui":
+    "atom-ide-diagnostics-ui": {}
+    use: {}
+  "autocomplete-python":
+    useKite: false
   core:
     audioBeep: false
     disabledPackages: [
       "exception-reporting"
       "metrics"
-      "activate-power-mode"
+      "linter"
     ]
+    excludeVcsIgnoredPaths: false
     ignoredNames: [
       "pip-selfcheck.json"
     ]
@@ -20,6 +26,7 @@
     invisibles: {}
     showIndentGuide: false
     showInvisibles: true
+  "ide-python": {}
   "isotope-light-ui":
     fontFamily: "System Default"
     matchEditorFont: true
@@ -37,7 +44,6 @@
     viewedVersion: "0.95.0"
   "tree-view":
     hideIgnoredNames: true
-    hideVcsIgnoredFiles: true
     squashDirectoryNames: true
   welcome:
     showOnStartup: false


remove tab length of 4

remove tab length of 4

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -24,7 +24,6 @@
     fontFamily: "Inconsolata, Monaco, Consolas, 'Courier New', Courier"
     invisibles: {}
     scrollPastEnd: true
-    tabLength: 4
     zoomFontWhenCtrlScrolling: true
     confirmCheckoutHeadRevision: false
     fontSize: 15


Update atom config to whatever I have now

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,20 +1,38 @@
-'global':
-  'welcome':
-    'showOnStartup': false
-  'editor':
-    'showIndentGuide': true
-    'softWrap': true
-    'fontFamily': 'Inconsolata-dz'
-    'lineHeight': 1.5
-    'fontSize': 12
-    'useHardwareAcceleration': false
-    'showInvisibles': true
-  'core':
-    'themes': [
-      'yosemite-unity-ui'
-      'wombat'
+"*":
+  welcome:
+    showOnStartup: false
+  editor:
+    fontFamily: "Inconsolata-dz"
+    fontSize: 12
+    showInvisibles: true
+    showIndentGuide: true
+    softWrap: true
+    invisibles: {}
+    scrollPastEnd: true
+    lineHeight: 1.5
+  core:
+    followSymlinks: true
+    themes: [
+      "atom-light-ui"
+      "one-light-syntax"
     ]
-    'useReactEditor': true
-  'tree-view':
-    'hideVcsIgnoredFiles': true
-
+  "tree-view":
+    hideVcsIgnoredFiles: true
+  "exception-reporting":
+    userId: "d315e297-f711-939e-05c1-de4ac1a4191e"
+  metrics:
+    userId: "d6fae20d4202703470b81281bd9b4d7b4ef68859"
+  linter: {}
+  react:
+    jsxTagStartPattern: "(?x)((^|=|return)\\s*<([^!/?](?!.+?(</.+?>))))"
+    jsxComplexAttributePattern: "(?x)\\{ [^}\"']* $|\\( [^)\"']* $"
+    decreaseIndentForNextLinePattern: "(?x) />\\s*(,|;)?\\s*$ | ^\\s*\\S+.*</[-_\\.A-Za-z0-9]+>$"
+  "graphite-ui":
+    syntaxThemeColoring: true
+  "atom-beautify":
+    _analyticsUserId: "f48ccd8c-b82f-4fbf-bb61-4e29de7a3348"
+  "vim-mode":
+    startInInsertMode: true
+    useClipboardAsDefaultRegister: true
+    useSmartcaseForSearch: true
+  "autocomplete-plus": {}


atom updates

atom updates

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -11,6 +11,8 @@
       panelContrast: true
   "autocomplete-plus":
     confirmCompletion: "tab and enter"
+  "autocomplete-python":
+    useKite: false
   core:
     disabledPackages: [
       "linter-eslint"
@@ -56,7 +58,10 @@
     useGlobalEslint: true
   "linter-jshint":
     disableWhenNoJshintrcFileInPath: true
-  "linter-pep8": {}
+  "linter-pep8":
+    ignoreErrorCodes: [
+      "E501"
+    ]
   metrics:
     userId: "f0927718331c072990cb750aafe7bbb7c24695ca"
   minimap:


added temporary sync between pouch and local couch

--- src/Main/Storage.coffee
+++ src/Main/Storage.coffee
@@ -1,9 +1,15 @@
 angular.module('lupo-proto').
 factory('storage', ($q, pouchdb) ->
-  remoteDb = pouchdb.create('localhost:5984/lupo-proto')
-  localDb = pouchdb.create('lupo-proto')
+  remoteDb = new PouchDB('http://localhost:5984/lupo-proto')
+  localDb = new PouchDB('lupo-proto')
+  PouchDB.sync(localDb, remoteDb, {
+    live: true
+  }).on('change', (e) -> console.log(e))
+  .on('complete', (e) -> console.log(e))
+  .on('error', (e) -> console.error(e))
+
   {
-    get: (_id) =>
+    get: (_id) ->
       deferred = $q.defer()
       localDb.get(_id)
       .then((result) =>
@@ -12,18 +18,25 @@
         deferred.reject(err)
       return deferred.promise
     ,
-    save: (doc) =>
+    save: (doc) ->
       deferred = $q.defer()
       method = if doc._id? then "put" else "post"
       console.log method, doc
       localDb[method](doc)
       .then((result) =>
-        console.log method, result
-        assert(result?, "no reply from db")
         deferred.resolve(result)
       ).catch (err) =>
         console.error(err)
         deferred.reject(err)
       return deferred.promise
+
+    query: (fun, options) ->
+      deferred = $q.defer()
+      localDb.query fun, options
+      .then (result) =>
+        deferred.resolve result
+      .catch (err) =>
+        deferred.reject err
+      return deferred.promise
   }
 )


removed localDb

removed localDb

--- src/Main/Storage.coffee
+++ src/Main/Storage.coffee
@@ -3,39 +3,61 @@
   dbUrl = $location.absUrl().split('#')[0]
   dbUrl += 'lupo-proto/'
   remoteDb = new PouchDB(dbUrl)
-  localDb = new PouchDB('lupo-proto')
+  #localDb = new PouchDB('lupo-proto')
   #TMP
-  PouchDB.replicate(localDb, remoteDb)
-  #.on('change', (e) -> console.log(e))
-  #.on('complete', (e) -> console.log(e))
-  #.on('error', (e) -> console.error(e))
-
+  #PouchDB.replicate(localDb, remoteDb, {live: true})
+  #.on('change', (e) -> console.log("upload", e))
+  #.on('complete', (e) -> console.log("upload", e))
+  #.on('error', (e) -> console.error("upload", e))
+  syncIds = {list: []}
+  ###
+  localDb.allDocs().then (list) =>
+    syncIds.list = (row.id for row in list.rows)
+    syncIds.list.push "proto"
+    PouchDB.replicate(localDb, remoteDb,
+      live: true
+    )
+    .on 'change', (change) =>
+      #syncIds.list.push result.id
+      console.log "local change", change
+    .on('complete', (e) -> console.log("complete", e))
+    .on('uptodate', (e) -> console.log("uptodate", e))
+    .on('error', (e) -> console.error("error", e))
+    remoteDb.change(
+      live: true
+    ).on 'change', (change) =>
+      console.log "remote change", change
+      if syncIds.indexOf(change.id) > -1
+        console.log "remote change!!"
+  ###
   _indent = "  "
   {
+    purge: (db) ->
+      if not db?
+        @purge(localDb).then =>
+          @purge(remoteDb)
+      else
+        db.allDocs().then (list) =>
+          for row in list.rows
+            db.remove({_id: row.id, _rev: row.value.rev})
+            .then =>
+              console.log "remove", row.id
+            .catch =>
+              console.error "error removing", row.id
+
     get: (_id) ->
       _funcName = _indent + "storage.get"
       console.log _funcName, _id
       deferred = $q.defer()
-      otherOneFailed = false
       remoteDb.get _id, (err, result) =>
         if err?
-          console.error "remote", err
-          if otherOneFailed
-            deferred.reject err
-          otherOneFailed = true
-        else
-          deferred.resolve result
-      localDb.get _id, (err, result) =>
-        if err?
-          console.error "local", err
-          if otherOneFailed
-            deferred.reject err
-          otherOneFailed = true
+          console.error "NOT FOUND", _id, err
+          deferred.reject err
         else
           deferred.resolve result
       return deferred.promise

-    _save: (doc, remoteAndLocal) ->
+    _save: (doc) ->
       deferred = $q.defer()
       if doc._id?
         method = "put"
@@ -44,11 +66,7 @@
         delete doc._id
         delete doc._rev
       console.log method, doc
-      (if remoteAndLocal
-        localDb[method](doc)
-      else
-        remoteDb[method](doc)
-      )
+      remoteDb[method](doc)
       .then (result) =>
         deferred.resolve(result)
       .catch (err) =>
@@ -59,20 +77,19 @@
     saveLocal: (doc) ->
       _funcName = _indent + "storage.saveLocal"
       console.log _funcName
-      @_save doc, true
+      @_save doc

     saveRemoteOnly: (doc) ->
       _funcName = _indent + "storage.saveRemoteOnly"
       console.log _funcName
-      @_save doc, false
+      @_save doc

     save: (doc) ->
-      @_save(doc, true)
+      @_save(doc)

     del: (doc) ->
       deletedDoc = {_id: doc._id, _rev: doc._rev, _deleted: true}
-      @saveLocal(deletedDoc).catch =>
-        @saveRemoteOnly(deletedDoc)
+      @save(deletedDoc)

     queryRemote: (fun, options) ->
       deferred = $q.defer()
@@ -87,20 +104,10 @@
       _funcName = _indent + "query"
       console.log _funcName, fun, options
       deferred = $q.defer()
-      localDeferred = $q.defer()
       otherOneFailed = false
-      localDb.query fun, options, (err, result) =>
-        if result.rows.length == 0
-          if otherOneFailed
-            deferred.resolve []
-          otherOneFailed = true
-        else
-          deferred.resolve (doc.value for doc in result.rows)
       remoteDb.query fun, options, (err, result) =>
         if result.rows.length == 0
-          if otherOneFailed
-            deferred.resolve []
-          otherOneFailed = true
+          deferred.resolve []
         else
           deferred.resolve (doc.value for doc in result.rows)
       return deferred.promise


I think this is the intent here

I think this is the intent here

--- index.coffee
+++ index.coffee
@@ -59,7 +59,7 @@

 		# Only add the window listener if it doesn't exist
 		if !@handlers[event].keys[key]?
-			@handlers[event].keys[key] = []
+			@handlers[event].keys[key] = true
 			window.addEventListener event,
 				_.debounce(_.throttle(@fire, options.throttle), options.debounce)


Fix when there aren't any words mispelled

--- index.coffee
+++ index.coffee
@@ -54,12 +54,13 @@
     Teacher.check(text, (err, data) ->
       i = 0
       data.forEach (word) ->
-        if word.suggestions.option instanceof Array
-          correct = word.suggestions.option[0]
-        else
-          correct = word.suggestions.option
+        if  word.suggestions
+          if word.suggestions.option instanceof Array
+            correct = word.suggestions.option[0]
+          else
+            correct = word.suggestions.option

-        text = text.replace word.string, correct
+          text = text.replace word.string, correct

         if ++i == data.length
           channel.send "#{response} _#{text}_"


added state update polling

added state update polling

--- src/homematic.coffee
+++ src/homematic.coffee
@@ -11,6 +11,7 @@
 				'qs' : vars
 				'url' : "http://#{host}/config/xmlapi/#{script}.cgi"
 				'withCredentials' : false
+				'scheme' : 'http' #a bug in browserify?

 parseXml = (xml) ->
 	xml2js.parseStringAsync xml
@@ -57,6 +58,17 @@
 		'new_value': value
 								 })

+module.exports.getState = (addr,id) ->
+	rq urlOf(addr,'state', {
+		'datapoint_id' : id
+		})
+	.then parseXml
+	.then (res) ->
+		if not res.state.datapoint? || res.state.datapoint.length == 0
+			throw 'empty resp'
+		res.state.datapoint[0].$.value
+
+
 module.exports.getDataPoints = (addr) ->
 	res = []
 	idx=0
@@ -77,4 +89,6 @@
 							'value' : dp.$.value #todo: type according to valuetype
 							'set' : (newValue) ->
 								module.exports.setState @ccu,@id,newValue
+							'update' : () ->
+								value = module.exports.getState @ccu,@id
 			return res


Allowance for overloading functions with empty signature

--- src/Overloadable.coffee
+++ src/Overloadable.coffee
@@ -60,7 +60,7 @@
     unless Object.isExtensible(this)
       throw new TypeError(ERRORS.FUNCTION_NOT_EXTENSIBLE)

-    if not Array.isArray(signature) or signature.length is 0
+    unless Array.isArray(signature)
       throw new Error(ERRORS.INVALID_OVERLOAD_SIGNATURE)

     if typeof functionToCall isnt "function"


hide path in `require 'readline'` for compatibility with `https://github.com/Jarred-Sumner/bun/releases/tag/bun-v0.1.2`

--- src/TRM.coffee
+++ src/TRM.coffee
@@ -79,7 +79,10 @@

 #-----------------------------------------------------------------------------------------------------------
 @ask = ( prompt, handler ) ->
-  rl = ( require 'readline' ).createInterface
+  ### https://github.com/Jarred-Sumner/bun v0.1.2 will try to resolve statically `require()` calls inside of
+  functions and fail for `readline`; putting the module name in a variable makes it skip that step: ###
+  hide_for_bun  = 'readline'
+  rl            = ( require hide_for_bun ).createInterface
     input:  process.stdin
     output: process.stdout
   #.........................................................................................................


Use rgba color settings by default

Use rgba color settings by default

Fixes issue where deselecting an rgba color made it hex, losing transparency.

--- packages/rocketchat-ui-admin/admin/admin.coffee
+++ packages/rocketchat-ui-admin/admin/admin.coffee
@@ -346,11 +346,17 @@
 		SideNav.openFlex()

 	Meteor.setTimeout ->
-		$('input.minicolors').minicolors({theme: 'rocketchat'})
+		$('input.minicolors').minicolors
+			theme: 'rocketchat'
+			format: 'rgb'
+			opacity: true
 	, 1000

 	Tracker.autorun ->
 		FlowRouter.watchPathChange()
 		Meteor.setTimeout ->
-			$('input.minicolors').minicolors({theme: 'rocketchat'})
+			$('input.minicolors').minicolors
+				theme: 'rocketchat'
+				format: 'rgb'
+				opacity: true
 		, 400


Followup 40c3e689248172406d76c13f259522398bdff7b2 - Fixes #3135 - Fixed arrow for values.

--- app/assets/javascripts/app/controllers/_application_controller_generic.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_generic.coffee
@@ -735,10 +735,10 @@

         if item.value_to
           if item.value_from
-            content += ' 🡒'
+            content += ' →'
           content += " '#{ App.Utils.htmlEscape(item.value_to) }'"
         else if item.value_from
-          content += " 🡒 '-'"
+          content += " → '-'"

       newItem.records.push content


default: shift-command-C clear post window

--- keymaps/supercollider.cson
+++ keymaps/supercollider.cson
@@ -12,10 +12,10 @@
   'shift-enter': 'supercollider:eval'
   'shift-cmd-k': 'supercollider:recompile'
   'cmd-.': 'supercollider:cmd-period'
+  'shift-cmd-c': 'supercollider:clear-post-window'
+
   # you may add these to your personal keymaps
   # scope dependant keymaps are an upcoming atom feature
-
-  # 'shift-alt-k': 'supercollider:clear-post-window'

   # cmd-D is far too popular
   # cmd-shift-h conflicts with git-plus


fix bug where options page wasn't properly being refreshed

--- src/app.coffee
+++ src/app.coffee
@@ -42,7 +42,10 @@
                 @storage.get ['opac', 'lat', 'long'], resp
                 true
             else if req.type is 'init_tab'
-                @refresh_overlay null, resp
+                @storage.get 'last_update', (it) =>
+                    @refresh_overlay null, resp
+                    if Date.now() - it.last_update > 1000*60*15 # 15 minutes
+                        @refresh_all_overlays()
                 true
             else if req.type is 'init_options'
                 @storage.get ['mode', 'keymode', 'kfs', 'auto_opac', 'color'], resp


changed listen to respond regarding exceptions...

--- scripts/exceptions.coffee
+++ scripts/exceptions.coffee
@@ -19,7 +19,7 @@
   data[cat] = counters

 module.exports = (robot) ->
-  robot.hear /(.*) (.*exception)(.*)/i, (msg) ->
+  robot.respond /(.*) (.*exception)(.*)/i, (msg) ->
     msg.send "Aie! : Got a #{msg.match[2]} from #{msg.match[1]} complaining about #{msg.match[3]}"
     key = "exceptions_#{today()}"


Adds more expression components to expression_to_string

--- javascripts/lib/math/expression_to_string.coffee
+++ javascripts/lib/math/expression_to_string.coffee
@@ -2,14 +2,14 @@
   ['lib/class_mixer', 'lib/object_refinement', 'lib/math/expression_components'],
   (class_mixer, object_refinement, comps)->

-
     ref = object_refinement.build()
-
     ref.forDefault({
       toString: ->
-        '?'
+        #console.log "toString not handled for #{AP @unrefined()}"
+        "?"
       toHTMLString: ->
-        '?'
+        #console.log "toHTMLString not handled for #{AP @unrefined()}"
+        "?"
       })

     ref.forType(comps.addition, {
@@ -23,11 +23,24 @@
       power: ->
         ref.refine(@unrefined().power()).toString()
       toString: ->
-        "#{@base()}^#{@power()}"
+        "#{@base()} ^ #{@power()}"
       toHTMLString: ->
-        "#{@base()}ˆ#{@power()}"
+        "#{@base()} ˆ #{@power()}"
       });

+    ref.forType(comps.multiplication, {
+      toString: ->
+        "*"
+      toHTMLString: ->
+        "×"
+      });
+
+    ref.forType(comps.subtraction, {
+      toString: ->
+        "*"
+      toHTMLString: ->
+        "×"
+      })

     ref.forType(comps.expression, {
       toString: ->
@@ -37,6 +50,11 @@
       mapconcatWithMethod: (method)->
         _(@expression).map((it)-> ref.refine(it)[method]()).join(' ')
       });
+
+    ref.forType(comps.blank, {
+      toString: -> ""
+      toHTMLString: -> ""
+      })

     ref.forType(comps.number, {
       toString: ->


Switched to zip file link

Switched to zip file link

--- app/pages/lab/how-to-page.cjsx
+++ app/pages/lab/how-to-page.cjsx
@@ -147,7 +147,7 @@
       You'll need to have all of your images in a single folder along with a manifest. The manifest file lists
       all the images we want to upload and links each image to additional information, also called metadata,
       such as date, time, and photographer. Read more about the manifest in the subsequent "Details" sections,
-      but for now we've done this for you in the ["Kitteh" folder](https://drive.google.com/folderview?id=0B9JCiuF48lmgfndFZjdhTVRtcHEtQ3haY2ZYQjFmMW4wb0VWdnpiakZ4OVIyWlRjdXpiTVk&usp=sharing).
+      but for now we've done this for you in the ["Kitteh" zip file](https://data.zooniverse.org/tutorial/kitteh_zoo.zip).

       Click on the "Upload Subjects" box and navigate to the "Kitteh" folder you downloaded. The easiest thing
       to do is simply hit _cmd + a_ (on Mac, or _ctrl + a_ on Windows) to select everything in that folder.