remove unused precursor to Testify

remove unused precursor to Testify

--- src/server/testify.coffee
+++ src/server/testify.coffee
@@ -1,83 +0,0 @@
-colors = require "colors"
-EventEmitter = require("events").EventEmitter
-
-# Test functions that take no arguments are treated as
-# wholly synchronous.  Test functions that take one argument
-# are provided a context object that makes provisions for
-# asynchronous usage.  The two primary provisions are the
-# `safely` function, used for wrapping callbacks in testliness;
-# and the `done` method, which signals the end (and success)
-# of a test.
-testify = (name, fn) ->
-  try
-    if fn.length == 0
-      fn()
-      success(name)
-    else
-      context = create_context(name)
-      testify.count++
-      context.emitter.on "done", ->
-        success(name)
-        testify.count--
-        if testify.count == 0
-          testify.emitter.emit("done")
-      fn(context)
-  catch error
-    failure(name, error)
-    process.exit()
-
-testify.count = 0
-
-testify.later = (name, fn) ->
-  () ->
-    testify(name, fn)
-
-testify.emitter = new EventEmitter()
-
-testify.on = (args...) ->
-  testify.emitter.on(args...)
-
-
-success = (name) -> console.log colors.green("Pass: '#{name}'")
-
-failure = (name, error) ->
-  if error.name == "AssertionError"
-    console.log colors.red("Fail: '#{name}'\n#{error}")
-  else
-    console.log colors.yellow("Error: '#{name}'\n#{error}")
-  # split,slice to remove the error message from the stack trace
-  if error.stack
-    console.log colors.white(error.stack.split("\n").slice(1).join("\n"))
-  process.exit()
-
-assertions = (test_name) ->
-  wrapped = {}
-  for name, fn of require("assert")
-    wrapped[name] = wrap_assertion(test_name, fn)
-  # custom assertions
-  wrapped.partialEqual = wrap_assertion test_name, (actual, expected) ->
-    for key, val of expected
-      assert.deepEqual(actual[key], val)
-  wrapped
-
-wrap_assertion = (test_name, fn) ->
-  (args...) ->
-    try
-      fn(args...)
-    catch error
-      failure(test_name, error)
-
-create_context = (name) ->
-  emitter = new EventEmitter
-  context =
-    name: name
-    emitter: emitter
-    done: () -> emitter.emit("done")
-    assert: assertions(name)
-
-#assert.partialEqual = (actual, expected) ->
-  #for key, val of expected
-    #assert.deepEqual(actual[key], val)
-
-module.exports = testify
-


Exclude TextEditorView that don't belong to a PaneView

Until the minimap gets integrated into the `<atom-text-editor>` node
this is a safe guard against randomly created `TextEditorView`s.

--- lib/mixins/view-management.coffee
+++ lib/mixins/view-management.coffee
@@ -71,6 +71,8 @@
       editorId = editorView.editor.id
       paneView = editorView.getPaneView()

+      return unless paneView?
+
       if (view = @minimapViews[editorId])?
         view.setEditorView editorView
         view.detachFromPaneView()


Save code logs faster for 5% of regular levels

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -135,6 +135,8 @@
     saveSpadeDelay = 10 * 60 * 1000
     if @options.level.get('releasePhase') is 'beta'
       saveSpadeDelay = 3 * 60 * 1000  # Capture faster for beta levels, to be more likely to get something
+    else if Math.random() < 0.05 and _.find(utils.freeAccessLevels, access: 'short', slug: @options.level.get('slug'))
+      saveSpadeDelay = 3 * 60 * 1000  # Capture faster for some free levels to compare with beta levels
     @saveSpadeTimeout = setTimeout @saveSpade, saveSpadeDelay

   createACEShortcuts: ->
@@ -714,7 +716,10 @@
     if @saveSpadeTimeout?
       window.clearTimeout @saveSpadeTimeout
       @saveSpadeTimeout = null
-      @saveSpade() if @options.level.get('releasePhase') is 'beta'
+      if @options.level.get('releasePhase') is 'beta'
+        @saveSpade()
+      else if Math.random() < 0.05 and _.find(utils.freeAccessLevels, access: 'short', slug: @options.level.get('slug'))
+        @saveSpade()

   onManualCast: (e) ->
     cast = @$el.parent().length


Fix permissions toggle label for new posts

--- assets/javascripts/views/permissions_fields_toggle.js.coffee
+++ assets/javascripts/views/permissions_fields_toggle.js.coffee
@@ -10,7 +10,9 @@

     @render()

-  context: (permissions = @parentView()?.post()?.get('permissions')) =>
+  context: (permissions) =>
+    permissions ?= @parentView()?.post()?.get('permissions')
+    permissions ?= { public: true }
     _.extend super,
       permissions: permissions


Add failing foo/{bar,baz} style glob unpack test

--- test/cli-spec.coffee
+++ test/cli-spec.coffee
@@ -117,6 +117,15 @@
       done compFiles tmpFile, 'test/expected/packthis-unpack-dir-globstar.asar'
       return
     return
+  it 'should create archive from directory with unpacked dirs specified by foo/{bar,baz} style pattern', (done) ->
+    tmpFile = 'tmp/packthis-unpack-dir-globstar-cli.asar'
+    tmpUnpacked = 'tmp/packthis-unpack-dir-globstar-cli.asar.unpacked'
+    exec 'node bin/asar p test/input/packthis-glob/ ' + tmpFile + ' --unpack-dir "y3/{x1,z1}" --exclude-hidden', (error, stdout, stderr) ->
+      assert.ok fs.existsSync tmpUnpacked + '/y3/x1/file4.txt'
+      assert.ok fs.existsSync tmpUnpacked + '/y3/z1/x2/file5.txt'
+      done()
+      return
+    return
   it 'should list files/dirs in archive with unpacked dirs', (done) ->
     exec 'node bin/asar l test/expected/packthis-unpack-dir.asar', (error, stdout, stderr) ->
       return done(error) if error?


Normalize package path before creating it

--- lib/package-generator-view.coffee
+++ lib/package-generator-view.coffee
@@ -62,7 +62,7 @@
         @close()

   getPackagePath: ->
-    packagePath = @miniEditor.getText().trim()
+    packagePath = fs.normalize(@miniEditor.getText().trim())
     packageName = _.dasherize(path.basename(packagePath))
     path.join(path.dirname(packagePath), packageName)


Now group common exceptions into one element.

--- web/coffee/management-exceptions.coffee
+++ web/coffee/management-exceptions.coffee
@@ -5,6 +5,7 @@
 Button = ReactBootstrap.Button
 Glyphicon = ReactBootstrap.Glyphicon
 Col = ReactBootstrap.Col
+Badge = ReactBootstrap.Badge

 ExceptionTab = React.createClass
   getInitialState: ->
@@ -47,15 +48,16 @@

     deleteButton =
-    <Button className="pad" bsSize="xsmall" onClick={@onDelete.bind this, exception}>
-      <Glyphicon glyph="remove"/>
-    </Button>
+    <Glyphicon onClick={@onDelete.bind this, exception} glyph="remove"/>
+
+    occurencesBadge =
+    <Badge>{exception.count}</Badge>

     exceptionHeader =

       {exception.request.api_endpoint_method} {exception.request.api_endpoint}

-          {time} {deleteButton}
+          {occurencesBadge} {time} {deleteButton}

@@ -65,15 +67,19 @@

{exception.trace}

-    style = if i == 0 then "warning" else "info"
-
-    <Panel bsStyle={style} eventKey={i} key={i} header={exceptionHeader}>
+    <Panel bsStyle="default" eventKey={i} key={i} header={exceptionHeader}>
       {exceptionBody}
       {@createInfoDisplay exception}
     </Panel>

   render: ->
-    exceptionList = @state.exceptions.map @createExceptionItem
+    groupedExceptions = _.groupBy @state.exceptions, (exception) -> exception.trace
+    uniqueExceptions = _.map groupedExceptions, (exceptions, commonTrace) ->
+        exception = _.first(exceptions)
+        exception.count = exceptions.length
+        return exception
+
+    exceptionList = uniqueExceptions.map @createExceptionItem
     exceptionDisplay = <Accordion defaultActiveKey={0}> {exceptionList} </Accordion>


Remove remote state if node process resumes execution.

--- src/scripts/background/debug/node/debugger.coffee
+++ src/scripts/background/debug/node/debugger.coffee
@@ -10,6 +10,11 @@

     @bps = []

+  _continueCallback: =>
+    @debugger.sendMessage
+      type: "debugger.resume"
+      origin: @dbg.origin()
+
   stepOver: (message, callback) =>
     m =
       type: "request"
@@ -17,7 +22,7 @@
       arguments:
         stepaction: "next"
         stepcount: 1
-    @dbg._sendCommand m, callback
+    @dbg._sendCommand m, @_continueCallback

   stepInto: (message, callback) =>
     m =
@@ -26,7 +31,7 @@
       arguments:
         stepaction: "in"
         stepcount: 1
-    @dbg._sendCommand m, callback
+    @dbg._sendCommand m, @_continueCallback

   stepOut: (message, callback) =>
     m =
@@ -35,14 +40,14 @@
       arguments:
         stepaction: "out"
         stepcount: 1
-    @dbg._sendCommand m, callback
+    @dbg._sendCommand m, @_continueCallback

   resume: (message, callback) =>
     @debugger.hideOverlay()
     m =
       type: "request"
       command: "continue"
-    @dbg._sendCommand m, callback
+    @dbg._sendCommand m, @_continueCallback

   pause: (message, callback) =>
     # Unsupported, do nothing


Removed console.log.

Removed console.log.

--- common/lib/xmodule/xmodule/js/src/annotatable/display.coffee
+++ common/lib/xmodule/xmodule/js/src/annotatable/display.coffee
@@ -137,7 +137,6 @@

     afterScrollToDiscussion: (discussion_el) ->
         btn = $('.discussion-show', discussion_el)
-        console.log(btn)
         btn.click() if !btn.hasClass('shown')

     afterScrollToSpan: (span_el) ->


h1, h2, h3, h4 support

h1, h2, h3, h4 support


Add close method to socket

Add close method to socket

--- src/flowdock.coffee
+++ src/flowdock.coffee
@@ -15,6 +15,10 @@
     "last_activity": new Date().getTime(),
     "client": @clientId

+  close: () ->
+    if @request
+      @request.abort()
+
   connect: () ->
     data = querystring.stringify(@data())
     options =
@@ -24,7 +28,7 @@
       headers:
         'Cookie': @cookies.join("; ")

-    https.get options, (res) =>
+    @request = https.get options, (res) =>
       buffer = ""
       res.on "data", (data) =>
         chunk = data.toString("utf8")


render tooltip in onRender, when we actually have an element

--- core/app/backbone/views/activities/activity_item_view.coffee
+++ core/app/backbone/views/activities/activity_item_view.coffee
@@ -58,7 +58,7 @@
   templateHelpers: ->
     topic: @topic().toJSON()

-  initialize: ->
+  onRender: ->
     Backbone.Factlink.makeTooltipForView
       parentView: @
       positioning:


resurrection.topics: fix destructing binding statement for JTag

--- client/Social/Topics/AppController.coffee
+++ client/Social/Topics/AppController.coffee
@@ -22,7 +22,7 @@
     @controllers = {}

   createFeed:(view, loadFeed = no)->
-    {JTag} = KD.remote.api.JTag
+    {JTag} = KD.remote.api
     KD.getSingleton("appManager").tell 'Feeder', 'createContentFeedController', {
       feedId                : 'topics.main'
       itemClass             : @listItemClass


CLI/new fixing the new projects generator

--- cli/commands/new.coffee
+++ cli/commands/new.coffee
@@ -24,7 +24,7 @@

   placeholders =
     projectname: projectname,
-    projectunit: projectname.replace(/(^|-)[a-z]/g, (m)-> m.toUpperCase())
+    projectunit: projectname.replace(/(^|-)([a-z])/g, (m,m1,m2)-> m2.toUpperCase())
     projectfile: projectname.replace(/\-/g, '_')
     year:        new Date().getFullYear(),
     username:    lovelyrc.name || "Vasily Pupkin"
@@ -90,12 +90,13 @@
   {Test, assert} = require('lovely')

   describe "%{projectunit}", ->
-    %{projectunit} = window = document = null
+    %{projectunit} = window = document = $ = null

     before Test.load module, (build, win)->
       %{projectunit} = build
       window   = win
       document = win.document
+      $        = win.Lovely.module('dom')

     it "should have a version", ->
       assert.ok %{projectunit}.version
@@ -112,12 +113,13 @@
   var assert = Lovely.assert;

   describe("%{projectunit}", function() {
-    var %{projectunit}, window, document;
+    var %{projectunit}, window, document, $;

     before(Test.load(module, function(build, win) {
       %{projectunit} = build;
       window   = win;
       document = win.document;
+      $        = win.Lovely.module('dom');
     }));

     it("should have a version number", function() {


dnd uploader naming fixes.

dnd uploader naming fixes.

--- client/app/CommonViews/DNDUploader.coffee
+++ client/app/CommonViews/DNDUploader.coffee
@@ -19,31 +19,31 @@
       @on "dragleave", => @unsetClass "hover"
       @on "drop",      => @unsetClass "hover"

-    @on "uploadFile", (file, percent)=>
+    @on "uploadFile", (fsFile, percent)=>
       finder = KD.getSingleton "finderController"
-      filePath  = "[#{file.vmName}]#{file.path}"
+      filePath  = "[#{fsFile.vmName}]#{fsFile.path}"
       finder.treeController.nodes[filePath]?.updateProgressView percent

-    @on "uploadStart", (file)=>
+    @on "uploadStart", (fsFile)=>
       finder = KD.getSingleton "finderController"
-      filePath   = "[#{file.vmName}]#{file.path}"
-      parentPath = "[#{file.vmName}]#{file.parentPath}"
+      filePath   = "[#{fsFile.vmName}]#{fsFile.path}"
+      parentPath = "[#{fsFile.vmName}]#{fsFile.parentPath}"

-      file._isBeingUploaded = yes
+      fsFile._isBeingUploaded = yes
       nodeView = finder.treeController.nodes[filePath]
       if nodeView
         nodeView.updateProgressView 1
-        nodeView.on "abortProgress", => file.abort yes
+        nodeView.on "abortProgress", => fsFile.abort yes
       else
         finder.treeController.on "NodeWasAdded", (nodeView)->
-          if nodeView.getData().path is filePath and file._isBeingUploaded
+          if nodeView.getData().path is filePath and fsFile._isBeingUploaded
             nodeView.updateProgressView 1
-            nodeView.on "abortProgress", => file.abort yes
+            nodeView.on "abortProgress", => fsFile.abort yes

-        file.save "", -> finder.revealPath parentPath
+        fsFile.save "", -> finder.revealPath parentPath

-    @on "uploadEnd", (file)->
-      file._isBeingUploaded = no
+    @on "uploadEnd", (fsFile)->
+      fsFile._isBeingUploaded = no

   reset: ->
     {uploadToVM, defaultPath, title} = @getOptions()
@@ -76,7 +76,7 @@
       lastFile = files.last
       for file, index in files
         sizeInMb = file.size/1024/1024
-        if sizeInMb > 50 && @getOptions().uploadToVM
+        if sizeInMb > 100 && @getOptions().uploadToVM
           new KDNotificationView
             type    : "tray"
             title   : "File is too big to upload!"
@@ -87,7 +87,6 @@
         reader.onloadend = do (file=files[index])=> (readEvent)=>
           if @getOptions().uploadToVM
             fsFile = @upload file.name, readEvent.target.result
-
           @emit "dropFile",
             origin  : "external"
             filename: file.name
@@ -137,33 +136,33 @@
       attributes: href: "#"
       click     : => @emit "cancel"

-  saveFile: (uploadFile, data)->
-    @emit "uploadStart", uploadFile
-    uploadFile.saveBinary data, (err, res, progress)=>
+  saveFile: (fsFile, data)->
+    @emit "uploadStart", fsFile
+    fsFile.saveBinary data, (err, res, progress)=>
       return if err
       if res.finished
-        @emit "uploadEnd", uploadFile
+        @emit "uploadEnd", fsFile
       else if res.abort
-        @emit "uploadAbort", uploadFile
+        @emit "uploadAbort", fsFile
       else
-        @emit "uploadFile", uploadFile, progress.percent
+        @emit "uploadFile", fsFile, progress.percent

-  upload: (file, data)->
-    modalStack  = KDModalView.createStack lastToFirst: yes
-    uploadDir   = FSHelper.createFileFromPath @path, 'folder'
-    uploadFile  = FSHelper.createFileFromPath "#{@path}/#{file}"
+  upload: (fileName, contents)->
+    modalStack      = KDModalView.createStack lastToFirst: yes
+    fsUploadFolder  = FSHelper.createFileFromPath @path, 'folder'
+    fsFileToUpload  = FSHelper.createFileFromPath "#{@path}/#{fileName}"

-    upload      = =>
-      uploadFile.exists (err, exists)=>
-        unless exists
-        then @saveFile uploadFile, data
+    upload = =>
+      fsFileToUpload.exists (err, exists)=>
+        if not exists or fsFileToUpload.getLocalFileInfo().lastUploadedChunk?
+        then @saveFile fsFileToUpload, contents
         else
           modalStack.addModal modal = new KDModalView
             overlay : no
             title   : "Overwrite File?"
             content : """

-            You already have the file #{uploadFile.path}. Do you want
+            You already have the file #{fsFileToUpload.path}. Do you want
             to overwrite it?

             """
@@ -171,7 +170,7 @@
               Overwrite:
                 cssClass: "modal-clean-green"
                 callback: =>
-                  @saveFile uploadFile, data
+                  @saveFile fsFileToUpload, contents
                   modal.destroy()
               cancel:
                 cssClass: "modal-cancel"
@@ -182,9 +181,9 @@
                 callback: ->
                   modalStack.destroy()

-    uploadDir.exists (err, exists)=>
+    fsUploadFolder.exists (err, exists)=>
       unless exists
-      then uploadDir.save -> upload()
+      then fsUploadFolder.save -> upload()
       else upload()

-    return uploadFile
+    return fsFileToUpload


IE10 cares about style order

IE10 cares about style order

Seems to be length of key?

--- test/unit/dom.coffee
+++ test/unit/dom.coffee
@@ -84,11 +84,11 @@
   )

   describe('styles', ->
-    html = 'Test'
+    html = 'Test'
     styles =
       'color': 'red'
+      'display': 'inline'
       'background-color': 'blue'
-      'display': 'inline'

     it('getStyles()', ->
       $(@container).html(html)


or instead of ||

or instead of ||

--- bokehjs/src/coffee/common/ui_events.coffee
+++ bokehjs/src/coffee/common/ui_events.coffee
@@ -94,7 +94,7 @@
     tm = @get('tool_manager')
     base_event_type = event_type.split(":")[0]
     # if testing, tm.gestures will be defined instead of tm.get('gestures')
-    gestures = tm.gestures || tm.get('gestures')
+    gestures = tm.gestures or tm.get('gestures')
     active = gestures[base_event_type].active
     if active?
       if event_type == "scroll"


Bugfix: highlights now delete properly

Bugfix: highlights now delete properly

Closes #135

--- coffee/src/shells/highlights_shell.coffee
+++ coffee/src/shells/highlights_shell.coffee
@@ -444,6 +444,16 @@
     @timeRangeView.setMax @duration()

+  _removeHighlightView: (highlightView) =>
+    # remove from model
+    highlights = @model.highlights()
+    highlights.splice(highlights.indexOf(highlightView.model), 1)
+
+    # remove from views
+    @highlightViews.splice(@highlightViews.indexOf(highlightView), 1)
+
+
+
   onEditHighlight: (highlightView) =>
     @inactivateHighlights [highlightView]
     highlightView.setActive true
@@ -495,13 +505,7 @@

     @inactivateHighlights()

-    # remove from model
-    highlights = @model.highlights()
-    highlights.splice(highlights.indexOf(highlightView.clip), 1)
-
-    # remove from views
-    @highlightViews.splice(@highlightViews.indexOf(highlightView), 1)
-
+    @_removeHighlightView(highlightView)
     @mediaView.highlightsGroupView.softRender()


mouseTrackingView: require $el parameter in method

_mouseOffsetFromElement now throws an explicit error when called without
a value

--- coffee/src/views/mouseTrackingView.coffee
+++ coffee/src/views/mouseTrackingView.coffee
@@ -270,6 +270,9 @@

   _mouseOffsetFromElement: ($el) =>
+    unless $el
+      MissingParameterError 'MouseTrackingView._mouseOffsetFromElement', '$el'
+
     $el = $ $el
     x = util.mouseLocationTracker.x - $el.offset().left
     y = util.mouseLocationTracker.y - $el.offset().top


ContextMenu: Fixed context menu positioning issue.

--- components/contextmenu/contextmenu.coffee
+++ components/contextmenu/contextmenu.coffee
@@ -51,8 +51,8 @@

   childAppended:->

-    @positionContextMenu()
     super
+    KD.utils.defer => @positionContextMenu()

   addArrow:->


Fixing toString() for Block

Fixing toString() for Block

--- src/js/Block.coffee
+++ src/js/Block.coffee
@@ -33,10 +33,10 @@
       @properties.middleRotation = (@properties.middleRotation + 270) % 360

   toString: ->
-    "#{@properties.top}#{@properties.topRotation}"
-    "#{@properties.middle}#{@properties.middleRotation}"
-    "#{@properties.low}#{@properties.lowRotation}"
-    "#{@opacity}#{@isSelected}"
+    return "#{@properties.top}#{@properties.topRotation}
+            #{@properties.middle}#{@properties.middleRotation}
+            #{@properties.low}#{@properties.lowRotation}
+            #{@opacity}#{@isSelected}"

   # All the types of blocks we support
   @Types:


Minor reorderings

Minor reorderings

--- library/membrane/preflight.coffee
+++ library/membrane/preflight.coffee
@@ -123,11 +123,11 @@
             logger.error error.message.red, error
             kernel.shutdownKernel reason
         installer.on "end", (installed) =>
+            bowerings.installed = installed
             message = "Get Bower lib %s@%s at %s"
             for packet in _.values(installed or {})
                 what = packet.pkgMeta?.name.underline
                 vers = packet.pkgMeta?.version.underline
                 where = @constructor.identify().underline
                 logger.debug message.cyan, what, vers, where
-                bowerings.installed = installed
         return next()


Deprecate custom events on EditorView

Deprecate custom events on EditorView

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -198,6 +198,16 @@
           deprecate('Use Workspace::onDidOpen instead')
       originalOn.apply(this, arguments)

+    EditorView = require './editor-view'
+    originalEditorOn = EditorView::on
+    EditorView::on = (eventName) ->
+      switch eventName
+        when 'cursor:moved'
+          deprecate('Use Editor::onDidChangeCursorPosition instead')
+        when 'selection:changed'
+          deprecate('Use Editor::onDidChangeSelectionRange instead')
+      originalEditorOn.apply(this, arguments)
+
   ###
   Section: Accessing the Workspace Model
   ###


attempt to prevent authworker from spamming terminal kite

--- workers/auth/lib/auth/authworker.coffee
+++ workers/auth/lib/auth/authworker.coffee
@@ -422,6 +422,13 @@
     { serviceGenericName, serviceUniqueName, routingKey
       correlationName, username } = messageData

+    # apparently auth worker can spam the terminal
+    # kite with requests for kite.who for guest accounts.
+    # this short-cicuiting is meant to prevent against that,
+    # but since I couldn't reproduce this problem locally,
+    # it is possible that this is not a sufficient fix. C.T.
+    return  if /^guest-\d+/.test username
+
     params = {
       serviceGenericName
       serviceUniqueName


Fixed non-passing tests

Fixed non-passing tests

- "TypeError: Path must be a string. Received undefined" was happening in 17 tests

--- test/unit/test-runner-test.coffee
+++ test/unit/test-runner-test.coffee
@@ -52,7 +52,7 @@
         options =
           server: "#{ABAO_IO_SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options , ''

         runCallback = sinon.stub()
         runCallback(done)
@@ -168,7 +168,7 @@
         options =
           server: "#{ABAO_IO_SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub test, 'run', (callback) ->
           callback()

@@ -196,7 +196,7 @@
         options =
           server: "#{SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub runner.mocha, 'run', (callback) -> callback()
         sinon.stub test, 'run', (callback) -> callback()

@@ -235,7 +235,7 @@
         options =
           server: "#{SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub runner.mocha, 'run', (callback) -> callback()
         sinon.stub test, 'run', (callback) -> callback()
         hooksStub.skippedTests = [test.name]
@@ -271,7 +271,7 @@
         options =
           server: "#{SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub runner.mocha, 'run', (callback) -> callback()
         sinon.stub test, 'run', (callback) -> callback()

@@ -314,7 +314,7 @@
         options =
           server: "#{SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         # sinon.stub runner.mocha, 'run', (callback) -> callback()
         testStub = sinon.stub test, 'run'
         testStub.throws('AssertionError')
@@ -356,7 +356,7 @@
         options =
           server: "#{SERVER}"

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub test, 'run', (callback) ->
           callback()

@@ -392,7 +392,7 @@
         options =
           names: true

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub runner.mocha, 'run', (callback) -> callback()
         sinon.spy console, 'log'

@@ -433,7 +433,7 @@
           server: "#{SERVER}"
           header: header

-        runner = new TestRunner options
+        runner = new TestRunner options, ''
         sinon.stub runner.mocha, 'run', (callback) ->
           receivedTest = _.clone(test)
           callback()
@@ -467,7 +467,7 @@
           server: "#{SERVER}"
           'hooks-only': true

-        runner = new TestRunner options
+        runner = new TestRunner options, ''

         mochaStub = runner.mocha
         originSuiteCreate = mocha.Suite.create


Debounce the scrolling.

Debounce the scrolling.

Prevents the inability to scroll away.

--- client/chanslate.coffee
+++ client/chanslate.coffee
@@ -59,8 +59,14 @@

 Handlebars.registerHelper('colorize', -> colorHandle(this["userName"]))

-scrollToBottom =  ->
-    $('html, body').animate({ scrollTop: 99999999 }, "slow")
+scrollToBottom = _.debounce(
+    ->
+        console.log('Debouncing')
+        $('html, body').animate({ scrollTop: 99999 }, "slow")
+    ,
+    100
+)
+

 # Template helpers
 Template.showMessages.helpers({
@@ -86,7 +92,6 @@

             textBox.value = ''
             textBox.focus()
-            autoScroll = true

     'keyup input[name="dst"]': (ev, template) ->
         if ev.which == 13
@@ -103,5 +108,4 @@

             textBox.value = ''
             textBox.focus()
-            autoScroll = true
 )


Flush loops exit early, if they are empty and some conditions are checked agoinst undefined variables.

--- js/core/elem/elem.coffee
+++ js/core/elem/elem.coffee
@@ -390,14 +390,17 @@
     _flushStartTime = new Date().getTime()
     @_flushTime -= _flushStartTime
     _loopMaxL = @_elemTodo.length
-    #if _loopMaxL > 0
-    _currTodo = @_elemTodo.splice( 0, _loopMaxL )
-    for i in [ 1.._loopMaxL ]
-      @_flushLoopFlushed++
-      _id = _currTodo.shift()
-      @_elemTodoH[_id] = false
-      @_flushStyleCache( _id )
-      @_flushAttrCache( _id )
+    if _loopMaxL > 0
+      _currTodo = @_elemTodo.splice( 0, _loopMaxL )
+      for i in [ 1.._loopMaxL ]
+        @_flushLoopFlushed++
+        _id = _currTodo.shift()
+        if _id == null
+          console.log('no id:',_id)
+          continue
+        @_elemTodoH[_id] = false
+        @_flushStyleCache( _id )
+        @_flushAttrCache( _id )
     @_flushCounter++
     @_flushTime += new Date().getTime()
     @_needFlush = @_elemTodo.length != 0 # unless @_needFlush
@@ -541,6 +544,8 @@
   Sets and buffers the named style attribute value or selectively direct
   ###
   setStyle: (_id, _key, _value, _noCache)->
+    if _id == undefined
+      console.log('ERROR; undefined id in ELEM#setStyle(',_id, _key, _value, _noCache,')')
     _noCache = true if BROWSER_TYPE.ie9
     try
       _cached = @_styleCache[_id]
@@ -634,12 +639,14 @@
     _styleTodo = @_styleTodo[_id]
     _cached = @_styleCache[_id]
     _loopMaxP = _styleTodo.length
+    return null if _loopMaxP == 0
     _currTodo = _styleTodo.splice( 0, _loopMaxP )
     for i in [ 1.._loopMaxP ]
       _key = _currTodo.shift()
       if _key == 'opacity'
         @setOpacity( _id, _cached[_key] )
       else
+        console.log( 'invalid style key:',_elem, _key, _cached) unless _key
         @_setElementStyle( _elem, _key, _cached[_key] )
     null


Fix zoom level not update

Fix zoom level not update

--- views/components/settings/parts/display-config.cjsx
+++ views/components/settings/parts/display-config.cjsx
@@ -39,6 +39,7 @@
     [].forEach.call $$('poi-app div.poi-app-tabpane'), (e) ->
       e.style.height = "#{poiappHeight / zoomLevel - 40}px"
       e.style.overflowY = "scroll"
+    window.zoomLevel = zoomLevel
     config.set('poi.zoomLevel', zoomLevel)
     @setState
       zoomLevel: zoomLevel


Refactored Form class

Refactored Form class

--- lib/assets/javascripts/form.js.coffee
+++ lib/assets/javascripts/form.js.coffee
@@ -3,9 +3,15 @@

   process: ->
     $disable = @$form.find('select:not(:disabled),input:not(:disabled)').filter(-> !$(this).val())
-    $disable.attr('disabled', true);
-
-    params = {}
+
+    $disable.attr('disabled', true)
+    url = this._url()
+    $disable.attr('disabled', false)
+
+    @page.load(url, @$form.attr("data-target"), this._type())
+
+  _params: ->
+    hash = {}

     for item in @$form.serializeArray()
       if item.name != 'utf8'
@@ -14,28 +20,30 @@
         else
           item.name

-        if params[name]?
-          params[name] = params[name] + ",#{item.value}"
+        if hash[name]?
+          hash[name] = hash[name] + ",#{item.value}"
         else
-          params[name] = item.value
+          hash[name] = item.value

+    hash
+
+  _type: ->
+    if (@$form.attr("data-push") == 'partial') then 'partial' else 'template'
+
+  _url: ->
     serialized = []

     # To find out why encodeURIComponent should be used, follow the link:
     # http://stackoverflow.com/questions/75980/best-practice-escape-or-encodeuri-encodeuricomponent
-    #
-    for key of params
-      serialized.push("#{key}=#{encodeURIComponent(params[key])}")
+    #
+    for key, value of this._params()
+      serialized.push("#{key}=#{encodeURIComponent(value)}")

     serialized = serialized.join('&')

     url = @$form.attr("action")
-    url += "?#{serialized}" if serialized.length > 0
-
-    $disable.attr('disabled', false);
-
-    type = if (@$form.attr("data-push") == 'partial') then 'partial' else 'template'
-    @page.load(url, @$form.attr("data-target"), type)
+    url += "?#{serialized}" if serialized.length > 0
+    url

 window._Wiselinks = {} if window._Wiselinks == undefined
 window._Wiselinks.Form = Form


group : getPermission method fetches defaultGroup permissions if no permission found.

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1482,3 +1482,10 @@
           body  : "Welcome to your group"
           group : @slug
         JNewStatusUpdate.create client, data, callback
+  getPermissionSet : (callback)->
+    @fetchPermissionSet (err, permissionSet) =>
+      callback err, null if err
+      if permissionSet
+        callback null, permissionSet
+      else
+        @fetchDefaultPermissionSet callback


Guest: add a temporary if statement for guest group kudos to @ybrs

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -1063,6 +1063,10 @@
       @fetchRolesHelper delegate, callback

   updateCounts:->
+    # remove this guest shit if required
+    if @getId().toString() is "51f41f195f07655e560001c1"
+      return callback null
+
     Relationship.count
       as         : 'member'
       targetName : 'JAccount'


Port waitfor.coffee to PhantomJS 1.2

Port waitfor.coffee to PhantomJS 1.2

--- examples/waitfor.coffee
+++ examples/waitfor.coffee
@@ -1,40 +1,52 @@
-###
- Wait until the test condition is true or a timeout occurs. Useful for waiting
- on a server response or for a ui change (fadeIn, etc.) to occur.
-
- @param testFx javascript condition that evaluates to a boolean,
- it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
- as a callback function.
- @param message a message describing e.g. the ui change
- @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
-###
-waitFor = (testFx, message, maxtimeOutMillis = 3000) ->
+##
+# Wait until the test condition is true or a timeout occurs. Useful for waiting
+# on a server response or for a ui change (fadeIn, etc.) to occur.
+#
+# @param testFx javascript condition that evaluates to a boolean,
+# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
+# as a callback function.
+# @param onReady what to do when testFx condition is fulfilled,
+# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
+# as a callback function.
+# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
+##
+waitFor = (testFx, onReady, timeOutMillis=3000) ->
     start = new Date().getTime()
     condition = false
-    while (new Date().getTime() - start) < maxtimeOutMillis
-        phantom.sleep(250)
-        if typeof(testFx) is "string"
-            condition = eval testFx
+    interval = setInterval ->
+        if (new Date().getTime() - start < timeOutMillis) and not condition
+            # If not time-out yet and condition not yet fulfilled
+            condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
         else
-            condition = testFx()
-        if condition
-            break
-    if not condition
-        console.log "Timeout: " + message
-        phantom.exit 1
+            if not condition
+                # If condition still not fulfilled (timeout but condition is 'false')
+                console.log "'waitFor()' timeout"
+                phantom.exit(1)
+            else
+                # Condition fulfilled (timeout and/or condition is 'true')
+                console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
+                if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
+                clearInterval interval #< Stop this interval
+    , 250 #< repeat check every 250ms
+
+
+page = new WebPage()
+
+# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
+page.onConsoleMessage = (msg) ->
+    console.log msg
+
+# Open Twitter on 'sencha' profile and, onPageLoad, do...
+page.open 'http://twitter.com/#!/sencha', (status) ->
+    # Check for page load success
+    if status isnt 'success'
+        console.log 'Unable to access network'
     else
-        console.log message
-        console.log "+++ waitUntil finished in " + (new Date().getTime() - start) + " millis."
-
-# example use:
-if not phantom.state
-    # load a twitter page
-    phantom.state = "loaded"
-    phantom.open "http://twitter.com/#!/senchainc"
-else
-    # click the "sign in" link
-    $(".signin-link").click()
-
-    # wait for the sign in dialog to pop up
-    waitFor (-> $("#signin-dropdown").is ":visible"), "The sign-in dialog should be visible"
-    phantom.exit()
+        # Wait for 'signin-dropdown' to be visible
+        waitFor ->
+            # Check in the page if a specific element is now visible
+            page.evaluate ->
+                $('#signin-dropdown').is ':visible'
+        , ->
+           console.log 'The sign-in dialog should be visible now.'
+           phantom.exit()


Standardizing access to `crawler` variable

--- www/src/theoricus/core/processes.coffee
+++ www/src/theoricus/core/processes.coffee
@@ -184,7 +184,7 @@
         @_run_pending_processes()
     else
       @locked = false
-      window.crawler.is_rendered = true
+      @the.crawler.is_rendered = true

       if @disable_transitions?
         @the.config.disable_transitions = @disable_transitions


refactor momentum calcuation

refactor momentum calcuation

--- js/umobi.scroller.coffee
+++ js/umobi.scroller.coffee
@@ -12,7 +12,12 @@

   class Scroller
     constructor: (@element) ->
+
+      # first touch offset Y from touchstart event.
       @startTouchY = 0
+
+      # last touch offset Y from touchmove event.
+      @lastTouchY          = 0
       @contentStartOffsetY = 0
       @element.addEventListener('touchstart', this, false)
       @element.addEventListener('touchmove', this, false)
@@ -38,9 +43,13 @@
       return if not @isDragging
       console.log 'onTouchMove', { touchY: e.touches[0].clientY , contentStartOffsetY: @contentStartOffsetY }

-      currentY = e.touches[0].clientY
-      deltaY = currentY - @startTouchY
-      newY = deltaY + @contentStartOffsetY
+      currentY    = e.touches[0].clientY
+      deltaY      = currentY - @startTouchY
+      newY        = deltaY   + @contentStartOffsetY
+      @lastTouchY = currentY
+      newY = 30 if newY > 30
+      # @startTouchY = currentY
+      # return
       @animateTo(newY)
       @contentLastOffsetY = newY

@@ -72,7 +81,12 @@

     isDecelerating: -> true

-    shouldStartMomentum: -> true
+    shouldStartMomentum: ->
+      return true
+      # @lastTouchY
+      contentOffsetY = @getContentOffsetY()
+      return false if contentOffsetY > 30
+      return true

     stopMomentum: () ->
       if @isDecelerating()
@@ -85,25 +99,33 @@
         # Set the element transform to where it is right now.
         @animateTo(transform.m42)

-    startMomentum: () ->
-      # Calculate the movement properties. Implement getEndVelocity using the
-      # start and end position / time.
+    # Calculate the movement properties. Implement getEndVelocity using the
+    # start and end position / time.
+    calculateMomentum: () ->
       velocity = @getEndVelocity()
       acceleration = if velocity < 0 then 0.0005 else -0.0005
       displacement = - (velocity * velocity) / (2 * acceleration)
       time = - velocity / acceleration
+      newY = @contentOffsetY + displacement
+      return {
+        velocity: velocity
+        acceleration: acceleration
+        displacement: displacement
+        time: time
+        newY: newY
+      }

-      console.log "startMomentum" , { velocity: velocity , acceleration: acceleration }
+    startMomentum: () ->
+      m = @calculateMomentum()

       # Set up the transition and execute the transform. Once you implement this
       # you will need to figure out an appropriate time to clear the transition
       # so that it doesn’t apply to subsequent scrolling.
       # @element.style.webkitTransition = '-webkit-transform ' + time + 'ms cubic-bezier(0.33, 0.66, 0.66, 1)'
-      @element.style.webkitTransition = '-webkit-transform ' + 1000 + 'ms cubic-bezier(0.33, 0.66, 0.66, 1)'
-
-      newY = @contentOffsetY + displacement
-      @element.style.webkitTransform = 'translate3d(0,' + newY + 'px, 0)'
-      @contentOffsetY = newY
+      @element.style.webkitTransition = '-webkit-transform ' + m.time + 'ms cubic-bezier(0.33, 0.66, 0.66, 1)'
+      @element.style.webkitTransform = 'translate3d(0,' + m.newY + 'px, 0)'
+      @contentOffsetY = m.newY
+      console.log "startMomentum", m

     snapToBounds: () ->


coding

coding

--- lib/generators/webrtc_rails/install/templates/main.js.coffee
+++ lib/generators/webrtc_rails/install/templates/main.js.coffee
@@ -176,7 +176,7 @@
       return
     @_peerConnection.createAnswer(
       (sessionDescription) =>
-        @_peerConnection.setLocalDescription sessionDescription
+        @_peerConnection.setLocalDescription(sessionDescription)
         @_sendSDP(sessionDescription)
       ->
         console.log('Create Answer failed')


remove JSON parsing (done in store)

remove JSON parsing (done in store)

--- src/components/navbar/server-error-monitoring.cjsx
+++ src/components/navbar/server-error-monitoring.cjsx
@@ -135,11 +135,9 @@
     return unless error and -1 is window.location.search.indexOf('reloaded')
     message = {}
     handler = 'default'
-    if error.message
-      try
-        message = JSON.parse(error.message)
-      catch e

+    if _.isObject(error.message)
+      {message} = error
       if message.errors?.length is 1 and ERROR_HANDLERS[message.errors[0].code]
         handler = message.errors[0].code


Added  mark-active class instead of input boxes

--- lib/package-list-packages-view.coffee
+++ lib/package-list-packages-view.coffee
@@ -6,26 +6,30 @@

   @content: (items) ->
     if items.length > 0
-      @div class: 'overlay from-top', id: 'package-list-container',  style: '300px; width: 300px',  =>
-        for item in items
-          @li =>
-            @span =>
-              @input type: 'checkbox', id: item
-              @span item
+      @div class: 'overlay from-top select-list', id: 'package-list-container', =>
+        @ol class: 'list-group mark-active', =>
+          for item in items
+            @li class: 'active', click: 'activatePackage', item
         @div class: 'block', =>
           @span class: 'pull-left', =>
             @button class: 'btn btn-success inline-block-tight gp-confirm-button', click: 'confirmList', 'Confirm'
           @span class: 'pull-right', =>
             @button class: 'btn btn-error inline-block-tight gp-cancel-button', click: 'abort', 'Cancel'
-     else
-        utils.displayMessage('All package from the list are already installed!', 1500)
+    else
+      @div
+      utils.displayMessage('All package from the list are already installed!', 1500)

-
+  activatePackage: ->
+    packageItem = event.target
+    if packageItem.className == 'active'
+      packageItem.className = ''
+    else
+      packageItem.className = 'active'

   confirmList: ->
     packagesToInstall = []
-    for item in $("#package-list-container").find('input:checked')
-      packagesToInstall.push item.id
+    for item in $("#package-list-container").find('.active')
+      packagesToInstall.push item.innerHTML

     utils.installPackageList packagesToInstall
     @detach()


Compiler: correction output path

Compiler: correction output path

--- lib/plugin/compilers/i18n.json.coffee
+++ lib/plugin/compilers/i18n.json.coffee
@@ -115,7 +115,7 @@
         """
       compiler_configuration.templates_registered_for.push helpers.getCompileStepArchAndPackage(compileStep)

-  output_path = input_path.replace /json$/, "js"
+  output_path = compileStep.rootOutputPath + compileStep.inputPath.replace /json$/, "js"
   compileStep.addJavaScript
     path: output_path,
     sourcePath: input_path,


Kite: fix style issues

Kite: fix style issues

--- workers/social/lib/social/models/kodingkey.coffee
+++ workers/social/lib/social/models/kodingkey.coffee
@@ -103,17 +103,19 @@
     return new KodingError "Key is not valid" unless @authCheckKey key
     return new KodingError "Data is not valid" unless username and hostname

-    JKodingKey.one {key:key}, (err, kodingKey)=>
+    JKodingKey.one {key}, (err, kodingKey)=>
       if err
         console.warn "Error occured while fetching koding-key username: #{username}, key: #{key}, err :#{err}"
         return callback new KodingError "There is a problem with your key"

       if kodingKey
         errMessage = "Authentication already established with #{kodingKey.hostname}!"
-        return callback new KodingError errMessage
+        error = new KodingError errMessage
+        error.code = 201
+        return callback error

       # if not created before, create here
-      JKodingKey.createKeyByUser {username, hostname, key}, (err, data)=>
+      JKodingKey.createKeyByUser {username, hostname, key}, (err, data)->
         if err
           console.warn "Error occured while creating koding key - Err: #{err}, "
           return callback new KodingError "An error occured while saving your key, please try again later"


Drop local Atom settings

Drop local Atom settings

--- tag-atom/atom/config.cson
+++ tag-atom/atom/config.cson
@@ -10,10 +10,3 @@
   'editor':
     'fontFamily': 'Inconsolata'
   'linter': {}
-  'exception-reporting':
-    'userId': '9414cc1b-fc84-82ec-55d4-75d5d0a3639d'
-  'remember-session':
-    'x': 0
-    'y': 66
-    'width': 1920
-    'height': 1014


Disable button on submit

Disable button on submit

--- resources/assets/coffee/react/beatmap-discussions/post.coffee
+++ resources/assets/coffee/react/beatmap-discussions/post.coffee
@@ -31,6 +31,7 @@

     @state =
       editing: false
+      posting: false
       message: @props.post.message

@@ -127,7 +128,7 @@
       @setState editing: false
       return

-    LoadingOverlay.show()
+    @setState posting: true

     @xhr.updatePost?.abort()
     @xhr.updatePost = $.ajax laroute.route('beatmap-discussion-posts.update', beatmap_discussion_post: @props.post.id),
@@ -142,7 +143,7 @@

     .fail osu.ajaxError

-    .always LoadingOverlay.hide
+    .always => @setState posting: false

   editStart: =>
@@ -278,12 +279,16 @@
           div className: "#{bn}__action",
             el BigButton,
               text: osu.trans 'common.buttons.cancel'
-              props: onClick: @editEnd
+              props:
+                onClick: @editEnd
+                disabled: @state.posting

           div className: "#{bn}__action",
             el BigButton,
               text: osu.trans 'common.buttons.save'
-              props: onClick: @throttledUpdatePost
+              props:
+                onClick: @throttledUpdatePost
+                disabled: @state.posting

   permalink: (e) =>


Change popup position

Change popup position

--- src/app/app.coffee
+++ src/app/app.coffee
@@ -62,7 +62,7 @@
     }, {
       type: ntype
       allow_dismiss: true
-      placement: {from: "top", align: "center"}
+      placement: {from: "bottom", align: "center"}
       delay: 2
       offset: {x: 20, y: 50}
       showProgressbar: true


Updated tests for project controller

Updated tests for project controller

--- spec/javascripts/unit/controllers/project_ctrl_spec.js.coffee
+++ spec/javascripts/unit/controllers/project_ctrl_spec.js.coffee
@@ -15,6 +15,30 @@
     it 'should not redirect to /', ->
       expect(@$location.path).not.toHaveBeenCalledWith('/')

+    describe 'should initialize vairables', ->
+
+      it 'should get projects list'
+      it 'should set defult vairables'
+      it 'should assign functions to scope'
+
+    describe '#addProject', ->
+      it 'should save progect'
+      it 'should handle errors'
+
+    describe '#editProject', ->
+      it 'should initialize editing'
+
+    describe '#cancelEditing', ->
+      it 'should cancel editing'
+
+    describe '#updateProject', ->
+      it 'should update progect'
+      it 'should handle errors'
+
+    describe '#destroyProject', ->
+      it 'should destroy progect'
+      it 'should handle errors'
+
   describe 'when not authenticated', ->
     beforeEach ->
       @Auth.isAuthenticated.and.returnValue(false)


Don't do anything when dragging unless it's a valid tab event

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -242,7 +242,7 @@
     return unless @draggedTab
     @lastDropTargetIndex = null

-    event.dataTransfer.setData 'atom-event', 'true'
+    event.dataTransfer.setData 'atom-tab-event', 'true'

     @draggedTab.element.classList.add('is-dragging')
     @draggedTab.destroyTooltip()
@@ -302,7 +302,7 @@

   onDragOver: (event) ->
     event.preventDefault()
-    unless isAtomEvent(event)
+    unless isAtomTabEvent(event)
       event.stopPropagation()
       return

@@ -348,7 +348,7 @@
   onDrop: (event) ->
     event.preventDefault()

-    return unless event.dataTransfer.getData('atom-event') is 'true'
+    return unless isAtomTabEvent(event)

     fromWindowId  = parseInt(event.dataTransfer.getData('from-window-id'))
     fromPaneId    = parseInt(event.dataTransfer.getData('from-pane-id'))
@@ -394,12 +394,14 @@

   # Show the tab bar when a tab is being dragged in this pane when alwaysShowTabBar = false
   onPaneDragEnter: (event) ->
+    return unless isAtomTabEvent(event)
     return if @pane.getItems().length > 1 or atom.config.get('tabs.alwaysShowTabBar')
     if @paneElement.contains(event.relatedTarget)
       @element.classList.remove('hidden')

   # Hide the tab bar when the dragged tab leaves this pane when alwaysShowTabBar = false
   onPaneDragLeave: (event) ->
+    return unless isAtomTabEvent(event)
     return if @pane.getItems().length > 1 or atom.config.get('tabs.alwaysShowTabBar')
     unless @paneElement.contains(event.relatedTarget)
       @element.classList.add('hidden')
@@ -546,9 +548,9 @@
       else
         currentElement = currentElement.parentElement

-isAtomEvent = (event) ->
+isAtomTabEvent = (event) ->
   for item in event.dataTransfer.items
-    if item.type is 'atom-event'
+    if item.type is 'atom-tab-event'
       return true

   return false


[optimizer] Remove extraneous logging

[optimizer] Remove extraneous logging


feat(regexp): add type params

feat(regexp): add type params

type will be equal to E, W or I.
Does not break linter api.


updated cc-dash spec

updated cc-dash spec

--- test/components/cc-dashboard/dashboard.spec.coffee
+++ test/components/cc-dashboard/dashboard.spec.coffee
@@ -100,7 +100,7 @@
             completed_percentage: 1.10

       Testing.renderComponent(SectionProgress, options).then ({dom}) ->
-        expect(dom.querySelector('.reading-progress-bar').attributes.label.value).to.equal('100% completed')
+        expect(dom.querySelector('.reading-progress-bar span span').innerHTML).to.equal('100% completed')

     it 'hides complete progress bar when 0% complete', ->
       options =
@@ -120,7 +120,7 @@
           performance: 1.0

       Testing.renderComponent(SectionPerformance, options).then ({dom}) ->
-        expect(dom.querySelector('.progress-bar-correct').attributes.label.value).to.be.equal('100% correct')
+        expect(dom.querySelector('.progress-bar-correct span span').innerHTML).to.be.equal('100% correct')
         expect(dom.querySelector('.progress-bar-incorrect')).to.be.null

     it 'hides correct progress bar when all incorrect', ->
@@ -129,7 +129,7 @@
           performance: 0.0

       Testing.renderComponent(SectionPerformance, options).then ({dom}) ->
-        expect(dom.querySelector('.progress-bar-incorrect').attributes.label.value).to.be.equal('100% incorrect')
+        expect(dom.querySelector('.progress-bar-incorrect span span').innerHTML).to.be.equal('100% incorrect')
         expect(dom.querySelector('.progress-bar-correct')).to.be.null


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -12,7 +12,7 @@
     width: 32
     height: 32

-  obj.include ActiveBou
+  obj.include ActiveBounds

 test "should remove objects outside of activeBounds", 2, ->
   obj = GameObject
@@ -21,7 +21,7 @@
     width: 32
     height: 32

-  obj.include(ActiveBounds)
+  obj.include ActiveBounds

   destroySpy = false


test for non-Error errors (failing)

test for non-Error errors (failing)

--- test/crashpad.test.coffee
+++ test/crashpad.test.coffee
@@ -25,10 +25,10 @@
         next new Error('what happened!?')

     beforeEach (done) ->
-      @request.get 'error', (err, @response) =>
+      @request.get '/error', (err, @response) =>
         done()

-    it 'retursn with a 500 status code', ->
+    it 'returns with a 500 status code', ->
       expect(@response.statusCode).to.equal 500

     it "returns with a json-formatted body", ->
@@ -48,7 +48,7 @@
         next error

     beforeEach (done) ->
-      @request.get 'error', (err, @response) =>
+      @request.get '/error', (err, @response) =>
         done()

     it "returns with the supplied status", ->
@@ -70,7 +70,7 @@
           foo: 'bar'

     beforeEach (done) ->
-      @request.get 'error', (err, @response) =>
+      @request.get '/error', (err, @response) =>
         done()

     it "returns with the status code", ->
@@ -84,3 +84,22 @@

     it "returns with the correct headers", ->
       expect(@response.headers).to.have.property 'www-authenticate', 'sample ttl="0", cache="", foo="bar", error="get off my lawn!"'
+
+
+  describe 'non-Error errors', ->
+    withServer (app) ->
+      app.get '/error', (req, res, next) ->
+        next 'poorly implemented error'
+
+    beforeEach (done) ->
+      @request.get '/error', (err, @response) =>
+        done()
+
+    it 'returns with a 500 status code', ->
+      expect(@response.statusCode).to.equal 500
+
+    it "returns with a json-formatted body", ->
+      expect(@response.body).to.deep.equal
+        statusCode: 500
+        error: 'Internal Server Error'
+        message: 'An internal server error occurred'


Add test for when input.read() returns a non-string

--- test/document_test.coffee
+++ test/document_test.coffee
@@ -1,20 +1,17 @@
 treeSitter = require "tree-sitter"
 assert = require "assert"
 compiler = require ".."
-
-require("segfault-handler").registerHandler()
+{ repeat } = compiler.rules

 describe "Document", ->
   document = null
-  language = null

-  before ->
-    grammar = compiler.grammar
-      name: "test"
-      rules:
-        the_rule: -> "stuff"
-
-    language = compiler.compileAndLoad(grammar)
+  language = compiler.compileAndLoad(compiler.grammar
+    name: "test"
+    rules:
+      sentence: -> repeat(@word)
+      word: -> "the-word"
+  )

   beforeEach ->
     document = new treeSitter.Document()
@@ -44,7 +41,12 @@
         document.setInput({
           read: ->
             @_readIndex++
-            ["st", "u", "ff", "", ""][@_readIndex - 1]
+            [
+              "the", "-", "word",
+              " ",
+              "the", "-", "word",
+              ""
+            ][@_readIndex - 1]

           seek: (n) ->
             0
@@ -52,7 +54,30 @@
           _readIndex: 0,
         })

-        assert.equal("(the_rule)", document.rootNode())
+        assert.equal("(sentence (word) (word))", document.rootNode().toString())
+
+      describe "when the input.read() returns something other than a string", ->
+        it "stops reading", ->
+          input = {
+            read: ->
+              @_readIndex++
+              [
+                "the", "-", "word",
+                {},
+                "the", "-", "word",
+                " "
+              ][@_readIndex - 1]
+
+            seek: (n) ->
+              0
+
+            _readIndex: 0,
+          }
+
+          document.setInput(input)
+
+          assert.equal("(sentence (word))", document.rootNode().toString())
+          assert.equal(4, input._readIndex)

     describe "when the supplied object does not implement #seek(n)", ->
       it "throws an exception", ->


assert basic confirm labels and classes

assert basic confirm labels and classes

--- tests/confirm.test.coffee
+++ tests/confirm.test.coffee
@@ -47,6 +47,14 @@
           it "creates a dialog object", ->
             expect(@dialog).to.be.an "object"

+          it "adds the correct button labels", ->
+            expect(@dialog.find(".btn:first").text()).to.equal "Cancel"
+            expect(@dialog.find(".btn:last").text()).to.equal "OK"
+
+          it "adds the correct button classes", ->
+            expect(@dialog.find(".btn:first").hasClass("btn-default")).to.be.true
+            expect(@dialog.find(".btn:last").hasClass("btn-primary")).to.be.true
+
     describe "with two arguments", ->
       describe "where the second argument is not a function", ->
         beforeEach ->
@@ -67,4 +75,12 @@
         it "creates a dialog object", ->
           expect(@dialog).to.be.an "object"

+        it "adds the correct button labels", ->
+          expect(@dialog.find(".btn:first").text()).to.equal "Cancel"
+          expect(@dialog.find(".btn:last").text()).to.equal "OK"
+
+        it "adds the correct button classes", ->
+          expect(@dialog.find(".btn:first").hasClass("btn-default")).to.be.true
+          expect(@dialog.find(".btn:last").hasClass("btn-primary")).to.be.true
+
   describe "configuration options tests", ->


first 2 stage test for loader working (still very verbose, need some frameworkisation)

--- tests/loader/start.coffee
+++ tests/loader/start.coffee
@@ -1,59 +1,212 @@
-connect = require('connect')
 mock = require("mock-fs")
 fs = require("fs")
 path = require("path")
 yaml = require("js-yaml")
+connect = require("connect")
+http = require("http")
+route = require("connect-route")
+
 spa = require("../../lib")

-mount = (dirname) ->
-    result = {}
+http.ServerResponse.prototype.redirect = (target) ->
+    @statusCode = 307
+    @setHeader('Location', target)
+    @end('Redirecting to ' + connect.utils.escape(target));
+
+http.ServerResponse.prototype.fail = () ->
+    @session.state = "failed"
+    @statusCode = 307
+    @setHeader('Location', "/")
+    @end('Redirecting to ' + connect.utils.escape(target));
+
+mount = (target, name, dirname) ->
+    result = target[name] ?= {}
     for name in fs.readdirSync(dirname)
         continue if name is "."
         continue if name is ".."
         child = path.join(dirname, name)
         stats = fs.statSync(child)
         if stats.isDirectory()
-            result[name] = mount(child)
+            mount(result, name, child)
         if stats.isFile()
             result[name] = fs.readFileSync(child)
     return result

+app = connect()
+    .use connect.logger()
+    .use connect.cookieParser()
+    .use connect.cookieSession
+        secret: 'spa:test!'
+        cookie:
+            maxAge: 1000
+
+    .use route (router) ->
+
+        router.get '/', (req, res, next) ->
+            unless req.session.state?
+                req.session.results ?= []
+                req.session.state = "do_next"
+                return res.redirect("/next")
+
+            state = req.session.state
+            test = req.session.test
+            phase = req.session.phase
+
+            console.log("\n## -- >> #{state}:#{test}:#{phase}\n")
+
+            switch state
+                when "do_before"
+                    req.session.state = "before_done"
+                    filename = path.join("/testimonial", test, "before.html")
+                    fs.readFile filename, (error, data) ->
+                        throw error if error?
+                        res.end(data)
+                when "do_run", "run_done"
+                    req.session.state = "run_done"
+                    filename = path.join("/testimonial", test, phase, "index.html")
+                    fs.readFile filename, (error, data) ->
+                        throw error if error?
+                        res.end(data)
+                when "success"
+                    req.session.results.push("success:#{test}:#{phase}")
+                    req.session.state = "do_next"
+                    res.redirect("/next")
+                when "failed"
+                    req.session.results.push("failed:#{test}:#{phase}")
+                    req.session.state = "do_next"
+                    res.redirect("/next")
+                when "all_done"
+                    req.session.state = null
+                    res.end(JSON.stringify(req.session.results, null, "  "))
+
+        router.get "/manifest.json", (req, res, next) ->
+            return res.fail() unless req.session.state is "run_done"
+            test = req.session.test
+            phase = req.session.phase
+            filename = path.join("/testimonial", test, phase, "manifest.json")
+            fs.readFile filename, encoding: "utf-8", (error, data) ->
+                throw error if error?
+                console.log("\nMANIFEST\n#{data}\n")
+                res.end(data)
+
+        router.get "/before", (req, res, next) ->
+            return res.fail() unless req.session.state is "before_done"
+            req.session.state = "do_run"
+            res.redirect("/")
+
+        router.get "/next", (req, res, next) ->
+            test = req.session.test
+            phase = req.session.phase
+
+            unless test?
+                req.session.state = "do_before"
+                req.session.test = "test1"
+                req.session.phase = "phase1"
+
+            switch test
+                when "test1"
+                    switch phase
+                        when "phase1"
+                            req.session.state = "do_run"
+                            req.session.phase = "phase2"
+                        when "phase2"
+                            req.session.state = "all_done"
+
+            res.redirect("/")
+
+        router.get "/test1/phase1", (req, res, next) ->
+            return res.fail() unless req.session.state is "run_done"
+            return res.fail() unless req.session.test is "test1"
+            return res.fail() unless req.session.phase is "phase1"
+            req.session.state = "success"
+            res.redirect("/")
+
+        router.get "/test1/phase2", (req, res, next) ->
+            return res.fail() unless req.session.state is "run_done"
+            return res.fail() unless req.session.test is "test1"
+            return res.fail() unless req.session.phase is "phase2"
+            req.session.state = "success"
+            res.redirect("/")
+
+        router.get "/favicon.ico", (req, res, next) ->
+            res.statusCode = 404
+            res.end()
+
+    .use connect.static("/testimonial", redirect: false)
+
+    .use (req, res, next) -> res.fail()
+
 system = yaml.safeLoad("""
+
     testimonial:
         test1:
+            before.html: |
+                <script>
+                    window.onload = function() {
+                        localStorage.clear();
+                        location.replace("/before");
+                        };
+                </script>
             phase1:
                 a.js: |
-                    var b = require("/b");
-                b.js: |
-                    var loader = require("loader")
+                    var loader = require("loader");
+                    var phase = "/test1/phase1";
                     loader.onApplicationReady = function() {
-                        console.log("Now I'm ready!");
+                        console.log(phase, "onApplicationReady");
                         loader.checkUpdate();
-                    }
+                    };
+                    loader.onUpdateFound = function() {
+                        // This time we run code of previously loaded phase1
+                        // at startup of phase2. How to check this WTF???
+                        console.log(phase, "onUpdateFound");
+                        loader.startUpdate();
+                    };
+                    loader.onUpToDate = function() {
+                        console.log(phase, "onUpToDate");
+                        location.replace(phase)
+                    };
                 spa.yaml: |
                     root: "./"
-                    manifest: "/testimonial/manifest.json"
-                    index: "/testimonial/index.html"
+                    manifest: "./manifest.json"
+                    index: "./index.html"
                     assets:
                         template: /assets/index.tmpl
                         loader: /assets/loader.js
                         md5: /assets/md5.js
                     hosting:
-                        "/(**/*.js)": "http://127.0.0.1:8010/test1/phase1/$1"
+                        "/a.js": "/test1/phase1/a.js"
+            phase2:
+                a.js: |
+                    var loader = require("loader");
+                    var phase = "/test1/phase2";
+                    loader.onApplicationReady = function() {
+                        console.log(phase, "onApplicationReady");
+                        loader.checkUpdate();
+                    };
+                    loader.onUpdateFound = function() {
+                        console.log(phase, "onUpdateFound", "FAIL!!");
+                    };
+                    loader.onUpToDate = function() {
+                        console.log(phase, "onUpToDate");
+                        location.replace(phase)
+                    };
+                spa.yaml: |
+                    root: "./"
+                    manifest: "./manifest.json"
+                    index: "./index.html"
+                    assets:
+                        template: /assets/index.tmpl
+                        loader: /assets/loader.js
+                        md5: /assets/md5.js
+                    hosting:
+                        "/a.js": "/test1/phase2/a.js"
     """)
-system["assets"] = mount(path.resolve(__dirname, "../../lib/assets"))
+mount(system, "assets", path.resolve(__dirname, "../../lib/assets"))

 process.chdir("/")
 mock(system)

-builder = spa.Builder.from_config("/testimonial/test1/phase1/spa.yaml")
-builder.build()
-
-app = connect()
-    .use (req, res, next) ->
-        console.log(req.method + " " + req.url)
-        try
-        finally
-            next()
-    .use(connect.static("/testimonial"))
+spa.Builder.from_config("/testimonial/test1/phase1/spa.yaml").build()
+spa.Builder.from_config("/testimonial/test1/phase2/spa.yaml").build()
+
 connect.createServer(app).listen(8010)


Didn't use imported name.

Didn't use imported name.

--- tests/youtube-info.coffee
+++ tests/youtube-info.coffee
@@ -2,7 +2,7 @@

 helper = new Helper('../scripts/youtube-info.coffee')
 expect = require('chai').expect
-stub = require('sinon')
+sinon = require('sinon')

 describe 'when user links', ->
   room = null


First hack at using geoNear to find cameras around the device with distance to each data.

--- prod/src/coffee-script/node/server.coffee
+++ prod/src/coffee-script/node/server.coffee
@@ -2,6 +2,10 @@

 # Can't figure out how else to use project-local module with Zappa.
 def mongoose: require "#{process.cwd()}/node_modules/mongoose"
+
+# Used for spherical calculations.  According to WolframAlpha.
+def radiusOfEarthMiles: 3956.6
+def feetInAMile: 5280

 get '/': ->
     # Define the mongoose schema.
@@ -46,14 +50,25 @@
         socket.on 'message', (raw) ->
             msg = JSON.parse raw
             console.log msg
+
+            # A message from the server.
             if msg.message
                 $('div[data-role="content"]')
                     .append $('<p>').text "#{msg.message.text}"
+
+            # A result from the server based on current position.
             if msg.currentPosition
+                # Show sensible units for accuracy.  Feet if under a half
+                # mile, miles if over.
+                if msg.currentPosition.position.coords.accuracy > 2640
+                    accuracy = "#{(parseFloat(msg.currentPosition.position.coords.accuracy, 10) / 5280).toFixed 2} miles"
+                else
+                    accuracy = "#{msg.currentPosition.position.coords.accuracy} feet"
+
                 $('p#stats').text """It looks like you're at
-(#{msg.currentPosition.position.coords.latitude}, #{msg.currentPosition.position.coords.longitude}), give or take #{msg.currentPosition.position.coords.accuracy} feet and that there's at least #{msg.currentPosition.cameras.length} cameras nearby."""
+(#{msg.currentPosition.position.coords.latitude}, #{msg.currentPosition.position.coords.longitude}), within an accuracy of #{accuracy} and that there's at least #{msg.currentPosition.cameras.results.length} cameras within a distance of #{msg.currentPosition.cameras.maxDistance} miles at #{new Date(msg.currentPosition.position.timestamp)}."""

-                for camera in msg.currentPosition.cameras
+                for camera in msg.currentPosition.cameras.results
                     $('ul#cam-list').append($('script#cam-item').tmpl(camera))
                 $('ul#cam-list').listview 'refresh'

@@ -73,12 +88,42 @@
 # Use the current position to do a geospatial lookup of available cameras.
 msg currentPosition: ->
     pos = [@position.coords.latitude, @position.coords.longitude]
-    console.log {loc: $near: pos, $maxDistance: .1}
-    app.CameraModel.find {loc: $near: pos, $maxDistance: .1}, (err, docs) =>
+
+    # Old, dumb geospatial query.
+    # query = loc: $near: pos, $maxDistance: .2
+    # console.log query
+    # app.CameraModel.find query, (err, docs) =>
+    #     if err
+    #         send 'message', text: JSON.stringify err
+    #     else
+    #         send 'currentPosition', position: @position, cameras: docs
+
+    # For now, let's base the max distance on the accuracy of the location we
+    # have.
+    # maxDistance = parseFloat(@position.coords.accuracy, 10) / feetInAMile / radiusOfEarthMiles
+
+    # Or, pick (user set?) a distance
+    maxDistanceInMiles = 4
+    maxDistanceInRadians = maxDistanceInMiles / radiusOfEarthMiles
+
+    # Construct a new, hot geospatial query for nearest cameras.
+    query =
+        geoNear: 'cameras' # Collection name.
+        near: pos
+        distanceMultiplier: radiusOfEarthMiles # Get distances back in miles.
+        spherical: true # We're dealing with the surface of the Earth!
+        maxDistance: maxDistanceInRadians # Spherical requires radians.
+        # num: 10 # Don't give back more than this, no matter what.
+
+    console.log query
+    mongoose.connection.db.executeDbCommand query, (err, docs) =>
         if err
             send 'message', text: JSON.stringify err
         else
-            send 'currentPosition', position: @position, cameras: docs
+            cameras = docs.documents[0]
+            cameras.maxDistance = maxDistanceInMiles
+            console.log cameras
+            send 'currentPosition', position: @position, cameras: cameras

 # Default view
 view ->
@@ -125,5 +170,6 @@
                 div class: 'ui-btn-inner ui-li', ->
                     div class: 'ui-btn-text', ->
                         a class: 'ui-link-inherit', ->
-                            img class: 'ui-li-thumb', src: '${url}', alt: 'M.I.A.'
-                            h3 class: 'ui-li-heading', '${name}'
+                            img class: 'ui-li-thumb', src: '${obj.url}', alt: 'M.I.A.'
+                            h3 class: 'ui-li-heading', '${obj.name}'
+                            p class: 'ui-li-desc', '${dis.toFixed(2)} miles away'


clear query params when transitioning to taxon concept

--- app/assets/javascripts/species/controllers/taxon_concepts_controller.js.coffee
+++ app/assets/javascripts/species/controllers/taxon_concepts_controller.js.coffee
@@ -50,7 +50,12 @@
       @get('controllers.search').set('redirected', false)
     m = Species.TaxonConcept.find(taxonConceptId)
     @transitionToRoute('taxonConcept.legal', m, {queryParams:
-      {taxon_concept_query: false, page: false}
+      {
+        taxon_concept_query: false,
+        geo_entities_ids: false,
+        geo_entity_scope: false,
+        page: false
+      }
     })

   actions:


ActivityListHeader: Fixed settings flag for activityController.

--- client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
+++ client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
@@ -48,7 +48,7 @@
         size         : "tiny"
         callback     : (state) =>
           @appStorage.setValue 'showLowQualityContent', state, =>
-          KD.getSingleton('activityController').flags = showExempt: state
+          KD.getSingleton('activityController').flags.showExempt = state
           KD.getSingleton('activityController').emit 'Refresh'

       @refreshLink = new KDCustomHTMLView
@@ -64,11 +64,13 @@
         tagName: "span"

     @appStorage.fetchStorage (storage)=>
-      state = @appStorage.getValue('liveUpdates') or off
+      state             = @appStorage.getValue("liveUpdates") or off
+      lowQualityContent = @appStorage.getValue "showLowQualityContent"
+      {flags}           = KD.getSingleton "activityController"
+      flags.liveUpdates = state
+      flags.showExempt  = lowQualityContent or off
       @liveUpdateButton.setValue state
-      KD.getSingleton('activityController').flags = liveUpdates : state
-      KD.getSingleton('activityController').flags = showExempt : (@appStorage.getValue('showLowQualityContent') or off)
-      @lowQualitySwitch.setValue? @appStorage.getValue('showLowQualityContent') or off
+      @lowQualitySwitch.setValue? lowQualityContent or off

   _checkForUpdates: do (lastTs = null, lastCount = null, alreadyWarned = no) ->
     itFailed = ->


Refactoring

Refactoring

--- gulpfile.coffee/tasks/stylus.coffee
+++ gulpfile.coffee/tasks/stylus.coffee
@@ -7,19 +7,13 @@
 sync     = require 'browser-sync'
 config   = require '../config'

-src    = "#{config.src}/index.styl"
-stylus = lazypipe()
-	.pipe stylus, use: [nib()]
-	.pipe gulp.dest, config.dist
-	.pipe sync.reload, stream: true
-
 gulp.task 'stylus', ->
-	gulp.src src
+	gulp.src "#{config.src}/index.styl"
 		.pipe plumber()
-		.pipe stylus()
+		.pipe stylus(use: [nib()])
+		.pipe gulp.dest(config.dist)
+		.pipe sync.reload(stream: true)

 gulp.task 'stylus:watch', ->
-	gulp.src src
-		.pipe plumber()
-		.pipe watch(src)
-		.pipe stylus()
+	watch "#{config.src}/**/*.styl", ->
+		gulp.start 'stylus'


:green_heart: Don't use the version hack in spec mode

--- lib/color-project.coffee
+++ lib/color-project.coffee
@@ -19,7 +19,7 @@

   @deserialize: (state) ->
     version = SERIALIZE_VERSION
-    version += '-dev' if atom.inDevMode()
+    version += '-dev' if atom.inDevMode() and !atom.inSpecMode()
     state = {} if state?.version isnt version
     new ColorProject(state)


fix one document exporter bug

fix one document exporter bug

--- lib/exporter-view.coffee
+++ lib/exporter-view.coffee
@@ -115,16 +115,15 @@
       @fileNameInput.setText(filePath)

     ## select
-    $('.format-select', @element).value = atom.config.get('markdown-preview-enhanced.exportPDFPageFormat')
+    $('.format-select', @element).val atom.config.get('markdown-preview-enhanced.exportPDFPageFormat')
     $('.format-select', @element).on 'change', (e)->
       atom.config.set('markdown-preview-enhanced.exportPDFPageFormat', this.value)

-    $('.orientation-select', @element).value =
-    atom.config.get('markdown-preview-enhanced.orientation')
+    $('.orientation-select', @element).val atom.config.get('markdown-preview-enhanced.orientation')
     $('.orientation-select', @element).on 'change', (e)->
       atom.config.set('markdown-preview-enhanced.orientation', this.value)

-    $('.margin-select', @element).value = atom.config.get('markdown-preview-enhanced.marginsType')
+    $('.margin-select', @element).val atom.config.get('markdown-preview-enhanced.marginsType')
     $('.margin-select', @element).on 'change', (e)->
       atom.config.set('markdown-preview-enhanced.marginsType', this.value)

@@ -149,6 +148,10 @@
   display: (markdownPreview)->
     @markdownPreview = markdownPreview

+    if !@markdownPreview.editor
+      return
+
+
     @panel ?= atom.workspace.addModalPanel(item: this, visible: false)
     @panel.show()


Make codegen a bit neater.

Make codegen a bit neater.

--- src/codegen.coffee
+++ src/codegen.coffee
@@ -32,20 +32,17 @@
   # Set up default opts
   opts = Object.assign (defaults opts), opts

-  # No source map
-  unless opts.sourceMap
-    return escodegen.generate ast, opts
-
-  # Sourcemap wanted
-  opts.sourceMap         ?= true
-  opts.sourceMapWithCode ?= true
-  opts.sourceMapRoot     ?= opts.sourceRoot ? ''
-
   # Minify
   if opts.minify?
     esmangle  = require 'esmangle'
     optimized = esmangle.optimize ast, null
     ast       = esmangle.mangle optimized
+
+  # Source maps
+  if opts.sourceMap
+    opts.sourceMap         ?= true
+    opts.sourceMapWithCode ?= true
+    opts.sourceMapRoot     ?= opts.sourceRoot ? ''

   # Generate code, source maps
   {code, map} = escodegen.generate ast, opts
@@ -56,9 +53,17 @@
     # libraries used by strip-debug, so we pass in the generated code instead
     code = require('strip-debug')(code).toString()

+  # Return generated code without source map
+  unless opts.sourceMap
+    return code
+
+  # Return generated code with source map as comment
+  unless opts.externalSourceMap
+    return code + convert.fromObject(map).toComment()
+
   # Return object if external source map requested
-  if opts.externalSourceMap
-    code: code
-    map:  convert.fromObject(map).toJSON()
-  else
-    code + convert.fromObject(map).toComment()
+  if opts.sourceMapURL?
+    code += '\n//# sourceMappingURL=' + opts.sourceMapURL
+
+  code: code
+  map:  convert.fromObject(map).toJSON()


#164 disable wholeWord if term is single char and non-word

--- lib/provider/scan.coffee
+++ lib/provider/scan.coffee
@@ -32,12 +32,17 @@
     items

   getItems: ->
-    firstQuery = @ui.getQuery().split(/\s+/)[0]
-    if firstQuery
+    searchTerm = @ui.getQuery().split(/\s+/)[0]
+    if searchTerm
       if @searchIgnoreCaseChangedManually
-        regexp = @getRegExpForSearchTerm(firstQuery, {@searchWholeWord, @searchIgnoreCase})
+        regexp = @getRegExpForSearchTerm(searchTerm, {@searchWholeWord, @searchIgnoreCase})
       else
-        regexp = @getRegExpForSearchTerm(firstQuery, {@searchWholeWord})
+        if @searchWholeWord and (searchTerm.length is 1) and (not /\w/.test(searchTerm))
+          @searchWholeWord = false
+          @ui.controlBar.updateStateElements(wholeWordButton: @searchWholeWord)
+
+        regexp = @getRegExpForSearchTerm(searchTerm, {@searchWholeWord})
+
         if regexp.ignoreCase isnt @searchIgnoreCase
           @searchIgnoreCase = regexp.ignoreCase
           @ui.controlBar.updateStateElements(ignoreCaseButton: @searchIgnoreCase)


Forward config menu click event to focused window

Previously the Atom > Preferences... menu just logged an error message.

Now it fires a window:open-config event to the focused window.

--- lib/settings-view.coffee
+++ lib/settings-view.coffee
@@ -23,6 +23,9 @@
       new SettingsView() if filePath is configUri

     rootView.command 'settings-view:toggle', ->
+      rootView.open(configUri)
+
+    $(window).on 'window:open-config', ->
       rootView.open(configUri)

   @deserialize: ({activePanelName}={}) ->


unfuck facebook V turbolinks for great justice!

--- lib/assets/javascripts/appitude/facebook.js.coffee
+++ lib/assets/javascripts/appitude/facebook.js.coffee
@@ -28,6 +28,27 @@

 _.extend(@App, {fb: features})

+# handle turbolinks stuff!
+fb_root = null
+justiceServed = false
+
+fixFacebookWithTurbolinksForGreatJustice = ->
+  document.addEventListener 'page:fetch', copyFbRoot
+  document.addEventListener 'page:change'. restoreFbRoot
+  document.addEventListener 'page:load', ->
+    FB?.XFBML.parse()
+  justiceServed = true
+
+copyFbRoot = ->
+  $('#fb-root').detach()
+
+restoreFbRoot = ->
+  if $('#fb-root').length > 0
+    $('#fb-root').replaceWith fb_root
+  else
+    $('body').append fb_root
+
 # add the fb js script to the page
 $ ()->
-  $.getScript("//connect.facebook.net/#{features.locale}/all.js")+  $.getScript("//connect.facebook.net/#{features.locale}/all.js")
+  fixFacebookWithTurbolinksForGreatJustice() unless justiceServed


 Merge branch 'master.groups.pricing' into 'master.groups'

groups: debit a "user" pack from group's subscription before invitation is redeemed

--- workers/social/lib/social/models/invitation.coffee
+++ workers/social/lib/social/models/invitation.coffee
@@ -20,8 +20,10 @@

   {ObjectRef, dash, daisy, secure, signature} = require 'bongo'

-  KodingError = require '../error'
-  JMail       = require './email'
+  KodingError  = require '../error'
+  JMail        = require './email'
+  JGroup       = require './group'
+  JPaymentPack = require './payment/pack'

   @share()

@@ -133,9 +135,17 @@
       isRedeemed = yes
     operation.$set = status: 'redeemed'  if isRedeemed

-    @update operation, (err)=>
-      return callback err  if err
-      @addRedeemer delegate, callback
+    JGroup.one slug: @group, (err, group) =>
+      callback err  if err
+      group.fetchSubscription (err, subscription) =>
+        callback err  if err
+        JPaymentPack.one tags: "user", (err, pack) =>
+          callback err  if err
+          subscription.debit pack, (err) =>
+            callback err  if err
+            @update operation, (err) =>
+              return callback err  if err
+              @addRedeemer delegate, callback

   # send invites from group dashboard
   @create = secure (client, group, email, options, callback)->


Email: trim the email address

Email: trim the email address

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -568,6 +568,8 @@

   @changeEmailByUsername = (options, callback) ->
     { account, oldUsername, email } = options
+    # prevent from leading and trailing spaces
+    username = username.trim()
     @update { username: oldUsername }, { $set: { email }}, (err, res)=>
       return callback err  if err
       account.profile.hash = getHash email


errorize: more unification

errorize: more unification

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -422,7 +422,7 @@

         cursor.nextObject (err, data) ->
           return callback err  if err?
-          return callback { message: 'Unrecognized email' }  unless data?
+          return callback errorize 'Unrecognized email'  unless data?

           callback null, data.username
     else
@@ -464,7 +464,7 @@
         session = fetchedSession
         unless session
           console.error "login: session not found", username
-          return callback { message: "Couldn't restore your session!" }
+          return callback errorize "Couldn't restore your session!"

         bruteForceControlData =
           ip        : session.clientIP
@@ -517,7 +517,7 @@
     , ->
       # fetch account of the user, we will use it later
       JAccount.one { "profile.nickname": username }, (err, account_)->
-        return callback { message: "couldn't find account!" }  if err
+        return callback errorize "couldn't find account!"  if err
         account = account_
         queue.next()

@@ -535,7 +535,7 @@
       JInvitation = require '../invitation'
       JInvitation.byCode invitationToken, (err, invitation_) =>
         return callback err  if err
-        return callback { message: "invitation is not valid" }  unless invitation_
+        return callback errorize "invitation is not valid"  unless invitation_
         invitation = invitation_
         queue.next()

@@ -1020,7 +1020,7 @@
   @removeFromGuestsGroup = (account, callback) ->
     JGroup.one { slug: 'guests' }, (err, guestsGroup) ->
       return callback err  if err?
-      return callback message: "Guests group not found!"  unless guestsGroup?
+      return callback errorize "Guests group not found!"  unless guestsGroup?
       guestsGroup.removeMember account, callback

   createGroupStack = (account, groupName, callback)->


Missing require, kudos goes to Cihangir

Missing require, kudos goes to Cihangir

--- workers/social/lib/social/traits/followable.coffee
+++ workers/social/lib/social/traits/followable.coffee
@@ -37,6 +37,7 @@
   @fetchMyFollowees = secure (client, ids, callback)->
     return callback null  unless ids

+    JAccount = require '../models/account'
     unless client.connection.delegate instanceof JAccount
       return callback new KodingError 'Access denied'


fixed routes precedence

fixed routes precedence


Added TODO

Added TODO

--- core/app/backbone/factlink.backbone.coffee
+++ core/app/backbone/factlink.backbone.coffee
@@ -6,7 +6,7 @@
 #= require react
 #= require react.backbone

-# Replace by just 'require tether' when
+# TODO: Replace by just 'require tether' when
 # this has been merged: https://github.com/HubSpot/tether/pull/25
 #= require tether/utils
 #= require tether/tether


Re-calculate splitview sizes after viewAppended

--- client/app/Applications/Environments.kdapplication/views/domainsmainview.coffee
+++ client/app/Applications/Environments.kdapplication/views/domainsmainview.coffee
@@ -39,6 +39,8 @@

     @tabView.showPaneByIndex 0
     @domainsListViewController.on "domainItemClicked", @bound "decorateMapperView"
+
+    @utils.defer => @splitView._windowDidResize()

   buildButtonsBar: ->
     @buttonsBar = new KDView cssClass : "header"
@@ -91,11 +93,9 @@
       {domainName} = form.inputs
       domainName.setFocus()

-
     creationForm.on 'CloseClicked', =>
       @actionArea.unsetClass 'in'
       @buttonsBar.unsetClass 'out'
-

   pistachio:->
     """


Remove log

Remove log

--- lib/keybinding-resolver-view.coffee
+++ lib/keybinding-resolver-view.coffee
@@ -33,7 +33,6 @@

   attach: ->
     atom.workspaceView.prependToBottom(this)
-      console.log "ok"
     @subscribe atom.keymap, "key-binding-matched", (usedKeyBinding, unusedKeyBindings) =>
       @update(usedKeyBinding, unusedKeyBindings)


Using value of for date cmp

Using value of for date cmp

--- src/getDays.coffee
+++ src/getDays.coffee
@@ -31,8 +31,8 @@

     obj.dayCount = (startDate, endDate) ->
         one_day = 1000*60*60*24
-        startDate_ms = startDate.getTime()
-        endDate_ms = endDate.getTime()
+        startDate_ms = startDate.valueOf()
+        endDate_ms = endDate.valueOf()
         difference_ms = endDate_ms - startDate_ms
-        return 1+Math.round difference_ms/one_day
+        return 1+difference_ms/one_day
     obj


grammar: made `,->` style consistent

grammar: made `,->` style consistent

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -88,13 +88,13 @@
     # a single generic "Operand OpSymbol Operand"-type rule,
     # but in order to make the precedence binding possible, separate
     # rules are necessary.
-    o 'Expression PLUS_MINUS Expression', -> Op $2, $1, $3
-    o 'Expression MATH       Expression', -> Op $2, $1, $3
-    o 'Expression SHIFT      Expression', -> Op $2, $1, $3
-    o 'Expression COMPARE    Expression', -> Op $2, $1, $3
-    o 'Expression LOGIC      Expression', -> Op $2, $1, $3
-    o 'Expression IMPORT     Expression', -> Import $1, $3, !$2
-    o 'Expression RELATION   Expression', ->
+    o 'Expression PLUS_MINUS Expression' ,-> Op $2, $1, $3
+    o 'Expression MATH       Expression' ,-> Op $2, $1, $3
+    o 'Expression SHIFT      Expression' ,-> Op $2, $1, $3
+    o 'Expression COMPARE    Expression' ,-> Op $2, $1, $3
+    o 'Expression LOGIC      Expression' ,-> Op $2, $1, $3
+    o 'Expression IMPORT     Expression' ,-> Import $1, $3, !$2
+    o 'Expression RELATION   Expression' ,->
       return if $2.charAt(0) is '!'
       then Op($2.slice 1; $1; $3).invert()
       else Op $2, $1, $3
@@ -102,7 +102,7 @@
     o 'UNARY      Expression' , -> Op $1, $2
     o 'PLUS_MINUS Expression' ,(-> Op $1, $2), prec: 'UNARY'

-    o 'Expression ?', -> Existence $1
+    o 'Expression ?' ,-> Existence $1

     o 'CREMENT SimpleAssignable' ,-> Op $1, $2
     o 'SimpleAssignable CREMENT' ,-> Op $2, $1, null, true
@@ -119,28 +119,28 @@

     # Comprehensions can either be normal, with a block of expressions
     # to execute, or postfix, with a single expression.
-    o 'LoopHead   Block',    -> $1.addBody $2
-    o 'Statement  LoopHead', -> $2.addBody Lines $1
-    o 'Expression LoopHead', -> $2.addBody Lines $1
-
-    o 'SWITCH Expression Cases',               -> Switch $2, $3
-    o 'SWITCH Expression Cases DEFAULT Block', -> Switch $2, $3, $5
-    o 'SWITCH Cases',                          -> Switch null, $2
-    o 'SWITCH Cases DEFAULT Block',            -> Switch null, $2, $4
-
-    o 'TRY Block',                                      -> Try $2
-    o 'TRY Block CATCH IDENTIFIER Block',               -> Try $2, $4, $5
-    o 'TRY Block                        FINALLY Block', -> Try $2, null, null, $4
-    o 'TRY Block CATCH IDENTIFIER Block FINALLY Block', -> Try $2, $4, $5, $7
+    o 'LoopHead   Block'    ,-> $1.addBody $2
+    o 'Statement  LoopHead' ,-> $2.addBody Lines $1
+    o 'Expression LoopHead' ,-> $2.addBody Lines $1
+
+    o 'SWITCH Expression Cases'               ,-> Switch $2, $3
+    o 'SWITCH Expression Cases DEFAULT Block' ,-> Switch $2, $3, $5
+    o 'SWITCH Cases'                          ,-> Switch null, $2
+    o 'SWITCH Cases DEFAULT Block'            ,-> Switch null, $2, $4
+
+    o 'TRY Block'                                      ,-> Try $2
+    o 'TRY Block CATCH IDENTIFIER Block'               ,-> Try $2, $4, $5
+    o 'TRY Block                        FINALLY Block' ,-> Try $2, null, null, $4
+    o 'TRY Block CATCH IDENTIFIER Block FINALLY Block' ,-> Try $2, $4, $5, $7

     # Class definitions have optional bodies of prototype property assignments,
     # and optional references to the superclass.
-    o 'CLASS OptExtends',                        -> Class null, $2
-    o 'CLASS OptExtends Block',                  -> Class null, $2, $3
-    o 'CLASS SimpleAssignable OptExtends',       -> Class $2, $3
-    o 'CLASS SimpleAssignable OptExtends Block', -> Class $2, $3, $4
-
-    o 'SimpleAssignable EXTENDS Expression', -> Extends $1, $3
+    o 'CLASS OptExtends'                        ,-> Class null, $2
+    o 'CLASS OptExtends Block'                  ,-> Class null, $2, $3
+    o 'CLASS SimpleAssignable OptExtends'       ,-> Class $2, $3
+    o 'CLASS SimpleAssignable OptExtends Block' ,-> Class $2, $3, $4
+
+    o 'SimpleAssignable EXTENDS Expression' ,-> Extends $1, $3
   ]

   # Any list of statements and expressions,
@@ -161,7 +161,7 @@

   Arg: [
     o     'Expression'
-    o '... Expression', -> Splat $2
+    o '... Expression' ,-> Splat $2
   ]
   # **ArgList** is both the list of objects passed into a function call,
   # as well as the contents of an array literal
@@ -174,12 +174,12 @@
     o 'ArgList OptComma INDENT ArgList OptComma OUTDENT' ,-> $1.concat $4
   ]
   Array: [
-    o '[ ArgList OptComma ]', -> Arr $2
+    o '[ ArgList OptComma ]' ,-> Arr $2
   ]

   # A reference to a property on `this`.
   ThisProperty: [
-    o 'THISPROP', -> Value Literal('this'), [Access Literal $1], true
+    o 'THISPROP' ,-> Value Literal('this'), [Access Literal $1], true
   ]

   # Parenthetical expressions. Note that the **Parenthetical** is a **Value**,
@@ -187,8 +187,8 @@
   # where only values are accepted, wrapping it in parentheses will always do
   # the trick.
   Parenthetical: [
-    o '(        Body         )', -> Parens $2.unwrap()
-    o '( INDENT Body OUTDENT )', -> Parens $3.unwrap()
+    o '(        Body         )' ,-> Parens $2.unwrap()
+    o '( INDENT Body OUTDENT )' ,-> Parens $3.unwrap()
   ]

   # Pure statements which cannot be expressions.
@@ -204,8 +204,8 @@
   # will convert some postfix forms into blocks for us, by adjusting the
   # token stream.
   Block: [
-    o 'INDENT Body OUTDENT', -> $2
-    o 'INDENT      OUTDENT', -> Lines()
+    o 'INDENT Body OUTDENT' ,-> $2
+    o 'INDENT      OUTDENT' ,-> Lines()
   ]

   # **Fun** node is the function literal, defined by an indented **Block**
@@ -216,9 +216,9 @@
   ]
   # The list of parameters that a function accepts can be of any length.
   ParamList: [
-    o '',                  -> []
-    o 'Param',             -> [$1]
-    o 'ParamList , Param', -> $1.concat $3
+    o ''                  ,-> []
+    o 'Param'             ,-> [$1]
+    o 'ParamList , Param' ,-> $1.concat $3
   ]
   # A single parameter in a function definition can be ordinary, or a splat
   # that hoovers up the remaining arguments.
@@ -228,7 +228,7 @@
     o     'ParamVar ASSIGN Expression' ,-> Param $1, $3
   ]
   ParamVar: [
-    o 'IDENTIFIER', -> Literal $1
+    o 'IDENTIFIER' ,-> Literal $1
     o 'ThisProperty'
     o 'Array'
     o 'Object'
@@ -249,29 +249,29 @@
     o '...        ObjAssignable' ,-> Splat  $2
     o 'PLUS_MINUS ObjAssignable' ,-> Assign $2, Literal($1 is '+'), ':'

-    o 'COMMENT', -> Comment $1
+    o 'COMMENT' ,-> Comment $1
   ]
   # Assignment of properties within an object literal can be separated by
   # comma, as in JavaScript, or simply by newline.
   AssignList: [
-    o '',                                                       -> []
-    o 'AssignObj',                                              -> [$1]
-    o 'AssignList , AssignObj',                                 -> $1.concat $3
-    o 'AssignList OptComma TERMINATOR AssignObj',               -> $1.concat $4
-    o 'AssignList OptComma INDENT AssignList OptComma OUTDENT', -> $1.concat $4
+    o ''                                                       ,-> []
+    o 'AssignObj'                                              ,-> [$1]
+    o 'AssignList , AssignObj'                                 ,-> $1.concat $3
+    o 'AssignList OptComma TERMINATOR AssignObj'               ,-> $1.concat $4
+    o 'AssignList OptComma INDENT AssignList OptComma OUTDENT' ,-> $1.concat $4
   ]
   # In Coco, an object literal is simply a list of assignments.
   Object: [
-    o '{ AssignList OptComma }', -> Obj $2
+    o '{ AssignList OptComma }' ,-> Obj $2
   ]

   # The most basic form of *if* is a condition and an action. The following
   # if-related rules are broken up along these lines in order to avoid
   # ambiguity.
   IfBlock: [
-    o 'IF Expression Block',              -> If $2, $3, name: $1
-    o 'IfBlock ELSE IF Expression Block', -> $1.addElse If $4, $5, name: $3
-    o 'IfBlock ELSE Block',               -> $1.addElse $3
+    o 'IF Expression Block'              ,-> If $2, $3, name: $1
+    o 'IfBlock ELSE IF Expression Block' ,-> $1.addElse If $4, $5, name: $3
+    o 'IfBlock ELSE Block'               ,-> $1.addElse $3
   ]

   LoopHead: [
@@ -302,27 +302,27 @@
   ]

   Cases: [
-    o       'CASE SimpleArgs Block', -> [Case $2, $3]
-    o 'Cases CASE SimpleArgs Block', -> $1.concat Case $3, $4
+    o       'CASE SimpleArgs Block' ,-> [Case $2, $3]
+    o 'Cases CASE SimpleArgs Block' ,-> $1.concat Case $3, $4
   ]
   # Just simple, comma-separated, required arguments (no fancy syntax).
   # We need this to be separate from the **ArgList** for use in **Cases**,
   # where having the newlines wouldn't make sense.
   SimpleArgs: [
-    o 'Expression',              -> [$1]
-    o 'SimpleArgs , Expression', -> $1.concat $3
+    o 'Expression'              ,-> [$1]
+    o 'SimpleArgs , Expression' ,-> $1.concat $3
   ]

   # Optional `extends` clause for class definition.
   OptExtends: [
-    o '',              -> null
-    o 'EXTENDS Value', -> $2
+    o ''              ,-> null
+    o 'EXTENDS Value' ,-> $2
   ]

   # The **Root** is the top-level node in the syntax tree.
   # Since we parse bottom-up, all parsing must end here.
   Root: [
-    o '', -> Lines()
+    o '' ,-> Lines()
     o 'Body'
     o 'Block TERMINATOR'
   ]


:art: Give snapshot variables less confusing names

--- src/history.coffee
+++ src/history.coffee
@@ -60,9 +60,9 @@
   popUndoStack: (currentSnapshot) ->
     if (checkpointIndex = @getBoundaryCheckpointIndex(@undoStack))?
       pop = @popChanges(@undoStack, @redoStack, checkpointIndex)
-      _.defaults(pop.snapshotBefore, currentSnapshot)
+      _.defaults(pop.snapshotAbove, currentSnapshot)
       {
-        snapshot: pop.snapshotAfter
+        snapshot: pop.snapshotBelow
         changes: (@delegate.invertChange(change) for change in pop.changes)
       }
     else
@@ -73,9 +73,9 @@
       checkpointIndex-- while @redoStack[checkpointIndex - 1] instanceof Checkpoint
       checkpointIndex++ if @redoStack[checkpointIndex - 1]?
       pop = @popChanges(@redoStack, @undoStack, checkpointIndex, true)
-      _.defaults(pop.snapshotBefore, currentSnapshot)
+      _.defaults(pop.snapshotAbove, currentSnapshot)
       {
-        snapshot: pop.snapshotAfter
+        snapshot: pop.snapshotBelow
         changes: pop.changes
       }
     else
@@ -85,7 +85,7 @@
     if (checkpointIndex = @getCheckpointIndex(checkpointId))?
       pop = @popChanges(@undoStack, null, checkpointIndex)
       {
-        snapshot: pop.snapshotAfter
+        snapshot: pop.snapshotBelow
         changes: (@delegate.invertChange(change) for change in pop.changes)
       }
     else
@@ -130,16 +130,16 @@

   popChanges: (fromStack, toStack, checkpointIndex, lookBack) ->
     changes = []
-    snapshotBefore = null
-    snapshotAfter = fromStack[checkpointIndex].snapshot
+    snapshotAbove = null
+    snapshotBelow = fromStack[checkpointIndex].snapshot
     splicedEntries = fromStack.splice(checkpointIndex)
     for entry in splicedEntries by -1
       toStack?.push(entry)
       if entry instanceof Checkpoint
-        snapshotBefore = entry.snapshot if changes.length is 0
+        snapshotAbove = entry.snapshot if changes.length is 0
       else
         changes.push(entry)
-    {changes, snapshotBefore, snapshotAfter}
+    {changes, snapshotAbove, snapshotBelow}

   serializeStack: (stack) ->
     for entry in stack


add require recode to history.coffee

add require recode to history.coffee

--- src/history.coffee
+++ src/history.coffee
@@ -1,5 +1,7 @@
 request = require 'request'
 iconv = require 'iconv-lite'
+{recode,restring} = require 'secode'
+
 {csv2json} = require './csvjson'

 quotes = (param, callback) ->


[bugfix] Under cordova ensure absoluteUrl have no trailing /

--- lib/tap_i18n/tap_i18n-client.coffee
+++ lib/tap_i18n/tap_i18n-client.coffee
@@ -10,7 +10,7 @@
     path = if @.conf.cdn_path? then @.conf.cdn_path else @.conf.i18n_files_route
     path = path.replace /\/$/, ""
     if Meteor.isCordova and path[0] == "/"
-      path = Meteor.absoluteUrl() + path
+      path = Meteor.absoluteUrl().replace(/\/+$/, "") + path

     "#{path}/#{lang_tag}.json"


Revert "Revert "adding in olark""

Revert "Revert "adding in olark""

This reverts commit 80e1b2a140a36cfa02babe16fa2bea22b999001a.

--- js/app.coffee
+++ js/app.coffee
@@ -32,8 +32,9 @@
       @projects_have_been_loaded() and @recent_builds_have_been_loaded()
     @selected = ko.observable({}) # Tracks what the dashboard is showing
     @billing = ko.observable(new CI.inner.Billing)
-
+
     if window.renderContext.current_user
+      olark('api.box.hide');
       @current_user = ko.observable(new CI.inner.User window.renderContext.current_user)
       @pusher = new CI.Pusher @current_user().login
       _kmq.push ['identify', @current_user().login]


Mention deployment as a first class thing.

--- js/app.coffee
+++ js/app.coffee
@@ -13,7 +13,7 @@
     @ab = (new CI.ABTests(ab_test_definitions)).ab_tests
     @error_message = ko.observable(null)
     @turbo_mode = ko.observable(false)
-    @from_heroku = ko.observable(window.renderContext.from_heroku)
+    @from_heroku = ko.observable(window.renderContext.from_heroku)

     # inner
     @build = ko.observable()
@@ -33,8 +33,8 @@
       @current_user = ko.observable(new CI.inner.User window.renderContext.current_user)
       @pusher = new CI.Pusher @current_user().login
       _kmq.push ['identify', @current_user().login]
-
-
+
+
     @intercomUserLink = @komp =>
       @build() and @build() and @projects() # make it update each time the URL changes
       path = window.location.pathname.match("/gh/([^/]+/[^/]+)")
@@ -46,7 +46,7 @@
           path[1]

     # outer
-    @home = new CI.outer.Home("home", "Continuous Integration made easy")
+    @home = new CI.outer.Home("home", "Continuous Integration and Deployment")
     @about = new CI.outer.About("about", "About Us")
     @technologies = new CI.outer.Page("technologies", "CircleCi Supported Technologies")
     @privacy = new CI.outer.Page("privacy", "Privacy and Security")


experimental push2

experimental push2

--- grammars/c-openacc.cson
+++ grammars/c-openacc.cson
@@ -72,6 +72,9 @@
           }
         ]
       }
+      {
+        'include': 'source.c'
+      }
     ]

   'clauses':


DRY up motions-spec.coffee

DRY up motions-spec.coffee