changeset 1753:3c997bc6d380

fix some coffee lint Ignore-this: 1a988be1598dda76dd2fefca3b499aa0
author Drew Perttula <drewp@bigasterisk.com>
date Thu, 24 May 2018 06:54:58 +0000
parents db49df52efc3
children 0c89cd7cda43
files coffeelint.json light9/web/coffee_element.coffee light9/web/edit-choice.coffee light9/web/graph.coffee light9/web/graph_test.coffee light9/web/rdfdbclient.coffee light9/web/timeline/adjustable.coffee light9/web/timeline/adjusters.coffee light9/web/timeline/drawing.coffee light9/web/timeline/timeline.coffee light9/web/timeline/viewstate.coffee package.json
diffstat 12 files changed, 296 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/coffeelint.json	Thu May 24 06:54:58 2018 +0000
@@ -0,0 +1,135 @@
+{
+  "arrow_spacing": {
+    "level": "ignore"
+  },
+  "braces_spacing": {
+    "level": "ignore",
+    "spaces": 0,
+    "empty_object_spaces": 0
+  },
+  "camel_case_classes": {
+    "level": "error"
+  },
+  "coffeescript_error": {
+    "level": "error"
+  },
+  "colon_assignment_spacing": {
+    "level": "ignore",
+    "spacing": {
+      "left": 0,
+      "right": 0
+    }
+  },
+  "cyclomatic_complexity": {
+    "level": "ignore",
+    "value": 10
+  },
+  "duplicate_key": {
+    "level": "error"
+  },
+  "empty_constructor_needs_parens": {
+    "level": "ignore"
+  },
+  "ensure_comprehensions": {
+    "level": "warn"
+  },
+  "eol_last": {
+    "level": "ignore"
+  },
+  "indentation": {
+    "value": 2,
+    "level": "error"
+  },
+  "line_endings": {
+    "level": "ignore",
+    "value": "unix"
+  },
+  "max_line_length": {
+    "value": 80,
+    "level": "error",
+    "limitComments": true
+  },
+  "missing_fat_arrows": {
+    "level": "ignore",
+    "is_strict": false
+  },
+  "newlines_after_classes": {
+    "value": 3,
+    "level": "ignore"
+  },
+  "no_backticks": {
+    "level": "warn"
+  },
+  "no_debugger": {
+    "level": "warn",
+    "console": false
+  },
+  "no_empty_functions": {
+    "level": "ignore"
+  },
+  "no_empty_param_list": {
+    "level": "ignore"
+  },
+  "no_implicit_braces": {
+    "level": "ignore",
+    "strict": true
+  },
+  "no_implicit_parens": {
+    "level": "ignore",
+    "strict": true
+  },
+  "no_interpolation_in_single_quotes": {
+    "level": "ignore"
+  },
+  "no_nested_string_interpolation": {
+    "level": "warn"
+  },
+  "no_plusplus": {
+    "level": "ignore"
+  },
+  "no_private_function_fat_arrows": {
+    "level": "warn"
+  },
+  "no_stand_alone_at": {
+    "level": "ignore"
+  },
+  "no_tabs": {
+    "level": "error"
+  },
+  "no_this": {
+    "level": "ignore"
+  },
+  "no_throwing_strings": {
+    "level": "error"
+  },
+  "no_trailing_semicolons": {
+    "level": "error"
+  },
+  "no_trailing_whitespace": {
+    "level": "error",
+    "allowed_in_comments": false,
+    "allowed_in_empty_lines": true
+  },
+  "no_unnecessary_double_quotes": {
+    "level": "ignore"
+  },
+  "no_unnecessary_fat_arrows": {
+    "level": "warn"
+  },
+  "non_empty_constructor_needs_parens": {
+    "level": "ignore"
+  },
+  "prefer_english_operator": {
+    "level": "ignore",
+    "doubleNotLevel": "ignore"
+  },
+  "space_operators": {
+    "level": "ignore"
+  },
+  "spacing_after_comma": {
+    "level": "ignore"
+  },
+  "transform_messes_up_line_numbers": {
+    "level": "warn"
+  }
+}
--- a/light9/web/coffee_element.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/coffee_element.coffee	Thu May 24 06:54:58 2018 +0000
@@ -4,12 +4,12 @@
 #
 # This workaround is to use names like '@getter_properties' in the
 # class then register with this function that fixes them.
-# 
+#
 # Also see http://coffeescript.org/#unsupported-get-set
 window.coffeeElementSetup = (cls) ->
   for attr in ['properties', 'observers']
     val = cls['getter_' + attr]
     if val?
       do (val) ->
-        Object.defineProperty(cls, attr, {get: ( -> val)})  
+        Object.defineProperty(cls, attr, {get: ( -> val)})
   customElements.define(cls.is, cls)
--- a/light9/web/edit-choice.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/edit-choice.coffee	Thu May 24 06:54:58 2018 +0000
@@ -43,19 +43,19 @@
 
 
 coffeeElementSetup(class EditChoice extends Polymer.Element
-    @is: "edit-choice",
-    @getter_properties:
-        graph: {type: Object, notify: true},
-        uri: {type: String, notify: true},
+  @is: "edit-choice",
+  @getter_properties:
+    graph: {type: Object, notify: true},
+    uri: {type: String, notify: true},
 
-    _setUri: (u) ->
-      @uri = u
-      @dispatchEvent(new CustomEvent('edited'))
+  _setUri: (u) ->
+    @uri = u
+    @dispatchEvent(new CustomEvent('edited'))
 
-    connectedCallback: ->
-      super.connectedCallback()
-      setupDrop(@$.box, @$.box, null, @_setUri.bind(@))
+  connectedCallback: ->
+    super.connectedCallback()
+    setupDrop(@$.box, @$.box, null, @_setUri.bind(@))
 
-    unlink: ->
-      @_setUri(null)
+  unlink: ->
+    @_setUri(null)
 )
--- a/light9/web/graph.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/graph.coffee	Thu May 24 06:54:58 2018 +0000
@@ -28,7 +28,9 @@
   
 class AutoDependencies
   constructor: () ->
-    @handlers = new Handler(null) # tree of all known Handlers (at least those with non-empty patterns). Top node is not a handler.
+    # tree of all known Handlers (at least those with non-empty
+    # patterns). Top node is not a handler.
+    @handlers = new Handler(null)
     @handlerStack = [@handlers] # currently running
     
   runHandler: (func, label) ->
@@ -127,7 +129,7 @@
   # Main graph object for a browser to use. Syncs both ways with
   # rdfdb. Meant to hide the choice of RDF lib, so we can change it
   # later.
-  # 
+  #
   # Note that _applyPatch is the only method to write to the graph, so
   # it can fire subscriptions.
 
@@ -151,7 +153,7 @@
     # if we had a Store already, this lets N3.Store free all its indices/etc
     @graph = N3.Store()
     @_addPrefixes(@prefixes)
-    @cachedFloatValues = new Map();
+    @cachedFloatValues = new Map()
 
   _clearGraphOnNewConnection: -> # must not send a patch to the server!
     log('graph: clearGraphOnNewConnection')
@@ -188,14 +190,14 @@
     patch = {delQuads: [], addQuads: []}
     parser = N3.Parser()
     parser.parse trig, (error, quad, prefixes) =>
-                  if error
-                    throw new Error(error)
-                  if (quad)
-                    patch.addQuads.push(quad)
-                  else
-                    @_applyPatch(patch)
-                    @_addPrefixes(prefixes)
-                    cb() if cb
+      if error
+        throw new Error(error)
+      if (quad)
+        patch.addQuads.push(quad)
+      else
+        @_applyPatch(patch)
+        @_addPrefixes(prefixes)
+        cb() if cb
                     
   quads: () -> # for debugging
     [q.subject, q.predicate, q.object, q.graph] for q in @graph.getQuads()
@@ -223,11 +225,11 @@
     
   _applyPatch: (patch) ->
     # In most cases you want applyAndSendPatch.
-    # 
+    #
     # This is the only method that writes to @graph!
     @cachedFloatValues.clear()
     for quad in patch.delQuads
-      #log("remove #{JSON.stringify(quad)}")      
+      #log("remove #{JSON.stringify(quad)}")
       did = @graph.removeQuad(quad)
       #log("removed: #{did}")
     for quad in patch.addQuads
@@ -323,11 +325,13 @@
       firsts = @graph.getQuads(current, RDF + 'first', null)
       rests = @graph.getQuads(current, RDF + 'rest', null)
       if firsts.length != 1
-        throw new Error("list node #{current} has #{firsts.length} rdf:first edges")
+        throw new Error(
+          "list node #{current} has #{firsts.length} rdf:first edges")
       out.push(firsts[0].object)
 
       if rests.length != 1
-        throw new Error("list node #{current} has #{rests.length} rdf:rest edges")
+        throw new Error(
+          "list node #{current} has #{rests.length} rdf:rest edges")
       current = rests[0].object
     
     return out
@@ -350,7 +354,7 @@
     throw new Error("can't make sequential uri with base #{base}")
 
   nextNumberedResource: (base) ->
-    @nextNumberedResources(base, 1)[0]       
+    @nextNumberedResources(base, 1)[0]
 
   contextsWithPattern: (s, p, o) ->
     @_autoDeps.askedFor(s, p, o, null)
--- a/light9/web/graph_test.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/graph_test.coffee	Thu May 24 06:54:58 2018 +0000
@@ -50,7 +50,7 @@
       graph.runHandler(hand, 'run')
       graph.applyAndSendPatch({
         delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]})
-      assert.equal(2, called) 
+      assert.equal(2, called)
 
     it 'notices new queries a handler makes upon rerun', ->
       called = 0
@@ -80,7 +80,7 @@
       graph.runHandler(hand, 'run')
       graph.applyAndSendPatch({
         delQuads: [quad(A1, A2, A3)], addQuads: [quad(A1, A2, A4)]})
-      assert.equal(2, called) 
+      assert.equal(2, called)
 
     describe 'works with nested handlers', ->
 
@@ -200,7 +200,7 @@
           values = []
           successes = 0
           hand = ->
-            try 
+            try
               head = graph.uriValue(U('x'), U('y'))
             catch
               # graph goes empty between clearGraph and loadTrig
@@ -212,15 +212,15 @@
             @prefix : <http://example.com/> .
             :ctx { :x :y (:a1 :a2 :a3) } .
           ", () ->
-            graph.runHandler(hand, 'run')
-            graph.clearGraph()
-            graph.loadTrig "
+             graph.runHandler(hand, 'run')
+             graph.clearGraph()
+             graph.loadTrig "
               @prefix : <http://example.com/> .
               :ctx { :x :y (:a1 :a3 :a2) } .
             ", () ->
-              assert.deepEqual([[A1, A2, A3], [A1, A3, A2]], values)
-              assert.equal(2, successes)
-              done()
+               assert.deepEqual([[A1, A2, A3], [A1, A3, A2]], values)
+               assert.equal(2, successes)
+               done()
   
       describe 'contains', ->
         it 'when a new triple is added', ->
--- a/light9/web/rdfdbclient.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/rdfdbclient.coffee	Thu May 24 06:54:58 2018 +0000
@@ -25,8 +25,8 @@
       cb())
     
   async.parallel([writeDels, writeAdds], (err) ->
-      cb(JSON.stringify(out))
-    )
+    cb(JSON.stringify(out))
+  )
 
 parseJsonPatch = (jsonPatch, cb) ->
   # note response cb doesn't have an error arg.
@@ -36,23 +36,24 @@
   parseAdds = (cb) =>
     parser = N3.Parser()
     parser.parse input.patch.adds, (error, quad, prefixes) =>
-                  if (quad)
-                    patch.addQuads.push(quad)
-                  else
-                    cb()
+      if (quad)
+        patch.addQuads.push(quad)
+      else
+        cb()
   parseDels = (cb) =>
     parser = N3.Parser()
     parser.parse input.patch.deletes, (error, quad, prefixes) =>
-                  if (quad)
-                    patch.delQuads.push(quad)
-                  else
-                    cb()
+      if (quad)
+        patch.delQuads.push(quad)
+      else
+        cb()
 
   async.parallel([parseAdds, parseDels], ((err) => cb(patch)))
 
 class window.RdfDbClient
   # Send and receive patches from rdfdb
-  constructor: (@patchSenderUrl, @clearGraphOnNewConnection, @applyPatch, @setStatus) ->
+  constructor: (@patchSenderUrl, @clearGraphOnNewConnection, @applyPatch,
+                @setStatus) ->
     @_patchesToSend = []
     @_lastPingMs = -1
     @_patchesReceived = 0
@@ -80,7 +81,7 @@
     console.log('rdfdbclient: queue patch to server ', patchSizeSummary(patch))
     @_patchesToSend.push(patch)
     @_updateStatus()
-    @_continueSending()           
+    @_continueSending()
 
   _newConnection: ->
     wsOrWss = window.location.protocol.replace('http', 'ws')
@@ -133,15 +134,15 @@
     # the dragging cases.
 
     sendOne = (patch, cb) =>
-        toJsonPatch(patch, (json) =>
-          log('rdfdbclient: send patch to server, ' + json.length + ' bytes')
-          @ws.send(json)
-          @_patchesSent++
-          @_updateStatus()
-          cb(null)
+      toJsonPatch(patch, (json) =>
+        log('rdfdbclient: send patch to server, ' + json.length + ' bytes')
+        @ws.send(json)
+        @_patchesSent++
+        @_updateStatus()
+        cb(null)
       )
 
     async.eachSeries(@_patchesToSend, sendOne, () =>
-        @_patchesToSend = []
-        @_updateStatus()
-      )
+      @_patchesToSend = []
+      @_updateStatus()
+    )
--- a/light9/web/timeline/adjustable.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/timeline/adjustable.coffee	Thu May 24 06:54:58 2018 +0000
@@ -18,7 +18,7 @@
     #   getTarget -> vec2 of current target position
     #   getSuggestedTargetOffset -> vec2 pixel offset from target
     #   emptyBox -> true if you want no value display
-    
+
     # updated later by layout algoritm
     @centerOffset = $V([0, 0])
 
@@ -26,7 +26,7 @@
     return '' if @config.emptyBox
     defaultFormat = d3.format(".4g")(@_getValue())
     if @config.getDisplayValue?
-      return @config.getDisplayValue(@_getValue(), defaultFormat) 
+      return @config.getDisplayValue(@_getValue(), defaultFormat)
     defaultFormat
 
   getSuggestedCenter: () ->
@@ -37,7 +37,7 @@
 
   getTarget: () -> # vec2 of pixels
     @config.getTarget()
-            
+
   subscribe: (onChange) ->
     # change could be displayValue or center or target. This likely
     # calls onChange right away if there's any data yet.
@@ -49,7 +49,7 @@
   continueDrag: (pos) ->
     ## pos is vec2 of pixels relative to the drag start
     @targetDraggedTo = pos.add(@initialTarget)
-    
+
   endDrag: () ->
     # override
 
@@ -64,13 +64,13 @@
 
     if ev.touches?.length
       ev = ev.touches[0]
-      
+
     # storing root on the object to remember it across calls in case
     # you drag outside the editor.
     @root = rootElem.getBoundingClientRect() if rootElem
     offsetParentPos = $V([ev.pageX - @root.left, ev.pageY - @root.top])
 
-    return offsetParentPos 
+    return offsetParentPos
 
 class window.AdjustableFloatObservable extends Adjustable
   constructor: (@config) ->
@@ -83,7 +83,7 @@
 
   _getValue: () ->
     @config.observable()
-    
+
   continueDrag: (pos) ->
     # pos is vec2 of pixels relative to the drag start.
     super(pos)
@@ -110,12 +110,13 @@
     @ctor2()
     if not @config.ctx?
       throw new Error("missing ctx")
-    @config.graph.runHandler(@_syncValue.bind(@), "adj sync #{@config.subj.value}")
+    @config.graph.runHandler(@_syncValue.bind(@),
+                             "adj sync #{@config.subj.value}")
 
   _syncValue: () ->
     @_currentValue = @config.graph.floatValue(@config.subj, @config.pred)
     @_onChange() if @_onChange
-    
+
   _getValue: () ->
     # this is a big speedup- callers use _getValue about 4x as much as
     # the graph changes and graph.floatValue is slow
@@ -123,7 +124,7 @@
 
   getTarget: () ->
     @config.getTargetPosForValue(@_getValue())
-    
+
   subscribe: (onChange) ->
     # only works on one subscription at a time
     throw new Error('multi subscribe not implemented') if @_onChange
@@ -133,11 +134,11 @@
     # pos is vec2 of pixels relative to the drag start
     super(pos)
     newValue = @config.getValueForPos(@_editorCoordinates())
-    
+
     @config.graph.patchObject(@config.subj, @config.pred,
                               @config.graph.LiteralRoundedFloat(newValue),
                               @config.ctx)
-                              
+
 class window.AdjustableFade extends Adjustable
   constructor: (@yForV, @i0, @i1, @note, offset, ctx) ->
     super()
@@ -156,11 +157,11 @@
     mid = @note.worldPts[@i0].x(.5).add(@note.worldPts[@i1].x(.5))
     mid.e(1)
 
-   continueDrag: (pos) ->
+  continueDrag: (pos) ->
     # pos is vec2 of pixels relative to the drag start
     super(pos)
     graph = @note.graph
-    U = (x) => graph.Uri(x)
+    U = (x) -> graph.Uri(x)
 
     goalCenterSec = @note.zoomInX.invert(@initialTarget.e(1) + pos.e(1))
 
--- a/light9/web/timeline/adjusters.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/timeline/adjusters.coffee	Thu May 24 06:54:58 2018 +0000
@@ -40,7 +40,8 @@
     pos = $V([ev.x, ev.y])
     if @currentDrag
       @currentDrag.cur = pos
-      @currentDrag.adj.continueDrag(@currentDrag.cur.subtract(@currentDrag.start))
+      @currentDrag.adj.continueDrag(
+        @currentDrag.cur.subtract(@currentDrag.start))
 
   onUp: (ev) ->
     return unless @currentDrag
@@ -159,7 +160,7 @@
     @ctx.fillText(label, x1 + 5, y2 - 5, x2 - x1 - 10)
 
     # coords from a center that's passed in
-    # # special layout for the thaeter ones with middinh 
+    # # special layout for the thaeter ones with middinh
     # l/r arrows
     # mouse arrow cursor upon hover, and accent the hovered adjuster
     # connector
--- a/light9/web/timeline/drawing.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/timeline/drawing.coffee	Thu May 24 06:54:58 2018 +0000
@@ -19,17 +19,17 @@
 
 # http://stackoverflow.com/a/4959890
 window.Drawing.roundRect = (ctx, sx,sy,ex,ey,r) ->
-    d2r = Math.PI/180
-    r = ( ( ex - sx ) / 2 ) if ( ex - sx ) - ( 2 * r ) < 0 # ensure that the radius isn't too large for x
-    r = ( ( ey - sy ) / 2 ) if ( ey - sy ) - ( 2 * r ) < 0 # ensure that the radius isn't too large for y
-    ctx.beginPath();
-    ctx.moveTo(sx+r,sy);
-    ctx.lineTo(ex-r,sy);
-    ctx.arc(ex-r,sy+r,r,d2r*270,d2r*360,false);
-    ctx.lineTo(ex,ey-r);
-    ctx.arc(ex-r,ey-r,r,d2r*0,d2r*90,false);
-    ctx.lineTo(sx+r,ey);
-    ctx.arc(sx+r,ey-r,r,d2r*90,d2r*180,false);
-    ctx.lineTo(sx,sy+r);
-    ctx.arc(sx+r,sy+r,r,d2r*180,d2r*270,false);
-    ctx.closePath();
+  d2r = Math.PI/180
+  r = ( ( ex - sx ) / 2 ) if ( ex - sx ) - ( 2 * r ) < 0 # ensure that the radius isn't too large for x
+  r = ( ( ey - sy ) / 2 ) if ( ey - sy ) - ( 2 * r ) < 0 # ensure that the radius isn't too large for y
+  ctx.beginPath()
+  ctx.moveTo(sx+r,sy)
+  ctx.lineTo(ex-r,sy)
+  ctx.arc(ex-r,sy+r,r,d2r*270,d2r*360,false)
+  ctx.lineTo(ex,ey-r)
+  ctx.arc(ex-r,ey-r,r,d2r*0,d2r*90,false)
+  ctx.lineTo(sx+r,ey)
+  ctx.arc(sx+r,ey-r,r,d2r*90,d2r*180,false)
+  ctx.lineTo(sx,sy+r)
+  ctx.arc(sx+r,sy+r,r,d2r*180,d2r*270,false)
+  ctx.closePath()
--- a/light9/web/timeline/timeline.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/timeline/timeline.coffee	Thu May 24 06:54:58 2018 +0000
@@ -9,7 +9,7 @@
     U = (x) => @graph.Uri(x)
     effect = U(uri.value + '/effect')
     quad = (s, p, o) => @graph.Quad(s, p, o, effect)
-    
+
     quads = [
       quad(effect, U('rdf:type'), U(':Effect')),
       quad(effect, U(':copiedFrom'), uri),
@@ -20,7 +20,7 @@
     fromSettings = @graph.objects(uri, U(':setting'))
 
     toSettings = @graph.nextNumberedResources(effect + '_set', fromSettings.length)
-      
+
     for fs in fromSettings
       ts = toSettings.pop()
       # full copies of these since I may have to delete captures
@@ -38,7 +38,7 @@
   makeNewNote: (song, effect, dropTime, desiredWidthT) ->
     U = (x) => @graph.Uri(x)
     quad = (s, p, o) => @graph.Quad(s, p, o, song)
-      
+
     newNote = @graph.nextNumberedResource("#{song.value}/n")
     newCurve = @graph.nextNumberedResource("#{newNote.value}c")
     points = @graph.nextNumberedResources("#{newCurve.value}p", 4)
@@ -51,11 +51,11 @@
         quad(newNote, U(':curve'), newCurve)
         quad(newCurve, U('rdf:type'), U(':Curve'))
         quad(newCurve, U(':attr'), U(':strength'))
-      ]        
+      ]
     pointQuads = []
 
-   
-    
+
+
     for i in [0...4]
       pt = points[i]
       pointQuads.push(quad(newCurve, U(':point'), pt))
@@ -67,7 +67,7 @@
       addQuads: curveQuads.concat(pointQuads)
       }
     @graph.applyAndSendPatch(patch)
-    
+
   getCurvePoints: (curve, xOffset) ->
     worldPts = []
     uris = @graph.objects(curve, @graph.Uri(':point'))
@@ -84,14 +84,14 @@
     tMin = @graph.floatValue(worldPts[0].uri, @graph.Uri(':time'))
     tMax = @graph.floatValue(worldPts[3].uri, @graph.Uri(':time'))
     tMax - tMin
-      
+
   deleteNote: (song, note, selection) ->
     patch = {delQuads: [@graph.Quad(song, graph.Uri(':note'), note, song)], addQuads: []}
     @graph.applyAndSendPatch(patch)
     if note in selection.selected()
       selection.selected(_.without(selection.selected(), note))
 
-    
+
 coffeeElementSetup(class TimelineEditor extends Polymer.mixinBehaviors([Polymer.IronResizableBehavior], Polymer.Element)
   @is: 'light9-timeline-editor'
   @getter_properties:
@@ -119,7 +119,7 @@
     super()
     @viewState = new ViewState()
     window.viewState = @viewState
-    
+
   ready: ->
     super.ready()
     @addEventListener 'mousedown', (ev) => @$.adjustersCanvas.onDown(ev)
@@ -127,12 +127,12 @@
     @addEventListener 'mouseup', (ev) => @$.adjustersCanvas.onUp(ev)
 
     ko.options.deferUpdates = true
-    
+
     @selection = {hover: ko.observable(null), selected: ko.observable([])}
 
     window.debug_zoomOrLayoutChangedCount = 0
     window.debug_adjUpdateDisplay = 0
-    
+
     ko.computed(@zoomOrLayoutChanged.bind(@))
 
     @trackMouse()
@@ -146,7 +146,7 @@
 
     Polymer.RenderStatus.afterNextRender this, =>
       setupDrop(@$.zoomed.$.rows, @$.zoomed.$.rows, @, @$.zoomed.onDrop.bind(@$.zoomed))
-            
+
   _onIronResize: ->
     @viewState.setWidth(@offsetWidth)
     @viewState.coveredByDiagramTop(@$.coveredByDiagram.offsetTop)
@@ -156,24 +156,24 @@
     if @$.zoomed?.$?.time?
       @viewState.zoomedTimeY(@$.zoomed.$.time.offsetTop)
       @viewState.zoomedTimeH(@$.zoomed.$.time.offsetHeight)
-    
+
   _onSongTime: (t) ->
     @viewState.cursor.t(t)
-    
+
   _onSongDuration: (d) ->
     d = 700 if d < 1 # bug is that asco isn't giving duration, but 0 makes the scale corrupt
     @viewState.zoomSpec.duration(d)
-    
+
   _onSong: (s) ->
     @song = @playerSong if @followPlayerSong
-    
+
   _onGraph: (graph) ->
     @project = new Project(graph)
     @show = 'http://light9.bigasterisk.com/show/dance2017'
 
   _onSetAdjuster: () ->
     @makeZoomAdjs()
-    
+
   updateDebugSummary: ->
     elemCount = (tag) -> document.getElementsByTagName(tag).length
     @debug = "#{window.debug_zoomOrLayoutChangedCount} layout change,
@@ -190,7 +190,7 @@
 
     # shouldn't need this- deps should get it
     @$.zoomed.gatherNotes() if @$.zoomed?.gatherNotes?
-  
+
     # todo: these run a lot of work purely for a time change
     if @$.zoomed?.$?.audio?
       #@dia.setTimeAxis(vs.width(), @$.zoomed.$.audio.offsetTop, vs.zoomInX)
@@ -237,10 +237,10 @@
 
   makeZoomAdjs: ->
     yMid = => @$.audio.offsetTop + @$.audio.offsetHeight / 2
-    
+
     valForPos = (pos) =>
-        x = pos.e(1)
-        t = @viewState.fullZoomX.invert(x)
+      x = pos.e(1)
+      t = @viewState.fullZoomX.invert(x)
     @setAdjuster('zoom-left', => new AdjustableFloatObservable({
       observable: @viewState.zoomSpec.t1,
       getTarget: () =>
@@ -258,14 +258,14 @@
     }))
 
     panObs = ko.pureComputed({
-        read: () =>
-          (@viewState.zoomSpec.t1() + @viewState.zoomSpec.t2()) / 2
-        write: (value) =>
-          zs = @viewState.zoomSpec
-          span = zs.t2() - zs.t1()
-          zs.t1(value - span / 2)
-          zs.t2(value + span / 2)
-      })
+      read: () =>
+        (@viewState.zoomSpec.t1() + @viewState.zoomSpec.t2()) / 2
+      write: (value) =>
+        zs = @viewState.zoomSpec
+        span = zs.t2() - zs.t1()
+        zs.t1(value - span / 2)
+        zs.t2(value + span / 2)
+    })
 
     @setAdjuster('zoom-pan', => new AdjustableFloatObservable({
       observable: panObs
@@ -275,7 +275,7 @@
       getTarget: () => $V([@viewState.fullZoomX(panObs()), yMid()])
       getSuggestedTargetOffset: () => $V([0, 0])
       getValueForPos: valForPos
-      }))
+    }))
 )
 
 
@@ -300,36 +300,36 @@
     @notes = []
     @stage = new PIXI.Container()
     @stage.interactive=true
-    
+
     @renderer = PIXI.autoDetectRenderer({
-        backgroundColor: 0x606060,
-        antialias: true,
-        forceCanvas: true,
+      backgroundColor: 0x606060,
+      antialias: true,
+      forceCanvas: true,
     })
-     
+
   ready: ->
     super.ready()
 
     @addEventListener('iron-resize', @_onResize.bind(@))
     Polymer.RenderStatus.afterNextRender(this, @_onResize.bind(@))
-    
+
     @$.rows.appendChild(@renderer.view)
 
     # This works for display, but pixi hit events didn't correctly
     # move with the objects, so as a workaround, I extended the top of
     # the canvas in _onResize.
-    # 
+    #
     #ko.computed =>
     #  @stage.setTransform(0, -(@viewState.rowsY()), 1, 1, 0, 0, 0, 0, 0)
-      
+
   _onResize: ->
     @$.rows.firstChild.style.position = 'relative'
     @$.rows.firstChild.style.top = -@viewState.rowsY() + 'px'
 
     @renderer.resize(@clientWidth, @clientHeight + @viewState.rowsY())
-    
+
     @renderer.render(@stage)
-  
+
   _onGraph: (graph, setAdjuster, song, viewState, project)->
     return unless @song # polymer will call again
     @graph.runHandler(@gatherNotes.bind(@), 'zoom notes')
@@ -344,25 +344,25 @@
     return unless @song?
 
     songNotes = @graph.objects(U(@song), U(':note'))
-    
+
     @stage.removeChildren()
     n.destroy() for n in @notes
     @notes = []
-    
+
     noteNum = 0
     for uri in _.sortBy(songNotes, 'id')
       con = new PIXI.Container()
       con.interactive=true
       @stage.addChild(con)
-      
+
       row = noteNum % 6
       rowTop = @viewState.rowsY() + 20 + 150 * row
       note = new Note(@, con, @project, @graph, @selection, uri, @setAdjuster, U(@song), @viewState, rowTop, rowTop + 140)
       @notes.push(note)
       noteNum = noteNum + 1
- 
+
     @renderer.render(@stage)
-    
+
   onDrop: (effect, pos) ->
     U = (x) => @graph.Uri(x)
 
@@ -447,12 +447,12 @@
     U = (x) => @graph.Uri(x)
     [pointUris, worldPts] = @getCurvePoints(@uri, U(':strength'))
     effect = @graph.uriValue(@uri, U(':effectClass'))
-    
+
     yForV = (v) => @rowBotY + (@rowTopY - @rowBotY) * v
     dependOn = [@viewState.zoomSpec.t1(), @viewState.zoomSpec.t2(), @viewState.width()]
     screenPts = (new PIXI.Point(@viewState.zoomInX(pt.e(1)), yForV(pt.e(2))) for pt in worldPts)
 
-    @container.removeChildren()    
+    @container.removeChildren()
     graphics = new PIXI.Graphics({nativeLines: false})
     graphics.interactive = true
     @container.addChild(graphics)
@@ -463,7 +463,7 @@
     graphics.endFill()
 
     # stroke should vary with @selection.hover() == @uri and with @uri in @selection.selected()
-    # 
+    #
     # #notes > path.hover {stroke-width: 1.5; stroke: #888;}
     # #notes > path.selected {stroke-width: 5; stroke: red;}
     graphics.lineStyle(2, 0xffd900, 1)
@@ -487,7 +487,7 @@
     curveWidthCalc = () => @project.curveWidth(worldPts)
     @_updateAdjusters(screenPts, worldPts, curveWidthCalc, yForV, @song)
     @_updateInlineAttrs(screenPts)
-    
+
   onUri: ->
     @graph.runHandler(@update.bind(@), "note updates #{@uri}")
 
@@ -501,7 +501,7 @@
           if @worldPts and timeEditFor not in @pointUris
             return false
     return true
-            
+
   update: (patch) ->
     # update our note DOM and SVG elements based on the graph
     if not @patchCouldAffectMe(patch)
@@ -525,7 +525,7 @@
 
   _updateInlineAttrs: (screenPts) ->
     w = 280
-    
+
     leftX = Math.max(2, screenPts[Math.min(1, screenPts.length - 1)].x + 5)
     rightX = screenPts[Math.min(2, screenPts.length - 1)].x - 5
     if screenPts.length < 3
@@ -544,7 +544,7 @@
       }
 
     @parentElem.updateInlineAttrs(@uri, config)
-    
+
   _makeCurvePointAdjusters: (yForV, worldPts, ctx) ->
     for pointNum in [0...worldPts.length]
       @_makePointAdjuster(yForV, worldPts, pointNum, ctx)
@@ -579,7 +579,7 @@
 
     adjId = @uri.value + '/offset'
     @adjusterIds[adjId] = true
-    @setAdjuster adjId, => 
+    @setAdjuster adjId, =>
       adj = new AdjustableFloatObject({
         graph: @graph
         subj: @uri
@@ -605,13 +605,13 @@
     return # not ready- AdjustableFade looks in Note object
     @adjusterIds[adjId] = true
     @setAdjuster adjId, => new AdjustableFade(yForV, i0, i1, @, offset, ctx)
-    
+
   _suggestedOffset: (pt) ->
     if pt.e(2) > .5
       $V([0, 30])
     else
       $V([0, -30])
-  
+
   _onMouseDown: (ev) ->
     sel = @selection.selected()
     if ev.data.originalEvent.ctrlKey
@@ -626,10 +626,10 @@
   _noteColor: (effect) ->
     effect = effect.value
     if effect in ['http://light9.bigasterisk.com/effect/blacklight',
-      'http://light9.bigasterisk.com/effect/strobewarm']
+                  'http://light9.bigasterisk.com/effect/strobewarm']
       hue = 0
       sat = 100
-    else        
+    else
       hash = 0
       for i in [(effect.length-10)...effect.length]
         hash += effect.charCodeAt(i)
@@ -641,4 +641,4 @@
     #elem = @getOrCreateElem(uri+'/label', 'noteLabels', 'text', {style: "font-size:13px;line-height:125%;font-family:'Verana Sans';text-align:start;text-anchor:start;fill:#000000;"})
     #elem.setAttribute('x', curvePts[0].e(1)+20)
     #elem.setAttribute('y', curvePts[0].e(2)-10)
-    #elem.innerHTML = effectLabel;
+    #elem.innerHTML = effectLabel
--- a/light9/web/timeline/viewstate.coffee	Thu May 24 06:50:28 2018 +0000
+++ b/light9/web/timeline/viewstate.coffee	Thu May 24 06:54:58 2018 +0000
@@ -23,7 +23,7 @@
 
     @zoomAnimSec = .1
 
-    ko.computed(@maintainZoomLimitsAndScales.bind(@))    
+    ko.computed(@maintainZoomLimitsAndScales.bind(@))
  
   setWidth: (w) ->
     @width(w)
@@ -87,6 +87,6 @@
         setTimeout(gotoStep, delay)
         lastTime = delay
     setTimeout(=>
-        @zoomSpec.t1(newT1)
-        @zoomSpec.t2(newT2)
-      , lastTime + 10)  
+      @zoomSpec.t1(newT1)
+      @zoomSpec.t2(newT2)
+    , lastTime + 10)
--- a/package.json	Thu May 24 06:50:28 2018 +0000
+++ b/package.json	Thu May 24 06:54:58 2018 +0000
@@ -14,6 +14,7 @@
     "bower": "^1.8.4",
     "browserify": "^16.2.0",
     "chai": "^3.5.0",
+    "coffeelint": "^2.1.0",
     "coffeescript": "^2.3.0",
     "d3": "^5.1.0",
     "mocha": "^2.5.3",