Working on zipping release directory with gulp

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -152,7 +152,6 @@

 gulp.task 'release:uglify', ['compile:sources', 'release:clean'],  ->
   gulp.src 'build/src/**/*.js'
-    .pipe uglify(mangle: off)
     .pipe gulp.dest 'release/src/'

 gulp.task 'release:minify', ['compile:assets', 'release:clean'],  ->
@@ -163,6 +162,10 @@
 gulp.task 'release:images', ['compile:assets', 'release:clean'], ->
   gulp.src 'build/assets/images/**/*'
     .pipe gulp.dest 'release/assets/images'
+
+gulp.task 'release:fonts', ['compile:assets', 'release:clean'], ->
+  gulp.src 'build/assets/fonts/**/*'
+  .pipe gulp.dest 'release/assets/fonts'

 gulp.task 'release:json', ['compile:assets', 'release:clean'], ->
   gulp.src 'build/**/*.json'
@@ -206,7 +209,7 @@
 gulp.task 'debug', ['compile:assets', 'compile:sources'], ->
   completeBuildTask 'build', DEBUG_MODE

-gulp.task 'release', ['release:clean', 'release:uglify', 'release:minify', 'release:json', 'release:libs', 'release:images', 'release:views', 'release:public', 'release:manifest', 'compile'],  ->
+gulp.task 'release', ['release:clean', 'release:uglify', 'release:minify', 'release:json', 'release:libs', 'release:images', 'release:views', 'release:public', 'release:manifest', 'release:fonts', 'compile'],  ->
   completeBuildTask 'release', RELEASE_MODE

 gulp.task 'package', ['release'], ->


(- fix Win) Preliminary handling of Windows carriage-returns

--- Paws/Source/parser.coffee
+++ Paws/Source/parser.coffee
@@ -20,7 +20,7 @@

 # A simple recursive descent parser with no backtracking. No lexing is needed here.
 class Parser
-   labelCharacters = /[^(){} \n]/ # Not currently supporting quote-delimited labels
+   labelCharacters = /[^(){} \r\n]/ # Not currently supporting quote-delimited labels

    constructor: (@text, opts = {})->
       # Keep track of the current position into the text
@@ -40,7 +40,7 @@

    # Swallow all whitespace
    whitespace: ->
-      true while @accept(' ') || @accept('\n')
+      true while @accept(' ') || @accept('\r') || @accept('\n')
       true

    # Sets a SourceRange on a expression


Grunt: watch -qunit

Grunt: watch -qunit

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -63,13 +63,6 @@
                 ]
                 tasks: 'newer:jscs:all'

-            qunit:
-                files: [
-                    'static/test/**/*.js',
-                    'static/test/**/*.html',
-                ]
-                tasks: 'qunit:all'
-
     grunt.registerTask 'lint', ['jshint', 'jscs']
     grunt.registerTask 'test', ['qunit']
     grunt.registerTask 'default', ['lint', 'watch']


feat(grunt): add missing templates when update AMSF

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -280,7 +280,6 @@
           {
             expand: true
             dot: true
-            filter: "isFile"
             cwd: "<%= config.amsf_core %>/"
             src: [
               ".*"
@@ -295,6 +294,16 @@
               "!TODOS.md"
             ]
             dest: "./"
+          }
+          {
+            expand: true
+            dot: true
+            cwd: "<%= config.amsf_core %>/_app/"
+            src: [
+              "*.xml"
+              "*.txt"
+            ]
+            dest: "<%= config.app %>/"
           }
           {
             expand: true


Switched to shell command for compiling coffee files

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,27 +1,8 @@
 module.exports = (grunt) ->
-
-  coffeeFiles = {}
-  [
-    "browser"
-    "cli"
-    "compiler"
-    "demo"
-    "gistquire"
-    "grammar_dsl"
-    "haml-jr"
-    "runtime"
-  ].forEach (name) ->
-    destination = "build/#{name}.js"
-    source = "source/#{name}.coffee"
-    coffeeFiles[destination] = source

   # Project configuration.
   grunt.initConfig
     pkg: grunt.file.readJSON('package.json')
-
-    coffee:
-      compile:
-        files: coffeeFiles

     uglify:
       web:
@@ -38,6 +19,8 @@
         stdout: true
         stderr: true
         failOnError: true
+      coffee:
+        command: "./node_modules/.bin/coffee -co build/ source/"
       lexer:
         command: [
           "jison-lex -o build/lexer.js source/haml.jisonlex"
@@ -80,7 +63,6 @@
         ].join(' && ')

   grunt.loadNpmTasks('grunt-browserify')
-  grunt.loadNpmTasks('grunt-contrib-coffee')
   grunt.loadNpmTasks('grunt-contrib-uglify')
   grunt.loadNpmTasks('grunt-shell')

@@ -88,7 +70,7 @@
   grunt.registerTask 'build', [
     'shell:lexer'
     'shell:parser'
-    'coffee'
+    'shell:coffee'
     'browserify'
     'uglify'
     'shell:demo'


fix(grunt): reset repo before updating

fix(grunt): reset repo before updating

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -419,6 +419,30 @@
       amsf__theme__update_remote:
         options:
           cwd: "<%= config.amsf_base %>/themes/<%= config.amsf_theme %>/"
+
+    gitclean:
+      options:
+        nonstandard: true
+
+      amsf__core__clean_git:
+        options:
+          cwd: "<%= gitpull.amsf__core__update_remote.options.cwd %>"
+
+      amsf__theme__clean_git:
+        options:
+          cwd: "<%= gitpull.amsf__theme__update_remote.options.cwd %>"
+
+    gitreset:
+      options:
+        mode: "hard"
+
+      amsf__core__reset_git:
+        options:
+          cwd: "<%= gitpull.amsf__core__update_remote.options.cwd %>"
+
+      amsf__theme__reset_git:
+        options:
+          cwd: "<%= gitpull.amsf__theme__update_remote.options.cwd %>"

     clean:
       default:
@@ -540,11 +564,15 @@
   ]

   grunt.registerTask "theme-update", "Update current theme from GitHub", [
+    "gitreset:amsf__theme__reset_git"
+    "gitclean:amsf__theme__clean_git"
     "gitpull:amsf__theme__update_remote"
     "theme-upgrade"
   ]

   grunt.registerTask "amsf-update", "Upgrade AM", [
+    "gitreset:amsf__core__reset_git"
+    "gitclean:amsf__core__clean_git"
     "gitpull:amsf__core__update_remote"
     "copy:amsf__core__to_app"
   ]


Coffeelint first

Coffeelint first

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -180,7 +180,7 @@

   @registerTask 'build-fast', ['coffee', 'exec:component_build','concat:worker']
   @registerTask 'build', ['coffee', 'exec', 'concat:worker', 'uglify:worker', 'uglify:engine', 'usebanner']
-  @registerTask 'test', ['build', 'coffeelint', 'phantom']
+  @registerTask 'test', ['coffeelint', 'build', 'phantom']
   @registerTask 'phantom', ['connect', 'mocha_phantomjs']
   @registerTask 'crossbrowser', ['build', 'coffeelint', 'connect', 'mocha_phantomjs', 'saucelabs-mocha']
   @registerTask 'default', ['build']


Add Grunt Fatal Error on Fail

Add Grunt Fatal Error on Fail

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -25,9 +25,13 @@
       tasks: ['sass', 'bootcamp']

   grunt.registerTask 'bootcamp', 'Log Bootcamp Results.', ->
-    contents = fs.readFileSync './test/results.css', 'utf8'
-    trim = (str) -> str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
-    grunt.log.writeln trim contents.match( /\/\* START TEST RUNNER \*\/((.|\n)*)\/\* END TEST RUNNER \*\// )[1]
+    trim = (str) -> str.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
+    contents = trim fs.readFileSync('./test/results.css', 'utf8').match( /\/\* START TEST RUNNER \*\/((.|\n)*)\/\* END TEST RUNNER \*\// )[1]
+
+    grunt.log.writeln contents
+
+    if (contents.indexOf('FAILED') > -1 )
+      grunt.fatal 'Bootcamp Tests Failed'

   # Tasks
   grunt.registerTask 'default', ['sass', 'bootcamp', 'watch']


make browser test failures fatal

make browser test failures fatal

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -52,6 +52,7 @@
         options:
           output: 'spec/result.xml'
           reporter: 'spec'
+          failWithOutput: true
           urls: ['spec/runner.html']

   # Grunt plugins used for testing


Remove wrapper IIFEs

Remove wrapper IIFEs

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -32,6 +32,8 @@
         ]
     coffee:
       compile:
+        options:
+          bare: true
         files: [
           expand: true
           cwd: './src/'


chore($Gruntfile): Remove unused grunt-shell commands

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -76,12 +76,6 @@
             travis: 'karma-travis.conf.coffee'

         shell:
-            start_saucecon:
-                command: './lib/sauce/sauce_connect_setup.sh'
-            kill_saucecon:
-                command: 'cat /tmp/sauce-connect.pid | xargs kill'
-            npm_install:
-                command: 'npm install'
             version_custom_templates:
                 command: "find #{customBuildDest}/ -type f -name '*.html' | xargs sed -i '' 's/{VERSION}/<%= pkg.version %>/'"
                 options:


Fixed easyXDM compilation, it now uses the easyXDM located in libs/ folder

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -111,8 +111,8 @@
           'dist/server/factlink.start_highlighting.min.js': ['<banner>', 'dist/factlink.start_highlighting.js']
           'dist/server/factlink.stop_highlighting.min.js':  ['<banner>', 'dist/factlink.stop_highlighting.js']
           'dist/server/factlink.min.js':                    ['<banner>', 'dist/factlink.js']
-          'dist/server/easyXDM/easyXDM.min.js':             ['<banner>', 'dist/easyXDM/easyXDM.js']
-          'dist/easyXDM/easyXDM.min.js':                    ['<banner>', 'dist/easyXDM/easyXDM.js']
+          'dist/server/easyXDM/easyXDM.min.js':             ['<banner>', 'libs/easyXDM.js']
+          'dist/easyXDM/easyXDM.min.js':                    ['<banner>', 'libs/easyXDM.js']

   grunt.registerTask 'default', ['jshint', 'qunit', 'less', 'concat', 'uglify', 'copy']
   grunt.registerTask 'server',  ['concat', 'uglify', 'less', 'copy']


Added a few more steps to build the project and release a new version - Using CoffeeLint before compiling the CoffeeScript to keep the code consistent - Publishing to NPM on the  task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -14,12 +14,25 @@
 				src: ["**/*.coffee"]
 				dest: "lib"
 				ext: ".js"
-
+
+		# CoffeeLint
+		coffeelint:
+			options:
+				no_tabs: level: "ignore"
+				indentation: level: "ignore"
+				max_line_length: level: "ignore"
+
+			source: ["src/**/*.coffee"]
+
 		# Bump files
 		bump:
 			options:
 				pushTo: "origin"

+		# Publish to NPM
+		shell:
+			publish:
+				command: "npm publish"

 		# Watch for changes
 		watch:
@@ -27,4 +40,8 @@
 				files: ["src/**/*.coffee"]
 				tasks: ["coffee"]

-	grunt.registerTask "default", ["coffee"]+
+	grunt.registerTask "default", ["coffeelint", "coffee"]
+	grunt.registerTask "release", "Release a new version, push it and publish", (target) ->
+		target ?= "patch"
+		grunt.task.run "coffeelint", "bump-only:#{target}", "coffee", "bump-commit", "shell:publish"


Remove extraneous removeShallow

Remove extraneous removeShallow

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -132,10 +132,6 @@
               'cs!pages/content/content'
               'cs!pages/search/search'
             ]
-            excludeShallow: [
-              'less/less-builder'
-              'less/lessc'
-            ]
             exclude: ['coffee-script', 'less/normalize']
           }]


Fix release task for new build.

Fix release task for new build.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -100,13 +100,13 @@
         remote: 'git@github.com:chaplinjs/downloads.git'
         branch: 'gh-pages'
         files: [
-          { expand: true, cwd: 'build/', src: '{amd,brunch}/chaplin.{js,min.js}' },
+          { expand: true, cwd: 'build/', src: 'chaplin.{js,min.js}' },
           {
             dest: 'component.json',
             body: {
               name: 'chaplin',
               version: pkg.version,
-              main: 'amd/chaplin.js',
+              main: 'chaplin.js',
               dependencies: { backbone: '>= 1.0.0' }
             }
           }
@@ -501,7 +501,6 @@
     'check:versions',
     'release:git',
     'build',
-    'build:minified',
     'transbrute:docs',
     'transbrute:downloads'
   ]


Add moments.

Add moments.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -45,6 +45,7 @@
           'bower_components/angular-bootstrap/*-tpls.js'
           'bower_components/angular-resource/*.js'
           'bower_components/angular-route/*.js'
+          'bower_components/moment/*.js'
           'bower_components/spin.js/spin.js'
           'bower_components/d3/*.js'
           'bower_components/nvd3/nv.d3.js'


Add clean:release task, do no generate source maps for dist

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -221,6 +221,7 @@
                     dir: 'dist/js'
                     optimize: 'uglify2'
                     removeCombined: true
+                    generateSourceMaps: false

         clean:
@@ -229,6 +230,8 @@
             dist: ['dist']
             postdist: [
                 '<%= distDir %>/js/templates'
+            ]
+            release: [
                 '<%= distDir %>/js/build.txt'
             ]

@@ -412,6 +415,7 @@
     grunt.registerTask 'release', 'Builds the distribution files, creates the release binaries, and creates a Git tag', [
         'bump-final'
         'dist'
+        'clean:release'
         'release-binaries'
         'tag-release'
         'release-help'


got rid of heroku namespace in gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -165,5 +165,5 @@
   grunt.registerTask 'server', ['jshint:server']
   grunt.registerTask 'client', ['jshint:client', 'copy:client', 'concat', 'stylus']
   grunt.registerTask 'client-prod', ['client', 'uglify']
-  grunt.registerTask 'heroku:production', ['client'];
+  grunt.registerTask 'heroku', ['client']
   grunt.registerTask 'default', ['server', 'client', 'concurrent']


Disable ROIs temporarily

Disable ROIs temporarily

--- overrides.coffee
+++ overrides.coffee
@@ -1,5 +1,5 @@
 require './show-project-details'
-require './show-roi'
+# require './show-roi'
 require './auto-choose-penguin-tool'
 require './limit-marks'
 require './show-counts'


Fixed back button

Fixed back button

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -81,7 +81,7 @@
       new_url = history_array.pop()

     sessionStorage.setItem('history', JSON.stringify(history_array))
-    if new_url == undefined
+    if new_url == undefined || new_url == 'undefined'
       window.location.href = new_url
     else
       window.location.href = '/broker/dashboard'


Save on section switch using the sidebar section links

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -273,11 +273,12 @@
   $(document).on "click", ".js-step-link", (e) ->
     e.preventDefault()
     if !$(this).hasClass("step-current")
+      autosave()
+
       current = $(this).attr("data-step")
       if $(this).hasClass "js-next-link"
         if $("body").hasClass("tried-submitting")
           validate()
-        autosave()
       showAwardStep(current)
       # Scroll to top
       $("html, body").animate(


Hound linter comments

Hound linter comments

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -324,18 +324,18 @@
                 "load": "img",
                 "abort": "img"
               }
-    element = element || document.createElement(TAGNAMES[eventName] || 'div')
-    eventName = 'on' + eventName
+    element = element || document.createElement(TAGNAMES[eventName] || "div")
+    eventName = "on" + eventName
     isSupported = eventName in element

     if !isSupported
       if !element.setAttribute
-        element = document.createElement('div')
+        element = document.createElement("div")
       if element.setAttribute && element.removeAttribute
-        element.setAttribute(eventName, '')
-        isSupported = typeof element[eventName] == 'function'
-
-        if typeof element[eventName] != 'undefined'
+        element.setAttribute(eventName, "")
+        isSupported = typeof element[eventName] == "function"
+
+        if typeof element[eventName] != "undefined"
           element[eventName] = undefined
         element.removeAttribute(eventName)


add handleAddedToCartWarning option to glysellinCart jQuery plugin

--- app/assets/javascripts/glysellin/cart.coffee
+++ app/assets/javascripts/glysellin/cart.coffee
@@ -14,14 +14,17 @@
   update: (markup) ->
     $markup = $(markup)
     $cart = $markup.find('.cart-container')
-    $warning = $markup.find('.added-to-cart-warning').remove()
+    $modal = $markup.find('.added-to-cart-warning').remove()

     @container.html($cart.html())

-    if $warning.length > 0
-      $warning.prependTo('body')
-      if ($default_modal = $warning.filter("[data-warning]"))
-        @handleDefaultModal($default_modal)
+    if $modal.length > 0
+      if @options.handleAddedToCartModal
+        @options.handleAddedToCartModal($modal)
+      else
+        $modal.prependTo('body')
+        if ($default_modal = $modal.filter("[data-warning]"))
+          @handleDefaultModal($default_modal)

     @updated()


Added memberSince method to user model in backbone to receive the attribute as a date.

Signed-off-by: Philip Vieira <3ba3974e96044dcde818e6310ed799abe10671d4@vallin.se>

--- app/assets/javascripts/models/user.js.coffee
+++ app/assets/javascripts/models/user.js.coffee
@@ -19,4 +19,7 @@
   removeAvatar: (options) ->
     attr = {}
     attr.remove_avatar = true
-    return @save(attr,options)+    return @save(attr,options)
+
+  memberSince: ->
+    new Date(@get('member_since'))


hex-cut photo to puzzle piece template

hex-cut photo to puzzle piece template

--- views/puzzle.coffee
+++ views/puzzle.coffee
@@ -95,6 +95,10 @@

 class PuzzlePiece
+  # FIXME The context scope issues that are causing so much perplexity might be
+  #       improved by defining image objects and contexts in the PuzzlePiece
+  #       class instead of the PuzzleView class for images that are part of the
+  #       puzzle piece.
   constructor: (puzzle_app) ->

     @puzzle = puzzle_app
@@ -104,7 +108,7 @@

     @box = new PieceRenderBox(this)
     @p_mask  = new PiecePattern(this)
-    @image = new PieceImage(this)
+#    @image = new PieceImage(this)
     @redraw = new PieceRedrawBuffer

@@ -114,6 +118,14 @@
     @hexes = @get_hexes()
     @box.set_box_dimensions()
     @p_mask.draw_pattern()
+    @cut_piece_from_photo()
+
+
+  cut_piece_from_photo: () ->
+    context = @p_mask.piece_mask_context
+    context.globalCompositeOperation = 'source-atop'
+    context.drawImage(@puzzle.puzzle_view.img,0,0,@box.width,@box.height,0,0,@box.width,@box.height)
+    context.globalCompositeOperation = 'source-over'

   draw_piece: (x,y) ->
@@ -166,41 +178,41 @@

-class PieceImage
-
-  constructor: (puzzle_piece) ->
-
-    @piece = puzzle_piece
-    @puzzle = @piece.puzzle
-    @img = @piece.p_mask.img
-#    @img = document.createElement('canvas')
-#    @img.id = "piece-mask"
-    @img.width = @piece.box.width
-    @img.height = @piece.box.height
-    @piece_image_context = @img.getContext('2d')
-
-
-
-
-# FIXME Nothing references this method yet.
-draw_piece:  (a,b) ->
-    # TODO I think the books said there are more than one kind of image object.
-    @pc_img = document.getElementById("piece")
-    if @grid_model.in_range(a,b)
-      xy = @grid_model.get_xy(a,b)
-      xx = xy[0]+@dx
-      yy = xy[1]+@dy
-
-      @context.drawImage(@redraw,@redraw_x,@redraw_y) if @redraw_active
-      ctx = @redraw.getContext('2d')
-      ctx.drawImage(@canvas,xx,yy,@width,@height,0,0,@width,@height)
-      @redraw_active = true
-      @redraw_x = xx
-      @redraw_y =yy
-
-      @context.drawImage(@pc_img,xx,yy)
-    else
-      @context.drawImage(@pc_img,0,100)
+#class PieceImage
+
+#  constructor: (puzzle_piece) ->
+
+#    @piece = puzzle_piece
+#    @puzzle = @piece.puzzle
+#    @img = @piece.p_mask.img
+##    @img = document.createElement('canvas')
+##    @img.id = "piece-mask"
+#    @img.width = @piece.box.width
+#    @img.height = @piece.box.height
+#    @piece_image_context = @img.getContext('2d')
+
+
+
+
+## FIXME Nothing references this method yet.
+#  draw_piece:  (a,b) ->
+#    # TODO I think the books said there are more than one kind of image object.
+#    @pc_img = document.getElementById("piece")
+#    if @grid_model.in_range(a,b)
+#      xy = @grid_model.get_xy(a,b)
+#      xx = xy[0]+@dx
+#      yy = xy[1]+@dy
+
+#      @context.drawImage(@redraw,@redraw_x,@redraw_y) if @redraw_active
+#      ctx = @redraw.getContext('2d')
+#      ctx.drawImage(@canvas,xx,yy,@width,@height,0,0,@width,@height)
+#      @redraw_active = true
+#      @redraw_x = xx
+#      @redraw_y =yy
+
+#      @context.drawImage(@pc_img,xx,yy)
+#    else
+#      @context.drawImage(@pc_img,0,100)

@@ -279,6 +291,8 @@
     console.log("    halves = "+halves)
     console.log("    WIDTH = "+@width)
     console.log("    HEIGHT = "+@height)
+#    console.log("    BOX-X = "+@box_x)
+#    console.log("    BOX-Y = "+@box_y)
     console.log("    ANCHOR HEX = "+@anchor_hex[0]+","+@anchor_hex[1])


Give focus to ID input field in project creation view

--- client/create.coffee
+++ client/create.coffee
@@ -13,7 +13,6 @@
   editor.attachAce()
   if text
     editor.setValue(text, 0)
-  editor.setFocus()
   editor.ace.on("change", ->
     logger.debug("Project text has changed - setting dirty state")
     Session.set("isProjectModified", true)
@@ -22,6 +21,9 @@
   editor.ace.gotoLine(0, 0)
   editor.ace.session.setUseWrapMode(true)

+Template.create.rendered = ->
+  logger.debug("Project creation view rendered")
+  document.getElementById("id-input").focus()
 Template.createDescription.rendered = ->
   logger.debug("Description editor rendered, giving Ace focus")
   handleEditorRendered(descriptionEditor)


Got rid of whitespace that failed Travis.

--- client/import.coffee
+++ client/import.coffee
@@ -218,7 +218,7 @@
 Template.importCancelButton.events =
   'click .canceled': (e) ->
     e.preventDefault()
-    # We stop event propagation to prevent the cancel from bubbling up
+    # We stop event propagation to prevent the cancel from bubbling up
     # to hide the overlay.
     e.stopPropagation()


Added changePlayer function.

Added changePlayer function.

--- client/script.coffee
+++ client/script.coffee
@@ -19,7 +19,7 @@
     d3table.enter()
         .append("div")
         .attr("class", "table")
-        .style("-webkit-transform-origin", "500px 500px")
+        .style("-webkit-transform-origin", "50% 50%")
     d3table.style("-webkit-transform", (d) -> d.matrix3d())
     width= $(".table").width()
     height= $(".table").height()
@@ -35,12 +35,18 @@
         .style("-webkit-transform-origin", (d,i) ->
             position = $(this).position()
             console.log this, position
-            (500-110*i)+"px "+ (500-0)+"px "
+            (width/2-110*i)+"px "+ (height/2-0)+"px "
         )
         .style("-webkit-transform", (d) -> d.matrix3d())

 @do1 = -> table.ownCS.matrix3d=new WebKitCSSMatrix() ; draw()
 @do2 = -> cards[0].relativeToCS =new CoordinateSystem() ; draw()
 @do3 = -> table.ownCS.matrix3d=new WebKitCSSMatrix().rotate 45, 0, 0 ; draw()
-
+@do4 = -> cards[0].ownCS.matrix3d =new WebKitCSSMatrix().rotate -45, 0, 0 ; draw()
+player = 0
+@changePlayer = ->
+    player = (player+1) % 2
+    table.ownCS.matrix3d = new WebKitCSSMatrix().rotate 45, 0, 0
+    table.ownCS.matrix3d = table.ownCS.matrix3d.rotate 0, 0, 180.1*player
+    draw()
 # yo.cards[0].relativeToCS.matrix3d=yo.cards[0].relativeToCS.matrix3d.rotate(-75,0,0);yo.draw()


fix #5 - all channels checked, might have to add some more new ones though

--- client/somafm.coffee
+++ client/somafm.coffee
@@ -1,21 +1,25 @@

 Template.somafm.channels =
-  [ 'secretagent'
-    'illstreet', 'spacestation', 'doomed'
-    'bootliquor', 'lush'
-    'u80s', 'sonicuniverse', 'poptron', 'covers'
-    'brfm', 'missioncontrol'
-
+  [
   # offline
-  # 480min, tags
+  # 480min tags sonicuniverse

   # checked
+    'secretagent'
+    'illstreet', 'spacestation', 'doomed'
+    'missioncontrol'
+    'beatblender'
+    'bootliquor'
+    'brfm'
+    'covers'
+    'digitalis'
+    'dronezone'
     'groovesalad'
-    'dronezone'
     'indiepop'
-    'beatblender'
-    'digitalis'
+    'lush'
+    'poptron'
     'suburbsofgoa'
+    'u80s',

   # latest added:
     'bagel', 'sf1033'
@@ -23,6 +27,7 @@

 Template.somafm.events
   'click ul li a': (e) ->
+    console.log e
     Session.set 'channel', e.srcElement.href.split('#')[1]

 Template.somafm.somaUrl = ->


Fix priority fee for update_reg_account

Fix priority fee for update_reg_account

--- app/js/controllers/update_reg_account.coffee
+++ app/js/controllers/update_reg_account.coffee
@@ -17,9 +17,14 @@

     $scope.symbolOptions = []
-    Blockchain.get_asset(0).then (v)->
-        $scope.delegate_reg_fee = Utils.formatAsset(Utils.asset( Info.info.delegate_reg_fee, v) )
-        $scope.priority_fee = Utils.formatAsset(Utils.asset(Info.info.priority_fee, v))
+
+    $scope.$watch ->
+        Wallet.info.delegate_reg_fee
+    , ->
+        Blockchain.get_asset(0).then (v)->
+            console.log('Info.info.delegate_reg_fee',Info.info.delegate_reg_fee)
+            $scope.delegate_reg_fee = Utils.formatAsset(Utils.asset( Info.info.delegate_reg_fee, v) )
+            $scope.priority_fee = Utils.formatAsset(Utils.asset(Wallet.info.priority_fee.amount, v))
     $scope.m={}
     $scope.m.payrate=50
     $scope.m.delegate=false
@@ -38,11 +43,6 @@
                 $scope.accounts.push([name, bals])

         $scope.m.payfrom= $scope.accounts[0]
-
-    WalletAPI.set_priority_fee().then (result) ->
-        asset_type = Blockchain.asset_records[result.asset_id]
-        $scope.priority_fee = Utils.asset(result.amount, asset_type)
-

     Wallet.get_accounts().then ->
         refresh_accounts()
@@ -68,7 +68,7 @@
             controller: "DialogConfirmationController"
             resolve:
                 title: -> "Are you sure?"
-                message: -> "This will update your account's private and public info, need to pay fee " + Utils.formatAsset($scope.priority_fee) + delegate_pay_rate_info + public_info_tip
+                message: -> "This will update your account's private and public info, need to pay fee " + $scope.priority_fee + delegate_pay_rate_info + public_info_tip
                 action: ->
                     ->
                         Wallet.account_update_private_data(name,{'gui_data':{'email':$scope.edit.newemail,'website':$scope.edit.newwebsite},'gui_custom_data_pairs':$scope.edit.pairs}).then ->


Don't show a field guide with no items

Don't show a field guide with no items

--- app/pages/project/potential-field-guide.cjsx
+++ app/pages/project/potential-field-guide.cjsx
@@ -37,7 +37,7 @@
     @setState revealed: not @state.revealed

   render: ->
-    if @state.guide?
+    if @state.guide? and @state.guide.items.length isnt 0
       <Pullout className="field-guide-pullout" side="right" open={@state.revealed}>
         <button type="button" className="field-guide-pullout-toggle" onClick={@toggleFieldGuide}>
           Field guide


Refactor for clarity

Refactor for clarity

Consistent zoom speed

--- app/scripts/alchemy/core/interactions.coffee
+++ app/scripts/alchemy/core/interactions.coffee
@@ -163,19 +163,21 @@
                           # to do, allow UDF initial scale and zoom
                           # .translate conf.initialTranslate
                           # .scale conf.initialScale
-                          .scaleExtent [0.28, 2]
+                          .scaleExtent [0.2, 2.4]
                           .on "zoom", ->
                             graph = d3.select(".alchemy svg g")
-
+
                             currTransform = graph.attr("transform")
                                         .match(/(-*\d+\.*\d*)/g)
                                         .map( (a) -> return parseFloat(a) )

-                            if d3.event.sourceEvent.type == "mousemove"
+                            e = d3.event.sourceEvent
+
+                            if e.type == "mousemove"
                                 graph.attr("transform", "translate(#{ d3.event.translate }) scale(#{ currTransform[2] })")

-                            else if d3.event.sourceEvent.type == "wheel"
-                                scrollDirection = d3.event.sourceEvent.wheelDelta / Math.abs(d3.event.sourceEvent.wheelDelta)
+                            else if e.type == "wheel"
+                                scrollDirection = e.wheelDelta / Math.abs(e.wheelDelta)
                                 graph
                                   .attr("transform", "translate(#{ currTransform[0] },#{ currTransform[1] })
                                                       scale(#{ currTransform[2] + (scrollDirection * 0.2) })")


less verbose

less verbose

--- lib/autocomplete-elixir-provider.coffee
+++ lib/autocomplete-elixir-provider.coffee
@@ -39,9 +39,9 @@
         i = 0
         while ++i <= count
           word += "${#{i}:#{i}}" + (if i != count then "," else "")
-        if func then word += ")"
-        word += "${#{count+1}:\u0020}"
-        console.log {prefix: prefix, word: word}
+        if func
+          word += ")"
+          word += "${#{count+1}:\u0020}"
         suggestion =
           snippet: if completions.length > 1 then word else prefix + word
           prefix:  if completions.length > 1 then "" else prefix


fix assign

fix assign

--- addon/services/tooltip-box-manager.coffee
+++ addon/services/tooltip-box-manager.coffee
@@ -140,7 +140,7 @@
       console.warn('TooltipBoxManager.addFromView: You need to add "TooltipBoxManager.attribute" to the attributeBindings!')
       return

-    element: view.$()
+    element = view.$()

     id = instance.registerTip(type, object, element, view)
     view.set(instance.attribute, id)


list: do not let itemview to freak out when there is no data available

--- lib/components/list/listitemview.coffee
+++ lib/components/list/listitemview.coffee
@@ -50,6 +50,8 @@
   getItemDataId: ->
     data = @getData()

+    return  unless data
+
     id = if data.getId?() then data.getId()
     else if data.id?      then data.id
     else if data._id?     then data._id


Teamwork: Prevented creating a new TeamworkApp on appView's handleQuery.

--- client/Teamwork/AppView.coffee
+++ client/Teamwork/AppView.coffee
@@ -11,3 +11,7 @@
       window.parent.postMessage "TeamworkReady", "*"

   handleQuery: (query) ->
+    unless @teamworkApp
+      @teamworkApp = new TeamworkApp
+        delegate  : this
+        query     : query


teamwork: show window chooser modal if requested session is different than current

--- client/Teamwork/AppView.coffee
+++ client/Teamwork/AppView.coffee
@@ -18,11 +18,34 @@
     else @teamworkApp.emit "NewSessionRequested"

   handleSessionKey: (sessionKey) ->
-    return @restoreLocation()  if sessionKey is @teamworkApp.getOption "sessionKey"
-    @teamworkApp.emit "JoinSessionRequested", sessionKey
+    currentSessionKey = @teamworkApp.getOption "sessionKey"
+    return @restoreLocation()  if sessionKey is currentSessionKey
+
+    if currentSessionKey
+    then @showChooseWindowModal sessionKey
+    else @teamworkApp.emit "JoinSessionRequested", sessionKey

   handleImportUrl: (importUrl) ->
     @teamworkApp.emit "ImportRequested", importUrl
+
+  showChooseWindowModal: (sessionKey) ->
+    modal = new KDModalView
+      title      : "Choose session window"
+      content    : "Where do you want to open session #{sessionKey}?"
+      cssClass   : "tw-modal"
+      overlay    : yes
+        buttons         :
+          CurrentWindow :
+            title       : "Current window"
+            callback    : =>
+              @teamworkApp.emit "JoinSessionRequested", sessionKey
+              modal.destroy()
+          NewWindow     :
+            title       : "New window"
+            callback    : =>
+              @restoreLocation()
+              window.open "#{window.location.origin}/Teamwork?sessionKey=#{sessionKey}", "_blank"
+              modal.destroy()

   restoreLocation: ->
     @setLocation @teamworkApp.getOption "sessionKey"


minor changes for pull request #8111

minor changes for pull request #8111

--- client/app/lib/mainview.coffee
+++ client/app/lib/mainview.coffee
@@ -248,21 +248,17 @@
     @toggleSidebar()

-  getClassNames: (logo) -> classnames
-    'team-logo' : yes
-    'default' : logo is DEAFULT_TEAM_LOGO
-
   createTeamLogo: ->

     logo = '/a/images/logos/default_team_logo.svg'

     { groupsController } = kd.singletons
-    team = groupsController?.getCurrentGroup()
+    team = groupsController.getCurrentGroup()

     if team.customize
       logo = team.customize.logo

-    className = @getClassNames logo
+    className = getClassNames logo

     @teamLogoWrapper.addSubView @teamLogo = new kd.CustomHTMLView
       tagName : 'img'
@@ -271,11 +267,10 @@
         src : "#{logo}"

     groupsController.on 'TEAM_DATA_TO_UPDATE', (dataToUpdate) =>
-      logo = dataToUpdate.customize?.logo
-      if logo
-        @teamLogo.setAttribute 'src', logo
-        @teamLogo.setAttribute 'class', ''
-        @teamLogo.setClass @getClassNames logo
+      return unless logo = dataToUpdate.customize?.logo
+      @teamLogo.setAttribute 'src', logo
+      @teamLogo.setAttribute 'class', ''
+      @teamLogo.setClass getClassNames logo

   createAccountArea: ->

@@ -450,3 +445,7 @@

     body.style.background = '#000'
     @setClass 'logout-tv'
+
+getClassNames = (logo) -> classnames
+  'team-logo' : yes
+  'default' : logo is DEAFULT_TEAM_LOGO


FSItem: use getKite which supports both old and new kites

--- client/finder/fs/fsitem.coffee
+++ client/finder/fs/fsitem.coffee
@@ -8,8 +8,7 @@

   @create:({ path, type, vmName, treeController }, callback)->

-    kite = KD.getSingleton('vmController').getKiteByVmName vmName
-
+    kite = @getKite()
     kite.vmOn().then ->

       plainPath = FSHelper.plainPath path


Formatting:

Formatting:

--- lib/integrated-learn-environment.coffee
+++ lib/integrated-learn-environment.coffee
@@ -17,6 +17,7 @@
   activate: (state) ->
     @term = new Terminal("ws://localhost:4463")
     @termView = new TerminalView(state, @term)
+
     @fs = new SyncedFS("ws://localhost:4464", @term)

     @subscriptions = new CompositeDisposable


Load data after all callbacks are installed

--- app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
+++ app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
@@ -56,8 +56,6 @@
         $scope.initialized = true
         $timeout ->
           $scope.resetSelectFilters()
-
-  $scope.refreshData()

   $scope.$watch 'bulk_order_form.$dirty', (newVal, oldVal) ->
     if newVal == true
@@ -152,3 +150,5 @@
     if lineItem.quantity > 0
       lineItem.final_weight_volume = LineItems.pristineByID[lineItem.id].final_weight_volume * lineItem.quantity / LineItems.pristineByID[lineItem.id].quantity
       $scope.weightAdjustedPrice(lineItem)
+
+  $scope.refreshData()


Remove unnecessary spec

Remove unnecessary spec

--- spec/editor-component-spec.coffee
+++ spec/editor-component-spec.coffee
@@ -123,8 +123,6 @@
         it "doesn't show end of line invisibles at the end of wrapped lines", ->
           expect(component.lineNodeForScreenRow(0).textContent).toBe "a line that "
           expect(component.lineNodeForScreenRow(1).textContent).toBe "wraps#{invisibles.space}#{invisibles.eol}"
-
-        it "displays trailing carriage return using a visible non-empty value", ->

     describe "when indent guides are enabled", ->
       beforeEach ->


Fix javascript errors where $scope.filteredLineItems hasn't been initialized yet

--- app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
+++ app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
@@ -129,12 +129,12 @@
     $scope.selectedUnitsVariant = unitsVariant

   $scope.sumUnitValues = ->
-    sum = $scope.filteredLineItems.reduce (sum,lineItem) ->
+    sum = $scope.filteredLineItems?.reduce (sum,lineItem) ->
       sum + lineItem.final_weight_volume
     , 0

   $scope.sumMaxUnitValues = ->
-    sum = $scope.filteredLineItems.reduce (sum,lineItem) ->
+    sum = $scope.filteredLineItems?.reduce (sum,lineItem) ->
         sum + lineItem.max_quantity * lineItem.units_variant.unit_value
     , 0


Increase the slow test threshold.

Increase the slow test threshold.

--- Jakefile.coffee
+++ Jakefile.coffee
@@ -73,7 +73,7 @@

 commands =
   minify: './node_modules/.bin/uglifyjs --lift-vars --output ./build/types.min.js ./build/types.js'
-  test: './node_modules/.bin/mocha --compilers coffee:coffee-script --ui tdd --reporter spec --colors --slow 10 ./test/types.coffee'
+  test: './node_modules/.bin/mocha --compilers coffee:coffee-script --ui tdd --reporter spec --colors --slow 50 ./test/types.coffee'
   jslint: './node_modules/.bin/jshint ./build/types.js --config config/jshint.json'
   cslint: './node_modules/.bin/coffeelint -f config/coffeelint.json ./src/types.coffee'
   compile: './node_modules/.bin/coffee -c -o ./build/types.js ./src/types.coffee'


beautify

beautify

--- test/test.coffee
+++ test/test.coffee
@@ -1,7 +1,7 @@
-echo = require '..'
-fs = require 'fs'
+echo    = require '..'
+fs      = require 'fs'
 testStr = 'testStr'
-dir = 'testdir'
+dir     = 'testdir'

 describe 'echo', ->


Remove unsed requires

Remove unsed requires

Was not using chai-json-schema or nock

--- test/test.coffee
+++ test/test.coffee
@@ -3,23 +3,12 @@
 sinon      = require 'sinon'
 isJSON     = require 'is-json'
 request    = require 'request'
-nock       = require 'nock'

 SL = require '../lib/'

 chai       = require 'chai'
 { expect } = require 'chai'
-chai.use(require('chai-json-schema'))
 chai.use(require('chai-xml'))
-
-###
-* Test promises
-* Test chaning promises (using mocks? nock.js?)
-* Test specifying format 'JSON' and 'XML'
-* Test att url:en är rätt
-* Test att request kastar en error
-* Testa getRaw
-###

 keys =
   realtimeInformation: 'xxx'


Implement test for handling array att vals

--- test/test.coffee
+++ test/test.coffee
@@ -88,7 +88,7 @@
         collection = new TestCollection()

         expected = []
-        actual = _.map collection.typeahead('a'), (m) -> m.get('id')
+        actual = _.map collection.typeahead('a'), (m) -> m.id

         actual.should.eql expected

@@ -100,7 +100,21 @@
       causeError.should.throw('Missing typeaheadAttributes value')

   describe 'Common Backbone Scenarios', ->
-    it 'should handle attributes with array values'
+    it 'should handle attributes with array values', ->
+      class MyModel extends Backbone.Model
+
+      class MyCollection extends Backbone.TypeaheadCollection
+        model: MyModel
+        typeaheadAttributes: ['array']
+
+      collection = new MyCollection([
+        { id: 1, array: ['Aa', 'Ab'] }
+        { id: 2, array: ['Aa'] }
+        { id: 3, array: ['Bb'] }
+      ])
+
+      expected = [1, 2]
+      actual = _.map collection.typeahead('a'), (m) -> m.id

     it 'should support alternative ID attributes', ->
       json = '[{"url":"people/Nick-Kishfy","indexText":"Nick Kishfy Founder & CEO boss hiker ceo","title":"Nick Kishfy"}]'


Ensure initial markdown editor is always used

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -179,6 +179,7 @@

       describe "when the preview is not the active item and not in the active pane", ->
         it "re-renders the preview and makes it active", ->
+          markdownEditor = atom.workspace.getActiveEditor()
           previewPane.focus()

           waitsForPromise ->
@@ -186,7 +187,7 @@

           runs ->
             editorPane.focus()
-            atom.workspace.getActiveEditor().setText("Hey!")
+            markdownEditor.setText("Hey!")

           waitsFor ->
             MarkdownPreviewView::renderMarkdown.callCount > 0


Semicolon fix

Semicolon fix

--- src/coffee/happy.coffee
+++ src/coffee/happy.coffee
@@ -149,11 +149,11 @@

 			if ie
 				event = document.createEvent('Event')
-				event.initEvent('change', true, true);
+				event.initEvent('change', true, true)
 			else
 				event = new Event('change', {'bubbles': true})

-			input.dispatchEvent(event);
+			input.dispatchEvent(event)

 	checkCheckboxStateOnChange: (e) =>
 		if e.target.classList.contains('happy')


Added support for .js.coffee file extensions.

--- Jakefile.coffee
+++ Jakefile.coffee
@@ -19,9 +19,16 @@
   concatenated: "build/#{config.buildName}-concat.js"
   minified: "build/#{config.buildName}-min.js"

+# PACKAGE METHODS AND VARIABLES
+
 # Used to track the watcher timeout, to avoid build spam on mass source changes.
 exports.watchTimeout = null
 exports.watchTimeoutWaiting = false
+
+# Gets the .js equivalent of a file.  Converts .js.coffe and .coffee to .js.
+exports.getJsName = (file) ->
+  return file.replace /(\.js)?\.coffee$/, '.js' if file.match /\.coffee$/
+  file

 # TASKS

@@ -30,6 +37,7 @@

 desc 'Compile from source.'
 task 'compile', ->
+  console.time 'Compile'
   console.log 'Compiling source...'
   # Traverse src tree to find old files
   findit.sync 'src', (file) ->
@@ -39,9 +47,18 @@
   console.log 'Pruning orphaned files...'
   orphanedDirs = []
   findit.sync 'build/compiled', (file) ->
+    # Build some path candidates and check if it exists in the source.
     searchPath = file.replace /^build\/compiled/, 'src'
-    searchPathCoffee = searchPath.replace /\.js$/, '.coffee'
-    return if path.existsSync(searchPath) or path.existsSync(searchPathCoffee)
+    pathCandidates = [
+      searchPath
+      "#{searchPath}.coffee"
+      searchPath.replace(/\.js$/, '.coffee')
+    ]
+    existsInSrc = false
+    existsInSrc = existsInSrc or path.existsSync(p) for p in pathCandidates
+    # We found it in src, so we leave it
+    return if existsInSrc
+    # Check if it is a file or a directory and handle appropriately
     fileStats = fs.statSync file
     if fileStats.isFile()
       fs.unlinkSync file
@@ -49,7 +66,7 @@
       # Collect directories to remove after files
       orphanedDirs.push file
   fs.rmdir dir for dir in orphanedDirs
-  console.log 'Compiled source.'
+  console.timeEnd 'Compile'

 namespace 'compile', ->
   desc 'Compile a file from source.'
@@ -61,7 +78,7 @@
     return unless ['coffee', 'js'].indexOf(extension) isnt -1
     # Calculate the target so we can check if copy or compilation is required
     if extension is 'coffee'
-      target = file.replace(/^src/, 'build/compiled').replace(/\.coffee$/, '.js')
+      target = exports.getJsName file.replace(/^src/, 'build/compiled')
     else
       target = file.replace /^src/, 'build/compiled'
     # Ignore file if the compiled version is newer
@@ -86,15 +103,16 @@

 desc 'Build concatenated source.'
 task 'concat', ->
-  jake.Task['compile'].invoke()
+  console.time 'Concatenate'
   console.log 'Concatenating compiled source...'
   jake.exec ["find build/compiled/ -name *.js | xargs cat > #{buildFiles.concatenated}"], ->
-    console.log 'Successfully concatenated compiled source.'
+    console.timeEnd 'Concatenate'
     complete()
 , {async: true}

 desc 'Build minified source.'
 task 'minify', ->
+  console.time 'Minify'
   console.log 'Minifying source...'
   concatenated = fs.readFileSync buildFiles.concatenated, 'utf8'
   jsp = uglifyJs.parser
@@ -104,12 +122,12 @@
   ast = pro.ast_squeeze ast
   minified = pro.gen_code ast
   fs.writeFileSync buildFiles.minified, minified
-  console.log 'Successfully minified source.'
+  console.timeEnd 'Minify'

 desc 'Clean build directory.'
 task 'clean', ['build/compiled'], ->
   console.log 'Cleaning build directory...'
-  jake.exec ['rm -rfv build/compiled/*'], ->
+  jake.exec ['rm -rfv build'], ->
     console.log 'Successfully cleaned build directory.'
     complete()
 , {async: true}
@@ -123,6 +141,9 @@
       console.log "#{f} updated."
     else
       console.log "#{f} removed."
+    # This is run with a timeout to avoid build spam, such as when moving and
+    # deleting a large amount of files.  The timer is reset whenever a request
+    # is made inside the timeout period.
     clearTimeout exports.watchTimeout if exports.watchTimeoutWaiting
     exports.watchTimeoutWaiting = true
     exports.watchTimeout = setTimeout ->


but hey, I fixed the specs

but hey, I fixed the specs

--- public/spec/try-it-spec.coffee
+++ public/spec/try-it-spec.coffee
@@ -395,6 +395,10 @@
   it "enables soft tabs (spaces instead of tabulators)", ->
     expect(editor.getSession().setUseSoftTabs).toHaveBeenCalledWith(true)

+  it "disables print margins", ->
+    expect(editor.renderer.setShowPrintMargin).toHaveBeenCalledWith(false)
+
+
   behavesLikeItSwitchesModes = (name) ->
     it "requires the #{name} mode", ->
       expect(require.callCount).toBe(1)
@@ -437,5 +441,8 @@
     setTheme: jasmine.createSpy('#setTheme'),
     switchMode: jasmine.createSpy('#switchMode'),
     insert: jasmine.createSpy('#insert'),
+    renderer: {
+      setShowPrintMargin: jasmine.createSpy('#setShowPrintMargin')
+    }
     getSession: -> session
   }


Fix bug

Fix bug

Typo led to undo not always being called correctly.

--- src/core/actions.coffee
+++ src/core/actions.coffee
@@ -10,7 +10,7 @@

   undo: ->
     @lc.shapes = @oldShapes
-    @lc.repaintLaye('main')
+    @lc.repaintLayer('main')

 class AddShapeAction
@@ -51,4 +51,4 @@
     @lc.repaintLayer('main')

-module.exports = {ClearAction, AddShapeAction}+module.exports = {ClearAction, AddShapeAction}


Fixes #2765 -- incorrect line number in mappings

--- coffee-script.coffee
+++ coffee-script.coffee
@@ -49,7 +49,8 @@

     fragments = (parser.parse lexer.tokenize(code, options)).compileToFragments options

-    currentLine = 0
+    # Two lines of comments will start the JS file.
+    currentLine = 2
     currentColumn = 0
     js = ""
     for fragment in fragments


Waller class fully implemented

Waller class fully implemented

Using Async node module to only open 5 http requests at a time.

Next up is to make max parallel requests configurable, and to make the
electron UI.

--- coffee/waller.coffee
+++ coffee/waller.coffee
@@ -25,7 +25,7 @@

 			@done = false

-		getJson: (url, callback) ->
+		getJson: (url, callback) =>
 			if @debug
 				console.log 'json req: ' + url

@@ -37,20 +37,20 @@
 						console.log 'json resp: ' + resp + ':' + body
 					callback body

-		getProjectInfo: (projectSlug, callback) ->
+		getProjectInfo: (projectSlug, callback) =>
 			@getJson base + artwork + projectSlug + '.json', callback

-		getUserInfo: (user, callback) ->
+		getUserInfo: (user, callback) =>
 			@getJson base + users + user + '.json', callback

-		getUserLikePage: (user, page, callback) ->
+		getUserLikePage: (user, page, callback) =>
 			# Get page #[page] of [user]'s likes
 			url = base + users + user + '/' + likes + '?page=' + page

 			@getJson url, (resp) =>
 				callback resp.data

-		getUserLikes: (user, callback) ->
+		getUserLikes: (user, callback) =>
 			@getUserInfo user, (resp) =>
 				# limit the number of projects we consider
 				count = resp.liked_projects_count
@@ -77,13 +77,15 @@
 						result = result.concat x
 					callback result

-		saveImage: (url, savePath) ->
+		saveImage: (url, savePath, callback) =>
 			if @debug
 				console.log 'saving image: ' + savePath
 			req = request url
 			req.pipe fs.createWriteStream savePath
+			if callback?
+				callback()

-		downloadProjectImage: (projectHash) ->
+		downloadProjectImage: (projectHash, callback) =>
 			@getProjectInfo projectHash, (projInfo) =>
 				asset = null
 				for x in projInfo.assets when x.has_image
@@ -96,9 +98,7 @@

 				# get rid of illegal chars
 				projInfo.title = projInfo.title.replace /\/|\\/g, "-"
-				projInfo.title = projInfo.title.replace /\"/g, ""
-				projInfo.title = projInfo.title.replace /\'/g, ""
-				projInfo.title = projInfo.title.replace /\?/g, ""
+				projInfo.title = projInfo.title.replace /\"|\'|\:|\?/g, ""

 				# extract file extension
 				ext = x.image_url.match(/(\.[A-z][A-z][A-z])\?/)[1]
@@ -108,10 +108,17 @@
 					dir: @savePath
 					base: projInfo.title

-				@saveImage x.image_url, savePath
+				@saveImage x.image_url, savePath, callback

-		downloadAllUserLikes: () ->
+		downloadAllUserLikes: (callback) =>
 			for user in @usernames
 				@getUserLikes user, (likes) =>
-					like = likes[0]
-					@downloadProjectImage like.hash_id
+					i = 0
+					likes = (like.hash_id for like in likes)
+					if @limit > 0 and likes.length > @limit
+						likes = likes.slice 0, @limit
+					async.eachLimit likes, 5, @downloadProjectImage, (err) =>
+						if @debug
+							console.log 'Downloading done'
+						if callback?
+							callback err


handle classes with no source file

handle classes with no source file

--- src/disassembler.coffee
+++ src/disassembler.coffee
@@ -17,7 +17,7 @@
   source_file = _.find(class_file.attrs, (attr) -> attr.constructor.name == 'SourceFile')
   ifaces = (class_file.constant_pool.get(i).deref() for i in class_file.interfaces)
   ifaces = ((if util.is_string(i) then util.ext_classname(i) else i.toExternalString()) for i in ifaces).join ','
-  rv = "Compiled from \"#{source_file.name}\"\n"
+  rv = "Compiled from \"#{source_file?.name ? 'unknown'}\"\n"
   rv += access_string class_file.access_flags
   if class_file.access_flags.interface
     rv += "interface #{class_file.this_class.toExternalString()} extends #{ifaces}\n"


updated methods

updated methods

--- src/drm-lightbox.coffee
+++ src/drm-lightbox.coffee
@@ -4,6 +4,7 @@
 ###############################################################################
 "use strict"

+$ = jQuery
 class @DrmLightbox
     constructor: (@images = $('ul.drm-lightbox-thumbnails'), @speed = 300) ->
         self = @
@@ -18,12 +19,12 @@
         self.body.on 'click', 'div.drm-blackout', self.removeLightbox

     createThumbnails: ->
-        links = @images.find 'a'
+        _links = @images.find 'a'
         thumbnailList = []
         thumbnails = ''

         # populate imgList array
-        links.each ->
+        _links.each ->
             thumbnailList.push $(@).attr 'href'

         # create html for thumbnail-list
@@ -33,12 +34,12 @@
         thumbnails

     createLightbox: (thumbnails) ->
-        img = $(@).attr 'href'
+        _img = $(@).attr 'href'
         # html for the actual lightbox

         imgVisible = $ '',
             class: 'img-visible'
-            src: img
+            src: _img
             alt: 'thumbnail'

         close = $ '<button></button>',
@@ -61,14 +62,14 @@

     changeImage: (e) ->
         img = $(@).attr 'href'
-        oldImg = $ 'div.drm-blackout img.img-visible'
-        oldImgSrc = oldImg.attr 'src'
+        _oldImg = $ 'div.drm-blackout img.img-visible'
+        _oldImgSrc = _oldImg.attr 'src'
         speed = @speed

         e.preventDefault()

-        if oldImgSrc isnt img
-            oldImg.fadeOut speed, ->
+        if _oldImgSrc isnt img
+            _oldImg.fadeOut speed, ->
                 $(@).attr('src', img).fadeIn speed

         e.stopPropagation()


Fix silly ancient math mistake

Fix silly ancient math mistake

--- app/lib/world/vector.coffee
+++ app/lib/world/vector.coffee
@@ -122,7 +122,7 @@

   dot: (other, useZ) ->
     sum = @x * other.x + @y * other.y
-    sum += @z + other.z if useZ
+    sum += @z * other.z if useZ
     sum

   # Not the strict projection, the other isn't converted to a unit vector first.


Dont allow user to assign color if he has no color available

--- static/script/pages/settings.coffee
+++ static/script/pages/settings.coffee
@@ -83,6 +83,7 @@
       (form_color.field 'submit').disable()

   # Opponent color
+  free_colors_count = null
   form_opponent_color = new window.hlib.Form
     fid:			'opponent_colors'
     clear_fields:		['color', 'username']
@@ -101,20 +102,33 @@
         kind:			(form_opponent_color.field 'kind').value()
       handlers:
         h200:			(response, ajax) ->
-          c.label = window.hlib._g c.label for c in response.colors
-          response._g = window.hlib._g
-
-          tmpl = doT.template '
-            <option value="">{{= window.hlib._g("Choose...")}}</option>
-            {{~ it.colors :color:index}}
-              <option value="{{= color.name}}" class="colors" style="background-image: url(/static/images/games/settlers/board/real/players/{{= color.name}}/node/village.gif)">{{= color.label}}</option>
-            {{~}}'
-          f.content tmpl response
+          free_colors_count = response.colors.length
+          if free_colors_count <= 3
+            (form_opponent_color.field 'color').disable()
+            (form_opponent_color.field 'username').disable()
+            (form_opponent_color.field 'submit').disable()
+
+          else
+            (form_opponent_color.field 'username').enable()
+            (form_opponent_color.field 'submit').enable()
+
+            c.label = window.hlib._g c.label for c in response.colors
+            response._g = window.hlib._g
+
+            tmpl = doT.template '
+              <option value="">{{= window.hlib._g("Choose...")}}</option>
+              {{~ it.colors :color:index}}
+                <option value="{{= color.name}}" class="colors" style="background-image: url(/static/images/games/settlers/board/real/players/{{= color.name}}/node/village.gif)">{{= color.label}}</option>
+              {{~}}'
+            f.content tmpl response

           window.hlib.MESSAGE.hide()

   (form_opponent_color.field 'color').disable (f) ->
-    f.placeholder 'Choose game kind first...'
+    if free_colors_count <= 3
+      f.placeholder 'You have no free colors to use'
+    else
+      f.placeholder 'Choose game kind first...'

   # list
   (form_opponent_color.field 'list').enable (f) ->
@@ -152,7 +166,8 @@
                   username:	u.user.name
                 handlers:
                   h200:	(response, ajax) ->
-                    (form_opponent_color.field 'color').on_enable(form_opponent_color.field 'color')
+                    (form_opponent_color.field 'color').enable()
+                    #(form_opponent_color.field 'color').on_enable(form_opponent_color.field 'color')
                     (form_opponent_color.field 'list').on_enable(form_opponent_color.field 'list')

                     window.hlib.MESSAGE.hide()


Only zoom to markers if we have any

Only zoom to markers if we have any

--- app/scripts/services.coffee
+++ app/scripts/services.coffee
@@ -253,7 +253,9 @@
         markerLayer.addLayer(m)

       @zoomToMarkers = () ->
-        map.fitBounds(markerLayer.getBounds())
+        bounds = markerLayer.getBounds()
+        if bounds.isValid()
+          map.fitBounds(bounds)

       return this


I am officially an idiot

I am officially an idiot

--- app/scripts/services.coffee
+++ app/scripts/services.coffee
@@ -7,11 +7,11 @@
             on:
                 method: 'PUT'
                 params:
-                    status: 'off'
+                    status: 'on'
             off:
                 method: 'PUT'
                 params:
-                    status: 'on'
+                    status: 'off'
 )

 angular.module('blankServices', ['ngResource'])


cleanup actions

cleanup actions

--- src/game/actions.coffee
+++ src/game/actions.coffee
@@ -4,9 +4,7 @@
 exports.game = {
   name: "Words"
   assume: 'shapes'
-  # TODO: rename as behavior
-  # have sprite behavior extend this
-  # bind actions at run-time
+  # TODO: integrate behavior
   actions: {
     # String of operation, key, parameter
     wait:    "call go 0"
@@ -18,5 +16,4 @@
     _victory: "send done 1"
     _failure: "send done -1"
   }
-
 }


Updated throw logic

Updated throw logic

--- src/highlightify.coffee
+++ src/highlightify.coffee
@@ -1,6 +1,6 @@
 Highlightify =
   highlightMatches: (opts) ->
-    if not opts?.text or not opts?.filter
+    if not (opts?.text and opts?.filter)
       throw 'Highlightify.highlightMatches requires `text` and `filter` options'

     className = opts.className or 'highlightify-is-match'


/api/v1 tests converted

/api/v1 tests converted

--- test/integration/controllers/v1/ApiController.test.coffee
+++ test/integration/controllers/v1/ApiController.test.coffee
@@ -8,6 +8,7 @@
 ###*
 # Test API "ping" endpoint.
 ###
+
 describe 'Requests to the root (/api) path', ->
   it 'GET: Returns a 200 status code', (done) ->
     request(sails.hooks.http.app)
@@ -46,3 +47,19 @@
       .expect 200, done
     return
   return
+  it 'GET: Returns v1 paths', (done) ->
+    request(sails.hooks.http.app)
+      .get('/api/v1')
+      .expect('content-type', /json/)
+      .end (err, res) ->
+        if err
+          throw err
+        res.body.should.have.property 'user'
+        res.body.user.should.have.property 'register'
+        res.body.user.register.should.endWith '/api/v1/user/register'
+        res.body.user.should.have.property 'password'
+        res.body.user.password.should.endWith '/api/v1/user/password'
+        done()
+        return
+    return
+  return


No longer needed

No longer needed

--- apps/artist/statuses.coffee
+++ apps/artist/statuses.coffee
@@ -17,7 +17,7 @@

       Q.allSettled([
         @fetchArtworks()
-        @fetchStatus 'shows', size: 2 # Remove once Gravity is deployed
+        @fetchStatus 'shows'
         @fetchStatus 'posts'
         @fetchStatus 'artists'
         @fetchStatus 'contemporary'


Thunkify webpack

Thunkify webpack

--- plugins/webpack/webpack.coffee
+++ plugins/webpack/webpack.coffee
@@ -36,15 +36,13 @@
             pathinfo: true
           plugins: []

-    writeAfter: ->
+    writeAfter: (opts, next)->
       docpad = @docpad
       cfg = docpad.getConfig()
       config = @getConfig()
       delete config.environments
       config.context = path.resolve cfg.srcPath, 'webpack'
       (config.output ||= {}).path = cfg.outPath
-      console.log ""
-      console.log "@@@@@@@@@@@@@@@@@@@", config
       webpack config, (err, stats)->
-        console.log "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", err
         docpad.log 'info', stats.toString colors: true
+        do next


Added some items to the controller todo list

--- controller.coffee
+++ controller.coffee
@@ -131,7 +131,9 @@
 		@currentState = @initialState

-
+# 	TODO:
+# 	1. Optionally support multiple active children.
+#	2. Add option to have STATE_ACTIVATED be default.

 class Controller extends Spine.Controller


Search completion; remove unused code.

Search completion; remove unused code.

This removes a couple of lines which should have been removed
previously.

--- background_scripts/completion_engines.coffee
+++ background_scripts/completion_engines.coffee
@@ -26,7 +26,6 @@

 # Several Google completion engines package XML responses in this way.
 class GoogleXMLRegexpEngine extends RegexpEngine
-  doNotCache: false # true (disbaled, experimental)
   parse: (xhr) ->
     for suggestion in xhr.responseXML.getElementsByTagName "suggestion"
       continue unless suggestion = suggestion.getAttribute "data"
@@ -38,7 +37,6 @@
     regexps ?= [
       # We match the major English-speaking TLDs.
       new RegExp "^https?://[a-z]+\.google\.(com|ie|co\.uk|ca|com\.au)/"
-      new RegExp "localhost/cgi-bin/booky" # Only for smblott.
       ]
     super regexps

@@ -77,7 +75,6 @@
       "http://suggestqueries.google.com/complete/search?client=youtube&ds=yt&xml=t&q=%s"

 class Wikipedia extends RegexpEngine
-  doNotCache: false # true (disbaled, experimental)
   # Example search URL: http://www.wikipedia.org/w/index.php?title=Special:Search&search=%s
   constructor: ->
     super [ new RegExp "^https?://[a-z]+\.wikipedia\.org/" ]


change spec to just test for definition

change spec to just test for definition

--- templates/spec/client/Screen.coffee
+++ templates/spec/client/Screen.coffee
@@ -2,4 +2,4 @@

     it "can be rendered", ->
         screen = LT.renderComponent(<%= screen_class %>)
-        expect(_.dom(screen).text).toMatch("Hello")
+        expect(_.dom(screen).text).toBeDefined()


details -> detail

details -> detail

--- src/notification.coffee
+++ src/notification.coffee
@@ -19,7 +19,7 @@
     unless _.isObject(@options) and not _.isArray(@options)
       throw new Error("Notification must be created with an options object: #{@options}")

-    if @options?.detail? and typeof @options.details isnt 'string'
+    if @options?.detail? and typeof @options.detail isnt 'string'
       throw new Error("Notification must be created with string detail: #{@options.detail}")

   onDidDismiss: (callback) ->


use change rather then click to submit filters

--- app/assets/javascripts/application.coffee
+++ app/assets/javascripts/application.coffee
@@ -5,7 +5,8 @@
 #= require_self

 $ ->
-  $('.filter input[type=radio], .filter input[type=checkbox], .filter select').click ->
+  $('.filter input[type=radio], .filter input[type=checkbox], .filter select').change ->
     $(this).closest('form').submit()
+
   $('.comments a').click ->
     $('.comments').hide()


Fixed burndown chart where completion date was not being calculated correctly

--- app/assets/javascripts/burndown.js.coffee
+++ app/assets/javascripts/burndown.js.coffee
@@ -23,6 +23,15 @@
         byOrAt = if key is "Target Completion" then "by" else "at"
         "
#{key}

#{y} remaining #{byOrAt} Week #{x}
"
+
+      ###
+      If under a tab, make sure tab changes re-render chart
+      ###
+      tab = $(chartContainer).parents ".tab-pane"
+      if tab.length
+        tab.each (i,e) ->
+          t = $("a[href='##{$(e).attr("id")}'][data-toggle]")
+          t.on "shown", -> chart.update()

       d3.select($(chartContainer).children("svg")[0])
         .datum(chartData)
@@ -122,8 +131,8 @@
   weekTaskWeightCompleted[i] = 0 for i in [0..cutOffWeek]

   tasks.forEach (task) ->
-    dueDate = task.task_template[taskDate]
-    dueWeek = moment(dueDate).diff startDate, 'weeks'
+    completionDate = if taskDate is 'target_date' then task.task_template.target_date else task.completion_date
+    dueWeek = moment(completionDate).diff startDate, 'weeks'
     weekTaskWeightCompleted[dueWeek] += task.weight

   weekTaskWeightCompleted


Revert "Merge branch 'feature/enable-cocoon-unrolls-on-edit' into 'core'"

This reverts commit e7ad4c896e973b5cc7d66b6a7368d7766394a30c, reversing
changes made to dca829a8ae297431e43e109de957d6d84d94b6f1.

--- app/assets/javascripts/selector.js.coffee
+++ app/assets/javascripts/selector.js.coffee
@@ -364,14 +364,8 @@
       false

   $(document).behave "load", "input[data-selector]", (event) ->
-    enableSelectors = ($collection) =>
-      $collection.each ->
-        $(this).selector()
-
-    document.addEventListener 'DOMContentLoaded', ->
-      enableSelectors($("input[data-selector]"))
-
-    E.onDOMElementAdded("input[data-selector]", enableSelectors)
+    $("input[data-selector]").each ->
+      $(this).selector()

   $(document).on "selector:change", (changeEvent, value) ->
     $("*[data-selector-update]").each ->


Remove debug output

Remove debug output

--- app/assets/javascripts/views/flash.coffee
+++ app/assets/javascripts/views/flash.coffee
@@ -5,29 +5,22 @@
         $(this).delay(waitTime + 500*idx).fadeOut 500, ->

   @add: (level, message, waitTime=2000)=>
-    console.log("add")
-    console.log(waitTime)
     $('.flash').append(HandlebarsTemplates['flash'](level: level, message: message))
     @fadeOut(waitTime)

   @info: (msg)=>
-    console.log("info")
     @add('info', msg)

   @success: (msg)=>
-    console.log("succ")
     @add('success', msg)

   @warning: (msg)=>
-    console.log("warn")
     @add('warning', msg)

   @error: (msg)=>
-    console.log("err")
     @add('error', msg, 5000)

   @default: (msg)=>
-    console.log("defa")
     @add('', msg)

 $(document).on 'ready page:load', ->


asar: Fix fs.realpath on package's root

asar: Fix fs.realpath on package's root

--- atom/common/lib/asar.coffee
+++ atom/common/lib/asar.coffee
@@ -118,7 +118,7 @@
   throw new Error("Invalid package #{asarPath}") unless archive

   real = archive.realpath filePath
-  throw createNotFoundError(asarPath, filePath) unless real
+  throw createNotFoundError(asarPath, filePath) if real is false

   path.join realpathSync(asarPath), real

@@ -135,7 +135,7 @@
   return callback new Error("Invalid package #{asarPath}") unless archive

   real = archive.realpath filePath
-  return callback createNotFoundError(asarPath, filePath) unless real
+  return callback createNotFoundError(asarPath, filePath) if real is false

   realpath asarPath, (err, p) ->
     return callback err if err


enhance: call `deviceChanged` on load

enhance: call `deviceChanged` on load

--- app/components/project-preferences.coffee
+++ app/components/project-preferences.coffee
@@ -12,6 +12,9 @@
   versions: ["Loading..."]
   availableDevices: ["Loading..."]
   currentDevice: ["Loading..."]
+
+  didInsertElement: ->
+    this.send('deviceChanged');

   actions:
     deviceChanged: (value) ->


action doctypes have not permissions

action doctypes have not permissions

--- app/controllers/request_controller.coffee
+++ app/controllers/request_controller.coffee
@@ -20,6 +20,7 @@
         else
             compound.app.feed.publish 'usage.application', appName
             next()
+, only: ['definition', 'remove', 'results', 'removeResults']

 # Lock document to avoid multiple modifications at the same time.
 before 'lock request', ->


本番出力用のタスクを調整

本番出力用のタスクを調整

--- grunt/aliases.coffee
+++ grunt/aliases.coffee
@@ -3,6 +3,7 @@
 		"clean"
 		"assemble"
 		"sass:production_pc"
+		"sass:production_sp"
 		"autoprefixer:production"
 		"browserify:production_pc"
 		"copy"


add none polarityMark option to configuration (#86)

--- src/qeda-pattern.coffee
+++ src/qeda-pattern.coffee
@@ -168,6 +168,8 @@
         y += d/2

     switch @settings.polarityMark
+      when 'none'
+        this
       when 'dot'
         r = d/2
         oldLineWidth = @currentLineWidth


Fixed Factory description

Fixed Factory description

--- www/src/theoricus/core/factory.coffee
+++ www/src/theoricus/core/factory.coffee
@@ -8,7 +8,8 @@
 Controller = require 'theoricus/mvc/controller'

 ###*
-  Factory class.
+  Factory is responsible for loading/creating the MVC classes.
+
   @class Factory
 ###

@@ -17,7 +18,6 @@
   controllers: {}

   ###*
-  Factory is responsible for creating the MVC classes.

   @constructor
   @param the {Theoricus} Shortcut for app's instance


Social: refactor functions to use request wrapper

--- workers/social/lib/social/models/socialapi/channel.coffee
+++ workers/social/lib/social/models/socialapi/channel.coffee
@@ -61,7 +61,7 @@
   Validators = require '../group/validators'
   {permit}   = require '../group/permissionset'

-  {fetchGroup} = require "./helper"
+  {fetchGroup, socialRequestWrapper, doRequest} = require "./helper"

   @generateChannelName = ({groupSlug, apiChannelType, apiChannelName})->
     return "socialapi-\
@@ -103,23 +103,41 @@
     options.channelId = options.id
     @doRequest 'fetchChannelActivities', client, options, callback

-  @searchTopics = secure (client, options = {}, callback)->
-    @doRequest 'searchTopics', client, options, callback
+  # searchTopics - search topics for autocompletion
+  @searchTopics          = socialRequestWrapper fnName: 'searchTopics'

-  @fetchProfileFeed = secure (client, options = {}, callback)->
-    @doRequest 'fetchProfileFeed', client, options, callback
+  # fetchProfileFeed - lists all activities of an account
+  # within a specified group
+  @fetchProfileFeed      = socialRequestWrapper fnName: 'fetchProfileFeed'

-  @fetchPopularTopics = secure (client, options = {}, callback)->
-    @doRequest 'fetchPopularTopics', client, options, callback
+  # fetchPopularTopics - lists group specific popular topics
+  # it can be daily, weekly, monthly
+  @fetchPopularTopics    = socialRequestWrapper fnName: 'fetchPopularTopics'

-  @fetchPopularPosts = secure (client, options = {}, callback)->
-    @doRequest 'fetchPopularPosts', client, options, callback
+  # fetchPopularPosts -  lists group specific popular posts
+  # it can be daily, weekly, monthly
+  @fetchPopularPosts     = socialRequestWrapper fnName: 'fetchPopularPosts'

-  @fetchChannels = secure (client, options = {}, callback)->
-    @doRequest 'fetchGroupChannels', client, options, callback
+  # fetchChannels - lists group's topic channels
+  @fetchChannels         = socialRequestWrapper fnName: 'fetchGroupChannels'

-  @fetchFollowedChannels = secure (client, options = {}, callback)->
-    @doRequest 'fetchFollowedChannels', client, options, callback
+  # fetchFollowedChannels - lists followed channels(topics) of an account
+  @fetchFollowedChannels = socialRequestWrapper fnName: 'fetchFollowedChannels'
+
+  # follow - endpoint for users to follow topics
+  @follow = socialRequestWrapper
+    fnName  : 'followTopic'
+    validate: ["channelId"]
+
+  # unfollow - endpoint for users to give up following a channel
+  @unfollow = socialRequestWrapper
+    fnName  : 'unfollowTopic'
+    validate: ["channelId"]
+
+  # updateLastSeenTime - updates user's channel presence data
+  @updateLastSeenTime = socialRequestWrapper
+    fnName  : 'updateLastSeenTime'
+    validate: ["channelId"]

   @fetchPinnedMessages = permit 'pin posts',
     success: (client, options, callback)->
@@ -136,16 +154,6 @@
       unless options.messageId
         return callback {message: "Message id is not set for un-pinning "}
       @doRequest 'unpinMessage', client, options, callback
-
-  @follow = secure (client, options, callback)->
-    unless options.channelId
-      return callback {message: "Channel id is not set for following a topic"}
-    @doRequest 'followTopic', client, options, callback
-
-  @unfollow = secure (client, options, callback)->
-    unless options.channelId
-      return callback {message: "Channel id is not set for topic unfollowing"}
-    @doRequest 'unfollowTopic', client, options, callback

   @followUser = secure (client, options, callback)->
     {connection:{delegate}} = client


Much better and correct version of nickname link regexp

--- core/utils.coffee
+++ core/utils.coffee
@@ -96,7 +96,7 @@

   expandUsernames: (text) ->
     return null unless text
-    text.replace /\ [@]+[A-Za-z0-9-_]+/g, (u) ->
+    text.replace /\B\@([\w\-]+)/gim, (u) ->
       username = u.replace "@", ""
       u.link "#!/member/#{username}"


Use closure instead of reference

Use closure instead of reference

--- views/index.cjsx
+++ views/index.cjsx
@@ -103,8 +103,7 @@
   componentDidMount: ->
     window.addEventListener 'game.response', @handleResponse

-    _this = @
-    setTimeout ->
+    setTimeout =>
       # Read packets from disk.
       list = glob.sync(path.join(APPDATA, "*.json"))
       list.sort (a, b) ->     # Sort from newest to older
@@ -116,9 +115,9 @@
         break if packets.length >= MAX_PACKET_NUMBER

       # Update state with loaded packets.
-      {packetList, packetListNonce, battlePacket, battleNonce} = _this.state
+      {packetList, packetListNonce, battlePacket, battleNonce} = @state
       packetList = packetList.concat(packets).slice(0, MAX_PACKET_NUMBER)
-      _this.setState
+      @setState
         packetList: packetList
         packetListNonce: updateNonce packetListNonce
         battlePacket: packetList[0]


Parse non-derp way.

Parse non-derp way.

--- src/scripts/auth.coffee
+++ src/scripts/auth.coffee
@@ -33,7 +33,10 @@
   unless process.env.HUBOT_AUTH_ADMIN?
     robot.logger.warning 'The HUBOT_AUTH_ADMIN environment variable not set'

-  admins = (process.env.HUBOT_AUTH_ADMIN or []).split ','
+  if process.env.HUBOT_AUTH_ADMIN?
+    admins = process.env.HUBOT_AUTH_ADMIN.split ','
+  else
+    admins = []

   class Auth
     hasRole: (user, roles) ->


Moved exports to top of gocd.coffee.

Moved exports to top of gocd.coffee.

--- src/scripts/gocd.coffee
+++ src/scripts/gocd.coffee
@@ -29,6 +29,37 @@
   console.warn("hubot-gocd is not setup to fetch cctray.xml from a url (HUBOT_GOCI_CCTRAY_URL is empty)!")
 if not room?
   console.warn("hubot-gocd is not setup announce build notifications into a chat room (HUBOT_GITHUB_EVENT_NOTIFIER_ROOM is empty)!")
+
+module.exports = (robot) ->
+  robot.brain.data.gociProjects or= { }
+
+  updateBrain(robot)
+  startCronJob(robot)
+
+  robot.respond /build status/i, (msg) ->
+    buildStatus(robot, msg)
+
+  robot.respond /build details/i, (msg) ->
+    for project in _.values(robot.brain.data.gociProjects)
+      msg.send("#{project.name}(#{project.lastBuildLabel}: #{project.lastBuildStatus}")
+
+  # exported functions for testing
+  updateBrain: () ->
+    updateBrain(robot)
+
+  fetchAndCompare: (callback) ->
+    fetchAndCompareData robot, callback
+
+  buildStatus: (msg) ->
+    buildStatus(robot, msg)
+
+  startCronJob: () ->
+    startCronJob(robot)
+
+  cronTick: () ->
+    crontTick(robot)
+
+# private functions

 parseData = (robot, callback) ->
   cctrayUrl = process.env.HUBOT_GOCI_CCTRAY_URL
@@ -86,32 +117,3 @@
   parseData robot, (projects) ->
     robot.brain.data.gociProjects[project.name] = project for project in projects

-
-module.exports = (robot) ->
-  robot.brain.data.gociProjects or= { }
-
-  updateBrain(robot)
-  startCronJob(robot)
-
-  robot.respond /build status/i, (msg) ->
-    buildStatus(robot, msg)
-
-  robot.respond /build details/i, (msg) ->
-    for project in _.values(robot.brain.data.gociProjects)
-      msg.send("#{project.name}(#{project.lastBuildLabel}: #{project.lastBuildStatus}")
-
-  updateBrain: () ->
-    updateBrain(robot)
-
-
-  fetchAndCompare: (callback) ->
-    fetchAndCompareData robot, callback
-
-  buildStatus: (msg) ->
-    buildStatus(robot, msg)
-
-  startCronJob: () ->
-    startCronJob(robot)
-
-  cronTick: () ->
-    crontTick(robot)


700 milisecond delay between I found and whats found (preserves appropriate order in campfire)

--- src/scripts/spot.coffee
+++ src/scripts/spot.coffee
@@ -33,6 +33,8 @@

 URL = "#{process.env.HUBOT_SPOT_URL}"

+CAMPFIRE_CHRONOLOGICAL_DELAY = 700
+
 spotRequest = (message, path, action, options, callback) ->
   message.http("#{URL}#{path}")
     .query(options)[action]() (err, res, body) ->
@@ -108,8 +110,10 @@
   if not results or not results.length
     return message.send(':small_blue_diamond: I found nothin\'')
   explanations = (explain track for track in results)
-  message.send(':small_blue_diamond:')
-  message.send(render(explanations))
+  message.send(":small_blue_diamond: I found:")
+  setTimeout(() ->
+    message.send(render(explanations))
+  , CAMPFIRE_CHRONOLOGICAL_DELAY)

 calcLength = (seconds) ->
   iSeconds = parseInt(seconds, 10)
@@ -241,7 +245,9 @@
       track = JSON.parse(body)
       robot.brain.set('lastSingleQuery', track)
       message.send(":small_blue_diamond: I found:")
-      message.send(explain track)
+      setTimeout(() ->
+        message.send(explain track)
+      , CAMPFIRE_CHRONOLOGICAL_DELAY)

   robot.respond /,?\s*find ?(.*) (music|((songs|tracks)( of)?)) (.*)/i, (message) ->
     limit = determineLimit message.match[1]


Correction to assets

Correction to assets

--- packages/tower-generator/server/generators/tower/app/templates/config/assets.coffee
+++ packages/tower-generator/server/generators/tower/app/templates/config/assets.coffee
@@ -27,7 +27,7 @@
       '/vendor/javascripts/socket.io'
       '/vendor/javascripts/handlebars'
       '/vendor/javascripts/ember'
-      '/vendor/javascripts/jstorage.js'
+      '/vendor/javascripts/jstorage'
       '/vendor/javascripts/tower'
       # '/vendor/javascripts/uri'
       # '/vendor/javascripts/bootstrap/bootstrap-transition'


remove unused user read endpoint

remove unused user read endpoint

--- tutor/src/api/index.coffee
+++ tutor/src/api/index.coffee
@@ -9,7 +9,6 @@
   connectModelCreate, connectModelRead, connectModelUpdate, connectModelDelete
 } = require './adapter'

-{CurrentUserActions} = require '../flux/current-user'
 {CourseActions} = require '../flux/course'
 {CoursePracticeActions} = require '../flux/practice'
 {CourseGuideActions} = require '../flux/guide'
@@ -207,8 +206,6 @@
     data: (id, answerId) ->
       {answer_id: answerId}
   )
-
-  connectRead(CurrentUserActions, url: 'user')

   connectRead(OfferingsActions, url: 'offerings')
   connectRead(PastTaskPlansActions, (courseId) ->


activity: use `ActivityLikeLink` class instead of deprecated `ActivityActionLink`

--- client/Social/Activity/views/likeview.coffee
+++ client/Social/Activity/views/likeview.coffee
@@ -18,7 +18,7 @@
         title     : ""
     , data

-    @likeLink = new ActivityActionLink partial: "Like"
+    @likeLink = new ActivityLikeLink {}, data

     {useTitle}     = @getOptions()
     {isInteracted} = data.interactions.like


flux: minor changes for teammembers

flux: minor changes for teammembers

--- client/app/lib/flux/stores/usersstore.coffee
+++ client/app/lib/flux/stores/usersstore.coffee
@@ -42,10 +42,10 @@
    * @param {Immutable.Map} users
    * @param {object} user
   ###
-
   handleDeleteTeamMember: (users, userId) ->

     return users.delete userId
+

   ###*
    * Handler for UPDATE_TEAM_MEMBER action.
@@ -54,9 +54,9 @@
    * @param {Immutable.Map} users
    * @param {object} user
   ###
-  handleUpdateTeamMember: (users, user) ->
-
-    return users.set user.get('id'), user
+  handleUpdateTeamMember: (users, { account }) ->
+
+    return users.set account.get('id'), account

   ###*


server: fix typo in import statement

server: fix typo in import statement

--- servers/sourcemaps/main.coffee
+++ servers/sourcemaps/main.coffee
@@ -1,6 +1,6 @@
 express = require 'express'

-KONFIG = require 'koding-config-manage'
+KONFIG = require 'koding-config-manager'

 process.title = 'koding-sourcemapserver'


reindent

reindent

--- app/generator.coffee
+++ app/generator.coffee
@@ -6,190 +6,191 @@
 path     = require 'path'

 module.exports = class FixatePwGenerator extends yeoman.generators.Base
-	constructor: (args, options, config) ->
-		super args, options, config
+  constructor: (args, options, config) ->
+    super args, options, config

-		@on "end", ->
-			@installDependencies skipInstall: options["skip-install"]
+    @on "end", ->
+      @installDependencies skipInstall: options["skip-install"]

-		@pkg = myUtils.loadJSON("../package.json", __dirname)
-		@settings = myUtils.loadJSON("./settings.json", __dirname)
+    @pkg = myUtils.loadJSON("../package.json", __dirname)
+    @settings = myUtils.loadJSON("./settings.json", __dirname)

-	askFor: () =>
-		cb = @async()
+  askFor: () =>
+    cb = @async()

-		#*------------------------------------*\
-		#   $YEOMAN PROMPTS
-		#*------------------------------------*/
-		console.log @yeoman
-		prompts = []
-		prompts.push
-			name: "pwBranch"
-			message: "Which branch of ProcessWire would you like to use?"
-			default: "master"
+    #*------------------------------------*\
+    #   $YEOMAN PROMPTS
+    #*------------------------------------*/
+    console.log @yeoman
+    prompts = []
+    prompts.push
+      name: "pwBranch"
+      message: "Which branch of ProcessWire would you like to use?"
+      default: "master"

-		prompts.push
-			name: "cssBranch"
-			message: "Which branch of the CSS Framework would you like to use?"
-			default: 'inuit'
+    prompts.push
+      name: "cssBranch"
+      message: "Which branch of the CSS Framework would you like to use?"
+      default: 'inuit'

-		prompts.push
-			name: "domain"
-			message: "What is the domain name for the production website (without protocol)?"
-			default: "example.com"
+    prompts.push
+      name: "domain"
+      message: "What is the domain name for the production website (without protocol)?"
+      default: "example.com"

-		@prompt prompts, (props) =>
-			@props = props
-			cb()
+    @prompt prompts, (props) =>
+      @props = props
+      cb()

-	app: () =>
-		github = (repo) ->
-			"https://github.com/#{repo}.git"
+  app: () =>
+    github = (repo) ->
+      "https://github.com/#{repo}.git"

-		dest = (p = '/') =>
-			path.join(@destinationRoot(), p)
+    dest = (p = '/') =>
+      path.join(@destinationRoot(), p)

-		at = (p, cb) ->
-			try
-				shell.pushd p
-				cb()
-			finally
-				shell.popd()
+    at = (p, cb) ->
+      try
+        shell.pushd p
+        cb()
+      finally
+        shell.popd()

-		#*------------------------------------*\
-		#   $REPOSITORY
-		#*------------------------------------*/
-		setupRepo = () =>
-			@mkdir d for d in [
-				'src',
-				'database/dev',
-				'database/prod',
-				'styleguide'
-			]
+    #*------------------------------------*\
+    #   $REPOSITORY
+    #*------------------------------------*/
+    setupRepo = () =>
+      @mkdir d for d in [
+        'src',
+        'database/dev',
+        'database/prod',
+        'styleguide'
+      ]

-			@copy ".bowerrc",             ".bowerrc"
-			@copy ".gitignore",           ".gitignore"
-			@copy ".gitattributes",       ".gitattributes"
-			@copy ".gitkeep",             "database/dev/.gitkeep"
-			@copy ".gitkeep",             "database/prod/.gitkeep"
-			@copy "private-sample.json",  "private-sample.json"
-			@copy "private-sample.json",  "private.json"
-			@template "_package.json",    "package.json"
-			@template "_gulpconfig.json", "gulpconfig.json"
-			@template "_robots.txt",      "src/robots.txt"
+      @copy ".bowerrc",             ".bowerrc"
+      @copy ".gitattributes",       ".gitattributes"
+      @copy "_gitignore",           ".gitignore"
+      @copy ".gitkeep",             "database/dev/.gitkeep"
+      @copy ".gitkeep",             "database/prod/.gitkeep"
+      @copy "setup.sh",             "setup.sh"
+      @copy "private-sample.json",  "private-sample.json"
+      @copy "private-sample.json",  "private.json"
+      @template "_package.json",    "package.json"
+      @template "_gulpconfig.json", "gulpconfig.json"
+      @template "_robots.txt",      "src/robots.txt"

-		#*------------------------------------*\
-		#   $PROCESSWIRE
-		#*------------------------------------*/
-		setupProcesswire = () =>
-			@log.info "Installing ProcessWire..."
-			repo_path = GitUtils.cacheRepo github(@settings.github.processwire)
-			@log.info "Copying ProcessWire install..."
-			GitUtils.export repo_path, dest('src/'), @props.pwBranch
+    #*------------------------------------*\
+    #   $PROCESSWIRE
+    #*------------------------------------*/
+    setupProcesswire = () =>
+      @log.info "Installing ProcessWire..."
+      repo_path = GitUtils.cacheRepo github(@settings.github.processwire)
+      @log.info "Copying ProcessWire install..."
+      GitUtils.export repo_path, dest('src/'), @props.pwBranch

-			at dest('/'), ->
-				shell.mv "src/site-default", "src/site"
+      at dest('/'), ->
+        shell.mv "src/site-default", "src/site"

-			@log.ok('OK')
+      @log.ok('OK')

-			@log.info "Installing ProcessWire MVC boilerplate..."
-			repo_path = GitUtils.cacheRepo github(@settings.github.pwBoilerplate)
-			GitUtils.export repo_path, dest('src/site/templates')
-			at dest('src/'), () =>
-				shell.ls('-A', "site/templates/\!root/*").forEach (file) ->
-					shell.mv '-f', file, '.'
-				shell.rm '-rf', "site/templates/\!root"
-				shell.rm ".gitignore"
-				shell.rm "robots.txt"
+      @log.info "Installing ProcessWire MVC boilerplate..."
+      repo_path = GitUtils.cacheRepo github(@settings.github.pwBoilerplate)
+      GitUtils.export repo_path, dest('src/site/templates')
+      at dest('src/'), () =>
+        shell.ls('-A', "site/templates/\!root/*").forEach (file) ->
+          shell.mv '-f', file, '.'
+        shell.rm '-rf', "site/templates/\!root"
+        shell.rm ".gitignore"
+        shell.rm "robots.txt"

-			# remove default ProcessWire templates
-			at dest('src/site/templates/'), () =>
-				shell.rm '-rf', "scripts"
-				shell.rm '-rf', "styles"
-				shell.rm "README.txt"
-				shell.rm "basic-page.php"
-				shell.rm "search.php"
-				shell.rm "sitemap.php"
-				shell.rm "home.php"
-				shell.rm "_init.php"
-				shell.rm "_main.php"
-				shell.rm "_func.php"
+      # remove default ProcessWire templates
+      at dest('src/site/templates/'), () =>
+        shell.rm '-rf', "scripts"
+        shell.rm '-rf', "styles"
+        shell.rm "README.txt"
+        shell.rm "basic-page.php"
+        shell.rm "search.php"
+        shell.rm "sitemap.php"
+        shell.rm "home.php"
+        shell.rm "_init.php"
+        shell.rm "_main.php"
+        shell.rm "_func.php"

-			# remove alternative ProcessWire site profiles
-			at dest('src/'), () =>
-				shell.rm '-rf', "site-beginner"
-				shell.rm '-rf', "site-blank"
-				shell.rm '-rf', "site-classic"
-				shell.rm '-rf', "site-languages"
+      # remove alternative ProcessWire site profiles
+      at dest('src/'), () =>
+        shell.rm '-rf', "site-beginner"
+        shell.rm '-rf', "site-blank"
+        shell.rm '-rf', "site-classic"
+        shell.rm '-rf', "site-languages"

-			# ensure processwire assets are committed
-			@copy ".gitkeep", "src/site/assets/cache/.gitkeep"
-			@copy ".gitkeep", "src/site/assets/sessions/.gitkeep"
-			@copy ".gitkeep", "src/site/assets/files/.gitkeep"
-			@copy ".gitkeep", "src/site/assets/logs/.gitkeep"
+      # ensure processwire assets are committed
+      @copy ".gitkeep", "src/site/assets/cache/.gitkeep"
+      @copy ".gitkeep", "src/site/assets/sessions/.gitkeep"
+      @copy ".gitkeep", "src/site/assets/files/.gitkeep"
+      @copy ".gitkeep", "src/site/assets/logs/.gitkeep"

-			# setup for ProcessWire install
-			at dest('src/site/'), () =>
-				shell.chmod '777', "assets"
-				shell.chmod '777', "assets/*"
-				shell.chmod '777', "modules"
-				shell.chmod '777', "config.php"
+      # setup for ProcessWire install
+      at dest('src/site/'), () =>
+        shell.chmod '777', "assets"
+        shell.chmod '777', "assets/*"
+        shell.chmod '777', "modules"
+        shell.chmod '777', "config.php"

-			@log.ok('OK')
+      @log.ok('OK')

-		#*------------------------------------*\
-		#   $KSS BOILERPLATE
-		#*------------------------------------*/
-		setupKSS = () =>
-			@log.info "Installing KSS Boilerplate"
-			repo_path = GitUtils.cacheRepo github(@settings.github.kssBoilerplate)
-			@mkdir 'styleguide'
-			GitUtils.export repo_path, dest('styleguide/')
-			at dest('styleguide/'), () =>
-				@log.info 'KSS Living Styleguide - bundle install'
-				GitUtils.exec 'bundle install'
-				shell.mv '-f', './scss', '../src/site/templates/assets/css'
+    #*------------------------------------*\
+    #   $KSS BOILERPLATE
+    #*------------------------------------*/
+    setupKSS = () =>
+      @log.info "Installing KSS Boilerplate"
+      repo_path = GitUtils.cacheRepo github(@settings.github.kssBoilerplate)
+      @mkdir 'styleguide'
+      GitUtils.export repo_path, dest('styleguide/')
+      at dest('styleguide/'), () =>
+        @log.info 'KSS Living Styleguide - bundle install'
+        GitUtils.exec 'bundle install'
+        shell.mv '-f', './scss', '../src/site/templates/assets/css'

-			@log.ok('OK')
+      @log.ok('OK')

-		#*------------------------------------*\
-		#   $CSS FRAMEWORK
-		#*------------------------------------*/
-		setupCSSFramework = () =>
-			@log.info "Installing CSS framework..."
+    #*------------------------------------*\
+    #   $CSS FRAMEWORK
+    #*------------------------------------*/
+    setupCSSFramework = () =>
+      @log.info "Installing CSS framework..."

-			repo_path = GitUtils.cacheRepo github(@settings.github.cssFramework)
-			GitUtils.export repo_path, dest('styleguide/'), @props.cssBranch
+      repo_path = GitUtils.cacheRepo github(@settings.github.cssFramework)
+      GitUtils.export repo_path, dest('styleguide/'), @props.cssBranch

-			at dest('styleguide/'), ->
-				shell.mv "style.css", "../src/site/templates/assets/css/style.css"
-				shell.rm "style.css"
+      at dest('styleguide/'), ->
+        shell.mv "style.css", "../src/site/templates/assets/css/style.css"
+        shell.rm "style.css"

-			@log.ok('OK')
+      @log.ok('OK')

-		#*------------------------------------*\
-		#   $GIT
-		#*------------------------------------*/
-		setupGit = () =>
-			GitUtils.init(dest())
+    #*------------------------------------*\
+    #   $GIT
+    #*------------------------------------*/
+    setupGit = () =>
+      GitUtils.init(dest())

-		#*------------------------------------*\
-		#   $DO IT
-		#*------------------------------------*/
-		setupRepo()
-		setupProcesswire()
-		setupKSS()
-		setupCSSFramework()
-		setupGit()
+    #*------------------------------------*\
+    #   $DO IT
+    #*------------------------------------*/
+    setupRepo()
+    setupProcesswire()
+    setupKSS()
+    setupCSSFramework()
+    setupGit()

-	projectfiles: () =>
-		@copy "_gulpfile.coffee", "gulpfile.coffee"
-		@copy ".editorconfig", ".editorconfig"
+  projectfiles: () =>
+    @copy "_gulpfile.coffee", "gulpfile.coffee"
+    @copy ".editorconfig", ".editorconfig"


Update nl.coffee

Update nl.coffee


Update nl.coffee

Update nl.coffee

To check the coverage

--- app/locale/nl.coffee
+++ app/locale/nl.coffee
@@ -63,6 +63,7 @@
     view_progress: "Bekijk voortgang"
     go_to_courses: "Ga naar mijn cursussen"
     want_coco: "Wil je CodeCombat op jouw school?"
+

   nav:
     play: "Levels" # The top nav bar entry where players choose which levels to play