Styles are more easily extensible.

Styles are more easily extensible.

--- lib/Watchers/Style/Style.coffee
+++ lib/Watchers/Style/Style.coffee
@@ -1,6 +1,7 @@
 fs = require 'graceful-fs'
 AssetWatcher = require '../Asset'
-q = require 'q'
+Q = require 'q'
+nib = require 'nib'

 class StyleWatcher extends AssetWatcher
     constructor: -> super()
@@ -8,19 +9,45 @@
     pattern: -> super ["**/#{@name}.styl"]

     type: -> "text/css"
-    # matches: (path)-> path is "/#{@name}.css"
     getPaths: -> ["/#{@name}.css"]

     render: (code, path)->
-        d = q.defer()
-        require('stylus')(code)
+        d = Q.defer()
+        compiler = require('stylus')(code)
             .set('filename', path)
-            .use(require('nib')()).import('nib')
-            .render (err, css)=>
-                if err
-                    d.reject err
-                else
-                    d.resolve css
+            .use(nib())
+            .import('nib')
+
+        @getImports().forEach (_1)-> compiler.include(_1)
+
+
+        compiler.render (err, css)=>
+            if err
+                d.reject err
+            else
+                d.resolve {css, path}
+
         d.promise

+    getVendorImports: ->
+        if @config.vendors?.stylus?
+            @config.vendors.stylus.map (_1)=>
+                @config.vendors.prefix + '/' + _1
+        else
+            []
+
+    getImports: ->
+        imports = @getVendorImports()
+        .concat(@config.root.map (_1)-> "#{_1}/stylus/definitions/variables")
+        .concat(@config.root.map (_1)-> "#{_1}/stylus/definitions/mixins")
+
+        imports = imports.filter (_1)->
+            if _1.indexOf '.css' is -1
+                _1 = "#{_1}.styl"
+            fs.existsSync _1
+        imports
+
+    concat: (styli)->
+        Q(styli.map((_)->_.css).join('\n'))
+
 module.exports = StyleWatcher


recfrac: Add a few comments

recfrac: Add a few comments

--- recfrac/rf.coffee
+++ recfrac/rf.coffee
@@ -131,6 +131,7 @@
       .attr("y1", (d) -> 0)
       .attr("y2", (d) -> height)

+  # chromosome labels above
   svg.selectAll("#xlab")
       .data(chr)
     .enter().append("text")
@@ -141,6 +142,7 @@
       .attr("text-anchor", "middle")
       .text((d) -> d.chr)

+  # chromosome labels on right
   svg.selectAll("#ylab")
       .data(chr)
     .enter().append("text")


Add keys to `ghc-mod`

Add keys to `ghc-mod`

* show info
* show type
* go to declaration

--- .atom/keymap.cson
+++ .atom/keymap.cson
@@ -34,3 +34,9 @@
 # tree view
 '.platform-linux':
   'ctrl-alt-r': 'tree-view:reveal-active-file'
+
+# haskell ide
+'atom-text-editor[data-grammar~="haskell"]':
+  'ctrl-cmd-i': 'haskell-ghc-mod:show-info'
+  'ctrl-cmd-t': 'haskell-ghc-mod:show-type'
+  'ctrl-cmd-g': 'haskell-ghc-mod:go-to-declaration'


activeleavingsharedmachine: set given machine id as an active machine

--- client/app/lib/flux/environment/stores/activeleavingsharedmachineidstore.coffee
+++ client/app/lib/flux/environment/stores/activeleavingsharedmachineidstore.coffee
@@ -12,7 +12,4 @@
     @on actions.SET_ACTIVE_LEAVING_SHARED_MACHINE_ID, @setMachineId

-  setMachineId: (activeWidgetId, { id }) ->
-
-    return null  if activeWidgetId is id
-    return id
+  setMachineId: (activeWidgetId, { id }) -> return id


Disable source urls since they break handlebars atm

--- config.coffee
+++ config.coffee
@@ -30,6 +30,10 @@
     templates:
       joinTo: 'javascripts/app.js'

+  # breaks handlebars
+  # modules:
+  #   addSourceURLs: true
+
   coffeelint:
     options:
       max_line_length:


Using Brunch 1.7

Using Brunch 1.7

--- config.coffee
+++ config.coffee
@@ -4,7 +4,10 @@
     wrapper: false
     definition: false
   paths:
-    app: 'src'
+    watched: [
+        'src'
+        'test'
+    ]
     public: 'build'
   files:
     javascripts:


yayfications, it works

yayfications, it works

--- hyperbolic_tessellation_test_app.coffee
+++ hyperbolic_tessellation_test_app.coffee
@@ -1,6 +1,6 @@
 "use strict"
 {Tessellation} = require "./hyperbolic_tessellation.coffee"
-{NodeHashMap, nodeMatrixRepr, newNode, showNode, chainEquals, nodeHash} = require "./vondyck_chain.coffee"
+{NodeHashMap, nodeMatrixRepr, newNode, showNode, chainEquals, nodeHash, node2array} = require "./vondyck_chain.coffee"
 {makeAppendRewrite, makeAppendRewriteRef, makeAppendRewriteVerified, vdRule, eliminateFinalA} = require "./vondyck_rewriter.coffee"
 {RewriteRuleset, knuthBendix} = require "./knuth_bendix.coffee"
 {mooreNeighborhood, evaluateTotalisticAutomaton} = require "./field.coffee"
@@ -14,7 +14,44 @@

 colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "gray", "orange"]

-
+class FieldObserver
+  constructor: (@tessellation, @appendRewrite, @minCellSize=1.0/400.0)->
+    @center = null
+    @cells = visibleNeighborhood @tessellation, @appendRewrite, @minCellSize
+    @cellOffsets = (node2array(c) for c in @cells)
+    @cellTransforms = (nodeMatrixRepr(c, @tessellation.group) for c in @cells)
+  rebuildAt: (newCenter) ->
+    @center = newCenter
+    @cells = for offset in @cellOffsets
+      #it is important to make copy since AR empties the array!
+      eliminateFinalA @appendRewrite(newCenter, offset[..]), @appendRewrite, @tessellation.group.n
+    return
+
+  draw: (cells, viewMatrix, context) ->
+    context.fillStyle = "black"
+    context.lineWidth = 1.0/400.0
+    context.strokeStyle = "rgb(128,128,128)"
+
+    #first borders
+    context.beginPath()
+    for cell, i in @cells
+      unless cells.get cell
+        cellTfm = @cellTransforms[i]
+        mtx = M.mul viewMatrix, cellTfm
+        @tessellation.makeCellShapePoincare mtx, context
+    context.stroke()
+
+    #then cells
+    context.beginPath()
+    for cell, i in @cells
+      if cells.get cell
+        cellTfm = @cellTransforms[i]
+        mtx = M.mul viewMatrix, cellTfm
+        @tessellation.makeCellShapePoincare  mtx, context
+    context.fill()
+    return
+
+
 drawVisibleCells = (visibleCells, cells, viewMatrix, tessellation, context) ->
   context.fillStyle = "black"
   context.lineWidth = 1.0/400.0
@@ -214,8 +251,11 @@
 xytFromCell = xyt2cell tessellation.group, appendRewrite

 viewCenter = null
-visibleCells = visibleNeighborhood tessellation, appendRewrite, minVisibleSize #farNeighborhood viewCenter, 5, appendRewrite, tessellation.group.n, tessellation.group.m
-console.log "Visible field contains #{visibleCells.length} cells"
+#visibleCells = visibleNeighborhood tessellation, appendRewrite, minVisibleSize #farNeighborhood viewCenter, 5, appendRewrite, tessellation.group.n, tessellation.group.m
+
+observer = new FieldObserver tessellation, appendRewrite, minVisibleSize
+
+#console.log "Visible field contains #{visibleCells.length} cells"

 transitionFunc = parseTransitionFunction "B 3 S 2 3", tessellation.group.n, tessellation.group.m
 dragHandler = null
@@ -245,7 +285,8 @@
       context.save()
       context.scale s, s
       context.translate 1, 1
-      drawVisibleCells visibleCells, cells, tfm, tessellation, context
+      #drawVisibleCells visibleCells, cells, tfm, tessellation, context
+      observer.draw cells, tfm, context
       context.restore()
     #console.log "Redraw. Population is #{cells.count}"
     #E("population").innerHTML = ""+cells.count
@@ -382,11 +423,18 @@
   #centerCoord = M.mulv tfm, [0.0, 0.0, 1.0]
   pathToCenterCell = xytFromCell centerCoord
   console.log "Jump by #{showNode pathToCenterCell}"
+
   m = nodeMatrixRepr pathToCenterCell, tessellation.group
   #console.log "dMatrix is #{JSON.stringify m}"
   #modifyView M.inv m
   tfm = M.mul tfm, m
   checkViewMatrix()
+
+  #move observation point
+  newCenter = appendRewrite observer.center, node2array(pathToCenterCell)
+  console.log  "New center at #{showNode newCenter}"
+  observer.rebuildAt newCenter
+
   redraw()

 redraw()
@@ -398,12 +446,11 @@
 #precision falls from 1e-16 to 1e-9 in 1000 steps.
 maxViewUpdatesBeforeCleanup = 500
 checkViewMatrix = ->
-  me = [-1,0,0,  0,-1,0, 0,0,-1]
-  d = M.add( me, M.mul(tfm, M.hyperbolicInv tfm))
-  ad = (Math.abs(x) for x in d)
-  maxDiff = Math.max( ad ... )
-  console.log "Step: #{viewUpdates}, R: #{maxDiff}"
-
+  #me = [-1,0,0,  0,-1,0, 0,0,-1]
+  #d = M.add( me, M.mul(tfm, M.hyperbolicInv tfm))
+  #ad = (Math.abs(x) for x in d)
+  #maxDiff = Math.max( ad ... )
+  #console.log "Step: #{viewUpdates}, R: #{maxDiff}"
   if (viewUpdates+=1) > maxViewUpdatesBeforeCleanup
     viewUpdates = 0
     tfm = cleanupHyperbolicMoveMatrix tfm


fix language changing

fix language changing

--- imports/ui/pages/vessels/vessels.coffee
+++ imports/ui/pages/vessels/vessels.coffee
@@ -102,10 +102,9 @@
 			vessel

 	drawTable = -> Tracker.afterFlush ->
-		$('#table').html('')
 		table = FooTable.init '#table',
 			columns: columns
-			rows: []
+			rows: getRows()
 			empty: ''
 			paging:
 				enabled: true
@@ -126,6 +125,7 @@
 		if language != tempLanguage
 			language = tempLanguage

+			$('#table').html('')
 			drawTable()

 	@autorun ->


Remove a fake failing test

Remove a fake failing test

--- spec/environments/envirofig-spec.coffee
+++ spec/environments/envirofig-spec.coffee
@@ -8,7 +8,6 @@
     context 'when no namespace is passed', ->
       it 'should throw an error', ->
         expect(-> Envirofig.init()).to.throw()
-        expect(false).to.be.true

     context 'when no environment is specified', ->
       it 'should default to development environment', ->


bug fix: track window's width and height, not screen's.

--- responsive.coffee
+++ responsive.coffee
@@ -1,20 +1,20 @@
 configurations =
   general:
-    resolution: -> Math.max screen.width, screen.height
+    resolution: -> Math.max window.innerWidth, window.innerHeight
     map:
       'low-res':  [0, 568]
       'mid-res':  [568, 1200]
       'high-res': [1200, 1919]
       'hd-res':   [1919]
   horizontal:
-    resolution: -> screen.width
+    resolution: -> window.innerWidth
     map:
       'x-low-res':  [0, 568]
       'x-mid-res':  [568, 1200]
       'x-high-res': [1200, 1919]
       'x-hd-res':   [1919]
   vertical:
-    resolution: -> screen.height
+    resolution: -> window.innerHeight
     map:
       'y-low-res':  [0, 568]
       'y-mid-res':  [568, 1200]


Fixed looping over properties

Fixed looping over properties

--- src/ScreepsStatsd.coffee
+++ src/ScreepsStatsd.coffee
@@ -80,6 +80,7 @@
   report: (data, prefix="") =>
     if prefix is ''
       console.log "Pushing to gauges - " + new Date()
+    for k,v of data
       if typeof v is 'object'
         @report(v, prefix+k+'.')
       else


sort services by name

sort services by name

--- routes/web.coffee
+++ routes/web.coffee
@@ -71,7 +71,7 @@
     @route 'status',
       path: '/status'
       data: ->
-        services: Services.find()
+        services: Services.find({}, sort: name: 1)

     @route 'logs',
       layoutTemplate: null


improved first line match.

improved first line match.


Alphabetise Pic grammar's pattern blocks

--- grammars/pic.cson
+++ grammars/pic.cson
@@ -37,6 +37,21 @@
 		]

+	# Attributes
+	attributes:
+		name: "variable.other.property.$1.pic"
+		match: """(?x)\\b
+			(cw|dashed|diameter|diam|dotted|down|height|ht|invisible
+			|invis|left|move|radius|rad|right|same|up|width|wid)\\b"""
+
+
+	# Instance backreferences: "1st, last, 2nd last, 8th", etc
+	backref:
+		name: "variable.language.backreference.pic"
+		match: "\\b(last|(?:\\d*1[1-3]th|\\d*0th|(?:(?!11st)\\d)*1st|\\d*2nd|(?:(?!13rd)\\d*)3rd|\\d*[4-9]th)(?:[ \t]+last)?)\\b"
+		captures: 0: name: "entity.name.pic"
+
+
 	# Comment lines
 	comment:
 		name: "comment.line.pic"
@@ -45,17 +60,44 @@
 		beginCaptures:
 			0: name: "punctuation.definition.comment.pic"

-
-	# "Double-quoted string"
-	string:
-		name: "string.quoted.double.pic"
-		begin: '"'
-		end:   '"'
-		beginCaptures: 0: name: "punctuation.definition.string.begin.pic"
-		endCaptures:   0: name: "punctuation.definition.string.end.pic"
-		patterns: [include: "text.roff#escapes"]
-
-
+
+	# Function call
+	"function-call":
+		contentName: "meta.function-call.pic"
+		begin: "\\b(?!\\d)(\\w+)(\\()"
+		end:   "\\)"
+		patterns: [include: "#main"]
+		beginCaptures:
+			0: name: "support.function.pic"
+			1: name: "entity.name.function.pic"
+			2: name: "punctuation.definition.arguments.begin.pic"
+		endCaptures:
+			0: name: "punctuation.definition.arguments.end.pic"
+
+
+	# Global variables
+	globals:
+		name: "support.variable.global.pic"
+		match: "(?x)\\b
+			(arcrad|arrowhead|arrowht|arrowwid|boxht|boxwid|circlerad|dashwid
+			|ellipseht|ellipsewid|fillval|lineht|linewid|maxpsht|maxpswid
+			|moveht|movewid|scale|textht|textwid)\\b"
+
+
+	# Keywords
+	keywords:
+		name: "keyword.operator.$1.pic"
+		match: "\\b(and|at|from|reset|then|to|with|of\\s+the\\s+way\\s+between)\\b"
+
+
+	# Labelled position
+	label:
+		match: "([A-Z][^#\\s:]*)(:)"
+		captures:
+			1: name: "storage.type.label.pic"
+			2: name: "punctuation.separator.key-value.pic"
+
+
 	# Numeric literal
 	number:
 		name: "constant.numeric.pic"
@@ -84,12 +126,6 @@
 		]

-	# Keywords
-	keywords:
-		name: "keyword.operator.$1.pic"
-		match: "\\b(and|at|from|reset|then|to|with|of\\s+the\\s+way\\s+between)\\b"
-
-
 	# Primitives
 	shapes:
 		name: "keyword.function.pic"
@@ -97,50 +133,14 @@
 		captures: 0: name: "entity.function.name.pic"

-	# Attributes
-	attributes:
-		name: "variable.other.property.$1.pic"
-		match: """(?x)\\b
-			(cw|dashed|diameter|diam|dotted|down|height|ht|invisible
-			|invis|left|move|radius|rad|right|same|up|width|wid)\\b"""
-
-
-	# Global variables
-	globals:
-		name: "support.variable.global.pic"
-		match: "(?x)\\b
-			(arcrad|arrowhead|arrowht|arrowwid|boxht|boxwid|circlerad|dashwid
-			|ellipseht|ellipsewid|fillval|lineht|linewid|maxpsht|maxpswid
-			|moveht|movewid|scale|textht|textwid)\\b"
-
-
-	# Function call
-	"function-call":
-		contentName: "meta.function-call.pic"
-		begin: "\\b(?!\\d)(\\w+)(\\()"
-		end:   "\\)"
-		patterns: [include: "#main"]
-		beginCaptures:
-			0: name: "support.function.pic"
-			1: name: "entity.name.function.pic"
-			2: name: "punctuation.definition.arguments.begin.pic"
-		endCaptures:
-			0: name: "punctuation.definition.arguments.end.pic"
-
-
-	# Instance backreferences: "1st, last, 2nd last, 8th", etc
-	backref:
-		name: "variable.language.backreference.pic"
-		match: "\\b(last|(?:\\d*1[1-3]th|\\d*0th|(?:(?!11st)\\d)*1st|\\d*2nd|(?:(?!13rd)\\d*)3rd|\\d*[4-9]th)(?:[ \t]+last)?)\\b"
-		captures: 0: name: "entity.name.pic"
-
-
-	# Labelled position
-	label:
-		match: "([A-Z][^#\\s:]*)(:)"
-		captures:
-			1: name: "storage.type.label.pic"
-			2: name: "punctuation.separator.key-value.pic"
+	# "Double-quoted string"
+	string:
+		name: "string.quoted.double.pic"
+		begin: '"'
+		end:   '"'
+		beginCaptures: 0: name: "punctuation.definition.string.begin.pic"
+		endCaptures:   0: name: "punctuation.definition.string.end.pic"
+		patterns: [include: "text.roff#escapes"]

 	# User-defined/generic variable


Fix broken highlighting of relative backreferences

--- grammars/pic.cson
+++ grammars/pic.cson
@@ -24,6 +24,7 @@
 		patterns: [
 			{include: "#comment"}
 			{include: "#keywords"}
+			{include: "#backref"}
 			{include: "#macros"}
 			{include: "#string"}
 			{include: "#number"}
@@ -33,7 +34,6 @@
 			{include: "#attributes"}
 			{include: "#globals"}
 			{include: "#function-call"}
-			{include: "#backref"}
 			{include: "#label"}
 			{include: "#variable"}
 		]


debug

debug

--- lib/emulator/emulator-manager.coffee
+++ lib/emulator/emulator-manager.coffee
@@ -46,10 +46,10 @@
     if typeof @debugServer.offline() is 'undefined'
       return alert "please launch debug server."

-    if typeof @emulatorView is 'undefined' and @debugServer.offline() == false
+    if typeof @emulatorView is 'undefined' and (!@debugServer.offline())
       EmulatorView = require './emulator-view'
       @emulatorView = new EmulatorView()
-    else if @debugServer.offline() == true and @emulatorView.isHidden() == true
+    else if @debugServer.offline() and @emulatorView.isHidden()
       if @debugServer.closeServer is "after"
         alert "please launch debug server."
     else


Update atom-beautify configuration

Update atom-beautify configuration

--- Atom/config.cson
+++ Atom/config.cson
@@ -23,5 +23,6 @@
     js_space_after_anon_function: true
     js_end_with_newline: true
     language_js_beautify_on_save: true
+    language_json_beautify_on_save: true
   "pigments":
     markerType: "dot"


:bug: Fix markers redraw on pane change after destroy

--- lib/minimap-find-results-view.coffee
+++ lib/minimap-find-results-view.coffee
@@ -18,6 +18,7 @@
       @unsubscribe()
       @destroyDecorations()
       @decorationsByMarkerId = {}
+      @markers = null

     destroyDecorations: ->
       decoration.destroy() for id, decoration of @decorationsByMarkerId
@@ -34,4 +35,4 @@

     activePaneItemChanged: ->
       @destroyDecorations()
-      setImmediate => @markersUpdated(@model.markers)
+      setImmediate => @markersUpdated(@model.markers) if @markers?


Allow excerpts to be set on unpositioned assets

Maybe this should be allowed anytime an unpositioned asset is (un)selected

--- app/assets/volume/slot.coffee
+++ app/assets/volume/slot.coffee
@@ -24,7 +24,7 @@
         .search('asset', undefined)
         .search('record', undefined)
         .search($scope.current?.type || '', $scope.current?.id)
-        .search('select', ruler.selection.format())
+        .search('select', ruler.selection?.format())

     if editing || slot.checkPermission(constants.permission.EDIT)
       url = if editing then slot.route() else slot.editRoute()
@@ -226,7 +226,8 @@

       editExcerpt: () ->
         @excerpt = undefined
-        return if !@asset || @segment.full || !@segment.overlaps(seg = ruler.selection) || !@asset.checkPermission(constants.permission.EDIT)
+        seg = ruler.selection
+        return if !@asset || !seg || (@segment.full && !seg.full) || !@segment.overlaps(seg) || !@asset.checkPermission(constants.permission.EDIT)
         excerpt = @excerpts.find((e) -> seg.overlaps(e.segment))
         @excerpt =
           if !excerpt


Remember tag toggles

Remember tag toggles

Fixes #3245

--- app/assets/volume/slot.coffee
+++ app/assets/volume/slot.coffee
@@ -708,7 +708,7 @@
               tag = $scope.tags.find (t) -> t.id == data.id
               unless tag
                 tag = new Tag(data)
-                tag.active = true
+                tag.toggle(true)
                 $scope.tags.push(tag)
             tag.fillData(data)
             if (if editing then tag.keyword?.length else tag.coverage?.length)
@@ -727,10 +727,12 @@
     $scope.vote = (name, vote) ->
       new TagName(name).save(vote)

+    tagToggle = storage.get('tag-toggle')?.split("\n") ? []
+
     class Tag extends TagName
       constructor: (t) ->
         @id = t.id
-        @active = false
+        @active = t.id in tagToggle
         @fillData(t)
         return

@@ -745,8 +747,12 @@
               this[f].push(Segment.make(s))
         return

-      toggle: ->
-        @active = !@active
+      toggle: (act) ->
+        if @active = act ? !@active
+          tagToggle.push(@id)
+        else
+          tagToggle.remove(@id)
+        storage.set('tag-toggle', tagToggle.join("\n"))

       update: ->
         state = false


完了タスクをドラッグ中に、スタッフなどの後ろに描画されていたのを修正

完了タスクをドラッグ中に、スタッフなどの後ろに描画されていたのを修正

--- app/js/project/task.js.coffee
+++ app/js/project/task.js.coffee
@@ -157,6 +157,7 @@
     helper: 'clone',
     cursor: 'url(../img/Hand_on.png), default',
     distance: 7,
+    zIndex: 100,
     start: (event, ui) -> $(this).css('visibility', 'hidden')
     stop: (event, ui) ->
       if $(this).hasClass('completed')


Update tutorial

Update tutorial

--- app/lib/tutorial-steps.coffee
+++ app/lib/tutorial-steps.coffee
@@ -10,6 +10,25 @@
     attachment: '0.5 0.5 .marking-surface 0.5 0.5'
     block: '.subject-container, button[name="next-step"]'
     next: 'measureStem'
+
+module.exports =
+  welcome: new Step
+    header: 'Welcome to the Leaves Project!'
+    details: 'This quick tutorial will guide you through your first classification.'
+    attachment: '0.5 0.5 .marking-surface 0.5 0.5'
+    block: '.subject-container, button[name="next-step"]'
+    next: 'whatIsThis'
+
+  whatIsThis: new Step
+    header: 'What are we looking at?'
+    details: '''
+      We are looking through a microscope at a section of a plant.
+      The rounded bulbs growing from either side are actually tiny leaves!
+      Measuring the length and width of these leaves can tell us what kind of plant we have.
+    '''
+    attachment: 'center bottom .marking-surface center bottom'
+    block: '.subject-container, button[name="next-step"]'
+    next: 'measureFirstLobule'

   # scale: new Step
   #   details: 'First we\'ll calibrate our classification to the scale of each image.'
@@ -35,28 +54,28 @@
   #   actionable: 'button[name="load-next-step"]'
   #   next: 'click button[name="load-next-step"]': 'measureStem'

-  measureStem: new Step
-    details: 'First we\'ll measure the thickness of the stem.'
-    instruction: 'Drag from the left to the right of the stem at its widest point.'
-    attachment: 'center bottom .subject-container center 0.4'
+  # measureStem: new Step
+  #   details: 'First we\'ll measure the thickness of the stem.'
+  #   instruction: 'Drag from the left to the right of the stem at its widest point.'
+  #   attachment: 'center bottom .subject-container center 0.4'

-    demo: (callback) ->
-      ghostMouse.run ->
-        @move '.marking-surface', 0.39, 0.66
-        @drag '.marking-surface', 0.53, 0.58
-        @do 0, -> callback()
+  #   demo: (callback) ->
+  #     ghostMouse.run ->
+  #       @move '.marking-surface', 0.39, 0.66
+  #       @drag '.marking-surface', 0.53, 0.58
+  #       @do 0, -> callback()

-    next:
-      'mouseup .marking-surface': 'nextAfterStem'
+  #   next:
+  #     'mouseup .marking-surface': 'nextAfterStem'

-  nextAfterStem: new Step
-    details: 'When you\'re satisfied with your measurement, move on the the next step.'
-    attachment: 'center bottom button[name="load-next-step"] center top'
-    actionable: 'button[name="load-next-step"]'
-    next: 'click button[name="load-next-step"]': 'measureFirstLobule'
+  # nextAfterStem: new Step
+  #   details: 'When you\'re satisfied with your measurement, move on the the next step.'
+  #   attachment: 'center bottom button[name="load-next-step"] center top'
+  #   actionable: 'button[name="load-next-step"]'
+  #   next: 'click button[name="load-next-step"]': 'measureFirstLobule'

   measureFirstLobule: new Step
-    details: 'Now we need to draw crosses to measure the major and minor axes of each of the lobules.'
+    details: 'Let\'s start by marking the length of the first leaf.'
     instruction: 'Drag from the top to the bottom of the lobule at the top-left of the image.'
     attachment: 'left middle .subject-container 0.4 0.4'

@@ -70,7 +89,11 @@
       'mouseup .marking-surface': 'measureSecondAxis'

   measureSecondAxis: new Step
-    details: 'Now the minor axis.'
+    details: '''
+      Now we drag out the width.
+      As you drag across, you'll be able to see the angle between the lines change.
+      Keep it as close to 90° as possible!
+    '''
     instruction: 'Now drag a line out perpendicular to the previous line to complete the cross.'
     attachment: 'left middle .subject-container 0.4 0.4'

@@ -96,9 +119,6 @@
       @mousesUp = 0

     demo: (callback) ->
-
-      [[], [], [], []]
-
       ghostMouse.run ->
         @move '.marking-surface', 0.560843373493976, 0.25523714208791376
         @drag '.marking-surface', 0.7740963855421686, 0.7611659958428545
@@ -109,20 +129,14 @@
     next:
       'mouseup .marking-surface': ->
         @mousesUp += 1 if @markCreatedOnStep
-
-        if @mousesUp is 2
-          console.log 'To finish'
-          'finish'
-        else
-          console.log 'Dont change steps'
-          'oneMore'
+        if @mousesUp is 2 then 'finish' else 'oneMore'

     onExit: ->
       delete @mousesUp
       delete @markCreatedOnStep

   finish: new Step
-    details: 'Now that we\'ve marked the stem and all the lobules, move on to the next image.'
+    details: 'Now that we\'ve marked all the leaves, we can move on to the next image.'
     attachment: 'center bottom button[name="finish"] center top'
     actionable: 'button[name="finish"]'
     next: 'click button[name="finish"]': true


[atom] add path to jshint

[atom] add path to jshint

--- .atom/config.cson
+++ .atom/config.cson
@@ -15,3 +15,5 @@
     rubyExecutablePath: "/Users/stevenschobert/.asdf/shims/ruby"
   "tree-view":
     hideVcsIgnoredFiles: true
+  "linter-jshint":
+    executablePath: "/Users/stevenschobert/.asdf/shims/jshint"


Update Atom preferences

Update Atom preferences

--- .atom/config.cson
+++ .atom/config.cson
@@ -15,11 +15,11 @@
     invisibles: {}
   emmet: {}
   linter:
+    lintOnFly: false
     showErrorInline: false
     showErrorTabLine: false
     underlineIssues: false
   "tree-view":
     hideIgnoredNames: true
   whitespace:
-    ensureSingleTrailingNewline: false
-    ignoreWhitespaceOnCurrentLine: false+    ignoreWhitespaceOnCurrentLine: false


Re-enable coffeelint.

Re-enable coffeelint.

--- .atom/config.cson
+++ .atom/config.cson
@@ -42,7 +42,6 @@
       "github"
       "linter-clang"
       "nvatom"
-      "linter-coffeelint"
     ]
     openEmptyEditorOnStart: false
     packagesWithKeymapsDisabled: [


Adjusts the PHP memory limit.

Adjusts the PHP memory limit.

--- .atom/config.cson
+++ .atom/config.cson
@@ -75,6 +75,8 @@
   "go-plus":
     panel:
       displayMode: "closed"
+  "ide-php":
+    memoryLimit: "512M"
   "ide-typescript": {}
   linter:
     lintOnChange: false


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -12,7 +12,7 @@

     bullet.include ActiveBounds

-    # => ullet will be removed when it
+    # => bullet will be removed when it
          goes outside of the game bounds.

     bullet2 = GameObject
@@ -26,7 +26,7 @@
         width: 100
         height 100

-
+

 ActiveBounds module
 @name ActiveBounds


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -26,8 +26,7 @@
         width: 100
         height 100

-    # => bullet2 will be removed when it
-         goes outside unless 30 <= I.x <= 130
+    # => bullet2 will be removed wunless 30 <= I.x <= 130
          and

 ActiveBounds module


Pump: clone source when pumping from an Array

--- src/Pump.coffee
+++ src/Pump.coffee
@@ -42,7 +42,7 @@
       @_from.on 'release', -> buffer.resume()
     else if buffer instanceof Array
       @_from = new Buffer
-        content: buffer
+        content: buffer.slice 0
         sealed: true
     else
       throw new Error 'Argument must be datapumps.Buffer or stream'


refactor regions

refactor regions

--- public/views/widget_view.coffee
+++ public/views/widget_view.coffee
@@ -1,7 +1,6 @@
 class WidgetView extends Backbone.View

   initialize: ->
-    @_defineRegions()
     @_grabOptions()

   template: _.template """
@@ -51,14 +50,10 @@
     @staticCategoryId = @$el.data("category-id")
     @productIds       = @$el.data("product-ids")?.split(/, */)

-  _defineRegions: ->
+  _initRegions: ->
     @regions =
-      productList:  ".epages-shop-product-list"
-      categoryList: ".epages-shop-category-list"
-      searchForm:   ".epages-shop-search-form"
-      sort:         ".epages-shop-sort"
-      cart:         ".epages-shop-cart"
-
-  _initRegions: ->
-    for name, className of @regions
-      @regions[name] = @$(className)
+      productList:  @$(".epages-shop-product-list")
+      categoryList: @$(".epages-shop-category-list")
+      searchForm:   @$(".epages-shop-search-form")
+      sort:         @$(".epages-shop-sort")
+      cart:         @$(".epages-shop-cart")


Restore cache methods

Restore cache methods

--- apps/about/test/routes.coffee
+++ apps/about/test/routes.coffee
@@ -57,16 +57,12 @@
     twilioSendSmsArgs = null
     send = null
     json = null
-    cacheSetArgs = null

     describe 'first time', ->

       beforeEach ->
-        cache = routes.__get__ 'cache'
-        cache.get = (key, callback) ->
-          callback null, null
-        cache.set = (key, value) ->
-          cacheSetArgs = arguments
+        sinon.stub routes.__get__('cache'), 'set', (key, value) =>
+          @cacheSet = arguments

         twilio = routes.__get__ 'twilio'
         twilio.RestClient = class TwilioClientStub
@@ -74,6 +70,9 @@
           sendSms: -> twilioSendSmsArgs = arguments

         routes.sendSMS { param: -> '+1 555 111 2222' }, { send: send = sinon.stub(), json: json = sinon.stub() }
+
+      afterEach ->
+        routes.__get__('cache').set.restore()

       it 'sends a link with a valid phone number', ->
         twilioSendSmsArgs[0].to.should.equal '+15551112222'
@@ -87,18 +86,17 @@
         json.args[0][1].msg.should.equal 'Error!'

       it 'sets sent in the cache', ->
-        cacheSetArgs[0].should.equal 'sms/iphone/+15551112222'
+        @cacheSet[0].should.equal 'sms/iphone/+15551112222'

     describe 'second time time', ->

       beforeEach ->
-        cache = routes.__get__ 'cache'
-        cache.get = (key, callback) ->
-          callback null, 'value set'
-        cache.set = (key, value) ->
-          cacheSetArgs = arguments
+        sinon.stub routes.__get__('cache'), 'get', (key, cb) ->
+          cb null, 'existy'
+        routes.sendSMS { param: -> '+1 555 111 2222' }, { send: send = sinon.stub(), json: json = sinon.stub() }

-        routes.sendSMS { param: -> '+1 555 111 2222' }, { send: send = sinon.stub(), json: json = sinon.stub() }
+      afterEach ->
+        routes.__get__('cache').get.restore()

       it 'throws an error', ->
         json.args[0][1].msg.should.equal 'Download link has already been sent to this number.'


Cut down to 10 minutes.

Cut down to 10 minutes.


old code

old code

--- apps/artist_old/routes.coffee
+++ apps/artist_old/routes.coffee
@@ -27,7 +27,6 @@
     carousel.fetch(cache: true)
     statuses.fetch(cache: true)
   ]).spread((artistRequest, carouselRequest, statusesRequest) ->
-    biography = artist.related().articles.biography()
     nav = new Nav artist: artist, statuses: statusesRequest.value

     if artistRequest.state is 'rejected'


Attach a Zoom modal for carousel images

Attach a Zoom modal for carousel images

--- apps/show/client/index.coffee
+++ apps/show/client/index.coffee
@@ -1,3 +1,4 @@
+_ = require 'underscore'
 { SHOW, ARTWORKS } = require('sharify').data
 PartnerShow = require '../../../models/partner_show.coffee'
 ShareView = require '../../../components/share/view.coffee'
@@ -5,12 +6,16 @@
 ArtworkColumnsView = require '../../../components/artwork_columns/view.coffee'
 attachFollowArtists = require '../components/follow_artists/index.coffee'
 attachFollowProfile = require '../components/follow_profile/index.coffee'
+ZoomView = require '../../../components/modal/zoom.coffee'

 module.exports.init = ->
   show = new PartnerShow SHOW
   show.related().artworks.reset ARTWORKS

-  initCarousel $('.js-show-installation-shot-carousel')
+  { flickity } = initCarousel $('.js-show-installation-shot-carousel')
+  flickity.on 'staticClick', (event, pointer, cellElement, cellIndex) ->
+    src = $(cellElement).find('img').attr('src')
+    new ZoomView imgSrc: src

   artworkColumnsView = new ArtworkColumnsView
     el: $('.js-show-artworks-columns')


Fix exporting of template due to missing credentials (#272)

* Fix exporting of template due to missing credentials

* Drop useless variable assignmet

--- src/coffee/export.coffee
+++ src/coffee/export.coffee
@@ -321,9 +321,8 @@
           Promise.reject err

   createTemplate: (languages, outputFile, allProductTypes = false) ->
-    @typesService.getAll(@client)
-    .then (result) =>
-      productTypes = result.body.results
+    @typesService.getAll(@client, @projectKey)
+    .then (productTypes) =>
       if _.size(productTypes) is 0
         Promise.reject 'Can not find any product type.'
       else


Remove debug.

Remove debug.

--- src/coffee/flight.coffee
+++ src/coffee/flight.coffee
@@ -217,22 +217,6 @@
         window.scrollTo 0, 1
     , 50

-  debug: (str) ->
-    debug = document.getElementById('debug')
-
-    if str is 'hide'
-      debug.style.display = "none"
-      return
-
-    if str is 'show'
-      debug.style.display = "block"
-      return
-
-    str = str += '<br />'
-    content = debug.innerHTML
-    str = str += content
-    debug.innerHTML = str
-
   handleEvents: (e) =>
     switch e.type
       when 'touchstart' then @onTouchStart(e)


Fix flight mouse events to simulate pressed state

* Pressed state used on touch devices.

--- src/coffee/flight.coffee
+++ src/coffee/flight.coffee
@@ -39,7 +39,7 @@
     @hideUrlBar() if options.hideUrlbar

     document.body.addEventListener('touchstart', @handleEvents, false)
-    document.body.addEventListener('click', @handleEvents, false)
+    document.body.addEventListener('mousedown', @handleEvents, false)

   # Public: Go to a specific page.
   #
@@ -220,19 +220,24 @@
   handleEvents: (e) =>
     switch e.type
       when 'touchstart' then @onTouchStart(e)
-      when 'click' then @onTouchStart(e)
+      when 'mousedown' then @onTouchStart(e)
       when 'touchmove' then @onTouchMove(e)
       when 'touchend' then @onTouchEnd(e)

   onTouchStart: (e) =>
     @moved = false
-    @theTarget =  document.elementFromPoint(e.targetTouches[0].clientX, e.targetTouches[0].clientY)
+
+    if window.Touch
+      @theTarget =  document.elementFromPoint(e.targetTouches[0].clientX, e.targetTouches[0].clientY)
+    else
+      @theTarget = document.elementFromPoint e.clientX, e.clientY

     if @theTarget.nodeName and @theTarget.nodeName.toLowerCase() isnt 'a'
       @theTarget = @theTarget.parentNode

     @theTarget.className+= ' pressed'
     @theTarget.addEventListener('touchmove', @onTouchMove, false)
+    @theTarget.addEventListener('mouseout', @onTouchEnd, false)
     @theTarget.addEventListener('touchend', @onTouchEnd, false)
     @theTarget.addEventListener('mouseup', @onTouchEnd, false)
     @theTarget.addEventListener('touchcancel', @onTouchcancel, false)


Removing extra external image upload as it is handled on creation.

--- src/coffee/import.coffee
+++ src/coffee/import.coffee
@@ -43,6 +43,7 @@
           deferred.resolve JSON.parse(body).results
         else
           deferred.reject 'Problem on getting existing products: ' + body
+
     deferred.promise

   initMatcher: (existingProducts) ->
@@ -124,6 +125,7 @@
           deferred.resolve "Problem on updating product:\n" + humanReadable
         else
           deferred.reject 'Problem on updating product: ' + body
+
     deferred.promise

   create: (product) ->
@@ -134,23 +136,18 @@
         deferred.reject 'Error on creating new product: ' + error
       else
         if response.statusCode is 201
-          @adjustmentsAfterCreation(product, JSON.parse(body), deferred)
+          @publishProduct(JSON.parse(body)).then (msg) ->
+            deferred.resolve 'New product created.'
+          .fail (msg) ->
+            deferred.reject msg
         else if response.statusCode is 400
           parsed = JSON.parse body
           humanReadable = JSON.stringify parsed, null, '  '
           deferred.reject "Problem on creating new product:\n" + humanReadable
         else
           deferred.reject 'Problem on creating new product: ' + body
+
     deferred.promise
-
-  adjustmentsAfterCreation: (product, respondedProduct, deferred) ->
-    @addExternalImages(product, respondedProduct).then (respondedProduct) =>
-      @publishProduct(respondedProduct).then (msg) ->
-        deferred.resolve 'New product created.'
-      .fail (msg) ->
-        deferred.reject msg
-    .fail (msg) ->
-      deferred.reject msg

   publishProduct: (product, publish = true) ->
     deferred = Q.defer()
@@ -179,46 +176,5 @@

     deferred.promise

-  addExternalImages: (product, respondedProduct) ->
-    deferred = Q.defer()
-    imageActions = @createExternalImageActions(product.masterVariant)
-    for variant in product.variants
-      imageActions = imageActions.concat(@createExternalImageActions(variant))
-    if _.size(imageActions) is 0
-      deferred.resolve respondedProduct
-      return deferred.promise
-    data =
-      version: respondedProduct.version
-      actions: imageActions
-    @rest.POST "/products/#{respondedProduct.id}", JSON.stringify(data), (error, response, body) ->
-      if error
-        deferred.reject 'Error on adding external images to product: ' + error
-      else
-        if response.statusCode is 200
-          deferred.resolve JSON.parse(body)
-        else if response.statusCode is 400
-          parsed = JSON.parse body
-          humanReadable = JSON.stringify parsed, null, '  '
-          deferred.reject "Problem on adding external images to product:\n" + humanReadable
-        else
-          deferred.reject 'Problem on adding external images to product: ' + body
-
-    deferred.promise
-
-  createExternalImageActions: (variant) ->
-    actions = []
-    return actions if _.size(variant.images) is 0
-    for image in variant.images
-      action =
-        action: 'addExternalImage'
-        variantId: variant.id
-        image:
-          url: image.url
-          dimensions: image.dimensions
-#          label: image.label
-      actions.push action
-
-    actions
-

 module.exports = Import


add optional # in fornt of incident number

--- scripts/pagerv2_commands.coffee
+++ scripts/pagerv2_commands.coffee
@@ -154,7 +154,7 @@
     res.finish()

 #   hubot pd incident <number> - gives more information about incident number <number>
-  robot.respond /pd (?:inc |incident )(\d+|[A-Z0-9]{7})\s*$/, 'pd_incident', (res) ->
+  robot.respond /pd (?:inc |incident )#?(\d+|[A-Z0-9]{7})\s*$/, 'pd_incident', (res) ->
     [ _, incident ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->
@@ -200,7 +200,7 @@
     res.finish()

 #   hubot pd ack <#>           - acknowledges incident <number>
-  robot.respond /pd ack (.+)\s*$/, 'pd_ack_one', (res) ->
+  robot.respond /pd ack #?(.+)\s*$/, 'pd_ack_one', (res) ->
     [ _, incidents ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->
@@ -229,7 +229,7 @@
     res.finish()

 #   hubot pd res|resolve <#>   - acknowledges incident <number>
-  robot.respond /pd res(?:olve)? (.+)\s*$/, 'pd_res_one', (res) ->
+  robot.respond /pd res(?:olve)? #?(.+)\s*$/, 'pd_res_one', (res) ->
     [ _, incidents ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->
@@ -264,7 +264,7 @@

 #   hubot pd assign <#,#,#> to me     - assigns incidents <#,#,#> to caller
 #   hubot pd assign <#,#,#> to <user> - assigns incidents <#,#,#> to user
-  robot.respond /pd assign (.+) to (me|[^ ]+)\s*$/, 'pd_assign_one', (res) ->
+  robot.respond /pd assign #?(.+) to (me|[^ ]+)\s*$/, 'pd_assign_one', (res) ->
     [ _, incidents, who ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->
@@ -300,7 +300,7 @@

 #   hubot pd snooze <#,#,#> [for] [<duration>] [min] - acknowledges incident <number>
   robot.respond (
-    /pd snooze (.+)(?: (?:for )(\d+)(?: min(?:utes)?)?)?\s*$/
+    /pd snooze #?(.+)(?: (?:for )(\d+)(?: min(?:utes)?)?)?\s*$/
   ), 'pd_snooze_one', (res) ->
     [ _, incidents, duration ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
@@ -316,7 +316,7 @@
     res.finish()

 #   hubot pd note <#,#,#> <note> - create a note for incidents <#,#,#>
-  robot.respond /pd note ([^\s]+) (.*)$/, 'pd_note', (res) ->
+  robot.respond /pd note #?([^\s]+) (.*)$/, 'pd_note', (res) ->
     [ _, incident, note ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->
@@ -328,7 +328,7 @@
     res.finish()

 #   hubot pd notes <#>           - read notes for incident <#>
-  robot.respond /pd notes ([^\s]+)\s*$/, 'pd_notes', (res) ->
+  robot.respond /pd notes #?([^\s]+)\s*$/, 'pd_notes', (res) ->
     [ _, incident ] = res.match
     pagerv2.getPermission(res.envelope.user, 'pduser')
     .then ->


¿Fix private welcome message?

¿Fix private welcome message?

--- scripts/welcome-to-zihub.coffee
+++ scripts/welcome-to-zihub.coffee
@@ -56,8 +56,8 @@
       if user.name in robot.brain.data.nicks
         robot.logger.debug "Already know #{user.name}"
         return
-      robot.messageRoom user.name, welcomeMsg(user.name)
-      robot.messageRoom '#presentaciones', "Hola @#{user.name}"
+      robot.messageRoom '#presentaciones', "Hola @#{user.name} ¿por qué no te presentas para que sepamos quién eres?"
+      robot.messageRoom "@#{user.name}", welcomeMsg(user.name)
       add_nicks user.name
 #      welcomeGif(user, user.name)


Check existence of login info

Check existence of login info

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -305,6 +305,9 @@

     JUser.login clientId, { username : email, password }, (err, info) ->

+      unless info
+        return res.status(500).send 'An error occurred'
+
       {isValid : isEmail} = JUser.validateAt 'email', email, yes

       if err and isEmail
@@ -364,7 +367,11 @@
   return handleClientIdNotFound res, req unless clientId

   JUser.login clientId, { username, password }, (err, info) ->
-    return res.status(403).send err.message  if err?
+    if err
+      return res.status(403).send err.message
+    else if not info
+      return res.status(500).send 'An error occurred'
+
     res.cookie 'clientId', info.replacementToken, path : '/'
     res.status(200).end()


fix boolean environment variables

fix boolean environment variables

--- packages/rocketchat-lib/server/functions/settings.coffee
+++ packages/rocketchat-lib/server/functions/settings.coffee
@@ -23,6 +23,10 @@

 	if process?.env?[_id]?
 		value = process.env[_id]
+		if value.toLowerCase() is "true"
+			value = true
+		else if value.toLowerCase() is "false"
+			value = false
 		options.processEnvValue = value
 		options.valueSource = 'processEnvValue'


Added test for debugging

Added test for debugging

--- javascripts/gh-pages.coffee
+++ javascripts/gh-pages.coffee
@@ -7,3 +7,6 @@
 do_wrap (ndx) -> $(this).wrap("<a href=\"" + $(this).text + "\"/>")

 $(".repository-name").each do_wrap
+
+# silly hello, world test for jquery inclusion
+$ -> alert "It works!"


Better webview size

Better webview size

--- Resources/webview_proxy.coffee
+++ Resources/webview_proxy.coffee
@@ -1,7 +1,7 @@
 class WebviewProxy
   constructor: ->
     @wv = Ti.UI.createWebView(
-      height: 200
+      height: 10
       width: 320
       bottom: 0
       left: 0


Fix boundary-matching of manpage title macros

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -922,8 +922,8 @@
 			# .TH: Title
 			name: "markup.heading.title.function.man.macro.roff"
 			patterns: [{include: "#params"}]
-			begin: "^([.'])[ \t]*(TH)"
-			end: "$"
+			begin: "^([.'])[ \t]*(TH)\\b"
+			end: "$|(?=\\\\\")"
 			beginCaptures:
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.name.function.roff"}
@@ -932,8 +932,8 @@
 			# .SH: Section heading
 			name: "markup.heading.section.function.man.macro.roff"
 			patterns: [{include: "#params"}]
-			begin: "^([.'])[ \t]*(SH)"
-			end: "$"
+			begin: "^([.'])[ \t]*(SH)\\b"
+			end: "$|(?=\\\\\")"
 			beginCaptures:
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.name.function.roff"}
@@ -942,8 +942,8 @@
 			# .SS: Subsection
 			name: "markup.heading.subsection.function.man.macro.roff"
 			patterns: [{include: "#params"}]
-			begin: "^([.'])[ \t]*(SS)"
-			end: "$"
+			begin: "^([.'])[ \t]*(SS)\\b"
+			end: "$|(?=\\\\\")"
 			beginCaptures:
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.name.function.roff"}
@@ -952,7 +952,7 @@
 			# .EX: Example code
 			contentName: "markup.raw.roff"
 			begin: "^([.'])[ \t]*(EX)\\s*(\\\\\".*)?$"
-			end:   "^([.'])[ \t]*(EE)\\b(.*)$"
+			end:   "^([.'])[ \t]*(EE)\\b"
 			patterns: [{ include: "$self" }]
 			beginCaptures:
 				1: {name: "punctuation.definition.function.macro.roff"}
@@ -961,8 +961,8 @@
 			endCaptures:
 				1: {name: "punctuation.definition.function.macro.roff"}
 				2: {name: "entity.name.function.roff"}
-				3: {patterns: [{include: "#params"}]}
-		},{
+		},{
+
 			# .B/.SB: Bold
 			contentName: "markup.bold.roff"
 			begin: "^([.'])[ \t]*(S?B)(\\s*\\\\\".*$)?(?=$|[ \t]+|\\\\)"


Highlight e-mail links as per Alhadis/Mono@f363ed4

Also, add more punctuation to whitelisted affix characters. Technically,
the macro imposes no restrictions about what can follow a hyperlink, but
I'd prefer these patterns didn't match anything they aren't supposed to.


Updates commit SHA (I actually fixed bug already)

--- js/src/turbolinks.js.coffee
+++ js/src/turbolinks.js.coffee
@@ -1,5 +1,5 @@
 # Rails / Turbolinks
-# Extracted from commit f90775d484b78f5ffd823f13f2265aef52a2620c
+# Extracted from commit a0a382a9871dac859a4282312603394adb9f13a6

 pageCache      = {}
 cacheSize      = 10


Add tests for trailingSlash - first problem, wrong scope for tests

--- js/tests/inner-tests.coffee
+++ js/tests/inner-tests.coffee
@@ -1,5 +1,11 @@
 j = @jasmine.getEnv()

-j.describe "circle test suite", ->
-  j.it 'should increment a variable', ->
-    @expect(1).toEqual 1
+j.describe "trailingSlash", ->
+  j.it 'should remove trailing slashes', ->
+    @expect(stripTrailingSlash('/gh/a/b/')).toEqual '/gh/a/b'
+
+  j.it 'shouldnt remove non-trailing slashes', ->
+    @expect(stripTrailingSlash('/gh/a/b/edit')).toEqual '/gh/a/b/edit'
+
+  j.it 'shouldnt delete root variable', ->
+    @expect(stripTrailingSlash('/')).toEqual '/'


Dojo release as 1.8.3

Dojo release as 1.8.3

--- src/dojo.coffee
+++ src/dojo.coffee
@@ -7,7 +7,7 @@
   # Merge user options with default options
   options ?= {}
   options.method ?= 'release'
-  options.version ?= '1.7.1'
+  options.version ?= '1.8.3'
   options.repository ?= '/tmp'
   # Store HTTP request in case we need to download Dojo
   loading = true


Fixup improper debug-logic guarding in game class.

--- src/game.coffee
+++ src/game.coffee
@@ -72,8 +72,9 @@
       @physics.startSystem Phaser.Physics.ARCADE

       @physics.arcade.gravity.y = 600
-      gui = @gui?.addFolder 'gravity'
-      gui.add @physics.arcade.gravity, 'y', 0, 2 * @physics.arcade.gravity.y
+      if @debugging
+        gui = @gui?.addFolder 'gravity'
+        gui.add @physics.arcade.gravity, 'y', 0, 2 * @physics.arcade.gravity.y

       @_addBackground()
       @_addMate()
@@ -112,6 +113,8 @@
       @physics.arcade.collide @player.sprite, @platforms.group

     _updateDebugDisplay: ->
+      return unless @debugging
+
       gutter = 2 * @debugFontSize
       line = kPhaserLineRatio * @debugFontSize

@@ -127,6 +130,8 @@
           layoutY += line

     _updateDebugOverlays: ->
+      return unless @debugging
+
       @debug.body @platforms.ground
       @debug.body @player.sprite if @player.debugging


Fix karma.conf

Fix karma.conf

--- karma.conf.coffee
+++ karma.conf.coffee
@@ -11,7 +11,7 @@
       'node_modules/commonjs-require/commonjs-require.js'

       # -- wrapped by commonjs --
-      'node_modules/expect.js/expect.js'
+      'node_modules/expect.js/index.js'
       'node_modules/underscore/underscore.js'
       'node_modules/backbone/backbone.js'
       'node_modules/async/lib/async.js'
@@ -36,7 +36,7 @@
       'src/**/*.coffee': ['commonjs', 'coffee']
       'spec/**/*.coffee': ['coffee']

-      'node_modules/expect.js/expect.js': ['commonjs']
+      'node_modules/expect.js/index.js': ['commonjs']
       'node_modules/underscore/underscore.js': ['commonjs']
       'node_modules/backbone/backbone.js': ['commonjs']
       'node_modules/async/lib/async.js': ['commonjs']
@@ -110,4 +110,4 @@
       'karma-spec-reporter'
       'karma-coffee-preprocessor'
       'karma-commonjs-preprocessor'
-    ]+    ]


fix scope

fix scope

--- client/landing/app/Applications/Groups.kdapplication/Views/groupsinvitationtabpaneview.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/groupsinvitationtabpaneview.coffee
@@ -18,7 +18,7 @@
     @addSubView @listView

     @controller.on 'UpdatePendingCount', @updatePendingCount.bind this
-    @listView.on 'invitationStatusChanged', ->
+    @listView.on 'invitationStatusChanged', =>
       @parent.tabHandle.markDirty()

   addListeners:->


Fix diffing weirdness

Fix diffing weirdness

--- salvus/page/project_search.cjsx
+++ salvus/page/project_search.cjsx
@@ -181,7 +181,8 @@
         search_cb       : rtypes.func

     getInitialState: ->
-        case_sensitive  : false    # do not change any of these to true without also changing : false    # the "@checkbox_state={}" below.
+        case_sensitive  : false    # do not change any of these to true without also changing
+        subdirectories  : false    # the "@checkbox_state={}" below.
         hidden_files    : false

     handle_change : (name) ->
@@ -218,7 +219,6 @@
     componentWillMount: ->
         if not @checkbox_state?
             @checkbox_state = {}
-

     toggle_checkbox : (checkbox) ->
         @checkbox_state[checkbox] = not @checkbox_state[checkbox]
@@ -265,12 +265,6 @@
                 command            : ""
                 most_recent_search : ""
                 most_recent_path   : @props.current_path.join("/")
-            @setState
-                search_results     : []
-                search_error       : undefined
-                command            : ""
-                most_recent_search : ""
-                most_recent_path   : @props.current_path.join("/")
             return

         cmd = @generate_command(query, @checkbox_state.subdirectories, not @checkbox_state.case_sensitive, @checkbox_state.hidden_files)
@@ -289,7 +283,7 @@
             command         : cmd + " | cut -c 1-256"  # truncate horizontal line length (imagine a binary file that is one very long line)
             timeout         : 10   # how long grep runs on client
             network_timeout : 15   # how long network call has until it must return something or get total error.
-            max_output      : max_output, cmd, cmd
+            max_output      : max_output
             bash            : true
             err_on_exit     : true
             path            : @props.current_path.join("/") # expects a string
@@ -351,7 +345,7 @@

     output_heading : ->
         if @state.most_recent_search? and @state.most_recent_path?
-            return <ProjectSearchOutputHeading
+            <ProjectSearchOutputHeading
                 most_recent_path   = {@state.most_recent_path}
                 command            = {@state.command}
                 most_recent_search = {@state.most_recent_search}


restore some Emacs move cmds, resolve conflicts btw atom-ide-ui/atom-ternjs

--- keymap.cson
+++ keymap.cson
@@ -35,8 +35,37 @@

 'atom-text-editor':
   'ctrl-alt-n': 'atom-notes:toggle'
+# cursor movement
+  'ctrl-n': 'core:move-down'
+  #TODO: set new key for fuzzy-finder
+  'ctrl-p': 'core:move-up'
+  #TODO: set new key for find-and-replace:use-selection-as-find-pattern
+  'ctrl-e': 'editor:move-to-end-of-screen-line'

 'atom-text-editor:not([mini])':
   'ctrl-alt-w': 'emmet:wrap-with-abbreviation'
   'ctrl-alt-m': 'emmet:merge-lines'  # ctrl-shift-m
   'ctrl-alt-e': 'emmet:interactive-expand-abbreviation' # ctrl-alt-enter
+
+'atom-text-editor[data-grammar~="source"]':
+  'ctrl-M': 'source-preview:toggle'
+
+# resolve conflict between atom-ide-ui and atom-ternjs packages
+'atom-text-editor[data-grammar~=js]':
+  'ctrl-alt-shift-d': 'atom-ternjs:definition'
+  'ctrl-alt-space': 'atom-ternjs:startCompletion'
+  'alt-shift-o': 'atom-ternjs:documentation'
+  'ctrl-shift-cmd-left': 'atom-ternjs:navigateBack'
+  'ctrl-shift-cmd-right': 'atom-ternjs:navigateForward'
+
+'.platform-darwin atom-text-editor[data-grammar~=js]':
+  'ctrl-alt-c': 'atom-ternjs:rename'
+  'ctrl-shift-r': 'atom-ternjs:references'
+
+'.platform-linux atom-text-editor[data-grammar~=js]':
+  'ctrl-alt-shift-c': 'atom-ternjs:rename'
+  'ctrl-alt-shift-e': 'atom-ternjs:references'
+
+'.platform-win32 atom-text-editor[data-grammar~=js]':
+  'ctrl-alt-c': 'atom-ternjs:rename'
+  'ctrl-shift-e': 'atom-ternjs:references'


cleanup

cleanup

--- resources/assets/coffee/react/profile-page/account-standing.coffee
+++ resources/assets/coffee/react/profile-page/account-standing.coffee
@@ -83,7 +83,8 @@
         td
           className: "#{bn}__table-cell #{bn}__table-cell--date"
           time
-            className: "timeago", dateTime: event.timestamp
+            className: "timeago"
+            dateTime: event.timestamp
             moment(event.timestamp).fromNow()

         td


typo fix #39

typo fix #39

--- docpad.coffee
+++ docpad.coffee
@@ -24,7 +24,7 @@

     # Active sections on the website
     # to deactivate comment out with '#'
-    # you can also chenge order here and it will reflect on page
+    # you can also change order here and it will reflect on page
     sections: [
       'about'
       'location'


add plugins stub

add plugins stub

--- lib/atom-ternjs-config-view.coffee
+++ lib/atom-ternjs-config-view.coffee
@@ -20,6 +20,16 @@
     @content.appendChild(@buildBoolean('libs'))
     @content.appendChild(@buildStringArray(config.loadEagerly, 'loadEagerly'))
     @content.appendChild(@buildStringArray(config.dontLoad, 'dontLoad'))
+
+    wrapper = document.createElement('section')
+    header = document.createElement('h2')
+    header.innerHTML = 'plugins'
+    text = document.createElement('p')
+    text.innerHTML = 'This section isn\'t implemented yet.<br />Please add plugins manually by editing your .tern-project file located in your root-path.'
+    wrapper.appendChild(header)
+    wrapper.appendChild(text)
+
+    @content.appendChild(wrapper)
     @content.appendChild(@close)

   buildStringArray: (obj, section) ->


improve status parsing

improve status parsing

--- src/status.coffee
+++ src/status.coffee
@@ -4,27 +4,10 @@
 # callback - Receives `(err, status)`
 #
 module.exports = S = (repo, callback) ->
-  repo.git "status", (err, stdout, stderr) ->
+  repo.git "status --porcelain", (err, stdout, stderr) ->
     status = new Status repo
     status.parse stdout
-    return callback err, status
-
-
-BEGIN_STAGED    = [
-  "# Changes to be committed:"
-]
-BEGIN_UNSTAGED  = [
-  "# Changed but not updated:"
-  "# Changes not staged for commit:"
-]
-BEGIN_UNTRACKED = [
-  "# Untracked files:"
-]
-FILE            = /^#\s+([^\s]+)[:]\s+(.+)$/
-TYPES =
-  added:    "A"
-  modified: "M"
-  deleted:  "D"
+    callback err, status

 S.Status = class Status
   constructor: (@repo) ->
@@ -32,26 +15,10 @@
   # Internal: Parse the status from stdout of a `git status` command.
   parse: (text) ->
     @files = {}
-    @clean = true
-    state  = null
+    @clean = text.length == 0
     for line in text.split("\n")
-      if ~BEGIN_STAGED.indexOf(line)
-        state = "staged"
-        @clean = false
-      else if ~BEGIN_UNSTAGED.indexOf(line)
-        state = "unstaged"
-        @clean = false
-      else if ~BEGIN_UNTRACKED.indexOf(line)
-        state = "untracked"
-        @clean = false
-      else if state && match = FILE.exec(line)
-        file = match[2]
-        data = switch state
-          when "staged"    then {staged: true,  tracked: true}
-          when "unstaged"  then {staged: false, tracked: true}
-        data.type    = TYPES[match[1]]
-        @files[file] = data
-      else if state == "untracked" && (match = /^#\s+([^\s]+)$/.exec(line))
-        file = match[1]
-        @files[file] = {tracked: false}
-    return
+      if line.length == 0
+        continue
+      file = line.substr 3
+      type = line.substr 0,2
+      @files[file] = { type: type.trim(), staged: (line[0] != " " and line[0] != "?" ) , tracked: line[0] != "?"  }


add tokenize function again

add tokenize function again

--- src/string.coffee
+++ src/string.coffee
@@ -32,9 +32,14 @@
         string = module.exports.replaceUmlauts string
         module.exports.removeSpecialChars string

+    tokenize: (string) ->
+        words = module.exports.words string
+        tokens = words.map module.exports.normalize
+        module.exports.removeDuplicates module.exports.removeEmpty tokens
+
     # split words on whitespace or - or _
-    words: (string) ->
-        _s.words string.replace /[\-_]/g, ' '
+    words: (string) -> _s.words string.replace /[\-_]/g, ' '

-    uniqueNonEmptyWords: (words) ->
-        _.uniq words.filter (word) -> word isnt ''
+    removeEmpty: (tokens) -> tokens.filter (word) -> word isnt ''
+
+    removeDuplicates: (tokens) -> _.uniq tokens


grunt clean as part of grunt dist

grunt clean as part of grunt dist

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -106,6 +106,6 @@

 	grunt.registerTask 'build', ['coffee', 'less']
 	grunt.registerTask 'dev', ['clean', 'build', 'concurrent:dev']
-	grunt.registerTask 'dist', ['build', 'copy:dist', 'ngmin']
+	grunt.registerTask 'dist', ['clean', 'build', 'copy:dist', 'ngmin']

 	grunt.registerTask 'default', ['dev']


Don't assume we can remove the BUILD_DIR

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -123,7 +123,7 @@
     rm 'prebuilt-cef'

   grunt.registerTask 'build', 'Build the application', ->
-    rm BUILD_DIR
+    rm SHELL_APP_DIR
     mkdir path.dirname(BUILD_DIR)
     cp 'atom-shell/Atom.app', SHELL_APP_DIR


Use standard reporter for mocha

Use standard reporter for mocha

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -217,12 +217,10 @@
         src: ['specs/unit/**/*.coffee']
         options:
           require: 'coffee-script/register'
-          reporter: 'dot'
       integration:
         src: ['specs/integration/**/*.coffee']
         options:
           require: 'coffee-script/register'
-          reporter: 'dot'

     # Acceptance testing with cucumber
     cucumberjs:


Compile before linting

Compile before linting

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -34,5 +34,5 @@

   grunt.registerTask 'clean', -> require('rimraf').sync('lib')
   grunt.registerTask('lint', ['coffeelint:src', 'coffeelint:test'])
-  grunt.registerTask('default', ['coffeelint', 'coffee'])
+  grunt.registerTask('default', ['coffee', 'coffeelint'])
   grunt.registerTask('test', ['default', 'coffeelint:test', 'shell:test'])


grunt: clean after test

grunt: clean after test

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -99,6 +99,6 @@
   # Register tasks
   grunt.registerTask 'compile', ['coffee', 'closureCompiler']
   grunt.registerTask 'sources', ['coffee', 'closureDepsWriter']
-  grunt.registerTask 'test', ['sources', 'jasmine']
+  grunt.registerTask 'test', ['sources', 'jasmine', 'clean:test']
   grunt.registerTask 'server', ['sources', 'testserver', 'watch']
   grunt.registerTask 'default', ['compile']


set max line lengths to 100 for coffeescript

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -29,6 +29,8 @@
     coffeelint:
       sabisu: ["lib/sabisu/public/coffee/**/*.coffee"]
       options:
+        max_line_length:
+          value: 100
         no_trailing_whitespace:
           level: 'error'


Gruntfile: Created a new task for examples.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -176,6 +176,9 @@
       dev                :
         path             : 'http://localhost:1111/public/debug'
         app              : 'Google Chrome'
+      examples           :
+        path             : 'http://localhost:1111/build/docs/examples/'
+        app              : 'Google Chrome'
       coverage           :
         path             : 'http://localhost:1111/build/coverage/PhantomJS 1.9.8 (Mac OS X)/lcov-report/index.html'
         app              : 'Google Chrome'
@@ -261,7 +264,7 @@
     ]

-  grunt.registerTask 'build', 'Compile code and run tests.', (app = 'app') ->
+  grunt.registerTask 'build', 'Compile code and run tests.', ->
     grunt.task.run [
       'clean'
       'mkdir'
@@ -277,7 +280,23 @@
     ]

-  grunt.registerTask 'default', 'Run tests and watch the stack for changes', (app = 'app') ->
+  grunt.registerTask 'examples', 'Compile and open examples directory', ->
+    grunt.task.run [
+      'coffee'
+      'coffee2closure'
+      'deps'
+      'builder'
+      'jsdoc'
+      'coffee:examples'
+      'stylus'
+      'copy'
+      'open:examples'
+      'http-server:debug'
+      'watch:examples'
+    ]
+
+
+  grunt.registerTask 'default', 'Run tests and watch the stack for changes', ->
     grunt.task.run [
       'clean'
       'mkdir'


Add support for build config functions

Add support for build config functions

Grunt is now configured as we read the config modules.  Those can now
return functions instead of objects; the functions are called with the
`grunt` object so they can use already-processed config.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -2,16 +2,23 @@
 require 'LiveScript'

 module.exports = (grunt) ->
-  gruntConfig =
+  # Initialize the config with the only thing we know.
+  grunt.config.init
     pkg: grunt.file.readJSON 'package.json'

+  # Assume all files under `grunt/config` and `grunt/userconfig`
+  # are config files.
   grunt.file.expand(
     {filter: 'isFile'},
     ['./grunt/config/**', './grunt/userconfig/**']
   ).forEach (filename) ->
-    key = path.basename filename, '.ls'
-    gruntConfig[key] = require filename
+    # The key is the file's basename sans extension.
+    key = path.basename filename, path.extname filename
+    # The value can be either an object or a function returning one.
+    value = require filename
+    if typeof value is 'function'
+      value = value(grunt)
+    grunt.config.set key, value

-  grunt.initConfig gruntConfig
   (require 'load-grunt-tasks')(grunt)
   grunt.loadTasks 'grunt/tasks'


change constants to uppercase

change constants to uppercase

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,25 +1,28 @@
 module.exports = ->

   @initConfig
+    SRC_DIR: 'src/'
+    TESTS_DIR: 'test/'
+    SPEC_DIR: '<%= TESTS_DIR %>spec/'
+    DIST_FILE: 'dist/<%= pkg.name %>'
+
     pkg: @file.readJSON('package.json')
-
-    distPath: 'dist/<%= pkg.name %>'

     concat:
       dist:
         src: [
-          'src/intro.js',
-          'src/core.js',
-          'src/query.js',
-          'src/manipulation.js',
-          'src/traversing.js',
-          'src/utilities.js',
-          'src/events.js',
-          'src/ajax.js',
-          'src/exports.js',
-          'src/outro.js'
+          '<%= SRC_DIR %>intro.js',
+          '<%= SRC_DIR %>core.js',
+          '<%= SRC_DIR %>query.js',
+          '<%= SRC_DIR %>manipulation.js',
+          '<%= SRC_DIR %>traversing.js',
+          '<%= SRC_DIR %>utilities.js',
+          '<%= SRC_DIR %>events.js',
+          '<%= SRC_DIR %>ajax.js',
+          '<%= SRC_DIR %>exports.js',
+          '<%= SRC_DIR %>outro.js'
         ]
-        dest: '<%= distPath %>.js'
+        dest: '<%= DIST_FILE %>.js'

       options:
         banner: '/*!\n' +
@@ -38,38 +41,38 @@
           jshintrc: '.jshintrc'

       lib:
-        src: ['<%= distPath %>.js']
+        src: ['<%= DIST_FILE %>.js']
         options:
-          jshintrc: 'src/.jshintrc'
+          jshintrc: '<%= SRC_DIR %>.jshintrc'

       tests:
-        src: ['test/spec/*.js']
+        src: ['<%= TESTS_DIR %><%= SPEC_DIR %>/*.js']
         options:
-          jshintrc: 'test/.jshintrc'
+          jshintrc: '<%= TESTS_DIR %>/.jshintrc'

     coffee:
       compile:
         expand: true
-        cwd: 'test/spec'
+        cwd: '<%= TESTS_DIR %><%= SPEC_DIR %>'
         src: ['*.coffee']
-        dest: 'test/spec/'
+        dest: '<%= TESTS_DIR %><%= SPEC_DIR %>/'
         ext: '.js'

     jasmine:
       test:
-        src: ['<%= distPath %>.js']
+        src: ['<%= DIST_FILE %>.js']
         options:
-          specs: ['test/spec/*Spec.js']
-          template: __dirname + '/test/SpecRunner.tmpl'
+          specs: ['<%= SPEC_DIR %>/*Spec.js']
+          template: '<%= TESTS_DIR %>SpecRunner.tmpl'

     uglify:
       dest:
         files:
-          '<%= distPath %>.min.js': ['<%= distPath %>.js']
+          '<%= DIST_FILE %>.min.js': ['<%= DIST_FILE %>.js']

       options:
         banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.homepage %> | <%= pkg.licenses[0].url %> */\n'
-        sourceMap: '<%= distPath %>.sourcemap.js'
+        sourceMap: '<%= DIST_FILE %>.sourcemap.js'

     watch:
       gruntfile:
@@ -77,11 +80,11 @@
         tasks: ['jshint:gruntfile']

       lib:
-        files: ['src/*.js']
+        files: ['<%= SRC_DIR %>*.js']
         tasks: ['build', 'jshint:lib', 'test']

       test:
-        files: ['test/spec/*.coffee']
+        files: ['<%= TESTS_DIR %><%= SPEC_DIR %>/*.coffee']
         tasks: ['test', 'jshint:tests']

   @loadNpmTasks 'grunt-contrib-concat'


Fix s3 upload

Fix s3 upload

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -48,17 +48,19 @@

     # Upload to s3
     s3:
-      bucket: "bugsnagcdn"
-      access: "public-read"
-      gzip: true
+      options:
+        bucket: "bugsnagcdn"
+        access: "public-read"
+        gzip: true

-      upload: [
-        src: "dist/bugsnag.js",
-        dest: "bugsnag-<%= pkg.version %>.js"
-      ,
-        src: "dist/bugsnag.min.js",
-        dest: "bugsnag-<%= pkg.version %>.min.js"
-      ]
+      release:
+        upload: [
+          src: "dist/bugsnag.js",
+          dest: "bugsnag-<%= pkg.version %>.js"
+        ,
+          src: "dist/bugsnag.min.js",
+          dest: "bugsnag-<%= pkg.version %>.min.js"
+        ]

     # Version bumping
     bump:


Only forceexit on Mac

Only forceexit on Mac

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,4 +1,7 @@
 module.exports = (grunt) ->
+  testCommand = 'node node_modules/jasmine-focused/bin/jasmine-focused --coffee --captureExceptions spec'
+  testCommand += ' --forceexit' if process.platform is 'darwin'
+
   grunt.initConfig
     pkg: grunt.file.readJSON('package.json')

@@ -28,7 +31,7 @@
           failOnError: true

       test:
-        command: 'node node_modules/jasmine-focused/bin/jasmine-focused --coffee --captureExceptions --forceexit spec'
+        command: testCommand
         options:
           stdout: true
           stderr: true


Put bower grunt task first

Put bower grunt task first

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -39,10 +39,10 @@
             forceLatest: true
             production: true

+  grunt.loadNpmTasks 'grunt-bower-task'
   grunt.loadNpmTasks 'grunt-contrib-watch'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-compass'
-  grunt.loadNpmTasks 'grunt-bower-task'

   grunt.registerTask 'default', ['bower', 'coffee', 'uglify', 'compass']


Fixes *min and usemin tasks order

Fixes *min and usemin tasks order

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -104,8 +104,12 @@
           banner: "<%= core.banner %>"
           report: "gzip"

-        files:
-          "<%= core.dist %>/assets/css/app.css": ["<%= core.dist %>/assets/css/*.css"]
+        files: [
+          expand: true
+          cwd: "<%= core.dist %>/assets/css/"
+          src: ["*.css", "!*.min.css"]
+          dest: "<%= core.dist %>/assets/css/"
+        ]

       # html:
       #   expand: true
@@ -187,7 +191,7 @@
   grunt.registerTask "test", ["coffeelint", "recess"]

   # Build site with `jekyll`
-  grunt.registerTask "build", ["clean", "test", "less:dist", "shell:dist", "useminPrepare", "concurrent:dist", "rev", "usemin", "manifest"]
+  grunt.registerTask "build", ["clean", "test", "less:dist", "shell:dist", "useminPrepare", "rev", "usemin", "concurrent:dist", "manifest"]

   # Archive old version with specific URL prefix, all old versions goes to http://sparanoid.com/lab/version/
   grunt.registerTask "archive", ["build", "shell:archive", "concurrent:dist"]


checkmaster improved

checkmaster improved

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -175,7 +175,7 @@
 				options:
 					callback:
 						(err, stdout, stderr, ret) ->
-							grunt.fail.fatal "You must be on master branch to run 'release' task"  if stdout isnt "master"
+							grunt.fail.fatal "You must be on master branch to run 'release' task"  if (/^master/).test(stdout) isnt true
 							ret()

 	## Aux Plugins.


Fixed Grunt connect server settings.

Fixed Grunt connect server settings.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -33,8 +33,8 @@
     connect:
       server:
         options:
-          port: 5000
-          hostname: 'localhost'
+          port: 8764 # phone keypad equivalent of TPMG
+          hostname: '*'
           base: 'build'
           livereload: true


Edit browsersync, only open google chrome

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -536,9 +536,7 @@
         # online: true
         open: true
         browser: [
-          "safari"
           "google chrome"
-          "firefox"
         ]
         notify: true


use testem

use testem

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,5 +1,6 @@
 module.exports = (grunt) ->
   grunt.initConfig
+    pkg: grunt.file.readJSON 'package.json'
     uglify:
       release:
         src: [
@@ -27,20 +28,66 @@

     concat:
       release:
+        options:
+          banner: """
+            /*!
+             * jsziptools.js <%= pkg.version %> - MIT License. https://github.com/ukyo/jsziptools/LICENSE
+             * ES6-Promises - MIT License. https://github.com/jakearchibald/ES6-Promises/blob/master/LICENSE
+             */
+            ;(function(){
+          """
+          footer: '}).call(this);'
         src: [
-          'src/header.js'
           'vendor/ES6-Promises/dist/promise-0.1.1.min.js'
           'vendor/zlib-asm/zlib.js'
           '_jsziptools.js'
-          'src/footer.js'
         ]
         dest: 'jsziptools.js'

     clean:
       release: '_jsziptools.js'

+    testem:
+      options:
+        launch_in_dev: ['Chrome', 'Firefox']
+      dev:
+        framework: 'buster'
+        src: [
+          'vendor/ES6-Promises/dist/promise-0.1.1.min.js'
+          'vendor/zlib-asm/zlib.js'
+          'src/jsziptools.js'
+          'src/utils.js'
+          'src/algorithms/adler32.js'
+          'src/algorithms/crc32.js'
+          'src/algorithms/deflate.js'
+          'src/algorithms/inflate.js'
+          'src/stream/algorithms/deflate.js'
+          'src/stream/algorithms/inflate.js'
+          'src/stream/zlib.compress.js'
+          'src/stream/zlib.decompress.js'
+          'src/stream/gz.compress.js'
+          'src/stream/gz.decompress.js'
+          'src/stream/zip.pack.js'
+          'src/zlib.compress.js'
+          'src/zlib.decompress.js'
+          'src/gz.compress.js'
+          'src/gz.decompress.js'
+          'src/zip.pack.js'
+          'src/zip.unpack.js'
+          'test/loadWorker.js'
+          'test/test.js'
+        ]
+      release:
+        framework: 'buster'
+        src: [
+          'jsziptools.js'
+          'test/loadWorkerRelease.js'
+          'test/test.js'
+        ]
+
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-contrib-clean'
+  grunt.loadNpmTasks 'grunt-contrib-testem'

-  grunt.registerTask 'release', ['uglify', 'concat', 'clean']+  grunt.registerTask 'release', ['uglify', 'concat', 'clean', 'testem:ci:release']


Fix broken css path in jasmine template

Fix broken css path in jasmine template

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -188,7 +188,7 @@
           )()
           styles: [
             "#{appsdk_path}/test/support/jasmine/rally-jasmine.css"
-            "#{appsdk_path}/workspace/packages/rui/build/resources/rui-all.css"
+            "#{appsdk_path}/builds/rui/resources/css/rui-all.css"
             "#{appsdk_path}/builds/rui/resources/css/rui-fonts.css"
             "#{appsdk_path}/builds/lib/closure/closure-20130117-r2446.css"
             "#{appsdk_path}/builds/rui/resources/css/lib-closure.css"


Update the repo

Update the repo

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -147,7 +147,7 @@
                 message: 'Built from %sourceCommit% on branch %sourceBranch%'
             pages:
                 options:
-                    remote: 'git@github.com:ukmadlz/no-service-nottjs-2016.git'
+                    remote: 'git@github.com:ukmadlz/no-service-brumjs-2016.git'
                     branch: 'gh-pages'


clean up gruntfile

clean up gruntfile

remove unused tasks, configure “build” to do coffee+require and build
on watch.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,4 +1,3 @@
-# Generated on 2013-08-10 using generator-webapp 0.2.6
 "use strict"

 # # Globbing
@@ -15,22 +14,10 @@
     watch:
       coffee:
         files: ["src/{,*/}*.coffee"]
-        tasks: ["coffee:dist", "requirejs"]
+        tasks: ["build"]

     clean:
       dist: ".tmp"
-
-    jshint:
-      options:
-        jshintrc: ".jshintrc"
-
-      all: ["Gruntfile.js", "<%= yeoman.app %>/scripts/{,*/}*.js", "!<%= yeoman.app %>/scripts/vendor/*", "test/spec/{,*/}*.js"]
-
-    mocha:
-      all:
-        options:
-          run: true
-          urls: ["http://localhost:<%= connect.options.port %>/index.html"]

     coffee:
       dist:
@@ -51,11 +38,6 @@
           ext: ".js"
         ]

-    # not used since Uglify task does concat,
-    # but still available if needed
-    #concat: {
-    #            dist: {}
-    #        },
     requirejs:
       dist:

@@ -63,10 +45,10 @@
         options:
           name: 'ivories'
           out: 'ivories.js'
-          # `name` and `out` is set by grunt-usemin
+          optimize: "none"
+
           # because of coffee-script, we'll have requirejs compile from .tmp folder
           baseUrl: ".tmp"
-          optimize: "none"

           # paths for our own files (not bower_components)
           # paths:
@@ -79,32 +61,11 @@
           useStrict: true
           wrap: true

-    # Put files not handled in other tasks here
-    copy:
-      dist:
-        files: [
-          expand: true
-          dot: true
-          cwd: "<%= yeoman.app %>"
-          dest: "<%= yeoman.dist %>"
-          src: ["*.{ico,png,txt}", ".htaccess", "images/{,*/}*.{webp,gif}", "styles/fonts/*"]
-        ,
-          expand: true
-          cwd: ".tmp/images"
-          dest: "<%= yeoman.dist %>/images"
-          src: ["generated/*"]
-        ]
-
-
-      # copy scripts/lib folder to .tmp for requirejs
-      lib:
-        files: [
-          expand: true
-          dot: true
-          cwd: "<%= yeoman.app %>"
-          dest: ".tmp"
-          src: ["scripts/{vendor,lib}/*.*"]
-        ]
+    mocha:
+      all:
+        options:
+          run: true
+          urls: ["http://localhost:<%= connect.options.port %>/index.html"]

     bower:
       options:
@@ -113,17 +74,5 @@
       all:
         rjsConfig: "<%= yeoman.app %>/scripts/main.js"

-
-    # symlink bower_components folder into .tmp for requirejs
-    symlink:
-      js:
-        dest: ".tmp/bower_components"
-        relativeSrc: "../<%= yeoman.app %>/bower_components"
-        options:
-          type: "dir"
-
-  # grunt.registerTask "server", (target oncurrent:server", "connect:livereload", "open", "watch"]
-
-  grunt.registerTask "test", ["clean:server", "concurrent:test", "connect:test", "mocha"]
   grunt.registerTask "build", ["clean:dist", "coffee:dist", "requirejs"]
-  # grunt.registerTask "default", ["jshint", "test", "build"]
+  grunt.registerTask "test", ["build", "mocha"]


Changed order of grunt task load.

Changed order of grunt task load.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -43,9 +43,9 @@

     # Plug-ins
     grunt.loadNpmTasks 'grunt-contrib-coffee'
+    grunt.loadNpmTasks 'grunt-contrib-jasmine'
     grunt.loadNpmTasks 'grunt-contrib-uglify'
     grunt.loadNpmTasks 'grunt-contrib-watch'
-    grunt.loadNpmTasks 'grunt-contrib-jasmine'

     # Tasks
     grunt.registerTask 'build', [


get livereload to not refresh for css

get livereload to not refresh for css

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -11,8 +11,13 @@
       options:
         livereload: true
       sass:
+        options:
+          livereload: false
         files: 'bikeme/apps/core/static/sass/*.s?ss'
         tasks: ["sass", ]
+      css:
+        files: 'bikeme/apps/core/static/css/*.css'
+        tasks: []

   grunt.loadNpmTasks 'grunt-contrib-sass'
   grunt.loadNpmTasks 'grunt-contrib-watch'


feat(Gruntfile): Output the custombuild directory post-build

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -33,7 +33,7 @@
     'docs': './docs'
     'test': './test'
     'custom': './_custom'
-  grunt.config.set('customBuildDest', path.join paths.custom, uuid.v1(1))
+  customBuildDest = path.join paths.custom, uuid.v1(1)

   # Browsers
   # ==========
@@ -49,6 +49,8 @@
   grunt.initConfig

     pkg: pkg
+
+    #grunt.config.set('c ustomBuildDest', path.join paths.custom, uuid.v1(1))

     bower:
       install:
@@ -129,7 +131,7 @@
         ]
       custom:
         options:
-          archive: "#{grunt.config.get('customBuildDest')}/<%= pkg.name %>-<%= pkg.version %>.zip"
+          archive: "#{customBuildDest}/<%= pkg.name %>-<%= pkg.version %>.zip"
         files: [
           {
             expand: true
@@ -407,8 +409,8 @@
           dest: "#{paths.build}/<%= pkg.name %>.min.css"
       custom:
         files:
-          src: ["#{grunt.config.get('customBuildDest')}/*.css"]
-          dest: "#{grunt.config.get('customBuildDest')}/<%= pkg.name %>.min.css"
+          src: ["#{customBuildDest}/*.css"]
+          dest: "#{customBuildDest}/<%= pkg.name %>.min.css"

     jshint:
       source: ["#{paths.src}/js/*.js"]
@@ -427,7 +429,8 @@

     custombuild:
       options:
-        dest: grunt.config.get('customBuildDest')
+        dest: customBuildDest
+        #dest: customBuildDest

     uglify:
       options:
@@ -451,8 +454,8 @@
         src: ['<%= concat.all.dest %>']
         dest: "#{paths.build}/all.<%= pkg.name %>.min.js"
       custom:
-        src: ["#{grunt.config.get('customBuildDest')}/*.js"]
-        dest: "#{grunt.config.get('customBuildDest')}/<%= pkg.name %>-<%= pkg.version %>.min.js"
+        src: ["#{customBuildDest}/*.js"]
+        dest: "#{customBuildDest}/<%= pkg.name %>-<%= pkg.version %>.min.js"

     usebanner:
       allhead:
@@ -601,6 +604,11 @@

   grunt.loadTasks './lib/grunt'

+  grunt.registerTask 'build_details', ->
+    grunt.log.writeln "\n##########\nCustom Build Generated: "
+    grunt.log.write customBuildDest
+    grunt.log.writeln "\n##########\n"
+
   # Tasks
   # ==========
   grunt.registerTask 'test:unit', 'Run unit tests locally with Karma', ['dev', 'tests:local']
@@ -612,6 +620,6 @@

   grunt.registerTask 'dev', 'Prepare code for testing', ['clean', 'shell:npm_install', 'bower', 'package', 'copy:test']
   grunt.registerTask 'build', 'Build from latest source', ['concat', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
-  grunt.registerTask 'build:custom', 'Build a custom version', ['custombuild', 'uglify:custom', 'cssmin:custom', 'usebanner:customhead', 'usebanner:customfoot', 'compress:custom']
+  grunt.registerTask 'build:custom', 'Build a custom version', ['custombuild', 'uglify:custom', 'cssmin:custom', 'usebanner:customhead', 'usebanner:customfoot', 'compress:custom', 'build_details']
   grunt.registerTask 'package', 'Build a zipped distribution-worthy version', ['build', 'copy:dist', 'compress']
   grunt.registerTask 'default', 'Default task: clean, bower, lint, build, & test', ['package']


Watch source files for changes and run the specs

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -119,6 +119,7 @@
         tasks: [
           'create_env_settings'
           'build_dist'
+          'karma:unit:run'
         ]

     coffee:


wip-fix baseurl int

wip-fix baseurl int

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -12,7 +12,20 @@
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   grunt.loadNpmTasks 'grunt-contrib-cssmin'
   grunt.loadNpmTasks 'grunt-exec'
+
+  target = grunt.option 'target'
+  if !target?
+    target = '<%= baseurl.local %>'
+
+  # TODO
+  # grunt.config.set ['baseurl.target', target] for target in '<%= baseurl %>'
+
   grunt.initConfig
+    baseurl: [
+      local: '"\'\'"'
+      ghpages: '/open-source-club-website'
+      target: target
+    ]

     csslint: test:
       options: import: 2
@@ -155,11 +168,10 @@
       bundler: cmd: 'bundle install --quiet'
       bower: cmd: 'bower install --quiet'
       purge: cmd: 'rm -rf _site/*'
-      lo_baseurl: cmd: 'bash _helpers/set-baseurl.sh "\'\'"'
-      gh_baseurl: cmd: 'bash _helpers/set-baseurl.sh /open-source-club-website'
       jekyll: cmd: 'bundle exec jekyll build --quiet'
       new_post: cmd: 'bash _helpers/new-post.sh'
       status: cmd: "clear && echo the site is now accessible at http://localhost:<%= connect.server.options.port %>"
+      baseurl: cmd: 'bash _helpers/set-baseurl.sh' + ' ' + "<%= baseurl.target || baseurl.local %>"

     watch:
       options: livereload: true
@@ -199,6 +211,7 @@
       base: '_site'
       livereload: false
   grunt.registerTask 'build', [
+    'exec:baseurl'
     'exec:bundler'
     'exec:bower'
     'jade'
@@ -210,7 +223,6 @@
     'cssmin'
   ]
   grunt.registerTask 'serve', [
-    'exec:lo_baseurl'
     'build'
     'connect:server'
     'exec:status'


Delete .sync-config.cson

Delete .sync-config.cson

--- .sync-config.cson
+++ .sync-config.cson
@@ -1,19 +0,0 @@
-remote:
-  host: "sakura13"
-  user: "shunta"
-  path: "/mnt/sakura201/mitmul/codes/chainer"
-behaviour:
-  uploadOnSave: true
-  syncDownOnOpen: false
-  forgetConsole: false
-  autoHideConsole: true
-  alwaysSyncAll: false
-option:
-  deleteFiles: false
-  exclude: [
-    ".sync-config.cson"
-    ".git"
-    "node_modules"
-    "tmp"
-    "vendor"
-  ]


now not pop word out of old array, just ref

--- src/kick.coffee
+++ src/kick.coffee
@@ -1,6 +1,5 @@
 Array::pop = (index=@length-1) -> @splice(index, 1)[0]
 Array::random = -> @[Math.floor(@length * Math.random())]
-Array::remove = (item) -> @pop(index) if (index = @indexOf(item)) > -1

 stage_height = 300
 stage_width = 1000
@@ -57,12 +56,12 @@
         @name = null

     add: (word) ->
-        if word == @name?.full
+        if word.full == @name?.full
             if @words.length >= player.longest.length
                 player.longest = @words
             @words = []
-        else if word in @words
-            @words.remove(word)
+        else if (index = @index(word))?
+            @words.pop(index)
         else
             @words.push(word)
         if not @words.length
@@ -70,9 +69,15 @@
         else
             @name = new ShootingWord('@neizod')

+    index: (find) ->
+        for word, i in @words
+            if word.full == find.full
+                return i
+
     show: ->
-        follow = if @name? then ' ' + @name.show.html() else ''
-        (word for word in @words).join(' ') + follow
+        sentence = @words.concat(if @name? then [@name] else [])
+        (word.show.html() for word in sentence).join(' ')
+

 class ShootingWord
@@ -92,8 +97,9 @@
     done: ->
         @full.slice(0, @full.length - @remain.length)

-    shot: ->
-        @remain = @remain.slice(1)
+    shot: (c) ->
+        if c == @remain[0]
+            @remain = @remain.slice(1)

     move: ->
         @left -= 1 # TODO render smoother w/ word movement speed
@@ -115,9 +121,7 @@
     $('#point').html(player.point)
     $('#keep').html(inventory.show())
     $('#playground').empty()
-    if player.word?
-        if player.word.full == inventory.name?.full
-            player.word.update()
+    player.word?.update()
     pool_words.move()
     player.die = true if pool_words.attack()
     pool_words.draw()
@@ -134,7 +138,7 @@
     if event.keyCode in [8, 27, 46] # backspace, escape, delete
         if player.word?
             player.word.reset()
-            pool_words.add(player.word.full)
+            player.word.update()
             player.word = null

 $(document).keypress (event) ->
@@ -144,12 +148,13 @@
     if not player.word? and inventory.name?
         if c == inventory.name.remain[0]
             player.word = inventory.name
-    if c == player.word?.remain[0]
-        player.word.shot()
+    player.word?.shot(c)
     if player.word?.remain == ''
         player.point += player.word.full.length
-        inventory.add(player.word.full)
+        inventory.add(player.word)
         pool_words.update()
+        player.word.reset()
+        player.word.update()
         player.word = null
         player.lvl += 1
         pool_words.autofill(player.lvl)


list.change should skip trying to add key props to items without any changes

--- src/list.coffee
+++ src/list.coffee
@@ -99,7 +99,7 @@
   @property 'change',
     get: -> Array.from(@state.changes.keys()).map (i) ->
       obj = i.change
-      obj[k] = i.get(k) for k in i.keys
+      obj[k] = i.get(k) for k in i.keys if obj?
       obj

   @property 'children',


cleanup

cleanup


better handling when target file is active

--- lib/debugger/stepper.coffee
+++ lib/debugger/stepper.coffee
@@ -28,17 +28,24 @@
     atom.workspace.getTextEditors()
       .filter((x)->x.getPath() is file)

+  activate: (file, line) ->
+    active = atom.workspace.getActiveTextEditor()
+    if active.getPath() is file
+      active.setCursorBufferPosition [line, 0]
+      Promise.resolve()
+    else
+      atom.workspace.open file,
+        initialLine: line
+        searchAllPanes: true
+        pending: true
+
   goto: (file, @line) ->
-    opts =
-      initialLine: @line
-      searchAllPanes: true
-      pending: true
-    atom.workspace.open(file, opts).then =>
+    @activate(file, @line).then =>
       if file == @file
         view.goto @line for view in @views
       else
+        @file = file
         @detach()
-        @file = file
         @attach(ed) for ed in @edsForFile file

   detach: ->


test #1

test #1

--- lib/directory-upload.coffee
+++ lib/directory-upload.coffee
@@ -83,6 +83,7 @@
       #   data: content
       #   filename: file.name
       #   type: file.type
+      console.log content
       eventbus.fire 'MySQL', 'insertFile', {} =
         appName: file.type
         url: 'none'


:lipstick: and :memo: for pending state

:lipstick: and :memo: for pending state

--- src/pane.coffee
+++ src/pane.coffee
@@ -8,6 +8,11 @@
 # Panes can contain multiple items, one of which is *active* at a given time.
 # The view corresponding to the active item is displayed in the interface. In
 # the default configuration, tabs are also displayed for each item.
+#
+# Each pane may also contain one *pending* item. When a pending item is added
+# to a pane, it will replace the currently pending item, if any, instead of
+# simply being added. In the default configuration, the text in the tab for
+# pending items is shown in italics.
 module.exports =
 class Pane extends Model
   container: undefined
@@ -380,19 +385,47 @@
     @setActiveItem(item) unless @getActiveItem()?
     item

+  clearPendingItem: =>
+    @setPendingItem(null)
+
   setPendingItem: (item) =>
+    # TODO: figure out events for changing/clearing pending item
     @pendingItem = item
+    @emitter.emit 'did-change-pending-item', @pendingItem
     @emitter.emit 'did-terminate-pending-state' if not item

+  # Public: Get the pending pane item in this pane, if any.
+  #
+  # Returns a pane item or `null`.
   getPendingItem: =>
-    @pendingItem
+    @pendingItem or null

   isItemPending: (item) =>
     @pendingItem is item

+  # Invoke the given callback when the value of {::getPendingItem} changes.
+  #
+  # * `callback` {Function} to be called with when the pending item changes.
+  #   * `pendingItem` The current pending item, or `null`.
+  #
+  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
+  onDidChangePendingItem: (callback) =>
+    @emitter.on 'did-change-pending-item', callback
+
+  # Public: Invoke the given callback with the current and future values of
+  # {::getPendingItem}.
+  #
+  # * `callback` {Function} to be called with the current and future pending
+  #   items.
+  #   * `pendingItem` The current pending item.
+  #
+  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
+  observePendingItem: (callback) ->
+    callback(@getPendingItem())
+    @onDidChangePendingItem(callback)
+
   onDidTerminatePendingState: (callback) =>
-    @emitter.on 'did-terminate-pending-state', ->
-      callback()
+    @emitter.on 'did-terminate-pending-state', callback

   # Public: Add the given items to the pane.
   #


get the id from the user object

get the id from the user object

--- src/poll.coffee
+++ src/poll.coffee
@@ -55,7 +55,7 @@

 	robot.respond /vote\s+(\d)/i, (msg) ->
 		vote = msg.match[1]
-		user = msg.envelope.user
+		user = msg.envelope.user.id
 		@robot.logger.info "Adding a vote for #{vote} for #{user}"
 		#check if the user already voted
 		for option in @robot.brain.data.poll.options


fix dataset integration test

fix dataset integration test


Define im

Define im

--- src/pull.coffee
+++ src/pull.coffee
@@ -6,6 +6,7 @@
 exports.pullImages = (file) ->
   # body...
   @images = parse.parse('config/images.yml')
+  im = 0
   while im < images.images.length
     exec('docker pull '+images.images[im])
     im++


Remove debug statement and reorder updating of elements

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -82,8 +82,6 @@
             @updateDataset(dataset.id)

         @updateDataset = (dataset) =>
-            console.log "Updating dataset #{dataset}"
-
             el = @root.select("g.datasets #dataset-#{dataset}")
             d = @data[dataset]

@@ -212,18 +210,13 @@

         # zooming
         zoom = =>
-            console.log "Scale #{d3.event.scale}, Translate #{d3.event.translate}"
-
-            # update axis & grids
-
+            # repaint the scales and the axis
+            d3.select(@element).select('g.axis').call(@axis.x)
+            d3.select(@element).select('g.brush').call(@brush)

             # repaint the datasets
             for dataset of @data
                 @updateDataset(dataset)
-
-            # repaint the scales and the axis
-            d3.select(@element).select('g.axis').call(@axis.x)
-            d3.select(@element).select('g.brush').call(@brush)

         @root.call(d3.behavior.zoom().x(@scales.x).on('zoom', zoom))


atom stuff

atom stuff

--- .atom/config.cson
+++ .atom/config.cson
@@ -1,6 +1,10 @@
 "*":
   "advanced-open-file":
     createDirectories: true
+  "atom-beautify":
+    python:
+      beautify_on_save: true
+      sort_imports: true
   "autocomplete-plus":
     backspaceTriggersAutocomplete: true
     confirmCompletion: "tab always, enter when suggestion explicitly selected"
@@ -29,11 +33,15 @@
       "snippets"
       "tabs"
     ]
+    packagesWithKeymapsDisabled: [
+      "atom-beautify"
+    ]
     telemetryConsent: "no"
   editor:
     fontFamily: "inconsolata"
     fontSize: 21
-    invisibles: {}
+    invisibles:
+      eol: false
     showInvisibles: true
     softWrap: true
   "exception-reporting":
@@ -74,6 +82,8 @@
   editor:
     tabLength: 8
 ".python.source":
+  editor:
+    showIndentGuide: true
   whitespace:
     removeTrailingWhitespace: true
 ".tex.text":


[atom] change keybinding for sidebar

[atom] change keybinding for sidebar

--- .atom/keymap.cson
+++ .atom/keymap.cson
@@ -4,7 +4,10 @@
   'alt-cmd-p': 'unset!'
 '.platform-darwin':
   'alt-cmd-p': 'project-plus:toggle-project-finder'
+  'cmd-0': 'tree-view:toggle'
+'body':
+  'cmd-0': 'unset!'
 'atom-text-editor[data-grammar="text html mustache"]:not([mini])':
-    'tab': 'emmet:expand-abbreviation-with-tab'
+  'tab': 'emmet:expand-abbreviation-with-tab'
 'atom-text-editor[data-grammar="source handlebars"]:not([mini])':
-    'tab': 'emmet:expand-abbreviation-with-tab'
+  'tab': 'emmet:expand-abbreviation-with-tab'


Add Chinese translation for teachers

Add Chinese translation for teachers

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -1233,78 +1233,85 @@
 #    class_name: "Class Name"
 #    teacher_account_restricted: "Your account is a teacher account, and so cannot access student content."

-#  teacher:
-#    teacher_dashboard: "Teacher Dashboard" # Navbar
-#    my_classes: "My Classes"
-#    courses: "Courses"
-#    enrollments: "Enrollments"
-#    resources: "Resources"
-#    help: "Help"
-#    students: "Students" # Shared
-#    language: "Language"
-#    edit_class_settings: "edit class settings"
-#    complete: "Complete"
-#    access_restricted: "Access Restricted" # My Classes page
-#    teacher_account_required: "A teacher account is required to access this content."
-#    create_teacher_account: "Create Teacher Account"
-#    what_is_a_teacher_account: "What's a Teacher Account?"
-#    teacher_account_explanation: "A CodeCombat Teacher account allows you to set up classrooms, monitor students’ progress as they work through courses, manage enrollments and access resources to aid in your curriculum-building."
-#    current_classes: "Current Classes"
-#    archived_classes: "Archived Classes"
-#    archived_classes_blurb: "Classes can be archived for future reference. Unarchive a class to view it in the Current Classes list again."
-#    view_class: "view class"
-#    archive_class: "archive class"
-#    unarchive_class: "unarchive class"
-#    no_students_yet: "This class has no students yet."
-#    add_students: "Add Students"
-#    create_new_class: "Create a New Class"
-#    class_overview: "Class Overview" # View Class page
-#    avg_playtime: "Average level playtime"
-#    total_playtime: "Total play time"
-#    avg_completed: "Average levels completed"
-#    total_completed: "Total levels completed"
-#    concepts_covered: "Concepts covered"
-#    earliest_incomplete: "Earliest incomplete level"
-#    latest_complete: "Latest completed level"
-#    enroll_student: "Enroll student"
-#    adding_students: "Adding students"
-#    course_progress: "Course Progress"
-#    not_applicable: "N/A"
-#    edit: "edit"
-#    remove: "remove"
-#    latest_completed: "Latest Completed"
-#    sort_by: "Sort by"
-#    progress: "Progress"
-#    select_course: "Select course to view"
-#    course_overview: "Course Overview"
-#    copy_class_code: "Copy Class Code"
-#    class_code_blurb: "New students can enter this class code on their dashboard or visit codecombat.com/courses to join the class."
-#    copy_class_url: "Copy Class URL"
-#    class_join_url_blurb: "New students can visit this URL while logged in to join the class."
-#    add_students_manually: "Add Students Manually"
-#    bulk_assign: "Bulk-assign"
-#    assign_to_selected_students: "Assign to Selected Students"
-#    assigned: "Assigned"
-#    enroll_selected_students: "Enroll Selected Students"
-#    guides_coming_soon: "Guides coming soon!" # Courses
-#    show_students_from: "Show students from" # Enroll students modal
-#    enroll_the_following_students: "Enroll the following students"
-#    all_students: "All Students"
-#    enrollments_blurb_1: "Students taking Computer Science" # Enrollments page
-#    enrollments_blurb_2: "require enrollments to access the courses."
-#    credits_available: "Credits Available"
-#    total_unique_students: "Total Unique Students"
-#    total_enrolled_students: "Total Enrolled Students"
-#    unenrolled_students: "Unenrolled Students"
-#    add_enrollment_credits: "Add Enrollment Credits"
-#    purchasing: "Purchasing..."
-#    purchased: "Purchased!"
-#    purchase_now: "Purchase Now"
-#    how_to_enroll: "How to Enroll Students"
-#    how_to_enroll_blurb_1: "If a student is not enrolled yet, there will be an \"Enroll\" button next to their course progress in your class."
-#    how_to_enroll_blurb_2: "To bulk-enroll multiple students, select them using the checkboxes on the left side of the classroom page and click the \"Enroll Selected Students\" button."
-#    how_to_enroll_blurb_3: "Once a student is enrolled, they will have access to all of the course content." # {change}
-#    bulk_pricing_blurb: "Purchasing for more than 15 students? Get in touch with us for bulk pricing quotes."
+  teacher:
+    teacher_dashboard: "老师面板" # Navbar
+    my_classes: "我的教室"
+    courses: "课程"
+    enrollments: "注册名额"
+    resources: "资源"
+    help: "帮助"
+
+    students: "学生" # Shared
+    language: "编程语言"
+    edit_class_settings: "修改教室设置"
+    complete: "已达成"
+
+    access_restricted: "访问受限" # My Classes page
+    teacher_account_required: "只有教师账号才能访问。"
+    create_teacher_account: "创建教师账号"
+    what_is_a_teacher_account: "什么是教师账号？"
+    teacher_account_explanation: "教师账号可以创建教师、跟踪学生学习进展、管理注册名额，并且可以查看相应的帮助文档以辅助构建课堂。"
+    current_classes: "当前课堂"
+    archived_classes: "已归档的课堂"
+    archived_classes_blurb: "您可以把课堂归档，便于后续查阅。课程可以解档课程，并在当前课程列表中再次查看。"
+    view_class: "查看课堂"
+    archive_class: "归档课堂"
+    unarchive_class: "解档课堂"
+    no_students_yet: "该课堂尚未有学生加入。"
+    add_students: "添加学生"
+    create_new_class: "创建新课堂"
+
+    class_overview: "课堂概览" # View Class page
+    avg_playtime: "单关平均通关时间"
+    total_playtime: "总时长"
+    avg_completed: "平均完成关卡数"
+    total_completed: "完成总关卡数"
+    concepts_covered: "覆盖语法概念"
+    earliest_incomplete: "最近未完成关卡"
+    latest_complete: "最近通关关卡"
+    enroll_student: "注册学生"
+    adding_students: "正在添加学生"
+    course_progress: "课程进度"
+    not_applicable: "N/A"
+    edit: "修改"
+    remove: "移除"
+    latest_completed: "最近通关"
+    sort_by: "排列依据"
+    progress: "进度"
+    select_course: "选择查看"
+    course_overview: "课程概览"
+    copy_class_code: "复制课堂编码"
+    class_code_blurb: "未加入的学生可以在自己的功能页面输入该课堂编码，或者访问网址加入课堂。"
+    copy_class_url: "复制课堂链接地址"
+    class_join_url_blurb: "新学生可以在登录之后，访问该网址加入课堂。"
+    add_students_manually: "手工添加学生"
+    bulk_assign: "批量添加"
+    assign_to_selected_students: "添加课堂到选中的学生"
+    assigned: "已添加"
+    enroll_selected_students: "注册选中的学生"
+
+    guides_coming_soon: "参考指导很快会推出！" # Courses
+
+    show_students_from: "展示这些学生" # Enroll students modal
+    enroll_the_following_students: "注册下列学生"
+    all_students: "所有学生"
+
+    enrollments_blurb_1: "计算机科学学习的学生段位" # Enrollments page
+    enrollments_blurb_2: "需要注册名额来加入课程。"
+    credits_available: "可用额度"
+    total_unique_students: "参与的总学生人数"
+    total_enrolled_students: "总注册人次"
+    unenrolled_students: "取消注册学生"
+    add_enrollment_credits: "购买注册名额"
+    purchasing: "正在购买……"
+    purchased: "购买成功！"
+    purchase_now: "现在买"
+    how_to_enroll: "如何注册学生？"
+    how_to_enroll_blurb_1: "如果学生尚未注册，在他们加入你的课堂之后，课程进度后面有一个『注册』按钮。"
+    how_to_enroll_blurb_2: "如果要批量注册多名学生，在教室页面中勾选学生，然后点击『注册选中的学生』按钮。"
+    how_to_enroll_blurb_3: "当学生被注册之后，他们就能访问所有的课程关卡了。" # {change}
+    bulk_pricing_blurb: "如果需要购买超过15学生名额，请联系我们获取批量采购折扣！"
+

   classes:
     archmage_title: "大法师"