Remove gulpfile.coffee

Remove gulpfile.coffee

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -1,59 +0,0 @@
-gulp = require 'gulp'
-concat = require 'gulp-concat'
-tsc = require 'gulp-typescript'
-bowerFiles = require 'gulp-bower-files'
-handlebars = require 'gulp-handlebars'
-wrap = require 'gulp-wrap'
-declare = require 'gulp-declare'
-path = require 'path'
-
-# main task
-gulp.task 'build',[
-  'build-assets',
-  'build-typescript',
-  'build-bower-components',
-  'build-templates',
-]
-
-gulp.task 'default',['build']
-
-gulp.task 'watch',['build'],->
-  gulp.watch './assets/**/*.*',['build-assets']
-  gulp.watch './src/ts/**/*.ts',['build-typescript']
-  gulp.watch './src/tpl/**/*.hbs',['build-templates']
-
-# sub task
-gulp.task 'build-assets',->
-  gulp.src './assets/**/*.*'
-    .pipe gulp.dest './dest/'
-
-gulp.task 'build-typescript',->
-  tsOption = {
-    noImplicitAny : true,
-    sortOutput: true,
-    target: "ES5",
-    sourceRoot: "./src/ts/rootFile.ts"
-  }
-  gulp.src './src/ts/**/*.ts'
-    .pipe tsc(tsOption)
-    .js
-    .pipe concat 'app.js'
-    .pipe gulp.dest './dest/js/'
-
-gulp.task 'build-bower-components',->
-  bowerFiles()
-    .pipe concat 'vendors.js'
-    .pipe gulp.dest './dest/js/'
-
-gulp.task 'build-templates',->
-  gulp.src './src/tpl/**/*.hbs'
-    .pipe handlebars()
-    .pipe wrap 'Handlebars.template(<%= contents %>)'
-    .pipe declare {
-      namespace: 'Diccal.templates',
-      noRedeclare: true,
-      processName: (filePath) ->
-        declare.processNameByPath filePath.replace 'src'+path.sep+'tpl'+path.sep,''
-    }
-    .pipe concat 'templates.js'
-    .pipe gulp.dest './dest/js/'


kill a js log

kill a js log

--- app/assets/javascripts/builder/views/crop_urls.js.coffee
+++ app/assets/javascripts/builder/views/crop_urls.js.coffee
@@ -12,7 +12,6 @@
   toggleCropUrls: (e) ->
     e.preventDefault()
     form = $(e.target).parents('header').find('form.image-croppings').first()
-    console.log form.length
     form.toggle()
     form.find("input[type='text']").first().focus()


restore setting in current run loop

restore setting in current run loop

--- app/assets/javascripts/controllers/my_settings.js.coffee
+++ app/assets/javascripts/controllers/my_settings.js.coffee
@@ -25,7 +25,7 @@

   restoreLocalSettings: ->
-    Ember.run.next =>
+    Ember.run =>
       @set 'useWebRtc',    app.loadLocalKey('useWebRtc')
       @set 'useAutoReady', app.loadLocalKey('useAutoReady')


Fix scroll to anchor

Fix scroll to anchor

--- app/assets/javascripts/legislation_annotatable.js.coffee
+++ app/assets/javascripts/legislation_annotatable.js.coffee
@@ -121,14 +121,21 @@
       anchor = $(location).attr('hash')
       if anchor && anchor.startsWith('#annotation')
         ann_id = anchor.split("-")[-1..]
-        el = $("span[data-annotation-id='" + ann_id + "']")
-        App.LegislationAllegations.show_comments()
-        $('html,body').animate({scrollTop: el.offset().top})
-        $.event.trigger
-          type: "renderLegislationAnnotation"
-          annotation_id: ann_id
-          annotation_url: el.closest(".legislation-annotatable").data("legislation-annotatable-base-url")
-          offset: el.offset()["top"]
+
+        checkExist = setInterval((->
+          if $("span[data-annotation-id='" + ann_id + "']").length
+            el = $("span[data-annotation-id='" + ann_id + "']")
+            el.addClass('current-annotation')
+            App.LegislationAllegations.show_comments()
+            $('html,body').animate({scrollTop: el.offset().top})
+            $.event.trigger
+              type: "renderLegislationAnnotation"
+              annotation_id: ann_id
+              annotation_url: el.closest(".legislation-annotatable").data("legislation-annotatable-base-url")
+              offset: el.offset()["top"]
+            clearInterval checkExist
+          return
+        ), 100)

   initialize: ->
     $(document).off("renderLegislationAnnotation").on("renderLegislationAnnotation", App.LegislationAnnotatable.renderAnnotationComments)


Refactor loading of order in Orders.find()

--- app/assets/javascripts/sprangular/services/orders.coffee
+++ app/assets/javascripts/sprangular/services/orders.coffee
@@ -4,7 +4,6 @@
     find: (number) ->
       $http.get("/api/orders/#{number}")
         .then (response) ->
-          order = new Sprangular.Order
-          order.load(response.data)
+          Sprangular.extend(response.data, Sprangular.Order)

   service


round mastery gradebook scores to two decimal places

fixes CNVS-13528

test plan
- create some outcome results with fractional scores (live
 assessments are great for this)
- ensure that the scores on the mastery gradebook rounds to two
 decimal places
- ensure that the header (which computes an average) also rounds

Change-Id: Icfa91e0a1d56afe3be2c73aabe32188fb52ba2ef
Reviewed-on: https://gerrit.instructure.com/36202
Reviewed-by: Braden Anderson <5d57265d16cfe2e0f2e6eb7f13e876bb378ef0f1@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Trevor deHaan <85df72112e8a9484fec7b3db2e31789c2c2d4e07@instructure.com>
Product-Review: Joel Hough <4816dabf8db1bc6cac35b3a24cab2ff844b5b0c7@instructure.com>

--- app/coffeescripts/gradebook2/OutcomeGradebookGrid.coffee
+++ app/coffeescripts/gradebook2/OutcomeGradebookGrid.coffee
@@ -334,7 +334,7 @@
         return unless outcome and _.isNumber(value)
         className   = Grid.View.masteryClassName(value, outcome)
         return '' if shouldFilter and !_.include(Grid.filter, className)
-        cellTemplate(score: value, className: className, masteryScore: outcome.mastery_points)
+        cellTemplate(score: Math.round(value * 100.0) / 100.0, className: className, masteryScore: outcome.mastery_points)

       studentCell: (row, cell, value, columnDef, dataContext) ->
         studentCellTemplate(value)


Don't hardcode repo in changelog tasks

Don't hardcode repo in changelog tasks

--- tasks/changelog.coffee
+++ tasks/changelog.coffee
@@ -3,6 +3,7 @@
 fs = require 'fs-extra-promise'

 manifest = require '../src/package.json'
+mainManifest = require '../package.json'
 changelogJson = require '../CHANGELOG.json'

 gulp.task 'changelog:deb', ->
@@ -78,18 +79,20 @@
       parsedDate = new Date(release.releasedAt)
       date = moment(parsedDate).format('YYYY-DD-MM')

+      repoUrl = mainManifest.repository.git.replace '.git', ''
+
       fullChangelog = ''
       if index < changelogJson.length - 1
-        fullChangelog = '[Full Changelog](https://github.com/Aluxian/Whatsie/compare/v' +
+        fullChangelog = '[Full Changelog](' + repoUrl + '/compare/v' +
           changelogJson[index+1].version + '...v' + release.version + ') • '

-      download = '[Download](https://github.com/Aluxian/Whatsie/releases/tag/v' + release.version + ')'
+      download = '[Download](' + repoUrl + '/releases/tag/v' + release.version + ')'

       channelSuffix = ''
       if release.channel isnt 'stable'
         channelSuffix = '-' + release.channel

-      return '## [' + release.version + channelSuffix + '](https://github.com/Aluxian/Whatsie/tree/v' +
+      return '## [' + release.version + channelSuffix + '](' + repoUrl + '/tree/v' +
           release.version + ') (' + date + ')\n\n' + fullChangelog + download + '\n' + log
     .join '\n\n'
   changelog += '\n'


When html is recieved instead of JSON the error message says this rather than dumping the html on the screen as the error message

--- SingularityUI/app/application.coffee
+++ SingularityUI/app/application.coffee
@@ -116,13 +116,12 @@
                     serverMessage = JSON.parse(jqxhr.responseText).message or jqxhr.responseText
                 catch
                     if jqxhr.status is 200
-                        console.error jqxhr
+                        console.error jqxhr.responseText
                         Messenger().error
-                            message:    '''
-
Expected JSON but received something else (possibly html). The response has been saved to your js console.

-
One possible cause is an http redirect to an html web page.

-                                        '''
-                        throw new Error "Expected JSON in response but received something else"
+                            message:    """
+
Expected JSON but received #{if jqxhr.responseText.startsWith '<!DOCTYPE html>' then 'html' else 'something else'}. The response has been saved to your js console.

+                                        """
+                        throw new Error "Expected JSON in response but received #{if jqxhr.responseText.startsWith '<!DOCTYPE html>' then 'html' else 'something else'}"
                     serverMessage = jqxhr.responseText

                 serverMessage = _.escape serverMessage


Improved console output of ti.createView

--- src/tb/lib/ti/index.coffee
+++ src/tb/lib/ti/index.coffee
@@ -44,7 +44,7 @@
     if viewCreator
       viewCreator attributes
     else
-      console.log "Could not find viewCreator for #{viewName}"
+      console.log "Could not find viewCreator for #{viewNameOrCreator}"

   $: (element) -> extend element


cleanup

cleanup

--- src/translate/index.coffee
+++ src/translate/index.coffee
@@ -12,7 +12,15 @@
 scripts = {}

 exports.script = (name) ->
-  scripts[name] ? (scripts[name] = exports.compile($("script[data-template-name='#{name}']").html()))
+
+  if scripts[name]
+    return scripts[name]
+
+  content = $("script[data-template-name='#{name}']").html()
+
+  return unless content
+
+  scripts[name] = exports.compile(content)

 if typeof window?.paperclip isnt "undefined"
   window.paperclip.compile = exports.compile


Add ~:`

Add ~:`

--- src/underscore-plus.coffee
+++ src/underscore-plus.coffee
@@ -15,6 +15,7 @@
 # Human key combos should always explicitly state the shift key. This map is a disambiguator.
 # 'shift-version': 'no-shift-version'
 shiftKeyMap =
+  '~': '`'
   '_': '-'
   '+': '='
   '|': '\\'


[fix] fix marking a ticket as unable-to-estimate

--- app/assets/javascripts/houston-scheduler/views/edit_ticket_view.coffee
+++ app/assets/javascripts/houston-scheduler/views/edit_ticket_view.coffee
@@ -16,6 +16,7 @@
     @template = @options.template
     @isValid = @options.isValid
     @attribute = @options.attribute
+    @unableToSetAttribute = "unableToSet#{@attribute[0].toUpperCase()}#{@attribute.substr(1)}"
     @$el.cssHover()

   render: ->
@@ -24,7 +25,7 @@
       .html(@template @ticket.toJSON())
       .toggleClass('saved', @isValid(@ticket))
       .delegate('.ticket-details', 'click', _.bind(@showTicketDetails, @))
-    @unableToEstimate() if @ticket.get("unable_to_set_#{@attribute}")
+    @unableToEstimate() if @ticket.get(@unableToSetAttribute)
     @

@@ -83,14 +84,14 @@
     e.preventDefault()

     attributes = {}
-    attributes["unable_to_set_#{@attribute}"] = disableMe = if @$el.hasClass('unable-to-estimate') then null else true
+    attributes[@unableToSetAttribute] = disableMe = if @$el.hasClass('unable-to-estimate') then null else true
     @unableToEstimate() if disableMe

     @saveAttributes attributes, =>
       @updateAbilityToEstimate()

   updateAbilityToEstimate: ->
-    if @ticket.get("unable_to_set_#{@attribute}")
+    if @ticket.get(@unableToSetAttribute)
       @unableToEstimate()
     else
       @ableToEstimate()


Test nested hyphenated attributes.  Refs #32

--- test/attributes.coffee
+++ test/attributes.coffee
@@ -1,5 +1,5 @@
 expect = require 'expect.js'
-{render, a, br} = require '..'
+{render, a, br, div} = require '..'

 describe 'Attributes', ->

@@ -42,3 +42,10 @@
     it 'expands attributes', ->
       template = -> br data: { name: 'Name', value: 'Value' }
       expect(render template).to.equal '
'
+
+  describe 'nested hyphenated attribute', ->
+    it 'renders', ->
+      template = ->
+        div 'proxy-on-click': "alert('hi')", ->
+          div '#inner'
+      expect(render template).to.equal '

'


STL/dom close #61 optimizing the elements build

--- stl/dom/src/element.coffee
+++ stl/dom/src/element.coffee
@@ -15,8 +15,7 @@
   constructor: (element, options)->
     # making a dom-element by the tag-name
     if typeof(element) is 'string'
-      element = if element of elements_cache then elements_cache[element]
-      else (elements_cache[element] = document.createElement(element))
+      element = elements_cache[element] || (elements_cache[element] = document.createElement(element))
       element = element.cloneNode(false)

     # handling dynamic typecasting


Correct single subject link for blocks

Correct single subject link for blocks

--- collections/feed_group.coffee
+++ collections/feed_group.coffee
@@ -61,7 +61,7 @@
     else if @first_item()?.base_class is 'User'
       "/#{@first_item()?.slug}"
     else
-      "/#/block/#{@first_item()?.id}"
+      "/block/#{@first_item()?.id}"

   single_subject_class: -> @first_item()?.base_class?.toLowerCase()


Clear comment input form after successful posting of message

--- core/app/backbone/views/facts/auto_complete_fact_relations_view.coffee
+++ core/app/backbone/views/facts/auto_complete_fact_relations_view.coffee
@@ -132,12 +132,17 @@
   initialize: (opts) ->
     @comments = opts.comments

+  clearForm: ->
+    @$('.content').val('')
+
   submit: ->
     content = @$('.content').val()
     comment = new Comment(content: content, created_by: currentUser)

     @comments.add comment
     comment.save {},
+      success: =>
+        @clearForm()
       error: =>
         @comments.remove comment
         alert 'Something went wrong while adding your comment.'


Bind key "g" to reload eventSource

Bind key "g" to reload eventSource

--- orgviz/static/timeline.coffee
+++ orgviz/static/timeline.coffee
@@ -1,5 +1,6 @@
 loadEventData = (tl, eventSource, url, callback) ->
   Timeline.loadJSON url, (timeline_data) ->
+    eventSource.clear()
     eventSource.loadJSON(timeline_data, url)
     tl.layout()
     callback() if callback
@@ -75,6 +76,8 @@
   tl = Timeline.create(tl_el, bandInfos, Timeline.HORIZONTAL);

   loadEventData tl, eventSource, data_source, (-> setupKeybinds tl)
+  $(document).bind "keydown", "g", ->
+    loadEventData tl, eventSource, data_source

   resizeTimerID = null
   $(document).resize ->


Changed API call based on input from @carlhaman in https://github.com/malmostad/sitevision_assets/issues/274#issuecomment-100228565

--- _includes/coffeescripts/video.coffee
+++ _includes/coffeescripts/video.coffee
@@ -24,13 +24,9 @@
       scrollTop: $(".movies").offset().top - 45
     , 200

-    # FIXME: use $videoId to set video and let BC select media type
-    bcPlayer.src([
-      {
-        "type":"video/mp4",
-        "src": "http://brightcove.vo.llnwd.net/v1/uds/pd/745456160001/201503/1629/745456160001_4144200317001_4144112584001.mp4"
-      }
-    ])
-    bcPlayer.play()
+    bcPlayer.catalog.getVideo $videoId, (error, video) ->
+      bcPlayer.catalog.load(video)
+      bcPlayer.play()
+      return
     return
   return


CustomPartials: Added delete notification.

--- client/Dashboard/views/customviews/customviewitem.coffee
+++ client/Dashboard/views/customviews/customviewitem.coffee
@@ -12,12 +12,30 @@
     @deleteButton = new KDButtonView
       cssClass    : "delete"
       iconOnly    : yes
-      callback    : @bound "delete"
+      callback    : =>
+        @notify => @delete()

     @editButton   = new KDButtonView
       cssClass    : "edit"
       iconOnly    : yes
       callback    : @bound "edit"
+
+  notify: (callback = noop) ->
+    modal          = new KDModalView
+      title        : "Are you sure?"
+      content      : "Are you sure you want to delete the item. This cannot be undone."
+      overlay      : yes
+      buttons      :
+        Delete     :
+          title    : "Delete"
+          cssClass : "modal-clean-red"
+          callback : =>
+            callback()
+            modal.destroy()
+        Cancel     :
+          title    : "Cancel"
+          cssClass : "modal-cancel"
+          callback : -> modal.destroy()

   edit: ->
     @getDelegate().emit "ViewEditRequested", @getData()


SidebarMachineList: Make addMachineBox logic separate method.

--- client/Social/Activity/sidebar/sidebarmachinelist.coffee
+++ client/Social/Activity/sidebar/sidebarmachinelist.coffee
@@ -39,10 +39,14 @@
     @machineBoxes = []

     for machineData in @getData()
+      @addMachineBox machineData

-      machineBox = new SidebarMachineBox {}, machineData
-      @addSubView machineBox
-      @machineBoxes.push machineBox
+
+  addMachineBox: (machineData) ->
+
+    machineBox = new SidebarMachineBox {}, machineData
+    @addSubView machineBox
+    @machineBoxes.push machineBox

   deselectMachines: ->


activity: transform channel links after component did mount

--- client/activity/lib/components/common/messagebody.coffee
+++ client/activity/lib/components/common/messagebody.coffee
@@ -23,16 +23,21 @@
     @state = { message: @props.message }

+  componentDidMount: ->
+
+    @transformChannelHashtags @state.message
+
+
   contentDidMount: (content) ->

     @content = content
     @renderEmojis()
-    @transformChannelHashtags @state.message

   componentDidUpdate: (prevProps, prevState) ->

     { message } = @props
+
     # if message body is updated in props, we need to process hashtags
     # and update state with a new message body
     unless prevProps.message.get('body') is message.get('body')


Separated elements in markups to KDViews.

--- client/app/Applications/Ace.kdapplication/AppView.coffee
+++ client/app/Applications/Ace.kdapplication/AppView.coffee
@@ -14,6 +14,12 @@
     super

     @listenWindowResize()
+
+    @editorHeader = new KDView
+      cssClass : "editor-header header-buttons"
+
+    @editorHeader.addSubView @headerButtonContainer = new KDView
+      cssClass : "header-buttons"

     @saveButton = new KDButtonViewWithMenu
       title         : "Save"
@@ -81,6 +87,10 @@
     @findAndReplaceView = new AceFindAndReplaceView delegate: @
     @findAndReplaceView.hide()

+    @headerButtonContainer.addSubView @compileAndRunButton
+    @headerButtonContainer.addSubView @previewButton
+    @headerButtonContainer.addSubView @saveButton
+
     @setViewListeners()

   setViewListeners:->
@@ -119,13 +129,7 @@
   pistachio:->

     """
-

-

-        {{> @compileAndRunButton}}
-        {{> @previewButton}}
-        {{> @saveButton}}
-

-

+    {{> @editorHeader}}

       {{> @ace}}


Hackathon: changed button title

Hackathon: changed button title

--- client/landing/site.hackathon/coffee/home/AppView.coffee
+++ client/landing/site.hackathon/coffee/home/AppView.coffee
@@ -104,7 +104,7 @@

       @signUpForm = new HomeRegisterForm
         cssClass    : 'login-form register no-anim'
-        buttonTitle : 'SIGN UP'
+        buttonTitle : 'LET\'S DO THIS'
         callback    : (formData) =>
           router.requireApp 'Login', (controller) =>
             controller.getView().showExtraInformation formData, @signUpForm


test(engine): improve tmpdir test with finally

--- packages/engine/test/plugins/metadata/tmpdir.coffee
+++ packages/engine/test/plugins/metadata/tmpdir.coffee
@@ -80,10 +80,12 @@
       nikita
         ssh: ssh
       , ->
-        @call metadata: tmpdir: true, dirty: true, (->)
-        @fs.base.exists '{{siblings.0.metadata.tmpdir}}'
-        .should.resolvedWith exists: true
-        @fs.base.rmdir '{{siblings.0.metadata.tmpdir}}'
+        try
+          @call metadata: tmpdir: true, dirty: true, (->)
+          {exists} = await @fs.base.exists '{{siblings.0.metadata.tmpdir}}'
+          exists.should.be.true()
+        finally
+          @fs.base.rmdir '{{siblings.0.metadata.tmpdir}}'

     they 'is false', ({ssh}) ->
       nikita


Remove obsolete run script commands in help string

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>

--- config/generateRunFile.coffee
+++ config/generateRunFile.coffee
@@ -169,8 +169,6 @@
       echo ""
       echo "  run                       : to start koding"
       echo "  run exec                  : to exec arbitrary commands"
-      echo "  run backend               : to start only backend of koding"
-      echo "  run killall               : to kill every process started by run script"
       echo "  run install               : to compile/install client and "
       echo "  run buildclient           : to see of specified worker logs only"
       echo "  run logs                  : to see all workers logs"


Remove outdated TODO

Remove outdated TODO

--- admin/static/coffee/dashboard.coffee
+++ admin/static/coffee/dashboard.coffee
@@ -48,10 +48,8 @@
             @cluster_status_redundancy.destroy()
             @cluster_status_reachability.destroy()
             @cluster_status_consistency.destroy()
-
             @cluster_performance.destroy()

-    # TODO: dropped RAM and disk distribution in the templates, need to remove support for them here as well
     class @ClusterStatusAvailability extends Backbone.View
         className: 'cluster-status-availability '


Added watch tasks for .hbs and .scss processing.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -27,7 +27,15 @@
     usemin:
       html: 'dist/index.html'
       css: 'dist/styles/main.css'
+    watch:
+      hbs:
+        files: 'app/js/templates/*.hbs'
+        tasks: ['handlebars']
+      sass:
+        files: 'app/sass/*.scss'
+        tasks: ['sass']

+  grunt.loadNpmTasks 'grunt-contrib-watch'
   grunt.loadNpmTasks 'grunt-usemin'
   grunt.loadNpmTasks 'grunt-contrib-sass'
   grunt.loadNpmTasks 'grunt-contrib-concat'
@@ -36,4 +44,4 @@
   grunt.loadNpmTasks 'grunt-contrib-copy'

   grunt.registerTask 'default', ['handlebars', 'sass']
-  grunt.registerTask 'build', ['handlebars', 'sass', 'useminPrepare', 'copy', 'concat', 'uglify', 'usemin']+  grunt.registerTask 'build', ['handlebars', 'sass', 'useminPrepare', 'copy', 'concat', 'uglify', 'usemin']


show jshint errors while in dev

show jshint errors while in dev

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -57,7 +57,7 @@
     watch:
       scripts:
         files: ['src/**/*.js']
-        tasks: ['concat','string-replace','uglify']
+        tasks: ['concat','string-replace','uglify','jshint']
         options:
           interrupt: true


Update Gruntfile

Update Gruntfile

Improve formating in Gruntfile and embrace CoffeeScript awesomeness.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,78 +1,59 @@
 module.exports = (grunt) ->

-  grunt.initConfig({
+  grunt.initConfig

-    pkg: grunt.file.readJSON('package.json'),
+    pkg: grunt.file.readJSON('package.json')
     banner: '/**\n * <%= pkg.name %> — <%= pkg.description %>\n' +
             ' * \n' +
             ' * @version <%= pkg.version %>\n' +
             ' * @license <%= pkg.license.type %>\n' +
             ' * @author  <%= pkg.author %>\n' +
-            ' */\n',
-    src: [ 'Functions/*.js', 'Number/*.js', 'String/*.js' ],
+            ' */\n'
+    src: [ 'Functions/*.js', 'Number/*.js', 'String/*.js' ]

-    clean: {
+    clean:
       files: 'helpers*.js'
-    },

-    jshint: {
-      options: {
+    jshint:
+      options:
         jshintrc: '.jshintrc'
-      },
-      beforeconcat: '<%= src %>',
-      afterconcat: '<%= pkg.name %>',
+      beforeconcat: '<%= src %>'
+      afterconcat: '<%= pkg.name %>'
       test: 'tests/units/*.js'
-    },

-    concat: {
-      options: {
-        banner: '<%= banner %>\n',
+    concat:
+      options:
+        banner: '<%= banner %>\n'
         separator: ';\n\n'
-      },
-      build: {
-        files: {
+      build:
+        files:
           '<%= pkg.name %>': '<%= src %>'
-        }
-      }
-    },

-    uglify: {
-      options: {
-        banner: '<%= banner %>',
+    uglify:
+      options:
+        banner: '<%= banner %>'
         report: 'gzip'
-      },
-      build: {
-        files: {
+      build:
+        files:
           '<%= pkg.name.replace(/js$/, "min.js") %>': '<%= pkg.name %>'
-        }
-      }
-    },

-    connect: {
-      server: {
-        options: {
-          port: 8000,
+    connect:
+      server:
+        options:
+          port: 8000
           base: '.'
-        }
-      }
-    },

-    qunit: {
-      all: {
-        options: {
+    qunit:
+      all:
+        options:
           urls: [ 'http://localhost:8000/tests/index.html' ]
-        }
-      }
-    }

-  })
+  grunt.loadNpmTasks 'grunt-contrib-clean'
+  grunt.loadNpmTasks 'grunt-contrib-jshint'
+  grunt.loadNpmTasks 'grunt-contrib-concat'
+  grunt.loadNpmTasks 'grunt-contrib-uglify'
+  grunt.loadNpmTasks 'grunt-contrib-qunit'
+  grunt.loadNpmTasks 'grunt-contrib-connect'

-  grunt.loadNpmTasks('grunt-contrib-clean')
-  grunt.loadNpmTasks('grunt-contrib-jshint')
-  grunt.loadNpmTasks('grunt-contrib-concat')
-  grunt.loadNpmTasks('grunt-contrib-uglify')
-  grunt.loadNpmTasks('grunt-contrib-qunit')
-  grunt.loadNpmTasks('grunt-contrib-connect')
-
-  grunt.registerTask('default', [ 'clean', 'jshint:beforeconcat', 'concat', 'jshint:afterconcat', 'uglify' ])
-  grunt.registerTask('test', [ 'jshint:test', 'connect', 'qunit' ])+  grunt.registerTask 'default', [ 'clean', 'jshint:beforeconcat', 'concat', 'jshint:afterconcat', 'uglify' ]
+  grunt.registerTask 'test', [ 'jshint:test', 'connect', 'qunit' ]


cssmin

cssmin

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -4,7 +4,6 @@

 module.exports = (grunt) ->

-  cssmin = {}
   dirs =
     output: "compiled"
     temp: "tmp"
@@ -33,7 +32,13 @@
   rootFile = outputPath(names.root)
   structureFile = outputPath(names.structure)
   themeFile = outputPath(names.theme)
-
+
+  # CSSMIN configuration
+  cssmin = { all: { } }
+  cssmin.all[ "#{rootFile}.min.css" ]      = ["<%= global.ver.min %>", rootFile + ".css"]
+  cssmin.all[ "#{structureFile}.min.css" ] = ["<%= global.ver.min %>", structureFile + ".css"]
+  cssmin.all[ "#{themeFile}.min.css" ]     = ["<%= global.ver.min %>", themeFile + ".css"]
+
   # Project configuration.
   grunt.config.init
     sizereport:
@@ -91,7 +96,7 @@
     # NOTE the keys are filenames which, being stored as variables requires that we use
     #      key based assignment. See below.
     uglify: `undefined`
-    cssmin: `undefined`
+    cssmin: cssmin
     compress: readCoffee "build/compress.coffee"

     # JS config, mostly the requirejs configuration
@@ -136,11 +141,6 @@
   uglify.js.files[ rootFile + ".min.js" ] = [rootFile + ".js"]
   grunt.config.set "uglify",uglify

-  # CSSMIN configuration
-  cssmin[rootFile + ".min.css"] = ["<%= global.ver.min %>", rootFile + ".css"]
-  cssmin[structureFile + ".min.css"] = ["<%= global.ver.min %>", structureFile + ".css"]
-  cssmin[themeFile + ".min.css"] = ["<%= global.ver.min %>", themeFile + ".css"]
-  grunt.config.set "cssmin", cssmin

   # authors task


Added slider CSS.

Added slider CSS.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -75,6 +75,7 @@
           'bower_components/bootstrap/dist/css/bootstrap.css'
           'bower_components/font-awesome/css/font-awesome.css'
           'bower_components/nvd3/nv.d3.css'
+          'bower_components/angular-slider/slider.css'
         ]
         dest: '_public/stylesheets/vendor.css'


Copy theme files

Copy theme files

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -62,6 +62,16 @@
         cwd: 'dist'
         src: 'assets/**'
         dest: 'public'
+      theme:
+        expand: true
+        cwd: 'dist/theme/'
+        src: '**'
+        dest: 'public/wp/wp-content/themes/dotby.jp/'
+      bottheme:
+        expand: true
+        cwd: 'dist/bot-theme/'
+        src: '**'
+        dest: 'public/wp/wp-content/themes/twentyfifteen-bot/'

     watch:
       sass:


Add grunt-open config on comment

Add grunt-open config on comment

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -42,10 +42,12 @@
     # browser open
     open:
       server:
-        path: "http://localhost:<%= connect.options.port %>"
+        path: "http://local.jp:<%= connect.options.port %>"
         app: 'Google Chrome Canary'
 #        app: 'Google Chrome'
-
+#        file:
+#        path : '/etc/hosts'
+
     coffee:
       grunt:
         files:


Gruntfile -> js

Gruntfile -> js

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,45 +0,0 @@
-module.exports = (grunt) ->
-  grunt.initConfig
-    pkg: grunt.file.readJSON('package.json')
-
-    babel: {
-      options: {
-        sourceMap: false
-      },
-      dist: {
-        files: [{
-          expand: true,
-          cwd: 'src',
-          src: ['**/*.js'],
-          dest: "lib",
-          ext: ".js"
-        }]
-      }
-    }
-
-    watch: {
-      scripts: {
-        files: ['src/*.js'],
-        tasks: ['default'],
-        options: {
-          spawn: false,
-        },
-      },
-    },
-
-    shell:
-      test:
-        command: 'jasmine-focused --captureExceptions --coffee spec/'
-        options:
-          stdout: true
-          stderr: true
-          failOnError: true
-
-  grunt.loadNpmTasks('grunt-babel')
-  grunt.loadNpmTasks('grunt-shell')
-  grunt.loadNpmTasks('grunt-contrib-watch')
-
-  grunt.registerTask 'clean', -> require('rimraf').sync('lib')
-  # grunt.registerTask('lint', ['coffeelint:src', 'coffeelint:test'])
-  grunt.registerTask('default', ['babel'])
-  grunt.registerTask('test', ['default', 'shell:test'])


chore: missed coveralls task config

chore: missed coveralls task config

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -50,6 +50,14 @@
         configFile: 'karma.conf.js'
         options: singleRun:true

+    coveralls:
+      options:
+        coverage_dir: '.coverage/',
+        debug: !!process.env.TRAVIS,
+        dryRun: !!process.env.TRAVIS,
+        force: true,
+        recursive: true
+
   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-watch'
   grunt.loadNpmTasks 'grunt-karma'


add dev env

add dev env

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -114,3 +114,7 @@
 		'copy:asset'
 		'manifest'
 	]
+	grunt.registerTask 'dev', [
+		'default'
+		'watch'
+	]


chore(grunt): fix "server:dist"

chore(grunt): fix "server:dist"

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -48,15 +48,11 @@
         port: 9000
         hostname: '*'
         livereload: 35729
-
-      livereload:
+        open: 'http://localhost:9000/'
+
+      server:
         options:
-          open: 'http://localhost:9000/'
           base: ['<%=bp.tmp%>', '<%=bp.app%>', '<%=bp.dist%>']
-
-      dist:
-        options:
-          base: '<%=bp.dist%>'

     shell:
       options:
@@ -268,14 +264,14 @@
         'shell:hooks'
         'clean:server'
         'concurrent:server'
-        'connect:livereload'
+        'connect:server'
         'karma:unit'
         'watch'
       ]
     else
       [
         'build'
-        'connect:dist:keepalive'
+        'connect:server:keepalive'
       ]

   grunt.registerTask 'precommit', [


Build the stdlib before copying files.

Build the stdlib before copying files.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -30,9 +30,9 @@
   grunt.registerTask 'build', [
     'clean',
     'peg:build',
+    'stdlib:build',
     'copy:build',
-    'coffee:build',
-    'stdlib:build'
+    'coffee:build'
   ]

   grunt.registerTask 'stdlib:build', [


fix output style in grunt-sass

fix output style in grunt-sass

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -37,7 +37,7 @@
     sass:
       dev:
         options:
-          style: 'expanded'
+          outputStyle: 'expanded'
           lineNumbers: true
           includePaths: [
             '<%= webAssetsPath %>/vendor/bootstrap-sass/assets/stylesheets'
@@ -51,7 +51,7 @@
         ]
       dist:
         options:
-          style: 'compressed'
+          outputStyle: 'compressed'
         files: [
           expand: true
           cwd: '<%= assetsPath %>/sass'


chore(Gruntfile): create less task config on runtime

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -7,6 +7,7 @@
 VENDOR_FILES     = 'lib/*/index.js'
 GRUNTFILE        = 'Gruntfile.coffee'
 TMP_DIR          = 'tmp'
+PLATFORMS        = ['android', 'ios','ios7']

 module.exports = (grunt) ->

@@ -87,36 +88,25 @@
         tasks: ['build', 'karma:unit:run']

     # internal tasks don't use by hand
-    less:
-      all:
-        dest: "#{DIST_DIR}/bradypodion.css"
-        src: ['<%= clean.tmp %>/bradypodion.less']
-      android:
-        dest: "#{DIST_DIR}/bradypodion.android.css"
-        src: ['<%= clean.tmp %>/bradypodion.less']
-      ios:
-        dest: "#{DIST_DIR}/bradypodion.ios.css"
-        src: ['<%= clean.tmp %>/bradypodion.less']
-      ios7:
-        dest: "#{DIST_DIR}/bradypodion.ios7.css"
-        src: ['<%= clean.tmp %>/bradypodion.less']
+    less: all:
+      dest: "#{DIST_DIR}/bradypodion.css"
+      src: ['<%= clean.tmp %>/bradypodion.less']

   grunt.registerTask 'cssbuild', ->
     # config
     template = 'modules/bradypodion.less'
     modules  = "#{MODULES_DIR}/directives/*/less/*.less"
-    possiblePlatforms = ['android', 'ios','ios7']

     # logic
     platforms = []
     if @args.length then @args.forEach (arg) ->
       arg = arg.toLowerCase()
-      index = possiblePlatforms.indexOf arg
+      index = PLATFORMS.indexOf arg
       if index >= 0
         platforms.push arg
-        possiblePlatforms.splice index, 1
+        PLATFORMS.splice index, 1
     else
-      platforms = possiblePlatforms
+      platforms = PLATFORMS

     fileContent = grunt.file.read template
     grunt.file.expand
@@ -134,11 +124,18 @@
     , modules

     grunt.file.write 'tmp/bradypodion.less', fileContent
-    lessTask =  if platforms is possiblePlatforms
+    lessTask =  if platforms is PLATFORMS
       'less:all'
     else
+      # create less task configuration on runtime depending on platforms
+      config = grunt.config.get 'less'
+      config.custom =
+        src: ["<%= clean.tmp %>/bradypodion.less"]
+        dest: "#{DIST_DIR}/bradypodion.#{platforms[0]}.css"
+      grunt.config.set 'less', config
+
       # TODO: handle custom builds like `cssbuild:ios:android`
-      "less:#{platforms[0]}"
+      "less:custom"

     grunt.task.run [
       lessTask


Ignore Uglify warnings

Ignore Uglify warnings

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -21,7 +21,7 @@
     copyIgnore: ['!script/**/*.js', '!script/{countries}']

   webpackPlugins = [
-    new webpack.optimize.UglifyJsPlugin(),
+    new webpack.optimize.UglifyJsPlugin({compress: { warnings: false }}),
     new webpack.BannerPlugin('front-phone - v'+pkg.version+' - https://vtex.github.io/front.phone/', {entryOnly: true})
   ]


use same url for development and production

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -37,19 +37,16 @@
     connect:
       options:
         port: 8000
+        base: 'dist'
       debug:
         options:
-          base: './'
           middleware: (connect, options) ->
             [
-              (req, res, next) ->
-                if req.url == '/'
-                  res.writeHead(302, {Location: 'dist'})
-                  res.end()
-                else
-                  next()
+              connect().use('/app',connect.static(__dirname+'/app'))
+              connect().use('/dist',connect.static(__dirname+'/dist'))
+              connect().use('/config',connect.static(__dirname+'/config'))
+              connect().use('/components',connect.static(__dirname+'/components'))
               connect.static(options.base)
-              connect.directory(options.base)
             ]
       production:
         options:
@@ -64,7 +61,7 @@
         ext: '.html'
         options:
           data:
-            config: require('./config/streetsmap'),
+            config: require('./config/app'),
             debug: true
       production:
         expand: true
@@ -74,7 +71,7 @@
         ext: '.html'
         options:
           data:
-            config: require('./config/streetsmap')
+            config: require('./config/app')
             debug: false

     handlebars:


Tab cleanup

Tab cleanup

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -4,12 +4,12 @@
     clean: ["build/js", "build/css"]

     concat:
-        options:
-            banner: "/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today(\"yyyy-mm-dd\") %> */\n"
+      options:
+        banner: "/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today(\"yyyy-mm-dd\") %> */\n"

-        dist:
-            src: ["build/js/<%= pkg.name %>.js"]
-            dest: "build/js/<%= pkg.name %>.js"
+      dist:
+        src: ["build/js/<%= pkg.name %>.js"]
+        dest: "build/js/<%= pkg.name %>.js"

     uglify:
       options:


Fix grunt watch and uglify tasks

Fix grunt watch and uglify tasks

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -75,7 +75,7 @@
             'components/lodash/lodash.js',
             'components/backbone/backbone.js',
             'components/backbone.shortcuts/index.js',
-            '<config:concat.dist.dest>'
+            '<%= concat.dist.dest %>'
           ]
       zepto:
         files:
@@ -94,7 +94,7 @@
           ]
     watch:
       files: [
-        '<config:coffeelint.files>'
+        '<%= coffeelint.files %>'
         'assets/templates/*.hbs'
         'assets/css/*.styl'
       ]


Grunt: Support TESTS envvar

Grunt: Support TESTS envvar

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -18,6 +18,7 @@
         src: ['spec/*.coffee']
         options:
           reporter: 'spec'
+          grep: process.env.TESTS

     # Coding standards
     coffeelint:


Simplify grunt file

Simplify grunt file

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -5,26 +5,20 @@
     clean: [ 'src/sass/_*-map.scss', 'index.html']

     'compile-handlebars':
-        # Generate icons map SCSS file
-        'icons-map':
+        # Generate map SCSS files
+        'maps':
             files: [
                 {
                     src: 'handlebars/templates/map-scss.handlebars',
-                    dest: 'src/sass/_icons-map.scss'
+                    dest: [
+                        'src/sass/_icons-map.scss', 'src/sass/_ships-map.scss'
+                    ]
                 }
             ]
-            templateData: 'src/json/icons-map.json',
-            helpers: 'handlebars/helpers/*.js'
-
-        # Generate ships map SCSS file
-        'ships-map':
-            files: [
-                {
-                    src: 'handlebars/templates/map-scss.handlebars',
-                    dest: 'src/sass/_ships-map.scss'
-                }
+            templateData: [
+                'src/json/icons-map.json',
+                'src/json/ships-map.json'
             ]
-            templateData: 'src/json/ships-map.json',
             helpers: 'handlebars/helpers/*.js'

         # Generate index.html from merged json
@@ -35,8 +29,11 @@
                     dest: 'index.html'
                 }
             ]
+            globals: [
+                'src/json/ships-map.json',
+                'src/json/icons-map.json'
+            ]
             partials: 'handlebars/templates/index-icon-set.handlebars'
-            globals: ['src/json/ships-map.json', 'src/json/icons-map.json']

     sass:
       compile:


Don't inline CSS

Don't inline CSS

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -54,7 +54,7 @@
     # Vulcanization compiles the Polymer elements into a HTML file
     exec:
       vulcanize:
-        command: 'node_modules/.bin/polymer-bundler --inline-css --strip-comments index.dist.html > index.html'
+        command: 'node_modules/.bin/polymer-bundler --strip-comments index.dist.html > index.html'

     # CoffeeScript compilation of tests
     coffee:


created new grunt task that tests compiled css

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -5,8 +5,14 @@
   grunt.loadNpmTasks 'grunt-contrib-connect'
   grunt.loadNpmTasks 'grunt-contrib-copy'
   grunt.loadNpmTasks 'grunt-contrib-watch'
+  grunt.loadNpmTasks 'grunt-contrib-csslint'
   grunt.loadNpmTasks 'grunt-exec'
   grunt.initConfig
+    csslint: test:
+      options: import: 2
+      expand: true
+      cwd: '_site/assets/'
+      src: '*.css'
     copy:
       jquery: files: [ {
         expand: true
@@ -84,4 +90,5 @@
     'connect:server'
     'watch'
   ]
+  grunt.registerTask 'test', [ 'csslint' ]
   grunt.registerTask 'default', [ 'serve' ]


Terminate literal RUNOFF blocks at ".end lit"

--- grammars/runoff.cson
+++ grammars/runoff.cson
@@ -117,7 +117,7 @@
 			# .LIT: Literal/monospaced text
 			contentName: "markup.raw.runoff"
 			begin: "(?i)((\\.)LIT)\\s*(?:$|\\n)"
-			end: "(?i)^(?=\\.EL(?:$|[\\s;!]))"
+			end: "(?i)^(?=\\.(?:EL|END\\s+LIT)(?:$|[\\s;!]))"
 			beginCaptures:
 				0: name: "keyword.function.name.runoff"
 				1: name: "entity.name.function.runoff"


Update config.cson

Update config.cson

--- IDE/atom/config.cson
+++ IDE/atom/config.cson
@@ -12,3 +12,6 @@
     surpressDirectoryArgument: false
   minimap:
     absoluteMode: true
+  "file-types":
+    "jade.tag": "source.jade",
+    "tag": "text.html"


i was apparently working on something

i was apparently working on something

--- examples/benchmark_async.coffee
+++ examples/benchmark_async.coffee
@@ -7,17 +7,17 @@

   bm.measure "composite", (outer) ->
     saneTimeout 5, ->
-      outer.measure "sync", ->
+      outer.measure "composite sync", ->
         a = []
         for i in [1..1000]
           a.push i
-      outer.measure "inner", (inner) ->
-        process.nextTick = -> inner.finish()

-async_benchmark.run
-  iterations: 10,
- (results) ->
-    console.log results.summarize()
+      outer.measure "composite inner", (inner) ->
+        saneTimeout 10, ->
+          inner.finish()
+
+async_benchmark.run {iterations: 3}, (results) ->
+  console.log JSON.stringify(results, null, 2)

 results_example =


browserify→webpack

browserify→webpack

--- gulp/tasks/js.coffee
+++ gulp/tasks/js.coffee
@@ -7,11 +7,8 @@

 browserSync  = require "browser-Sync"

-
 webpack      = require "gulp-webpack"
 webpackConf  = require '../../webpack.config.js'
-
-b.on 'update', bundle

 gulp.task "js", ()->
   gulp.src config.js.src+'main.js'


renaming

renaming

--- handlers/thread.iced
+++ handlers/thread.iced
@@ -8,7 +8,7 @@

 #=============================================================================

-class GetChallengeHandler extends Handler
+class GetSessionChallengeHandler extends Handler

   _handle : (cb) ->
     await sct.generate defer err, token
@@ -27,7 +27,7 @@

 #=============================================================================

-class InitHandler extends Handler
+class SessionInitHandler extends Handler

   needed_inputs : -> {
     "challenge.token"    : { checker : check_array(4) }
@@ -39,8 +39,8 @@
 #=============================================================================

 exports.bind_to_app = (app) ->
-  GetChallengeHandler.bind app, api_route("challenge"), GET
-  InitHandler.bind         app, api_route("init"), POST
+  GetSessionChallengeHandler.bind app, api_route("session/challenge"), GET
+  SessionInitHandler.bind         app, api_route("session/init"), POST

 #=============================================================================


thread server

thread server

--- handlers/thread.iced
+++ handlers/thread.iced
@@ -18,6 +18,7 @@
   input_template : -> {
     session_id : checkers.buffer(4)   # valid session ID
     i : checkers.buffer(8)            # the thread ID
+    etime : checkers.intval()
     users : checkers.array {
       min : 2,
       checker : arr_subchecker {
@@ -55,8 +56,14 @@
     dbtx.push q, args

     for u,i in @input.users
-      q = """INSERT INTO thread_keys (thread_id, user_zid, key_data, write_key)
+      q = """INSERT INTO thread_keys (thread_id, user_zid, key_data, write_key, etime)
+             VALUES(?,?,?,?,?)
           """
+      args = [ @input.i, i, u.ctext, u.t, @input.etime ]
+      dbtx.push q, args
+
+    await mm.db.transaction dbtx, defer err
+    cb err

   #----------------


Correction de la largeur de l'image

Correction de la largeur de l'image

--- js/game/entities/Plane.coffee
+++ js/game/entities/Plane.coffee
@@ -12,7 +12,7 @@
             @image = null

             # Dimensions
-            @width =  23 * 3
+            @width =  24 * 3
             @height = 16 * 3

             # Limites de vitesse (en pixels/s)


remove unneeded event handler

remove unneeded event handler

--- app/classifier/tasks/text/index.cjsx
+++ app/classifier/tasks/text/index.cjsx
@@ -64,6 +64,7 @@

   componentDidMount: ->
     @setState initOffsetHeight: @refs.textInput.offsetHeight
+    @updateHeight()

   setTagSelection: (e) ->
     textTag = e.target.value
@@ -84,10 +85,6 @@
     newAnnotation = Object.assign @props.annotation, {value}
     @props.onChange newAnnotation

-  handleClear: (e) ->
-    if e.which is 8 or e.which is 46
-      @setState textareaHeight: @state.initOffsetHeight
-
   updateHeight: ->
     @setState textareaHeight: @refs.textInput.scrollHeight + 2

@@ -102,7 +99,6 @@
           onChange={@handleChange}
           rows="1"
           style={height: @state.textareaHeight}
-          onKeyDown={@handleClear}
         />
       </label>
       {if @props.task.text_tags


Remove commented code

Remove commented code

--- scripts/welcome-to-zihub.coffee
+++ scripts/welcome-to-zihub.coffee
@@ -62,13 +62,4 @@

   robot.respond /la bienvenida/i, (msg) ->
     msg.reply welcomeMsg('')
-#    msg.reply 'hola #presentaciones # \#general \\#general \\\#general '
-#    robot.adapter.client.web.postMessage(msg.message.room, welcomeMsg(''), {as_user: true, link_names: true})
-#    robot.adapter.client.chat.postMessage(msg.mes   sage.room, welcomeMsg(''), {as_user: true, link_names: true})

-#    robot.adapter.client._apiCall("chat.postMessage", {
-#      channel: msg.message.rawMessage.channel,
-#      text: welcomeMsg(''),
-#      as_user: true
-#    })
-


Client: Poison Heal doesn't activate if at full HP

--- server/bw/data/abilities.coffee
+++ server/bw/data/abilities.coffee
@@ -692,6 +692,10 @@
 makeAbility 'Poison Heal', ->
   # Poison damage neutralization is hardcoded in Attachment.Poison and Toxic.
   this::endTurn = ->
+    # Return early so that:
+    # 1. We don't trigger ability activation if the pokemon won't be healed.
+    # 2. Ability activation must happen before HP animation.
+    return  if @pokemon.currentHP == @pokemon.stat('hp')
     if @pokemon.has(Status.Poison) || @pokemon.has(Status.Toxic)
       @pokemon.activateAbility()
       amount = @pokemon.stat('hp') >> 3


label free response text input

label free response text input

--- shared/src/components/exercise/mode.cjsx
+++ shared/src/components/exercise/mode.cjsx
@@ -68,6 +68,7 @@

     if mode is 'free-response'
       <textarea
+        aria-labelledby="question response text box"
         disabled={disabled}
         ref='freeResponse'
         placeholder='Enter your response'


fix search navigation, the changes have to go in the coffee script

--- solr/src/templates/page_templates.coffee
+++ solr/src/templates/page_templates.coffee
@@ -18,7 +18,7 @@
     template: """

-

+


app: Fix bug when joining invalid table.

--- Oghma/app.coffee
+++ Oghma/app.coffee
@@ -477,7 +477,7 @@
   join_table: ( which ) ->
     table = @allverse.table.with_name( which )[0]
     if ! table?
-      error( "Attempt to join non-existent table: #{which}" )
+      @error( "Attempt to join non-existent table: #{which}" )
       return

     if @tableverse.domain()?


tune colors for an old map look

tune colors for an old map look

--- app/world.coffee
+++ app/world.coffee
@@ -8,14 +8,14 @@
     # background
     r.rect(0, 0, @width, @height).attr(
       stroke: 'none',
-      fill: '0-#9bb7cb-#adc8da'
+      fill: '0-#f8d59b-#e8ad5d'
     )

     # country shapes
     r.setStart()
     for own _, shape of worldmap.shapes
       do (shape) ->
-        r.path(shape).attr(stroke: '#ccc6ae', fill: '#f0efeb', 'stroke-opacity': 0.25)
+        r.path(shape).attr(stroke: '#a23105', fill: '#b35317', 'stroke-opacity': 0.5)
     world = r.setFinish()

     # demonstrate the use of parseLatLon for marking a position by geo coords


Binding loops detection added

Binding loops detection added

--- impl/base/level1/binding.coffee
+++ impl/base/level1/binding.coffee
@@ -13,6 +13,8 @@
 	cache = Object.create null
 	(prop) ->
 		cache[prop] ||= "on#{utils.capitalize(prop)}Change"
+
+MAX_LOOPS = 50

 module.exports = (impl) ->
 	{items} = impl
@@ -161,7 +163,10 @@
 					connections.push Connection.factory @, component.objects, elem[0], elem[1]

 			# update
-			# @updatePending = false
+			`//<development>`
+			@updatePending = false
+			@updateLoop = 0
+			`//</development>`
 			Object.preventExtensions @

 			@update()
@@ -182,6 +187,17 @@
 			unless @args
 				return

+			`//<development>`
+			if @updatePending
+				if @updateLoop > MAX_LOOPS
+					return
+				if ++@updateLoop is MAX_LOOPS
+					log.error "Potential loop detected. Property binding '#{@prop}' on item '#{@item.toString()}' has been disabled."
+					return
+			else
+				@updateLoop = 0
+			`//</development>`
+
 			result = utils.tryFunction @func, @ctx, @args
 			unless result?
 				result = getDefaultValue @
@@ -189,9 +205,13 @@
 			if typeof result is 'number' and not isFinite(result)
 				result = getDefaultValue @

-			# @updatePending = true
+			`//<development>`
+			@updatePending = true
+			`//</development>`
 			@obj[@prop] = result
-			# @updatePending = false
+			`//<development>`
+			@updatePending = false
+			`//</development>`
 			return

 		destroy: ->
@@ -212,9 +232,6 @@
 	setItemBinding: (prop, binding, component, ctx) ->
 		data = @_impl
 		data.bindings ?= {}
-
-		# if data.bindings[prop]?.updatePending
-		# 	return

 		data.bindings[prop]?.destroy()


Don't allow loading users sessions for non premium dashboards. Hoist memberLimit variable Don't sort member's on the server side, let the client handle it Use mongo limits instead of breaking server side.

--- server/clans/clan_handler.coffee
+++ server/clans/clan_handler.coffee
@@ -9,6 +9,8 @@
 LevelSessionHandler = require '../levels/sessions/level_session_handler'
 User = require '../users/User'
 UserHandler = require '../users/user_handler'
+
+memberLimit = 200

 ClanHandler = class ClanHandler extends Handler
   modelClass: Clan
@@ -94,17 +96,15 @@

   getMemberAchievements: (req, res, clanID) ->
     # TODO: add tests
-    memberLimit = 200
     Clan.findById clanID, (err, clan) =>
       return @sendDatabaseError(res, err) if err
       return @sendNotFoundError(res) unless clan
       memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
-      User.find {_id: {$in: memberIDs}}, 'nameLower', {sort: {nameLower: 1}}, (err, users) =>
+      User.find {_id: {$in: memberIDs}}, 'nameLower', {limit: memberLimit}, (err, users) =>
         return @sendDatabaseError(res, err) if err
         memberIDs = []
         for user in users
           memberIDs.push user.id
-          break unless memberIDs.length < memberLimit
         EarnedAchievement.find {user: {$in: memberIDs}}, 'achievementName user', (err, documents) =>
           return @sendDatabaseError(res, err) if err?
           cleandocs = (EarnedAchievementHandler.formatEntity(req, doc) for doc in documents)
@@ -115,8 +115,8 @@
     Clan.findById clanID, (err, clan) =>
       return @sendDatabaseError(res, err) if err
       return @sendNotFoundError(res) unless clan
-      memberIDs = clan.get('members') ? []
-      User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {sort: {nameLower: 1}}, (err, users) =>
+      memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
+      User.find {_id: {$in: memberIDs}}, 'name nameLower points heroConfig.thangType', {}, (err, users) =>
         return @sendDatabaseError(res, err) if err
         cleandocs = (UserHandler.formatEntity(req, doc) for doc in users)
         @sendSuccess(res, cleandocs)
@@ -124,12 +124,12 @@
   getMemberSessions: (req, res, clanID) ->
     # TODO: add tests
     # TODO: restrict information returned based on clan type
-    memberLimit = 200
     Clan.findById clanID, (err, clan) =>
       return @sendDatabaseError(res, err) if err
       return @sendNotFoundError(res) unless clan
+      return @sendForbiddenError(res) unless clan.get('dashboardType') is 'premium'
       memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
-      User.find {_id: {$in: memberIDs}}, 'name', {sort: {name: 1}}, (err, users) =>
+      User.find {_id: {$in: memberIDs}}, 'name', {limit: memberLimit}, (err, users) =>
         return @sendDatabaseError(res, err) if err
         memberIDs = []
         for user in users


+ lint okay

+ lint okay

--- test/usage_test.coffee
+++ test/usage_test.coffee
@@ -41,9 +41,11 @@
       data = [x**2 for x in range(len(100))]
       ```
       """
+      #coffeelint: disable=max_line_length
       output = """

Here's a beautiful Python Code for my love:

data = [x**2 for x in range(len(100))]

\n
       """
+      #coffeelint: enable=max_line_length
       expect(cb.compileMarkdown(input)).to.equal(output)


Refactor main.js

Refactor main.js

--- source/assets/javascripts/main.js.coffee
+++ source/assets/javascripts/main.js.coffee
@@ -12,70 +12,6 @@
 # ==============================================================================
 # PUSHDOWN
 # ========
-
-# ------------------------------------------------------------------------------
-# Reusable
-# --------
-
-  # pushIt = (selector) ->
-  #   e = $(selector)
-  #   if e.css('top') == '0px'
-  #     e.css('top', '+=520')
-  #   else
-  #     e.css('top', '0')
-
-  # openPanel = (panel, banner, extra) ->
-  #   $(panel).slideDown(1500)
-  #   $(banner).fadeOut(1200)
-  #   pushIt(extra)
-  #   coachVideo.play()
-
-  # closePanel = (panel, banner, extra) ->
-  #   $(panel).slideUp(1500)
-  #   $(banner).fadeIn(2000)
-  #   pushIt(extra)
-  #   coachVideo.pause()
-  #   return
-
-  # panelAction = (selector, action, panel, banner, extra) ->
-  #   $(selector).on 'click', 'h3', ->
-  #     action(panel, banner, extra)
-  #   return
-
-  # panelAction('.expand',   openPanel,  '#panel', '#banner', '#extra')
-  # panelAction('.collapse', closePanel, '#panel', '#banner', '#extra')
-
-
-  # $('.panel').on 'click', (e) ->
-  #   if e.target == @
-  #     window.open("http://www.coach.com/", "_blank")
-
-  # $('video').on 'click', ->
-  #   coachVideo.pause()
-
-  # window.onload = ->
-  #   setTimeout (->
-  #     openPanel('#panel', '#banner', '#extra')
-  #     setTimeout (->
-  #       closePanel('#panel', '#banner', '#extra')
-  #     ), 9000
-  #   ), 1000
-
-# ------------------------------------------------------------------------------
-# Concise
-# -------
-
-  timer = undefined
-  isMouseOver = false
-
-  startTimeout = () ->
-    timer = window.setTimeout (->
-      console.log("closing")
-      closePanel()
-    ), 8000
-
-  stopTimeout = () ->
-    window.clearTimeout(timer)

   pushIt = () ->
     extra = $('#extra')
@@ -112,7 +48,24 @@

   $('video').on 'click', ->
     coachVideo.pause()
+
+
+# ==============================================================================
+# USER INTERACTION
+# ================

+  timer = undefined
+  isMouseOver = false
+
+  startTimeout = () ->
+    timer = window.setTimeout (->
+      console.log("closing")
+      closePanel()
+    ), 8000
+
+  stopTimeout = () ->
+    window.clearTimeout(timer)
+
   window.onload = ->
     window.setTimeout (->
       openPanel()


Fix bug in user interaction on auto expand

--- source/assets/javascripts/main.js.coffee
+++ source/assets/javascripts/main.js.coffee
@@ -72,7 +72,7 @@

   startTimeout = () ->
     timer = window.setTimeout (->
-      closePanel()
+      closePanel() if isPanelOpen == true and isMouseOver == false
     ), 8000
     return

@@ -83,14 +83,14 @@
   window.onload = ->
     window.setTimeout (->
       openPanel()
-      startTimeout() if isMouseOver == false
+      startTimeout()
     ), 1000
     document.getElementById('panel').onmouseover = ->
       isMouseOver = true
       stopTimeout()
     document.getElementById('panel').onmouseout = ->
       isMouseOver = false
-      startTimeout() if isPanelOpen == true
+      startTimeout()
     return


handle 3 chagim tables safely when they are rosh hashana, som gedalia and shabbat

--- source/javascripts/index/schedule.coffee
+++ source/javascripts/index/schedule.coffee
@@ -69,6 +69,10 @@
         switch
           when $("#chagim-tables > div.shabbat .zachor").not(".hidden").size() > 0 then [5,7]
           else [6,6]
+      when 3
+        switch
+          when $("#chagim-tables > div.rosh-hashana").not(".hidden").size() > 0 then [6,6,6]
+          else throw "This should never happen!"
     visible_tables.each (i) -> $(this).addClass("col-xs-#{new_width[i]}")

 $ ->


Properly escapes - in regex.

Properly escapes - in regex.


on login-success if CurrentUser() hasn't ever joined a group yet, do nothing except stop loadbar

--- app/boot.coffee
+++ app/boot.coffee
@@ -27,6 +27,8 @@
             $location.path('/')
             Dialog.alert(title: 'error!', content: 'invalid credentials!')
             LoadBar.stop()
+      else
+        LoadBar.stop()

   $rootScope.$on '$stateChangeError', (e, toState, toParams, fromState, fromParams, error) ->
     console.log('$stateChangeError signal fired!')


refactored app.coffee

refactored app.coffee

--- platform/src/app.coffee
+++ platform/src/app.coffee
@@ -1,42 +1,67 @@
+### Constants ###
+
 globals = @

 CODE_CHANGE_TIMEOUT = 1000
+MessageType = GE.makeConstantSet("Error", "Info")
+SPINNER_OPTS =
+  lines: 9
+  length: 7
+  width: 4
+  radius: 10
+  corners: 1
+  rotate: 0
+  color: '#000'
+  speed: 1
+  trail: 60
+  shadow: false
+  hwaccel: false
+  className: 'spinner'
+  zIndex: 2e9
+  top: 'auto'
+  left: 'auto'

-$(document).ready ->
-  MessageType = GE.makeConstantSet("Error", "Info")

+### Globals ###
+
+spinner = new Spinner(SPINNER_OPTS)
+
+
+### Functions ###
+
+initCanvas = ->
   canvas = $("#gameCanvas")
   context = canvas[0].getContext("2d")
   context.setFillColor("black")
   context.fillRect(0, 0, canvas.width(), canvas.height())

-  editors = {}
-  onResize = ->
-    for editorName, editor of editors
-      session = editor.session
+adjustEditorToSize = (editor) ->
+  session = editor.session

-      editor.resize()
-      if session.getUseWrapMode()
-          characterWidth = editor.renderer.characterWidth
-          contentWidth = editor.renderer.scroller.clientWidth
+  editor.resize()
+  if session.getUseWrapMode()
+    characterWidth = editor.renderer.characterWidth
+    contentWidth = editor.renderer.scroller.clientWidth

-          if contentWidth > 0
-            limit = parseInt(contentWidth / characterWidth, 10)
-            session.setWrapLimitRange(limit, limit)
-  window.onresize = onResize
+    if contentWidth > 0
+      limit = parseInt(contentWidth / characterWidth, 10)
+      session.setWrapLimitRange(limit, limit)

-  showMessage = (messageType, message) ->
-    switch messageType
-      when MessageType.Error
-        $("#topAlertMessage").html(message)
-        $("#topAlert").show()
-      when MessageType.Info
-        $("#topInfoMessage").html(message)
-        $("#topInfo").show()
-      else throw new Error("Incorrect messageType")
+handleResize = -> for editorName, editor of editors then adjustEditorToSize(editor)

-  clearMessage = -> $("#topAlert, #topInfo").hide()
+showMessage = (messageType, message) ->
+  switch messageType
+    when MessageType.Error
+      $("#topAlertMessage").html(message)
+      $("#topAlert").show()
+    when MessageType.Info
+      $("#topInfoMessage").html(message)
+      $("#topInfo").show()
+    else throw new Error("Incorrect messageType")

+clearMessage = -> $("#topAlert, #topInfo").hide()
+
+setupLayout = ->
   # top
   $("#saveButton").button({ icons: { primary: "ui-icon-transferthick-e-w" }})
   $("#shareButton").button({ icons: { primary: "ui-icon-link" }})
@@ -52,12 +77,10 @@
     value: 0
   $("#resetButton").button({ icons: { primary: "ui-icon-arrowreturnthick-1-w" }, text: false })

-  # Based on http://layout.jquery-dev.net/demos/accordion.html
-
   $("#west").tabs()
   $("#south").tabs().addClass( "ui-tabs-vertical ui-helper-clearfix" )
   $("#south li").removeClass( "ui-corner-top" ).addClass( "ui-corner-left" )
-  $("#south li a").click(onResize)
+  $("#south li a").click(handleResize)

   # TODO: look for a callback for tabs
   $('body').layout
@@ -66,81 +89,7 @@
     north__size: 50
     west__size: 300
     applyDefaultStyles: true
-    onresize:  onResize
-
-  for id in ["modelEditor", "assetsEditor", "actionsEditor", "layoutEditor"]
-    editor = ace.edit(id)
-    editor.getSession().setMode("ace/mode/javascript")
-    editor.getSession().setUseWrapMode(true)
-    editor.setWrapBehavioursEnabled(true)
-    editors[id] = editor
-
-    editor.getSession().on "change", -> notifyCodeChange()
-
-  # TODO: find another way to include global data
-  globals.editors = editors
-
-  loadIntoEditor = (editorId, url) ->
-    $.ajax
-      url: url
-      dataType: "text"
-      cache: false
-      success: (data) ->
-        editors[editorId].setValue(data)
-        # The new contect will be selected by default
-        editors[editorId].selection.clearSelection()
-
-  loadIntoEditor("modelEditor", "optics/model.json")
-  loadIntoEditor("assetsEditor", "optics/assets.json")
-  loadIntoEditor("actionsEditor", "optics/actions.js")
-  loadIntoEditor("layoutEditor", "optics/layout.json")
-
-  runStep = ->
-    try
-      assets = JSON.parse(editors.assetsEditor.getValue())
-    catch error
-      return showMessage(MessageType.Error, "Assets error. #{error}")
-
-    try
-      modelData = JSON.parse(editors.modelEditor.getValue())
-    catch error
-      return showMessage(MessageType.Error, "Model error. #{error}")
-
-    try
-      actions = eval(editors.actionsEditor.getValue())
-    catch error
-      return showMessage(MessageType.Error, "Actions error. #{error}")
-
-    try
-      layout = JSON.parse(editors.layoutEditor.getValue())
-    catch error
-      return showMessage(MessageType.Error, "Assets error. #{error}")
-
-    showMessage(MessageType.Info, "Game updated")
-
-    gameController = new GE.GameController(new GE.Model(modelData), assets, actions, layout)
-    gameController.loadAssets (err) ->
-      if err? then throw err
-      gameController.step()
-
-  lastCodeChangeTimeoutId = null
-  notifyCodeChange = ->
-    timeoutCallback = ->
-      spinner.stop()
-      runStep()
-
-    spinner.spin($("#north")[0])
-    clearMessage()
-
-    # cancel previous timeout
-    if lastCodeChangeTimeoutId
-      window.clearTimeout(lastCodeChangeTimeoutId)
-      lastCodeChangeTimeoutId = null
-
-    # TODO: catch exceptions here?
-    window.setTimeout(timeoutCallback, CODE_CHANGE_TIMEOUT)
-
-  $(window).on 'beforeunload', -> 'If you leave the page, you will lose unsaved changes'
+    onresize: handleResize

   # TODO:
   # use requestAnimationFrame
@@ -162,23 +111,87 @@
         icons:
           primary: "ui-icon-play"

-  spinnerOpts =
-    lines: 9,
-    length: 7
-    width: 4
-    radius: 10
-    corners: 1
-    rotate: 0
-    color: '#000'
-    speed: 1
-    trail: 60
-    shadow: false
-    hwaccel: false
-    className: 'spinner'
-    zIndex: 2e9
-    top: 'auto'
-    left: 'auto'
-  spinner = new Spinner(spinnerOpts)
+setupEditor = (id) ->
+  editor = ace.edit(id)
+  editor.getSession().setMode("ace/mode/javascript")
+  editor.getSession().setUseWrapMode(true)
+  editor.setWrapBehavioursEnabled(true)
+  return editor

+loadIntoEditor = (editor, url) ->
+  $.ajax
+    url: url
+    dataType: "text"
+    cache: false
+    success: (data) ->
+      editor.setValue(data)
+      # The new contect will be selected by default
+      editor.selection.clearSelection()
+
+runStep = ->
+  try
+    assets = JSON.parse(editors.assetsEditor.getValue())
+  catch error
+    return showMessage(MessageType.Error, "Assets error. #{error}")
+
+  try
+    modelData = JSON.parse(editors.modelEditor.getValue())
+  catch error
+    return showMessage(MessageType.Error, "Model error. #{error}")
+
+  try
+    actions = eval(editors.actionsEditor.getValue())
+  catch error
+    return showMessage(MessageType.Error, "Actions error. #{error}")
+
+  try
+    layout = JSON.parse(editors.layoutEditor.getValue())
+  catch error
+    return showMessage(MessageType.Error, "Assets error. #{error}")
+
+  showMessage(MessageType.Info, "Game updated")
+
+  gameController = new GE.GameController(new GE.Model(modelData), assets, actions, layout)
+  gameController.loadAssets (err) ->
+    if err? then throw err
+    gameController.step()
+
+notifyCodeChange = ->
+  timeoutCallback = ->
+    spinner.stop()
+    runStep()
+
+  spinner.spin($("#north")[0])
+  clearMessage()
+
+  # cancel previous timeout
+  if notifyCodeChange.timeoutId
+    window.clearTimeout(notifyCodeChange.timeoutId)
+    notifyCodeChange.timeoutId = null
+
+  # TODO: catch exceptions here?
+  notifyCodeChange.timeoutId = window.setTimeout(timeoutCallback, CODE_CHANGE_TIMEOUT)
+
+### Start-up ###
+
+$(document).ready ->
+  initCanvas()
+  setupLayout()
+
+  editors = {}
+  for [id, url] in [["modelEditor", "optics/model.json"], ["assetsEditor", "optics/assets.json"], ["actionsEditor", "optics/actions.js"], ["layoutEditor", "optics/layout.json"]]
+    editor = setupEditor(id)
+    loadIntoEditor(editor, url)
+    editor.getSession().on "change", -> notifyCodeChange()
+    editors[id] = editor
+  # TODO: find another way to include global data
+  globals.editors = editors
+
+  # Setup event handlers
+  $(window).on "onresize", handleResize
+
+  $(window).on 'beforeunload', -> 'If you leave the page, you will lose unsaved changes'
+
+  # Load code
   notifyCodeChange()


back to making switchToPane king. reverts e55e237e60d401972d27646bb77a11dc2a3c99f0

--- extensions/tabs/tabs-pane.coffee
+++ extensions/tabs/tabs-pane.coffee
@@ -18,16 +18,14 @@
     # click tab
     tabPane = this
     $('#tabs ul li').live 'mousedown', ->
-      window.open $(this).data 'path'
+      tabPane.switchToTab this
       false

   nextTab: ->
-    if path = $('#tabs ul .active').next().data 'path'
-      window.open path
+    @switchToTab $('#tabs ul .active').next()

   prevTab: ->
-    if path = $('#tabs ul .active').prev().data 'path'
-      window.open path
+    @switchToTab $('#tabs ul .active').prev()

   switchToTab: (tab) ->
     tab = $("#tabs ul li").get(tab - 1) if _.isNumber tab
@@ -37,6 +35,7 @@
     path = $(tab).data 'path'
     $("#tabs ul .active").removeClass("active")
     $(tab).addClass 'active'
+    window.open path

   addTab: (path) ->
     existing = $("#tabs [data-path='#{path}']")


Cleanup

Cleanup

--- framer/DeviceView.coffee
+++ framer/DeviceView.coffee
@@ -60,12 +60,6 @@
 		@deviceType = defaults.deviceType

 		_.extend @, Utils.setDefaultProperties(options, defaults)
-
-
-
-
-
-

 	_setup: ->


Clean up old methods, add focus event

Clean up old methods, add focus event

--- framer/InputLayer.coffee
+++ framer/InputLayer.coffee
@@ -5,6 +5,7 @@
 Events.EnterKey  = "EnterKey"
 Events.BackSpaceKey  = "BackSpaceKey"
 Events.InputValueChange = "InputValueChange"
+Events.InputFocus = "InputFocus"

 class exports.InputLayer extends TextLayer
 	constructor: (options={}) ->
@@ -39,12 +40,11 @@
 		@html = ""

 		# Default focus interaction
-		@input.onfocus = ->
-			@style.color = "#000"
-			@value = ""
+		@input.onfocus = (e) =>
+			@input.style.color = "#000"
+			@input.value = ""
+			@emit(Events.InputFocus, event)

-		isInArray = (value, array) ->
-			return array.indexOf(value) > -1

 		@input.onkeyup = (e) =>

@@ -67,9 +67,7 @@
 	@define "value",
 		get: -> @input.value

-	@isInArray: (value, array) ->
-		return array.indexOf(value) > -1
-
 	onEnterKey: (cb) -> @on(Events.EnterKey, cb)
 	onBackSpaceKey: (cb) -> @on(Events.BackSpaceKey, cb)
 	onInputChange: (cb) -> @on(Events.InputValueChange, cb)
+	onInputFocus: (cb) -> @on(Events.InputFocus, cb)


Remove redundant last character substring filtering

--- framer/InputLayer.coffee
+++ framer/InputLayer.coffee
@@ -86,9 +86,6 @@

 		@_inputElement.onkeyup = (e) =>

-			# Check last character
-			lastCharacter = @_inputElement.value.substr(@_inputElement.value.length - 1)
-
 			# Exclude enter, shift, caps lock, control, alt, command etc.
 			unless e.which in [13, 16, 17, 18, 20, 91, 93]
 				@emit("change:value", @value)


editor (trivial): 'xsl' - extension for xml

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -66,7 +66,7 @@
     r      : 'r'
     rst    : 'rst'
     rb     : 'text/x-ruby'
-    ru        : 'text/x-ruby'
+    ru     : 'text/x-ruby'
     sage   : 'python'
     sagews : 'sagews'
     scala  : 'text/x-scala'
@@ -79,6 +79,7 @@
     bib    : 'stex'
     bbl    : 'stex'
     xml    : 'xml'
+    xsl    : 'xsl'
     yaml   : 'yaml'
     ''     : 'text'

@@ -268,7 +269,7 @@

 class exports.Editor
     constructor: (opts) ->
-
+
         opts = defaults opts,
             project_page  : required
             initial_files : undefined # if given, attempt to open these files on creation


trivial/trivial refactor in editor.coffee

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -549,9 +549,10 @@
         if not @codemirror?
             return

+        width = @element.width(); height = @element.height()
         $(@codemirror.getWrapperElement()).css
-            'max-height' : @element.height()
-            'max-width': @element.width()
+            'max-height' : height
+            'max-width'  : width

         @codemirror.focus()
         @codemirror.refresh()


increase json size to 2mb

increase json size to 2mb

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

-server.use bodyParser.json()
+server.use bodyParser.json(limit: "2mb")
 server.use metrics.http.monitor(logger)

 server.post "/user/:user_id/check", SpellingAPIController.check


Fixing 80 column layout

Fixing 80 column layout

--- app.coffee
+++ app.coffee
@@ -48,8 +48,7 @@

 # We need a super layer big enough to hold all the cards
-cardContainer                   = new Layer({width: (screenWidth*3),
-													 height: screenHeight})
+cardContainer                   = new Layer({width: (screenWidth*3), height: screenHeight})
 cardContainer.y                 = 0
 cardContainer.backgroundColor   = "transparent"
 cardContainer.draggable.enabled = true
@@ -173,4 +172,4 @@
  	    opacity: 1
  	  time: 0.4,
  	  #curve: "spring(400,50,0)"
- 	  curve: "cubic-bezier(0.7, 0.73, 0.17, 1.01)"+ 	  curve: "cubic-bezier(0.7, 0.73, 0.17, 1.01)"


fix metrics key name

fix metrics key name

--- app.coffee
+++ app.coffee
@@ -5,7 +5,7 @@
 restify = require 'restify'
 Path = require("path")
 metrics = require("metrics-sharelatex")
-metrics.initialize("tpds")
+metrics.initialize("spelling")
 metrics.mongodb.monitor(Path.resolve(__dirname + "/node_modules/mongojs/node_modules/mongodb"), logger)
 HealthCheckController = require("./app/js/HealthCheckController")


Remove debugging line

Remove debugging line

--- app.coffee
+++ app.coffee
@@ -51,7 +51,6 @@
 options = _.extend {port: 80, debug: false}, defaults, project, personal, _.pick(commander, 'port', 'debug')

 options.routes = _.extend {}, defaults.routes, project.routes, personal.routes
-console.log require('util').inspect defaults

 proxy.start options


FasterKoding: analytics to wait maincontroller before making a call

--- client/Main/analytic.coffee
+++ client/Main/analytic.coffee
@@ -6,5 +6,6 @@
       KD.mixpanel "Visit page, success", argsForMixpanel
       break

-    argsForMixpanel.username = KD.whoami()?.profile?.nickname
-    KD.remote.api.JPageHit.create argsForMixpanel, ->
+    KD.singletons.mainController.ready ->
+      argsForMixpanel.username = KD.whoami()?.profile?.nickname
+      KD.remote.api.JPageHit.create argsForMixpanel, ->


Run 'lint:es'

Run 'lint:es'

--- gulp/tasks/compile.coffee
+++ gulp/tasks/compile.coffee
@@ -4,7 +4,7 @@

 gulp.task("compile", ["compile:babel", "compile:coffee", "compile:scss", "compile:haml"])

-gulp.task "compile:babel", ->
+gulp.task "compile:babel", ["lint:es"], ->
   gulp.src(config.src.babel)
     .pipe($.plumber())
     .pipe($.sourcemaps.init())


isInRole method on Angular Role service

isInRole method on Angular Role service

takes a name and a list of ids and returns a promise that will resolve
to true if the name matches on of the given role ids or false otherwise

--- client/services/role.coffee
+++ client/services/role.coffee
@@ -1,5 +1,6 @@
 angular.module('app').factory 'Role'
-, ['$resource', ($resource) ->
+, ['$resource', '$filter', '$q'
+, ($resource, $filter, $q) ->

   methods =
     query:
@@ -75,10 +76,28 @@
   factory = () ->
     name: ''

+
+  isInRole = (name, roleIds) ->
+    deferred = $q.defer()
+    all (roles) ->
+      inRole = false
+      toCheck = $filter('filter')(roles, (role) ->
+
+        role.name.toLowerCase() is name.toLowerCase()
+      )
+      angular.forEach toCheck, (role) ->
+        angular.forEach roleIds, (id) ->
+          if id is role._id
+            inRole = true
+
+      deferred.resolve inRole
+    deferred.promise
+
   query: all
   all: all
   get: get
   create: factory
   destroy: destroy
   save: save
+  isInRole: isInRole
 ]


Fixes #3571: sort slash commands before filtering

rather than breaking out of the loop after processing the 11th slash command, we will process all of the slash commands, sort them alphabetically, then return the top 11

--- packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee
+++ packages/rocketchat-ui-message/message/popup/messagePopupConfig.coffee
@@ -148,11 +148,10 @@
 							params: item.params
 							description: TAPi18n.__ item.description

-					if commands.length > 10
-						break
-
 				commands = commands.sort (a, b) ->
 					return a._id > b._id
+
+				commands = commands[0..10]

 				template.resultsLength.set commands.length
 				return commands


Fix opening cases

Fix opening cases

--- static/coffee/services.coffee
+++ static/coffee/services.coffee
@@ -285,7 +285,9 @@
       data = new FormData()
       data.append('message', message.id)
       data.append('summary', summary)
-      data.append('assignee', if assignee then assignee.id else null)
+      if assignee
+        data.append('assignee', assignee.id)
+
       $http.post('/case/open/', data, DEFAULT_POST_OPTS)
       .success (_case) ->
         callback(_case)


Enable copy pase on right panel by adding 'native-key-bindings'

--- lib/atom-solidity-view.coffee
+++ lib/atom-solidity-view.coffee
@@ -4,6 +4,7 @@
         # Create root element
         @element = document.createElement('div')
         @element.classList.add('atom-solidity')
+        @element.classList.add('native-key-bindings')

         # Create message element
         message = document.createElement('div')
@@ -98,7 +99,7 @@

         # Appent to inputs
         cNode.appendChild(inputsNode)
-
+
         # Create button
         createButton = document.createElement('div')
         att = document.createAttribute('id')


translations for carousel images

translations for carousel images

--- components/body/data.coffee
+++ components/body/data.coffee
@@ -9,29 +9,29 @@
         image_url: './images/body-1-1.jpg',
         englishCaption: 'Musée du Louvre',
         caption:
-          simplified: '画廊',
+          simplified: '卢浮宫',
           traditional: '畫廊'
       },
       {
         image_url: './images/body-1-2.jpg',
         englishCaption: 'Los Angeles Modern Auctions',
         caption:
-          simplified: '美术馆',
-          traditional: '藝術館'
+          simplified: '拍卖行',
+          traditional: '盧浮宮'
       },
       {
         image_url: './images/body-1-3.jpg',
         englishCaption: 'Pearl Lam',
         caption:
-          simplified: '艺术博览会',
-          traditional: '藝術博覽會'
+          simplified: '艺术门',
+          traditional: '藝術門'
       },
       {
         image_url: "./images/body-1-4.jpg",
         englishCaption: 'The Armory Show',
         caption:
-          simplified: '拍卖会',
-          traditional: '拍賣會'
+          simplified: '博览会',
+          traditional: '博覽會'
       }
     ],
     artWorldBody: {


#10 common statistics page: tables are hidden while jquery loads data


Use getPath() internally

Use getPath() internally

--- src/app/git.coffee
+++ src/app/git.coffee
@@ -19,7 +19,7 @@
   getPath: -> @repo.getPath()

   getWorkingDirectory: ->
-    repoPath = @repo.getPath()
+    repoPath = @getPath()
     if repoPath
       repoPath.substring(0, repoPath.length - 5)


Add documentation for Biskoto

Add documentation for Biskoto

--- src/biskoto.coffee
+++ src/biskoto.coffee
@@ -1,8 +1,21 @@
 define ->
+  ###
+    A light version of the [Biskoto](https://github.com/skroutz/biskoto) module
+    to manipulate the `document.cookie`.
+  ###
   class Biskoto
     encode = encodeURIComponent
     decode = decodeURIComponent

+    ###
+      Retrieves the value for a given property of `document.cookie`
+
+      @example Get the Analytics Session ID from `document.cookie`.
+        Biskoto.get('analytics_session')
+
+      @param [String] name The name of the property to retrieve
+      @return [Object, null] The retrieved value as key-value object
+    ###
     @get: (name) ->
       if document.cookie
         cookies = document.cookie.split(/;\s/g)
@@ -17,20 +30,46 @@

       return null

+    ###
+      Sets a new `document.cookie` property
+
+      @example Set the Analytics Session ID to `document.cookie`.
+        Biskoto.set('analytics_session', 'analytics-47fd-8df3-277e55b7',
+          {expires: 60})
+
+      @param [String] name The key of the property to set
+      @param [Object] value The value of the property to set
+      @option [Object] options The options for the new property
+    ###
     @set: (name, value, options = {}) ->
       document.cookie = "#{name}=#{encode( JSON.stringify(value) )}#{@_cookieOptions(options)}"

+    ###
+      Forces a cookie to expire
+
+      @param [String] name The name of the cookie to expire
+      @option [Object] options Options for the cookie to expire
+
+      @todo Clean up. Param options really needed?
+    ###
     @expire: (name, options = {}) ->
       options.expires = -1
       @set(name, '', options)

     ###
-      options = {
-        expires : Integer (seconds)
-        secure  : Boolean
-        domain  : String
-        path    : String
-      }
+      Constructs a string out of a given set of options that is ready to be
+        appended to `document.cookie`.
+
+      @example Build the cookie string for given options
+        Biskoto._cookieOptions({
+          expires : 60                    // Integer in seconds
+          secure  : false                 // Boolean
+          domain  : 'http://example.com'  // String
+          path    : '/foo/bar/'           // String
+        })
+
+      @option [Object] options The options to parse
+      @return [String] The `document.cookie` ready string
     ###
     @_cookieOptions: (options = {}) ->
       cookie_str = ''
@@ -43,6 +82,12 @@

       cookie_str += "; path=#{if options.path then options.path else '/'}"

+    ###
+      Calculates the expiration date of a cookie for given seconds
+
+      @param [Number] seconds The time to live of cookie in seconds
+      @return [String] The expiration date of the cookie
+    ###
     @_createExpireDate: (seconds) ->
       new Date(
         +new Date() + (seconds * 1000)


Fix Biskoto to be compatible with PhantomJS's escaping of cookies

--- src/biskoto.coffee
+++ src/biskoto.coffee
@@ -5,19 +5,20 @@

     @get: (name) ->
       if document.cookie
-        cookies = decode(document.cookie).split(/;\s/g)
+        cookies = document.cookie.split(/;\s/g)

         for cookie in cookies
           if cookie.indexOf(name) is 0
+            value = decode(cookie.split('=')[1])
             try
-              return JSON.parse(cookie.split('=')[1])
+              return JSON.parse(value)
             catch err
-              return cookie.split('=')[1]
+              return value

       return null

     @set: (name, value, options = {}) ->
-      document.cookie = "#{name}=#{JSON.stringify(value)}#{@_cookieOptions(options)}"
+      document.cookie = "#{name}=#{encode( JSON.stringify(value) )}#{@_cookieOptions(options)}"

     @expire: (name, options = {}) ->
       options.expires = -1
@@ -47,5 +48,4 @@
         +new Date() + (seconds * 1000)
       ).toUTCString()

-  window.Biskoto = Biskoto
   return Biskoto


test: output stateparams

test: output stateparams

--- src/app/sessions/states/sign-in/sign-in.coffee
+++ src/app/sessions/states/sign-in/sign-in.coffee
@@ -41,6 +41,7 @@

     if $scope.SSOLoginUrl
       if $stateParams.authToken
+        console.log $stateParams
         # This is AAF and we just got an auth_token? Must request to sign in
         $scope.signIn({ auth_token: $stateParams.authToken, username: $stateParams.username })
       else


fix #27: easy standalone contexts

fix #27: easy standalone contexts

--- src/context.coffee
+++ src/context.coffee
@@ -66,7 +66,7 @@
     bound_fns

   create_base_context = ({module_names, imports}) ->
-    modules.load_modules(_.union imports, module_names or []).then (modules) ->
+    modules.load_modules(_.union imports or [], module_names or []).then (modules) ->
       {modules, imports}

   create_context = (base) ->
@@ -170,6 +170,11 @@

     run_context

+  create_standalone_context = ($el, {imports, module_names}={}) ->
+    create_base_context({imports: ['builtins'].concat(imports or []), module_names})
+    .then (base_context) ->
+      create_run_context $el, [create_context base_context]
+
   run_coffeescript_in_context = (run_context, string) ->
     try
       compiled = CoffeeScript.compile(string, bare: true) + "\n//@ sourceURL=console-coffeescript.js"
@@ -189,4 +194,4 @@
     catch e
       run_context.handle_exception e, string

-  {create_base_context, create_context, create_run_context, run_coffeescript_in_context, run_in_context, collect_extension_points}
+  {create_base_context, create_context, create_run_context, create_standalone_context, run_coffeescript_in_context, run_in_context, collect_extension_points}


Forgot to uncomment marking origin

Forgot to uncomment marking origin

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -4499,7 +4499,7 @@
   typeOrConstraint

 mutateMarkingOrigin = (typeOrConstraint, expression) ->
-  # typeOrConstraint.origin = expression
+  typeOrConstraint.origin = expression

 # Clones constrained types and parts of them
 # Class constraint arguments are not cloned


Fix nested caching in pattern matching, duh

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -869,8 +869,7 @@
     # ctx.setAssignTo "#{ctx.assignTo()}#{jsObjectAccess paramNames[i]}"
     ctx.setAssignTo (jsAccess ctx.assignTo(), paramNames[i])
     elemCompiled = expressionCompile ctx, arg
-    ctx.resetAssignTo()
-    elemCompiled)
+    withCache ctx.resetAssignTo(), elemCompiled)

   precsForData = operatorCompile ctx, call

@@ -995,9 +994,7 @@
         # "#{ctx.assignTo()}[#{i}]"
         ctx.setAssignTo (jsAccess ctx.assignTo(), "#{i}")
         elemCompiled = expressionCompile ctx, elem
-        cache = ctx.resetAssignTo()
-        precs: elemCompiled.precs
-        assigns: cache.concat elemCompiled.assigns or []
+        withCache ctx.resetAssignTo(), elemCompiled
     else
       termsCompile ctx, elems
   # TODO: could support partial tuple application via bare labels
@@ -1013,6 +1010,10 @@
     (labelOperator form)
     # "[#{listOf compiledElems}]"
     assignCompile ctx, form, (jsArray compiledElems)
+
+withCache = (cache, compiled) ->
+  precs: compiled.precs
+  assigns: cache.concat compiled.assigns or []

 seqOrMapCompile = (ctx, form) ->
   elems = _terms form
@@ -1049,8 +1050,7 @@
       ctx.setAssignTo rhs
       lhsCompiled = expressionCompile ctx, lhs
       retrieve elem, lhs
-      ctx.resetAssignTo()
-      lhsCompiled)
+      withCache ctx.resetAssignTo(), lhsCompiled)
     elemType = ctx.freshTypeVariable star
     # TODO use (Seq c e) instead of (Array e)
     form.tea = new Constrained (concatMap _constraints, (map _tea, elems)),


Fix compilation of constructors, the operator label overrode the const labeland broke it

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -87,7 +87,6 @@
     ['string', -> /^"/.test symbol]
     ['char', -> /^\\/.test symbol]
     ['regex', -> /^\/.*\/[gmi]?$/.test symbol]
-    ['const', -> /^[A-Z]([^\s\.-]|-(?=[A-Z]))*$/.test symbol] # TODO: instead label based on context
     ['paren', -> symbol in ['(', ')']]
     ['bracket', -> symbol in ['[', ']']]
     ['brace', -> symbol in ['{', '}']]
@@ -2879,7 +2878,8 @@
   contextType = ctx.type symbol
   # log "nameCompile", symbol, ctx.isInsideLateScope(), (printType contextType), ctx.isDeclared symbol
   if exp = ctx.assignTo()
-    if atom.label is 'const'
+    if isConst atom
+      atom.label = 'const'
       if contextType
         type: mapOrigin (freshInstance ctx, ctx.type symbol), atom
         pattern: constPattern ctx, symbol
@@ -2935,7 +2935,8 @@
   id = ctx.declarationId symbol
   ctx.addToUsedNames symbol
   translation =
-    if atom.label is 'const'
+    if isConst atom
+      atom.label = 'const'
       switch symbol
         when 'True' then 'true'
         when 'False' then 'false'
@@ -3370,6 +3371,9 @@

 isDotAccess = (atom) ->
   /^\.-?\w+/.test atom.symbol
+
+isConst = (atom) ->
+   /^[A-Z]([^\s\.-]|-(?=[A-Z]))*$/.test atom.symbol # TODO: instead label based on context

 isLabel = (atom) ->
   /[^\\]:$/.test atom.symbol
@@ -7194,6 +7198,20 @@
   """
   '(expand 3 "2")', ""

+  'using constructor in deferred definition'
+  """
+  Maybe (data [a]
+    None
+    Just [value: a])
+
+  test (fn []
+    (Just x)
+    x (test2))
+
+  test2 (fn []
+    42)
+  """
+  "(Just-value (test))", 42

   # TODO: support matching with the same name
   #       to implement this we need the iife to take as arguments all variables


Add a failing test for #7

Add a failing test for #7

--- spec/bracket-matcher-spec.coffee
+++ spec/bracket-matcher-spec.coffee
@@ -301,6 +301,15 @@
           expect(buffer.lineForRow(0)).toBe "\"\""
           expect(editor.getCursorBufferPosition()).toEqual [0, 1]

+    describe "when return is pressed after automatic insertion", ->
+      it "correctly triggers autoindent", ->
+        editor.insertText 'void main() '
+        editor.insertText '{'
+        expect(buffer.lineForRow(0)).toBe 'void main() {}'
+        editor.insertNewline()
+        expect(editor.getCursorBufferPosition().toArray()[0]).toEqual 1
+        expect(buffer.lineForRow(2)).toBe '}'
+
   describe "matching bracket deletion", ->
     it "deletes the end bracket when it directly proceeds a begin bracket that is being backspaced", ->
       buffer.setText("")


Remove file left behind.

Remove file left behind.

--- packages/deft/src/coffee/ioc/Injector.coffee
+++ packages/deft/src/coffee/ioc/Injector.coffee
@@ -1,273 +0,0 @@
-###
-Copyright (c) 2012-2013 [DeftJS Framework Contributors](http://deftjs.org)
-Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
-###
-
-###*
-A lightweight IoC container for dependency injection.
-
-## [Basic Configuration](https://github.com/deftjs/DeftJS/wiki/Basic-Application-and-IoC-Configuration)
-
-    // Common configuration, using dependency provider name and class.
-    Deft.Injector.configure({
-      companyStore: "DeftQuickStart.store.CompanyStore",
-      companyService: "DeftQuickStart.store.CompanyService"
-    });
-
-In the IoC configuration above, we have created two **dependency providers**, one named `companyStore` and one named `companyService`. By default, DeftJS uses lazy instantiation to create singleton instances of the `CompanyStore` and `CompanyService` classes. This means that a singleton won't be created until an object in your application specifies one of these dependency providers as an injected dependency.
-
-## [Singleton vs. Prototype Dependency Providers](https://github.com/deftjs/DeftJS/wiki/Singleton-vs.-Prototype-Dependency-Providers)
-
-By default, the dependency providers set up with the DeftJS `Injector` are singletons. This means that only one instance of that dependency will be created, and the same instance will be injected into all objects that request that dependency.
-
-For cases where this is not desired, you can create non-singleton (prototype) dependency providers like this:
-
-    Deft.Injector.configure({
-      editHistory: {
-        className: "MyApp.util.EditHistory",
-        singleton: false
-      }
-    });
-
-## [Lazy vs. Eager Dependency Creation](https://github.com/deftjs/DeftJS/wiki/Eager-vs.-Lazy-Instantiation)
-
-By default, dependency providers are created **lazily**. This means that the dependency will not be created by DeftJS until another object is created which specifies that dependency as an injection.
-
-In cases where lazy instantiation is not desired, you can set up a dependency provider to be created immediately upon application startup by using the `eager` configuration:
-
-    Deft.Injector.configure({
-      notificationService: {
-        className: "MyApp.service.NotificationService",
-        eager: true
-      }
-    });
-
-> **NOTE: Only singleton dependency providers can be eagerly instantiated.** This means that specifying `singleton: false` and `eager: true` for a dependency provider won't work. The reason may be obvious: DeftJS can't do anything with a prototype object that is eagerly created, since by definition each injection of a prototype dependency must be a new instance!
-
-## [Constructor Parameters](https://github.com/deftjs/DeftJS/wiki/Constructor-Parameters)
-
-If needed, constructor parameters can be specified for a dependency provider. These parameters will be passed into the constructor of the target object when it is created. Constructor parameters can be configured in the following way:
-
-    Deft.Injector.configure({
-      contactStore: {
-        className: 'MyApp.store.ContactStore',
-
-        // Specify an array of params to pass into ContactStore constructor
-        parameters: [{
-          proxy: {
-            type: 'ajax',
-            url: '/contacts.json',
-            reader: {
-              type: 'json',
-              root: 'contacts'
-            }
-          }
-        }]
-      }
-    });
-
-## [Factory Functions](https://github.com/deftjs/DeftJS/wiki/Factory-Functions)
-
-A dependency provider can also specify a function to use to create the object that will be injected:
-
-    Deft.Injector.configure({
-
-      contactStore: {
-        fn: function() {
-          if (useMocks) {
-            return Ext.create("MyApp.mock.store.ContactStore");
-          } else {
-            return Ext.create("MyApp.store.ContactStore");
-          }
-        },
-        eager: true
-      },
-
-      contactManager: {
-        // The factory function will be passed a single argument:
-        // The object instance that the new object will be injected into
-        fn: function(instance) {
-          if (instance.session.getIsAdmin()) {
-            return Ext.create("MyApp.manager.admin.ContactManager");
-          } else {
-            return Ext.create("MyApp.manager.user.ContactManager");
-          }
-        },
-        singleton: false
-      }
-
-    });
-
-When the Injector is called to resolve dependencies for these identifiers, the factory function is called and the dependency is resolved with the return value.
-
-As shown above, a lazily instantiated factory function can optionally accept a parameter, corresponding to the instance for which the Injector is currently injecting dependencies.
-
-Factory function dependency providers can be configured as singletons or prototypes and can be eagerly or lazily instantiated.
-
-> **NOTE: Only singleton factory functions can be eagerly instantiated.** This means that specifying `singleton: false` and `eager: true` for a dependency provider won't work. The reason may be obvious: DeftJS can't do anything with a prototype object that is eagerly created, since by definition each injection of a prototype dependency must be a new instance!
-
-###
-Ext.define( 'Deft.ioc.Injector',
-	alternateClassName: [ 'Deft.Injector' ]
-	requires: [
-		'Ext.Component'
-
-		'Deft.log.Logger'
-		'Deft.ioc.DependencyProvider'
-		'Deft.util.Function'
-	]
-	singleton: true
-
-	constructor: ->
-		@providers = {}
-		@injectionStack = []
-		return @
-
-	###*
-	Configure the Injector.
-	###
-	configure: ( configuration ) ->
-		Deft.Logger.log( 'Configuring the injector.' )
-		newProviders = {}
-		Ext.Object.each(
-			configuration,
-			( identifier, config ) ->
-				Deft.Logger.log( "Configuring dependency provider for '#{ identifier }'." )
-				if Ext.isString( config )
-					provider = Ext.create( 'Deft.ioc.DependencyProvider',
-						identifier: identifier
-						className: config
-					)
-				else
-					provider = Ext.create( 'Deft.ioc.DependencyProvider',
-						Ext.apply(
-							identifier: identifier,
-							config
-						)
-					)
-				@providers[ identifier ] = provider
-				newProviders[ identifier ] = provider
-				return
-			@
-		)
-		Ext.Object.each(
-			newProviders
-			( identifier, provider ) ->
-				if provider.getEager()
-					Deft.Logger.log( "Eagerly creating '#{ provider.getIdentifier() }'." )
-					provider.resolve()
-				return
-			@
-		)
-		return
-
-	###*
-	Reset the Injector.
-	###
-	reset: ->
-		Deft.Logger.log( 'Resetting the injector.' )
-		@providers = {}
-		return
-
-	###*
-	Indicates whether the Injector can resolve a dependency by the specified identifier with the corresponding object instance or value.
-	###
-	canResolve: ( identifier ) ->
-		provider = @providers[ identifier ]
-		return provider?
-
-	###*
-	Resolve a dependency (by identifier) with the corresponding object instance or value.
-
-	Optionally, the caller may specify the target instance (to be supplied to the dependency provider's factory function, if applicable).
-	###
-	resolve: ( identifier, targetInstance, targetInstanceConstructorArguments ) ->
-		provider = @providers[ identifier ]
-		if provider?
-			return provider.resolve( targetInstance, targetInstanceConstructorArguments )
-		else
-			Ext.Error.raise( msg: "Error while resolving value to inject: no dependency provider found for '#{ identifier }'." )
-		return
-
-	###*
-	Inject dependencies (by their identifiers) into the target object instance.
-	###
-	inject: ( identifiers, targetInstance, targetInstanceConstructorArguments, targetInstanceIsInitialized = true ) ->
-
-		targetClass = Ext.getClassName( targetInstance )
-
-		# Maintain a set of classes processed during this injection pass. If we hit a circular dependency, throw an error.
-		if( Ext.Array.contains( @injectionStack, targetClass ) )
-			stackMessage = @injectionStack.join( " -> " )
-			@injectionStack = []
-			Ext.Error.raise( msg: "Error resolving dependencies for '#{ targetClass }'. A circular dependency exists in its injections: #{ stackMessage } -> *#{ targetClass }*" )
-			return null
-
-		@injectionStack.push( targetClass )
-
-		injectConfig = {}
-		identifiers = [ identifiers ] if Ext.isString( identifiers )
-		Ext.Object.each(
-			identifiers
-			( key, value ) ->
-				targetProperty = if Ext.isArray( identifiers ) then value else key
-				identifier = value
-
-				resolvedValue = @resolve( identifier, targetInstance, targetInstanceConstructorArguments )
-				if targetProperty of targetInstance.config
-					Deft.Logger.log( "Injecting '#{ identifier }' into '#{ targetClass }.#{ targetProperty }' config." )
-					injectConfig[ targetProperty ] = resolvedValue
-				else
-					Deft.Logger.log( "Injecting '#{ identifier }' into '#{ targetClass }.#{ targetProperty }' property." )
-					targetInstance[ targetProperty ] = resolvedValue
-				return
-			@
-		)
-
-		@injectionStack = []
-
-		# Ext JS and Sencha Touch do not provide a consistent mechanism (across the target framework versions) for detecting whether initConfig() has been executed.
-		# Consequently, we rely on an optional method parameter to determine this state instead.
-		if targetInstanceIsInitialized
-			for name, value of injectConfig
-				setterFunctionName = 'set' + Ext.String.capitalize( name )
-				targetInstance[ setterFunctionName ].call( targetInstance, value )
-		else
-			if Ext.getVersion( 'extjs' )? and targetInstance instanceof Ext.ClassManager.get( 'Ext.Component' )
-				# NOTE: Ext JS's Ext.Component doesn't "play by the rules" and never actually calls Ext.Base::initConfig().
-				# Store the configs to be injected and apply via the constructor override define below.
-				targetInstance.injectConfig = injectConfig
-			else if Deft.isFunction( targetInstance.initConfig )
-				originalInitConfigFunction = targetInstance.initConfig
-				targetInstance.initConfig = ( config ) ->
-					result = originalInitConfigFunction.call( @, Ext.Object.merge( {}, config or {}, injectConfig ) )
-					return result
-
-		return targetInstance
-,
-	->
-		# NOTE: Ext JS's Ext.Component doesn't "play by the rules" and never calls Ext.Base::initConfig().
-		# Apply the stored configs to be injected via a constructor override.
-		if Ext.getVersion( 'extjs' )?
-			if Ext.getVersion( 'core' ).isLessThan( '4.1.0' )
-				# Ext JS 4.0
-				Ext.Component.override(
-					constructor: ( config ) ->
-						config = Ext.apply(config or {}, @injectConfig)
-						delete @injectConfig
-						return @callOverridden( [ config ] )
-				)
-			else
-				# Ext JS 4.1+
-				Ext.define( 'Deft.InjectableComponent',
-					override: 'Ext.Component'
-
-					constructor: ( config ) ->
-						config = Ext.apply(config or {}, @injectConfig)
-						delete @injectConfig
-						return @callParent( [ config ] )
-				)
-
-		return
-
-)


Add owner, owned keywords

Add owner, owned keywords

--- grammars/protosnirk.cson
+++ grammars/protosnirk.cson
@@ -37,11 +37,11 @@
     }
     'keyword_control': {
         'name': 'keyword.control.protosnirk'
-        'match': '\\b(return|break|continue|yield|if|else|match|for|while|do|with|is|in)\\b'
+        'match': '\\b(return|break|continue|yield|if|else|match|for|while|do|with|is)\\b'
     }
     'keyword_declaration': {
         'name': 'keyword.control.protosnirk'
-        'match': '\\b(use|import|public|struct|class|trait|enum|fn|strong|weak)\\b'
+        'match': '\\b(use|import|public|struct|class|trait|enum|fn|strong|weak|owned|owner)\\b'
     }
     'builtin_type': {
         'name': 'keyword.other.protosnirk'
@@ -49,7 +49,7 @@
     }
     'keyword_other': {
         'name': 'keyword.other.protosnirk'
-        'match': '\\b(or|and|not|bitand|bitor|bitxor|bitnot)\\b'
+        'match': '\\b(or|and|not|bitand|bitor|bitxor|bitnot|sameas|in)\\b'
     }
     'identifier': {
         'name': 'source.protosnirk' # Keep them basic


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/bounded.coffee
+++ src/bounded.coffee
@@ -85,7 +85,7 @@
   @returns {Number} Distance between the two objects
   ###
   distance: (otherObj) ->
-    Point.distance(self.position(), otherObj.position())
+    Point.distance(self.position(), otherObj.position())

   ###*
   The position of this game object. By default it is the top left point.