Use stable API

Use stable API

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,7 +1,7 @@
 module.exports = (grunt) ->
   pkg = grunt.file.readJSON('package.json')

-  environment = process.env.VTEX_HOST or 'vtexcommerce'
+  environment = process.env.VTEX_HOST or 'vtexcommercestable'

   verbose = grunt.option('verbose')


update gruntfile task

update gruntfile task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -40,4 +40,4 @@
   grunt.loadNpmTasks 'grunt-contrib-jshint'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   # Custom tasks
-  grunt.registerTask 'default',['watch']
+  grunt.registerTask 'default',['clean','coffee','jshint','uglify']


JSlove entfernt

JSlove entfernt

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -43,14 +43,6 @@
 			working: [
 				'<%= settings.tempDirectory %>'
 				'<%= settings.distDirectory %>'
-			]
-			# Used for those that desire plain old JavaScript
-			jslove: [
-				'**/*.coffee'
-				'!**/.components/**'
-				'!**/.temp/**'
-				'!**/bower_components/**'
-				'!**/node_modules/**'
 			]

 		# Compiles CoffeeScript (.coffee) files to JavaScript (.js)
@@ -255,25 +247,6 @@
 					'.temp/scripts/views.js': '.temp/**/*.html'
 				options:
 					trim: '<%= settings.tempDirectory %>'
-
-		prompt:
-			jslove:
-				options:
-					questions: [
-						{
-							config: 'coffee.jslove.compile'
-							type: 'input'
-							message: 'Are you sure you wish to convert all CoffeeScript (.coffee) files to JavaScript (.js)?' + '\n' + 'This cannot be undone.'.red + ': (y/N)'
-							default: false
-							filter: (input) ->
-								confirmed = /^y(es)?/i.test input
-
-								if not confirmed
-									grunt.fatal 'exiting jslove'
-
-								return confirmed
-						}
-					]

 		# RequireJS optimizer configuration for both scripts and styles
 		# This configuration is only used in the 'prod' build
@@ -586,13 +559,3 @@
 		'build'
 		'karma'
 	]
-
-	# Compiles all CoffeeScript files in the project to JavaScript then deletes all CoffeeScript files
-	# Used for those that desire plain old JavaScript
-	# Enter the following command at the command line to execute this build task:
-	# grunt jslove
-	grunt.registerTask 'jslove', [
-		'prompt:jslove'
-		'coffee:jslove'
-		'clean:jslove'
-	]


added SauceLab tags

added SauceLab tags

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -142,11 +142,17 @@
         options:
           urls: ["http://127.0.0.1:9999/pub/test/browser/index.html"],
           tunnelTimeout: 5,
-          build: process.env.TRAVIS_JOB_ID,
+          build: process.env.TRAVIS_BUILD_NUMBER,
           concurrency: 2,
           browsers: browsers,
           testname: "chai-counter browser tests",
-          tags: ["master"]
+          tags: [
+            "TRAVIS_JOB_ID: " + process.env.TRAVIS_JOB_ID,
+            "TRAVIS_JOB_NUMBER: " + process.env.TRAVIS_JOB_NUMBER,
+            "TRAVIS_BUILD_ID: " + process.env.TRAVIS_BUILD_ID,
+            "TRAVIS_BUILD_NUMBER: " + process.env.TRAVIS_BUILD_NUMBER,
+            "TRAVIS_REPO_SLUG: " + process.env.TRAVIS_REPO_SLUG
+          ]
     'watch': {}

   # loading dependencies


grunt `quickbuild` task added: does not check generated lib files through JSHint nor does it run the tests: this is used to generate 'known/probably broken' `c3.js` files used for testing/debugging particular issues where we don't want to be be bothered with `grunt --force` and the additional cost/time it takes to run the checks we know will report (*other*) issues anyway.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -133,6 +133,7 @@
 # dependencies:
     grunt.registerTask 'build', ['concat', 'jshint', 'jasmine', 'sass', 'cssmin', 'uglify', 'karma']
     grunt.registerTask 'update_web', ['build', 'copy:web']
+    grunt.registerTask 'quickbuild', ['concat', 'copy:web', 'cssmin', 'uglify']

 # main / default:
     grunt.registerTask 'default', ['update_web']


Also clean the output folder

Also clean the output folder

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

   grunt.initConfig
     pkg: grunt.file.readJSON 'package.json'
-    clean: ['build']
+    clean: ['build', 'output']
     coffee:
       build:
         files: [


Better commit message for deploys

Better commit message for deploys

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -2,9 +2,10 @@
 path = require 'path'

 module.exports = ->
+  pkg = @file.readJSON 'package.json'
   # Project configuration
   @initConfig
-    pkg: @file.readJSON 'package.json'
+    pkg: pkg

     # CoffeeScript compilation
     coffee:
@@ -61,11 +62,13 @@
     'gh-pages':
       options:
         base: 'dist/',
+        clone: 'gh-pages'
+        message: "Release #{pkg.name} #{process.env.TRAVIS_TAG}"
+        repo: 'https://' + process.env.GH_TOKEN + '@github.com/flowbased/fbp-protocol.git'
         user:
           name: 'fbp-protocol bot',
           email: 'jononor+fbpprotocolbot@gmail.com'
         silent: true
-        repo: 'https://' + process.env.GH_TOKEN + '@github.com/flowbased/fbp-protocol.git'
       src: '**/*'

   # Grunt plugins used for testing


Fixed Gruntfile.coffee

Fixed Gruntfile.coffee

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -92,7 +92,7 @@
           dest: '<%= path.dist %>/fonts/'
         ,
           expand: true
-          cwd: 'bower_modules/jquery/'
+          cwd: 'bower_modules/jquery/dist/'
           src: ['jquery.min.js']
           dest: '<%= path.dist %>/js/'
         ,


chore(Gruntfile.coffee): add version:release task to remove pre-release version suffix

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -577,6 +577,10 @@
                 options:
                     release: 'build'
                 src: fineUploaderModules.modules.versioned
+            release:
+                options:
+                    release: pkg.version.replace /-\d+$/, ""
+                src: fineUploaderModules.modules.versioned

         watch:
             options:


Server: create session when request is valid

--- servers/lib/server/handlers/api/ssotokenlogin.coffee
+++ servers/lib/server/handlers/api/ssotokenlogin.coffee
@@ -11,14 +11,14 @@

   { JUser, JSession, JAccount } = (require '../../bongo').models

-  { token } = req.body
+  { token } = req.query
   user      = null
   group     = null
   account   = null
   username  = null

   unless token
-    return res.status(400).send 'invalid request'
+    return res.status(400).send 'token is required'

   queue = [

@@ -26,6 +26,11 @@
       validateToken token, (err, data) ->
         return res.status(err.statusCode).send(err.message)  if err
         { username, group } = data
+
+        # making sure subdomain is same with group slug
+        unless group in req.subdomains
+          return res.status(400).send('invalid request')
+
         queue.next()

     ->
@@ -45,12 +50,13 @@
         queue.next()

     ->
-      JSession.createNewSession { username, groupName }, (err, session) ->
+      # creating a user session for the group if everything is ok
+      JSession.createNewSession { username, groupName : group }, (err, session) ->
         return res.status(500).send 'an error occurred'         if err
         return res.status(500).send 'failed to create session'  unless session

         setSessionCookie res, session.clientId
-        res.status(200)
+        res.redirect('/')

   ]


fix broken css (#1865)

fix broken css (#1865)

--- app/assets/javascripts/avalon_player.js.coffee
+++ app/assets/javascripts/avalon_player.js.coffee
@@ -103,7 +103,7 @@
             marker_id = $(this)[0].dataset['marker']
             title = String($(this).find('.marker_title')[0].text).replace(/"/g, '"') + " ["+mejs.Utility.secondsToTimeCode(offset)+"]"
             offset_percent = if isNaN(parseFloat(offset)) then 0 else Math.min(1, offset / duration)
-            offset = $('.mejs-time-total').width() * offset_percent
+            offset = Math.round($('.mejs-time-total').width() * offset_percent)+'px'
             scrubber.append('')
         @player.setCurrentTime initialTime


Fix not highlighting below current buffer in different panes

--- lib/highlighted-area-view.coffee
+++ lib/highlighted-area-view.coffee
@@ -109,8 +109,6 @@
     if atom.config.get('highlight-selected.ignoreCase')
       regexFlags = 'gi'

-    range =  [[0, 0], editor.getEofBufferPosition()]
-
     @ranges = []
     regexSearch = result[0]

@@ -137,6 +135,9 @@
     markerLayerForHiddenMarkers = editor.addMarkerLayer()
     @markerLayers.push(markerLayer)
     @markerLayers.push(markerLayerForHiddenMarkers)
+
+    range =  [[0, 0], editor.getEofBufferPosition()]
+
     editor.scanInBufferRange new RegExp(regexSearch, regexFlags), range,
       (result) =>
         @resultCount += 1


Added search to the get tabs.

Added search to the get tabs.

--- app/assets/javascripts/docker/docker.js.coffee
+++ app/assets/javascripts/docker/docker.js.coffee
@@ -5,6 +5,7 @@
     @slideInit()
     @tabCollapseInit()
     @tabGetInit()
+    @tabGetSearchInit()

   dockHtml: ->
     "

@@ -28,6 +29,7 @@
       "

+          <input type=\"text\" name=\"search\" class=\"dock-tab-content-search\" placeholder=\"Search\" style=\"width: 100%;\">

@@ -57,6 +59,12 @@
           $.each fieldNames, (i, name) ->
             dataAppend = dataAppend.replace("%#{i}", res[name]);
           $(self).append(dataAppend)
+
+  tabGetSearchInit: ->
+    @slideMenu().on 'keyup', '.dock-tab-content-search', ->
+      query = $(@).val()
+      $(@).siblings('div').children().show()
+      $(@).siblings('div').children().not(":contains('#{query}')").hide()

   slideMenu: ->
     $('.slideout-menu')


glob pattern to jade/html tasks

glob pattern to jade/html tasks

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -53,13 +53,31 @@
           # you can provide specfic content to a template by using the src, dest params
           data: (src, dest) ->
             require './data/content.json'
-        files:
-          'build/index.html': 'src/index.jade'
+        files: [
+          expand: true
+          src: 'pages/**/*.jade'
+          dest: 'build/'
+          cwd: 'src/views'
+          ext: '.html'
+          rename: (src, dest) ->
+            dest = dest.split('/')
+            dest.shift()
+            src + dest.join('/')
+        ]
       release:
         options:
           pretty: false
-        files:
-          'release/index.html': 'relase/index.jade'
+        files: [
+          expand: true
+          src: 'pages/**/*.jade'
+          dest: 'release/'
+          cwd: 'src/views'
+          ext: '.html'
+          rename: (src, dest) ->
+            dest = dest.split('/')
+            dest.shift()
+            src + dest.join('/')
+        ]

     # Less
     less:
@@ -158,8 +176,12 @@
       dist:
         options:
           process: true
-        files:
-          'release/index.html': ['release/index.html']
+        files: [
+          expand: true
+          src: '**/*.html'
+          dest: 'release/'
+          cwd: 'release/'
+        ]

     # Compress HTML
     htmlmin:
@@ -168,8 +190,12 @@
           removeComments: true
           collapseWhitespace: true
           removeCommentsFromCDATA: true
-        files:
-          'release/index.html': 'relase/index.html'
+        files: [
+          expand: true
+          src: '**/*.html'
+          dest: 'release/'
+          cwd: 'release/'
+        ]

     # Compress Images
     imagemin:


Update browser versions to test against

Update browser versions to test against

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -74,13 +74,13 @@
             ,
               browserName: 'safari'
               platform: 'OS X 10.8'
-              version: '6'
+              version: '7'
             ,
               browserName: 'opera'
             ,
               browserName: 'internet explorer'
               platform: 'WIN8'
-              version: '10'
+              version: '11'
           ]
           build: process.env.TRAVIS_JOB_ID
           testname: 'Create.js cross-browser tests'


Fix grunt task name

Fix grunt task name

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

   grunt.registerTask "build", ["clean", "compile", "copy:dist"]

-  grunt.registerTask "dist", ["deploy", "connect:dist", "open", "watch"]
+  grunt.registerTask "dist", ["build", "connect:dist", "open", "watch"]

   grunt.registerTask "compile", ["coffee:dev","typescript:dev", "sass:dev", "less:dev", "stylus:dev"]


fuss fix jquery path

fuss fix jquery path

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -66,7 +66,7 @@
           styles: 'dist/css/<%= pkg.name %>.css',
           specs: 'spec/build/javascripts/*.spec.js',
           vendor: [
-            'bower_components/jquery/dist/jquery.js',
+            'bower_components/jQuery/dist/jquery.js',
             'bower_components/Caret.js/src/*.js'
           ],
           helpers: [


compile the new module folders

compile the new module folders

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -16,6 +16,8 @@
             'coffeescript/love.js/*.coffee',
             'coffeescript/love.js/audio/*.coffee',
             'coffeescript/love.js/graphics/*.coffee',
+            'coffeescript/love.js/filesystem/*.coffee',
+            'coffeescript/love.js/image/*.coffee',
           ]
     concat:
       banner:


Fix clean task

Fix clean task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -28,7 +28,8 @@
     # Tasks
     ###

-    clean:          '<%= dirs.dist %>'
+    clean:
+      dist:         '<%= dirs.dist %>'

     watch:


Remove css banner; isn't served anyhow

Remove css banner; isn't served anyhow

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -71,8 +71,6 @@
           'build/css/framed_controls.css': ['build/css/framed_controls_without_embeds.css']
     cssmin:
       build:
-        options:
-          banner: banner_template
         expand: true
         cwd: 'build/css/'
         dest: 'build/css/'


load grunt-coffee task

load grunt-coffee task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -180,10 +180,12 @@
   # authors task
   grunt.loadNpmTasks "grunt-git-authors"
   grunt.loadNpmTasks "grunt-junit"
+  grunt.loadNpmTasks "grunt-coffee"

   # Ease of use aliases for users who want the zip and docs
   grunt.registerTask "docs", "js css legacy_tasks:docs"
   grunt.registerTask "zip", "js css legacy_tasks:zip"
+

   # load the project's default tasks
   grunt.loadTasks "build/tasks"


complete Gruntfile

complete Gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,8 +1,3 @@
-# [Template](http://template-extension.org)
-# (c) 2013 Alasdair Mercer
-# Freely distributable under the MIT license:
-# <http://template-extension.org/license>
-
 module.exports = (grunt) ->

   # Configuration
@@ -15,10 +10,12 @@
     pkg

     clean:
-      build:     'bin/*'
+      build: 'bin/*'

-      dist:      ['dist/*', 'docs/*']
+      dist:      'dist/*'
       distAfter: 'dist/temp/'
+
+      docs: 'docs/*'

     compress:
       dist:
@@ -125,15 +122,18 @@
   ]

   grunt.registerTask 'dist', [
-    'build'
     'clean:dist'
-    'docco'
     'copy:dist'
     'locale-prepare'
     'json-minify'
     'uglify'
     'compress'
     'clean:distAfter'
+  ]
+
+  grunt.registerTask 'docs', [
+    'clean:docs'
+    'docco'
   ]

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


Use relative path for replace

Use relative path for replace

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

     files: ["build/#{relativePath}/index.html", "build/#{relativePath}/#{relativePath}/index.html"]

-  transform.replace["/admin/#{pkg.name}/"] = "//io.vtex.com.br/#{pkg.name}/#{pkg.version}/"
+  transform.replace["/#{relativePath}/"] = "//io.vtex.com.br/#{pkg.name}/#{pkg.version}/"

   deploy = ->
     done = @async()


Try another attempt

Try another attempt

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -89,30 +89,9 @@
                     timestamp: true
                     exclude: [
                       'bower_components/reveal.js/plugin/leap'
-                      'bower_components/reveal.js/plugin/leap/leap.js'
                       'bower_components/reveal.js/test'
-                      'bower_components/reveal.js/test/examples'
-                      'bower_components/reveal.js/test/examples/assets'
-                      'bower_components/reveal.js/test/examples/assets/image1.png'
-                      'bower_components/reveal.js/test/examples/assets/image2.png'
-                      'bower_components/reveal.js/test/examples/barebones.html'
-                      'bower_components/reveal.js/test/examples/embedded-media.html'
-                      'bower_components/reveal.js/test/examples/math.html'
-                      'bower_components/reveal.js/test/examples/slide-backgrounds.html'
-                      'bower_components/reveal.js/test/qunit-1.12.0.css'
-                      'bower_components/reveal.js/test/qunit-1.12.0.js'
-                      'bower_components/reveal.js/test/test-markdown-element-attributes.html'
-                      'bower_components/reveal.js/test/test-markdown-element-attributes.js'
-                      'bower_components/reveal.js/test/test-markdown-slide-attributes.html'
-                      'bower_components/reveal.js/test/test-markdown-slide-attributes.js'
-                      'bower_components/reveal.js/test/test-markdown.html'
-                      'bower_components/reveal.js/test/test-markdown.js'
-                      'bower_components/reveal.js/test/test.html'
-                      'bower_components/reveal.js/test/test.js'
                       'bower_components/reveal.js/plugin/math'
-                      'bower_components/reveal.js/plugin/math/math.js'
                       'bower_components/reveal.js/plugin/print-pdf'
-                      'bower_components/reveal.js/plugin/print-pdf/print-pdf.js'
                     ]
                 src: [
                     'css/**'


Added null check to formatResult (#46)

Added null check to formatResult (#46)

--- app/assets/javascripts/utils/helpers.js.coffee
+++ app/assets/javascripts/utils/helpers.js.coffee
@@ -41,12 +41,11 @@
   @param {Result} input - the result object to be parsed into a Quantity
   @returns cql.Quantity
   ###
-
   @formatResult: (input) ->
     if input
       if input.codes?
-        code_system = Object.keys(input.codes)[0]
-        code = input.codes[code_system][0]
+        code_system = Object.keys(input.codes)?[0]
+        code = input.codes[code_system]?[0]
         new cql.Code(code, code_system)
       # Check that the scalar portion is a number and the units are a non-zero length string.
       else if (input.scalar.match(/^[-+]?[0-9]*\.?[0-9]+$/) != null)


update Gruntfile, remove some code for ancient browsers by default

disable support for IE6/7, old Gecko, old Webkit
add example for este demo apps compilation

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -115,21 +115,49 @@
           '--output_wrapper="(function(){%output%})();"'
           '--compilation_level="ADVANCED_OPTIMIZATIONS"'
           '--warning_level="VERBOSE"'
-          '--define=goog.DEBUG=true'
           '--debug=true'
           '--formatting="PRETTY_PRINT"'
+          '--define=goog.DEBUG=true'
         ]
         else [
           '--output_wrapper="(function(){%output%})();"'
           '--compilation_level="ADVANCED_OPTIMIZATIONS"'
           '--warning_level="VERBOSE"'
           '--define=goog.DEBUG=false'
+          # disable support for IE6/7, old Gecko, old Webkit
+          '--define=goog.net.XmlHttp.ASSUME_NATIVE_XHR=true'
+          '--define=goog.style.GET_BOUNDING_CLIENT_RECT_ALWAYS_EXISTS=true'
+          '--define=este.json.SUPPORTS_NATIVE_JSON=true'
         ]

       app:
         options:
           namespace: 'app.start'
           outputFilePath: 'client/app/build/app.js'
+
+      # este.App demos compilation examples.
+      # todomvc:
+      #   options:
+      #     namespace: 'este.demos.app.todomvc.start'
+      #     outputFilePath: 'client/app/build/app_todomvc.js'
+
+      # simple:
+      #   options:
+      #     namespace: 'este.demos.app.simple.start'
+      #     outputFilePath: 'client/app/build/app_simple.js'
+
+      # layout:
+      #   options:
+      #     namespace: 'este.demos.app.layout.start'
+      #     outputFilePath: 'client/app/build/app_layout.js'
+
+      # Use this task to build all languages, /client/build/app_de.js etc.
+      # appLocalized:
+      #   options:
+      #     namespace: 'app.start'
+      #     outputFilePath: 'client/app/build/app.js'
+      #     messagesPath: 'messages/app'
+      #     locales: ['cs', 'de']

     esteUnitTests:
       options:


fix bug where event was getting bound multiple times

--- app/assets/javascripts/widget_editor.js.coffee
+++ app/assets/javascripts/widget_editor.js.coffee
@@ -40,9 +40,9 @@
     evt.target.submit()

   bind_events: ->
-    @$new_button.on 'click', @new_widget
-    @$editor.parents('form').on 'submit', @remove_library
-    @$editor.find(@delete_button).on 'click', @delete_widget
-    @$editor.find(@undelete_button).on 'click', @undelete_widget
+    @$new_button.off().on 'click', @new_widget
+    @$editor.parents('form').off().on 'submit', @remove_library
+    @$editor.find(@delete_button).off().on 'click', @delete_widget
+    @$editor.find(@undelete_button).off().on 'click', @undelete_widget

 window.WidgetEditor = WidgetEditor


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'])


Fix manifest to refer to subdirectory

Fix manifest to refer to subdirectory

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -39,7 +39,7 @@
         options:
           replacements: [
             pattern: '<html>'
-            replacement: '<html manifest="/manifest.appcache">'
+            replacement: '<html manifest="/noflo-browser/manifest.appcache">'
           ]

     'gh-pages':


Run set-development-version task during ci task

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

   grunt.registerTask('compile', ['coffee', 'less', 'cson'])
   grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
-  grunt.registerTask('ci', ['lint', 'partial-clean', 'update-atom-shell', 'build', 'test'])
+  grunt.registerTask('ci', ['lint', 'partial-clean', 'update-atom-shell', 'build', 'set-development-version', 'test'])
   grunt.registerTask('deploy', ['partial-clean', 'update-atom-shell', 'build', 'codesign'])
   grunt.registerTask('default', ['update-atom-shell', 'build', 'set-development-version', 'install'])


fix config for ie.styl files

fix config for ie.styl files

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -114,8 +114,10 @@
         src: [
           'lib/normalize-css/normalize.css',
           'blocks/i-reset/i-reset.css',
-          'lib/**/*!(.ie).css',
+          'lib/**/*.css',
+          '!lib/**/*.ie.css',
           'blocks/b-*/**/*.css',
+          '!blocks/b-*/**/*.ie.css',
           '!blocks/i-*/'
         ]
         dest: 'publish/style.css'
@@ -164,8 +166,17 @@
           livereload: true
         files: [
           'blocks/**/*.styl',
-        ]
-        tasks: ['stylus:dev', 'stylus:dev_ie', 'concat:css', 'concat:css_ie']
+          '!blocks/**/*.ie.styl'
+        ]
+        tasks: ['stylus:dev', 'concat:css']
+
+      stylus_ie:
+        options:
+          livereload: true
+        files: [
+          'blocks/**/*.ie.styl',
+        ]
+        tasks: ['stylus:dev_ie', 'concat:css_ie']

       js:
         options:
@@ -236,7 +247,7 @@
         src:    [
           'i-reset/i-reset.styl',
           'b-*/**/*.styl',
-          '!i-*/'
+          '!b-*/**/*.ie.styl',
         ]
         dest:   'blocks'
         ext:    '.css'
@@ -245,13 +256,11 @@
         options:
           define:
             ie: true
-
         expand: true
         cwd:    'blocks/'
         src: [
           'i-reset/i-reset.styl',
           'b-*/**/*.ie.styl',
-          '!i-*/'
         ]
         dest:   'blocks'
         ext:    '.ie.css'
@@ -259,14 +268,14 @@
       publish:
         options:
           compress: true
-        files:
+        files:
           'publish/style.css': 'publish/style.css'
         # base64: true

       publish_ie:
         options:
           compress: true
-        files:
+        files:
           'publish/style.ie.css': 'publish/style.ie.css'
         # base64: true

@@ -281,6 +290,8 @@
     if grunt.file.isMatch( grunt.config('watch.stylus.files'), filepath)
       filepath = filepath.replace( grunt.config('stylus.dev.cwd'), '' );
       grunt.config( 'stylus.dev.src', filepath );
+    if grunt.file.isMatch( grunt.config('watch.stylus_ie.files'), filepath)
+      filepath = filepath.replace( grunt.config('stylus.dev_ie.cwd'), '' );
       grunt.config( 'stylus.dev_ie.src', filepath );
     if grunt.file.isMatch( grunt.config('watch.jade.files'), filepath)
       filepath = filepath.replace( grunt.config('jade.dev.cwd'), '' );


update gruntfile, remove build

update gruntfile, remove build

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -56,6 +56,7 @@
           'bower_components/este-library/**/*.css'
           'bower_components/este-library/**/*.js'
           '!bower_components/este-library/node_modules/**/*.js'
+          'client/**/build/**.*'
           'client/**/css/**/*.css'
           'client/**/js/**/*.js'
           'server/**/*.js'
@@ -223,7 +224,7 @@
       app:
         cmd: 'node server/app'

-    # remember, sudo ulimit -n 2048, see https://github.com/gruntjs/grunt-contrib-watch#how-do-i-fix-the-error-emfile-too-many-opened-file
+    # remember, sudo ulimit -n 10000, see https://github.com/gruntjs/grunt-contrib-watch#how-do-i-fix-the-error-emfile-too-many-opened-file
     watch:
       options:
         # nospawn option is must for livereload, also speeds up the reaction


single click for split appt group, fixes #7745

test plan:
* create an appointment group in scheduler
* enter the date and time
* leave the cursor in the end time box
* click the split button
* the time slot should be split up with just 1 click

Change-Id: I9d5bde1b5c4fecc01da6f458a018c9cc5826786b
Reviewed-on: https://gerrit.instructure.com/11667
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Jon Jensen <44f878afe53efc66b76772bd845eb65944ed8232@instructure.com>

--- app/coffeescripts/calendar/TimeBlockRow.coffee
+++ app/coffeescripts/calendar/TimeBlockRow.coffee
@@ -6,9 +6,12 @@
   class TimeBlockRow
     constructor: (@TimeBlockList, data={}) ->
       @locked = data.locked
+      timeoutId = null
       @$row = $(timeBlockRowTemplate(data)).bind
-        focusin: @focus
-        focusout: => @$row.removeClass('focused')
+        focusin: =>
+          clearTimeout timeoutId
+          @focus()
+        focusout: => timeoutId = setTimeout((=> @$row.removeClass('focused')), 50)
       @inputs = {}
       unless @locked
         @$row.find('.date_field').date_field()


Force commit to be displayed with --format=full

When color.ui=auto was set in .gitconfig the commit view was being
polluted with terminal color signs.
This patch forces the commit to be displayed with --format=full.

--- lib/models/commits/commit.coffee
+++ lib/models/commits/commit.coffee
@@ -93,7 +93,7 @@
   # Public: Show this commit.
   showCommit: =>
     if not @gitShowMessage?
-      git.show @commitID()
+      git.show @commitID(), format: 'full'
       .then (data) =>
         @gitShowMessage = @unicodify(data)
         @showCommit()


Changes to fix issues pointed by @bhuga.

Now you can press % inside (abc) and it will do the same as in vim.

--- lib/motions/search-motion.coffee
+++ lib/motions/search-motion.coffee
@@ -143,6 +143,9 @@
     super(@editorView, @vimState)
     Search.currentSearch = @
     @reverse = @initiallyReversed = false
+    @characters         = [')','(','}','{',']','[']
+    @charactersMatching = ['(',')','{','}','[',']']
+    @reverseSearch      = [true,false,true,false,true,false]

     # FIXME: This must depend on the current language
     @input = new Input(@getCurrentWordMatch())
@@ -151,26 +154,13 @@
     cursor = @editor.getCursor()
     tempPoint = cursor.getBufferPosition().toArray()
     @character = @editor.getTextInBufferRange([cursor.getBufferPosition(),new Point(tempPoint[0],tempPoint[1] + 1)])
-    if @character == ']'
-      @matching = '['
-      @reverse = true
-    else if @character == '['
-      @matching = ']'
-      @reverse = false
-    else if @character == ')'
-      @matching = '('
-      @reverse = true
-    else if @character == '('
-      @matching = ')'
-      @reverse = false
-    else if @character == '}'
-      @matching = '{'
-      @reverse = true
-    else if @character == '{'
-      @matching = '}'
-      @reverse = false
-    else
-      @character = ''
+    @startUp = false;
+    index = @characters.indexOf(@character)
+    if index >= 0
+      @matching = @charactersMatching[index]
+      @reverse = @reverseSearch[index]
+    else
+      @startUp = true

     @character

@@ -212,7 +202,11 @@

   select: (count=1) ->
     @scan()
-    cur = @editor.getCursorBufferPosition()
+    if @startUp
+      cur = @startUpPos
+    else
+      cur = @editor.getCursorBufferPosition()
+
     @match count, (pos) =>
       if @reverse
         tempPoint = cur.toArray()
@@ -223,6 +217,25 @@
     [true]

   scan: ->
+    if @startUp
+      @startUpPos = @editor.getCursorBufferPosition()
+      min = -1
+      iwin = -1
+      for i in [0..@characters.length - 1]
+        matchesCharacter = @searchFor(@characters[i])
+        if matchesCharacter.length > 0
+          dst = matchesCharacter[0].range.start.toArray()
+          if @startUpPos.toArray()[0] == dst[0] and @startUpPos.toArray()[1] < dst[1]
+            if dst[1] < min or min == -1
+              line = dst[0]
+              min = dst[1]
+              iwin = i
+      if iwin != -1
+        @editor.setCursorBufferPosition(new Point(line,min))
+        @character = @characters[iwin]
+        @matching = @charactersMatching[iwin]
+        @reverse = @reverseSearch[iwin]
+
     matchesCharacter = @searchFor(@character)
     matchesMatching = @searchFor(@matching)
     if matchesMatching.length == 0
@@ -257,6 +270,10 @@
         retVal.push(matchesMatching[winner])
       @matches = retVal

+    if @matches.length == 0 and @startUp
+      @editor.setCursorBufferPosition(@startUpPos)
+
+

   execute: (count=1) ->
     super(count) if @input.characters.length > 0


use 1 instead of true for hashset (fixup)

--- lib/org_unit_provisioning.coffee
+++ lib/org_unit_provisioning.coffee
@@ -98,7 +98,7 @@
         # Don't treat this as an error
         if err? and not (err?.error?.code is 400 and err?.error?.message is 'Invalid Ou Id')
           return cb_es "Unable to create org unit #{full_path}: #{JSON.stringify err}"
-        cache[full_path] = true
+        cache[full_path] = 1
         parent = full_path
         cb_es()
     , (err) ->


Login: do not allow usernames to start with numbers

--- client/landing/site.hackathon/coffee/login/AppView.coffee
+++ client/landing/site.hackathon/coffee/login/AppView.coffee
@@ -331,8 +331,8 @@
           rules          :
             required     : yes
             rangeLength  : [4, 25]
-            # regExp       : /^[^0-9][a-z\d]+([-][a-z\d]+)*$/i
-            regExp       : /^[a-z\d]+([-][a-z\d]+)*$/i
+            regExp       : /^[^0-9][a-z\d]+([-][a-z\d]+)*$/i
+            # regExp       : /^[a-z\d]+([-][a-z\d]+)*$/i
             usernameCheck: (input, event) => @usernameCheck input, event
             finalCheck   : (input, event) => @usernameCheck input, event, 0
           messages       :


Enable verbose reporter

Enable verbose reporter

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -85,6 +85,8 @@

     nodeunit:
       all: ['test/nodejs/*.js']
+      options:
+        reporter: 'verbose'

     # Automated recompilation and testing when developing
     watch:


Gruntfile: Added karma task to default task list.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -132,7 +132,7 @@
       'stylus'
       'templates'
       'deps'
-      'tests'
+      'karma'
       'builder'
     ]


Add -9 flag to pkill command

Add -9 flag to pkill command

When I ssh'ed into one of the CI boxes it had over 500 Atom processes
still hanging around.

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

     shell:
       'kill-atom':
-        command: 'pkill Atom'
+        command: 'pkill -9 Atom'
         options:
           stdout: false
           stderr: false


chore(grunt): fix "release" due to change from "dist" to "build"

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -226,7 +226,7 @@
       grunt.fail.fatal "Version has to be greater than #{oldVersion}"

     exec "./node_modules/semver-sync/bin/semver-sync -b #{newVersion} &&
-        grunt dist changelog &&
+        grunt build changelog &&
         git add package.json bower.json &&
         git add -f dist/bradypodion.css &&
         git add -f dist/bradypodion.android.css &&
@@ -239,7 +239,8 @@
         git commit -m 'v#{newVersion}' &&
         git tag v#{newVersion}",
     (error, stdout, stderr) ->
-      grunt.log.writeln if error then stderr else stdout
+      grunt.log.writeln stderr if stderr
+      grunt.log.writeln stdout if stdout
       done error or {}

   grunt.registerTask 'server', (target) ->


Add grunt-release again.

Add grunt-release again.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -75,13 +75,10 @@
   ]

   grunt.registerTask 'publish', 'Publish a new version', [
-    # This needs to be fixed before using the publish task again:
-    # https://github.com/geddski/grunt-release/pull/14
-    #
-    #'jasmine_node'
-    #'dist'
-    #'replace:changelog'
-    #'release'
+    'jasmine_node'
+    'dist'
+    'replace:changelog'
+    'release'
   ]
-
+
   grunt.registerTask 'default', ['watch']


Update Gruntfile.coffee (#1525)

Update Gruntfile.coffee (#1525)

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -133,6 +133,7 @@
           baseUrl: 'scripts'
           dir: 'dist'
           mainConfigFile: 'src/scripts/config.js'
+          waitSeconds: 360 # Jenkins takes a while to build (when running multiple jobs)
           findNestedDependencies: true
           removeCombined: false
           keepBuildDir: false


Simplify notifications

Simplify notifications

--- app/js/jail_iframe/classes/notification.coffee
+++ app/js/jail_iframe/classes/notification.coffee
@@ -1,50 +1,42 @@
 FactlinkJailRoot.showShouldSelectTextNotification = ->
-  show
+  showNotification
     message: 'To create an annotation, select a statement and click the Factlink button.'
     type_classes: 'fl-message-icon-add'
-    in_screen_time: 3000

 FactlinkJailRoot.showLoadedNotification = ->
-  show
+  showNotification
     message: 'Factlink is loaded!'
     type_classes: 'fl-message-success fl-message-icon-time'
-    in_screen_time: 3000

+in_screen_time = 3000
+removal_delay = 1000 # Should be larger than notification_transition_time
+content = """
+

+

+

+""".trim()

-show = (options) ->
-  message = new Notification options
-  message.render()
+showNotification = (options) ->
+  $el = $(content)

+  setMessage = -> $el.find('.fl-js-message').text(options.message)

-class Notification
-  content: """
-

-

-

-  """
+  render = ->
+    $el.addClass(options.type_classes)
+    setMessage()
+    FactlinkJailRoot.$factlinkCoreContainer.append($el)
+    positionElement()

-  constructor: (@options={}) ->
-    @$el = $(@content)
-    @$el.addClass(@options.type_classes)
-    @setMessage(@options.message)
+    $el.addClass 'active'
+    setTimeout(remove, in_screen_time)

-  setMessage: (message) ->
-    @$el.find('.fl-js-message').text(message)
-
-  render: ->
-    FactlinkJailRoot.$factlinkCoreContainer.append(@$el)
-    @positionElement()
-
-    @$el.addClass 'active'
-    @$el.addClass 'been-active'
-    setTimeout(@remove, @options.in_screen_time)
-
-  positionElement: ->
-    @$el.css
+  positionElement = ->
+    $el.css
       top: '65px',
       left: '50%',
-      marginLeft: "-#{@$el.width()/2}px"
+      marginLeft: "-#{$el.width()/2}px"

-  remove: =>
-    @$el.removeClass 'active'
-    setTimeout (=> @$el.remove()), 2000 # Should be larger than @notification_transition_time
+  remove = ->
+    $el.removeClass 'active'
+    setTimeout (-> $el.remove()), removal_delay
+  render()


feat($Grunfile): closes #890 - Add lint to build

JSHint will now run whenver a build is created. Rules are defined in
.jshintrc.

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

     grunt.registerTask 'dev', 'Prepare code for testing', ['clean', 'bower', 'build', 'copy:test']

-    grunt.registerTask 'build', 'Build from latest source', ['concat', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
+    grunt.registerTask 'build', 'Build from latest source', ['jshint:source', 'concat', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']
     grunt.registerTask 'build_stripped', 'Build from latest source w/ test artifacts stripped out', ['concat', 'strip_code:build', 'minify', 'usebanner:allhead', 'usebanner:allfoot', 'copy:images']

     grunt.registerTask 'package', 'Build a zipped distribution-worthy version', ['build_stripped', 'copy:dist', 'shell:version_dist_templates', 'compress:jquery', 'compress:jqueryS3', 'compress:core', 'compress:coreS3' ]


Removed comments

Removed comments

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -91,7 +91,6 @@
           deps: ['all']
           insertRequire: ['all']
           name: 'almond'
-          # modules: [{ name: 'all' }]

     watch:
       dist:
@@ -124,4 +123,4 @@
     'clean:global'
   ]

-  grunt.registerTask 'default', ['test']
+  grunt.registerTask 'default', ['test']


Finish implementing destructuring and fix &

--- src/type.coffee
+++ src/type.coffee
@@ -304,14 +304,14 @@
 # Unify two types, if possible, into a single type. If `assign` is true, then
 # this behaves asymmetrically for pointer types and automatic promotions of
 # primitive types.
-unify = (types, lty, rty, assign) ->
+unify = (types, lty, rty, assigning) ->
   # Unify is reflexive.
   return lty if lty is rty
   # If the left side is dynamic, the entire expression is dynamic.
   return unless lty and rty
   # Two pointer types are unifiable iff their bases are size compatible.
   if lty instanceof PointerType and rty instanceof PointerType
-    if assign
+    if assigning
       # Assigning a narrower pointer to a wider one may mess up due to
       # alignment, since all views are aligned.
       if rty.base and rty.baseAlignment() < lty.baseAlignment()
@@ -327,8 +327,8 @@
     return unless lptys.length is rptys.length
     ptys = []
     for lpty, i in lptys
-      ptys.push unify types, lpty, rptys[i], assign
-    return new ArrowType ptys, unify(types, lty.ret, rty.ret, assign)
+      ptys.push unify types, lpty, rptys[i], assigning
+    return new ArrowType ptys, unify(types, lty.ret, rty.ret, assigning)
   if lty instanceof PointerType and rty in integral
     printWarn "conversion from `#{rty}' to pointer without cast"
     return lty
@@ -340,7 +340,7 @@
     # If we're assigning, return the left type, else return the wider primitive.
     if lty.size isnt rty.size
       printWarn "conversion from `#{rty}' to `#{lty}' may alter its value"
-      return if assign then lty else if lty.size > rty.size then lty else rty
+      return if assigning then lty else if lty.size > rty.size then lty else rty
     # Return the sign of the left type if they're the same size. This is just
     # to break the tie arbitrarily and to behave as expected for assignments.
     if lty.signed isnt rty.signed
@@ -405,31 +405,65 @@
   @computedType = @type.lint o.types

 # Assignments do asymmetric type unification.
+assign = (o, lval, rval, context) ->
+  if lval instanceof Value
+    if lval.isArray()
+      rval = if rval.isArray() then rval.base else null
+    else if lval.isObject()
+      rval = if rval.isObject() then rval.base else null
+    else if lval.this
+      return
+    lval = lval.base
+  if lval instanceof Literal and lty = lval.computedType
+    # As a convenience if the left-hand side is a pointer and the right-hand
+    # side is 0, replace the right-hand side with null, which has the type *any
+    # to suppress int-to-pointer warnings.
+    if rval?
+      value = rval.unwrapAll()
+      if lty instanceof PointerType and value instanceof Literal and value.value is '0'
+        value.computedType = anyPtrTy
+      # `context` can only be passed in from `Assign::computeType'. This is okay
+      # since compound assignments only have **SimpleAssignable**s as lvals.
+      rty = if context
+        op = context.substr 0, context.indexOf '='
+        binopType o, op, lty, value.computedType, lval
+      else
+        value.computedType
+    else
+      rty = null
+    unless unify o.types, lty, rty, true
+      msg = "incompatible types: assigning `#{tystr(rty)}' to `#{lty}'"
+      if context
+        error lval, msg + " using #{context}"
+      else
+        error lval, msg
+  else if lval instanceof Arr
+    robjects = rval?.objects
+    assign o, lel, robjects?[i] for lel, i in lval.objects
+  else if lval instanceof Obj
+    # Build property-name mapping.
+    props = {}
+    if rval?
+      for prop in rval.properties
+        prop = prop.variable if prop.isComplex()
+        if prop?
+          propName = prop.unwrapAll().value.toString()
+          props[propName] = prop
+    for obj in lval.objects
+      if obj instanceof Assign
+        assign o, obj.value, props[obj.variable.unwrapAll().value]
+      else if obj instanceof Value
+        assign o, obj.base, props[obj.base.unwrapAll().value]
+
 Assign::computeType = (r, o) ->
   if @context is 'object'
     delete @variable.computedType
     return
   return @computedType if @typeCached
   @typeCached = true
-  return unless lty = @variable.unwrapAll().computedType
-  # As a convenience if the left-hand side is a pointer and the right-hand
-  # side is 0, replace the right-hand side with null, which has the type *any
-  # to suppress int-to-pointer warnings.
-  value = @value.unwrapAll()
-  if lty instanceof PointerType and value instanceof Literal and value.value is '0'
-    value.computedType = anyPtrTy
-  rty = value.computedType
-  context = @context
-  @computedType = if context
-    binopType context.substr(0, context.indexOf('=')), lty, rty
-  else
-    unify o.types, lty, rty, true
-  unless @computedType
-    msg = "incompatible types: assigning `#{tystr(rty)}' to `#{lty}'"
-    if context
-      error @variable, msg + " using #{context}"
-    else
-      error @variable, msg
+  assign o, (variable = @variable), @value, @context
+  # Complex left-hand sides (destructuring assignments) always have dynamic type.
+  @computedType = variable.computedType unless variable.isComplex()

 # Accesses on struct types may be typed. If we arrived at this case it's
 # because `unwrapAll()` didn't manage to unwrap value, i.e. this is a properties
@@ -505,22 +539,22 @@
 BITWISE = [ '<<', '>>', '>>>', '~', '&', '|' ]
 COMPARE = [ '===', '!==', '<', '>', '<=', '>=' ]

-binopType = (op, ty1, ty2) ->
+binopType = (o, op, ty1, ty2, node) ->
   if (op is '+' or op is '-') and ty1 instanceof PointerType
     if ty2 in integral
       ty1
     else if op is '-' and ty2 instanceof PointerType
       unless unify o.types, ty1.base, ty2.base
-        printWarn "pointer subtraction on incompatible pointer types `#{ty1}' and `#{ty2}'"
+        printWarn "pointer subtraction on incompatible pointer types `#{tystr(ty1)}' and `#{ty2}'"
       i32ty
     else
-      error this, "invalid operand type `#{ty2}' for pointer arithmetic"
+      error node, "invalid operand type `#{tystr(ty2)}' for pointer arithmetic"
   else if op is '%'
     i32ty
   else if op in COMPARE
     if ty1 instanceof PointerType and ty2 instanceof PointerType and
        not unify o.types, ty1, ty2
-      printWarn "comparison between incompatible pointer types `#{ty1}' and `#{ty2}'"
+      printWarn "comparison between incompatible pointer types `#{tystr(ty1)}' and `#{tystr(ty2)}'"
     i32ty
   else if op in BITWISE
     i32ty
@@ -577,25 +611,7 @@
     ty1 = ty2
     ty2 = tmp

-  @computedType = if (op is '+' or op is '-') and ty1 instanceof PointerType
-    unless ty2 in integral
-      error this, "invalid operand type `#{ty2}' for pointer arithmetic"
-    ty1
-  else if op is '-' and ty1 instanceof PointerType and ty2 instanceof PointerType
-    unless unify o.types, ty1.base, ty2.base
-      printWarn "pointer subtraction on incompatible pointer types `#{ty1}' and `#{ty2}'"
-    i32ty
-  else if op is '%'
-    i32ty
-  else if op in COMPARE
-    if ty1 instanceof PointerType and ty2 instanceof PointerType and
-       not unify o.types, ty1, ty2
-      printWarn "comparison between incompatible pointer types `#{ty1}' and `#{ty2}'"
-    i32ty
-  else if op in BITWISE
-    i32ty
-  else if op in ARITH and ty1 in numeric and ty2 in numeric
-    f64ty
+  @computedType = binopType o, op, ty1, ty2, this

 # Gather return expressions.
 returnExpressions = (body) ->
@@ -671,61 +687,57 @@
 # Declaring a type associates a type with the variable in the current
 # scope. Destructuring is allowed, but each destructured variable must get a
 # simple type, i.e. not a **TypeArr** or a **TypeObj**.
-declare = (scope, v, ty, node) ->
+declare = (scope, v, ty, variables) ->
   if v instanceof Literal
     name = v.value
-    error node, "cannot redeclare typed variable `#{name}'" if scope.check name
+    error v, "cannot redeclare typed variable `#{name}'" if scope.check name
     return unless ty
     if ty instanceof TypeArr or ty instanceof TypeObj
-      error node, "cannot type non-destructuring variable with destructuring type `#{ty}'"
+      error v, "cannot type non-destructuring variable with destructuring type `#{ty}'"
     bind = new Binding ty
     scope.add name, bind
-    node.variables.push { name, type: ty, binding: bind }
+    variables.push { name, type: ty, binding: bind }
     putOnStack scope, name if ty instanceof StructType
     return
   if v instanceof Value
-    error node, "cannot type properties" if v.hasProperties()
+    error v, "cannot type properties" if v.hasProperties()
     v = v.base
   if v instanceof Arr
     els = v.objects
     unless ty instanceof TypeArr
-      error node, "cannot type destructuring array with non-destructuring array type `#{ty}'"
+      error v, "cannot type destructuring array with non-destructuring array type `#{ty}'"
     for el, i in els
       if el.this
-        error node, "cannot type @-names"
+        error v, "cannot type @-names"
       else
-        declare scope, el.base, ty.elements[i], node
+        declare scope, el.base, ty.elements[i], variables
     return
   if v instanceof Obj
     objs = v.objects
     unless ty instanceof TypeObj
-      error node, "cannot type destructuring object with non-destructuring object type `#{ty}'"
+      error v, "cannot type destructuring object with non-destructuring object type `#{ty}'"
     for obj in objs
       if obj instanceof Assign
         name = obj.variable.base
-        declare scope, name, ty.names[name.value]?.type, node
+        declare scope, obj.value, ty.names[name.value]?.type, variables
       else if obj.this
-        error node, "cannot type @-names"
+        error v, "cannot type @-names"
       else
         name = obj.base
-        declare scope, name, ty.names[name.value]?.type, node
+        declare scope, name, ty.names[name.value]?.type, variables
     return
-  error node, "trying to type non-typeable"
+  error v, "trying to type non-typeable"

 DeclareType::declareType = (r, o) ->
-  type  = @type.lint o.types
   scope = o.scope
-  @variables = []
-  declare scope, v, type, this for v in @typeables
+  declare scope, v, @type.lint(o.types), (@variables = []) for v in @typeables
   return

 Param::declareType = (r, o) ->
   # Lint just in case the user manually declared the parameter types and
   # thus the types were not linted before this point.
-  type  = @type.lint o.types
   scope = o.scope
-  @variables = []
-  declare scope, this.name, type, this
+  declare scope, this.name, @type.lint(o.types), (@variables = [])
   return

 #### AST Transformation
@@ -774,9 +786,9 @@
       destProp.computedType = fty
       srcProp = new Value srcPtr, [access]
       srcProp.computedType = fty
-      assign = new Assign destProp, srcProp
-      assign.computedType = fty
-      stmts.push assign
+      asn = new Assign destProp, srcProp
+      asn.computedType = fty
+      stmts.push asn
   else
     for i in [0...ty.size]
       offset = new Value new Literal i
@@ -842,10 +854,10 @@
           arg.save = freshVariable arg.name
           plh = new Value new Literal arg.name
           prh = new Value arg.save
-          assign = new Assign plh, prh
-          assign.computedType = plh.computedType = prh.computedType = arg.type
+          asn = new Assign plh, prh
+          asn.computedType = plh.computedType = prh.computedType = arg.type
           plh.computedBinding = arg.binding
-          exprs.unshift assign
+          exprs.unshift asn
     o.frameSize = frameSize
     stackFence o, exprs, frameSize, @spOffsets
     for param in @params
@@ -943,12 +955,15 @@
       new Call FREE, [@first]
     else if op is 'sizeof'
       new Literal @first.size
-    else if op is '&' and ty1 = @computedType.base
-      # The typechecker guarantees that `@first` is assignable, so if we're
-      # taking the address of a stack variable, `@first.unwrapAll()` must be
-      # the literal of that variable.
-      @first.unwrapAll().noStackDeref = true
-      @first
+    else if op is '&'
+      if @computedType.base instanceof StructType
+        # If we're taking the pointer of a struct, we don't need to do anything
+        # since structs are kept as pointers.
+        @first
+      else
+        # Otherwise we must be doing a dereference, so transform it now and
+        # get out the index expression, which must be the address.
+        @first.unwrapAll().transformNode(o).properties[0].index
     else if op is '*'
       # This is only called when this deref is _not_ the base of a struct
       # access, as in struct accesses, dereferencing is the same as not


Lint empty param lists as an error

Lint empty param lists as an error

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -12,6 +12,8 @@

     coffeelint:
       options:
+        no_empty_param_list:
+          level: 'error'
         max_line_length:
           level: 'ignore'


Fix missing field handling in destructuring object types

--- src/type.coffee
+++ src/type.coffee
@@ -673,10 +673,11 @@
 # simple type, i.e. not a **TypeArr** or a **TypeObj**.
 declare = (scope, v, ty, node) ->
   if v instanceof Literal
+    name = v.value
+    error node, "cannot redeclare typed variable `#{name}'" if scope.check name
+    return unless ty
     if ty instanceof TypeArr or ty instanceof TypeObj
       error node, "cannot type non-destructuring variable with destructuring type `#{ty}'"
-    name = v.value
-    error node, "cannot redeclare typed variable `#{name}'" if scope.check name
     bind = new Binding ty
     scope.add name, bind
     node.variables.push { name, type: ty, binding: bind }
@@ -702,12 +703,12 @@
     for obj in objs
       if obj instanceof Assign
         name = obj.variable.base
-        declare scope, name, ty.names[name.value].type, node
+        declare scope, name, ty.names[name.value]?.type, node
       else if obj.this
         error node, "cannot type @-names"
       else
         name = obj.base
-        declare scope, name, ty.names[name.value].type, node
+        declare scope, name, ty.names[name.value]?.type, node
     return
   error node, "trying to type non-typeable"


feat(grunt): add `publish` task support

feat(grunt): add `publish` task support

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -371,6 +371,9 @@

       amsf__theme__to_dev_repo:
         command: "rsync -avz --delete --progress --exclude=.git --exclude=node_modules <%= amsf.base %>/themes/<%= amsf.theme.current %>/ /Users/sparanoid/Git/amsf-<%= amsf.theme.current %> > rsync-theme-dev.log"
+
+      amsf__staging:
+        command: "git checkout staging && git pull && git merge master --no-edit && git push && git checkout master && git push"

       amsf__release:
         command: "git checkout release && git pull && git merge master --no-edit && git push && git checkout master && git push"
@@ -709,10 +712,11 @@
       "replace:amsf__site__update_version"
       "bump-commit"
     ]
-    if grunt.option("push")
-      grunt.task.run [
-        "shell:amsf__release"
-      ]
+
+  grunt.registerTask "publish", "Publish new release", (branch) ->
+    grunt.task.run [
+      "shell:amsf__#{branch or 'staging'}"
+    ]

   grunt.registerTask "deploy-rsync", "Deploy to remote server via rsync",  [
     "shell:amsf__deploy__rsync"


chore(grunt): preserve copyright banners closes #14

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -73,6 +73,9 @@
       options:
         jshintrc: '.jshintrc'
       watch: [ '<%= app.app %>/scripts/**/*.js' ]
+
+    uglify: options:
+     preserveComments: 'some'

     clean:
       dist:


Ajuste no fix para url segura, lendo corretamente do package.json a opção desejada.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -15,7 +15,11 @@

   verbose = grunt.option('verbose')

-  imgProxyOptions = url.parse("https://#{accountName}.vteximg.com.br/arquivos")
+  if secureUrl
+    imgProxyOptions = url.parse("https://#{accountName}.vteximg.com.br/arquivos")
+  else
+    imgProxyOptions = url.parse("http://#{accountName}.vteximg.com.br/arquivos")
+
   imgProxyOptions.route = '/arquivos'

   # portalHost is also used by connect-http-please


updated coffee lint files

updated coffee lint files

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,5 +1,14 @@
+###
+grunt-coffee-toaster
+https://github.com/weareinteractive/grunt-coffee-toaster
+
+Copyright (c) 2013 We Are Interactive
+Licensed under the MIT license.
+###
+
+"use strict"
+
 module.exports = (grunt) ->
-  'use strict'

   # Project configuration.
   grunt.initConfig
@@ -36,7 +45,7 @@
           bail: true
           ui: 'exports'
           timeout: 10000
-        src: ['test/**/*.test.coffee']
+        src: ['test/specs/**/*.test.coffee']

     bump:
       options:


Edit Gruntfile

Edit Gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -6,5 +6,6 @@
     redirect:
       dist:
         files:
-          "tmp/test.txt": "gcc --version"
+          "tmp/test01.txt": "gcc --version"
+          "tmp/test02.txt": "gcc --version"


Fix a bug

Fix a bug

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -40,8 +40,8 @@
                     enabled: false

             ts: (filepath) ->
-                grunt.config ['typescript', 'dev', 'src'], [filepath]
-                ['typescript:dev']
+                grunt.config ['typescript', 'all', 'src'], [filepath]
+                ['typescript']

     grunt.registerTask 'default', ['typescript:dev']
     grunt.registerTask 'build', ['clean:dev', 'typescript']


Gruntfile: Create variables and properties out files.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -112,6 +112,9 @@
           '--output_wrapper="(function(){%output%})();"'
           '--compilation_level="ADVANCED_OPTIMIZATIONS"'
           '--warning_level="VERBOSE"'
+          '--create_source_map="build/source_map.js"'
+          '--property_renaming_report="build/properties.out"'
+          '--variable_renaming_report="build/variables.out"'
           # '--externs=src/externs/externs.js'
           '--jscomp_error=accessControls'
           '--jscomp_error=checkRegExp'
@@ -171,4 +174,4 @@
       'deps'
       'karma'
       'watch'
-    ]+    ]


added parsing for usps activities

added parsing for usps activities

--- src/usps.coffee
+++ src/usps.coffee
@@ -42,6 +42,8 @@
   getWeight: (shipment) ->

   presentTimestamp: (dateString, timeString) ->
+    tsString = if dateString? and timeString? then "#{dateString} #{timeString}" else dateString
+    moment(tsString).toDate() if tsString?

   presentStatus: (status) ->
     return ShipperClient.STATUS_TYPES.UNKNOWN
@@ -88,8 +90,28 @@
       when 'Delivered' then ShipperClient.STATUS_TYPES.DELIVERED
       when 'In Transit' then @findStatusFromMap shipment?['Status']?[0]

+  presentActivity: (rawActivity) ->
+    return unless rawActivity?
+    activity = null
+    city = rawActivity['EventCity']?[0]
+    stateCode = rawActivity['EventState']?[0] if rawActivity['EventState']?[0]?.length
+    postalCode = rawActivity['EventZIPCode']?[0] if rawActivity['EventZIPCode']?[0]?.length
+    countryCode = rawActivity['EventCountry']?[0] if rawActivity['EventCountry']?[0]?.length
+    location = @presentLocation {city, stateCode, countryCode, postalCode}
+    timestamp = @presentTimestamp rawActivity?['EventDate']?[0], rawActivity?['EventTime']?[0]
+    details = rawActivity?['Event']?[0]
+    if details? and location? and timestamp?
+      activity = {timestamp, location, details}
+    activity
+
   getActivitiesAndStatus: (shipment) ->
-    {status: @getStatus shipment}
+    activities = []
+    trackSummary = @presentActivity shipment?['TrackSummary']?[0]
+    activities.push trackSummary if trackSummary?
+    for rawActivity in shipment?['TrackDetail'] or []
+      activity = @presentActivity rawActivity
+      activities.push activity if activity?
+    {activities: activities, status: @getStatus shipment}

   requestOptions: ({trackingNumber, reference, test}) ->
     xml = @generateRequest trackingNumber, reference


Add callback on handling of domain events

--- src/aggregate.coffee
+++ src/aggregate.coffee
@@ -42,7 +42,8 @@

   _handleDomainEvent: (domainEventName, domainEvent) ->
     if @root["handle#{domainEventName}"]
-      @root["handle#{domainEventName}"] domainEvent
+      # TODO: should we wait until the domainevent got handled?
+      @root["handle#{domainEventName}"] domainEvent, ->

     else
       err = new Error "Tried to handle the DomainEvent '#{domainEventName}' without a matching handle method"


Pass res to graphQL variables

Pass res to graphQL variables

--- apps/user/routes.coffee
+++ apps/user/routes.coffee
@@ -88,12 +88,12 @@
       count: channels.length
   .catch next

-channelsVariables = (req) ->
+channelsVariables = (req, res) ->
   send =
     query: query
     user: req.user or null
     variables:
-      id: req.params.username
+      id: res.locals.author.id
       per: 2,
       perBlocks: 5
       page: parseInt(req.query.page, 10) or 1
@@ -101,7 +101,7 @@
       sort: req.query.sort?.toUpperCase() or 'UPDATED_AT'

 @channelsAPI = (req, res, next) ->
-  send = channelsVariables req
+  send = channelsVariables req, res
   graphQL send
     .then (response) ->
       res.setHeader 'Content-Type', 'application/json'
@@ -111,7 +111,7 @@
 @channels = (req, res, next) ->
   return next() unless res.locals.author

-  send = channelsVariables req
+  send = channelsVariables req, res
   graphQL send
     .then (response) ->
       res.locals.sd.QUERY = req.query.q


Add provision for special margins on first, last lines

--- src/view.coffee
+++ src/view.coffee
@@ -167,22 +167,58 @@
           @margins =
             top: padding
             bottom: @view.opts.indentTongueHeight
-            left: @view.opts.indentWidth + @view.opts.padding
-            right: padding
+
+            firstLeft: 0
+            midLeft: @view.opts.indentWidth + @view.opts.padding
+            lastLeft: @view.opts.indentWidth + @view.opts.padding
+
+            firstRight: 0
+            midRight: 0
+            lastRight: padding
+
         else if parenttype is 'block' or (
             parenttype is 'socket' and @model.type is 'text')
           @margins =
             top: padding
             bottom: padding
-            left: padding
-            right: padding
+
+            firstLeft: padding
+            midLeft: padding
+            lastLeft: padding
+
+            firstRight: padding
+            midRight: padding
+            lastRight: padding
         else
-          @margins = {left:0, right:0, top:0, bottom:0}
+          @margins = {
+            firstLeft: 0, midLeft:0, lastLeft: 0
+            firstRight: 0, midRight:0, lastRight: 0
+            top:0, bottom:0
+          }

         for childObj in @children
           @view.getViewNodeFor(childObj.child).computeMargins()

         return null
+
+      getMargins: (line) ->
+        margins =
+          left: @margins.midLeft
+          right: @margins.midRight
+          top: 0
+          bottom: 0
+
+        if line is 0
+          margins.top = @margins.top
+          margins.left = @margins.firstLeft
+          margins.right = @margins.firstRight
+
+        if line is @lineLength - 1
+          margins.bottom = @margins.bottom
+          margins.left = @margins.lastLeft
+          margins.right = @margins.lastRight
+
+        return margins

       # ## computeDimensions
       # Compute the size of our bounding box on each
@@ -608,10 +644,7 @@
           # Horizontal margins get added to every line.
           for size, line in dimensions
             desiredLine = line + childObject.startLine
-            firstTop = if line is 0 then childNode.margins.top else 0
-            lastBottom = if line is dimensions.length - 1
-                childNode.margins.bottom
-              else 0
+            margins = childNode.getMargins line

             # Unless we are in the middle of an indent,
             # add padding on the right of the child.
@@ -619,17 +652,17 @@
             # Exception: Children with invisible bounding boxes
             # should remain invisible. This matters
             # mainly for indents starting at the end of a line.
-            unless size.width is 0
-              @dimensions[desiredLine].width += size.width +
-                childNode.margins.left + childNode.margins.right
+            @dimensions[desiredLine].width += size.width +
+              margins.left +
+              margins.right

             # Compute max distance above and below text
             @distanceToBase[desiredLine].above = Math.max(
               @distanceToBase[desiredLine].above,
-              distanceToBase[line].above + firstTop)
+              distanceToBase[line].above + margins.top)
             @distanceToBase[desiredLine].below = Math.max(
               @distanceToBase[desiredLine].below,
-              distanceToBase[line].below + lastBottom)
+              distanceToBase[line].below + margins.bottom)

         # Height is just the sum of the above-base and below-base counts.
         # Empty lines should have some height.
@@ -687,14 +720,12 @@
         for lineChild, i in @lineChildren[line]
           childView = @view.getViewNodeFor lineChild.child
           childLine = line - lineChild.startLine
-
-          if childView.dimensions[childLine].width is 0
-            childView.computeBoundingBoxX childLeft, childLine
-          else
-            childLeft += childView.margins.left
-            childView.computeBoundingBoxX childLeft, childLine
-            childLeft +=
-              childView.dimensions[childLine].width + childView.margins.right
+          childMargins = childView.getMargins childLine
+
+          childLeft += childMargins.left
+          childView.computeBoundingBoxX childLeft, childLine
+          childLeft +=
+            childView.dimensions[childLine].width + childMargins.right

         # Return the bounds we just
         # computed.
@@ -1385,7 +1416,7 @@
       # no multiline children, either)
       computeChildren: ->
         @multilineChildrenData = [NO_MULTILINE]
-        return 1
+        return @lineLength = 1

       # ## computeDimensinos
       #


zipcode importer: import country data too

--- node_modules_koding/koding-zips-importer/src/zips.coffee
+++ node_modules_koding/koding-zips-importer/src/zips.coffee
@@ -62,10 +62,25 @@

     queue.push ->
       csv()
-        .from.path(nodePath.join(__dirname, path), encoding)
+        .from.path(path, encoding)
         .to.stream(stream)
-        .on 'record', ([_num, zip, _zcType, city, state], i) ->
-          collection.insert { zip, city, state }, (err) ->
+        .on 'record', (row, i) ->
+          [
+            _num
+            zip
+            _zcType
+            city
+            state
+            _locType
+            _lat
+            _long
+            _xAxis
+            _yAxis
+            _zAxis
+            _worldRegion
+            country
+          ] = row
+          collection.insert { zip, city, state, country }, (err) ->
             return stream.emit 'error', err  if err
         .on 'close', -> queue.next()


Special-case GBM model builder This is a temporary fix.

--- h2o-web/src/main/steam/scripts/create-model-dialog.coffee
+++ h2o-web/src/main/steam/scripts/create-model-dialog.coffee
@@ -78,9 +78,9 @@

 createControlFromParameter = (parameter) ->
   switch parameter.type
-    when 'enum', 'Frame', 'Vec'
+    when 'enum', 'Frame', 'string'
       createDropdownControl parameter
-    when 'Vec[]'
+    when 'string[]'
       createListControl parameter
     when 'boolean'
       createCheckboxControl parameter
@@ -162,10 +162,10 @@
           validationFrameParameter = findParameter parameters, 'validation_frame'
           responseColumnParameter = findParameter parameters, 'response_column'
           #TODO HACK hard-coding DL column params for now - rework this when Vec type is supported.
-          responseColumnParameter.type = 'Vec'
+          #responseColumnParameter.type = 'Vec'
           ignoredColumnsParameter = findParameter parameters, 'ignored_columns'
           #TODO HACK hard-coding DL column params for now - rework this when Vec type is supported.
-          ignoredColumnsParameter.type = 'Vec[]'
+          #ignoredColumnsParameter.type = 'Vec[]'

           validationFrameParameter.values = copy trainingFrameParameter.values

@@ -174,6 +174,22 @@
             sort columnLabels
             responseColumnParameter.values = columnLabels
             ignoredColumnsParameter.values = columnLabels
+        else if algorithm.key is 'gbm'
+          #validationFrameParameter = findParameter parameters, 'validation_frame'
+          responseColumnParameter = findParameter parameters, 'response_column'
+          #TODO HACK hard-coding DL column params for now - rework this when Vec type is supported.
+          #responseColumnParameter.type = 'Vec'
+          #ignoredColumnsParameter = findParameter parameters, 'ignored_columns'
+          #TODO HACK hard-coding DL column params for now - rework this when Vec type is supported.
+          #ignoredColumnsParameter.type = 'Vec[]'
+
+          #validationFrameParameter.values = copy trainingFrameParameter.values
+
+          if trainingFrame = (find result.frames, (frame) -> frame.key.name is frameKey)
+            columnLabels = map trainingFrame.columns, (column) -> column.label
+            sort columnLabels
+            responseColumnParameter.values = columnLabels
+            #ignoredColumnsParameter.values = columnLabels
         go()

   # If a source model is specified, we already know the algo, so skip algo selection


Fix curriculum guides' table of contents anchor linking

--- app/views/teachers/MarkdownResourceView.coffee
+++ app/views/teachers/MarkdownResourceView.coffee
@@ -18,8 +18,8 @@
       unless /<!doctype html>/i.test(data)
         renderer = new marked.Renderer()
         linkIDs = new Set
-        renderer.heading = (text, level) ->
-          if level isnt 3
+        renderer.heading = (text, level) =>
+          if level not in [2, 3] or (_.string.startsWith(@name, 'faq') and level is 2)
             return "<h#{level}>#{text}</h#{level}>"
           linkID = _.string.slugify text
           if not linkID.replace(/(codecombat|-)/g, '') or linkIDs.has linkID


better commit message on deploy

better commit message on deploy

--- bin/deploy.coffee
+++ bin/deploy.coffee
@@ -15,5 +15,5 @@

 run "npm run build"
 run "git add --force --no-ignore-removal public/"
-run "git commit -m 'deploy'"
+run "git commit -m '[bot] build and deploy'"
 run "git push --force git@heroku.com:#{HEROKU_APP}.git HEAD:master"