Retab

Retab

--- app/webroot/js/search.coffee
+++ app/webroot/js/search.coffee
@@ -35,184 +35,184 @@

 # Initializes the search.
 searchMain = ->
-	showField()
-	attachListener()
+    showField()
+    attachListener()

 # Checks whether there is an AJAX request pending.
 isAjaxActive = ->
-	now = new Date().getTime()
-	if now - lastAjax > ajaxTimeout
-		ajaxActive = false
-		false
-	else
-		ajaxActive
+    now = new Date().getTime()
+    if now - lastAjax > ajaxTimeout
+        ajaxActive = false
+        false
+    else
+        ajaxActive

 # Inserts the search field into the DOM and focuses it.
 showField = ->
-	$('#navigation').after '
<form action="bookmarks/search" method="post" autocomplete="off"><input id="search_input" name="data[query]" type="text" autocomplete="off" /></form>
'
-	$('#search_input').focus()
+    $('#navigation').after '
<form action="bookmarks/search" method="post" autocomplete="off"><input id="search_input" name="data[query]" type="text" autocomplete="off" /></form>
'
+    $('#search_input').focus()

 # Attaches the listeners to the search input field.
 attachListener = ->
-	$('#search_input').keyup formChanged
-	$('#search_input').keydown keyDown
+    $('#search_input').keyup formChanged
+    $('#search_input').keydown keyDown

 # This is called whenever the input has changed.
 #
 # It does not necessarily fire off an AJAX request if the last one was just a
 # little time ago.
 formChanged = ->
-	newQuery = $(this).val()
-
-	if newQuery == currentQuery
-		return
-
-	currentQuery = newQuery
-	lastChange = new Date().getTime()
-	waitToQuery()
+    newQuery = $(this).val()
+
+    if newQuery == currentQuery
+        return
+
+    currentQuery = newQuery
+    lastChange = new Date().getTime()
+    waitToQuery()

 # Checks whether another AJAX request can be performed. Otherwise this
 # function will wait and call itself again.
 waitToQuery = ->
-	if isAjaxActive()
-		return
-
-	now = new Date().getTime()
-	elapsed = now - lastChange
-
-	if (elapsed > idleTime)
-		hideResultPane()
-		performQuery()
-	else
-		toWait = idleTime - elapsed
-		setTimeout waitToQuery, toWait
+    if isAjaxActive()
+        return
+
+    now = new Date().getTime()
+    elapsed = now - lastChange
+
+    if (elapsed > idleTime)
+        hideResultPane()
+        performQuery()
+    else
+        toWait = idleTime - elapsed
+        setTimeout waitToQuery, toWait

 # Performs the actual AJAX request and queries the database.
 performQuery = ->
-	ajaxActive = true
-	lastAjax = new Date().getTime()
-	$.ajax({
-		dataType: 'json',
-		success: querySuccess,
-		type: 'GET',
-		url: 'bookmarks/ajaxsearch/'+currentQuery,
-	})
+    ajaxActive = true
+    lastAjax = new Date().getTime()
+    $.ajax({
+        dataType: 'json',
+        success: querySuccess,
+        type: 'GET',
+        url: 'bookmarks/ajaxsearch/'+currentQuery,
+    })

 # This is called when the AJAX request suceeds.
 #
 # @param data Search results from the server.
 querySuccess = (data, textStatus, jqXHR) ->
-	ajaxActive = false
-	currentData = data
-	updateResultPane()
+    ajaxActive = false
+    currentData = data
+    updateResultPane()

 ajaxError = (data, textStatus, jqXHR) ->
-	ajaxActive = false
+    ajaxActive = false

 # Initializes the result pane, creates it if needed.
 initResultPane = ->
-	if $('#search_result_pane').length == 0
-		$('#search').append('

')
-		$('#search_result_pane').slideUp(0)
+    if $('#search_result_pane').length == 0
+        $('#search').append('

')
+        $('#search_result_pane').slideUp(0)

 # Hides the result pane. When the animation is done, the ``animationDone()``
 # will be called.
 hideResultPane = ->
-	if $('#search_result_pane').length > 0
-		animationActive = true
-		$('#search_result_pane').slideUp(animationTime, animationDone)
+    if $('#search_result_pane').length > 0
+        animationActive = true
+        $('#search_result_pane').slideUp(animationTime, animationDone)

 # Inserts the current data into the results pane and slides it down.
 updateResultPane = ->
-	if ajaxActive || animationActive
-		return
-
-	if currentData is null
-		return
-
-	initResultPane()
-	searchResultPane = $('#search_result_pane')
-	currentSelection = 0
-	searchResultPane.html(formatResults(currentData))
-	moveSelection 0
-	searchResultPane.slideDown animationTime
+    if ajaxActive || animationActive
+        return
+
+    if currentData is null
+        return
+
+    initResultPane()
+    searchResultPane = $('#search_result_pane')
+    currentSelection = 0
+    searchResultPane.html(formatResults(currentData))
+    moveSelection 0
+    searchResultPane.slideDown animationTime

 # Called when the slide up animation is done.
 animationDone = ->
-	animationActive = false
-	updateResultPane()
+    animationActive = false
+    updateResultPane()

 # Formats the results.
 #
 # @param data Data from database.
 # @return HTML string.
 formatResults = (data) ->
-	parts = []
-
-	for row in data
-		hitTarget = 'bookmarks/visit/'+row.Bookmark.id
-		viewTarget = 'bookmarks/view/'+row.Bookmark.id
-
-		parts.push('
')
-		parts.push('')
-		parts.push('')
-		parts.push(row.Bookmark.title)
-		parts.push('')
-		parts.push(' – ')
-		parts.push(row.Bookmark.url)
-		parts.push('')
-		parts.push('')
-		# TODO I18n.
-		parts.push('view')
-		parts.push('')
-		parts.push('
')
-
-	'
'+parts.join('')+'
'
+    parts = []
+
+    for row in data
+        hitTarget = 'bookmarks/visit/'+row.Bookmark.id
+        viewTarget = 'bookmarks/view/'+row.Bookmark.id
+
+        parts.push('
')
+        parts.push('')
+        parts.push('')
+        parts.push(row.Bookmark.title)
+        parts.push('')
+        parts.push(' – ')
+        parts.push(row.Bookmark.url)
+        parts.push('')
+        parts.push('')
+        # TODO I18n.
+        parts.push('view')
+        parts.push('')
+        parts.push('
')
+
+    '
'+parts.join('')+'
'

 # Deletes the cached data and hides the result pane.
 exitSearch = ->
-	currentData = null
-	hideResultPane()
+    currentData = null
+    hideResultPane()

 # Handles the keydown event in the search field.
 #
 # @param e Key event.
 keyDown = (e) ->
-	switch e.keyCode
-		when 38
-			moveUp()
-		when 40
-			moveDown()
-		when 13
-			visitSelected()
+    switch e.keyCode
+        when 38
+            moveUp()
+        when 40
+            moveDown()
+        when 13
+            visitSelected()

 # Moves the selection up one step.
 moveUp = ->
-	moveSelection(-1)
+    moveSelection(-1)

 # Moves the selection down one step.
 moveDown = ->
-	moveSelection(1)
+    moveSelection(1)

 # Moves the selection the given steps.
 #
 # @param steps Positive or negative step number.
 moveSelection = (steps) ->
-	entries = $('li.search_entry')
-	entryCount = entries.length
-	newSelection = currentSelection + steps
-	if 0 <= newSelection < entryCount
-		$(entries[currentSelection]).removeClass('selected')
-		$(entries[newSelection]).addClass('selected')
-		currentSelection = newSelection
+    entries = $('li.search_entry')
+    entryCount = entries.length
+    newSelection = currentSelection + steps
+    if 0 <= newSelection < entryCount
+        $(entries[currentSelection]).removeClass('selected')
+        $(entries[newSelection]).addClass('selected')
+        currentSelection = newSelection

 # Points the browser to the currently selected URL.
 visitSelected = ->
-	entries = $('li.search_entry')
-	entry = $(entries[currentSelection])
-	titleLink = entry.children('a.title')
-	url = titleLink.attr('href')
-	# TODO Make sure the referrer is not sent.
-	window.location = url
+    entries = $('li.search_entry')
+    entry = $(entries[currentSelection])
+    titleLink = entry.children('a.title')
+    url = titleLink.attr('href')
+    # TODO Make sure the referrer is not sent.
+    window.location = url

 $(searchMain)


Invalidate initial-value links if source is coll.

If the source node of an `initial-value` link gets changed into a
collector node, invalidate the relationship.

--- src/code/stores/graph-store.coffee
+++ src/code/stores/graph-store.coffee
@@ -321,7 +321,8 @@
             changedLinks = [].concat(node.inLinks())
                             # along with outbound transfer links
                               .concat(_.filter(node.outLinks(), (link) ->
-                                link.relation.type is 'transfer'))
+                                link.relation.type is 'transfer' or
+                                link.relation.type is 'initial-value'))
             originalRelations = {}
             for link in changedLinks
               originalRelations[link.key] = link.relation


Shorten a url of bar chart

Shorten a url of bar chart


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_game_state.coffee
+++ src/engine_game_state.coffee
@@ -17,7 +17,7 @@
     # Handle state change
     if requestedState?
       I.currentState.trigger "exit", requestedState
-      self.trig
+      self.trigger ''

       previousState = I.currentState
       I.currentState = requestedState


fixed a bug.

fixed a bug.

--- lib/views/add-ui-snippets-view.coffee
+++ lib/views/add-ui-snippets-view.coffee
@@ -286,9 +286,11 @@
         @snippet_name.setText(@edit_name)
         @snippet_tab.setText(prefix)
         @snippet_scope.setText(@edit_source)
-        for tmp_img in img
-          tmp_path = path.join @snippet_img_path, tmp_img
-          @add_image_detail(tmp_path)
+        # console.log img
+        unless !img
+          for tmp_img in img
+            tmp_path = path.join @snippet_img_path, tmp_img
+            @add_image_detail(tmp_path)
         @snippet_body.context.value = body
         @snippet_desc.context.value = desc
         # @snippet_css.context.value = @edit_css


remove roots-base before roots.new in test

--- test/new.coffee
+++ test/new.coffee
@@ -19,16 +19,19 @@

   it 'should create a project', (done) ->
     spy = sinon.spy()
-    Roots.new
-      path: new_path
-      overrides: { foo: 'love it' }
-    .progress(spy)
-    .catch(done)
-    .done (proj) ->
-      proj.root.should.exist
-      spy.should.have.callCount(1)
-      spy.should.have.been.calledWith('project created')
-      rimraf(new_path, done)
+    Roots.template.remove(name: 'roots-base')
+    .then ->
+      Roots.new
+        path: new_path
+        overrides: { foo: 'love it' }
+      .progress(spy)
+      .catch(done)
+      .done (proj) ->
+        proj.root.should.exist
+        spy.should.have.callCount(2)
+        spy.should.have.been.calledWith('base template added')
+        spy.should.have.been.calledWith('project created')
+        rimraf(new_path, done)

   it 'should create a project with another template if provided', (done) ->
     Roots.template.add(name: 'foobar', uri: test_tpl_path)


adding security enforcement mechanism

adding security enforcement mechanism


Reverted to previous exec settings handling


add alpha support

add alpha support


fix docs and methods for now PRs for getting actual underline docs and a nice goto view are incoming

--- lib/runtime/evaluation.coffee
+++ lib/runtime/evaluation.coffee
@@ -3,6 +3,7 @@
 {client} =  require '../connection'
 {notifications, views, selector} = require '../ui'
 {paths} = require '../misc'
+modules = require './modules'

 module.exports =
   client: client.import
@@ -45,17 +46,22 @@

   # get documentation or methods for the current word
   toggleMeta: (type) ->
+    mod = modules.currentModule()
+    mod = if mod then mod else 'Main'
     editor = atom.workspace.getActiveTextEditor()
     [word, range] = @getWord editor
     # if we only find numbers or nothing, return prematurely
     if word.length == 0 || !isNaN(word) then return
-    client.rpc(type, word).then ({result}) =>
-      view = if result.type then result.view else result
-      view = @ink.tree.fromJson(view)[0]
-      @ink.links.linkify view
-      r = @ink.results.toggleUnderline editor, range,
-        content: view
-        clas: 'julia'
+    client.rpc(type, {word: word, mod: mod}).then ({result}) =>
+      if result?
+        error = result.type == 'error'
+        view = if error then result.view else result
+        fade = not @ink.Result.removeLines editor, range.start.row, range.end.row
+        r = new @ink.Result editor, [range.start.row, range.end.row],
+          content: views.render view
+          error: error
+          fade: fade
+        # type: 'block'

   # gets the word and its range in the `editor` which the last cursor is on
   getWord: (editor) ->


[bugfix] fix the package templates detection (got broken by a Meteor API change)

The Template object in Meteor is not an object anymore, but a function

--- lib/plugin/compilers/package-tap.i18n.coffee
+++ lib/plugin/compilers/package-tap.i18n.coffee
@@ -81,12 +81,7 @@

       // Record the list of templates prior to package load
       var _ = Package.underscore._;
-      Template = Package.templating.Template;
-      if (typeof Template !== "object") {
-        non_package_templates = [];
-      } else {
-        non_package_templates = _.keys(Template);
-      }
+      non_package_templates = _.keys(Template);

       """


fix improperly formatted hex strings when using floats


Update momentjs rounding

Update momentjs rounding

--- resources/assets/coffee/main.coffee
+++ resources/assets/coffee/main.coffee
@@ -6,6 +6,11 @@
 Turbolinks.setProgressBarDelay(0)

 Lang.setLocale(@currentLocale)
+moment.relativeTimeThreshold('s', 120)
+moment.relativeTimeThreshold('m', 120)
+moment.relativeTimeThreshold('h', 48)
+moment.relativeTimeThreshold('d', 62)
+moment.relativeTimeThreshold('M', 24)
 jQuery.timeago.inWords = (distanceMillis) ->
   moment.duration(-1 * distanceMillis).humanize(true)


Updated tests for all non-callback signatures

--- test/generators/conventions/callbacks.coffee
+++ test/generators/conventions/callbacks.coffee
@@ -48,174 +48,261 @@

       queue.await done

-    it 'Model.save (null, options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save null, {
-        success: (model) ->
-          assert.equal(flat, model, 'returned the model')
-
-          model = new Flat({id: flat.id})
-          model.fetch (err, flat) ->
-            assert.ok(!err, "No errors: #{err}")
-            assert.equal(flat, model, 'returned the model')
-            assert.equal(flat.get('name'), 'Bob', 'name matches')
-            done()
-      }
-
-    it 'Model.save (attrs, options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save {}, {
-        success: (model) ->
-          assert.equal(flat, model, 'returned the model')
-
-          model = new Flat({id: flat.id})
-          model.fetch (err, flat) ->
-            assert.ok(!err, "No errors: #{err}")
-            assert.equal(flat, model, 'returned the model')
-            assert.equal(flat.get('name'), 'Bob', 'name matches')
-            done()
-      }
-
-    it 'Model.save (callback)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Model.save (attrs, callback)', (done) ->
-      flat = new Flat()
-      flat.save {name: 'Bob'}, (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Model.save (attrs, options, callback)', (done) ->
-      flat = new Flat()
-      flat.save {name: 'Bob'}, {}, (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Model.save (key, value, options, callback)', (done) ->
-      flat = new Flat()
-      flat.save 'name', 'Bob', {}, (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Model.destroy (no options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: model_id = flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-
-          flat.destroy (err) ->
-            assert.ok(!err, "No errors: #{err}")
-            model = new Flat({id: model_id})
-            model.fetch (err) ->
-              assert.ok(err, "Model not found: #{err}")
-              done()
-
-    it 'Model.destroy (with options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: model_id = flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-
-          flat.destroy {}, (err) ->
-            assert.ok(!err, "No errors: #{err}")
-            model = new Flat({id: model_id})
-            model.fetch (err) ->
-              assert.ok(err, "Model not found: #{err}")
-              done()
-
-    it 'Model.fetch (no options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Model.fetch (with options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        model = new Flat({id: flat.id})
-        model.fetch {}, (err, flat) ->
-          assert.ok(!err, "No errors: #{err}")
-          assert.equal(flat, model, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Collection.fetch (no options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        flats = new Flats()
-        flats.fetch (err) ->
-          assert.ok(!err, "No errors: #{err}")
-          model = flats.get(flat.id)
-          assert.equal(flat.id, model.id, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
-
-    it 'Collection.fetch (with options)', (done) ->
-      flat = new Flat({name: 'Bob'})
-      flat.save (err, model) ->
-        assert.ok(!err, "No errors: #{err}")
-        assert.equal(flat, model, 'returned the model')
-
-        flats = new Flats()
-        flats.fetch {}, (err) ->
-          assert.ok(!err, "No errors: #{err}")
-          model = flats.get(flat.id)
-          assert.equal(flat.id, model.id, 'returned the model')
-          assert.equal(flat.get('name'), 'Bob', 'name matches')
-          done()
+    ##############################
+    # No Callbacks (Options)
+    ##############################
+
+    describe "No callbacks", ->
+
+      it 'Model.save (null, options) - non callback', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save null, {
+          success: (model) ->
+            assert.equal(flat, model, 'returned the model')
+
+            model = new Flat({id: flat.id})
+            model.fetch (err, flat) ->
+              assert.ok(!err, "No errors: #{err}")
+              assert.equal(flat, model, 'returned the model')
+              assert.equal(flat.get('name'), 'Bob', 'name matches')
+              done()
+          error: ->
+            assert.ok(false, "No errors: #{err}")
+        }
+
+      it 'Model.save (attrs, options) - non callback', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save {}, {
+          success: (model) ->
+            assert.equal(flat, model, 'returned the model')
+
+            model = new Flat({id: flat.id})
+            model.fetch (err, flat) ->
+              assert.ok(!err, "No errors: #{err}")
+              assert.equal(flat, model, 'returned the model')
+              assert.equal(flat.get('name'), 'Bob', 'name matches')
+              done()
+          error: ->
+            assert.ok(false, "No errors: #{err}")
+        }
+
+      it 'Model.save (key, value, options) - non callback', (done) ->
+        flat = new Flat()
+        flat.save 'name', 'Bob', {
+          success: (model) ->
+            assert.equal(flat, model, 'returned the model')
+
+            model = new Flat({id: flat.id})
+            model.fetch (err, flat) ->
+              assert.ok(!err, "No errors: #{err}")
+              assert.equal(flat, model, 'returned the model')
+              assert.equal(flat.get('name'), 'Bob', 'name matches')
+              done()
+          error: ->
+            assert.ok(false, "No errors: #{err}")
+        }
+
+      it 'Model.destroy (options) - non callback', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: model_id = flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+
+            flat.destroy {
+              success: ->
+                model = new Flat({id: model_id})
+                model.fetch (err) ->
+                  assert.ok(err, "Model not found: #{err}")
+                  done()
+              error: ->
+                assert.ok(false, "No errors: #{err}")
+            }
+
+      it 'Model.fetch (options) - non callback', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          flat.fetch {
+            success: (model) ->
+              assert.equal(flat, model, 'returned the model')
+              assert.equal(flat.get('name'), 'Bob', 'name matches')
+              done()
+            error: ->
+              assert.ok(false, "No errors: #{err}")
+          }
+
+      it 'Collection.fetch (options)  - non callback', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          flats = new Flats()
+          flats.fetch {
+            success: ->
+              model = flats.get(flat.id)
+              assert.equal(flat.id, model.id, 'returned the model')
+              assert.equal(flat.get('name'), 'Bob', 'name matches')
+              done()
+            error: ->
+              assert.ok(false, "No errors: #{err}")
+          }
+
+    ##############################
+    # Callbacks
+    ##############################
+
+    describe "Callbacks", ->
+
+      it 'Model.save (callback)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Model.save (attrs, callback)', (done) ->
+        flat = new Flat()
+        flat.save {name: 'Bob'}, (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Model.save (attrs, options, callback)', (done) ->
+        flat = new Flat()
+        flat.save {name: 'Bob'}, {}, (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Model.save (key, value, options, callback)', (done) ->
+        flat = new Flat()
+        flat.save 'name', 'Bob', {}, (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Model.destroy (no options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: model_id = flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+
+            flat.destroy (err) ->
+              assert.ok(!err, "No errors: #{err}")
+              model = new Flat({id: model_id})
+              model.fetch (err) ->
+                assert.ok(err, "Model not found: #{err}")
+                done()
+
+      it 'Model.destroy (with options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: model_id = flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+
+            flat.destroy {}, (err) ->
+              assert.ok(!err, "No errors: #{err}")
+              model = new Flat({id: model_id})
+              model.fetch (err) ->
+                assert.ok(err, "Model not found: #{err}")
+                done()
+
+      it 'Model.fetch (no options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Model.fetch (with options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          model = new Flat({id: flat.id})
+          model.fetch {}, (err, flat) ->
+            assert.ok(!err, "No errors: #{err}")
+            assert.equal(flat, model, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Collection.fetch (no options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          flats = new Flats()
+          flats.fetch (err) ->
+            assert.ok(!err, "No errors: #{err}")
+            model = flats.get(flat.id)
+            assert.equal(flat.id, model.id, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()
+
+      it 'Collection.fetch (with options)', (done) ->
+        flat = new Flat({name: 'Bob'})
+        flat.save (err, model) ->
+          assert.ok(!err, "No errors: #{err}")
+          assert.equal(flat, model, 'returned the model')
+
+          flats = new Flats()
+          flats.fetch {}, (err) ->
+            assert.ok(!err, "No errors: #{err}")
+            model = flats.get(flat.id)
+            assert.equal(flat.id, model.id, 'returned the model')
+            assert.equal(flat.get('name'), 'Bob', 'name matches')
+            done()


Add toolbar assertations

Add toolbar assertations

--- test/src/system/block_formatting_test.coffee
+++ test/src/system/block_formatting_test.coffee
@@ -283,6 +283,7 @@
   test "adding bullet to header block", (done) ->
     clickToolbarButton attribute: "header", ->
       clickToolbarButton attribute: "bullet", ->
+        assert.ok isToolbarButtonActive(attribute: "header")
         assert.blockAttributes([1, 2], [])
         done()

@@ -290,14 +291,17 @@
     clickToolbarButton attribute: "bullet", ->
       clickToolbarButton attribute: "header", ->
         clickToolbarButton attribute: "bullet", ->
+          assert.ok isToolbarButtonActive(attribute: "header")
           assert.blockAttributes([0, 1], ["header"])
           done()

   test "breaking out of header in list", (done) ->
     clickToolbarButton attribute: "bullet", ->
       clickToolbarButton attribute: "header", ->
+        assert.ok isToolbarButtonActive(attribute: "header")
         typeCharacters "abc", ->
           typeCharacters "\n", ->
+            assert.ok isToolbarButtonActive(attribute: "bullet")
             document = getDocument()
             assert.equal document.getBlockCount(), 2

@@ -315,6 +319,8 @@
       typeCharacters "abc", ->
         moveCursor direction: "left", times: 1, ->
           typeCharacters "\n", ->
+            assert.ok isToolbarButtonActive(attribute: "header")
+
             document = getDocument()
             assert.equal document.getBlockCount(), 1


Refactor loop rendering tests to reuse one really common jQuery.

--- tests/batman/view/loop_rendering_test.coffee
+++ tests/batman/view/loop_rendering_test.coffee
@@ -1,4 +1,5 @@
 helpers = if typeof require is 'undefined' then window.viewHelpers else require './view_helper'
+getPs = (view) -> $('p', view.get('node')).map(-> @innerHTML).toArray()

 QUnit.module "Batman.View loop rendering"

@@ -7,9 +8,7 @@
   objects = new Batman.Set('foo', 'bar', 'baz')

   helpers.render source, {objects}, (node, view) ->
-    names = $('p', view.get('node')).map -> @innerHTML
-    names = names.toArray()
-    deepEqual names, ['foo', 'bar', 'baz']
+    deepEqual getPs(view), ['foo', 'bar', 'baz']
     QUnit.start()

 asyncTest 'it should allow loops over empty collections', 1, ->
@@ -17,9 +16,7 @@
   objects = new Batman.Set()

   helpers.render source, {objects}, (node, view) ->
-    names = $('p', view.get('node')).map -> @innerHTML
-    names = names.toArray()
-    deepEqual names, []
+    deepEqual getPs(view), []
     QUnit.start()

 asyncTest 'it should allow loops over undefined values', 3, ->
@@ -27,16 +24,13 @@
   context = Batman()
   Batman.developer.suppress()
   helpers.render source, context, (node, view) ->
-    names = $('p', view.get('node')).map(-> @innerHTML).toArray()
-    deepEqual names, []
+    deepEqual getPs(view), []
     context.set 'objects', new Batman.Set('foo', 'bar', 'baz')
     delay ->
-      names = $('p', view.get('node')).map(-> @innerHTML).toArray()
-      deepEqual names, ['foo', 'bar', 'baz']
+      deepEqual getPs(view), ['foo', 'bar', 'baz']
       context.unset 'objects'
       delay ->
-        names = $('p', view.get('node')).map(-> @innerHTML).toArray()
-        deepEqual names, []
+        deepEqual getPs(view), []
         Batman.developer.unsuppress()

 asyncTest 'it should render new items as they are added', ->
@@ -46,9 +40,7 @@
   helpers.render source, {objects}, (node, view) ->
     objects.add('foo', 'baz', 'qux')
     delay =>
-      names = $('p', view.get('node')).map -> @innerHTML
-      names = names.toArray()
-      deepEqual names, ['foo', 'bar', 'baz', 'qux']
+      deepEqual getPs(view), ['foo', 'bar', 'baz', 'qux']

 asyncTest 'it should remove items from the DOM as they are removed from the set', ->
   source = '

'
@@ -57,9 +49,7 @@
   helpers.render source, {objects}, (node, view) ->
     objects.remove('foo')
     delay =>
-      names = $('p', view.get('node')).map -> @innerHTML
-      names = names.toArray()
-      deepEqual names, ['bar']
+      deepEqual getPs(view), ['bar']

 asyncTest 'it should atomically reorder DOM nodes when the set is reordered', ->
   source = '

'
@@ -67,19 +57,15 @@
   context = Batman({objects, currentSort: 'id'})

   helpers.render source, context, (node, view) ->
-    names = ($('p', view.get('node')).map -> @innerHTML).toArray()
-    deepEqual names, ['foo', 'bar']
+    deepEqual getPs(view), ['foo', 'bar']
     # multiple reordering all at once should not end up with duplicate DOM nodes
     context.set 'currentSort', 'name'
     delay =>
-      ($('p', view.get('node')).map -> @innerHTML)
       context.set 'currentSort', 'id'
       delay =>
-        ($('p', view.get('node')).map -> @innerHTML)
         context.set 'currentSort', 'name'
         delay =>
-          names = ($('p', view.get('node')).map -> @innerHTML).toArray()
-          deepEqual names, ['bar', 'foo']
+          deepEqual getPs(view), ['bar', 'foo']

 asyncTest 'it should add items in order', ->
   source = '

'
@@ -87,8 +73,7 @@
   helpers.render source, {objects}, (node, view) ->
     objects.add({id: 0, name: 'zero'})
     delay =>
-      names = $('p', view.get('node')).map(-> @innerHTML).toArray()
-      deepEqual names, ['zero', 'foo', 'bar']
+      deepEqual getPs(view), ['zero', 'foo', 'bar']

 asyncTest 'the ready event should wait for all children to be rendered', ->
   source = '

'
@@ -124,23 +109,22 @@
   objects1 = new Batman.Set('foo', 'bar', 'baz')
   objects2 = new Batman.Set('a', 'b', 'c')

-  helpers.render source, false, {objects1, objects2}, (node) ->
-    names = $('p', node).map(-> @innerHTML).toArray()
-    deepEqual names, ['foo', 'bar', 'baz', 'a', 'b', 'c']
+  helpers.render source, false, {objects1, objects2}, (node, view) ->
+    deepEqual getPs(view), ['foo', 'bar', 'baz', 'a', 'b', 'c']
     QUnit.start()

 asyncTest 'it should render consecutive loops bound to the same collection', 4, ->
   source = '

'
   objects = new Batman.Set('foo', 'bar', 'baz')

-  helpers.render source, false, {objects}, (node) ->
-    equal $('p', node).length, 6
+  helpers.render source, false, {objects}, (node, view) ->
+    deepEqual getPs(view), ['foo', 'bar', 'baz', 'foo', 'bar', 'baz']
     objects.remove 'foo'
     delay ->
-      equal $('p', node).length, 4
+      deepEqual getPs(view), ['bar', 'baz', 'bar', 'baz']
       objects.remove 'bar'
       delay ->
-        equal $('p', node).length, 2
+        deepEqual getPs(view), ['baz', 'baz']
         objects.remove 'baz'
         delay ->
           equal $('p', node).length, 0
@@ -149,16 +133,14 @@
   source = '

'
   objects = new Batman.Set()

-  helpers.render source, false, {objects}, (node) ->
+  helpers.render source, false, {objects}, (node, view) ->
     equal $('p', node).length, 0
     objects.add 'foo', 'bar', 'baz'
     delay ->
-      names = $('p', node).map(-> @innerHTML).toArray()
-      deepEqual names, ['foo', 'bar', 'baz', 'foo', 'bar', 'baz']
+      deepEqual getPs(view), ['foo', 'bar', 'baz', 'foo', 'bar', 'baz']
       objects.remove 'bar'
       delay ->
-        names = $('p', node).map(-> @innerHTML).toArray()
-        deepEqual names, ['foo', 'baz', 'foo', 'baz']
+        deepEqual getPs(view), ['foo', 'baz', 'foo', 'baz']

 asyncTest 'it should update the whole set of nodes if the collection changes', ->
   source = '

'
@@ -285,7 +267,6 @@
       equal parseInt(childNode.innerHTML, 10), playerScores[childNode.id]
     QUnit.start()

-getPs = (view) -> $('p', view.get('node')).map(-> @innerHTML).toArray()

 asyncTest 'it should prevent parent renders even if it has to defer (note: this test can take a while)', ->
   oldDeferEvery = Batman.DOM.Iterator::deferEvery


replaced deprecated .workspace and .editor selectors with atom-workspace and atom-text-editor tags

--- keymaps/jumpy.cson
+++ keymaps/jumpy.cson
@@ -7,10 +7,10 @@

 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
-'.workspace .editor:not(.mini)':
+'atom-workspace atom-text-editor:not(.mini)':
     'shift-enter': 'jumpy:toggle'

-'.workspace .editor.jumpy-jump-mode':
+'atom-workspace atom-text-editor.jumpy-jump-mode':
     'backspace': 'jumpy:reset'
     'enter': 'jumpy:clear'
     'space': 'jumpy:clear'


Update spec strings

Update spec strings

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -385,7 +385,7 @@
           """
           atom.config.loadUserConfig()

-        it "updates the config data based on the file contents", ->
+        it "updates the only the settings that have values matching the schema", ->
           expect(atom.config.get("foo.bar")).toBe 'baz'
           expect(atom.config.get("foo.int")).toBe 12

@@ -438,7 +438,7 @@
           atom.config.set("hair", "blonde")
           expect(atom.config.save).toHaveBeenCalled()

-  describe "when there is a schema specified", ->
+  describe "when a schema is specified", ->
     schema = null

     describe '.setSchema(keyPath, schema)', ->
@@ -584,7 +584,7 @@
           default: 'def'
         atom.config.setSchema('foo.bar', schema)

-      it 'can set a string, a boolean, and unset', ->
+      it 'can set a string, a boolean, and revert back to the default', ->
         atom.config.set('foo.bar', 'ok')
         expect(atom.config.get('foo.bar')).toBe 'ok'

@@ -653,7 +653,10 @@
         atom.config.set('foo.bar.aBool', null)
         expect(atom.config.get('foo.bar.aBool')).toBe false

-        # unset
+      it 'reverts back to the default value when undefined is passed to set', ->
+        atom.config.set('foo.bar.aBool', 'false')
+        expect(atom.config.get('foo.bar.aBool')).toBe false
+
         atom.config.set('foo.bar.aBool', undefined)
         expect(atom.config.get('foo.bar.aBool')).toBe true


mochacompat: Use afterEach() for cleanup

More robust in error conditions

--- spec/mochacompat.coffee
+++ spec/mochacompat.coffee
@@ -36,12 +36,18 @@
 # FIXME: move to protocol

 describe 'Mocha compatibility runner', ->
+  httpServer = null
   definition = null
+
+  afterEach () ->
+    if httpServer
+      httpServer.close()
+
   it 'should implement the FBP runtime protocol', (done) ->
     options =
       files: [ testPath('bdd-nested-passing.coffee') ]
     setupAndConnect options, (err, client, def, state, server) ->
-      server.close()
+      httpServer = server
       definition = def
       return done err if err
       chai.expect(def).to.include.keys ['protocol', 'type', 'version', 'capabilities']
@@ -61,7 +67,7 @@
       options =
         files: [ testPath('bdd-nested-passing.coffee') ]
       setupAndConnect options, (err, client, def, state, server) ->
-        server.close()
+        httpServer = server
         return done err if err
         protocol.getComponentTests client, (err, suites) ->
           return done err if err


Temporarily disable iframe tests - they are failing too often.

--- tests/html/src/endtoendtests.coffee
+++ tests/html/src/endtoendtests.coffee
@@ -41,13 +41,13 @@
                 hook.del()
                 start()

-module('sockjs in head')
-body_protocols = ['iframe-eventsource',
-            'iframe-htmlfile',
-            'iframe-xhr-polling',
-            'jsonp-polling']
-for protocol in body_protocols
-    factory_body_check(protocol)
+# module('sockjs in head')
+# body_protocols = ['iframe-eventsource',
+#             'iframe-htmlfile',
+#             'iframe-xhr-polling',
+#             'jsonp-polling']
+# for protocol in body_protocols
+#     factory_body_check(protocol)

 module('connection errors')


Change ssl files logging level to warn

Change ssl files logging level to warn

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -237,8 +237,8 @@
         key = paths.relative process.cwd(), secure.key
         cert = paths.relative process.cwd(), secure.cert
         template = "Reading SSL %s file at %s".toString()
-        logger.info template.grey, "key".bold, key.underline
-        logger.info template.grey, "cert".bold, cert.underline
+        logger.warn template.grey, "key".bold, key.underline
+        logger.warn template.grey, "cert".bold, cert.underline
         logger.debug "Assembling the HTTPS options".grey
         options.key = fs.readFileSync paths.resolve key
         options.cert = fs.readFileSync paths.resolve cert


don't include type on the audio player for now. Let the browser decide.

--- js/song.coffee
+++ js/song.coffee
@@ -23,8 +23,8 @@
   load: (@name, cb) ->
     if @name && @name isnt ''
       @audio = $('<audio id="audio" preload="auto" controls>')
-      @audio.append $('<source>').attr(src: @musicFileUrl(@name).replace(/\.(\w+?$)/, '.ogg'), type: "audio/ogg")
-      @audio.append $('<source>').attr(src: @musicFileUrl(@name), type: "audio/#{ @name.match(/\.(\w+?$)/)[1] }")
+      @audio.append $('<source>').attr(src: @musicFileUrl(@name).replace(/\.(\w+?$)/, '.ogg'))#, type: "audio/ogg")
+      @audio.append $('<source>').attr(src: @musicFileUrl(@name))#, type: "audio/#{ @name.match(/\.(\w+?$)/)[1] }")

       # @audio.attr src: @musicFileUrl(@name)
       $('body').append @audio


reword better

reword better

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -58,7 +58,7 @@
         attempt = $("#input_answer").val()
         if attempt.toLowerCase() == @current.toLowerCase()
           $(".alert").addClass("alert-success")
-          $(".alert").empty().append("You had just spelt the word " + @current + " right!")
+          $(".alert").empty().append("You had just spelled the word " + @current + " right!")
           $("#revealed").empty()
           @reveal = ""
           update_question(@data)


node style require

node style require

--- jasmine-harness.coffee
+++ jasmine-harness.coffee
@@ -1,4 +1,4 @@
-require.load './lib/jasmine.js'
+require './lib/jasmine.js'
 # require.load './lib/jasmine-html.js'
 # require.load './lib/jasmine.tap_reporter.js'


better whose news bookmarklet closing

better whose news bookmarklet closing

--- src/bookmarklet/src/main.coffee
+++ src/bookmarklet/src/main.coffee
@@ -40,16 +40,8 @@
   # Set the src of the iframe to the popup
   appFrame.src = scriptTag.getAttribute('data-context') + popupPath

-  # Create a function to close Whose News
-  window.closeWhoseNews = ->
-    delete window.closeWhoseNews
-    body.removeChild scriptTag
-    body.removeChild holder
-
-  # Unflag that Whose News is loading
-  window.whoseNewsLoading = false
   # Create an event listener for messages
-  window.addEventListener "message", (message) ->
+  messageListener = (message) ->
     # Get the data from the message
     {data} = message
     console.log "got message", data
@@ -67,3 +59,16 @@
     if data?.title == "open-url"
       console.log "Opening url"
       window.open data.url
+
+  # Add the event listener
+  window.addEventListener "message", messageListener
+
+  # Create a function to close Whose News
+  window.closeWhoseNews = ->
+    window.removeEventListener "message", messageListener
+    body.removeChild scriptTag
+    body.removeChild holder
+    delete window.closeWhoseNews
+
+  # Unflag that Whose News is loading
+  window.whoseNewsLoading = false


Implement indent_style validation

Implement indent_style validation

--- src/brave-mouse/validate.coffee
+++ src/brave-mouse/validate.coffee
@@ -1,6 +1,7 @@
 fs = require 'fs'

 editorconfig = require 'editorconfig'
+detectIndent = require 'detect-indent'

 module.exports = (filePath, callback) ->
 	editorconfig.parse(filePath)
@@ -10,6 +11,13 @@
 		fs.readFile filePath, 'utf8', (err, fileContents) ->
 			return callback err if err

+			indentStyle = detectIndent(fileContents).type
+
+			if indentStyle isnt editorconfigProperties.indent_style or !indentStyle
+				result.indent_style =
+					expected: editorconfigProperties.indent_style
+					is: indentStyle
+
 			result = true if Object.keys(result).length is 0

 			callback null, result


changing default proposer setting now reflected in customization + naming changes


focusEditorAfterSearch

focusEditorAfterSearch

--- etc/atom/config.cson
+++ etc/atom/config.cson
@@ -22,3 +22,5 @@
   'removeTrailingWhitespace': false
 'bracket-matcher':
   'autocompleteBrackets': false
+'find-and-replace':
+  'focusEditorAfterSearch': true


ensure that left-entering animations work as well as from the right

--- src/coffeescript/notifyr.coffee
+++ src/coffeescript/notifyr.coffee
@@ -48,7 +48,6 @@
       @render()

     Notifyr::render = () ->
-      @empty()
       closeButton = $(@options.closeButtonHtml)
       closeButton.on 'click', (e) =>
         e.preventDefault()
@@ -83,10 +82,16 @@
       opts = {}
       if (state == 'show')
         opts.opacity = 1
-        opts.right = '15px'
+        if @options.location.match(/left/)
+          opts.left = '15px'
+        else
+          opts.right = '15px'
       else
         opts.opacity = 0
-        opts.right = '-300px'
+        if @options.location.match(/left/)
+          opts.left = '-300px'
+        else
+          opts.right = '-300px'
       opts

     Notifyr


Add contributor

Add contributor


Remove spurious blank lines

Remove spurious blank lines

--- metrics.coffee
+++ metrics.coffee
@@ -20,8 +20,6 @@
 destructors = []

 require "./uv_threadpool_size"
-
-

 module.exports = Metrics =
 	initialize: (_name) ->


Changed name and prefix for class page controller

--- completions.cson
+++ completions.cson
@@ -381,8 +381,8 @@
     }
   ]

-'Class & Controller Silverstripe':
-  'prefix': 'classcontroller'
+'Class Page & Controller Silverstripe':
+  'prefix': 'classpagecontroller'
   'module': 'silverstripe/cms'
   'minVersion': '3.0'
   'maxVersion': '4.0'


ES fix

ES fix

--- server/api/lib/elasticsearch.coffee
+++ server/api/lib/elasticsearch.coffee
@@ -122,7 +122,7 @@
 API.es._reindexing = false
 API.es.reindex = (index, type, mapping=API.es._mapping, rename, del, change, fromurl=API.settings.es.url, tourl=API.settings.es.url) ->
   fromurl = fromurl[Math.floor(Math.random()*fromurl.length)] if Array.isArray fromurl
-  tourl = tourl[Math.floor(Math.random()*fromurl.length)] if Array.isArray tourl
+  tourl = tourl[Math.floor(Math.random()*tourl.length)] if Array.isArray tourl
   return false if not index? or not type?
   # index names will be treated as specific
   # and only handle indexes in the API.settings.es.index namespace - or allow move from others? handy for moving old systems to new
@@ -202,7 +202,7 @@
         else
           try
             if API.settings.es.mappings.indexOf('http') is 0
-              maps = RetryHttp.call('GET', API.settings.es.mappings, {retry:API.es._retries}).data
+              maps = HTTP.call('GET', API.settings.es.mappings).data
             else
               maps = JSON.parse fs.readFileSync(API.settings.es.mappings).toString()
         if maps?[index]?[type]?


Fix bug in custom pad calculating

Fix bug in custom pad calculating

--- src/pattern/default/common/calculator.coffee
+++ src/pattern/default/common/calculator.coffee
@@ -135,7 +135,7 @@
     if padDiameter < (holeDiameter + 2*settings.minimum.ringWidth)
       padDiameter = holeDiameter + 2*settings.minimum.ringWidth
     if housing.pitch? or (housing.horizontalPitch? and housing.verticalPitch?)
-      pitch = housing.pitch ? Math.min(housing.horizontalPitch, housing.verticalPitch)
+      pitch = housing.pitch ? Math.min(Math.abs(housing.horizontalPitch), Math.abs(housing.verticalPitch))
       clearance = housing.padSpace ? settings.clearance.padToPad
       if padDiameter > pitch - clearance
         padDiameter = pitch - clearance


fix Sublime Text warnings

fix Sublime Text warnings

--- lib/atomizr.coffee
+++ lib/atomizr.coffee
@@ -106,7 +106,7 @@

     # Minimum requirements
     if sublime.completions.length is 0
-      @atom.notifications.addWarning("Atomizr", detail: "This doesn't seem to be a valid Atom snippet file. Aborting.", dismissable: false)
+      @invalidFormat("Atom snippet")
       return

     # Convert to JSON
@@ -136,6 +136,8 @@
       @sublCompletionsToAtom()
     else if scope is "text.xml.subl"
       @sublSnippetToAtom()
+    else
+      @invalidFormat("Sublime Text")

   # Convert Sublime Text completion into Atom snippet
   sublCompletionsToAtom: ->
@@ -154,7 +156,7 @@

     # Minimum requirements
     unless obj.scope? or obj.completions?
-      @atom.notifications.addWarning("Atomizr", detail: "This doesn't seem to be a valid Sublime Text completions file. Aborting.", dismissable: false)
+      @invalidFormat("Sublime Text completions")
       return

     # Conversion
@@ -212,7 +214,7 @@

     # Minimum requirements
     unless obj.scope? or obj.content?
-      @atom.notifications.addWarning("Atomizr", detail: "This doesn't seem to be a valid Sublime Text snippet file. Aborting.", dismissable: false)
+      @invalidFormat("Sublime Text snippet")
       return

     # Get scope, convert if necessary
@@ -326,6 +328,9 @@
       outputFile = path.join parentDir, baseName + ".#{extension}"
       fs.rename inputFile, outputFile

+  invalidFormat: (type) ->
+    @atom.notifications.addWarning("Atomizr", detail: "This doesn't seem to be a valid #{type} file. Aborting.", dismissable: false)
+
   makeCoffee: (editor, input) ->
     output = CSON.createCSONString(input)


Clear console before building

Clear console before building

--- lib/builder.coffee
+++ lib/builder.coffee
@@ -64,6 +64,7 @@

   build: ->
     @ltConsole.show()
+    @ltConsole.clear()

     te = atom.workspace.getActiveTextEditor()
     if te == ''


Fixed the init() method.

Fixed the init() method.

--- lib/dequeue.coffee
+++ lib/dequeue.coffee
@@ -53,13 +53,13 @@
     if @rear then @rear.first() else if @front then @front.first()

   rest: ->
-    if @front
+    if @front?
       create @front.rest(), @lf - 1, @rear, @lr
     else if @rest
       new Dequeue()

   init: ->
-    if @rest
+    if @rear?
       create @front, @lf, @rear.rest(), @lr - 1
     else if @front
       new Dequeue()


Delay requires that could be delayed in the package main

--- lib/minimap.coffee
+++ lib/minimap.coffee
@@ -1,11 +1,10 @@
-{deprecate} = require 'grim'
 EmitterMixin = require('emissary').Emitter
 {Emitter} = require 'event-kit'
-semver = require 'semver'

 ViewManagement = require './mixins/view-management'
 PluginManagement = require './mixins/plugin-management'
-MinimapPluginGeneratorView = require './minimap-plugin-generator-view'
+
+[MinimapPluginGeneratorView, deprecate, semver] = []

 require '../vendor/resizeend'

@@ -119,7 +118,9 @@
   #                     version.
   #
   # Returns a {Boolean}.
-  versionMatch: (expectedVersion) -> semver.satisfies(@version, expectedVersion)
+  versionMatch: (expectedVersion) ->
+    semver ?= require 'semver'
+    semver.satisfies(@version, expectedVersion)

   # Public: Toggles the minimap activation state.
   toggle: ->
@@ -134,6 +135,7 @@

   # Public: Opens the plugin generation view.
   generatePlugin: ->
+    MinimapPluginGeneratorView ?= require './minimap-plugin-generator-view'
     view = new MinimapPluginGeneratorView()

   # Public: Calls the `callback` when the minimap package have been activated.
@@ -228,6 +230,7 @@

   # Internal: Used only for old events deprecation.
   on: (eventName) ->
+    deprecate ?= require('grim').deprecate
     switch eventName
       when 'activated'
         deprecate("Use Minimap::onDidActivate instead.")


Adds basic documentation

Adds basic documentation

--- lib/minimap.coffee
+++ lib/minimap.coffee
@@ -6,26 +6,43 @@

 require '../vendor/resizeend'

+# Public: The `Minimap` package provides a eagle-eye view of text buffers.
+#
+# It also provides API for plugin packages that want to interact with the
+# minimap and be available to the user through the minimap settings..
 class Minimap
   Emitter.includeInto(this)
   Debug('minimap').includeInto(this)
   ViewManagement.includeInto(this)
   PluginManagement.includeInto(this)

+  # Public: The default minimap settings
   configDefaults: { plugins: {} }

-  # We'll be using this property to store the toggle state as the
-  # minimapViews object will never be set to null.
+  # Internal: The activation state of the minimap package.
   active: false

+  # Public: Activates the minimap package.
   activate: ->
     atom.workspaceView.command 'minimap:toggle', => @toggleNoDebug()
     atom.workspaceView.command 'minimap:toggle-debug', => @toggleDebug()

+  # Public: Deactivates the minimap package.
   deactivate: ->
     @destroyViews()
     @emit('deactivated')

+  # Public: Toggles the minimap activation state with debug turned on.
+  toggleDebug: ->
+    @getChannel().activate()
+    @toggle()
+
+  # Public: Toggles the minimap activation state with debug turned off.
+  toggleNoDebug: ->
+    @getChannel().deactivate()
+    @toggle()
+
+  # Internal: Toggles the minimap activation state.
   toggle: () ->
     if @active
       @active = false
@@ -35,12 +52,5 @@
       @active = true
       @emit('activated')

-  toggleDebug: ->
-    @getChannel().activate()
-    @toggle()
-
-  toggleNoDebug: ->
-    @getChannel().deactivate()
-    @toggle()
-
+# The minimap module is an instance of the {Minimap} class.
 module.exports = new Minimap()


syntax error and function mispelling, lint

--- lib/pagerv2.coffee
+++ lib/pagerv2.coffee
@@ -50,9 +50,6 @@
       for _, value of @robot.brain.data.pagerv2.custom
         if value.name?
           @robot.brain.data.pagerv2.custom_name[value.name] = value
-    if process.env.PAGERV2_SCHEDULE_FILE?
-      content = fs.readFileSync(process.env.PAGERV2_SCHEDULE_FILE)
-      @robot.brain.data.pagerv2.schedules = JSON.parse(content)
     @logger.debug 'Pagerv2 Loaded'
     if process.env.PAGERV2_LOG_PATH?
       @errorlog = path.join process.env.PAGERV2_LOG_PATH, 'pagerv2-error.log'
@@ -195,20 +192,18 @@
         "Sorry, I can't figure #{user.name} email address. " +
         'Can you ask them to `.pager me as <email>`?'

-  getScheduleByName: (name) ->
-    new Promise (res,err) ->
-      if @robot.brain.data.pagerv2.services[name]?
+  getScheduleIdByName: (name) ->
+    new Promise (res, err) ->
       if @robot.brain.data.pagerv2.schedule[name]?
         res @robot.brain.data.pagerv2.schedule[name]
       else
-        @request('GET'),"/schedules")
+        @request('GET', '/schedules')
         .then (body) ->
           for schedule in body.schedules
             @robot.brain.data.pagerv2.schedule[schedule.name] = schedule.id
             if schedule.name is name
               res schedule.id
-              break
-
+              return

   getSchedule: (schedule_id = process.env.PAGERV2_SCHEDULE_ID) ->
     @request('GET', "/schedules/#{schedule_id}")
@@ -227,7 +222,7 @@
       body.overrides

   getOnCallOrFallBack: (fromtime = null, schedule_id) ->
-    @getOnCall(fromtime,schedule_id)
+    @getOnCall(fromtime, schedule_id)
     .catch (error) ->
       @robot.logger.debug "something went wrong getting the OnCAll #{error}"
       return @getSchedule(schedule_id)
@@ -246,7 +241,11 @@
     .then (body) ->
       body.oncalls[0]

-  setOverride: (from, who, duration = null, start = null, schedule_id = process.env.PAGERV2_SCHEDULE_ID) ->
+  setOverride: (from,
+  who,
+  duration = null,
+  start = null,
+  schedule_id = process.env.PAGERV2_SCHEDULE_ID) ->
     return new Promise (res, err) =>
       if duration? and duration > 1440
         err 'Sorry you cannot set an override of more than 1 day.'


commented

commented

--- lib/wd-sync.coffee
+++ lib/wd-sync.coffee
@@ -2,8 +2,8 @@
 {MakeSync,Sync} = require 'make-sync'

-# We force mixed mode on those, because either they are executed internally
-# in async mode or it makes sense to call them asynchronously
+# we force mixed mode on those, because either they are executed internally
+# in async mode or it makes sense to call them asynchronously.
 mixedArgsMethods = [
   'executeAsync'
   , 'element'
@@ -43,7 +43,7 @@
     args.push done
     _moveTo.apply @, args

-  # fixing click and doubleclick so it can be called without
+  # fixing click and doubleclick so it can be called without arguments
   for m in ['click','doubleclick']
     do ->
       _m = browser[m]
@@ -55,10 +55,7 @@
   # making methods synchronous
   options = buildOptions( mode )
   MakeSync browser, options
-
-  # element and getAttribute may be called internally or externally
-  # , so better stick to this mode
-  for k in mixedArgsMethods
+  for k in mixedArgsMethods # methods forced to mixed-args mode
     do ->
       browser[k] = MakeSync browser[k], mode:['mixed', 'args']

@@ -81,7 +78,9 @@
   # retrieve the browser currently in use
   # useful when writting helpers
   current: -> Fiber.current.wd_sync_browser
-
+
+# starts sync block.
+# the browser is passed in the 'with' option.
 Wd = (options, cb) ->
   [options,cb] = [null,options] if typeof options is 'function'
   if cb?
@@ -95,8 +94,8 @@
       options2 = options if not options2?
       Wd options2, cb2

-# careful, below browser is a function so it get evaluated with the rest
-# of the code
+# wrapper around Wd.
+# a function returning the browser is passed in the 'with' option.
 WdWrap = (options, cb) ->
   [options,cb] = [null,options] if typeof options is 'function'
   if cb?
@@ -104,7 +103,7 @@
       options.pre.apply @, [] if options?.pre?
       Sync ->
         Fiber.current.wd_sync_browser = options?.with?()
-        cb.apply options?.with?(), []
+        cb.apply options?.with?(), []
         done() if done?
   if options
     # returning an identical function with context(browser) preconfigured


IDE: Disable ideView test suite.

IDE: Disable ideView test suite.

--- client/ide/test/index.coffee
+++ client/ide/test/index.coffee
@@ -1,3 +1,3 @@
 # require './collaborationstatemachine.test'
 require './routes.test'
-require './views/tabview/ideview.test'
+# require './views/tabview/ideview.test'


use shorter code to clear frame body

use shorter code to clear frame body

--- js-library/app/js/jail_iframe/classes/control_iframe.coffee
+++ js-library/app/js/jail_iframe/classes/control_iframe.coffee
@@ -22,9 +22,7 @@
     @frameBody = @doc.body

   setContent: (contentNode) ->
-    bodyEl = @doc.body
-    while bodyEl.firstChild
-      bodyEl.removeChild(bodyEl.firstChild)
+    @frameBody.innerHTML = '';
     @frameBody.appendChild(contentNode)
     @sizeFrameToFitContent()


Fix tests

Fix tests

--- client/apps/settings/test/curations.coffee
+++ client/apps/settings/test/curations.coffee
@@ -22,6 +22,8 @@
         id: '1234'
         type: 'editorial-feature'
         sections: [{body: 'foo'}]
+        carousel: []
+        placeholder: ""
       locals = _.extend(fixtures().locals,
         curation: @curation
       )


tests: CollabTest

tests: CollabTest

--- client/test/lib/collaboration/start.coffee
+++ client/test/lib/collaboration/start.coffee
@@ -72,3 +72,5 @@
       startSession browser, firstUser, secondUser
     else
       joinSession browser, firstUser, secondUser
+
+


Tests: Require ide/tests.

Tests: Require ide/tests.

--- client/testrunner/lib/require-tests.coffee
+++ client/testrunner/lib/require-tests.coffee
@@ -1,3 +1,3 @@
 require '../../app/test'
 require '../../activity/test'
-# require '../../ide/test'
+require '../../ide/test'


Added $zero

Added $zero

--- lib/ajax_cursor.coffee
+++ lib/ajax_cursor.coffee
@@ -10,6 +10,8 @@
   # Execution of the Query
   ##############################################
   toJSON: (callback) ->
+    return callback(null, if @hasCursorQuery('$one') then null else []) if @hasCursorQuery('$zero')
+
     # build query
     query = JSONUtils.toQuery(_.extend(_.extend({}, @_find), @_cursor))
     @request


Use comma if its not JTag

Use comma if its not JTag

--- client/app/CommonViews/linkviews/linkgroup.coffee
+++ client/app/CommonViews/linkviews/linkgroup.coffee
@@ -55,9 +55,9 @@
       click       : =>
         new FollowedModalView {group}, @getData()

-    sep = ' '
-    if participants[0] instanceof bongo.api.JAccount
-      sep = ', '
+    sep = ', '
+    if participants[0] instanceof bongo.api.JTag
+      sep = ' '
     switch totalCount
       when 0 then ""
       when 1 then "{{> @participant0}}"


ComputeController: fetchSoloMachines: helper on client side

--- client/app/lib/providers/computecontroller.coffee
+++ client/app/lib/providers/computecontroller.coffee
@@ -1337,3 +1337,14 @@
     return  if not stack or not stack.config

     delete stack.config.adminMessage
+
+
+  fetchSoloMachines: (callback) ->
+
+    return callback null, @_soloMachines  if @_soloMachines
+
+    remote.api.ComputeProvider.fetchSoloMachines (err, res) =>
+      @_soloMachines = res?.machines ? []
+      kd.warn err  if err
+      callback null, @_soloMachines
+


WebtermMessagePane: handle session invalid errors correctly so we can see click here to open a new tab message instead of an unknown error occurred for invalid sessions.

--- client/app/lib/terminal/webtermmessagepane.coffee
+++ client/app/lib/terminal/webtermmessagepane.coffee
@@ -64,7 +64,7 @@
     kd.utils.killRepeat @loader.repeater
     @loader.hide()

-    if err.message is "ErrNoSession"
+    if err.message in ["ErrNoSession", "session doesn't exists"]

       @setMessage \
         "This session is not valid anymore,


Bind kd.NotificationView as KDNotificationView

--- client/app/lib/userenvironmentdataprovider.coffee
+++ client/app/lib/userenvironmentdataprovider.coffee
@@ -5,6 +5,8 @@
 Machine = require 'app/providers/machine'
 sinkrow = require 'sinkrow'

+KDNotificationView = kd.NotificationView
+

 module.exports = UserEnvironmentDataProvider =


fixed bug with post switching inside carousel.

--- client/coffeescript/templates/post_wrapper.coffee
+++ client/coffeescript/templates/post_wrapper.coffee
@@ -127,7 +127,8 @@
         ancestors.push(cur.parent_id)
       if parent._id in ancestors && window.carousel_handle?
         r = Template.post_wrapper.start_carousel(@)
-        Session.set('showing_post', @)
+        unless Session.get('showing_post').parent_id is @parent_id
+          Session.set('showing_post', @)
   }

   start_carousel: (parent_post) ->


fix the express() 3.0 cookie case-sensitivity problem

--- client/landing/app/MainApp/login/loginview.coffee
+++ client/landing/app/MainApp/login/loginview.coffee
@@ -100,7 +100,6 @@
     @loginForm = new LoginInlineForm
       cssClass : "login-form"
       callback : (formData)=>
-        log 'hey-o'
         formData.clientId = $.cookie('clientId')
         @doLogin formData

@@ -275,7 +274,7 @@
           duration: 1000
         @loginForm.resetDecoration()
       else
-        $.cookie 'clientId', replacementToken if replacementToken
+        $.cookie 'clientId', replacementToken  if replacementToken
         @getSingleton('mainController').accountChanged account
         new KDNotificationView
           cssClass  : "login"


oauth: implement fb oauth

oauth: implement fb oauth

--- client/landing/app/MainApp/oauthcontroller.coffee
+++ client/landing/app/MainApp/oauthcontroller.coffee
@@ -16,7 +16,9 @@
     mainController = KD.getSingleton "mainController"

     if err then @notify err
-    else mainController.emit "ForeignAuthCompleted", provider
+    else
+      console.log "authCompleted", provider
+      mainController.emit "ForeignAuthCompleted", provider

   notify: (err)->
     message = if err then err else "Something went wrong"


Tests: Domains: Add date now to domain name.

--- client/test/lib/helpers/environmenthelpers.coffee
+++ client/test/lib/helpers/environmenthelpers.coffee
@@ -232,7 +232,7 @@
     buttonSelector       = '.domains .kdheaderview button.add-button'
     buttonLoaderSelector = '.add-view button.loading'
     paragraph            = helpers.getFakeText()
-    createDomainName     = paragraph.split(' ')[0]
+    createDomainName     = "#{paragraph.split(' ')[0]}#{Date.now()}"
     domainName           = createDomainName + '.' + user.username + '.dev.koding.io'

     browser


an effect fix

an effect fix

--- app/assets/javascripts/app/index.js.coffee
+++ app/assets/javascripts/app/index.js.coffee
@@ -27,7 +27,7 @@
       scale:   '.8'
       opacity: '0'

-    @el.show().gfx
+    @el.delay(100).show().gfx
       scale:   '1'
       opacity: '1'


Remove useless dropdown logic

Remove useless dropdown logic

--- app/assets/javascripts/dropdowns.js.coffee
+++ app/assets/javascripts/dropdowns.js.coffee
@@ -1,7 +0,0 @@
-$(document).ready( ->
-  $(".dropdown-menu li a").click((e) ->
-    e.preventDefault()
-    $(@).parents(".languages-dropdown").find('.btn').html($(@).text() + ' ')
-    $(@).parents(".languages-dropdown").find('.btn').val($(@).data('value'))
-  )
-)


allow adding custom buttons to div.buttons

…and other assorted cleanups that probably don't warrant their own commit

--- app/assets/javascripts/hat-trick.js.coffee
+++ app/assets/javascripts/hat-trick.js.coffee
@@ -6,21 +6,19 @@
     fieldsets = @form.find("fieldset")
     fieldsets.addClass("step")
     # prevent submitting the step that happens to be the last fieldset
-    this.setDefaultButtons()
+    this.addDefaultButtons()
     this.addFakeLastStep()
-    this.enableFormwizard() # unless this.formwizardEnabled()
+    this.enableFormwizard()
     this.setCurrentStepField()
-    # TODO: Try this out instead of putting :start first
-    # this.showStep(@wizard.currentStep)
     this.bindEvents()

   linkClass: "_ht_link"

   buttons: {}

-  setDefaultButtons: ($scope = @form.find("fieldset")) ->
+  addDefaultButtons: ($scope = @form.find("fieldset")) ->
     wizard_buttons = '<input type="reset" /><input type="submit" />'
-    $scope.find("div.buttons").html wizard_buttons
+    $scope.find("div.buttons").prepend wizard_buttons

   findStep: (stepId) ->
     @form.find("fieldset##{stepId}")
@@ -100,7 +98,7 @@

   goToStepId: (stepId) ->
     console.log "Setting up goto #{stepId}"
-    this.setHTMeta("next_step", stepId)
+    this.showStep(stepId)
     @form.formwizard("next")

   repeatStep: (step) ->
@@ -113,9 +111,9 @@
     this.updateSteps()
     @form.formwizard("show", step.name)

-  showStep: (step) ->
-    inputId = "_ht_link_to_#{step.fieldset}"
-    this.setHiddenInput "_ht_step_link", step.fieldset, inputId, @linkClass, this.currentStep()
+  showStep: (stepId) ->
+    inputId = "_ht_link_to_#{stepId}"
+    this.setHiddenInput "_ht_step_link", stepId, inputId, @linkClass, this.currentStep()

   formwizardEnabled: ->
     @form.formwizard?
@@ -217,7 +215,7 @@
         $existingButtons = $buttonsDiv.find(buttonSelector)
         if $existingButtons.length == 0
           # console.log "Adding new #{name}:#{label} button"
-          $newButton = $buttonsDiv.append(this.createButton(name, label))
+          $newButton = $(this.createButton(name, label)).appendTo($buttonsDiv)
           $newButton.click (event) =>
             event.preventDefault()
             this.goToStepId(name)
@@ -230,7 +228,7 @@
         fieldsetContents = $partial.find('fieldset').html()
         $step = $("fieldset##{stepId}")
         $step.html fieldsetContents
-        this.setDefaultButtons($step)
+        this.addDefaultButtons($step)
         this.updateSteps()

   bindEvents: ->
@@ -254,7 +252,7 @@
       if hatTrick.metadata?.currentStep?.repeatOf?
         this.repeatStep(hatTrick.metadata.currentStep)
       else if hatTrick.metadata?.currentStep?
-        this.showStep(hatTrick.metadata.currentStep)
+        this.showStep(hatTrick.metadata.currentStep.fieldset)

 $ ->
   $form = $("form.wizard")


clean up on drag

clean up on drag

--- app/assets/javascripts/views/map.js.coffee
+++ app/assets/javascripts/views/map.js.coffee
@@ -25,6 +25,8 @@
       icon: new @marker_icon, clickable: false, draggable: true)
     @from.on 'dragend', @plan
     @to.on 'dragend', @plan
+    @from.on 'dragstart', @clean_up
+    @to.on 'dragstart', @clean_up
     Bus.events.on 'geocode:complete', @update_markers
     @_polylines = []


reply with "@name, " instead of "@name: "

--- www/src/views/comment/collection.coffee
+++ www/src/views/comment/collection.coffee
@@ -86,7 +86,7 @@
                 success: @resetForm

         composeComment: (opt) ->
-            @textarea().reveal("@#{opt.reply}: ")
+            @textarea().reveal("@#{opt.reply}, ")
             @textarea
             $('html, body').animate {
                 scrollTop: @$('.comment-add').offset().top


(fix) Add tilde to contingent to show that it isn't exact (#1).

--- app/scripts/pages/overview/overview.coffee
+++ app/scripts/pages/overview/overview.coffee
@@ -11,9 +11,9 @@
     @isDue = ko.computed => @dueDate().getTime() < new Date().getTime()
     @isCorrected = ko.computed => @corrected() > @solutions()
     @contingent =
-      should: Math.ceil data.should #TODO why does the server even send fractions here?
+      should: '~' + Math.ceil data.should #TODO remove tilde once this value is exact (see issue #1)
       is: data.is
-    @contingent.ratio = @contingent.is / @contingent.should
+    @contingent.ratio = @contingent.is / Math.ceil data.should

   correct: -> window.location.hash = "#correction/#{@exercise.id()}"

@@ -23,9 +23,7 @@

     api.get.overview()
     .then (data) =>
-      number = 1
       @exercises data.map (exercise) ->
-        exercise.number = number++
         exercise.is = exercise.is
         exercise.should = exercise.should
         new ExerciseCard(exercise)


Skip delimiters on Enter

Skip delimiters on Enter

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -186,6 +186,20 @@
       name: 'open-fullscreen-editor'
       bindKey: {win: 'Ctrl-Shift-M', mac: 'Command-Shift-M|Ctrl-Shift-M'}
       exec: -> Backbone.Mediator.publish 'tome:toggle-maximize', {}
+    addCommand
+      # TODO: Restrict to beginner campaign levels
+      name: 'enter-skip-delimiters'
+      bindKey: 'Enter|Return'
+      exec: =>
+        if @aceSession.selection.isEmpty()
+          cursor = @ace.getCursorPosition()
+          line = @aceDoc.getLine(cursor.row)
+          if delimMatch = line.substring(cursor.column).match /^(["|']?\)+;?)/
+            newRange = @ace.getSelectionRange()
+            newRange.setStart newRange.start.row, newRange.start.column + delimMatch[1].length
+            newRange.setEnd newRange.end.row, newRange.end.column + delimMatch[1].length
+            @aceSession.selection.setSelectionRange newRange
+        @ace.execCommand 'insertstring', '\n'

   fillACE: ->
     @ace.setValue @spell.source


Kill some console logs @poojawins

Kill some console logs @poojawins

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -317,9 +317,7 @@
             xstart = startOfRow(row)
             if language is 'python'
               requiredIndent = new RegExp '^' + new Array(xstart / 4 + 2).join '(    |\t)' + '(\\S|\\s*$)'
-              console.log requiredIndent
               for crow in [docRange.start.row+1..docRange.end.row]
-                console.log("CROW", xstart, crow, lines[crow])
                 unless requiredIndent.test lines[crow]
                   docRange.end.row = crow - 1
                   break


Fix max-range to fit what is used elsewhere

--- client/terrain/object.coffee
+++ client/terrain/object.coffee
@@ -8,7 +8,7 @@
 L = require('leaflet')

 # What does the maximum value of terrain data represent in meters when using 8 bit terrain data?
-OUT_RANGE = 2404
+OUT_RANGE = 2469

 # The number of samples per dimension of the terrain model
 SAMPLES_PER_SIDE = 200


type couchmuffin

type couchmuffin

--- server/src/Component/Builtin/Database/CouchMuffin.coffee
+++ server/src/Component/Builtin/Database/CouchMuffin.coffee
@@ -19,8 +19,7 @@
         @$ = @component 'QueryBuilder', true

     _addType: (data) ->
-        console.log @_type
-        data?._type = @_type unless @_type?
+        data._type = @_type unless @_type? and data?

     _addCreatedAt: (data) ->
         data._createdAt = new Date().toISOString() if @_trackDates


Allow confirmed_at date to be specified

Allow confirmed_at date to be specified

--- services/web/app/coffee/Features/User/UserUpdater.coffee
+++ services/web/app/coffee/Features/User/UserUpdater.coffee
@@ -152,7 +152,10 @@
 				else
 					return callback new Error("non-success code from v1: #{response.statusCode}")

-	confirmEmail: (userId, email, callback) ->
+	confirmEmail: (userId, email, confirmedAt, callback) ->
+		if arguments.length == 3
+			callback = confirmedAt
+			confirmedAt = new Date()
 		email = EmailHelper.parseEmail(email)
 		return callback(new Error('invalid email')) if !email?
 		logger.log {userId, email}, 'confirming user email'
@@ -166,7 +169,7 @@
 				'emails.email': email
 			update =
 				$set:
-					'emails.$.confirmedAt': new Date()
+					'emails.$.confirmedAt': confirmedAt
 			@updateUser query, update, (error, res) ->
 				return callback(error) if error?
 				logger.log {res, userId, email}, "tried to confirm email"


Fix log tailing

Fix log tailing

--- assets/scripts/app/views/job.coffee
+++ assets/scripts/app/views/job.coffee
@@ -100,10 +100,6 @@
       $(window).scrollTop(0)

     jobBinding: 'context'
-
-    toggleTailing: (event) ->
-      Travis.app.tailing.toggle()
-      event.preventDefault()

     logSubscriber: (->
       # for some reason observing context does not work,
@@ -134,6 +130,10 @@
       @_super.apply this, arguments
       @set 'logManager', Travis.Log.create(target: this)

+    toggleTailing: (event) ->
+      Travis.app.tailing.toggle()
+      event.preventDefault()
+
     didInsertElement: ->
       @_super.apply this, arguments


Don't swallow errors when setting cookies

--- assets/javascripts/lib/cookie_store.coffee
+++ assets/javascripts/lib/cookie_store.coffee
@@ -2,28 +2,23 @@
   INT = /^\d+$/

   get: (key) ->
-    try
-      value = Cookies.get(key)
-      value = parseInt(value, 10) if value? and INT.test(value)
-      value
-    catch
+    value = Cookies.get(key)
+    value = parseInt(value, 10) if value? and INT.test(value)
+    value

   set: (key, value) ->
     if value == false
-      return @del(key)
-    else if value == true
-      value = 1
+      @del(key)
+      return

-    try
-      Cookies.set(key, '' + value, path: '/', expires: 1e8)
-      true
-    catch
+    value = 1 if value == true
+    Cookies.set(key, '' + value, path: '/', expires: 1e8)
+    throw new Error("Failed to set cookie '#{key}'") unless @get(key) == value
+    return

   del: (key) ->
-    try
-      Cookies.expire(key)
-      true
-    catch
+    Cookies.expire(key)
+    return

   reset: ->
     try


Move global feed to /global

Move global feed to /global

--- assets/javascripts/routers/posts.js.coffee
+++ assets/javascripts/routers/posts.js.coffee
@@ -4,7 +4,7 @@
   routes:
     ""                 : "root"
     "profile"          : "myProfile"
-    "feed"             : "globalFeed"
+    "global"           : "globalFeed"
     "posts"            : "index"
     "posts/:entity/:post_id" : "conversation"
     "posts/:post_id" : "conversation"
@@ -41,7 +41,7 @@
   globalFeed: =>
     unless TentStatus.config.tent_host_domain and window.location.hostname == "app.#{TentStatus.config.tent_host_domain}"
       return @index()
-    TentStatus.setPageTitle "Global Feed"
+    TentStatus.setPageTitle "Tent.is Global Feed"
     @view = new TentStatus.Views.GlobalFeed

   mentions: =>


needs to be a computed property

needs to be a computed property

--- assets/scripts/app/models/broadcast.coffee
+++ assets/scripts/app/models/broadcast.coffee
@@ -7,12 +7,12 @@
     { type: 'broadcast', id: @get('id'), message: @get('message') }

   isSeen: (->
-    @get('id') in Travis.Broadcast.seen()
+    @get('id') in Travis.Broadcast.get('seen')
   ).property()

   setSeen: ->
-    Travis.Broadcast.seen.pushObject(@get('id'))
-    Travis.storage.setItem('travis.seen_broadcasts', JSON.stringify(Travis.Broadcast.seen()))
+    Travis.Broadcast.get('seen').pushObject(@get('id'))
+    Travis.storage.setItem('travis.seen_broadcasts', JSON.stringify(Travis.Broadcast.get('seen')))
     @notifyPropertyChange('isSeen')

 @Travis.Broadcast.reopenClass
@@ -20,7 +20,7 @@
     seenBroadcasts = Travis.storage.getItem('travis.seen_broadcasts')
     seenBroadcasts = JSON.parse(seenBroadcasts) if seenBroadcasts?
     Ember.A(seenBroadcasts || [])
-  )
+  ).property()

   # TODO fix or monkey-patch the adapter's url and key lookup/generation crap
   # url: 'users/broadcasts'


Expose sendInputEvent in webview

Expose sendInputEvent in webview

--- atom/renderer/lib/web-view/web-view.coffee
+++ atom/renderer/lib/web-view/web-view.coffee
@@ -292,6 +292,7 @@
     "inspectServiceWorker"
     "print"
     "printToPDF"
+    "sendInputEvent"
   ]

   # Forward proto.foo* method calls to WebViewImpl.foo*.


spec: Test setContentSize for frameless window

--- spec/api-browser-window-spec.coffee
+++ spec/api-browser-window-spec.coffee
@@ -117,6 +117,15 @@
       assert.equal after[0], size[0]
       assert.equal after[1], size[1]

+    it 'works for framless window', ->
+      w.destroy()
+      w = new BrowserWindow(show: false, frame: false, width: 400, height: 400)
+      size = [400, 400]
+      w.setContentSize size[0], size[1]
+      after = w.getContentSize()
+      assert.equal after[0], size[0]
+      assert.equal after[1], size[1]
+
   describe 'BrowserWindow.fromId(id)', ->
     it 'returns the window with id', ->
       assert.equal w.id, BrowserWindow.fromId(w.id).id
@@ -130,6 +139,16 @@
       assert.equal contentSize[1], 400

     it 'make window created with window size when not used', ->
+      size = w.getSize()
+      assert.equal size[0], 400
+      assert.equal size[1], 400
+
+    it 'works for framless window', ->
+      w.destroy()
+      w = new BrowserWindow(show: false, frame: false, width: 400, height: 400, 'use-content-size': true)
+      contentSize = w.getContentSize()
+      assert.equal contentSize[0], 400
+      assert.equal contentSize[1], 400
       size = w.getSize()
       assert.equal size[0], 400
       assert.equal size[1], 400


Removed log from tests - oops

Removed log from tests - oops

--- spec/javascripts/events.spec.coffee
+++ spec/javascripts/events.spec.coffee
@@ -26,7 +26,6 @@
 	  it "trigger tab", ->
 	    spyOn(callbacks, "before_insert").and.callThrough()
 	    tab_event = $.Event("keydown.atwhoInner", keyCode: KEY_CODE.TAB)
-	    console.log tab_event
 	    $inputor.trigger(tab_event)
 	    expect(controller.view.visible()).toBe(false)
 	    expect(callbacks.before_insert).toHaveBeenCalled()


GameObject.Effect

GameObject.Effect

--- src/floating_text_effect.coffee
+++ src/floating_text_effect.coffee
@@ -1,5 +1,5 @@
 ###*
-FloatingTextEffect is a simple subclass of `TextEffect`. It provides some defaults
+TextEffect.Floa is a simple subclass of `TextEffect`. It provides some defaults
 to move the text upward and fade it out over 0.5 seconds.

     # adds a FloatingTextEffect to the engine


Downcase all IDs for bulk follow endpoint (for now)

--- components/follow_button/collection.coffee
+++ components/follow_button/collection.coffee
@@ -87,6 +87,7 @@

   followAll: (ids, options = {}) ->
     ids = [ids] unless _.isArray ids
+    ids = _.map ids, (id) -> id.toLowerCase()

     options.success = _.wrap options.success, (success, model, response, options) =>
       @set _.map response, (attributes) =>


adding EVE online sso support (#3389)

adding EVE online sso support (#3389)

* add EVE sso support

* Update custom_oauth_server.coffee

* bah. tab indents.

--- packages/rocketchat-custom-oauth/custom_oauth_server.coffee
+++ packages/rocketchat-custom-oauth/custom_oauth_server.coffee
@@ -120,6 +120,9 @@
 			if identity?.user_id and not identity.id
 				identity.id = identity.user_id

+			if identity?.CharacterID and not identity.id
+				identity.id = identity.CharacterID
+
 			# console.log 'id:', JSON.stringify identity, null, '  '

 			serviceData =
@@ -132,7 +135,7 @@
 				serviceData: serviceData
 				options:
 					profile:
-						name: identity.name or identity.username or identity.nickname
+						name: identity.name or identity.username or identity.nickname or identity.CharacterName

 			# console.log data


Introduced a special class ProxyNode for interior nodes with only one child.

--- lib/collections.coffee
+++ lib/collections.coffee
@@ -87,19 +87,19 @@
 # A sparse interior node using a bitmap to indicate which of the
 # indices 0..31 are in use.
 class BitmapIndexedNode
-  constructor: (@bitmap, @table, @size) ->
+  constructor: (@bitmap, @progeny, @size) ->
     unless @bitmap?
-      @bitmap = 0
-      @table  = []
-      @size   = 0
+      @bitmap  = 0
+      @progeny = []
+      @size    = 0

   each: (func) ->
-    for node in @table
+    for node in @progeny
       node.each(func)

   get: (shift, key, data) ->
     [bit, i] = util.bitPosAndIndex(@bitmap, key, shift)
-    @table[i].get(shift + 5, key, data) if (@bitmap & bit) != 0
+    @progeny[i].get(shift + 5, key, data) if (@bitmap & bit) != 0

   with: (shift, key, leaf) ->
     [bit, i] = util.bitPosAndIndex(@bitmap, key, shift)
@@ -107,84 +107,122 @@
     if (@bitmap & bit) == 0
       n = util.bitCount(@bitmap)
       if n < 8
-        newArray = util.arrayWithInsertion(@table, i, leaf)
+        newArray = util.arrayWithInsertion(@progeny, i, leaf)
         new BitmapIndexedNode(@bitmap | bit, newArray, @size + 1)
       else
-        table = new Array(32)
+        progeny = new Array(32)
         for m in [0..31]
           b = 1 << m
-          table[m] = @table[util.indexForBit(@bitmap, b)] if (@bitmap & b) != 0
-        new ArrayNode(table, util.mask(key, shift), leaf, @size + 1)
-    else
-      v = @table[i]
+          progeny[m] = @progeny[util.indexForBit(@bitmap, b)] if (@bitmap & b) != 0
+        new ArrayNode(progeny, util.mask(key, shift), leaf, @size + 1)
+    else
+      v = @progeny[i]
       node = v.with(shift + 5, key, leaf)
       newSize = @size + node.size - v.size
-      new BitmapIndexedNode(@bitmap, util.arrayWith(@table, i, node), newSize)
+      new BitmapIndexedNode(@bitmap, util.arrayWith(@progeny, i, node), newSize)

   without: (shift, key, data) ->
     [bit, i] = util.bitPosAndIndex(@bitmap, key, shift)

-    v = @table[i]
+    v = @progeny[i]
     node = v.without(shift + 5, key, data)
     if node?
       newBitmap = @bitmap
       newSize   = @size + node.size - v.size
-      newArray  = util.arrayWith(@table, i, node)
+      newArray  = util.arrayWith(@progeny, i, node)
     else
       newBitmap = @bitmap ^ bit
       newSize   = @size - 1
-      newArray  = util.arrayWithout(@table, i)
+      newArray  = util.arrayWithout(@progeny, i)

     bits = util.bitCount(newBitmap)
     if bits == 0
       null
-    else if bits == 1 and not newArray[0].table?
-      newArray[0]
+    else if bits == 1
+      node = newArray[0]
+      if node.progeny?
+        new ProxyNode(util.bitCount(newBitmap - 1), node)
+      else
+        newArray[0]
     else
       new BitmapIndexedNode(newBitmap, newArray, newSize)

-  toString: -> "BitmapIndexedNode(#{@table.join(", ")})"
+  toString: -> "BitmapIndexedNode(#{@progeny.join(", ")})"
+
+
+# Special case of a sparse interior node which has exactly one descendant.
+class ProxyNode
+  constructor: (@child_index, @progeny) ->
+    @size = @progeny.size
+
+  each: (func) -> @progeny.each(func)
+
+  get: (shift, key, data) ->
+    @progeny.get(shift + 5, key, data) if @child_index == util.mask(key, shift)
+
+  with: (shift, key, leaf) ->
+    i = util.mask(key, shift)
+
+    if @child_index == i
+      node = @progeny.with(shift + 5, key, leaf)
+      new ProxyNode(i, node)
+    else
+      bitmap = (1 << @child_index) | (1 << i)
+      array = if i < @child_index then [leaf, @progeny] else [@progeny, leaf]
+      new BitmapIndexedNode(bitmap, array, @size + leaf.size)
+
+  without: (shift, key, data) ->
+    node = @progeny.without(shift + 5, key, data)
+
+    if node?
+      new ProxyNode(@child_index, node)
+    else
+      null
+
+  toString: -> "ProxyNode(#{@progeny})"
+
+ProxyNode.make = (shift, key, leaf) -> new ProxyNode(util.mask(key, shift), leaf)

 # A dense interior node with room for 32 entries.
 class ArrayNode
-  constructor: (baseTable, i, node, @size) ->
-    @table = util.arrayWith(baseTable, i, node)
+  constructor: (progeny, i, node, @size) ->
+    @progeny = util.arrayWith(progeny, i, node)

   each: (func) ->
-    for node in @table
+    for node in @progeny
       node.each(func) if node?

   get: (shift, key, data) ->
     i = util.mask(key, shift)
-    @table[i].get(shift + 5, key, data) if @table[i]?
+    @progeny[i].get(shift + 5, key, data) if @progeny[i]?

   with: (shift, key, leaf) ->
     i = util.mask(key, shift)

-    if @table[i]?
-      node = @table[i].with(shift + 5, key, leaf)
-      newSize = @size + node.size - @table[i].size
-      new ArrayNode(@table, i, node, newSize)
-    else
-      new ArrayNode(@table, i, leaf, @size + 1)
+    if @progeny[i]?
+      node = @progeny[i].with(shift + 5, key, leaf)
+      newSize = @size + node.size - @progeny[i].size
+      new ArrayNode(@progeny, i, node, newSize)
+    else
+      new ArrayNode(@progeny, i, leaf, @size + 1)

   without: (shift, key, data) ->
     i = util.mask(key, shift)

-    node = @table[i].without(shift + 5, key, data)
+    node = @progeny[i].without(shift + 5, key, data)
     if node?
-      new ArrayNode(@table, i, node, @size - 1)
-    else
-      remaining = j for j in [1...@table.length] when j != i and @table[j]
+      new ArrayNode(@progeny, i, node, @size - 1)
+    else
+      remaining = j for j in [1...@progeny.length] when j != i and @progeny[j]
       if remaining.length <= 4
         bitmap = util.reduce(remaining, ((b, j) -> b | (1 << j)), 0)
-        array  = @table[j] for j in remaining
+        array  = @progeny[j] for j in remaining
         new BitmapIndexedNode(bitmap, array, @size - 1)
       else
-        new ArrayNode(@table, i, null, @size - 1)
-
-  toString: -> "ArrayNode(#{(x for x in @table when x?).join(", ")})"
+        new ArrayNode(@progeny, i, null, @size - 1)
+
+  toString: -> "ArrayNode(#{(x for x in @progeny when x?).join(", ")})"

 # --------------------------------------------------------------------


Replaces caret by space in engineName algorithm

--- coffee/home_presenter.coffee
+++ coffee/home_presenter.coffee
@@ -13,7 +13,7 @@

       if c is " "
         outcome += "-"
-      else if c is c.toUpperCase() and i > 0 and trimmedValue[i - 1] != "-"
+      else if c is c.toUpperCase() and i > 0 and trimmedValue[i - 1] != " "
         outcome += "-" + c.toLowerCase()
       else
         outcome += c.toLowerCase()


oh, do always display options

oh, do always display options

--- editor.coffee
+++ editor.coffee
@@ -314,13 +314,15 @@
         fn 'Gets or sets options', (options) ->
           if options?
             $.extend current_options, options
-          cli.object current_options
+          context.success()
+          current_options

       defaults:
         cmd 'Gets or sets default options', (options) ->
           if options?
             $.extend default_options, options
-          cli.object default_options
+          context.success()
+          default_options

       url:
         fn 'Generates a URL for a Graphite image', (args...) ->


thegrid-designsystem-update: Allow to pass custom options

--- tools/designsystem-update.coffee
+++ tools/designsystem-update.coffee
@@ -45,6 +45,7 @@
       designsystem: p.designsystem
       preventAutosolve: not p.autosolve
       staging: p.staging
+      options: p.options
     signed = jwt.sign payload, secret

 newVersion = (secret, payload, callback) ->
@@ -71,11 +72,13 @@
     default:
       autosolve: true
       staging: true
+      options: '{}'
   parsed = minimist args, parseOptions

   parsed.designsystem = parsed._[0]
   parsed.version = parsed._[1]
   parsed.url = parsed._[2]
+  parsed.options = JSON.parse(parsed.options)

   return parsed


GridPlot ToolProxy should not forward 'tools' attr

--- bokehjs/src/coffee/common/grid_plot.coffee
+++ bokehjs/src/coffee/common/grid_plot.coffee
@@ -37,6 +37,7 @@

   set: (attr, value) ->
     super(attr, value)
+    attr = _.omit(attr, "tools")
     for tool in @attributes.tools
       tool.set(attr, value)
     return null


Realign code so maximum line length is kept.

--- src/plugins/image/upload.coffee
+++ src/plugins/image/upload.coffee
@@ -12,10 +12,10 @@
     _create: ->
       @element.html '
         <form class="upload">
-          <input type="file" class="file" name="userfile" accept="image/*" />
-          <input type="hidden" name="tags" value="" />
-          <input type="text" class="caption" name="caption" placeholder="Title" />
-          <button class="uploadSubmit">Upload</button>
+        <input type="file" class="file" name="userfile" accept="image/*" />
+        <input type="hidden" name="tags" value="" />
+        <input type="text" class="caption" name="caption" placeholder="Title" />
+        <button class="uploadSubmit">Upload</button>
         </form>
       '
     _init: ->


Porphyrius - house system default

Porphyrius - house system default


BUGFIX: hide timescamp of directory on detaching.


Set correct auth header

Set correct auth header

--- lib/webserver.coffee
+++ lib/webserver.coffee
@@ -8,6 +8,7 @@

 server.on 'request', (req, res) ->
   if !req.headers.authorization?
+    res.setHeader('www-authenticate', 'Basic')
     res.writeHead 401
     return res.end "auth required"
   authArray = new Buffer(req.headers.authorization.split(' ')[1], 'base64').toString('ascii').split(':')


Change legend text glyph to 'text'

Change legend text glyph to 'text'

--- bokehjs/src/coffee/renderer/glyph/text.coffee
+++ bokehjs/src/coffee/renderer/glyph/text.coffee
@@ -31,7 +31,7 @@
     ctx.font = ctx.font.replace(/\b[\d\.]+[\w]+\b/, '10pt')
     ctx.textAlign = "right"
     ctx.textBaseline = "middle"
-    ctx.fillText("txt", x2, (y1+y2)/2)
+    ctx.fillText("text", x2, (y1+y2)/2)
     ctx.restore()

 class Text extends Glyph.Model


dev helper command to clear debug output on file


fixes to Yes/No/Cancel dialog

fixes to Yes/No/Cancel dialog

* make it wider so on the Mac the three buttons appear in one row
* focus window when the dialog is shown; the Mac doesn't do that automatically
* closing the dialog with the [x] button behaves the same way as Cancel

--- client/editor.coffee
+++ client/editor.coffee
@@ -328,11 +328,15 @@
     if @cm.getValue() == @originalText && @breakpoints.join() == @originalBreakpoints
       @EP(); return
     else if !@dialog
-      @dialog = $("
The object \"#{@name}\" has changed.
Do you want to save the changes?
").dialog buttons: [
-        {text: 'Yes',    click: => @dialog.dialog 'close'; @dialog = null; @EP(); return}
-        {text: 'No',     click: => @dialog.dialog 'close'; @dialog = null; @QT(); return}
-        {text: 'Cancel', click: => @dialog.dialog 'close'; @dialog = null; return}
-      ]
+      window.focus()
+      @dialog = $("
The object \"#{@name}\" has changed.
Do you want to save the changes?
").dialog
+        width: 400
+        close: => @dialog.dialog 'close'; @dialog = null; return
+        buttons: [
+          {text: 'Yes',    click: => @dialog.dialog 'close'; @dialog = null; @EP(); return}
+          {text: 'No',     click: => @dialog.dialog 'close'; @dialog = null; @QT(); return}
+          {text: 'Cancel', click: => @dialog.dialog 'close'; @dialog = null; return}
+        ]
       # When a string is returned from onbeforeunload:
       #   NW.js prevents the window from closing.
       #   Browsers ask the user "Are you sure you want to close this window?"


keep search matches at 1/3 of the editor

--- client/editor.coffee
+++ client/editor.coffee
@@ -188,6 +188,8 @@
       else
         if wrapped then $.alert 'Search wrapping', 'Dyalog APL Error' # [sic]
         cm.setSelections [anchor: cm.posFromIndex(j), head: cm.posFromIndex j + q.length]
+        h = $e.height(); {left, top} = cm.cursorCoords true, 'local'
+        cm.scrollIntoView left: left, right: left, top: top - h / 3, bottom: top + 2 * h / 3
     false

   setDebugger = (x) ->


minor refactorirng of our routes/before filters

--- client/router.coffee
+++ client/router.coffee
@@ -94,13 +94,14 @@
 remove_host_css = ->
   $('link[rel="stylesheet"]').remove()

-
+BASE_HOUSTON_ROUTES = ['home', 'collection', 'document', 'change_password', 'custom_template']
+ALL_HOUSTON_ROUTES = BASE_HOUSTON_ROUTES.concat(['login'])
 Router.onBeforeAction mustBeAdmin,
-  only: (Houston._houstonize_route(name) for name in ['home', 'collection', 'document', 'change_password'])
+  only: (Houston._houstonize_route(name) for name in BASE_HOUSTON_ROUTES)
 Router.onBeforeAction hide_non_admin_stuff,
-  only: (Houston._houstonize_route(name) for name in ['home', 'collection', 'document', 'login', 'custom_template'])
+  only: (Houston._houstonize_route(name) for name in ALL_HOUSTON_ROUTES)
 Router.onBeforeAction remove_host_css,
-  only: (Houston._houstonize_route(name) for name in ['home', 'collection', 'document', 'login'])
+  only: (Houston._houstonize_route(name) for name in ALL_HOUSTON_ROUTES)

 onRouteNotFound = Router.onRouteNotFound
 Router.onRouteNotFound = (args...) ->


Cleanup of image popup

Cleanup of image popup

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -24,18 +24,18 @@
             @options.dialog = jQuery "

Suggestions | Search | Upload

"

             insertImage = () ->
-                uri = $(this).attr('src')
-                document.execCommand "insertImage", null, uri #This may need to insert an image that does not have the same URL as the preview image, since it may be a different size
+                #This may need to insert an image that does not have the same URL as the preview image, since it may be a different size
+                document.execCommand "insertImage", null, $(this).attr('src')
                 widget._closeDialog()

-            @options.dialog.find("#activeimage").click insertImage
+            @options.dialog.find(".halloimage-activeimage").click insertImage

             buttonset = jQuery ""

             id = "#{@options.uuid}-image"
             buttonset.append jQuery("<input id=\"#{id}\" type=\"checkbox\" />Image").button()
             button = jQuery "##{id}", buttonset
-            button.bind "click", (event) ->
+            button.bind "change", (event) ->
                 if widget.options.dialog.dialog "isOpen"
                     widget._closeDialog()
                 else


Cleans up formatting

Cleans up formatting

--- models/user.coffee
+++ models/user.coffee
@@ -1,45 +1,42 @@
-#
-# Model for a single user
-#
-
-Base = require "./base.coffee"
-analytics = require '../lib/analytics.coffee'
-sd = require("sharify").data
 _ = require 'underscore'
 _s = require 'underscore.string'
+Base = require './base.coffee'
+analytics = require '../lib/analytics.coffee'
+{ API_URL, APP_URL } = require('sharify').data

 module.exports = class User extends Base
+  url: ->
+    "#{API_URL}/users/#{@slugOrId()}"

-  url: -> "#{sd.API_URL}/users/#{@slugOrId()}"
+  urlRoot: ->
+    "#{API_URL}/users/#{@slugOrId()}"

-  urlRoot: -> "#{sd.API_URL}/users/#{@slugOrId()}"
-
-  href: -> "#{sd.APP_URL}/#{@get('slug')}"
+  href: ->
+    "#{APP_URL}/#{@get('slug')}"

   slugOrId: ->
-    @get('slug') || @id
+    @get('slug') or @id

   isPremium: ->
     @get('is_pro') is true or @get('is_pro') is 'true'

   startPrivateChannel: ->
     $.ajax
-      type: "POST"
+      type: 'POST'
       url: "#{@url()}/message"
       success: (response) =>
-        analytics.track.click "Collaborative private channel made"
+        analytics.track.click 'Collaborative private channel made'
         location.href = "/#{response.user.slug}/#{response.slug}"

-  getPermissions: (user)->
-    return "" unless user?
+  getPermissions: (user) ->
+    return '' unless user?

     permissions = ['can-read']

-    # user is user
     if user.id is @id
       permissions.push 'can-edit'

-    (_.uniq permissions).join ' '
+    _.uniq(permissions).join ' '

   allows: (permission, user) ->
-    _s.include @getPermissions(user), permission+    _s.include @getPermissions(user), permission


Bug correction in request when method is DELETE

make node-trello request method to correctly call the del method of request module instead of unexistant delete method

--- lib/node-trello.coffee
+++ lib/node-trello.coffee
@@ -47,7 +47,7 @@
       method: method
       json: @addAuthArgs @parseQuery uri, args

-    request[method.toLowerCase()] options, (err, response, body) => callback err, body
+    request[if method is 'DELETE' then 'del' else method.toLowerCase()] options, (err, response, body) => callback err, body

   addAuthArgs: (args) ->
     args.key = @key


Fixed a syntax error in jsdom_wrapper.coffee that slipped through the last commit.

--- src/server/jsdom_wrapper.coffee
+++ src/server/jsdom_wrapper.coffee
@@ -43,7 +43,7 @@
             click : (event) ->
                 url = event.target.href
                 # TODO: how should we handle hash urls?
-                if url)
+                if url
                     if /jsdom_wrapper/.test(browser.window.location)
                         url = "http://localhost:3001" + url
                     browser.load url