Remove brunch config

Remove brunch config

--- config.coffee
+++ config.coffee
@@ -1,304 +0,0 @@
-#- Imports, helpers
-_ = require 'lodash'
-_.str = require 'underscore.string'
-sysPath = require 'path'
-fs = require('fs')
-commonjsHeader = require('commonjs-require-definition')
-TRAVIS = process.env.COCO_TRAVIS_TEST
-console.log 'Travis Build' if TRAVIS
-
-
-#- regJoin replace a single '/' with '[\/\\]' so it can handle either forward or backslash
-regJoin = (s) -> new RegExp(s.replace(/\//g, '[\\\/\\\\]'))
-
-gameLibraries = [
-  'register-game-libraries'
-  'createjs'
-  'ShaderParticles'
-  'deku'
-  'htmlparser2'
-  'css'
-  'firepad'
-  'jquery-ui-custom'
-  'coffeescript'
-].join '|'
-
-#- Build the config
-
-exports.config =
-
-  paths:
-    public: 'public'
-    watched: [
-      'app',
-      'vendor',
-      'test/app',
-      'test/demo'
-    ]
-
-  conventions:
-    ignored: (path) -> _.str.startsWith(sysPath.basename(path), '_')
-
-  sourceMaps: 'absoluteUrl'
-
-  overrides:
-    production:
-      sourceMaps: 'absoluteUrl'
-      plugins:
-        coffeelint:
-          pattern: /\A\Z/
-        afterBrunch: [
-          "coffee scripts/minify.coffee",
-        ]
-    fast:
-      onCompile: (files) -> console.log "I feel the need, the need... for speed."
-      plugins:
-        coffeelint:
-          pattern: /\A\Z/
-    vagrant:
-      watcher:
-        usePolling: true
-
-  server:
-    # NOTE: This is a temporary workaround for https://github.com/nodejs/node-v0.x-archive/issues/2318
-    command: "#{if process.platform is 'win32' then 'node_modules\\.bin\\nodemon.cmd' else 'nodemon'} ."
-
-  files:
-    javascripts:
-      defaultExtension: 'coffee'
-      joinTo:
-
-        #- app.js, the first file that is loaded. These modules are required to initialize the client.
-        'javascripts/app.js': [
-
-          # IMPORTANT: if you add to this, make sure you also add any other dependencies,
-          # or better yet, put them in a 'core' folder.
-          regJoin('^app/schemas')
-          regJoin('^app/models')
-          regJoin('^app/collections')
-          regJoin('^app/core')
-          regJoin('^app/views/core')
-          'app/locale/locale.coffee'
-          'app/locale/en.coffee'
-          'app/locale/en-US.coffee'
-          'app/lib/sprites/SpriteBuilder.coffee' # loaded by ThangType
-          'app/views/HomeView.coffee'
-        ]
-
-        #- Karma is a bit more tricky to get to work. For now just dump everything into one file so it doesn't need to load anything through ModuleLoader.
-        'javascripts/whole-app.js': if TRAVIS then [
-          regJoin('^app')
-        ] else []
-
-        #- Wads. Groups of modules by folder which are loaded as a group when needed.
-        'javascripts/perf.js': [
-          regJoin('^bower_components/lodash')
-          regJoin('^bower_components/jquery')
-          regJoin('^bower_components/backbone')
-          regJoin('^app/lib/scripts/PerfTester')
-        ]
-        'javascripts/app/lib.js': regJoin('^app/lib')
-        'javascripts/app/views/play.js': regJoin('^app/views/play')
-        'javascripts/app/views/editor.js': regJoin('^app/views/editor')
-        'javascripts/app/views/courses.js': regJoin('^app/views/courses')
-
-        #- world.js, used by the worker to generate the world in game
-        'javascripts/world.js': [
-          regJoin('^app/lib/world(?!/test)')
-          regJoin('^app/core/CocoClass.coffee')
-          regJoin('^app/core/utils.coffee')
-          regJoin('^vendor/scripts/Box2dWeb-2.1.a.3')
-          regJoin('^vendor/scripts/string_score.js')
-          regJoin('^bower_components/underscore.string')
-          regJoin('^vendor/scripts/coffeescript.js')
-        ]
-
-        #- vendor.js, all the vendor libraries
-        'javascripts/vendor.js': [
-          regJoin('^vendor/scripts/(?!(coffeescript|difflib|diffview|jasmine|co|' + gameLibraries + '))')
-          regJoin('^bower_components/(?!(aether|d3|treema|three.js|esper.js|jquery-ui|vimeo-player-js|' + gameLibraries  + '))')
-          'bower_components/treema/treema-utils.js'
-        ]
-
-        'javascripts/game-libraries.js': [
-          regJoin('^vendor/scripts/(' + gameLibraries + ')')
-          regJoin('^bower_components/(' + gameLibraries  + ')')
-
-        ],
-
-        'javascripts/whole-vendor.js': if TRAVIS then [
-          regJoin('^vendor/scripts/(?!(jasmine|register-game-libraries))')
-          regJoin('^bower_components/(?!aether|esper.js)')
-        ] else []
-
-        #- Other vendor libraries in separate bunches
-
-        # Include box2dweb for profiling and IE9
-        # Vector renamed to Box2DVector to avoid name collisions
-        # TODO: move this to assets/lib since we're not really joining anything here?
-        'javascripts/box2d.js': regJoin('^vendor/scripts/Box2dWeb-2.1.a.3')
-        'javascripts/lodash.js': regJoin('^bower_components/lodash/dist/lodash.js')
-        'javascripts/aether.js': regJoin('^bower_components/aether/build/aether.js')
-        'javascripts/esper.js': 'bower_components/esper.js/esper.js'
-        'javascripts/app/vendor/aether-coffeescript.js': 'bower_components/aether/build/coffeescript.js'
-        'javascripts/app/vendor/aether-javascript.js': 'bower_components/aether/build/javascript.js'
-        'javascripts/app/vendor/aether-lua.js': 'bower_components/aether/build/lua.js'
-        'javascripts/app/vendor/aether-java.js': 'bower_components/aether/build/java.js'
-        'javascripts/app/vendor/aether-python.js': 'bower_components/aether/build/python.js'
-        'javascripts/app/vendor/aether-html.js': 'bower_components/aether/build/html.js'
-        'javascripts/app/vendor/vimeo-player-js.js': 'bower_components/vimeo-player-js/dist/player.min.js'
-
-        # Any vendor libraries we don't want the client to load immediately
-        'javascripts/app/vendor/d3.js': regJoin('^bower_components/d3')
-        'javascripts/app/vendor/coffeescript.js': 'vendor/scripts/coffeescript.js'
-        'javascripts/app/vendor/difflib.js': 'vendor/scripts/difflib.js'
-        'javascripts/app/vendor/diffview.js': 'vendor/scripts/diffview.js'
-        'javascripts/app/vendor/treema.js': 'bower_components/treema/treema.js'
-        'javascripts/app/vendor/jasmine-bundle.js': regJoin('^vendor/scripts/jasmine')
-        'javascripts/app/vendor/jasmine-mock-ajax.js': 'vendor/scripts/jasmine-mock-ajax.js'
-        'javascripts/app/vendor/three.js': 'bower_components/three.js/three.min.js'
-        'javascripts/app/vendor/htmlparser2.js': 'vendor/scripts/htmlparser2.js'
-        'javascripts/app/vendor/deku.js': 'vendor/scripts/deku.js'
-        'javascripts/app/vendor/co.js': 'vendor/scripts/co.js'
-
-        #- test, demo libraries
-        'javascripts/app/tests.js': regJoin('^test/app/')
-        'javascripts/app/demo-app.js': regJoin('^test/demo/')
-
-        #- More output files are generated at the below
-
-      order:
-        before: [
-          # jasmine-bundle.js ordering
-          'vendor/scripts/jasmine.js'
-          'vendor/scripts/jasmine-html.js'
-          'vendor/scripts/jasmine-boot.js'
-          'vendor/scripts/jasmine-mock-ajax.js'
-
-          # vendor.js ordering
-          'bower_components/jquery/dist/jquery.js'
-          'bower_components/lodash/dist/lodash.js'
-          'bower_components/backbone/backbone.js'
-          # Twitter Bootstrap jquery plugins
-          'bower_components/bootstrap/dist/bootstrap.js'
-          # CreateJS dependencies
-          'vendor/scripts/createjs.js'
-          # Validated Backbone Mediator dependencies
-          'bower_components/tv4/tv4.js'
-          # Aether before box2d for some strange Object.defineProperty thing
-          'bower_components/aether/build/aether.js'
-          'bower_components/esper.js/esper.js'
-          'bower_components/fastclick/lib/fastclick.js'
-          'bower_components/d3/d3.min.js'
-          'vendor/scripts/async.js'
-          'vendor/scripts/jquery-ui-1.11.1.js.custom.js'
-        ]
-        after: [
-          'bower_components/algolia-autocomplete-no-conflict/no-conflict.js'
-        ]
-    stylesheets:
-      defaultExtension: 'sass'
-      joinTo:
-        'stylesheets/app.css': /^(app|vendor|bower_components)/
-      order:
-        before: [
-          'app/styles/bootstrap/*'
-          'vendor/styles/nanoscroller.scss'
-        ]
-
-    templates:
-      defaultExtension: 'jade'
-      joinTo:
-        'javascripts/app.js': [regJoin('^app/templates/core'), regJoin('^app/templates/home-view')]
-        'javascripts/app/views/play.js': regJoin('^app/templates/play')
-        'javascripts/app/views/courses.js': regJoin('^app/templates/courses')
-        'javascripts/app/views/game-menu.js': regJoin('^app/templates/game-menu')
-        'javascripts/app/views/editor.js': regJoin('^app/templates/editor')
-        'javascripts/whole-app.js': if TRAVIS then regJoin('^app/templates') else []
-
-  framework: 'backbone'
-
-  plugins:
-    coffeelint:
-      pattern: /^app\/.*\.coffee$/
-      options:
-        line_endings:
-          value: 'unix'
-          level: 'error'
-        max_line_length:
-          level: 'ignore'
-        no_trailing_whitespace:
-          level: 'ignore'  # PyCharm can't just autostrip for .coffee, needed for .jade
-        no_unnecessary_fat_arrows:
-          level: 'ignore'
-    sass:
-      mode: 'native'
-      allowCache: true
-    assetsmanager:
-      copyTo:
-        'lib/ace': ['node_modules/ace-builds/src-min-noconflict/*']
-        'fonts': ['bower_components/openSansCondensed/!(*bower.json)', 'bower_components/openSans/!(*bower.json)', 'bower_components/font-awesome/fonts/*']
-        'javascripts': ['bower_components/esper.js/esper.modern.js']
-    autoReload:
-      delay: 1000
-    static:
-      processors: [
-        require('./brunch-static-stuff') {
-          locals: {shaTag: process.env.GIT_SHA or 'dev'}
-        }
-      ]
-
-  modules:
-    definition: (path, data) ->
-      needHeaderExpr = regJoin('^public/javascripts/?(app.js|world.js|perf.js|whole-app.js)')
-      defn = if path.match(needHeaderExpr) then commonjsHeader else ''
-      return defn
-
-#- Find all .coffee and .jade files in /app
-
-dirStack = ['./app']
-coffeeFiles = []
-jadeFiles = []
-
-while dirStack.length
-  dir = dirStack.pop()
-  contents = fs.readdirSync(dir)
-  for file in contents
-    fullPath = "#{dir}/#{file}"
-    stat = fs.statSync(fullPath)
-    if stat.isDirectory()
-      dirStack.push(fullPath)
-    else
-      if _.str.endsWith(file, '.coffee') or _.str.endsWith(file, '.js')
-        coffeeFiles.push(fullPath)
-      else if _.str.endsWith(file, '.jade')
-        jadeFiles.push(fullPath)
-
-for file in coffeeFiles
-  inputFile = file.replace('./app', 'app')
-  outputFile = file.replace('.coffee', '.js').replace('./app', 'javascripts/app')
-  exports.config.files.javascripts.joinTo[outputFile] = inputFile
-
-numBundles = 0
-
-for file in jadeFiles
-  continue if /static.jade$/.test file
-  inputFile = file.replace('./app', 'app')
-  outputFile = file.replace('.jade', '.js').replace('./app', 'javascripts/app')
-  exports.config.files.templates.joinTo[outputFile] = inputFile
-
-  #- If a view template name matches its view, bundle it in there.
-  templateFileName = outputFile.match(/[^/]+$/)[0]
-  viewFileName = _.str.capitalize(_.str.camelize(templateFileName))
-  possibleViewFilePath = outputFile.replace(templateFileName, viewFileName).replace('/templates/', '/views/')
-  if exports.config.files.javascripts.joinTo[possibleViewFilePath]
-    exports.config.files.templates.joinTo[possibleViewFilePath] = inputFile
-    numBundles += 1
-
-console.log "Got #{coffeeFiles.length} coffee files and #{jadeFiles.length} jade files (bundled #{numBundles} of them together)."
-
-if process.env.GIT_SHA
-  info =
-    sha: process.env.GIT_SHA
-  fs.writeFile '.build_info.json', JSON.stringify info, null, '  '
-  console.log( "Wrote build information file");


Refactor code style

Refactor code style

--- src/mongodb_store.coffee
+++ src/mongodb_store.coffee
@@ -14,7 +14,7 @@
   initialize: (@_context, options = {}) ->
     # TODO: Make db private but allow to request it to access the store directly if needed
     @db = null
-    @_initializePromise = new Promise (resolve) =>
+    @_initializePromise = new Promise (resolve, reject) =>
       @_defaults options, @_optionDefaults
       @_domainEventsCollectionName = "#{@_context.name}.DomainEvents"

@@ -27,6 +27,9 @@
       .then (db) =>
         @db = db
         resolve()
+      .catch reject
+
+    return @_initializePromise

   _defaults: (options, optionDefaults) ->
@@ -58,7 +61,7 @@
       upsert: true
       new: true

-    @_getCollection 'eventSourcingConfig'
+    return @_getCollection 'eventSourcingConfig'
     .then (collection) ->
       # TODO: findAndModify is deprecated: http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#findAndModify
       # Use findOneAndUpdate: http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#findOneAndUpdate


Update ng-quick-date.coffee

Update ng-quick-date.coffee

--- src/ng-quick-date.coffee
+++ src/ng-quick-date.coffee
@@ -349,7 +349,7 @@

-                      {{day}}
+                      {{day}}


Updated atom font

Updated atom font

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -34,3 +34,5 @@
     showOnStartup: false
   "release-notes":
     viewedVersion: "0.89.0"
+  fonts:
+    fontFamily: "FiraCode"


Switched to light theme in atom.io

Switched to light theme in atom.io

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -13,8 +13,8 @@
     'vendor'
   ]
   'themes': [
-    'unity-ui'
-    'glacier-syntax'
+    'atom-light-ui'
+    'atom-light-syntax'
   ]
   'hideGitIgnoredFiles': true
   'disabledPackages': [


bump atom config

bump atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,34 +1,35 @@
-'editor':
-  'showIndentGuide': true
-  'fontFamily': 'Menlo'
-  'fontSize': 15
-  'invisibles': {}
-'core':
-  'ignoredNames': [
-    '.bundle'
-    '.git'
-    'log'
-    'repositories'
-    'tmp'
-    'vendor'
-  ]
-  'themes': [
-    'unity-ui'
-    'glacier-syntax'
-  ]
-  'hideGitIgnoredFiles': true
-  'disabledPackages': [
-    'background-tips'
-    'exception-reporting'
-    'metrics'
-  ]
-'spell-check':
-  'grammars': [
-    'text.plain'
-    'source.gfm'
-    'text.git-commit'
-  ]
-'welcome':
-  'showOnStartup': false
-'release-notes':
-  'viewedVersion': '0.89.0'
+'global':
+  'editor':
+    'showIndentGuide': true
+    'fontFamily': 'Menlo'
+    'fontSize': 15
+  'core':
+    'ignoredNames': [
+      '.bundle'
+      '.git'
+      'log'
+      'repositories'
+      'tmp'
+      'vendor'
+    ]
+    'themes': [
+      'unity-ui'
+      'glacier-syntax'
+    ]
+    'hideGitIgnoredFiles': true
+    'disabledPackages': [
+      'background-tips'
+      'exception-reporting'
+      'metrics'
+    ]
+  'spell-check':
+    'grammars': [
+      'text.plain'
+      'source.gfm'
+      'text.git-commit'
+    ]
+  'welcome':
+    'showOnStartup': false
+  'release-notes':
+    'viewedVersion': '0.89.0'
+  'go-plus': {}


bump atom config

bump atom config


Ability to update the char info

Ability to update the char info

--- static/js/encoding-mashup.coffee
+++ static/js/encoding-mashup.coffee
@@ -1,6 +1,6 @@
 template = Handlebars.compile("""

-    <form>
+    <form data-char-id="{{view.id}}">

         {{{view.moe}}}
         {{view.display}}
@@ -8,17 +8,26 @@

       <input type="text" name="cns" value="{{exact.cns}}"></input>
       <input type="text" name="comments" value="{{comments}}"></input>
+      <button class="btn btn-small btn-primary" type="button">Save</button>
     </form>

 """)
+
+allCharData = {}

 onReady = ->
   $context = $('#context')

   $.getJSON('/api/chars/all', (data) ->
+    console.dir data
+
+    # Bind to this file's scope
+    allCharData = data
+
     for key, datum of data
       view = {}

+      view.id = key
       # TODO: Select display from multiple sources pua -> uni -> ids
       view.display = datum.display.uni

@@ -35,6 +44,33 @@
     for key, datum of data
       html = template(datum)
       $context.append(html)
+
+    $('button').on('click', (event) ->
+      $form = $(this).parent()
+      id = $form.data('char-id')
+      datum = allCharData[id]
+
+      # Tricky deep clone
+      datum = JSON.parse(JSON.stringify(datum))
+
+      cns = $form.children('input[name="cns"]').val()
+      comments = $form.children('input[name="comments"]').val()
+
+      datum.comments = comments
+      datum.exact.cns = cns
+
+      url = "/api/char/#{encodeURIComponent(datum.view.id)}"
+
+      # TODO: Refactoring: Move extra info from `view` to somewhere else
+      delete datum.view
+
+      $.ajax {
+        url: url
+        type: 'PUT'
+        data: JSON.stringify(datum)
+      }
+
+    )
   )

 $(onReady)


Fixed maintenance mode access grantees removal

--- static/script/pages/admin.coffee
+++ static/script/pages/admin.coffee
@@ -50,7 +50,7 @@

{{= user.name}}

-
+


uncomment notification socket

uncomment notification socket

--- lib/notifier.coffee
+++ lib/notifier.coffee
@@ -8,7 +8,6 @@
 remote = require 'remote'
 localStorage = require './local-storage'
 BrowserWindow = remote.require('browser-window')
-bus = require('./event-bus')()

 module.exports =
 class Notifier extends EventEmitter
@@ -20,82 +19,81 @@

   activate: ->
     try
-      console.log 'in notification'
-      # @userInfo =  JSON.parse(localStorage.get('commit-live:user-info'))
-      # @socket = io.connect('http://35.154.206.75:5000/' , reconnect: true)
-      # @socket.on 'connect', =>
-      #   @socket.emit 'join', room: @userInfo.username
-      #   console.log 'socket.io is connected, listening for notification'
-      #
-      # @socket.on 'my_response', (msg) ->
-      #   console.log 'msg from websocket'
-      #   console.log msg
-      #   if msg.data == 'ping'
-      #     console.log "Got ping packet from websocket server :)"
-      #
-      #   if msg.data != 'ping'
-      #     try
-      #       rawData = JSON.parse(msg.data)
-      #       console.log rawData
-      #       if rawData.type == 'notify_ide'
-      #         if rawData.message.type == 'test_case_pass'
-      #           notif = new Notification rawData.title,
-      #             body: 'Test cases passed successfully'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #         if rawData.message.type == 'test_case_fail'
-      #           notif = new Notification rawData.title,
-      #             body: 'Test cases failed'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #         if rawData.message.type == 'completed_reading'
-      #           notif = new Notification rawData.title,
-      #             body: rawData.message.value == 'true' ? 'Reading completed successfully' : 'Reading not completed'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #         if rawData.message.type == 'forked'
-      #           notif = new Notification rawData.title,
-      #             body: rawData.message.value == 'true' ? 'Lesson forked successfully' : 'Lesson forked failed'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #         if rawData.message.type == 'submitted_pull_request'
-      #           notif = new Notification rawData.title,
-      #             body: rawData.message.value == 'true' ? 'Pull request submitted successfully' : 'Pull request failed'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #         if rawData.message.type == 'reviewed'
-      #           notif = new Notification rawData.title,
-      #             body: rawData.message.value == 'true' ? 'Review completed successfully' : 'Review failed'
-      #
-      #           notif.onclick = ->
-      #             notif.close()
-      #
-      #       if rawData.type == 'pop_image'
-      #         win = new BrowserWindow(
-      #           show: false,
-      #           width: parseInt(rawData.width),
-      #           height: parseInt(rawData.height),
-      #           resizable: true,
-      #           useContentSize : true
-      #         )
-      #         win.setSkipTaskbar(true)
-      #         win.setMenuBarVisibility(false)
-      #         win.setTitle(rawData.title)
-      #         win.loadURL(rawData.url)
-      #         win.show()
-      #
-      #     catch error
-      #       console.log 'Notification message from websocket contains invali JSON string'
+      @userInfo =  JSON.parse(localStorage.get('commit-live:user-info'))
+      @socket = io.connect('http://35.154.206.75:5000/' , reconnect: true)
+      @socket.on 'connect', =>
+        @socket.emit 'join', room: @userInfo.username
+        console.log 'socket.io is connected, listening for notification'
+
+      @socket.on 'my_response', (msg) ->
+        console.log 'msg from websocket'
+        console.log msg
+        if msg.data == 'ping'
+          console.log "Got ping packet from websocket server :)"
+
+        if msg.data != 'ping'
+          try
+            rawData = JSON.parse(msg.data)
+            console.log rawData
+            if rawData.type == 'notify_ide'
+              if rawData.message.type == 'test_case_pass'
+                notif = new Notification rawData.title,
+                  body: 'Test cases passed successfully'
+
+                notif.onclick = ->
+                  notif.close()
+
+              if rawData.message.type == 'test_case_fail'
+                notif = new Notification rawData.title,
+                  body: 'Test cases failed'
+
+                notif.onclick = ->
+                  notif.close()
+
+              if rawData.message.type == 'completed_reading'
+                notif = new Notification rawData.title,
+                  body: rawData.message.value == 'true' ? 'Reading completed successfully' : 'Reading not completed'
+
+                notif.onclick = ->
+                  notif.close()
+
+              if rawData.message.type == 'forked'
+                notif = new Notification rawData.title,
+                  body: rawData.message.value == 'true' ? 'Lesson forked successfully' : 'Lesson forked failed'
+
+                notif.onclick = ->
+                  notif.close()
+
+              if rawData.message.type == 'submitted_pull_request'
+                notif = new Notification rawData.title,
+                  body: rawData.message.value == 'true' ? 'Pull request submitted successfully' : 'Pull request failed'
+
+                notif.onclick = ->
+                  notif.close()
+
+              if rawData.message.type == 'reviewed'
+                notif = new Notification rawData.title,
+                  body: rawData.message.value == 'true' ? 'Review completed successfully' : 'Review failed'
+
+                notif.onclick = ->
+                  notif.close()
+
+            if rawData.type == 'pop_image'
+              win = new BrowserWindow(
+                show: false,
+                width: parseInt(rawData.width),
+                height: parseInt(rawData.height),
+                resizable: true,
+                useContentSize : true
+              )
+              win.setSkipTaskbar(true)
+              win.setMenuBarVisibility(false)
+              win.setTitle(rawData.title)
+              win.loadURL(rawData.url)
+              win.show()
+
+          catch error
+            console.log 'Notification message from websocket contains invali JSON string'

     catch err
         console.log err


update clearProjectState endpoint

update clearProjectState endpoint

--- services/web/app/coffee/Features/DocumentUpdater/DocumentUpdaterHandler.coffee
+++ services/web/app/coffee/Features/DocumentUpdater/DocumentUpdaterHandler.coffee
@@ -155,7 +155,7 @@

 	clearProjectState: (project_id, callback = (error) ->) ->
 		timer = new metrics.Timer("clear-project-state")
-		url = "#{settings.apis.documentupdater.url}/project/#{project_id}/clear"
+		url = "#{settings.apis.documentupdater.url}/project/#{project_id}/clearState"
 		logger.log project_id:project_id, "clearing project state from document updater"
 		request.post url, (error, res)->
 			timer.done()


comment

comment

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -252,7 +252,7 @@
   restoreCursorPositions: ->
     @cursorPositionManager.restore(strict: not @isWithOccurrence())
     @cursorPositionManager = null
-    @emitDidRestoreCursorPositions() # not called on early return [FIXME?]
+    @emitDidRestoreCursorPositions()

 # Select
 # When text-object is invoked from normal or viusal-mode, operation would be


add smart quote support

add smart quote support

--- lib/bracket-matcher.coffee
+++ lib/bracket-matcher.coffee
@@ -12,6 +12,8 @@
     '"': '"'
     "'": "'"
     '`': '`'
+    "“": "”"
+    '‘': '’'

   constructor: (editorView) ->
     {@editor} = editorView


German was special…once again...

German was special…once again...

--- chrome/src/gmailr.coffee
+++ chrome/src/gmailr.coffee
@@ -259,7 +259,7 @@
               "a[href$='#inbox'][title^='Posteingang']" # German
               "a[href$='#inbox'][title^='Postvak IN']"  # Dutch

-              "a[href$='#inbox']:not([title='Gmail'])"  # Generic fallback
+              "a[href$='#inbox'][target='_top']"  # Generic fallback
               ]

     getInboxLink: ->


this is basically done

this is basically done

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -1,4 +1,3 @@
-# TODO: buffering
 # TODO: autocomplete

 {Emitter} = require 'atom'


fix up/down keybindings

fix up/down keybindings

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -7,7 +7,7 @@
 module.exports =
 class Console
   @activate: ->
-    @evalCmd = atom.commands.add 'ink-console atom-text-editor',
+    @evalCmd = atom.commands.add 'ink-console atom-text-editor:not([mini])',
       'console:evaluate': ->
         ed = @getModel()
         ed.inkConsole.eval ed


daily

daily

--- lib/cli/init.coffee
+++ lib/cli/init.coffee
@@ -34,7 +34,10 @@
     "typescript": "lib/src/generatedComponents.ts",
     "declaration": "lib/ext/#{namespace}.d.ts"
   },
-  "alloc": 100,
+  "alloc": {
+    "entities": 128,
+    "components": 64
+  },
   "components": {
   },
   "systems": {


runtime: Ignore a warning

runtime: Ignore a warning

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -436,6 +436,9 @@
     if command in ['start', 'stop', 'getstatus']
         m = { protocol: 'network', command: command, payload: payload }
         sendMessage runtime, m
+    else if command in ['debug']
+        # does nothing relevant, response not expected
+        return
     else if command is "edges"
         # TODO: merge with those of exported outports
         runtime.edgesForInspection = payload.edges


:fire: debug code

:fire: debug code

--- lib/searcher.coffee
+++ lib/searcher.coffee
@@ -1,6 +1,3 @@
-{inspect} = require 'util'
-p = (args...) -> console.log inspect(args...)
-
 path = require 'path'
 _ = require 'underscore-plus'
 {Point, Range, BufferedProcess} = require 'atom'


temp workaround for invalid cert

temp workaround for invalid cert

--- lib/spawner.coffee
+++ lib/spawner.coffee
@@ -46,7 +46,8 @@
     request.on "success", (data) ->
       url = require("url").parse(data.rendezvous_url)
       rendezvous = tls.connect url.port, url.hostname, ->
-        if rendezvous.authorized
+        # work around invalid cert
+        if true || rendezvous.authorized
           console.log "valid socket"
           rendezvous.write url.pathname.substring(1) + "\n"
         else


Fix minor typo in settings.coffee

Fix minor typo in settings.coffee

Connects-To: #506
Signed-off-by: Tim Perry <5ee0edb9e2229c0838f1959779f1949031de0123@resin.io>

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -19,7 +19,7 @@
 getSettings = (deps, opts) ->
 	{ settings } = deps

-	expots = {}
+	exports = {}

 	###*
 	# @summary Get a single setting. **Only implemented in Node.js**


tests: Wait for subscription complete callback before sending

Could cause failures due to race

--- spec/01transport.coffee
+++ spec/01transport.coffee
@@ -150,8 +150,8 @@

           clients.receiver.subscribeToQueue sharedQueue, onReceive, (err) ->
             chai.expect(err).to.be.a 'null'
-          clients.sender.sendTo 'outqueue', sharedQueue, payload, (err) ->
-            chai.expect(err).to.be.a 'null'
+            clients.sender.sendTo 'outqueue', sharedQueue, payload, (err) ->
+              chai.expect(err).to.be.a 'null'

   describe 'inqueue==outqueue with binding', ->
@@ -174,8 +174,8 @@

             clients.receiver.subscribeToQueue sharedQueue, onReceive, (err) ->
               chai.expect(err).to.be.a 'null'
-            clients.sender.sendTo 'outqueue', sharedQueue, payload, (err) ->
-              chai.expect(err).to.be.a 'null'
+              clients.sender.sendTo 'outqueue', sharedQueue, payload, (err) ->
+                chai.expect(err).to.be.a 'null'

   describe 'outqueue bound to inqueue', ->
@@ -201,8 +201,8 @@

             clients.receiver.subscribeToQueue inQueue, onReceive, (err) ->
               chai.expect(err).to.be.a 'null'
-            clients.sender.sendTo 'outqueue', outQueue, payload, (err) ->
-              chai.expect(err).to.be.a 'null'
+              clients.sender.sendTo 'outqueue', outQueue, payload, (err) ->
+                chai.expect(err).to.be.a 'null'

   describe 'multiple outqueues bound to one inqueue', ->


Coffee style fix

Coffee style fix

--- django/bb_chat/static/bb_chat/app.coffee
+++ django/bb_chat/static/bb_chat/app.coffee
@@ -29,7 +29,7 @@
   template: _.template $('#conversation-list-view').html()

   initialize: ->
-    @collection = new Conversations()
+    @collection = new Conversations
     @listenTo @collection, 'update', @render
     @collection.fetch()
     return
@@ -90,7 +90,7 @@

   sendMessage: (event) =>
     event.preventDefault()
-    data = _.object(_.map($(event.target).serializeArray(), _.values))
+    data = _.object _.map $(event.target).serializeArray(), _.values
     message = new Message text: data.text
     message.url = "/bb/conversations/#{@id}/messages"
     message.save {},
@@ -107,7 +107,7 @@

   render: =>
     @$el.html @template()
-    @conversationListView = new ConversationListView()
+    @conversationListView = new ConversationListView
     @conversationListView.$el = @.$('.conversations')
     @conversationListView.render()
     this
@@ -139,14 +139,13 @@

   conversation: (id) ->
     chatView = new ChatView id: id
-    $('.main').html(chatView.$el)
     window.chatView = chatView
     return

 class App
   constructor: ->
-    @router = new Router()
-    @navigationView = new NavigationView()
+    @router = new Router
+    @navigationView = new NavigationView
     @navigationView.render()

 (exports ? this).App = App


conversation.get('messages') -> conversation.messages

--- django/bb_chat/static/bb_chat/app.coffee
+++ django/bb_chat/static/bb_chat/app.coffee
@@ -1,37 +1,30 @@
 class Message extends Backbone.Model
-
-class Messages extends Backbone.Collection
-  model: Message

 class Conversation extends Backbone.Model
   urlRoot: '/bb/conversations'

+  parse: (response, options) ->
+    if not @messages?
+      @messages = new Messages
+    @messages.add response.messages, merge: true
+    delete response.messages
+    return response
+
   getViewUrl: ->
     '/bb/c/' + @get('id') + '/'

-  parse: (response, options) ->
-    response.messages = new Messages response.messages
-    return response
+class Messages extends Backbone.Collection
+  model: Message

 class Conversations extends Backbone.Collection
   model: Conversation
   url: '/bb/conversations'

-class ConversationItemView extends Backbone.View
-  className: 'conversation'
-  template: _.template $('#conversation-view').html()
-
-  render: ->
-    @$el.html @template()
-    this
-
 class ConversationListView extends Backbone.View
   template: _.template $('#conversation-list-view').html()

   initialize: ->
-    @collection = new Conversations
     @listenTo @collection, 'update', @render
-    @collection.fetch()
     return

   render: =>
@@ -82,7 +75,7 @@

   render: =>
     @$el.html @template
-    @messageListView = new MessageListView collection: @model.get('messages')
+    @messageListView = new MessageListView collection: @model.messages
     @messageListView.$el = @.$('.messages')
     @messageListView.render()
     @messageListView.scrollToBottom()
@@ -93,8 +86,8 @@
     data = _.object _.map $(event.target).serializeArray(), _.values
     message = new Message text: data.text
     message.url = "/bb/conversations/#{@id}/messages"
-    message.save {},
-      beforeSend: (xhr) =>
+    message.save null,
+      beforeSend: (xhr) ->
         xhr.setRequestHeader 'X-CSRFToken', data.csrfmiddlewaretoken
       success: =>
         @$el.find('textarea') .val ''
@@ -108,8 +101,9 @@
   render: =>
     @$el.html @template()
     @conversationListView = new ConversationListView
+      collection: new Conversations
+    @conversationListView.collection.fetch()
     @conversationListView.$el = @.$('.conversations')
-    @conversationListView.render()
     this

 class Router extends Backbone.Router
@@ -135,7 +129,6 @@
     super callback, args, name

   home: ->
-    return

   conversation: (id) ->
     chatView = new ChatView id: id


Tests: Environments: Unindent code.

Tests: Environments: Unindent code.

--- tests/src/environments/environments.coffee
+++ tests/src/environments/environments.coffee
@@ -8,22 +8,22 @@

 openVmSettingsModal = (browser) ->

-    vmSelector = '.activity-sidebar a.running'
-
-    browser
-      .waitForElementVisible   vmSelector, 20000
-      .pause                   5000
-      .moveToElement           vmSelector + ' span', 125, 20
-      .click                   vmSelector + ' span'
-      .waitForElementVisible   modalSelector, 20000 # Assertion
+  vmSelector = '.activity-sidebar a.running'
+
+  browser
+    .waitForElementVisible   vmSelector, 20000
+    .pause                   5000
+    .moveToElement           vmSelector + ' span', 125, 20
+    .click                   vmSelector + ' span'
+    .waitForElementVisible   modalSelector, 20000 # Assertion

 clickMoreButtonInVMSettingsModal = (browser) ->

-    browser
-      .waitForElementVisible  '.settings form.with-fields .moreview', 20000
-      .click                  '.settings form.with-fields .moreview label.more'
-      .pause  200
+  browser
+    .waitForElementVisible  '.settings form.with-fields .moreview', 20000
+    .click                  '.settings form.with-fields .moreview label.more'
+    .pause  200

 clickAddVMButton = (browser) ->
@@ -39,35 +39,35 @@

 seeUpgradeModal = (browser) ->

-    clickAddVMButton(browser)
-    browser.waitForElementVisible '.computeplan-modal.free-plan .kdmodal-inner', 20000 # Assertion
-
-
-  addDomain = (browser) ->
-
-    user = helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
-
-    domainSelector    = '.more-form .domains .domains-a-hrefhttplearnkodingcomfaqvm-hostname-target-blank-span-classdomain-helpspan-a-span-classdomain-togglespan span.domain-toggle'
-    paragraph         = helpers.getFakeText()
-    createDomainName  = paragraph.split(' ')[0]
-    domainName        = createDomainName + '.' + user.username + '.dev.koding.io'
-
-    openVmSettingsModal(browser)
-
-    clickMoreButtonInVMSettingsModal(browser)
-
-    browser
-      .waitForElementVisible    '.more-form .domains', 20000
-      .waitForElementVisible    domainSelector, 20000
-      .click                    domainSelector
-      .waitForElementVisible    '.domains-view input.text', 20000
-      .setValue                 '.domains-view input.text', createDomainName + '\n'
-      .waitForElementVisible    '.domains-view .in-progress.kdloader', 10000
-      .waitForElementNotVisible '.domains-view .in-progress.kdloader', 20000
-      .assert.containsText      '.domains-view .listview-wrapper', domainName
-
-    return domainName
+  clickAddVMButton(browser)
+  browser.waitForElementVisible '.computeplan-modal.free-plan .kdmodal-inner', 20000 # Assertion
+
+
+addDomain = (browser) ->
+
+  user = helpers.beginTest(browser)
+  helpers.waitForVMRunning(browser)
+
+  domainSelector    = '.more-form .domains .domains-a-hrefhttplearnkodingcomfaqvm-hostname-target-blank-span-classdomain-helpspan-a-span-classdomain-togglespan span.domain-toggle'
+  paragraph         = helpers.getFakeText()
+  createDomainName  = paragraph.split(' ')[0]
+  domainName        = createDomainName + '.' + user.username + '.dev.koding.io'
+
+  openVmSettingsModal(browser)
+
+  clickMoreButtonInVMSettingsModal(browser)
+
+  browser
+    .waitForElementVisible    '.more-form .domains', 20000
+    .waitForElementVisible    domainSelector, 20000
+    .click                    domainSelector
+    .waitForElementVisible    '.domains-view input.text', 20000
+    .setValue                 '.domains-view input.text', createDomainName + '\n'
+    .waitForElementVisible    '.domains-view .in-progress.kdloader', 10000
+    .waitForElementNotVisible '.domains-view .in-progress.kdloader', 20000
+    .assert.containsText      '.domains-view .listview-wrapper', domainName
+
+  return domainName

 module.exports =


:new: Add test for findFile

:new: Add test for findFile

--- spec/helper-spec.coffee
+++ spec/helper-spec.coffee
@@ -1,8 +1,8 @@
+fs = require 'fs'
+helpers = require '../lib/helpers'
+testFile = __dirname + '/fixtures/test.txt'
+testContents = fs.readFileSync(testFile).toString()
 describe 'linter helpers', ->
-  helpers = require '../lib/helpers'
-  fs = require 'fs'
-  testFile = __dirname + '/fixtures/test.txt'
-  testContents = fs.readFileSync(testFile).toString()
   describe '::exec', ->
     it 'cries when no argument is passed', ->
       gotError = false
@@ -63,4 +63,6 @@
       try
         helpers.parse()
       catch erro then gotError = true
-      expect(gotError).toBe(true)+      expect(gotError).toBe(true)
+    it 'works', ->
+      expect(helpers.findFile(__dirname, 'package.json')).toBe(fs.realpathSync(__dirname + '/../package.json'))


:lipstick:

:lipstick:

--- spec/keymap-spec.coffee
+++ spec/keymap-spec.coffee
@@ -185,7 +185,7 @@
           expect(events).toEqual ['enter-visual-mode']
           expect(clearTimeout).toHaveBeenCalled()

-      describe "when there are no subsequent keystrokes for ::partialMatchTimeout", ->
+      describe "when ::partialMatchTimeout milliseconds elapses before there are additional keystrokes", ->
         it "disables the bindings with the longest keystroke sequences and replays the queued keystrokes", ->
           keymap.handleKeyboardEvent(keydownEvent('v', target: editor))
           expect(events).toEqual []


:fire: Remove duplicate key

:fire: Remove duplicate key

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -89,7 +89,7 @@
   atom.project.setPaths([projectPath])
   atom.workspace = new Workspace({
     config: atom.config, project: atom.project, packageManager: atom.packages,
-    grammarRegistry: atom.grammars, notificationManager: atom.notifications,
+    notificationManager: atom.notifications,
     setRepresentedFilename: jasmine.createSpy('setRepresentedFilename'),
     setDocumentEdited: atom.setDocumentEdited.bind(atom), atomVersion: atom.getVersion(),
     clipboard: atom.clipboard, viewRegistry: atom.views, grammarRegistry: atom.grammars,


 Merge branch 'master.custom-partials' into 'master'

Master.Custom Partials

--- client/Intro/home.coffee
+++ client/Intro/home.coffee
@@ -1,6 +1,6 @@
 class HomePage extends JView

-  iframe = """"""
+  iframe = """"""

   partialData = KD.customPartial?.partial or {}


Fixed: warning message in  was shown even if OK cases

--- client/app/router.coffee
+++ client/app/router.coffee
@@ -164,7 +164,7 @@

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


A twitter client with a shortcut

A twitter client with a shortcut

--- lib/twitter.coffee
+++ lib/twitter.coffee
@@ -8,4 +8,19 @@

 # I give you, a pre-configured twitter client,
 # So you don't have to.
-module.exports = client+module.exports =
+  client: client
+
+  # A helper for the general case, posts `body`
+  # as a tweet, and calls you back with it, as well
+  # as a pre-built URL
+  tweet: (body, cb=(err, tweet, url)) =>
+    params = status: body
+    client.post 'statuses/update', params, (error, tweet, response) ->
+      return cb(error)  if error
+
+      # LUCKY US
+      myself = tweet.user.screen_name
+      tid = tweet.id_str
+      url = "https://twitter.com/#{myself}/status/#{tid}"
+      return cb(tweet, url)


Fix bug: invoke isPending only if exists

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -6,7 +6,7 @@
   initialize: (@item) ->
     if typeof @item.getPath is 'function'
       @path = @item.getPath()
-      @isPreviewTab = @item.isPending()
+      @isPreviewTab = @item.isPending?()

     @classList.add('tab', 'sortable')


adds export of Pool

adds export of Pool

--- lib/DbManager.coffee
+++ lib/DbManager.coffee
@@ -7,6 +7,7 @@

 module.exports = class DbManager extends EventEmitter
   @Pool: Pool
+  Pool: Pool
   conn: null
   models: null
   reconnectDelay: 100


Basic Makefile support

Basic Makefile support

Runs the makefile or the selected bash command.

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -211,6 +211,14 @@
       command: "bash"
       args: (context) -> [context.filepath]

+  Makefile:
+    "Selection Based":
+      command: "bash"
+      args: (context) -> ['-c', context.getCode()]
+    "File Based":
+      command: "make"
+      args: (context) -> ['-f', context.filepath]
+
   Scala:
     "Selection Based":
       command: "scala"


Little tests refactor

Little tests refactor

--- test/test.coffee
+++ test/test.coffee
@@ -7,58 +7,60 @@
   describe 'without factory', ->
     it 'basic', ->
       err = Whoops()
-      isType.error(err).should.be.equal true
+      isType.error(err).should.be.true()
       err.name.should.be.equal 'Error'
       (!!err.code).should.be.equal false
       (!!err.description).should.be.equal false
       (!!err.message).should.be.equal false

-  describe 'object factory', ->
-    it 'providing message', ->
-      err = Whoops
-        message: 'damn'
+  describe 'factory', ->

-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'Error'
-      err.message.should.be.equal 'damn'
+    describe 'object', ->
+      it 'providing message', ->
+        err = Whoops
+          message: 'damn'

-    it 'providing mesage and name', ->
-      err = Whoops
-        name: 'DAMN'
-        message: 'something is wrong'
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'Error'
+        err.message.should.be.equal 'damn'

-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'DAMN'
-      err.message.should.be.equal 'something is wrong'
+      it 'providing mesage and name', ->
+        err = Whoops
+          name: 'DAMN'
+          message: 'something is wrong'

-    it 'providing mesage, name and more fields',  ->
-      err = Whoops
-        name: 'DAMN'
-        message: 'something is wrong'
-        path: process.cwd()
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'DAMN'
+        err.message.should.be.equal 'something is wrong'

-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'DAMN'
-      err.message.should.be.equal 'something is wrong'
-      err.path.should.be.equal process.cwd()
+      it 'providing mesage, name and more fields',  ->
+        err = Whoops
+          name: 'DAMN'
+          message: 'something is wrong'
+          path: process.cwd()
+
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'DAMN'
+        err.message.should.be.equal 'something is wrong'
+        err.path.should.be.equal process.cwd()

-  describe 'string factory', ->
-    it 'providing message', ->
-      err = Whoops 'damn'
-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'Error'
-      err.message.should.be.equal 'damn'
+    describe 'string', ->
+      it 'providing message', ->
+        err = Whoops 'damn'
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'Error'
+        err.message.should.be.equal 'damn'

-    it "providing mesage and name", ->
-      err = Whoops 'DAMN', 'something is wrong'
-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'DAMN'
-      err.message.should.be.equal 'something is wrong'
+      it "providing mesage and name", ->
+        err = Whoops 'DAMN', 'something is wrong'
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'DAMN'
+        err.message.should.be.equal 'something is wrong'

-    it "providing mesage, name and code", ->
-      err = Whoops 'DAMN', 'ENOCODE', 'something is wrong'
-      isType.error(err).should.be.equal true
-      err.name.should.be.equal 'DAMN'
-      err.code.should.be.equal 'ENOCODE'
-      err.message.should.be.equal 'ENOCODE, something is wrong'
+      it "providing mesage, name and code", ->
+        err = Whoops 'DAMN', 'ENOCODE', 'something is wrong'
+        isType.error(err).should.be.true()
+        err.name.should.be.equal 'DAMN'
+        err.code.should.be.equal 'ENOCODE'
+        err.message.should.be.equal 'ENOCODE, something is wrong'


Add test for auto-reversing args

Add test for auto-reversing args

For backward compatibility to original API

--- test/test.coffee
+++ test/test.coffee
@@ -30,6 +30,11 @@
 	it 'should return empty array when there are no deps', (done) ->
 		progeny() 'foo.scss', '$a: 5px; .test {\n  border-radius: $a; }\n', (err, deps) ->
 			assert.deepEqual deps, []
+			do done
+
+	it 'should auto-correct reversed args', (done) ->
+		progeny() '@require bar\na=5px\n.test\n\tborder-radius a', 'foo.styl', (err, deps) ->
+			assert.deepEqual deps, ['bar.styl']
 			do done

 describe 'progeny.Sync', ->


adapted test script to recent config property changes

--- test/test.coffee
+++ test/test.coffee
@@ -12,9 +12,9 @@
 						showMillis: true
 					log = new logger config

-				"the value of the logger config for showMillis is true and stringifyJSON is still true": (topic) ->
+				"the value of the logger config for showMillis is true and showTimestamp is still true": (topic) ->
 					assert.equal topic.config.showMillis,true
-					assert.equal topic.config.stringifyJSON,true
+					assert.equal topic.config.showTimestamp,true

 			"with a custom config showMillis = false":
 				topic: () ->
@@ -22,9 +22,9 @@
 						showMillis: false
 					log = new logger config

-				"the value of the logger config for showMillis is false and stringifyJSON is still true": (topic) ->
+				"the value of the logger config for showMillis is false and showTimestamp is still true": (topic) ->
 					assert.equal topic.config.showMillis,false
-					assert.equal topic.config.stringifyJSON,true
+					assert.equal topic.config.showTimestamp,true

 		"when padding a one-digit number with zeros to 2 digits":
 			topic: () ->


change id name from hint to question

change id name from hint to question

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -1,5 +1,5 @@
 $ ->
-  $("#hint").hide()
+  $("#question").hide()
   words = $.getJSON("spellings.json")
   $.when(words).done ((d)->
     d['words']
@@ -11,4 +11,4 @@
   )

   startUp = (data) ->
-    $("#hint").show()
+    $("#question").show()


Check group before reparenting

Check group before reparenting

--- lib/messages.coffee
+++ lib/messages.coffee
@@ -778,6 +778,9 @@
   else
     group = position ? cmsg.group
     position = null  ## henceforth, position should be an integer or null
+    unless findGroup group
+      throw new Meteor.Error 'messageParent.badGroup',
+        "Attempt to reparent #{child} into unknown group #{group}"
     root = null

   #unless canEdit(child) and canPost group, parent


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/text.coffee
+++ test/text.coffee
@@ -25,7 +25,7 @@

   equals text.I.alpha, 1

-  text.update(0.25)
+  text.update(1)
   text.trigger "afterUpdate", 1

   equals text.I.alpha, 0.5


Fix the check for random Subject.group

Fix the check for random Subject.group

--- overrides.coffee
+++ overrides.coffee
@@ -37,7 +37,7 @@

 ClassifyPage::onNoMoreSubjects = ()->
   # fall back from /groups{group_id}/subjects to /groups/subjects
-  if @Subject.group is not 'random'
+  if @Subject.group != 'random'
     @Subject.group = 'random'
     localStorage.removeItem 'active-group'
     @Subject.next()


:fire: unused

:fire: unused

--- lib/operation-stack.coffee
+++ lib/operation-stack.coffee
@@ -7,9 +7,6 @@
 {CurrentSelection, Select, MoveToRelativeLine} = {}
 {OperationStackError, OperatorError, OperationAbortedError} = require './errors'
 swrap = require './selection-wrapper'
-
-{debug} = require './utils'
-

 # opration life in operationStack
 # 1. run
@@ -53,9 +50,6 @@
     swrap(@editor.getLastSelection()).hasProperties()

   run: (klass, properties={}) ->
-    # @reportAliveMakerLength('run')
-    if settings.get('debug')
-      debug 'run-start:', @hasSelectionProperty()
     try
       switch type = typeof(klass)
         when 'string', 'function'
@@ -109,7 +103,6 @@
       top = @peekTop()

       if top.isComplete()
-        debug "will-execute:", top.toString()
         @execute(@stack.pop())
       else
         if @vimState.isMode('normal') and top.isOperator()
@@ -164,10 +157,6 @@
       # [FIXME] SCATTERED_CURSOR_ADJUSTMENT
       moveCursorLeft(cursor, {preserveGoalColumn: true})

-  reportAliveMakerLength: (subject) ->
-    length = @vimState.markerLayer.getMarkers().length
-    console.log "#{subject}:", length
-
   finish: (operation=null) ->
     @record(operation) if operation?.isRecordable()
     @vimState.emitter.emit('did-finish-operation')
@@ -179,7 +168,6 @@
       @vimState.modeManager.updateNarrowedState()
     @vimState.updateCursorsVisibility()
     @vimState.reset()
-    # @reportAliveMakerLength('fin')

   peekTop: ->
     _.last(@stack)


Set requirejs log-level to warning

Set requirejs log-level to warning

--- bokehjs/Gruntfile.coffee
+++ bokehjs/Gruntfile.coffee
@@ -96,6 +96,7 @@

     requirejs:
       options:
+        logLevel: 2
         baseUrl: 'build/js'
         name: 'vendor/almond/almond'
         paths:


Rollback to 6 last operations

Rollback to 6 last operations

--- app/src/controllers/wallet/accounts/wallet_accounts_show_view_controller.coffee
+++ app/src/controllers/wallet/accounts/wallet_accounts_show_view_controller.coffee
@@ -35,7 +35,7 @@
   _updateOperations: ->
     operations = @getAccount().get 'operations'
     @view.emptyContainer.hide() if operations.length > 0
-    render 'wallet/operations/operations_table', {operations: operations.slice(0, 7)}, (html) =>
+    render 'wallet/operations/operations_table', {operations: operations.slice(0, 6)}, (html) =>
       @view.operationsList.html html

   getAccount: () ->


Improve InsertAtStartOfSelection you don't need enter vB only for insert at start of selection.

This allow cmd-d, cmd-d… then `I` operation work by mapping  `I` in
visual mode.

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -1127,6 +1127,9 @@
       @getBlockwiseSelections().forEach (bs) =>
         bs.removeEmptySelections()
         bs.setPositionForSelections(@which)
+    else
+      for selection in @editor.getSelections()
+        swrap(selection).setBufferPositionTo('start')
     super

 class InsertAtEndOfSelection extends InsertAtStartOfSelection


Replace dash with async.parallel

Replace dash with async.parallel

--- lib/cacheable.coffee
+++ lib/cacheable.coffee
@@ -1,4 +1,5 @@
-sinkrow = require 'sinkrow'
+async = require 'async'
+
 ModelLoader = require './modelloader'

@@ -54,12 +55,12 @@

   models = []

-  queue = batch.map (single, i) =>=>
+  queue = batch.map (single, i) => (done) =>
     {name, type, constructorName, id} = single
     handleSingle.call this, type or name or constructorName, id, (err, model) ->
       if err then callback err
       else
         models[i] = model
-        queue.fin()
-  sinkrow.dash queue, -> callback null, models
-  return
+        done()
+
+  async.parallel queue, -> callback null, models


Fix board name on sketch editor

Fix board name on sketch editor

--- src/editor/sketcheditor.coffee
+++ src/editor/sketcheditor.coffee
@@ -211,12 +211,8 @@
         .find("thead").remove().end()
         .find("tbody")
       tr("Name", @_sketch?.friendlyName)
-      tr("Board", @_board?.friendlyName or notConf)
-      switch @_sketch?.dirFs?.fsType
-        when AsyncFs.TEMPORARY
-          tr("Stored_location", I18n.getMessage("Draft"))
-        when AsyncFs.LOCAL
-          tr("Stored_location", I18n.getMessage("Storage_in_this_PC"))
+      tr("Board", @_sketch.board?.friendlyName or notConf)
+      tr("Stored_location", I18n.getMessage("fsType_#{@_sketch?.dirFs?.fsType}"))
       body = $("#template-panel").children().clone().appendTo(div)
         .find(".panel-heading").text(I18n.getMessage("Startup_file")).end()
         .find(".panel-body")


autocomplete with 2 characters

autocomplete with 2 characters

--- atom/config.cson
+++ atom/config.cson
@@ -1,4 +1,6 @@
 "*":
+  "autocomplete-plus":
+    minimumWordLength: 2
   core:
     audioBeep: false
     disabledPackages: [


Reworded the io title a bit.

Reworded the io title a bit.

--- client/io.coffee
+++ client/io.coffee
@@ -1,5 +1,5 @@
 #
-# # Socket IO
+# # Socket.IO Client
 #
 # The client side Socket IO code.
 #


Disable expand-region (broken on Atom v1.37.0)

--- atom/config.cson
+++ atom/config.cson
@@ -46,6 +46,7 @@
       "welcome"
       "whitespace"
       "teletype"
+      "expand-region"
     ]
     followSymlinks: false
     ignoredNames: [


Add configuration for Break package

Add configuration for Break package

--- atom/config.cson
+++ atom/config.cson
@@ -91,3 +91,9 @@
       'column': 72
     }
   ]
+'atom-color-highlight':
+  'hideMarkersInComments': true
+'break':
+  'microBreakIntervalInSeconds': 900
+  'microBreakLengthInSeconds': 30
+  'macroBreakIntervalInMicroAmount': 4


plugin update

plugin update

--- atom/config.cson
+++ atom/config.cson
@@ -24,7 +24,9 @@
   minimap:
     plugins:
       "find-and-replace": true
+      "find-and-replaceDecorationsZIndex": 0
       "git-diff": true
+      "git-diffDecorationsZIndex": 0
   "one-dark-ui": {}
   welcome:
     showOnStartup: false


Ignore Python lint

Ignore Python lint

--- atom/config.cson
+++ atom/config.cson
@@ -37,6 +37,10 @@
     general:
       _analyticsUserId: "b0b8fef0-e9f3-4ad9-b6b1-7af19d95e9f9"
   linter: {}
+  "linter-flake8":
+    ignoreErrorCodes: [
+      "H238"
+    ]
   "linter-ui-default": {}
   "linter-write-good":
     severityLevel: "Warning"


Latest Atom configuration

Latest Atom configuration

--- atom/config.cson
+++ atom/config.cson
@@ -60,7 +60,7 @@
       "one-light-syntax"
     ]
   editor:
-    fontFamily: "Source Code Pro"
+    fontFamily: "Anonymous Pro"
     fontSize: 16
     invisibles:
       cr: "↩"
@@ -84,6 +84,7 @@
   "highlight-selected":
     showInStatusBar: false
   "markdown-preview":
+    openPreviewInSplitPane: false
     useGitHubStyle: true
   "markdown-table-formatter":
     formatOnSave: false
@@ -113,8 +114,6 @@
     changeSoftTabsMode: true
     onSave: "untabify"
   "tree-view":
-    autoReveal: true
-    focusOnReveal: false
     hideIgnoredNames: true
     hideVcsIgnoredFiles: true
     squashDirectoryNames: true
@@ -125,23 +124,14 @@
     softWrap: true
   "wrap-guide":
     enabled: false
-".basic.html.text":
-  editor:
-    preferredLineLength: 100
 ".c.source":
   editor:
-    preferredLineLength: 100
     tabLength: 4
-".console.python.text":
-  editor:
-    preferredLineLength: 100
 ".cpp.source":
   editor:
-    preferredLineLength: 100
     tabLength: 4
 ".gfm.source":
   editor:
-    preferredLineLength: 100
     showInvisibles: false
     softWrap: true
     tabLength: 4
@@ -153,9 +143,6 @@
 ".haml.text":
   "wrap-guide":
     enabled: false
-".html.php.text":
-  editor:
-    preferredLineLength: 100
 ".java.source":
   editor:
     tabLength: 4
@@ -164,15 +151,7 @@
     enabled: false
 ".python.regexp.source":
   editor:
-    preferredLineLength: 100
     tabLength: 4
 ".python.source":
   editor:
-    preferredLineLength: 100
     tabLength: 4
-".python.text.traceback":
-  editor:
-    preferredLineLength: 100
-".source.yaml":
-  editor:
-    preferredLineLength: 100


Tweak init.coffee

Tweak init.coffee

--- atom/init.coffee
+++ atom/init.coffee
@@ -20,7 +20,7 @@
 atom.commands.add 'atom-workspace', 'dot-atom:toggle-theme', ->
   activeThemes = atom.themes.getActiveNames()

-  if activeThemes[0].indexOf("dark") is -1
+  if activeThemes[0].indexOf("light") > 0
     atom.themes.setEnabledThemes(["one-dark-ui", "one-dark-syntax"])
   else
     atom.themes.setEnabledThemes(["one-light-ui", "one-light-syntax"])


Fix for dashboard/panel/redundancy

Fix for dashboard/panel/redundancy

--- admin/static/coffee/dashboard.coffee
+++ admin/static/coffee/dashboard.coffee
@@ -27,12 +27,15 @@
                         .concatMap(identity)
                         .filter({role: "director", state: "ready"})
                         .count()
-                    num_replicas: table_config('shards').concatMap(identity)("replicas").count()
+                    num_replicas: table_config('shards').concatMap(identity)("replicas").concatMap(identity).count()
                     num_available_replicas: table_status('shards')
                         .concatMap(identity)
                         .concatMap(identity)
-                        .filter({role: "replica", state: "ready"})
-                        .count()
+                        .filter( (assignment) ->
+                            assignment("state").eq("ready").and(
+                                assignment("role").eq("replica").or(assignment("role").eq("director"))
+                            )
+                        ).count()
                     tables_with_directors_not_ready: table_status.merge( (table) ->
                         shards: table("shards").indexesOf( () -> true ).map( (position) ->
                             table("shards").nth(position).merge
@@ -75,9 +78,11 @@
                 num_non_available_tables: r.row("tables_with_directors_not_ready").count()

             driver.run query, (error, result) =>
+                ###
                 console.log '----- err, result ------'
                 console.log error
                 console.log result
+                ###
                 if error?
                     #TODO
                     console.log error
@@ -263,14 +268,18 @@
             @$('.popup_container').hide()

         render: =>
-            @$el.html @template
+            data =
                 status_is_ok: @model.get('num_available_replicas') is @model.get('num_replicas')
-                num_replicas: @model.get 'num_directors'
-                num_available_replicas: @model.get 'num_available_directors'
-                num_non_available_replicas: @model.get('num_directors')-@model.get('num_available_directors')
+                num_replicas: @model.get 'num_replicas'
+                num_available_replicas: @model.get 'num_available_replicas'
+                num_non_available_replicas: @model.get('num_replicas')-@model.get('num_available_replicas')
                 num_non_available_tables: @model.get 'num_non_available_tables'
                 num_tables: @model.get 'num_tables'
-                tables_with_replicas_not_ready: @model.get('tables_with_directors_not_ready')
+                tables_with_replicas_not_ready: @model.get('tables_with_replicas_not_ready')
+
+            console.log JSON.stringify data, null, 2
+
+            @$el.html @template data

             if @display_popup is true and @model.get('num_available_directors') isnt @model.get('num_directors')
                 # We re-display the pop up only if there are still issues


Remove the old release of life.

Remove the old release of life.

--- coffee/auto-updater.iced
+++ coffee/auto-updater.iced
@@ -63,7 +63,14 @@
     if err?
       @emit "download-failed", err
       return
+
     wrench.chmodSyncRecursive appPath, '0755'
+
+    await @_removeOldReleaseMac appPath, @options.osxAppName, defer err
+    if err?
+      @emit "download-failed", err
+      return
+
     @emit "update-installed"

   _downloadUpdate: (targetPath, remoteUrl, progressCb, doneCb) ->
@@ -89,6 +96,11 @@
   _hideOriginalMac: (appPath, appName, cb) ->
     filename = appName + '.app'
     fs.rename appPath + '/' + filename, appPath + '/.' + filename, cb
+
+  _removeOldReleaseMac: (appPath, appName, cb) ->
+    filename = appName + '.app'
+    wrench.rmdirSyncRecursive appPath + '/.' + filename
+    cb()

   _copyUpdateMac: (appName, from, to, callback) ->
     wrench.copyDirRecursive from + '/' + appName + '.app',


Updated description of issue

Updated description of issue

--- lib/code-peek.coffee
+++ lib/code-peek.coffee
@@ -66,9 +66,9 @@
     atom.workspace.scan(regExp, {paths: ["*.#{fileType}"]}, (matchingFile) =>
       initialLine = 0

-      # HACK I literally have no idea why this is happening. If the file has
-      # unsaved changes, we get a range object. If it does not, we get an array
-      # for the range.
+      # HACK If the file has unsaved changes, we get a range object.
+      # If it does not, we get an array for the range. Bug in Atom itself,
+      # logged here: https://github.com/atom/atom/issues/10900
       if matchingFile.matches[0].range? and
         matchingFile.matches[0].range.start? and
         matchingFile.matches[0].range.start.row?


bug fix

bug fix

--- commands/use/food.coffee
+++ commands/use/food.coffee
@@ -45,7 +45,7 @@
     (cb) ->
       remove_item user, item, 1, cb
     (cb) ->
-      alter_target_hpmax_and_hunger character, hpmax_gain, hunger_gain, cb
+      alter_target_hpmax_and_hunger target, hpmax_gain, hunger_gain, cb
     (cb) ->
       send_message 'feed', user, user,
         item: item.id


Change to dispose the listener

Change to dispose the listener

--- lib/transient-emacs.coffee
+++ lib/transient-emacs.coffee
@@ -113,9 +113,10 @@
         findAndReplace?.mainModule.findView?.findEditor?.element?.focus()
       else
         findAndReplace?.mainModule.findOptions?.set 'useRegex':useRegex
-        atom.packages.onDidActivatePackage (pkg)->
+        tempListener = atom.packages.onDidActivatePackage (pkg)->
           if pkg.name == "find-and-replace"
             pkg.mainModule.findOptions?.set 'useRegex':useRegex
+            tempListener.dispose()
         atom.commands.dispatch(e.target, "find-and-replace:show")

   activateIsearch: (forward)->


Progress starts at 0, but bar should still be shown

--- src/components/attachment-chooser.cjsx
+++ src/components/attachment-chooser.cjsx
@@ -26,7 +26,7 @@
     @setState(progress: 0)

   renderUploadStatus: ->
-    return unless @state.progress
+    return unless @state.progress?
     <BS.ProgressBar now={@state.progress} />

   onImageChange: (ev) ->


Simpler kicker component

Simpler kicker component

--- components/kicker.coffee
+++ components/kicker.coffee
@@ -1,19 +1,9 @@
-# The count component receives input on a single input port, and sends the
-# number of data items received to the output port when the input socket
-# disconnects
-
-data = null
-
-handleOutput = (socket) ->
-    socket.on "initialize", ->
+# This component generates a single packet and sends in to the output port.
+# Mostly usable for debugging, but can also be useful for starting up
+# networks.
+exports.getOutputs = ->
+    output: (socket) ->
         socket.on "connect", ->
-            socket.send data
+            socket.send null
             socket.disconnect()
         socket.connect()
-
-exports.initialize = (config) ->
-    if config.data
-        data = config.data
-
-exports.getOutputs = ->
-    output: handleOutput


tweak numeral input js

tweak numeral input js

--- app/assets/javascripts/folio/console/simple_form_inputs/_string_input.coffee
+++ app/assets/javascripts/folio/console/simple_form_inputs/_string_input.coffee
@@ -67,7 +67,7 @@
       .removeAttr('name')
       .prop('type', 'string')
     $this.after """<input type="hidden" name="#{name}" value="#{@value}">"""
-    cleave = new Cleave(this, cleaveOpts)
+    $this.data('cleave', new Cleave(this, cleaveOpts))

 window.folioConsoleUnbindNumeralInput = ($elements) ->
   $elements.each ->
@@ -76,15 +76,15 @@
     $this.prop('type', $this.data('type')) if $this.data('type')
     $this.prop('name', $this.data('name')) if $this.data('name')

+    cleave = $this.data('cleave')
+    if cleave
+      cleave.destroy()
+      $this.data('cleave', null)
+
     $hidden = $this.next('input[type="hidden"]')
     if $hidden.length
       $this.val($hidden.val())
       $hidden.remove()
-
-    cleave = $this.data('cleave')
-    if cleave
-      cleave.destroy()
-      $this.data('cleave', null)

 window.folioConsoleBindNumeralInputIn = ($wrap) ->
   window.folioConsoleBindNumeralInput $wrap.find(NUMERAL_SELECTOR)


Workspace: Disabled sorting and closeAppWhenAllTabsClosed for tabbed editor.

--- client/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
+++ client/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
@@ -41,8 +41,10 @@
       addPlusHandle     : no

     @tabView = new ApplicationTabView
-      delegate           : @
-      tabHandleContainer : @tabHandleContainer
+      delegate                  : @
+      sortable                  : no
+      closeAppWhenAllTabsClosed : no
+      tabHandleContainer        : @tabHandleContainer

     @tabView.on "PaneAdded", (pane) =>
       {tabHandle} = pane


Workspace: Recreate iframe again to clear it's content for not previewable pages.

--- client/landing/CollaborativeWorkspace/panes/collaborativepreviewpane.coffee
+++ client/landing/CollaborativeWorkspace/panes/collaborativepreviewpane.coffee
@@ -25,13 +25,20 @@

   openPathFromSnapshot: (snapshot) ->
     value = snapshot.val()
-    return unless value
-    @previewer.openPath value.url  if value.url
-    @previewPane.secureInfo?.destroy()
+
+    if value?.url
+      @recreateIframe()
+      @previewer.openPath value.url
+      @previewPane.secureInfo?.destroy()

   openUrl: (url) ->
+    @recreateIframe()
     @previewer.openPath url
     @saveUrl yes
+
+  recreateIframe: ->
+    @previewer.iframe.destroy()
+    @previewer.createIframe()

   saveUrl: (force) ->
     {path} = @previewer


change menu order

change menu order

--- menus/atomizr.cson
+++ menus/atomizr.cson
@@ -21,26 +21,17 @@
           'command': 'atomizr:convert-atom-to-sublime-text'
         },
         {
-          'label': 'Toggle Atom format (CSON↔JSON)'
-          'command': 'atomizr:toggle-atom-format'
+          'label': 'Convert Sublime Text to Atom'
+          'command': 'atomizr:convert-sublime-text-to-atom'
         },
         { 'type': 'separator' },
         {
-          'label': 'Convert Sublime Text to Atom'
-          'command': 'atomizr:convert-sublime-text-to-atom'
+          'label': 'Toggle Atom format (CSON↔JSON)'
+          'command': 'atomizr:toggle-atom-format'
         },
         {
           'label': 'Toggle Sublime Text format (XML↔JSON)'
           'command': 'atomizr:toggle-sublime-sublformat'
-        },
-        { 'type': 'separator' },
-        {
-          'label': 'Convert Sublime Text to Atom (completions)'
-          'command': 'atomizr:convert-sublime-text-completions-to-atom'
-        },
-        {
-          'label': 'Convert Sublime Text to Atom (snippet)'
-          'command': 'atomizr:convert-sublime-text-snippet-to-atom'
         }
       ]
     ]


Use browser independent new tab page URL (about:newtab)

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -171,7 +171,7 @@
       # az: http://www.amazon.com/s/?field-keywords=%s Amazon
       # qw: https://www.qwant.com/?q=%s Qwant
       """
-    newTabUrl: "chrome://newtab"
+    newTabUrl: "about:newtab"
     grabBackFocus: false
     regexFindMode: false
     waitForEnterForFilteredHints: false # Note: this defaults to true for new users; see below.


Avoid using ES6 Array.from

Avoid using ES6 Array.from

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -183,7 +183,7 @@

   getScopeChain: (object) ->
     scopesArray = object?.getScopesArray?()
-    scopesArray ?= Array.from(object)
+    scopesArray ?= object
     scopesArray
       .map (scope) ->
         scope = ".#{scope}" unless scope[0] is '.'


Updating example config file.

Updating example config file.

--- examples/browser-sample/toaster.coffee
+++ examples/browser-sample/toaster.coffee
@@ -9,6 +9,15 @@
     'src'
   ]

+  # main module
+  main: 'app/app'
+
+  # base url to reach your release folder through htto
+  base_url: 'js'
+
+  # release folder
+  release_dir: 'www/js'
+
   # excluded items (default=[])
   exclude: []

@@ -16,13 +25,7 @@
   bare: true

   # minifies release files (default=true)
-  minify: true
-
-  # release folder
-  release_dir: 'www/js'
-
-  # base url to reach your release folder through htto
-  base_url: 'js'
+  minify: false

   # infos for simple static server (with -s option)
   webroot: 'www'
@@ -35,33 +38,11 @@
     # vendors to consider (can be local or remote)
     vendors:
       'jquery': 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'
-      '_': 'src/vendors/_.js'
+      '_': 'vendors/_.js'

-    # TODO: draft
-    #
     # each layer wil hold all the definitions needed (all levels) in order to
-    # work. if layers share dpendencies, they will not repeated from the first
-    # to the last.
-    #
-    # main:
-    #  ~> will become www/js/main.s
-    #
-    # progressive:
-    #   ~> will become www/js/progressive.s
-    #   ~> wont duplicate modules already included in `main`.
-    #
-    # triphop:
-    #   ~> will become www/js/triphop.s
-    #   ~> wont duplicate modules already included in `main` and `progressive`.
-    #
-    # important to say that if `progressive` layers have some shared dependency
-    # with the `main` layer, it'll not be included twice across layers.
-    #
-    # so try to mount your layers orderly as your app as usued. anyhow, nothing
-    # will demage your application, because
-    #
-    # anyway, if you load some progressive/* module and
+    # work. if layers share dpendencies, they will not repeat acros layers.
     layers:
       'main': ['app/app']
-      'progressive': ['genres/progressive/']
-      'triphop': ['genres/triphop/*']+      'progressive': ['app/genres/progressive']
+      'triphop': ['app/genres/triphop']


Improve examples test case

Improve examples test case

--- src/test/examples.coffee
+++ src/test/examples.coffee
@@ -1,24 +1,29 @@
 path = require('path')
 lib = require('../lib')

-module.exports = (base, spec, name) ->
-  if not name?
-    name = spec ? 'examples'
-    spec ?= path.join('../', name, '**/*.{js,coffee}')
+module.exports = util.fnOption(
+  {
+    spec: undefined
+    name: 'examples'
+    base: undefined
+  }
+  (options) ->
+    options.base ?= util.findPackageRoot()
+    options.spec ?= path.join(options.base, options.name, '**/*.{js,coffee}')

-  fileNames = lib.util.glob.sync(path.join(base, spec), {})
+    fileNames = lib.util.glob.sync(options.spec, {})

-  isRedundant = (fileName) ->
-    ext = path.extname(fileName)
-    coffeeName = fileName.slice(fileName.length = ext.length) + '.coffee'
-    if ext == '.js' and fileNames.indexOf(coffeeName) != -1
-      return true
-    return false
+    isRedundant = (fileName) ->
+      ext = path.extname(fileName)
+      coffeeName = fileName.slice(0, fileName.length - ext.length) + '.coffee'
+      if ext == '.js' and fileNames.indexOf(coffeeName) != -1
+        return true
+      return false

-  suite(name, () ->
-    for fileName in fileNames when not isRedundant(fileName)
-      test(path.relative(base, fileName), () ->
-        require(fileName)
-      )
-  )
-
+    suite(name, () ->
+      for fileName in fileNames when not isRedundant(fileName)
+        test(path.relative(options.base, fileName), () ->
+          require(fileName)
+        )
+    )
+)


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -1,13 +1,11 @@
 class Dashing.FullpieAgent extends Dashing.Widget
   #@accessor 'value'
   @accessor 'data'
-
   onData: (data) ->
     $(@node).fadeOut().fadeIn()
     #@buildPieStructure()
     #@render(data.data)
     @update(data.data)
-
   buildPieStructure: ->
     @width = 300
     @height = 300
@@ -17,9 +15,7 @@
     @arc = d3.svg.arc().innerRadius(@radius - 100).outerRadius(@radius - 50)
     @svg = d3.select(@node).append('svg').attr('width', @width).attr('height', @height).append('g').attr('transform', 'translate(' + @width / 2 + ',' + @height / 2 + ')')
     return
-
   oldPieData: ''
-
   pieTween: (d, i) ->
     `var i`
     that = this
@@ -39,7 +35,6 @@
     #else
     #  s0 = 0
     #  e0 = 0
-
     # TS
     s0 = 0
     e0 = 0
@@ -53,7 +48,6 @@
     (t) ->
       b = i(t)
       return @arc b
-
   removePieTween: (d, i) ->
     `var i`
     that = this
@@ -68,14 +62,11 @@
     (t) ->
       b = i(t)
       @arc b
-
   update: (dataSet) ->
-
     if !dataSet
         dataSet = @get("data")
     if !dataSet
         return
-
     width = 750
     height = 450
     radius = Math.min(width, height) / 2
@@ -85,7 +76,6 @@
     pie = d3.layout.pie()#.sort(null)
     arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)#.innerRadius(radius - 100).outerRadius(radius - 50)
     svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
-
     console.log 'update pie', dataSet
     that = this
     piedata = pie(dataSet[0].value)
@@ -124,7 +114,6 @@
                 b = i(t)
                 return arc(b)
         )
-
     #@path.exit().transition().duration(300).attrTween('d', that.removePieTween).remove()
     path.exit()
         .transition()
@@ -136,7 +125,6 @@
                 return arc(b)
         )
         .remove()
-
     labels = labelGroup.selectAll('text').data(piedata.sort((p1, p2) ->
       p1.startAngle - p2.startAngle
     ))
@@ -167,20 +155,16 @@
       # Move all calculations into the each function.
       # Position values are stored in the data object
       # so can be accessed later when drawing the line
-
       ### calculate the position of the center marker ###
-
       a = (d.startAngle + d.endAngle) / 2
       #trig functions adjusted to use the angle relative
       #to the "12 o'clock" vector:
       #console.log 'ts: a', a
       d.cx = Math.sin(a) * (radius - 75)
       d.cy = -Math.cos(a) * (radius - 75)
-
       ### calculate the default position for the label,
          so that the middle of the label is centered in the arc
       ###
-
       bbox = @getBBox()
       #bbox.width and bbox.height will
       #describe the size of the label text
@@ -195,7 +179,6 @@
       ### check whether the default position
          overlaps any other labels
       ###
-
       conflicts = []
       labelLayout.visit (node, x1, y1, x2, y2) ->
         #recurse down the tree, adding any overlapping
@@ -231,11 +214,9 @@
         d.r = d.l + bbox.width + 10
       else
         console.log 'no conflicts for ', d
-
       ### add this label to the quadtree, so it will show up as a conflict
          for future labels.
       ###
-
       labelLayout.add d
       maxLabelWidth = Math.max(maxLabelWidth, bbox.width + 10)
       maxLabelHeight = Math.max(maxLabelHeight, bbox.height + 10)


Agent pie: test globalizing variables

Agent pie: test globalizing variables

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -24,7 +24,7 @@
         width = (Dashing.widget_base_dimensions[0] * @container.data('sizex')) - Dashing.widget_margins[0] * 4 * (@container.data('sizex') - 1)

         # Height of the SVG area allowing for header and footer text
-        height = (Dashing.widget_base_dimensions[1] * container.data('sizey')) - 120
+        height = (Dashing.widget_base_dimensions[1] * @container.data('sizey')) - 120

         # Calculated min dimension of the SVG area
         radius = Math.min(width, height) / 2


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -7,13 +7,13 @@
     #@render(data.data)
     @update(data.data)
   buildPieStructure: ->
-    @width = 300
-    @height = 300
-    @radius = Math.min(@width, @height) / 2
+    width = 300
+    height = 300
+    radius = Math.min(width, height) / 2
     @color = d3.scale.category20()
-    @pie = d3.layout.pie().sort(null)
-    @arc = d3.svg.arc().innerRadius(@radius - 100).outerRadius(@radius - 50)
-    @svg = d3.select(@node).append('svg').attr('width', @width).attr('height', @height).append('g').attr('transform', 'translate(' + @width / 2 + ',' + @height / 2 + ')')
+    pie = d3.layout.pie().sort(null)
+    arc = d3.svg.arc().innerRadius(radius - 100).outerRadius(radius - 50)
+    svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
     return
   oldPieData: ''
   pieTween: (d, i) ->
@@ -47,7 +47,7 @@
       endAngle: d.endAngle)
     (t) ->
       b = i(t)
-      return @arc b
+      return arc b
   removePieTween: (d, i) ->
     `var i`
     that = this
@@ -61,7 +61,7 @@
       endAngle: e0)
     (t) ->
       b = i(t)
-      @arc b
+      arc b
   update: (dataSet) ->
     if !dataSet
         dataSet = @get("data")
@@ -74,7 +74,7 @@
     radiusi = 90
     color = d3.scale.category20()
     pie = d3.layout.pie()#.sort(null)
-    arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)#.innerRadius(radius - 100).outerRadius(radius - 50)
+    arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
     svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
     console.log 'update pie', dataSet
     that = this
@@ -132,12 +132,12 @@
     labels.exit().remove()
     labelLayout = d3.geom.quadtree().extent([
       [
-        -that.width
-        -that.height
+        -width
+        -height
       ]
       [
-        that.width
-        that.height
+        width
+        height
       ]
     ]).x((d) ->
       d.x


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -224,7 +224,7 @@

         pie = d3.layout.pie()
             .sort(null)
-            #.value((d) -> d.value)
+            .value((d) -> d.value)

         arc = d3.svg.arc()
           .outerRadius(radiuso)


Fix some tests.

Fix some tests.

--- test/server/commands_spec.coffee
+++ test/server/commands_spec.coffee
@@ -52,20 +52,20 @@
           ratings.setRating(@user2.id, user2Rating, done)

       it "returns the user's rating to the user without arguments", (done) ->
-        spy = @sandbox.spy(@user1, 'message')
+        spy = @sandbox.spy(@user1, 'announce')
         commands.executeCommand @server, @user1, @room, "rating", =>
           spy.callCount.should.equal(1)
-          spy.firstCall.args[0].should.include(@user1.name)
-          spy.firstCall.args[0].should.include(user1Rating)
+          spy.firstCall.args[1].should.include(@user1.name)
+          spy.firstCall.args[1].should.include(user1Rating)
           done()

       it "returns someone's rating to the user as an argument", (done) ->
-        spy = @sandbox.spy(@user1, 'message')
+        spy = @sandbox.spy(@user1, 'announce')
         commands.executeCommand @server, @user1, @room, "rating", @user2.id, =>
           spy.callCount.should.equal(1)
           spy.callCount.should.equal(1)
-          spy.firstCall.args[0].should.include(@user2.name)
-          spy.firstCall.args[0].should.include(user2Rating)
+          spy.firstCall.args[1].should.include(@user2.name)
+          spy.firstCall.args[1].should.include(user2Rating)
           done()

     describe "kick", ->
@@ -335,13 +335,13 @@
         @server.beginBattles (err, battleIds) =>
           if err then throw err
           battleIds.length.should.equal(2)
-          spy = @sandbox.spy(@user1, 'message')
+          spy = @sandbox.spy(@user1, 'announce')
           commands.executeCommand @server, @user1, @room, "battles", @user2.name, =>
             spy.callCount.should.equal(1)
-            spy.firstCall.args[0].should.include(@user2.name)
-            spy.firstCall.args[0].should.include(battleIds[0])
-            spy.firstCall.args[0].should.not.include(@user1.name)
-            spy.firstCall.args[0].should.not.include(battleIds[1])
+            spy.firstCall.args[1].should.include(@user2.name)
+            spy.firstCall.args[1].should.include(battleIds[0])
+            spy.firstCall.args[1].should.not.include(@user1.name)
+            spy.firstCall.args[1].should.not.include(battleIds[1])
             done()

       it "does not include alts in the battle list", (done) ->
@@ -349,11 +349,11 @@
         @server.queuePlayer(@user2.id, [ Factory("Magikarp") ], "Im an Alt")
         @server.beginBattles (err, battleIds) =>
           if err then throw err
-          spy = @sandbox.spy(@user1, 'message')
+          spy = @sandbox.spy(@user1, 'announce')
           commands.executeCommand @server, @user1, @room, "battles", @user2.name, =>
             if err then throw err
             spy.callCount.should.equal(1)
-            spy.firstCall.args[0].should.include(@user2.name)
+            spy.firstCall.args[1].should.include(@user2.name)
             done()

     describe "topic", ->
@@ -379,7 +379,7 @@
           done()

       it "messages all rooms and all battles", (done) ->
-        mock = @sandbox.mock(@room).expects('message').once()
+        mock = @sandbox.mock(@room).expects('announce').once()
         spy1 = @sandbox.spy(@user1, 'send')
         spy2 = @sandbox.spy(@user2, 'send')
         @server.queuePlayer(@user1.id, generateTeam()).should.be.empty
@@ -429,22 +429,22 @@

       it "returns a list of alts and the main account", (done) ->
         @user1.authority = auth.levels.MOD
-        spy = @sandbox.spy(@user1, 'message')
+        spy = @sandbox.spy(@user1, 'announce')
         commands.executeCommand @server, @user1, @room, "whois", @user1.name, =>
           spy.callCount.should.equal(1)
-          spy.firstCall.args[0].should.include(@user1.name)
-          spy.firstCall.args[0].should.include("alt1")
-          spy.firstCall.args[0].should.include("alt2")
+          spy.firstCall.args[1].should.include(@user1.name)
+          spy.firstCall.args[1].should.include("alt1")
+          spy.firstCall.args[1].should.include("alt2")
           done()

     describe "help", ->
       it "messages all available commands to that user", (done) ->
-        spy = @sandbox.spy(@user1, 'message')
-        mock = @sandbox.mock(@user2).expects('message').never()
+        spy = @sandbox.spy(@user1, 'announce')
+        mock = @sandbox.mock(@user2).expects('announce').never()
         commandNames = (name  for name of commands.HelpDescriptions)
         commands.executeCommand @server, @user1, @room, "help", ->
           spy.callCount.should.equal(1)
           for commandName in commandNames
-            spy.firstCall.args[0].should.include(commandName)
-          mock.verify()
-          done()
+            spy.firstCall.args[1].should.include(commandName)
+          mock.verify()
+          done()


mixpanel: track deleting accounts

mixpanel: track deleting accounts

--- client/app/Applications/Account.kdapplication/views/deleteaccountview.coffee
+++ client/app/Applications/Account.kdapplication/views/deleteaccountview.coffee
@@ -57,6 +57,7 @@
               if err then new KDNotificationView title : 'There was a problem, please try again!'
               else
                 new KDNotificationView title : 'Thank you for trying Koding!'
+                KD.track "Account", "Deleted Account"
                 KD.utils.wait 2000, ->
                   $.cookie 'clientId', erase : yes
                   location.replace '/'


embedly: minor fix

embedly: minor fix

--- client/landing/app/Applications/Activity.kdapplication/views/embedbox.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/embedbox.coffee
@@ -121,9 +121,8 @@
       value = data[key]
       wantedData[key] = value

-    for key, value of wantedData
-      if typeof value is "string"
-        wantedData[key] = Encoder.htmlDecode value
+    for key, value of wantedData when "string" is typeof value
+      wantedData[key] = Encoder.htmlDecode value

     return wantedData


fix client not selected problem

fix client not selected problem

--- app/assets/javascripts/angular/worklogs/worklogs_controller.js.coffee
+++ app/assets/javascripts/angular/worklogs/worklogs_controller.js.coffee
@@ -19,7 +19,10 @@

     $q.all(query).then (results)->
       $scope.clients = results[0]
-      $scope.worklog = if idPresent then results[1] else new Worklog
+      if idPresent
+        $scope.worklog = results[1]
+      else
+        $scope.worklog = new Worklog

       # All loaded, start watching.
       $scope.$watch("worklog.client", (newValue, oldValue)->
@@ -35,6 +38,11 @@
         $scope.worklog.total = t
       , true)

+      if gon.client_id
+        getSelectedClient = ->
+          _.select($scope.clients, (c)-> c.id == gon.client_id)[0]
+        $scope.worklog.client = getSelectedClient()
+
   $scope.open = ($event, timeframe)->
     $event.preventDefault()
     $event.stopPropagation()


.htc stylesheets are not allowed

.htc stylesheets are not allowed

--- controllers/iframe.coffee
+++ controllers/iframe.coffee
@@ -3,7 +3,7 @@
 m = require './middleware'

 app.get '/iframe/:teamId', [m.loadTeam, m.loadMyVote], (req, res) ->
-  css = req.query.css if /^https?:\/\//.test(req.query.css)
+  css = req.query.css if /^https?:\/\//.test(req.query.css) and not /\.htc$/.test(req.query.css)
   req.vote = null unless req.user?.voter
   Vote.count teamId: req.team._id, type: 'voter', (err, count) ->
     next err if err


[Completes #34780451] Nessus not used, defaults now include Makemake, Haumea, more to come...


Cleanup a spec var

Cleanup a spec var

--- test/src/svg-documentSpec.coffee
+++ test/src/svg-documentSpec.coffee
@@ -1,7 +1,8 @@
 describe 'Curve.SvgDocument', ->
+  svg = null
   beforeEach ->
     loadFixtures 'canvas.html'
-    @s = new Curve.SvgDocument($('#canvas')[0])
+    svg = new Curve.SvgDocument($('#canvas')[0])

   it 'has a tool layer', ->
     expect($('#canvas svg>.tool-layer')).toExist()
@@ -10,17 +11,17 @@
     beforeEach ->

     it 'will deserialize an svg document', ->
-      @s.deserialize(DOCUMENT)
+      svg.deserialize(DOCUMENT)

       expect($('#canvas svg>svg')).toExist()
       expect($('#canvas svg>svg #arrow')).toExist()

     it 'places tool things in the tool layer', ->
-      @s.deserialize(DOCUMENT)
+      svg.deserialize(DOCUMENT)

-      @s.objects[0]
-      @s.selectionModel.setSelected(@s.objects[0])
-      @s.selectionModel.setSelectedNode(@s.objects[0].subpaths[0].nodes[0])
+      svg.objects[0]
+      svg.selectionModel.setSelected(svg.objects[0])
+      svg.selectionModel.setSelectedNode(svg.objects[0].subpaths[0].nodes[0])

       expect($('#canvas .tool-layer .node-editor-node')).toExist()
       expect($('#canvas .tool-layer .object-selection')).toExist()
@@ -29,12 +30,12 @@
     beforeEach ->

     it 'will export an svg document', ->
-      @s.deserialize(DOCUMENT)
-      expect(@s.serialize().trim()).toEqual DOCUMENT_WITH_XML_DOCTYPE
+      svg.deserialize(DOCUMENT)
+      expect(svg.serialize().trim()).toEqual DOCUMENT_WITH_XML_DOCTYPE

     it 'serializing and deserializing is symmetrical', ->
-      @s.deserialize(DOCUMENT_WITH_XML_DOCTYPE)
-      expect(@s.serialize().trim()).toEqual DOCUMENT_WITH_XML_DOCTYPE
+      svg.deserialize(DOCUMENT_WITH_XML_DOCTYPE)
+      expect(svg.serialize().trim()).toEqual DOCUMENT_WITH_XML_DOCTYPE

 DOCUMENT = '''
   <svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg">


Use disposables instead of subscribe

Use disposables instead of subscribe

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -1,4 +1,5 @@
 {$$} = require 'atom-space-pen-views'
+{CompositeDisposable} = require 'atom'
 SymbolsView = require './symbols-view'
 TagGenerator = require './tag-generator'

@@ -9,19 +10,17 @@

     @cachedTags = {}

-    @subscribe atom.project.eachBuffer (buffer) =>
-      @subscribe buffer, 'reloaded saved destroyed path-changed', =>
-        delete @cachedTags[buffer.getPath()]
+    @editorsSubscription = atom.workspace.observeTextEditors (editor) =>
+      removeFromCache = => delete @cachedTags[editor.getPath()]
+      editorSubscriptions = new CompositeDisposable()
+      editorSubscriptions.add(editor.onDidChangeGrammar(removeFromCache))
+      editorSubscriptions.add(editor.onDidStopChanging(removeFromCache))
+      editorSubscriptions.add(editor.onDidSave(removeFromCache))
+      editorSubscriptions.add(editor.onDidChangePath(removeFromCache))
+      editor.onDidDestroy => editorSubscriptions.dispose()

-      @subscribe buffer, 'destroyed', =>
-        @unsubscribe(buffer)
-
-    @subscribe atom.workspace.eachEditor (editor) =>
-      @subscribe editor, 'grammar-changed', =>
-        delete @cachedTags[editor.getPath()]
-
-      @subscribe editor, 'destroyed', =>
-        @unsubscribe(editor)
+  beforeRemove: ->
+    @editorsSubscription.dispose()

   viewForItem: ({position, name}) ->
     $$ ->


Make record completer work with options

Make record completer work with options

A little messy...

--- app/assets/volume/spreadsheet.coffee
+++ app/assets/volume/spreadsheet.coffee
@@ -771,6 +771,7 @@
                         r:r
                         v:r.measures[info.metric.id]
                         d:Object.keys(r.measures).sort(byNumber).map(mf(r)).join(', ')
+                        l:Object.keys(r.measures).map(mf(r)).join(' ').toLowerCase()
                   editScope.records = rs
                 else if info.metric.options
                   editScope.type = 'options'
@@ -901,32 +902,40 @@
           info = editScope.info
           o = []
           defd = false
-          add = (t, f, nd) ->
+          add = (t, f, d) ->
             o.push
               text: t
               select: (cell) ->
                 f(cell ? unedit(false))
                 undefined
-              default: !nd && !defd
-            defd ||= !nd
+              default: d && !defd
+            defd ||= d
           if !input && info.r
             add("Remove " + info.record.displayName + " from this session",
-              (cell) -> setRecord(cell, info, null))
+              (cell) -> setRecord(cell, info, null),
+              true)
           else if !info.r || input != info.record.measures[info.metric.id]
+            inputl = input.toLowerCase()
             set = (r) -> (cell) ->
               setRecord(cell, info, r)
             for r in editScope.records
-              add("Use " + info.category.name + ' ' + r.d, set(r.r), r.v != input) if r.d.includes(input)
-            if info.metric.options
-              # TODO
-            else if input
+              add("Use " + info.category.name + ' ' + r.d, set(r.r), r.v == input) if r.l.includes(inputl)
+            v = if info.metric.options
+                (x for x in info.metric.options when x.toLowerCase().startsWith(inputl))
+              else if input
+                [input]
+              else
+                []
+            v.forEach (i) ->
               if info.r
-                add("Change all " + info.record.displayName + " " + info.metric.display + " to '" + input + "'",
-                  (cell) -> saveMeasure(cell, info.record, info.metric, input))
-              add("Create new " + info.category.name + " with " + info.metric.name + " '" + input + "'",
-                (cell) -> setRecord(cell, info).then (r) ->
-                  saveMeasure(cell, r, info.metric, input) if r
-                  return)
+                add("Change all " + info.record.displayName + " " + info.metric.name + " to '" + i + "'",
+                  (cell) -> saveMeasure(cell, info.record, info.metric, i),
+                  i == input)
+              add("Create new " + info.category.name + " with " + info.metric.name + " '" + i + "'"
+                , (cell) -> setRecord(cell, info).then (r) ->
+                    saveMeasure(cell, r, info.metric, i) if r
+                    return
+                , i == input)
           o

         optionCompletions = (input) ->


Fixing pagination on issues.

Fixing pagination on issues.

--- app/coffee/controllers/issues.coffee
+++ app/coffee/controllers/issues.coffee
@@ -47,7 +47,7 @@

         @scope.setPage = (n) =>
             @scope.page = n
-            @filterIssues()
+            @.refreshIssues()

         # Load initial data
         @rs.resolve(pslug: @routeParams.pslug).then (data) =>


Implement not sending updates when gamepad hasn't changed.

--- app/scripts/ansible/reporters.coffee
+++ app/scripts/ansible/reporters.coffee
@@ -6,10 +6,15 @@
   'ansible'
   'AMessage'
   ($interval, ansible, AMessage) ->
+
+    # used for not sending redundant gamepad state
+    previousTimestamp = 0
     update = ->
       g = navigator.getGamepads()[0]
-      if not g?
+      if not g? or g.timestamp == previousTimestamp
         return # we don't have anything to send
+
+      previousTimestamp = g.timestamp

       content =
         axes: g.axes
@@ -18,5 +23,5 @@
       message = new AMessage('gamepad', content)
       ansible.send(message)

-    $interval(update, 100)
+    $interval(update, 20) # fastest practical for gamepad api
   ]


Display "?" while searching for word frequency and "0" for null results

--- app/scripts/controllers/words.coffee
+++ app/scripts/controllers/words.coffee
@@ -10,7 +10,7 @@
     $scope.$watch "rep", ->
       $scope.getRepWords()
     $scope.$watch "wordQuery", ->
-      $scope.wordFrequency = 0
+      $scope.wordFrequency = "?"
       clearTimeout $scope.waitForTypingToEnd()
       $scope.waitForTypingToEnd()

@@ -51,7 +51,11 @@
           q: "select * from json where url=\'#{url}\'"
           format: "json"
       ).success((data, status) ->
-        $scope.wordFrequency = $scope.countFrequency(data.query.results.json.results)
+        console.log data
+        if data.query.results.json == null
+          $scope.wordFrequency = 0
+        else
+          $scope.wordFrequency = $scope.countFrequency(data.query.results.json.results)
       ).error (data, status) ->
         console.log "Error #{status}: #{data}"


adding export

adding export

--- lib/jsMegaHal.coffee
+++ lib/jsMegaHal.coffee
@@ -154,4 +154,6 @@
 			quad = @quads[newQuad.hash()]
 			parts.unshift prevToken

-		parts.join ' '+		parts.join ' '
+
+module.exports = exports = Quad


Fixed UploadField snippet namespace

Fixed UploadField snippet namespace

--- completions.cson
+++ completions.cson
@@ -1720,7 +1720,7 @@
     {
       'minVersion': '4.0'
       'useNamespace': [
-        'SilverStripe\\Forms\\UploadField'
+        'SilverStripe\\AssetAdmin\\Forms\\UploadField'
       ]
     }
     {


Revise lower panel to span the full length

--- cistrans/cistrans.coffee
+++ cistrans/cistrans.coffee
@@ -4,9 +4,9 @@
   # dimensions of panels
   w = [800, 300]
   h = [w[0], 300]
-  w = [w[0], w[0], w[1]]
+  pad = {left:60, top:40, right:40, bottom: 40}
+  w = [w[0], w[0] + w[1] + pad.left + pad.right, w[1]]
   h = [h[0], h[1], h[0]]
-  pad = {left:60, top:40, right:40, bottom: 40}

   left = [pad.left, pad.left,
           pad.left + w[0] + pad.right + pad.left]
@@ -26,6 +26,9 @@
   peakRad = 2
   bigRad = 5

+  # gap between chromosomes in lower plot
+  chrGap = 8
+
   # height of marker ticks in lower panel
   tickHeight = (bottom[1] - top[1])*0.02

@@ -73,12 +76,27 @@
   # slight adjustments
   top[0] = data.chr["X"].end_Ypixel-peakRad
   right[1] = right[0] = data.chr["X"].end_Xpixel+peakRad
-  w[1] = w[0] = right[0] - left[0]
   h[0] = bottom[0] - top[0]
   data.chr["1"].start_Xpixel = left[0]
   data.chr["1"].start_Ypixel = bottom[0]
   data.chr["X"].end_Xpixel = right[0]
   data.chr["X"].end_Ypixel = top[0]
+
+  # chr scales in lower figure
+  chrLowXScale = {}
+  cur = Math.round(pad.left + chrGap/2)
+  for c in data.chrnames
+    data.chr[c].start_lowerXpixel = cur
+    data.chr[c].end_lowerXpixel = cur + Math.round((w[1]-chrGap*(data.chrnames.length))/totalChrLength*data.chr[c].length_cM)
+    chrLowXScale[c] = d3.scale.linear()
+                        .domain([data.chr[c].start_cM, data.chr[c].end_cM])
+                        .range([data.chr[c].start_lowerXpixel, data.chr[c].end_lowerXpixel])
+    cur = data.chr[c].end_lowerXpixel + chrGap
+
+  # slight adjustments
+  data.chr["1"].start_lowerXpixel = left[1]
+  data.chr["X"].end_lowerXpixel = right[1]
+

   # create SVGs
   svg = d3.select("div#cistrans").append("svg")
@@ -113,13 +131,19 @@
   for ci,i in data.chrnames
       if(i % 2 == 0)
         checkerboard2.append("rect")
-           .attr("x", data.chr[ci].start_Xpixel)
-           .attr("width", data.chr[ci].end_Xpixel - data.chr[ci].start_Xpixel)
+           .attr("x", data.chr[ci].start_lowerXpixel)
+           .attr("width", data.chr[ci].end_lowerXpixel - data.chr[ci].start_lowerXpixel)
            .attr("y", top[1])
            .attr("height", h[1])
            .attr("stroke", "none")
            .attr("fill", darkGray)
            .style("pointer-events", "none")
+
+  # use just the peaks with LOD > 10
+  tmp = []
+  for p in data.peaks
+    tmp.push(p) if p.lod > 10
+  data.peaks = tmp

   # maximum lod score
   maxlod = d3.max(data.peaks, (d) -> d.lod)


show help default  #2

show help default  #2

--- bin/theta.coffee
+++ bin/theta.coffee
@@ -95,4 +95,7 @@
       console.log "BatteryLevel: #{res.dataPacket.toString()}"
       theta.disconnect()

+if process.argv.length < 3
+  parser.on_switches.help.call()
+
 parser.parse process.argv