:lipstick:

:lipstick:

--- lib/main.coffee
+++ lib/main.coffee
@@ -18,14 +18,14 @@
     atom.views.getView(@statusBarPanel).classList.add("tool-panel", "panel-bottom")

     # Wrap status bar element in a jQuery wrapper for backwards compatibility
-    wrappedStatusBar = $(@statusBar)
-    wrappedStatusBar.appendLeft        = (view) => @statusBar.appendLeft(view)
-    wrappedStatusBar.appendRight       = (view) => @statusBar.appendRight(view)
-    wrappedStatusBar.prependLeft       = (view) => @statusBar.prependLeft(view)
-    wrappedStatusBar.prependRight      = (view) => @statusBar.prependRight(view)
-    wrappedStatusBar.getActiveBuffer   = => @statusBar.getActiveBuffer()
-    wrappedStatusBar.getActiveItem     = => @statusBar.getActiveItem()
-    wrappedStatusBar.subscribeToBuffer = (event, callback) => @statusBar.subscribeToBuffer(event, callback)
+    wrappedStatusBar = $.extend $(@statusBar),
+      appendLeft: (view) => @statusBar.appendLeft(view)
+      appendRight: (view) => @statusBar.appendRight(view)
+      prependLeft: (view) => @statusBar.prependLeft(view)
+      prependRight: (view) => @statusBar.prependRight(view)
+      getActiveBuffer: => @statusBar.getActiveBuffer()
+      getActiveItem: => @statusBar.getActiveItem()
+      subscribeToBuffer: (event, callback) => @statusBar.subscribeToBuffer(event, callback)

     if atom.__workspaceView?
       Object.defineProperty atom.__workspaceView, 'statusBar',


revert last change

revert last change

--- lib/main.coffee
+++ lib/main.coffee
@@ -54,7 +54,6 @@

     # Register commands
     @subscriptions.add atom.commands.add 'atom-workspace', 'nsl-assembler:save-&-transpile': => @buildScript(@consolePanel)
-    @subscriptions.add atom.commands.add 'atom-workspace', 'nsl-assembler:satisfy-package-dependencies': => @satisfyDependencies()

     if atom.config.get('language-nsl.manageDependencies')
       @satisfyDependencies()


Make the github login less annoying

Make the github login less annoying

--- backend/ide-init.coffee
+++ backend/ide-init.coffee
@@ -41,7 +41,6 @@
   webContents = win.webContents

   win.setSkipTaskbar(true)
-  win.setAlwaysOnTop(true)
   win.setMenuBarVisibility(false)
   win.setTitle('Sign in to Github to get started with the Learn IDE')


fix #541

fix #541

--- lib/runtime/evaluation.coffee
+++ lib/runtime/evaluation.coffee
@@ -144,7 +144,7 @@

   cdSelect: ->
     opts = properties: ['openDirectory']
-    dialog.showOpenDialog BrowserWindow.getFocusedWindow(), opts, (path) ->
+    dialog.showOpenDialog BrowserWindow.getFocusedWindow(), opts, (path) =>
       if path? then @_cd path[0]

   _cd: (dir) ->


no longer need to call this

no longer need to call this

--- lib/runtime/evaluation.coffee
+++ lib/runtime/evaluation.coffee
@@ -34,11 +34,9 @@
         if result?
           error = result.type == 'error'
           view = if error then result.view else result
-          fade = not @ink.Result.removeLines editor, start-1, end-1
           r = new @ink.Result editor, [start-1, end-1],
             content: views.render view
             error: error
-            fade: fade
           r.view.classList.add 'julia'
           if error and result.highlights?
             @showError r, result.highlights


clear results on eval

clear results on eval

--- lib/runtime/evaluation.coffee
+++ lib/runtime/evaluation.coffee
@@ -70,6 +70,7 @@

   evalAll: ->
     editor = atom.workspace.getActiveTextEditor()
+    atom.commands.dispatch atom.views.getView(editor), 'inline-results:clear-all'
     @client.evalall({
                       path: editor.getPath()
                       module: editor.juliaModule


linkcontroller : if router is instance of jAccount, pass the entrySlug as an option parameter to avoid mis-linking on avatar view clicks

--- client/Main/linkcontroller.coffee
+++ client/Main/linkcontroller.coffee
@@ -8,14 +8,19 @@
     {JAccount, JGroup, JTag} = KD.remote.api
     data = link.getData?()
     return  unless data?
-    route = switch data.constructor
-      when JAccount   then "/#{data.profile.nickname}"
-      when JGroup     then "/#{data.slug}"
+    options = {}
+    route   = switch data.constructor
+      when JAccount
+        entryPoint = type : "account" # everytime user clicks on avatar view,
+        "/#{data.profile.nickname}"   # regardless of group, user will always
+      when JGroup                     # routed to /USER_NAME page. ~ EA
+        "/#{data.slug}"
       when JTag
         {group, slug} = data
         route = if group is KD.defaultSlug then '' else "/#{group}"
         route += "/Activity/?tagged=#{slug}"
-    KD.getSingleton('router').handleRoute route, {state:data}  if route?
+
+    KD.getSingleton('router').handleRoute route, {state : data, entryPoint}  if route?

   registerLink:(link)->
     id = link.getId()


platform-specific keymaps

platform-specific keymaps


add in where not to go on sign in

add in where not to go on sign in

--- client/views/signIn/signIn.coffee
+++ client/views/signIn/signIn.coffee
@@ -40,7 +40,6 @@

     Meteor.loginWithPassword(Session.get('email'), Session.get('password'), (error)->
       Session.set('password', undefined)
-      console.log("login", Session.get('fromWhere'), AccountsEntry.settings.dashboardRoute)
       if error
         T9NHelper.accountsError error
       else if Session.get('fromWhere')


updated setSpeed

updated setSpeed

--- oridomi.coffee
+++ oridomi.coffee
@@ -866,7 +866,7 @@

   setSpeed: (speed) ->
-    @_setTweening @settings.speed = speed
+    @_setTweening (@_settings.speed = speed), 0

   # Disables oriDomi slicing by showing the original, untouched target element.


fixed _isIdenticalOperation

fixed _isIdenticalOperation

--- oridomi.coffee
+++ oridomi.coffee
@@ -517,8 +517,8 @@
   _isIdenticalOperation: (op) ->
     return true  unless @lastOp.fn
     return false if @lastOp.reset
-    return false if @lastOp[key] isnt op[key] for key in ['angle', 'anchor', 'fn']
-    return false if v isnt @lastOp.options[k] and k isnt 'callback' for k, v of op.options
+    (return false if @lastOp[key] isnt op[key]) for key in ['angle', 'anchor', 'fn']
+    (return false if v isnt @lastOp.options[k] and k isnt 'callback') for k, v of op.options
     true


adding animation on checkout page

adding animation on checkout page

--- app/assets/javascripts/campaigns.js.coffee
+++ app/assets/javascripts/campaigns.js.coffee
@@ -10,6 +10,9 @@
       $(this).hide()

     # Checkout section functions:
+    if($('#checkout').length)
+      $('html,body').animate({scrollTop: $('#checkout').offset().top})
+
     $('#quantity').on "change", (e) ->
       quantity = $(this).val()
       $amount = $('#amount')


Show 1 selected item in bootstrap-multiselect

--- app/assets/javascripts/dashboard.js.coffee
+++ app/assets/javascripts/dashboard.js.coffee
@@ -121,8 +121,7 @@

       if multiselect_boxes && multiselect_boxes.length > 0
         multiselect_boxes.multiselect
-          buttonText: (options, select) ->
-            if options.length == 0 then 'No option selected ...' else "#{options.length} options selected"
+          numberDisplayed: 1

 observer.observe(document.documentElement, {childList: true, subtree: true});


Redeploy

Redeploy

--- app/assets/javascripts/dashboard.js.coffee
+++ app/assets/javascripts/dashboard.js.coffee
@@ -2,23 +2,12 @@
 # # All this logic will automatically be available in application.js.
 # # You can use CoffeeScript in this file: http://coffeescript.org/

-# #counter = 0
-
-# #@playSound = (audioPath) ->
-# 	#audio = new Audio(audioPath)
-# 	#audio.play()
-# 	#console.log 'Play pressed'
-# 	#'hello'
-
-# @stopRefresher = () ->
-# 	clearInterval(@intervalId)
 root = exports ? this

 root.intervalId = -> 0

 @setRefresher = () ->
 	root.intervalId = setInterval(refresh, 30000)
-

 refresh = () ->
 	$.ajax
@@ -38,77 +27,4 @@

 		error: ->
 			console.log('Reload error')
-
-	# divs = document.querySelectorAll('[executeat]');
-	# checkTasks(divs)
-
-# @setActivator = () ->
-# 	divs = document.querySelectorAll('[executeat]');
-# 	console.log "DIVS: " + divs.length
-
-# 	setInterval(checkTasks(divs), 5000)
-
-
-
-
-# checkTasks = (divs) ->
-
-# 	console.log "Checking task time."
-
-# 	for div in divs
-# 		do (div) ->
-# 			divValue = div.getAttribute("executeat")
-
-# 			now = new Date;
-# 			utc_timestamp = Date.UTC(now.getUTCFullYear(),now.getUTCMonth(), now.getUTCDate() , now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds());
-# 			#currentTime = new Date().getTime()
-
-# 			intValue = parseInt(divValue)
-# 			intCurrent = parseInt(utc_timestamp)
-
-# 			if (intValue > intCurrent - 30000 && intValue < intCurrent + 30000)
-# 				console.log "We have right div!"
-
-# printText = (text) ->
-# 	#counter += 1
-# 	#text = "Printed counter: " + counter
-
-# 	fetchTaskList()
-
-# 	console.log(text)
-
-# @setTimer = () ->
-# 	setInterval(printText, 5000)
-
-# fetchTaskList = () ->
-# 	$.ajax
-# 		url: '/list/tasks'
-# 		type: 'GET'
-# 		success: (data, status, response) ->
-
-# 			#console.log('Success: ' + JSON.stringify(data))
-
-# 			taskArray = data.tasks
-
-# 			#console.log('Tasks Array: ' + JSON.stringify(taskArray))
-
-# 			for task in taskArray
-# 				do (task) ->
-# 					#console.log("Date: " + Date.parse(task.date_to_execute))
-# 					#console.log("Current Date: " + (new Date).getTime())
-
-# 					tasksDate = Date.parse(task.date_to_execute)
-# 					currentDate = (new Date).getTime()
-
-# 					if task.was_shown == false && tasksDate > tasksDate - 30000 && currentDate + 30000 > currentDate
-# 						task.was_shown = true
-# 						alert(task.title)
-
-
-
-# 		error: ->
-# 			console.log('Error')
-
-
-
-# 	+


Ensure that table ops work for every table.

--- app/assets/javascripts/databases.js.coffee
+++ app/assets/javascripts/databases.js.coffee
@@ -47,6 +47,7 @@
   $.get "/tables/#{table_id}", (data, textStatus, jqXHR) ->
     $('.database .tables .table').append($(data))
     bindEventHandlers()
+    enableTableOps()

 columnsReordered = ->
   console.log('Columns reordered') # TODO: Send updates to server, so column order is persisted.
@@ -123,6 +124,7 @@
   enableEditables()
   enableDataTables()
   enableColumnHeaders()
+  enableTableOps()

 $ ->
   bindEventHandlers()
@@ -166,13 +168,16 @@
   $(".edit-column #column_linked_table").on 'change', (e) ->
     toggleLinkColumnFields $(e.target).val()

-  $('form.add-record').on 'click', (e) ->
+  enableTableOps()
+
+enableTableOps = () ->
+  $('form.add-record').on 'submit', (e) ->
     e.preventDefault()
     $.post '/records', {table_id: $('.database .tables .table').data('id')}, (data, textStatus, jqXHR) ->
       add_new_record_to_table(data['id'])
     , 'json'

-  $('form.add-column').on 'click', (e) ->
+  $('form.add-column').on 'submit', (e) ->
     e.preventDefault()
     num_columns = $('table.data-table thead tr th:not(.actions)').length
     new_column_name = "Column #{num_columns + 1}"


pass entire row object to column filter fn if no property defined

--- coffee/directives/fixtable.coffee
+++ coffee/directives/fixtable.coffee
@@ -223,7 +223,8 @@
 					for i in [0..scope.data.length-1].reverse()
 						for filter in scope.columnFilters
 							filterFn = fixtableFilterTypes[filter.type].filterFn
-							unless filterFn scope.data[i][filter.property], filter.values
+							testValue = if filter.property then scope.data[i][filter.property] else scope.data[i]
+							unless filterFn testValue, filter.values
 								scope.data.splice i, 1
 								break


Fixed scale rating UI.

Fixed scale rating UI.

--- coffee/fields/scale_rating.coffee
+++ coffee/fields/scale_rating.coffee
@@ -3,8 +3,7 @@
   view: """
     <%var field_options = (rf.get(Formbuilder.options.mappings.OPTIONS) || [])%>

-

-

+

           <%= rf.get(Formbuilder.options.mappings.STARTING_POINT_TEXT) %>

@@ -13,7 +12,6 @@
         <% for ( var i = 0 ; i < field_options.length ; i++) { %>

             <%= i+1 %>
-

               <input type='radio' value='<%= i+1 %>'
                 <%=
@@ -25,8 +23,7 @@

         <% } %>

-

-

+

           <%= rf.get(Formbuilder.options.mappings.ENDING_POINT_TEXT) %>


prevent action on clipboard events when disabled (#2722)

fixes #2460

--- coffee/lib/abstract-chosen.coffee
+++ coffee/lib/abstract-chosen.coffee
@@ -303,6 +303,7 @@
         break

   clipboard_event_checker: (evt) ->
+    return if @is_disabled
     setTimeout (=> this.results_search()), 50

   container_width: ->


Switched places of calling set_default_values() and set_default_text() from the AbstractChosen constructor to prevent that chosen.proto.coffee uses @results_none_found before it is set.

--- coffee/lib/abstract-chosen.coffee
+++ coffee/lib/abstract-chosen.coffee
@@ -7,10 +7,9 @@
 class AbstractChosen

   constructor: (@form_field, @options={}) ->
-    this.set_default_values()
-
     @is_multiple = @form_field.multiple
     this.set_default_text()
+    this.set_default_values()

     this.setup()


OX-120 debug

OX-120 debug

--- app/assets/javascripts/model/binary.coffee
+++ app/assets/javascripts/model/binary.coffee
@@ -159,6 +159,9 @@
       unless lastPosition
         lastPosition = [0, 0, 0]

+      unless direction
+        direction = [1, 0, 0]
+
       @lastPosition = position
       @lastZoomSteps = zoomSteps.slice(0)
       @lastDirection = direction
@@ -187,19 +190,21 @@
         position[1] - lastPosition[1],
         position[2] - lastPosition[2]
       ]
-
-      directionMax = Math.abs(Math.max(newDirection[0], newDirection[1], newDirection[2]))
-      newDirectionMax = [
-          newDirection[0] / directionMax,
-          newDirection[1] / directionMax,
-          newDirection[2] / directionMax
-        ]

       direction = [
         direction[0] * 0.8 + newDirection[0] * 0.2,
         direction[1] * 0.8 + newDirection[1] * 0.2,
         direction[2] * 0.8 + newDirection[2] * 0.2
       ]
+
+      directionMax = Math.abs(Math.max(direction[0], direction[1], direction[2]))
+
+      unless directionMax = 0
+        direction = [
+          direction[0] / directionMax,
+          direction[1] / directionMax,
+          direction[2] / directionMax
+        ]

       delta_x = delta_y = delta_z = 0
       direction_x = direction_y = direction_z = 0


fixed merge again

fixed merge again

--- app/assets/javascripts/model/binary.coffee
+++ app/assets/javascripts/model/binary.coffee
@@ -1,10 +1,7 @@
 ### define
 model/binary/interpolation_collector : InterpolationCollector
 model/binary/polyhedron_rasterizer : PolyhedronRasterizer
-<<<<<<< HEAD
-=======
 model/binary/cube : Cube
->>>>>>> df86ce244a657a21f6714847aaaf399e3a57b311
 model/game : Game
 libs/simple_array_buffer_socket : SimpleArrayBufferSocket
 libs/simple_worker : SimpleWorker


Turn off existing event listeners

Turn off existing event listeners

--- app/assets/javascripts/user_tabs.js.coffee
+++ app/assets/javascripts/user_tabs.js.coffee
@@ -69,6 +69,10 @@
     @activateTab(action)

   bindEvents: ->
+    # Turn off existing event listeners
+    $(document).off 'shown.bs.tab', '.nav-links a[data-toggle="tab"]'
+
+    # Set event listeners
     $(document).on 'shown.bs.tab', '.nav-links a[data-toggle="tab"]', @tabShown

   tabStateInit: ->


Enable classroom version items, gems, and exp by default

Previously, this was a setting that could be enabled, but defaulted to
disabled. Now, with the default of enabled, students in existing
classrooms will automatically see these features. Teachers can disable
these features in each classrooms' settings.

--- app/schemas/models/classroom.schema.coffee
+++ app/schemas/models/classroom.schema.coffee
@@ -6,7 +6,7 @@
   title: 'Classroom'
   required: ['name']
   default:
-    classroomItems: false
+    classroomItems: true

 c.extendNamedProperties ClassroomSchema  # name first


minor config.period improvement

minor config.period improvement

--- src/scripts/daterangepicker/config.coffee
+++ src/scripts/daterangepicker/config.coffee
@@ -29,7 +29,8 @@
     ko.observable(val || 'UTC')

   _period: (val) ->
-    Period.extendObservable(ko.observable(val || 'day'))
+    val = 'day' unless val in ['day', 'week', 'month', 'quarter', 'year']
+    Period.extendObservable(ko.observable(val))

   _periods: (val) ->
     ko.observableArray(val || Period.allPeriods)


test(body): remove on-the-fly platform change test

--- modules/directives/body/test/index.coffee
+++ modules/directives/body/test/index.coffee
@@ -16,14 +16,3 @@
     it 'should have default class ios', ->
       expect(element.hasClass 'ios').toBe true
       expect(element.hasClass config.platform).toBe true
-
-    it 'should reflect changed config', ->
-      config.platform = 'ios7'
-      scope.$apply()
-      expect(element.hasClass 'ios7').toBe true
-      expect(element.hasClass config.platform).toBe true
-
-      config.platform = 'android'
-      scope.$apply()
-      expect(element.hasClass 'android').toBe true
-      expect(element.hasClass config.platform).toBe true


selections for ovals

selections for ovals

--- static/coffee/renderers/glyph/oval.coffee
+++ static/coffee/renderers/glyph/oval.coffee
@@ -12,8 +12,20 @@
 class OvalView extends GlyphView

   initialize: (options) ->
-    glyphspec = @mget('glyphspec')
-    @glyph_props = new glyph_properties(
+    ##duped in many classes
+    @glyph_props = @init_glyph(@mget('glyphspec'))
+    if @mget('selection_glyphspec')
+      spec = _.extend({}, @mget('glyphspec'), @mget('selection_glyphspec'))
+      @selection_glyphprops = @init_glyph(spec)
+    if @mget('nonselection_glyphspec')
+      spec = _.extend({}, @mget('glyphspec'), @mget('nonselection_glyphspec'))
+      @nonselection_glyphprops = @init_glyph(spec)
+    ##duped in many classes
+    @do_fill   = @glyph_props.fill_properties.do_fill
+    @do_stroke = @glyph_props.line_properties.do_stroke
+    super(options)
+  init_glyph : (glyphspec) ->
+    glyph_props = new glyph_properties(
       @,
       glyphspec,
       ['x', 'y', 'width', 'height', 'angle'],
@@ -22,16 +34,17 @@
         new line_properties(@, glyphspec)
       ]
     )
-
-    @do_fill   = @glyph_props.fill_properties.do_fill
-    @do_stroke = @glyph_props.line_properties.do_stroke
-    super(options)
+    return glyph_props

   _set_data: (@data) ->
     @x = @glyph_props.v_select('x', data)
     @y = @glyph_props.v_select('y', data)
     angles = (@glyph_props.select('angle', obj) for obj in data) # TODO deg/rad
     @angle = (-angle for angle in angles) # TODO deg/rad
+    #duped
+    @selected_mask = new Array(data.length-1)
+    for i in [0..@selected_mask.length-1]
+      @selected_mask[i] = false

   _render: () ->
     [@sx, @sy] = @plot_view.map_to_screen(@x, @glyph_props.x.units, @y, @glyph_props.y.units)
@@ -41,10 +54,24 @@
     ctx = @plot_view.ctx

     ctx.save()
+    #duped
+    selected = @mget_obj('data_source').get('selected')
+    for idx in selected
+      @selected_mask[idx] = true
     if @glyph_props.fast_path
       @_fast_path(ctx)
     else
-      @_full_path(ctx)
+      ##duped in many classes
+      if selected and selected.length and @nonselection_glyphprops
+        if @selection_glyphprops
+          props =  @selection_glyphprops
+        else
+          props = @glyph_props
+        @_full_path(ctx, props, 'selected')
+        @_full_path(ctx, @nonselection_glyphprops, 'unselected')
+      else
+        @_full_path(ctx)
+      ##duped in many classes
     ctx.restore()

   _fast_path: (ctx) ->
@@ -85,11 +112,18 @@
         ctx.translate(-@sx[i], -@sy[i])
       ctx.stroke()

-  _full_path: (ctx) ->
+  _full_path: (ctx, glyph_props, use_selection) ->
+    if not glyph_props
+      glyph_props = @glyph_props
     for i in [0..@sx.length-1]
       if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
         continue
-
+      if isNaN(@sx[i] + @sy[i] + @sw[i] + @sh[i] + @angle[i])
+        continue
+      if use_selection == 'selected' and not @selected_mask[i]
+        continue
+      if use_selection == 'unselected' and @selected_mask[i]
+        continue
       ctx.translate(@sx[i], @sy[i])
       ctx.rotate(@angle[i])

@@ -100,11 +134,11 @@
       ctx.closePath()

       if @do_fill
-        @glyph_props.fill_properties.set(ctx, @data[i])
+        glyph_props.fill_properties.set(ctx, @data[i])
         ctx.fill()

       if @do_stroke
-        @glyph_props.line_properties.set(ctx, @data[i])
+        glyph_props.line_properties.set(ctx, @data[i])
         ctx.stroke()

       ctx.rotate(-@angle[i])
@@ -147,6 +181,24 @@
     ctx.stroke()

     ctx.restore()
+  ##duped
+  select : (xscreenbounds, yscreenbounds) ->
+    xscreenbounds = [@plot_view.view_state.sx_to_device(xscreenbounds[0]),
+      @plot_view.view_state.sx_to_device(xscreenbounds[1])]
+    yscreenbounds = [@plot_view.view_state.sy_to_device(yscreenbounds[0]),
+      @plot_view.view_state.sy_to_device(yscreenbounds[1])]
+    xscreenbounds = [_.min(xscreenbounds), _.max(xscreenbounds)]
+    yscreenbounds = [_.min(yscreenbounds), _.max(yscreenbounds)]
+    selected = []
+    for i in [0..@sx.length-1]
+      if xscreenbounds
+        if @sx[i] < xscreenbounds[0] or @sx[i] > xscreenbounds[1]
+          continue
+      if yscreenbounds
+        if @sy[i] < yscreenbounds[0] or @sy[i] > yscreenbounds[1]
+          continue
+      selected.push(i)
+     return selected

 class Oval extends Glyph


minor sig changes

minor sig changes

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -114,7 +114,7 @@
     # the kernel boots up. With no arguments it returns the launcher.
     # This is a convenient way of running additions config routines,
     # when designing the derivative kernels with custom configuration.
-    @configure: (explain, routine) ->
+    @configure: (xexplain, xroutine) ->
         {series, apply} = async or require "async"
         assert _.isString config = "Configuring: %s"
         bareCall = (try arguments.length or 0) is 0
@@ -122,6 +122,8 @@
         gr = (o) -> try o.routine.apply.bind o.routine
         lg = (o) -> logger.info config, o.explain.bold
         fn = (t) -> (o) -> (a...) -> lg o; gr(o) t, a
+        explain = _.find(arguments, _.isString) or null
+        routine = _.find(arguments, _.isFunction) or 0
         assert _.isArray $configure = @$configure or []
         return (-> series _.map $configure, fn @) if run
         return (-> null) if not @$configure and bareCall


fix some weird nconf error

fix some weird nconf error

--- library/nucleus/scaled.coffee
+++ library/nucleus/scaled.coffee
@@ -298,8 +298,7 @@
         record = @seaport.register identica, cfg
         assert _.isNumber(record), "got mistaken"
         logger.info msg.green, "#{record}".bold
-        assert config?.server?.https = record
-        nconf.set config; super; return this
+        nconf.set "server:https", record; super

     # Setup and launch either HTTP or HTTPS servers to listen at
     # the configured addresses and ports. This method reads up the
@@ -318,5 +317,4 @@
         record = @seaport.register identica, cfg
         assert _.isNumber(record), "got mistaken"
         logger.info msg.green, "#{record}".bold
-        assert config?.server?.http = record
-        nconf.set config; super; return this
+        nconf.set "server:http", record; super


Unit Test fail

Unit Test fail

Signed-off-by: Raghu <0aa38c2facaa05f699cb077ebe8e93d3eed7097f@openly.co>

--- test/unit_test/lib/controller.coffee
+++ test/unit_test/lib/controller.coffee
@@ -5,7 +5,7 @@

   errorFn = ()->
     contrObj.setupRoutes()
-  errorFn.should.throw()
+  errorFn.should.not.throw()

 describe 'Controller Super Class', ->
   it 'should throw error if the setupRoutes is not defined in subclass', errorOnNoSetupRoutes


Don't override components we already know about, just amend them

--- src/plugins/nofloLibrary.coffee
+++ src/plugins/nofloLibrary.coffee
@@ -37,22 +37,29 @@
   prepareComponents: (graph) ->
     components = {}
     graph.nodes.forEach (node) =>
-      components[node.component] =
-        name: node.component
-        description: ''
-        inPorts: []
-        outPorts: []
+      unless components[node.component]
+        components[node.component] =
+          name: node.component
+          description: ''
+          inPorts: []
+          outPorts: []
       graph.edges.forEach (edge) ->
         if edge.from.node is node.id
+          for outport in components[node.component].outPorts
+            return if outport.id is edge.from.port
           components[node.component].outPorts.push
             id: edge.from.port
             type: 'all'
         if edge.to.node is node.id
+          for inport in components[node.component].inPorts
+            return if inport.id is edge.to.port
           components[node.component].inPorts.push
             id: edge.to.port
             type: 'all'
       graph.initializers.forEach (iip) ->
         if iip.to.node is node.id
+          for inport in components[node.component].inPorts
+            return if inport.id is iip.to.port
           components[node.component].inPorts.push
             id: iip.to.port
             type: 'all'


pls spare me from all the searching

pls spare me from all the searching

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -43,6 +43,18 @@
     audioBeep: false
     closeDeletedFileTabs: true
     excludeVcsIgnoredPaths: false
+    ignoredNames: [
+      ".git"
+      ".hg"
+      ".svn"
+      ".DS_Store"
+      "._*"
+      "Thumbs.db"
+      "desktop.ini"
+      "tmp"
+      "htmlcov"
+      "env"
+    ]
     packagesWithKeymapsDisabled: [
       "python-autopep8"
     ]


Update Atom config

Update Atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -24,13 +24,16 @@
     coloured: false
   "language-log":
     tail: true
-  linter:
-    showErrorPanel: false
   "linter-js-yaml":
     customTags: [
       "!include"
+      "!include_dir_list"
+      "!include_dir_named"
+      "!include_dir_merge_list"
+      "!include_dir_merge_named"
     ]
   "linter-pylama":
+    ignoreErrorsAndWarnings: "D203,D212,D213,D404,E501"
     pylamaVersion: "internal"
     usePep257: false
   "one-dark-ui":


fix atom workspace config to be atom 1.0 compliant

atom.workspaceView is no longer available

--- atom.symlink/init.coffee
+++ atom.symlink/init.coffee
@@ -1,6 +1,5 @@
 path = require 'path'

-atom.workspaceView.eachEditorView (editorView) ->
-  editor = editorView.getEditor()
+atom.workspace.observeTextEditors (editor) ->
   if path.extname(editor.getPath()) is '.md'
     editor.setSoftWrap(true)


Bongo: if selector is instance of a regex we can not traverse over it with for own in/of, just return the selector as casted value if the selector is not traversable

--- node_modules_koding/bongo/lib/util.coffee
+++ node_modules_koding/bongo/lib/util.coffee
@@ -19,10 +19,11 @@
   return casted

 castAll = (selector, konstructor, parents = []) ->
+
+  return selector if selector instanceof RegExp
+
   casted = {}
-
   for own key, node of selector
-
     path      = parents.concat key
     pathName  = path.join '.'
     nodeType  = konstructor.types?[pathName]
@@ -47,13 +48,13 @@
            not konstructor.dontAutoCastId

         new ObjectId node
-
+
       when nodeType is String and node instanceof RegExp
         node
-
+
       when not parents.length and konstructor.castValue? and nodeType?
         konstructor.castValue node, nodeType
-
+
       else node

   return casted
@@ -83,4 +84,4 @@
     result

   convertComplexSelector: convertComplexSelector
-  castAll: castAll+  castAll: castAll


Use cryptoServiceLoader instead of searchKeySerializer for encrypt

--- js/src/auth/SearchCredentialService.coffee
+++ js/src/auth/SearchCredentialService.coffee
@@ -9,16 +9,22 @@
   'kryptnostic.crypto-key-storage-api'
   'kryptnostic.credential-loader'
   'kryptnostic.search-key-serializer'
+  'kryptnostic.crypto-service-loader'
+  'kryptnostic.aes-crypto-service'
+  'kryptnostic.block-ciphertext'
 ], (require) ->

-  _                      = require 'lodash'
-  Promise                = require 'bluebird'
-  Logger                 = require 'kryptnostic.logger'
-  AuthenticationStage    = require 'kryptnostic.authentication-stage'
-  CredentialLoader       = require 'kryptnostic.credential-loader'
-  CryptoKeyStorageApi    = require 'kryptnostic.crypto-key-storage-api'
-  SearchKeySerializer    = require 'kryptnostic.search-key-serializer'
-  SearchKeyGenerator     = require 'kryptnostic.search-key-generator'
+  _                   = require 'lodash'
+  Promise             = require 'bluebird'
+  Logger              = require 'kryptnostic.logger'
+  AuthenticationStage = require 'kryptnostic.authentication-stage'
+  CredentialLoader    = require 'kryptnostic.credential-loader'
+  CryptoKeyStorageApi = require 'kryptnostic.crypto-key-storage-api'
+  SearchKeySerializer = require 'kryptnostic.search-key-serializer'
+  SearchKeyGenerator  = require 'kryptnostic.search-key-generator'
+  CryptoServiceLoader = require 'kryptnostic.crypto-service-loader'
+  AesCryptoService    = require 'kryptnostic.aes-crypto-service'
+  BlockCiphertext     = require 'kryptnostic.block-ciphertext'

   log = Logger.get('SearchCredentialService')

@@ -33,6 +39,7 @@
       setter    : (api) -> api.setFhePrivateKey
       stage     : AuthenticationStage.FHE_KEYGEN
       encrypt   : true
+      id        : 'FHE_PRIVATE_KEY'
     }
     SEARCH_PRIVATE_KEY : {
       generator : (clientKeys) -> clientKeys.searchPrivateKey
@@ -40,6 +47,7 @@
       setter    : (api) -> api.setSearchPrivateKey
       stage     : AuthenticationStage.SEARCH_KEYGEN
       encrypt   : true
+      id        : 'SEARCH_PRIVATE_KEY'
     }
     CLIENT_HASH_FUNCTION : {
       generator : (clientKeys) -> clientKeys.clientHashFunction
@@ -47,22 +55,27 @@
       setter    : (api) -> api.setClientHashFunction
       stage     : AuthenticationStage.CLIENT_HASH_GEN
       encrypt   : false
+      id        : 'CLIENT_HASH_FUNCTION'
     }
   }

-  serializeKey = ({ credentialType, uint8Key, searchKeySerializer }) ->
+  serializeKey = ({ credentialType, uint8Key, cryptoServiceLoader }) ->
     if _.isEmpty(uint8Key)
       return uint8Key
     else if credentialType.encrypt
-      return searchKeySerializer.encrypt(uint8Key)
+      cryptoServiceLoader.getObjectCryptoService(credentialType.id, { expectMiss : true })
+      .then (cryptoService) =>
+        return cryptoService.encryptUint8Array(uint8Key)
     else
       return uint8Key

-  deserializeKey = ({ credentialType, uint8Key, searchKeySerializer }) ->
+  deserializeKey = ({ credentialType, uint8Key, cryptoServiceLoader }) ->
     if _.isEmpty(uint8Key)
       return uint8Key
     else if credentialType.encrypt
-      return searchKeySerializer.decrypt(uint8Key)
+      cryptoServiceLoader.getObjectCryptoService(credentialType.id, { expectMiss : true })
+      .then (cryptoService) =>
+        return cryptoService.decryptToUint8Array(BlockCiphertext(uint8Key))
     else
       return uint8Key

@@ -79,6 +92,7 @@
       @cryptoKeyStorageApi = new CryptoKeyStorageApi()
       @searchKeyGenerator  = new SearchKeyGenerator()
       @searchKeySerializer = new SearchKeySerializer()
+      @cryptoServiceLoader = new CryptoServiceLoader()

     # initializes keys if needed.
     ensureCredentialsInitialized: ( notifier = -> ) ->
@@ -91,6 +105,12 @@
         else
           return Promise.resolve()

+    #
+    # returns: {
+    #  FHE_PRIVATE_KEY      : Uint8Array
+    #  SEARCH_PRIVATE_KEY   : Uint8Array
+    #  CLIENT_HASH_FUNCTION : Uint8Array
+    # }
     getAllCredentials: ->
       Promise.resolve()
       .then =>
@@ -113,7 +133,7 @@
         return _.mapValues(credentialsByType, (credential, typeKey) =>
           credentialType = CredentialType[typeKey]
           uint8Key       = credential
-          return deserializeKey({ credentialType, uint8Key, @searchKeySerializer })
+          return deserializeKey({ credentialType, uint8Key, @cryptoServiceLoader })
         )

     hasInitialized: ->
@@ -156,7 +176,7 @@
         Promise.resolve(notifier(credentialType.stage))
       .then =>
         uint8Key        = credentialType.generator(clientKeys)
-        storeableKey    = serializeKey({ credentialType, uint8Key, @searchKeySerializer })
+        storeableKey    = serializeKey({ credentialType, uint8Key, @cryptoServiceLoader })
         storeCredential = credentialType.setter(@cryptoKeyStorageApi)
         storeCredential(storeableKey)
       .then ->


Also allow . , ; : ! ( ) in between words

--- js-library/app/js/jail_iframe/util/create.coffee
+++ js-library/app/js/jail_iframe/util/create.coffee
@@ -16,4 +16,4 @@

 FactlinkJailRoot.textSelected = ->
   # At least 4 words of at least 2 characters
-  /(\w{2,}[\s-_&\/#%]+){4}/.test window.document.getSelection().toString()
+  /(\w{2,}[\s-_&\/#%.,;:!()]+){4}/.test window.document.getSelection().toString()


Better search value handling

Better search value handling

--- components/search_bar/view.coffee
+++ components/search_bar/view.coffee
@@ -63,7 +63,9 @@
   checkSubmission: (e) ->
     @hideSuggestions()
     return if !(e.which is 13) or @selected?
-    @trigger 'search:entered', @query
+
+    unless @isEmpty()
+      @trigger 'search:entered', encodeURIComponent(@$input.val())

   indicateLoading: ->
     @renderFeedback()


Update itemform methods

Update itemform methods

--- public/coffeescripts/itemform.coffee
+++ public/coffeescripts/itemform.coffee
@@ -15,25 +15,14 @@

   insertFields = (data) ->
     dataKeys = Object.keys(data)
+    for key in Object.keys(data)
+      addFieldData key, data[key]
     if data.parentCollection
       for radio in $('#partOfCollection input')
         if data.parentCollection == $(radio).val()
           $(radio).prop('checked', true)
     if data.showcase == 'true' then $('#extended input[value="true"]').prop 'checked', true else $('#extended input[value="false"]').prop 'checked', true
-    i = 0
-    while i < dataKeys.length
-      key = dataKeys[i]
-      keyData = data[key]
-      if typeof keyData == 'string' or key == 'Images'
-        addFieldData key, keyData
-      else if typeof keyData == 'object'
-        key_2 = Object.keys(keyData)
-        keyData_2 = keyData
-        j = 0
-        while j < key_2.length
-          addFieldData key + '\\:' + key_2[j], keyData_2[key_2[j]]
-          j++
-      i++
+    if data.featured == 'true' then $('#featured input[value="true"]').prop 'checked', true else $('#featured input[value="false"]').prop 'checked', true

   addFieldData = (key, data) ->
     field = $('form').find('#' + key).children('[name=' + key + ']')


add mapSortOrder tests

add mapSortOrder tests

--- tests/mixins/Query.mixin.test.coffee
+++ tests/mixins/Query.mixin.test.coffee
@@ -89,6 +89,38 @@
     test.equal regex, orProperty.$regex, "Calling mapQuery should set an and property on each searchable key with the global search."
     test.equal options, orProperty.$options, "Calling mapQuery should set an and property on each searchable key with the global search."

+  Tinytest.add "jQuery DataTables Mixins - Query:mapSortOrder( Number, Object )", ( test ) ->
+    column =
+      mDataProp: "somePropertyKey"
+
+    otherColumn =
+      mDataProp: "someOtherKey"
+
+    data = []
+    data[ "mDataProp_0" ] = value: column.mDataProp
+    data[ "iSortCol_0" ] = value: 0
+    data[ "sSortDir_0" ] = value: "asc"
+    data[ "mDataProp_1" ] = value: otherColumn.mDataProp
+    data[ "iSortCol_1" ] = value: 1
+    data[ "sSortDir_1" ] = value: "desc"
+
+    sortIndex = 1
+
+    component = UI.renderWithData Template.DataTable, ReactiveData
+    tI = component.templateInstance
+    $DOM = $( '

' )
+    UI.insert component, $DOM
+
+    tI.tableState
+      sort: {}
+
+    tI.mapSortOrder 1, data
+    tI.mapSortOrder 2, data
+
+    console.log tI.tableState()
+
+    test.equal tI.tableState().sort[ column.mDataProp ], 1, "A datatable with sort asc set maps to a sort element in the tablestate of 1."
+    test.equal tI.tableState().sort[ otherColumn.mDataProp ], -1, "A datatable with sort desc set maps to a sort element in the tablestate of -1."

@@ -96,3 +128,7 @@

+
+
+
+


Add autoSize trigger

Add autoSize trigger


Don't show visual indent for comment ace things are blocks.

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -264,6 +264,13 @@

     if me.level() < 20 or aceConfig.indentGuides
       # Add visual ident guides
+      language = @spell.language
+      ensureLineStartsBlock = (line) ->
+        return false unless language is "python"
+        match = /^\s*([^#]+)/.exec(line)
+        return false if not match?
+        return /:\s*$/.test(match[1])
+
       @aceSession.addDynamicMarker
         update: (html, markerLayer, session, config) =>
           Range = ace.require('ace/range').Range
@@ -286,6 +293,8 @@
             if not docRange?
               guess = startOfRow(row)
               docRange = new Range(row,guess,row,guess+4)
+
+            continue unless ensureLineStartsBlock(lines[row])

             if /^\s+$/.test lines[docRange.end.row+1]
               docRange.end.row += 1


cocalc: standby notice should also use the white logo

--- src/smc-webapp/client_browser.coffee
+++ src/smc-webapp/client_browser.coffee
@@ -28,17 +28,17 @@

 client = require('smc-util/client')

-APP_ICON_URL = require('cocalc-icon.svg')
+WHITE_APP_ICON_URL = require('cocalc-icon-white-transparent.svg')

 # these idle notifications were in misc_page, but importing it here failed

 idle_notification_html = ->
     {redux}   = require('./smc-react')
     customize = redux.getStore('customize')
-    site_name = customize?.get('site_name') ? "SageMathCloud"
+    site_name = customize?.get('site_name') ? "CoCalc"
     """

-
+

#{site_name}
 is on standby

     — click to resume —


Plurals are a thing

Plurals are a thing

--- lib/capabilities/ControlBrowserCapability.coffee
+++ lib/capabilities/ControlBrowserCapability.coffee
@@ -36,7 +36,7 @@
       forms: [
         '(what is |describe|report )?(the )?(status|state) of( the)? <control>'
         '(what is |describe|report )?(the )?<control> (status|state)'
-        'is( the)? <control> (on|off|open|closed|locked|unlocked)']
+        '(is|are)( the)? <control> (on|off|open|closed|locked|unlocked)']
       resolve: (cap, {control}) ->
         control = cap.resolveControlName(control)
         if control? then {control: control} else null


Rename lintOnFly() to lintFileOnFly()

Rename lintOnFly() to lintFileOnFly()

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -60,7 +60,7 @@

     @subscriptions.add atom.config.observe 'linter-pylama.lintOnFly',
     (lintOnFly) =>
-      @isLintOnFly = lintOnFly
+      @lintOnFly = lintOnFly

     @subscriptions.add atom.config.observe 'linter-pylama.configFileLoad',
     (configFileLoad) =>
@@ -76,7 +76,7 @@

   isLintOnFly: ->
-    return @isLintOnFly
+    return @lintOnFly

   initEnv: (filePath, projectPath) ->
@@ -194,7 +194,7 @@
         message

-  lintOnFly: (textEditor) =>
+  lintFileOnFly: (textEditor) =>
     filePath = do textEditor.getPath
     fileName = path.basename do textEditor.getPath
     helpers.tempFile fileName, do textEditor.getText, (tmpFilePath) =>
@@ -206,14 +206,14 @@
     filePath = do textEditor.getPath
     if process.platform is 'win32'
       if filePath.slice(0, 2) == '\\\\'
-        return @lintOnFly textEditor
+        return @lintFileOnFly textEditor
     lintInfo = @makeLintInfo filePath
     @lintFile lintInfo, textEditor

   lint: (textEditor) =>
     return [] if not @pylamaPath
-    return @lintOnFly textEditor if @isLintOnFly
+    return @lintFileOnFly textEditor if @lintOnFly
     @lintOnSave textEditor


Check if the loading indicator is visible on didInsertElement.

--- app/assets/javascripts/components/load-more.js.coffee
+++ app/assets/javascripts/components/load-more.js.coffee
@@ -7,6 +7,7 @@

   didInsertElement: ->
     $(window).bind 'scroll.loadmore', $.proxy(@checkInView, this)
+    @checkInView()

   willClearRender: ->
     $(window).unbind 'scroll.loadmore'


Add separate function for building each suggestion

--- lib/love-provider.coffee
+++ lib/love-provider.coffee
@@ -19,13 +19,16 @@
         suggestions = []
         for item in completions
             if @compareStrings( item.displayText, prefix )
-                suggestions.push( {
-                        displayText: item.displayText
-                        snippet: item.snippet
-                        type: item.type
-                    } )
+                suggestions.push( @buildSuggestion( item ) )

         suggestions
+
+    buildSuggestion: ( item ) ->
+        suggestion =
+            displayText: item.displayText
+            snippet: item.snippet
+            type: item.type
+        return suggestion

     loadCompletions: ->
         @completions = {}


removing unnecessary helper for tags

removing unnecessary helper for tags

--- app/assets/javascripts/ems/helpers/tags_helper.coffee
+++ app/assets/javascripts/ems/helpers/tags_helper.coffee
@@ -1,37 +0,0 @@
-Batman.mixin Batman.Filters,
-  simpleFormat: (text) ->
-    return undefined if typeof text is 'undefined'
-    text = text.replace(/(\n\n+)|(\r\r+)|(\r\n(\r\n)+)/g, "
\n\n
")  # 2+ newline  -> paragraph
-    text = text.replace(/([^\n]\n)(?=[^\n])/g, '\1
') # 1 newline   -> br
-    text = "
#{text}
"
-    text
-
-  autolink: (text) ->
-    return undefined if typeof text is 'undefined'
-    # Turns all urls into clickable links.
-    text.replace AUTO_LINK_RE, (href, scheme, offset) ->
-      punctuation = []
-
-      if isAutoLinked(text.slice(0, offset), text.slice(offset + href.length))
-        # do not change string; URL is already linked
-        href
-      else
-        linkText = href
-        href = 'http://' + href unless scheme
-        "#{linkText}"
-
-  prettyDate: (x) -> x
-
-
-# regexps for determining context, used high-volume
-AUTO_LINK_RE = ///
-  (?: ([0-9A-Za-z+.:-]+:)// | www\. )
-  [^\s<]+
-///g
-AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, //i, /<\/a>/i]
-AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
-
-# Detects already linked context or position in the middle of a tag
-isAutoLinked = (left, right) ->
-  (AUTO_LINK_CRE[0].exec(left) and AUTO_LINK_CRE[1].exec(right)) or
-  (AUTO_LINK_CRE[2].exec(left) and !AUTO_LINK_CRE[3].exec(right))


:fire: comment

:fire: comment

--- lib/misc-commands.coffee
+++ lib/misc-commands.coffee
@@ -1,6 +1,3 @@
-# The commands defined in this file is processed by operationStack.
-# The commands which is not well fit to one of Motion, TextObject, Operator
-#  goes here.
 {Range} = require 'atom'
 Base = require './base'
 swrap = require './selection-wrapper'


Get webContents on request.

Get webContents on request.

--- atom/browser/api/lib/browser-window.coffee
+++ atom/browser/api/lib/browser-window.coffee
@@ -15,7 +15,9 @@
     @setMenu menu if menu?

   # Define getter for webContents.
-  @webContents = @getWebContents()
+  @__webContents = null
+  @__defineGetter__ 'webContents', ->
+    @__webContents ?= @getWebContents()
   @__devToolsWebContents = null
   @__defineGetter__ 'devToolsWebContents', ->
     if @isDevToolsOpened()


use ActivityLogger while cherry picking

use ActivityLogger while cherry picking

--- lib/views/cherry-pick-select-commits-view.coffee
+++ lib/views/cherry-pick-select-commits-view.coffee
@@ -2,6 +2,7 @@

 git = require '../git'
 notifier = require '../notifier'
+ActivityLogger = require('../activity-logger').default
 SelectListMultipleView = require './select-list-multiple-view'

 module.exports =
@@ -53,6 +54,11 @@
   completed: (items) ->
     @cancel()
     commits = items.map (item) -> item.hash
+    message =  """cherry pick commits: #{commits.join(' ')}"""
     git.cmd(['cherry-pick'].concat(commits), cwd: @repo.getWorkingDirectory())
-    .then (msg) -> notifier.addSuccess msg
-    .catch (msg) -> notifier.addError msg
+    .then (msg) ->
+      notifier.addSuccess msg
+      ActivityLogger.record({message, output: msg})
+    .catch (msg) ->
+      notifier.addError msg
+      ActivityLogger.record({message, output: msg, failed: true})


Simplify link_hints.coffee

Simplify link_hints.coffee

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -38,10 +38,13 @@
       HUD.showForDuration "Yanked #{url}", 2000
     else
       HUD.showForDuration "No link to yank.", 2000
+    return
 OPEN_INCOGNITO =
   name: "incognito"
   indicator: "Open link in incognito window"
-  linkActivator: (link) -> chrome.runtime.sendMessage handler: 'openUrlInIncognito', url: link.href
+  linkActivator: (link) ->
+    chrome.runtime.sendMessage handler: 'openUrlInIncognito', url: link.href
+    return
 DOWNLOAD_LINK_URL =
   name: "download"
   indicator: "Download link URL"
@@ -51,20 +54,25 @@
   indicator: "Copy link text"
   linkActivator: (link) ->
     text = link.textContent
-    if 0 < text.length
+    if text.length > 0
       HUD.copyToClipboard text
       text = text[0..25] + "...." if 28 < text.length
       HUD.showForDuration "Yanked #{text}", 2000
     else
       HUD.showForDuration "No text to yank.", 2000
+    return
 HOVER_LINK =
   name: "hover"
   indicator: "Hover link"
-  linkActivator: (link) -> new HoverMode link
+  linkActivator: (link) ->
+    new HoverMode link
+    return
 FOCUS_LINK =
   name: "focus"
   indicator: "Focus link"
-  linkActivator: (link) -> link.focus()
+  linkActivator: (link) ->
+    link.focus()
+    return

 availableModes = [OPEN_IN_CURRENT_TAB, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB, OPEN_WITH_QUEUE, COPY_LINK_URL,
   OPEN_INCOGNITO, DOWNLOAD_LINK_URL, COPY_LINK_TEXT, HOVER_LINK, FOCUS_LINK]
@@ -76,6 +84,7 @@

   sendMessage: (messageType, request = {}) ->
     Frame.postMessage "linkHintsMessage", extend request, {messageType}
+    return

   prepareToActivateMode: (mode, onExit) ->
     # We need to communicate with the background page (and other frames) to initiate link-hints mode.  To
@@ -88,10 +97,14 @@
       exitOnEscape: true
     # FIXME(smblott) Global link hints is currently insufficiently reliable.  If the mode above is left in
     # place, then Vimium blocks.  As a temporary measure, we install a timer to remove it.
-    Utils.setTimeout 1000, -> cacheAllKeydownEvents.exit() if cacheAllKeydownEvents?.modeIsActive
+    Utils.setTimeout 1000, ->
+      if cacheAllKeydownEvents && cacheAllKeydownEvents.modeIsActive
+        cacheAllKeydownEvents.exit()
+      return
     @onExit = [onExit]
     @sendMessage "prepareToActivateMode",
       modeIndex: availableModes.indexOf(mode), isVimiumHelpDialog: window.isVimiumHelpDialog
+    return

   # Hint descriptors are global.  They include all of the information necessary for each frame to determine
   # whether and when a hint from *any* frame is selected.  They include the following properties:
@@ -105,13 +118,14 @@
       # If link hints is launched within the help dialog, then we only offer hints from that frame.  This
       # improves the usability of the help dialog on the options page (particularly for selecting command
       # names).
-      @localHints =
-        if isVimiumHelpDialog and not window.isVimiumHelpDialog
-          []
-        else
-          LocalHints.getLocalHints requireHref
+      if isVimiumHelpDialog and not window.isVimiumHelpDialog
+        @localHints = []
+      else
+        @localHints = LocalHints.getLocalHints requireHref
       @localHintDescriptors = @localHints.map ({linkText}, localIndex) -> {frameId, localIndex, linkText}
       @sendMessage "postHintDescriptors", hintDescriptors: @localHintDescriptors
+      return
+    return

   # We activate LinkHintsMode() in every frame and provide every frame with exactly the same hint descriptors.
   # We also propagate the key state between frames.  Therefore, the hint-selection process proceeds in lock
@@ -119,71 +133,99 @@
   activateMode: ({hintDescriptors, modeIndex, originatingFrameId}) ->
     # We do not receive the frame's own hint descritors back from the background page.  Instead, we merge them
     # with the hint descriptors from other frames here.
-    [hintDescriptors[frameId], @localHintDescriptors] = [@localHintDescriptors, null]
-    hintDescriptors = [].concat (hintDescriptors[fId] for fId in (fId for own fId of hintDescriptors).sort())...
+    hintDescriptors[frameId] = @localHintDescriptors
+    @localHintDescriptors = null
+
+    hintDescriptors = Object.keys(hintDescriptors || {})
+      .sort()
+      .map((frame) => hintDescriptors[frame])
+      .flat(1)
+
     # Ensure that the document is ready and that the settings are loaded.
     DomUtils.documentReady => Settings.onLoaded =>
-      @cacheAllKeydownEvents.exit() if @cacheAllKeydownEvents?.modeIsActive
-      @onExit = [] unless frameId == originatingFrameId
+      if @cacheAllKeydownEvents?.modeIsActive
+        @cacheAllKeydownEvents.exit()
+      unless frameId == originatingFrameId
+        @onExit = []
       @linkHintsMode = new LinkHintsMode hintDescriptors, availableModes[modeIndex]
       # Replay keydown events which we missed (but for filtered hints only).
-      @cacheAllKeydownEvents?.replayKeydownEvents() if Settings.get "filterLinkHints"
+      if Settings.get "filterLinkHints" && @cacheAllKeydownEvents
+        @cacheAllKeydownEvents.replayKeydownEvents()
       @cacheAllKeydownEvents = null
       @linkHintsMode # Return this (for tests).

   # The following messages are exchanged between frames while link-hints mode is active.
-  updateKeyState: (request) -> @linkHintsMode.updateKeyState request
-  rotateHints: -> @linkHintsMode.rotateHints()
-  setOpenLinkMode: ({modeIndex}) -> @linkHintsMode.setOpenLinkMode availableModes[modeIndex], false
-  activateActiveHintMarker: -> @linkHintsMode.activateLink @linkHintsMode.markerMatcher.activeHintMarker
-  getLocalHintMarker: (hint) -> if hint.frameId == frameId then @localHints[hint.localIndex] else null
+  updateKeyState: (request) ->
+    @linkHintsMode.updateKeyState request
+    return
+  rotateHints: ->
+    @linkHintsMode.rotateHints()
+    return
+  setOpenLinkMode: ({modeIndex}) ->
+    @linkHintsMode.setOpenLinkMode availableModes[modeIndex], false
+    return
+  activateActiveHintMarker: ->
+     @linkHintsMode.activateLink @linkHintsMode.markerMatcher.activeHintMarker
+     return
+  getLocalHintMarker: (hint) ->
+     return if hint.frameId == frameId then @localHints[hint.localIndex] else null

   exit: ({isSuccess}) ->
     @linkHintsMode?.deactivateMode()
-    @onExit.pop() isSuccess while 0 < @onExit.length
+    while @onExit.length > 0
+      @onExit.pop() isSuccess
     @linkHintsMode = @localHints = null
+    return

 LinkHints =
   activateMode: (count = 1, {mode, registryEntry}) ->
     mode ?= OPEN_IN_CURRENT_TAB
     # Handle modes which are only accessible via command options.
-    switch registryEntry?.options.action
+    action = if registryEntry then registryEntry.options.action else null
+    switch action
       when "copy-text" then mode = COPY_LINK_TEXT
       when "hover" then mode = HOVER_LINK
       when "focus" then mode = FOCUS_LINK
-    #
-    if 0 < count or mode is OPEN_WITH_QUEUE
+
+    if count > 0 or mode is OPEN_WITH_QUEUE
       HintCoordinator.prepareToActivateMode mode, (isSuccess) ->
         if isSuccess
           # Wait for the next tick to allow the previous mode to exit.  It might yet generate a click event,
           # which would cause our new mode to exit immediately.
           Utils.nextTick -> LinkHints.activateMode count-1, {mode}
-
-  activateModeToOpenInNewTab: (count) -> @activateMode count, mode: OPEN_IN_NEW_BG_TAB
-  activateModeToOpenInNewForegroundTab: (count) -> @activateMode count, mode: OPEN_IN_NEW_FG_TAB
-  activateModeToCopyLinkUrl: (count) -> @activateMode count, mode: COPY_LINK_URL
-  activateModeWithQueue: -> @activateMode 1, mode: OPEN_WITH_QUEUE
-  activateModeToOpenIncognito: (count) -> @activateMode count, mode: OPEN_INCOGNITO
-  activateModeToDownloadLink: (count) -> @activateMode count, mode: DOWNLOAD_LINK_URL
+          return
+
+  activateModeToOpenInNewTab: (count) -> @activateMode count, mode: OPEN_IN_NEW_BG_TAB; return
+  activateModeToOpenInNewForegroundTab: (count) -> @activateMode count, mode: OPEN_IN_NEW_FG_TAB; return
+  activateModeToCopyLinkUrl: (count) -> @activateMode count, mode: COPY_LINK_URL; return
+  activateModeWithQueue: -> @activateMode 1, mode: OPEN_WITH_QUEUE; return
+  activateModeToOpenIncognito: (count) -> @activateMode count, mode: OPEN_INCOGNITO; return
+  activateModeToDownloadLink: (count) -> @activateMode count, mode: DOWNLOAD_LINK_URL; return

 class LinkHintsMode
-  hintMarkerContainingDiv: null
-  # One of the enums listed at the top of this file.
-  mode: undefined
-  # Function that does the appropriate action on the selected link.
-  linkActivator: undefined
-  # The link-hints "mode" (in the key-handler, indicator sense).
-  hintMode: null
-  # A count of the number of Tab presses since the last non-Tab keyboard event.
-  tabCount: 0
-
+  # @mode: One of the enums listed at the top of this file.
   constructor: (hintDescriptors, @mode = OPEN_IN_CURRENT_TAB) ->
     # We need documentElement to be ready in order to append links.
     return unless document.documentElement

+    @hintMarkerContainingDiv = null
+    # Function that does the appropriate action on the selected link.
+    @linkActivator = undefined
+    # The link-hints "mode" (in the key-handler, indicator sense).
+    @hintMode = null
+    # A count of the number of Tab presses since the last non-Tab keyboard event.
+    @tabCount = 0
+
     if hintDescriptors.length == 0
       HUD.showForDuration "No links to select.", 2000
       return
+
+    # # TODO(philc): Why do we need a closure here?
+    @getNextZIndex = do ->
+      # This is the starting z-index value; it produces z-index values which are greater than all of the other
+      # z-index values used by Vimium.
+      baseZIndex = 2140000000
+      -> baseZIndex += 1

     # This count is used to rank equal-scoring hints when sorting, thereby making JavaScript's sort stable.
     @stableSortCount = 0
@@ -218,38 +260,33 @@
       HintCoordinator.sendMessage "setOpenLinkMode", modeIndex: availableModes.indexOf @mode
     else
       @setIndicator()
+    return

   setIndicator: ->
     if windowIsFocused()
-      typedCharacters = @markerMatcher.linkTextKeystrokeQueue?.join("") ? ""
+      typedCharacters = if @markerMatcher.linkTextKeystrokeQueue then @markerMatcher.linkTextKeystrokeQueue .join("") else ""
       indicator = @mode.indicator + (if typedCharacters then ": \"#{typedCharacters}\"" else "") + "."
       @hintMode.setIndicator indicator
-
-  getNextZIndex: do ->
-    # This is the starting z-index value; it produces z-index values which are greater than all of the other
-    # z-index values used by Vimium.
-    baseZIndex = 2140000000
-    -> baseZIndex += 1
+    return

   #
   # Creates a link marker for the given link.
   #
   createMarkerFor: (desc) ->
-    marker =
-      if desc.frameId == frameId
-        localHintDescriptor = HintCoordinator.getLocalHintMarker desc
-        el = DomUtils.createElement "div"
-        el.rect = localHintDescriptor.rect
-        el.style.left = el.rect.left + "px"
-        el.style.top = el.rect.top  + "px"
-        # Each hint marker is assigned a different z-index.
-        el.style.zIndex = @getNextZIndex()
-        extend el,
-          className: "vimiumReset internalVimiumHintMarker vimiumHintMarker"
-          showLinkText: localHintDescriptor.showLinkText
-          localHintDescriptor: localHintDescriptor
-      else
-        {}
+    if desc.frameId == frameId
+      localHintDescriptor = HintCoordinator.getLocalHintMarker desc
+      el = DomUtils.createElement "div"
+      el.rect = localHintDescriptor.rect
+      el.style.left = el.rect.left + "px"
+      el.style.top = el.rect.top  + "px"
+      # Each hint marker is assigned a different z-index.
+      el.style.zIndex = @getNextZIndex()
+      marker = extend el,
+        className: "vimiumReset internalVimiumHintMarker vimiumHintMarker"
+        showLinkText: localHintDescriptor.showLinkText
+        localHintDescriptor: localHintDescriptor
+    else
+      marker = {}

     extend marker,
       hintDescriptor: desc
@@ -259,11 +296,12 @@

   # Handles all keyboard events.
   onKeyDownInMode: (event) ->
-    return if event.repeat
+    if event.repeat
+      return

     # NOTE(smblott) The modifier behaviour here applies only to alphabet hints.
-    if event.key in ["Control", "Shift"] and not Settings.get("filterLinkHints") and
-      @mode in [ OPEN_IN_CURRENT_TAB, OPEN_WITH_QUEUE, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB ]
+    if ["Control", "Shift"].includes(event.key) and not Settings.get("filterLinkHints") and
+      [OPEN_IN_CURRENT_TAB, OPEN_WITH_QUEUE, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB].includes(@mode)
         # Toggle whether to open the link in a new or current tab.
         previousMode = @mode
         key = event.key
@@ -333,54 +371,62 @@
     else if linksMatched.length == 1
       @activateLink linksMatched[0], userMightOverType
     else
-      @hideMarker marker for marker in @hintMarkers
-      @showMarker matched, @markerMatcher.hintKeystrokeQueue.length for matched in linksMatched
+      for marker in @hintMarkers
+        @hideMarker marker
+      for matched in linksMatched
+        @showMarker matched, @markerMatcher.hintKeystrokeQueue.length

     @setIndicator()

+  markerOverlapsStack: (marker, stack) ->
+    for otherMarker in stack
+      if Rect.intersects marker.markerRect, otherMarker.markerRect
+        return true
+    false
+
   # Rotate the hints' z-index values so that hidden hints become visible.
-  rotateHints: do ->
-    markerOverlapsStack = (marker, stack) ->
-      for otherMarker in stack
-        return true if Rect.intersects marker.markerRect, otherMarker.markerRect
-      false
-
-    ->
-      # Get local, visible hint markers.
-      localHintMarkers = @hintMarkers.filter (marker) ->
-        marker.isLocalMarker and marker.style.display != "none"
-
-      # Fill in the markers' rects, if necessary.
-      marker.markerRect ?= marker.getClientRects()[0] for marker in localHintMarkers
-
-      # Calculate the overlapping groups of hints.  We call each group a "stack".  This is O(n^2).
-      stacks = []
-      for marker in localHintMarkers
-        stackForThisMarker = null
-        stacks =
-          for stack in stacks
-            markerOverlapsThisStack = markerOverlapsStack marker, stack
-            if markerOverlapsThisStack and not stackForThisMarker?
-              # We've found an existing stack for this marker.
-              stack.push marker
-              stackForThisMarker = stack
-            else if markerOverlapsThisStack and stackForThisMarker?
-              # This marker overlaps a second (or subsequent) stack; merge that stack into stackForThisMarker
-              # and discard it.
-              stackForThisMarker.push stack...
-              continue # Discard this stack.
-            else
-              stack # Keep this stack.
-        stacks.push [marker] unless stackForThisMarker?
-
-      # Rotate the z-indexes within each stack.
+  rotateHints: ->
+    # Get local, visible hint markers.
+    localHintMarkers = @hintMarkers.filter (marker) ->
+      marker.isLocalMarker and marker.style.display != "none"
+
+    # Fill in the markers' rects, if necessary.
+    marker.markerRect ?= marker.getClientRects()[0] for marker in localHintMarkers
+
+    # Calculate the overlapping groups of hints.  We call each group a "stack".  This is O(n^2).
+    stacks = []
+    for marker in localHintMarkers
+      stackForThisMarker = null
+      results = []
       for stack in stacks
-        if 1 < stack.length
-          zIndexes = (marker.style.zIndex for marker in stack)
-          zIndexes.push zIndexes[0]
-          marker.style.zIndex = zIndexes[index + 1] for marker, index in stack
-
-      null # Prevent Coffeescript from building an unnecessary array.
+        markerOverlapsThisStack = @markerOverlapsStack marker, stack
+        if markerOverlapsThisStack and not stackForThisMarker?
+          # We've found an existing stack for this marker.
+          stack.push marker
+          stackForThisMarker = stack
+          results.push(stack)
+        else if markerOverlapsThisStack and stackForThisMarker?
+          # This marker overlaps a second (or subsequent) stack; merge that stack into stackForThisMarker
+          # and discard it.
+          stackForThisMarker.push stack...
+          continue # Discard this stack.
+        else
+          stack # Keep this stack.
+          results.push(stack)
+      stacks = results
+
+      unless stackForThisMarker?
+        stacks.push [marker]
+
+    # Rotate the z-indexes within each stack.
+    for stack in stacks
+      if stack.length > 1
+        zIndexes = stack.map((marker) => marker.style.zIndex)
+        zIndexes.push zIndexes[0]
+        for marker, index in stack
+          marker.style.zIndex = zIndexes[index + 1]
+
+    null # Prevent Coffeescript from building an unnecessary array.

   # When only one hint remains, activate it in the appropriate way.  The current frame may or may not contain
   # the matched link, and may or may not have the focus.  The resulting four cases are accounted for here by
@@ -411,7 +457,7 @@
             #     focus it to let user press space to activate the popup menu
             # <object> & <embed>: for Flash games which have their own key event handlers
             #     since we have been able to blur them by pressing `Escape`
-            if clickEl.nodeName.toLowerCase() in ["input", "select", "object", "embed"]
+            if ["input", "select", "object", "embed"].includes(clickEl.nodeName.toLowerCase())
               clickEl.focus()
             linkActivator clickEl

@@ -441,23 +487,31 @@
   # Shows the marker, highlighting matchingCharCount characters.
   #
   showMarker: (linkMarker, matchingCharCount) ->
-    return unless linkMarker.isLocalMarker
+    unless linkMarker.isLocalMarker
+      return
     linkMarker.style.display = ""
-    for j in [0...linkMarker.childNodes.length]
+    for j in [0...linkMarker.childNodes.length] by 1
       if (j < matchingCharCount)
         linkMarker.childNodes[j].classList.add("matchingCharacter")
       else
         linkMarker.childNodes[j].classList.remove("matchingCharacter")
-
-  hideMarker: (linkMarker) -> linkMarker.style.display = "none" if linkMarker.isLocalMarker
+    return
+
+  hideMarker: (linkMarker) ->
+    if linkMarker.isLocalMarker
+      linkMarker.style.display = "none"
+    return

   deactivateMode: ->
     @removeHintMarkers()
     @hintMode?.exit()
+    return

   removeHintMarkers: ->
-    DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv
+    if @hintMarkerContainingDiv
+      DomUtils.removeElement @hintMarkerContainingDiv
     @hintMarkerContainingDiv = null
+    return

 # Use characters for hints, and do not filter links by their text.
 class AlphabetHints
@@ -467,9 +521,11 @@

   fillInMarkers: (hintMarkers) ->
     hintStrings = @hintStrings(hintMarkers.length)
-    for marker, idx in hintMarkers
-      marker.hintString = hintStrings[idx]
-      marker.innerHTML = spanWrap(marker.hintString.toUpperCase()) if marker.isLocalMarker
+    for marker, i in hintMarkers
+      marker.hintString = hintStrings[i]
+      if marker.isLocalMarker
+        marker.innerHTML = spanWrap(marker.hintString.toUpperCase())
+    return

   #
   # Returns a list of hint strings which will uniquely identify the given number of links. The hint strings
@@ -491,8 +547,8 @@
     matchString = @hintKeystrokeQueue.join ""
     linksMatched: hintMarkers.filter (linkMarker) -> linkMarker.hintString.startsWith matchString

-  pushKeyChar: (keyChar) ->
-    @hintKeystrokeQueue.push keyChar
+  pushKeyChar: (keyChar) -> @hintKeystrokeQueue.push keyChar
+
   popKeyChar: -> @hintKeystrokeQueue.pop()

   # For alphabet hints, <Space> always rotates the hints, regardless of modifiers.
@@ -512,19 +568,21 @@
   generateHintString: (linkHintNumber) ->
     base = @linkHintNumbers.length
     hint = []
-    while 0 < linkHintNumber
+    while linkHintNumber > 0
       hint.push @linkHintNumbers[Math.floor linkHintNumber % base]
       linkHintNumber = Math.floor linkHintNumber / base
     hint.reverse().join ""

   renderMarker: (marker) ->
     linkText = marker.linkText
-    linkText = "#{linkText[..32]}..." if 35 < linkText.length
+    if linkText.length > 35
+      linkText = "#{linkText[..32]}..."
     marker.innerHTML = spanWrap(marker.hintString +
         (if marker.showLinkText then ": " + linkText else ""))

   fillInMarkers: (hintMarkers, getNextZIndex) ->
-    @renderMarker marker for marker in hintMarkers when marker.isLocalMarker
+    for marker in hintMarkers when marker.isLocalMarker
+      @renderMarker marker

     # We use @getMatchingHints() here (although we know that all of the hints will match) to get an order on
     # the hints and highlight the first one.
@@ -540,16 +598,19 @@
     # Visually highlight of the active hint (that is, the one that will be activated if the user
     # types <Enter>).
     tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length
-    @activeHintMarker?.classList?.remove "vimiumActiveHintMarker"
+
+    if @activeHintMarker
+      @activeHintMarker.classList.remove "vimiumActiveHintMarker"
     @activeHintMarker = linksMatched[tabCount]
-    @activeHintMarker?.classList?.add "vimiumActiveHintMarker"
-    @activeHintMarker?.style?.zIndex = getNextZIndex()
+    if @activeHintMarker
+      @activeHintMarker.classList.add "vimiumActiveHintMarker"
+      @activeHintMarker.style.zIndex = getNextZIndex()

     linksMatched: linksMatched
-    userMightOverType: @hintKeystrokeQueue.length == 0 and 0 < @linkTextKeystrokeQueue.length
+    userMightOverType: @hintKeystrokeQueue.length == 0 and @linkTextKeystrokeQueue.length > 0

   pushKeyChar: (keyChar) ->
-    if 0 <= @linkHintNumbers.indexOf keyChar
+    if @linkHintNumbers.indexOf(keyChar) >= 0
       @hintKeystrokeQueue.push keyChar
     else if keyChar.toLowerCase() != keyChar and @linkHintNumbers.toLowerCase() != @linkHintNumbers.toUpperCase()
       # The the keyChar is upper case and the link hint "numbers" contain characters (e.g. [a-zA-Z]).  We don't want
@@ -560,6 +621,7 @@
       # Since we might renumber the hints, we should reset the current hintKeyStrokeQueue.
       @hintKeystrokeQueue = []
       @linkTextKeystrokeQueue.push keyChar.toLowerCase()
+    return

   popKeyChar: ->
     @hintKeystrokeQueue.pop() or @linkTextKeystrokeQueue.pop()
@@ -571,45 +633,47 @@
       hintMarkers
         .filter (linkMarker) =>
           linkMarker.score = scoreFunction linkMarker
-          0 == @linkTextKeystrokeQueue.length or 0 < linkMarker.score
+          @linkTextKeystrokeQueue.length == 0 or linkMarker.score > 0
         .sort (a, b) ->
           if b.score == a.score then b.stableSortCount - a.stableSortCount else b.score - a.score

-    if matchingHintMarkers.length == 0 and @hintKeystrokeQueue.length == 0 and 0 < @linkTextKeystrokeQueue.length
+    if matchingHintMarkers.length == 0 and @hintKeystrokeQueue.length == 0 and @linkTextKeystrokeQueue.length > 0
       # We don't accept typed text which doesn't match any hints.
       @linkTextKeystrokeQueue.pop()
       @filterLinkHints hintMarkers
     else
       linkHintNumber = 1
-      for linkMarker in matchingHintMarkers
-        linkMarker.hintString = @generateHintString linkHintNumber++
-        @renderMarker linkMarker
-        linkMarker
+      matchingHintMarkers.map((m) =>
+        m.hintString = @generateHintString linkHintNumber++
+        @renderMarker m
+        m)

   # Assign a score to a filter match (higher is better).  We assign a higher score for matches at the start of
   # a word, and a considerably higher score still for matches which are whole words.
   scoreLinkHint: (linkSearchString) ->
     searchWords = linkSearchString.trim().toLowerCase().split @splitRegexp
     (linkMarker) =>
-      return 0 unless 0 < searchWords.length
+      unless searchWords.length > 0
+        return 0
       # We only keep non-empty link words.  Empty link words cannot be matched, and leading empty link words
       # disrupt the scoring of matches at the start of the text.
-      linkWords = linkMarker.linkWords ?= linkMarker.linkText.toLowerCase().split(@splitRegexp).filter (term) -> term
-
-      searchWordScores =
-        for searchWord in searchWords
-          linkWordScores =
-            for linkWord, idx in linkWords
-              position = linkWord.indexOf searchWord
-              if position < 0
-                0 # No match.
-              else if position == 0 and searchWord.length == linkWord.length
-                if idx == 0 then 8 else 4 # Whole-word match.
-              else if position == 0
-                if idx == 0 then 6 else 2 # Match at the start of a word.
-              else
-                1 # 0 < position; other match.
-          Math.max linkWordScores...
+      if !linkMarker.linkWords
+        linkMarker.linkWords = linkMarker.linkText.toLowerCase().split(@splitRegexp).filter (term) -> term
+      linkWords = linkMarker.linkWords
+
+      searchWordScores = searchWords.map((searchWord) =>
+        linkWordScores = linkWords.map((linkWord, idx) =>
+          position = linkWord.indexOf searchWord
+          if position < 0
+            0 # No match.
+          else if position == 0 and searchWord.length == linkWord.length
+            if idx == 0 then 8 else 4 # Whole-word match.
+          else if position == 0
+            if idx == 0 then 6 else 2 # Match at the start of a word.
+          else
+            1) # 0 < position; other match.
+
+        Math.max linkWordScores...)

       if 0 in searchWordScores
         0
@@ -642,7 +706,7 @@
   getVisibleClickable: (element) ->
     # Get the tag name.  However, `element.tagName` can be an element (not a string, see #2035), so we guard
     # against that.
-    tagName = element.tagName.toLowerCase?() ? ""
+    tagName = (if element.tagName.toLowerCase then element.tagName.toLowerCase()) || ""
     isClickable = false
     onlyHasTabIndex = false
     possibleFalsePositive = false
@@ -663,33 +727,36 @@

     # Check aria properties to see if the element should be ignored.
     # Note that we're showing hints for elements with aria-hidden=true. See #3501 for discussion.
-    if (element.getAttribute("aria-disabled")?.toLowerCase() in ["", "true"])
+    ariaDisabled = element.getAttribute("aria-disabled");
+    if (ariaDisabled && ["", "true"].includes(ariaDisable.toLowerCase()))
       return [] # This element should never have a link hint.

     # Check for AngularJS listeners on the element.
-    @checkForAngularJs ?= do ->
-      angularElements = document.getElementsByClassName "ng-scope"
-      if angularElements.length == 0
-        -> false
-      else
-        ngAttributes = []
-        for prefix in [ '', 'data-', 'x-' ]
-          for separator in [ '-', ':', '_' ]
-            ngAttributes.push "#{prefix}ng#{separator}click"
-        (element) ->
-          for attribute in ngAttributes
-            return true if element.hasAttribute attribute
-          false
-
-    isClickable ||= @checkForAngularJs element
-
-    # Check for attributes that make an element clickable regardless of its tagName.
-    if element.hasAttribute("onclick") or
-        (role = element.getAttribute "role") and role.toLowerCase() in [
-          "button" , "tab" , "link", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio"
-        ] or
-        (contentEditable = element.getAttribute "contentEditable") and
-          contentEditable.toLowerCase() in ["", "contenteditable", "true"]
+    unless @checkForAngularJs
+      @checkForAngularJs = do ->
+        angularElements = document.getElementsByClassName "ng-scope"
+        if angularElements.length == 0
+          -> false
+        else
+          ngAttributes = []
+          for prefix in [ '', 'data-', 'x-' ]
+            for separator in [ '-', ':', '_' ]
+              ngAttributes.push "#{prefix}ng#{separator}click"
+          (element) ->
+            for attribute in ngAttributes
+              return true if element.hasAttribute attribute
+            false
+
+    if !isClickable
+      isClickable = @checkForAngularJs element
+
+    if element.hasAttribute("onclick")
+      isClickable = true
+    else if (role = element.getAttribute "role")? and
+        ["button" , "tab" , "link", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio"].includes(role.toLowerCase())
+      isClickable = true
+    else if (contentEditable = element.getAttribute "contentEditable")? and
+        ["", "contenteditable", "true"].includes(contentEditable.toLowerCase())
       isClickable = true

     # Check for jsaction event listeners on the element.
@@ -697,13 +764,14 @@
       jsactionRules = element.getAttribute("jsaction").split(";")
       for jsactionRule in jsactionRules
         ruleSplit = jsactionRule.trim().split ":"
-        if 1 <= ruleSplit.length <= 2
+        if ruleSplit.length >=1 and ruleSplit.length <= 2
           [eventType, namespace, actionName ] =
             if ruleSplit.length == 1
               ["click", ruleSplit[0].trim().split(".")..., "_"]
             else
               [ruleSplit[0], ruleSplit[1].trim().split(".")..., "_"]
-          isClickable ||= eventType == "click" and namespace != "none" and actionName != "_"
+          if !isClickable
+            isClickable = eventType == "click" and namespace != "none" and actionName != "_"

     # Check for tagNames which are natively clickable.
     switch tagName
@@ -712,7 +780,8 @@
       when "textarea"
         isClickable ||= not element.disabled and not element.readOnly
       when "input"
-        isClickable ||= not (element.getAttribute("type")?.toLowerCase() == "hidden" or
+        type = element.getAttribute("type")
+        isClickable ||= not ((type && type.toLowerCase() == "hidden") or
                              element.disabled or
                              (element.readOnly and DomUtils.isSelectable element))
       when "button", "select"
@@ -748,7 +817,8 @@
     # An element with a class name containing the text "button" might be clickable.  However, real clickables
     # are often wrapped in elements with such class names.  So, when we find clickables based only on their
     # class name, we mark them as unreliable.
-    if not isClickable and 0 <= element.getAttribute("class")?.toLowerCase().indexOf "button"
+    className = element.getAttribute("class")
+    if not isClickable and className and className.toLowerCase().includes("button")
       possibleFalsePositive = isClickable = true

     # Elements with tabindex are sometimes useful, but usually not. We can treat them as second class
@@ -774,7 +844,7 @@
   getElementFromPoint: (x, y, root = document, stack = []) ->
     element = if root.elementsFromPoint then root.elementsFromPoint(x, y)[0] else root.elementFromPoint(x, y)

-    if stack.indexOf(element) != -1
+    if stack.includes(element)
       return element

     stack.push(element)
@@ -793,7 +863,8 @@
   #
   getLocalHints: (requireHref) ->
     # We need documentElement to be ready in order to find links.
-    return [] unless document.documentElement
+    unless document.documentElement
+      return []
     # Find all elements, recursing into shadow DOM if present.
     getAllElements = (root, elements = []) ->
       for element in root.querySelectorAll "*"
@@ -821,9 +892,10 @@
     # false positive for which a close descendant is already clickable.  False positives tend to be close
     # together in the DOM, so - to keep the cost down - we only search nearby elements.  NOTE(smblott): The
     # visible elements have already been reversed, so we're visiting descendants before their ancestors.
-    descendantsToCheck = [1..3] # This determines how many descendants we're willing to consider.
+    descendantsToCheck = [1, 2, 3] # This determines how many descendants we're willing to consider.
     visibleElements =
       for element, position in visibleElements
+        # TODO(philc): Pull this function out into a helper function, and/or use Array.some()
         continue if element.possibleFalsePositive and do ->
           index = Math.max 0, position - 6 # This determines how far back we're willing to look.
           while index < position
@@ -878,7 +950,8 @@
       hint.rect.left += left

     if Settings.get "filterLinkHints"
-      extend hint, @generateLinkText hint for hint in localHints
+      for hint in localHints
+        extend hint, @generateLinkText hint
     localHints

   generateLinkText: (hint) ->
@@ -895,7 +968,7 @@
         if linkText[linkText.length-1] == ":"
           linkText = linkText[...linkText.length-1]
         showLinkText = true
-      else if element.getAttribute("type")?.toLowerCase() == "file"
+      else if (element.getAttribute("type") || "").toLowerCase() == "file"
         linkText = "Choose File"
       else if element.type != "password"
         linkText = element.value
@@ -922,17 +995,17 @@
 # Suppress all keyboard events until the user stops typing for sufficiently long.
 class TypingProtector extends Mode
   constructor: (delay, callback) ->
-    @timer = Utils.setTimeout delay, => @exit()
-
-    resetExitTimer = (event) =>
-      clearTimeout @timer
-      @timer = Utils.setTimeout delay, => @exit()
-
     super
       name: "hint/typing-protector"
       suppressAllKeyboardEvents: true
       keydown: resetExitTimer
       keypress: resetExitTimer
+
+    @timer = Utils.setTimeout delay, => @exit()
+
+    resetExitTimer = (event) =>
+      clearTimeout @timer
+      @timer = Utils.setTimeout delay, => @exit()

     @onExit ->
       callback true # true -> isSuccess.
@@ -954,9 +1027,10 @@
           callback false # false -> isSuccess.

 class HoverMode extends Mode
-  constructor: (@link) ->
+  constructor: (link) ->
+    super name: "hover-mode", singleton: "hover-mode", exitOnEscape: true
+    @link = link
     DomUtils.simulateHover @link
-    super name: "hover-mode", singleton: "hover-mode", exitOnEscape: true
     @onExit => DomUtils.simulateUnhover @link

 root = exports ? (window.root ?= {})
@@ -964,4 +1038,3 @@
 root.HintCoordinator = HintCoordinator
 # For tests:
 extend root, {LinkHintsMode, LocalHints, AlphabetHints, WaitForEnter}
-extend window, root unless exports?


Fix rotate hints for filtered hints.

Fix rotate hints for filtered hints.

We should rotate on `<Shift-Space>` too.

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -589,7 +589,7 @@

   # For filtered hints, we require a modifier (because <Space> on its own is a token separator).
   shouldRotateHints: (event) ->
-    event.ctrlKey or event.altKey or event.metaKey
+    event.ctrlKey or event.altKey or event.metaKey or event.shiftKey

 #
 # Make each hint character a span, so that we can highlight the typed characters as you type them.


Move LinkHint mode indicator text into modes

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -13,17 +13,22 @@
 isMac = KeyboardUtils.platform == "Mac"
 OPEN_IN_CURRENT_TAB =
   name: "curr-tab"
+  indicator: "Open link in current tab."
 OPEN_IN_NEW_BG_TAB =
   name: "bg-tab"
+  indicator: "Open link in new tab."
   clickModifiers: metaKey: isMac, ctrlKey: not isMac
 OPEN_IN_NEW_FG_TAB =
   name: "fg-tab"
+  indicator: "Open link in new tab and switch to it."
   clickModifiers: shiftKey: true, metaKey: isMac, ctrlKey: not isMac
 OPEN_WITH_QUEUE =
   name: "queue"
+  indicator: "Open multiple links in new tabs."
   clickModifiers: metaKey: isMac, ctrlKey: not isMac
 COPY_LINK_URL =
   name: "link"
+  indicator: "Copy link URL to Clipboard."
   linkActivator: (link) ->
     if link.href?
       chrome.runtime.sendMessage handler: "copyToClipboard", data: link.href
@@ -34,9 +39,11 @@
       HUD.showForDuration "No link to yank.", 2000
 OPEN_INCOGNITO =
   name: "incognito"
+  indicator: "Open link in incognito window."
   linkActivator: (link) -> chrome.runtime.sendMessage handler: 'openUrlInIncognito', url: link.href
 DOWNLOAD_LINK_URL =
   name: "download"
+  indicator: "Download link URL."
   clickModifiers: altKey: true, ctrlKey: false, metaKey: false

 LinkHints =
@@ -117,22 +124,7 @@
   setOpenLinkMode: (@mode) ->
     clickActivator = (modifiers) -> (link) -> DomUtils.simulateClick link, modifiers
     @linkActivator = @mode.linkActivator ? clickActivator @mode.clickModifiers
-
-    if @mode is OPEN_IN_NEW_BG_TAB or @mode is OPEN_IN_NEW_FG_TAB or @mode is OPEN_WITH_QUEUE
-      if @mode is OPEN_IN_NEW_BG_TAB
-        @hintMode.setIndicator "Open link in new tab."
-      else if @mode is OPEN_IN_NEW_FG_TAB
-        @hintMode.setIndicator "Open link in new tab and switch to it."
-      else
-        @hintMode.setIndicator "Open multiple links in new tabs."
-    else if @mode is COPY_LINK_URL
-      @hintMode.setIndicator "Copy link URL to Clipboard."
-    else if @mode is OPEN_INCOGNITO
-      @hintMode.setIndicator "Open link in incognito window."
-    else if @mode is DOWNLOAD_LINK_URL
-      @hintMode.setIndicator "Download link URL."
-    else # OPEN_IN_CURRENT_TAB
-      @hintMode.setIndicator "Open link in current tab."
+    @hintMode.setIndicator @mode.indicator

   #
   # Creates a link marker for the given link.


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -232,15 +232,6 @@
         #        return arc b
         #)
         path.transition().duration(2000).attrTween('d', (d,i) ->
-            console.log('tween @instanceDataId: ',@instanceDataId)
-            console.log('tween myInstanceDataId: ',myInstanceDataId)
-            console.log('window.oldPieData['+myInstanceDataId+']: ',window.oldPieData[myInstanceDataId])
-            #lastPieData = window.oldPieData[myInstanceDataId]
-            console.log('lastPieData: ',lastPieData)
-            #window.oldPieData[myInstanceDataId][i] = window.oldPieData[myInstanceDataId][i] ? []
-            #window.oldPieData[myInstanceDataId][i] = d
-            console.log('live pie data: ',d)
-
             s0 = undefined
             e0 = undefined
             if lastPieData[i]
@@ -261,33 +252,27 @@
             },
                 startAngle: d.startAngle
                 endAngle: d.endAngle)
-
-            #myInterpolater = d3.interpolate(lastPieData, d)
-
-            #window.oldPieData[myInstanceDataId][i] = myInterpolater(0) ? d
-            #if myInstanceDataId = 'resolved' and i = 0
-            #    console.log('in tween - NEW DATA - ' + myInstanceDataId + '[' + i + ']: ',window.oldPieData[myInstanceDataId][i])
-            #console.log('2. in tween - d: ',d)
             return (t) ->
                 return arc(myInterpolater(t))
         )
         path.exit()
-            #.transition()
-            #.duration(300)
-            #.attrTween('d', (d,i) ->
-            #    `var i`
-            #    s0 = 2 * Math.PI
-            #    e0 = 2 * Math.PI
-            #    i = d3.interpolate({
-            #        startAngle: d.startAngle
-            #        endAngle: d.endAngle
-            #    },
-            #        startAngle: s0
-            #        endAngle: e0)
-            #    (t) ->
-            #        b = i(t)
-            #        return arc b
-            #)
+            .transition()
+            .duration(300)
+            .attrTween('d', (d,i) ->
+                #`var i`
+                s0 = 2 * Math.PI
+                e0 = 2 * Math.PI
+                i = d3.interpolate({
+                    startAngle: d.startAngle
+                    endAngle: d.endAngle
+                },
+                    startAngle: s0
+                    endAngle: e0)
+                (t) ->
+                #    b = i(t)
+                    b = x(t)
+                    return arc b
+            )
             .remove()

         labels = labelGroup.selectAll('text').data(piedata.sort((p1, p2) ->


Agent: testing pointers with switcher

Agent: testing pointers with switcher

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -17,8 +17,8 @@

         # Define the container
         @container = $(@node).parent()
-        console.log ('node',$(@node))
-        console.log ('container',@container)
+        console.log 'node',$(@node)
+        console.log 'container',@container

         #
         # CONFIG ZONE


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -106,7 +106,7 @@
             r = -r
         #return "translate(" + (x/h * labelRadius) + "," + (y/h * labelRadius) + ")"
         #return "translate(" + r + "," + y + ")"#(y/h * labelRadius) + ")"
-        return "translate(" + ((x/h * labelRadius)+r/2) + "," + y*my + ")"#(y/h * labelRadius) + ")"
+        return "translate(" + ((x/h * labelRadius)+r/4) + "," + y*my + ")"#(y/h * labelRadius) + ")"
         )

         .attr('fill', "#fff")


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -137,18 +137,11 @@

   pieTween: (d, i) ->

-        i = d3.interpolate({
-            startAngle: 0,
-            endAngle: 0
-        }, {
-            startAngle: d.startAngle,
-            endAngle: d.endAngle
-        })
+        i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})

         return (t) ->
             b = i(t);
             return $(@node).arc(b)
-

   renderX3: (data) ->

@@ -280,22 +273,21 @@
             labelGroup = svg.append("g").attr("class", "labels")

         path = pathGroup.selectAll("path.pie")
-            #.data(data)
             .data(piedata)

         path.enter().append("path")
             .attr("class", "pie")
-            .attr("fill", "#ffffff")#(d, i) -> return color i)
-        #pathGroup.attr("d", arc)
+            .attr("fill",(d, i) -> return color i)
+
         path.transition()
             .duration(1500)
-            #.attrTween("d", pieTween);
-            .attrTween("d", (d,i) ->
-                i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})
-                return (t) ->
-                    b = i(t)
-                    return arc(b)
-            )
+            .attrTween("d", pieTween)
+            #.attrTween("d", (d,i) ->
+            #    i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})
+            #    return (t) ->
+            #        b = i(t)
+            #        return arc(b)
+            #)

         path.exit()
             .transition()


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -218,18 +218,15 @@
         #and keep them in the correct drawing order
         pathGroup = svg.select("g.piePaths")
         if pathGroup.empty()
-            pathGroup = svg.append("g")
-                       .attr("class", "piePaths")
+            pathGroup = svg.append("g").attr("class", "piePaths")

         pointerGroup = svg.select("g.pointers")
         if pointerGroup.empty()
-            pointerGroup = svg.append("g")
-                           .attr("class", "pointers")
+            pointerGroup = svg.append("g").attr("class", "pointers")

         labelGroup = svg.select("g.labels")
         if labelGroup.empty()
-            labelGroup = svg.append("g")
-                         .attr("class", "labels")
+            labelGroup = svg.append("g").attr("class", "labels")

         path = pathGroup.selectAll("path.pie")
             #.data(data)


JVM: Add createFreeVm method

JVM: Add createFreeVm method

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -50,6 +50,7 @@
           'fetchDefaultVm'
           'fetchVmRegion'
           'createVmByNonce'
+          'createFreeVm'
         ]
       instance          : []
     schema              :
@@ -214,6 +215,50 @@
         return {groupSlug, prefix, nickname, uid, type:'user', alias}
     return null

+  @createFreeVm = secure (client, callback)->
+
+    @fetchDefaultVm client, (err, vm)=>
+
+      return callback err  if err
+
+      { delegate: account } = client.connection
+
+      unless vm
+
+        JGroup = require './group'
+        JGroup.one slug:'koding', (err, group)=>
+
+          account.fetchUser (err, user) =>
+            return callback err  if err
+            return callback new Error "user not found" unless user
+
+            nameFactory = (require 'koding-counter')
+              db          : JVM.getClient()
+              offset      : 0
+              counterName : "koding~#{user.username}~"
+
+            nameFactory.next (err, uid)=>
+              return console.error err  if err
+              # Counter created
+
+              @addVm {
+                uid
+                user
+                account
+                sudo      : yes
+                type      : 'user'
+                target    : account
+                planCode  : 'free'
+                groupSlug : group.slug
+                planOwner : "user_#{account._id}"
+                webHome   : account.profile.nickname
+                groups    : wrapGroup group
+              }, callback
+
+      else
+
+        callback new KodingError('Default VM already exists'), vm
+
   vmProductMap =
     "f34ba4e35041fea7e519dc20a96d3e1b": { core  : 1 }
     "04d5a80edbde8c2b4be2c4fc0da4d527": { ram   : 1024 }


Adding else clauses to short-circuit parsing

Per the suggestion by DSpeckhals.

--- lib/python-indent.coffee
+++ lib/python-indent.coffee
@@ -123,16 +123,16 @@
                 else
                     if c == stringDelimiter
                         stringDelimiter = []
-                    if c == '\\'
+                    else if c == '\\'
                         isEscaped = true
             else
                 if c == '#'
                     break
-                if c in '[({'
+                else if c in '[({'
                     bracketStack.push(col)
-                if c in '})]'
+                else if c in '})]'
                     bracketStack.pop()
-                if c in '\'"'
+                else if c in '\'"'
                     stringDelimiter = c

     return bracketStack


Fix incorrect scopes on disable autocomplete selector.

--- lib/auto-complete-styled-components.coffee
+++ lib/auto-complete-styled-components.coffee
@@ -17,7 +17,7 @@

 module.exports =
   selector: '.source.inside-js.css.styled, .source.css.styled'
-  disableForSelector: ".source.inside-js.css.styled .comment, .source.inside-js.css.styled .string, .source.inside-js .css.styled.entity.quasi.element.js, .source.css.styled .comment, .source.css.styled .string, .source.css.styled .css.styled.entity.quasi.element.js"
+  disableForSelector: ".source.inside-js.css.styled .comment, .source.inside-js.css.styled .string, .source.inside-js.css.styled .entity.quasi.element.js, .source.css.styled .comment, .source.css.styled .string, .source.css.styled .entity.quasi.element.js"

   filterSuggestions: true
   inclusionPriority: 10000


disableWebSecurity in Plot Pane

disableWebSecurity in Plot Pane

--- lib/runtime/plots.coffee
+++ lib/runtime/plots.coffee
@@ -32,6 +32,7 @@
   ploturl: (url) ->
     v = views.render webview
       class: 'blinkjl',
+      disablewebsecurity: true,
       src: url,
       style: 'width: 100%; height: 100%'
     @ensureVisible()


plot size fix

plot size fix

--- lib/runtime/plots.coffee
+++ lib/runtime/plots.coffee
@@ -26,9 +26,7 @@
     @pane.show views.render view

   plotSize: ->
-    @ensureVisible().then =>
-      view = atom.views.getView(@pane).querySelector('.fill')
-      [view?.clientWidth or 400, view?.clientHeight or 300]
+    @ensureVisible().then => @pane.size()

   ploturl: (url) ->
     @show webview


return exit status when using cpdir

return exit status when using cpdir

--- code/li.coffee
+++ code/li.coffee
@@ -119,7 +119,8 @@
     localdir = args[2]
     instancename = args[3]
     Linode.get instancename, (instance) ->
-      instance.cpdir localdir, ->
+      instance.cpdir localdir, (code, signal) ->
+        process.exit(code)

 # Run all, or a single hook(s) on a specified instance by config
 # args[2] is the instance


adjust merge to not color varlist before using

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -206,8 +206,8 @@
     'match': '^\\s*(sca(l|la|lar)?(\\s+de(f|fi|fin|fine)?)?)\\s+(?!(drop|dir?|l(i|is|ist)?)\\s+)'
   }
   {
-    'match': '\\b(mer(g|ge)?)\\s+(1|m|n)(:)(1|m|n)'
-    'captures':
+    'begin': '\\b(mer(g|ge)?)\\s+(1|m|n)(:)(1|m|n)'
+    'beginCaptures':
       '1':
         'name': 'keyword.control.flow.stata'
       '3':
@@ -232,6 +232,21 @@
             'name': ''
           }
         ]
+    'end': 'using'
+    'patterns': [
+      {
+        'include': '#builtin_variables'
+      }
+      {
+        'include': '#macro-local'
+      }
+      {
+        'include': '#macro-global'
+      }
+      {
+        'include': '#comments'
+      }
+    ]
   }
   {
     'captures':


Fix syntax command. Fixes #61

Fix syntax command. Fixes #61

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -321,18 +321,18 @@
     'end': '\\n'
     'patterns': [
       {
-        'begin': '///'
-        'end': '\\n'
-        'name': 'comment.block.stata'
-      }
-      {
         'comment': 'color before the comma'
         'begin': 'syntax'
         'beginCaptures':
           '0':
             'name': 'keyword.functions.program.stata'
-        'end': '(?=,)'
-        'patterns': [
+        'end': '(?=,|\\n)'
+        'patterns': [
+          {
+            'begin': '///'
+            'end': '\\n'
+            'name': 'comment.block.stata'
+          }
           {
             'match': '\\['
             'name': 'punctuation.definition.parameters.begin.stata'
@@ -352,7 +352,6 @@
       }
       {
         'comment': 'things to color after the comma'
-        'comment': 'TODO: This can be improved to alert when new macros are created with illegal meaning'
         'begin': ','
         'beginCaptures':
           '0':


modify detection for packages folder

modify detection for packages folder

--- lib/browse.coffee
+++ lib/browse.coffee
@@ -8,7 +8,7 @@
   browsePackagesView: null
   subscriptions: null
   fileManager: null
-  configDir: path.join(atom.packages.resolvePackagePath('browse'), '..', '..')
+  packageDir: atom.packages.getPackageDirPaths()[0]

   activate: (state) ->

@@ -28,11 +28,9 @@

     if @fileManager isnt null

-      packageDir = path.join(@configDir, 'packages')
-
       # Does packages folder exist?
       try
-        fs.accessSync(packageDir, fs.F_OK)
+        fs.accessSync(@packageDir, fs.F_OK)
       catch e
         console.log e
         return


Setting game level.

Setting game level.

--- src/game/states/game.coffee
+++ src/game/states/game.coffee
@@ -70,7 +70,7 @@
     #@soundSputnik = @game.add.audio 'soundSputnik'

     #setup game input/output
-    @input.onDown.add @onInputDown, this
+    #@input.onDown.add @onInputDown, this
     @cursors = @game.input.keyboard.createCursorKeys()

     #setup game physics
@@ -93,8 +93,8 @@
      	       @game.add.tween(star).to({alpha:1},200,Phaser.Easing.Quintic.Out,true)
      	 else
        #if Player not on star
+     	       @game.add.tween(star).to({alpha:0.1},15000,Phaser.Easing.Quintic.Out,true)

-     	       @game.add.tween(star).to({alpha:0.1},15000,Phaser.Easing.Quintic.Out,true)
      	 if won
      	    if star.alpha < 0.35
      	       won = false
@@ -114,12 +114,6 @@
         #Plays A Sound
         #@soundSputnik.play()

-
-  onInputDown: ->
-    @game.state.start 'menu'
-
-
-
   drawConstellation: (level) ->
      console.log @constellation
      for star, i in level.starsArray


Use dynamic column name for text editor data attribute value

--- lib/table-element.coffee
+++ lib/table-element.coffee
@@ -4,6 +4,7 @@
 {EventsDelegation, SpacePenDSL} = require 'atom-utils'
 PropertyAccessors = require 'property-accessors'

+columnName = require './column-name'
 Table = require './table'
 TableEditor = require './table-editor'
 TableCellElement = require './table-cell-element'
@@ -613,7 +614,7 @@
     @editorElement.style.height = @toUnit(activeCellRect.height)
     @editorElement.style.display = 'block'

-    @editorElement.dataset.column = @tableEditor.getScreenColumn(position.column).name
+    @editorElement.dataset.column = @tableEditor.getScreenColumn(position.column).name ? columnName(position.column)
     @editorElement.dataset.row = position.row + 1

     @editorElement.focus()