check for new Intercom messages every 10 seconds, see #479

--- client/code/router/main.coffee
+++ client/code/router/main.coffee
@@ -13,6 +13,7 @@
     @errorView ?= new Cu.View.ErrorAlert el: '#error-alert'
     @on 'route', @errorView.hide
     @on 'route', @trackPageView
+    @on 'route', @trackIntercom

     # TODO: this isn't a great place for this constant
     window.latestTerms = 1
@@ -47,13 +48,21 @@
   trackPageView: (e) ->
     path = Backbone.history.getFragment()
     _gaq.push ['_trackPageview', "/#{path}"]
+
+  trackIntercom: ->
     if 'real' of window.user and window.intercomUserHash != ''
       @getIntercomSettings (intercomSettings) ->
         if window.intercomBooted?
+          # tell Intercom we're still here
           window.Intercom 'update', intercomSettings
         else
+          # start Intercom, and tell it we're here
           window.Intercom 'boot', intercomSettings
           window.intercomBooted = true
+          # check for new Intercom messages/notifications every 10 seconds
+          setInterval ->
+            window.Intercom 'update'
+          , 10000

   getIntercomSettings: (cb) ->
     real = window.user.real


no need to add saved and error classes to editable title widget

--- client/code/view/subnav.coffee
+++ client/code/view/subnav.coffee
@@ -307,16 +307,8 @@
       $label.text(@newName).show()
       @model.set 'displayName', @newName
       @model.save {},
-        success: =>
-          $label.addClass 'saved'
-          setTimeout ->
-            $label.removeClass 'saved'
-          , 1000
         error: (e) =>
-          $label.text(@oldName).addClass 'error'
-          setTimeout ->
-            $label.removeClass 'error'
-          , 1000
+          $label.text @oldName
           @model.set 'displayName', @oldName
           console.warn 'error saving new name', e


update dataset settings breadcrumb on title change

--- client/code/view/titles.coffee
+++ client/code/view/titles.coffee
@@ -68,6 +68,9 @@

 class Cu.View.DatasetSettingsTitle extends Cu.View.Title
+  initialize: ->
+    @model.on 'change', @render, this
+
   render: ->
     tpl = """
       My Datasets


made About dialogue not modal

made About dialogue not modal

--- client/about.coffee
+++ client/about.coffee
@@ -33,7 +33,7 @@
     </div>
   """)
     .dialog
-      modal: 1, title: 'About', width: 520, height: 410, buttons: buttons
+      title: 'About', width: 520, height: 410, buttons: buttons
       open: -> $(@).find('textarea').focus(); return
     .find('textarea').val(info).select()
   return


Use prototype hasOwnProperty in JS for..in snippet

See <http://stackoverflow.com/q/12017693/560642>

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -177,7 +177,7 @@

   'for..in':
     'prefix': 'forin'
-    'body': 'for (var ${1:key} in ${2:object}) {\n\tif (${2:object}.hasOwnProperty(${1:key})) {\n\t\t$3\n\t}\n}'
+    'body': 'for (var ${1:key} in ${2:object}) {\n\tif Object.prototype.hasOwnProperty.call(${2:object}, ${1:key})) {\n\t\t$3\n\t}\n}'

   # Functions


Revert "Don't tokenize files that have more than 10000 lines"

This was a premature optimization. The real problem is
with the spell-check package.

This reverts commit 987d1da233c4514be86b78b70aa103a6fa82f9d6.

--- src/app/tokenized-buffer.coffee
+++ src/app/tokenized-buffer.coffee
@@ -62,11 +62,8 @@
     @invalidateRow(0)
     @trigger "changed", { start: 0, end: lastRow, delta: 0 }

-  tooBigToTokenize: ->
-    @screenLines.length > 10000
-
   tokenizeInBackground: ->
-    return if not @visible or @pendingChunk or @tooBigToTokenize()
+    return if not @visible or @pendingChunk
     @pendingChunk = true
     _.defer =>
       @pendingChunk = false


fix for REMOVAL of checked attr on checkbox

(similar changes may be needed for other elements,
see code for ADDITION of attributes)

--- src/client/client_engine.coffee
+++ src/client/client_engine.coffee
@@ -154,7 +154,10 @@
             else
                 target.setAttribute(name, value)
         else if attrChange == 'REMOVAL'
-            target.removeAttribute(name)
+            if /^checked$/.test(name)
+                target[name] = false
+            else
+                target.removeAttribute(name)
         else
             throw new Error("Invalid attrChange: #{attrChange}")


use same protocol as Page for Ships

use same protocol as Page for Ships

--- src/client/embeds/import.coffee
+++ src/client/embeds/import.coffee
@@ -1,5 +1,6 @@
 Promise  = require('es6-promise').Promise
 _        = require '../../utils/lodash'
+logger   = require '../../utils/logger'

 fjs = document.getElementsByTagName("script")[0]

@@ -8,7 +9,8 @@
     {href, shipId, container, scoped} = opts

     @shipId = shipId
-    @href = href
+    protocol = document.location.protocol
+    @href = href.replace(/^https?:/,protocol)
     @scoped = scoped

     if container


final code cleanup for utils.coffee

final code cleanup for utils.coffee

--- src/lib/utils.coffee
+++ src/lib/utils.coffee
@@ -12,8 +12,7 @@
 class Class

   # Override the default `toString` implementation to provide a cleaner output.
-  toString: ->
-    @constructor.name
+  toString: -> @constructor.name

 # Private variables
 # -----------------
@@ -43,7 +42,7 @@
   # Generate a unique key based on the current time and using a randomly
   # generated hexadecimal number of the specified length.
   keyGen: (separator = '.', length = 5, prefix = '', upperCase = yes) ->
-    parts  = []
+    parts = []
     # Populate the segment(s) to attempt uniquity.
     parts.push new Date().getTime()
     if length > 0
@@ -65,8 +64,7 @@
     entity for entity in entities when filter entity

   # Generate a random number between the `min` and `max` values provided.
-  random: (min, max) ->
-    Math.floor(Math.random() * (max - min + 1)) + min
+  random: (min, max) -> Math.floor(Math.random() * (max - min + 1)) + min

   # Repeat the string provided the specified number of times.
   repeat: (str = '', repeatStr = str, count = 1) ->
@@ -98,8 +96,7 @@
       0

   # Convenient shorthand for `chrome.extension.getURL`.
-  url: ->
-    chrome.extension.getURL arguments...
+  url: -> chrome.extension.getURL arguments...

 # Public classes
 # --------------
@@ -112,8 +109,7 @@
 class utils.Runner extends utils.Class

   # Create a new instance of `Runner`.
-  constructor: ->
-    @queue = []
+  constructor: -> @queue = []

   # Finalize the process by resetting this `Runner` an then calling `onfinish`,
   # if it was specified when `run` was called.
@@ -153,21 +149,19 @@
   # latter, `context` is ignored and should be `null` (not omitted). All of the
   # remaining `args` are passed to the function when it is called during the
   # process.
-  push: (context, reference, args...) ->
-    @queue.push
-      args:      args
-      context:   context
-      reference: reference
+  push: (context, reference, args...) -> @queue.push
+    args:      args
+    context:   context
+    reference: reference

   # Add a new task to the queue using the *packed* values provided.
   # This method varies from `push` since the arguments are provided in the form
   # of a function which is called immediately before the function, which allows
   # any dependent arguments to be correctly referenced.
-  pushPacked: (context, reference, packedArgs) ->
-    @queue.push
-      args:      packedArgs
-      context:   context
-      reference: reference
+  pushPacked: (context, reference, packedArgs) -> @queue.push
+    args:      packedArgs
+    context:   context
+    reference: reference

   # Start the process by calling the first task in the queue and register the
   # `onfinish` function provided.
@@ -176,5 +170,4 @@
     @next()

   # Remove the specified number of tasks from the front of the queue.
-  skip: (count = 1) ->
-    @queue.splice 0, count+  skip: (count = 1) -> @queue.splice 0, count


Warn if response has a deprecation header. Closes #56

--- src/coffee/services/base.coffee
+++ src/coffee/services/base.coffee
@@ -431,6 +431,10 @@
       errorBody = _.extend(responseJson, errorResp)
       reject new HttpError errorMessage, errorBody
     else
+      # check for API deprecation headers
+      if response.headers['X-DEPRECATION-NOTICE']
+        console.warn("Deprecation notice: #{response.headers['X-DEPRECATION-NOTICE']}")
+
       # TODO: check other possible acceptable codes (304, ...)
       if 200 <= response.statusCode < 300
         resolve _.extend responseJson,


For checkouts/details/status line, there is no need to display copy status if item is checked out.

--- src/account/checkouts.coffee
+++ src/account/checkouts.coffee
@@ -92,7 +92,7 @@

 						$list.prepend tpl_co_item {
 							circ_id: circ_id
-							circ_type: type
+							circ_type: if type is 'out' then '' else type
 						}

 						((type, $x) ->


show only one content section at a time

show only one content section at a time

--- client/index.coffee
+++ client/index.coffee
@@ -103,8 +103,7 @@

 	$('.navButton#btnPortfolio').click (e) ->
 		$('.navSection').not('#projects').slideUp()
-		$('.navButton').removeClass('active')
-		$(e.target).addClass('active')
+		$('.navButton').not('#btnPortfolio').removeClass('active')
 		checkBtnTopOffset()

 	$('.navButton').not('#btnPortfolio').click (e) ->
@@ -115,6 +114,8 @@
 			$section.slideUp()
 			$button.removeClass('active')
 		else
+			$('.navSection').not('#projects').slideUp()
+			$('.navButton').not('#btnPortfolio').removeClass('active')
 			$section.slideDown()
 			$button.addClass('active')
 		checkBtnTopOffset()


Tweak tags typeahead code

Tweak tags typeahead code

--- client/views/admin/edit.coffee
+++ client/views/admin/edit.coffee
@@ -98,20 +98,18 @@
         @$('.html-editor').html post.body

   # Tags
-  @$('input[data-role="tagsinput"]').tagsinput
-    confirmKeys: [13, 44, 9]
-
-  @$('input[data-role="tagsinput"]').tagsinput('input').typeahead(
+  $tags = @$('[data-role=tagsinput]')
+  $tags.tagsinput confirmKeys: [13, 44, 9]
+  $tags.tagsinput('input').typeahead(
     highlight: true,
     hint: false
   ,
     name: 'tags'
     displayKey: 'val'
     source: substringMatcher Tag.first().tags
-  ).bind('typeahead:selected', $.proxy (obj, datum) ->
-    this.tagsinput('add', datum.val)
-    this.tagsinput('input').typeahead('val', '')
-  , $('input[data-role="tagsinput"]'))
+  ).bind 'typeahead:selected', (obj, datum) ->
+    $tags.tagsinput 'add', datum.val
+    $tags.tagsinput('input').typeahead 'val', ''

   # Medium editor
   @editor = BlogEditor.make @


Add duplicate torrent upload message

Add duplicate torrent upload message

--- src/controllers/torrents.coffee
+++ src/controllers/torrents.coffee
@@ -25,39 +25,44 @@
         hasher.update bencode.bencode(torrentInfo.info)
         infohash = hasher.digest 'hex'

-        if fields.title
-          title = fields.title
-        else
-          title = torrentInfo.info.name.toString 'utf8'
-
-        torrentFiles = []
-        if torrentInfo.info.files
-          size = 0
-          for file in torrentInfo.info.files
-            torrentFiles.push {
-              'path' : (file.path.toString 'utf8'),
-              'size' : file.length
+        Torrent.findOne {'infohash' : infohash}, (err, doc) ->
+          if doc
+            req.flash 'error', 'This torrent is already uploaded'
+            res.redirect ('/torrent/' + doc.permalink)
+          else
+            if fields.title
+              title = fields.title
+            else
+              title = torrentInfo.info.name.toString 'utf8'
+
+            torrentFiles = []
+            if torrentInfo.info.files
+              size = 0
+              for file in torrentInfo.info.files
+                torrentFiles.push {
+                  'path' : (file.path.toString 'utf8'),
+                  'size' : file.length
+                }
+                size += file.length
+            else
+              size = torrentInfo.info.length
+              torrentFiles.push {
+                'path' : (torrentInfo.info.name.toString 'utf8'),
+                'size' : torrentInfo.info.length
+              }
+
+            torrent = new Torrent {
+              'infohash' : infohash,
+              'size'     : size,
+              'title'    : title,
+              'files'    : torrentFiles,
+              'description' : fields.description
             }
-            size += file.length
-        else
-          size = torrentInfo.info.length
-          torrentFiles.push {
-            'path' : (torrentInfo.info.name.toString 'utf8'),
-            'size' : torrentInfo.info.length
-          }
-
-        torrent = new Torrent {
-          'infohash' : infohash,
-          'size'     : size,
-          'title'    : title,
-          'files'    : torrentFiles,
-          'description' : fields.description
-        }
-        torrent.generatePermalink (err) ->
-          torrent.save (err) ->
-            fs.writeFile (__dirname+'/../../torrents/' + infohash + '.torrent'), data, (err) ->
-              fs.unlink files.torrent.path, (err) ->
-                res.redirect '/'
+            torrent.generatePermalink (err) ->
+              torrent.save (err) ->
+                fs.writeFile (__dirname+'/../../torrents/' + infohash + '.torrent'), data, (err) ->
+                  fs.unlink files.torrent.path, (err) ->
+                    res.redirect ('/torrent/' + torrent.permalink)
   else
     req.flash 'error', "There was an error with the upload form"
     res.redirect '/upload'


just use @ejs_runtime.array_new instead of a local in visitArrayExpression.  also add an unreachable ir instruction after the call to _ejs_throw to help the optimizer out.

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -954,8 +954,7 @@
                 obj

         visitArrayExpression: (n) ->
-                array_new = @ejs_runtime.array_new
-                obj = @createCall array_new, [consts.int32 n.elements.length], "arrtmp", !array_new.doesNotThrow
+                obj = @createCall @ejs_runtime.array_new, [consts.int32 0], "arrtmp", !@ejs_runtime.array_new.doesNotThrow
                 i = 0;
                 for el in n.elements
                         val = @visit el
@@ -1109,6 +1108,7 @@
         visitThrow: (n) ->
                 arg = @visit n.argument
                 @createCall @ejs_runtime.throw, [arg], "", true
+                ir.createUnreachable()

         visitTry: (n) ->
                 insertBlock = ir.getInsertBlock()


provide atom's path to julia

provide atom's path to julia

--- lib/frontend.coffee
+++ lib/frontend.coffee
@@ -6,3 +6,6 @@
     client.handle 'select', ({items}, resolve) =>
       selector.show items, (item) =>
         resolve item: item
+
+    client.handle 'atompath', (_, resolve) =>
+      resolve result: atom.config.resourcePath


Show correct information for submodules paths

Use Git::getCachedUpstreamAheadBehindCount API to correctly update the
ahead/behind count for files inside submodules.

Also updates the HEAD label to use the correct repository for the current
item path.

Closes #22

--- lib/git-view.coffee
+++ lib/git-view.coffee
@@ -52,7 +52,7 @@
     @branchArea.hide()
     return unless atom.project.contains(@getActiveItemPath())

-    head = atom.project.getRepo()?.getShortHead() or ''
+    head = atom.project.getRepo()?.getShortHead(@getActiveItemPath()) or ''
     @branchLabel.text(head)
     @branchArea.show() if head

@@ -65,17 +65,19 @@
     repo = atom.project.getRepo()
     return unless repo?

-    if repo.upstream.ahead > 0
-      @commitsAhead.text(repo.upstream.ahead).show()
+    upstream = repo.getCachedUpstreamAheadBehindCount(itemPath) ? {}
+
+    if upstream.ahead > 0
+      @commitsAhead.text(upstream.ahead).show()
     else
       @commitsAhead.hide()

-    if repo.upstream.behind > 0
-      @commitsBehind.text(repo.upstream.behind).show()
+    if upstream.behind > 0
+      @commitsBehind.text(upstream.behind).show()
     else
       @commitsBehind.hide()

-    @commitsArea.show() if repo.upstream.ahead > 0 or repo.upstream.behind > 0
+    @commitsArea.show() if upstream.ahead > 0 or upstream.behind > 0

     status = repo.statuses[itemPath]
     @gitStatusIcon.removeClass()


added file based grammar for D

added file based grammar for D

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -53,6 +53,11 @@
       command: "coffee"
       args: (context) -> [context.filepath]

+  D:
+    "File Based":
+      command: "rdmd"
+      args: (context) -> [context.filepath]
+
   Elixir:
     "Selection Based":
       command: "elixir"


Only listen for model changes if model is defined

--- src/scripts/modules/search/header/header.coffee
+++ src/scripts/modules/search/header/header.coffee
@@ -8,4 +8,4 @@

     initialize: () ->
       super()
-      @listenTo(@model, 'change:results', @render)
+      @listenTo(@model, 'change:results', @render) if @model


VirtualMethod doc stub should contain new  method (closes #87)

--- src/nodes/doc.coffee
+++ src/nodes/doc.coffee
@@ -261,6 +261,7 @@
             todos: doc.todos
             examples: doc.examples
             authors: doc.authors
+            hasComment: -> true

       else
         comment.push line


Create requestClient immediately after config changes.

--- src/nodeswork.coffee
+++ src/nodeswork.coffee
@@ -50,8 +50,13 @@
       when 'DEV' then _.extend @opts, envOpts, opts
       when 'PROD' then _.extend @opts, opts, envOpts

-    @opts.env = env
-    @jar      = @opts.jar ? request.jar()
+    @opts.env       = env
+    @jar            = @opts.jar ? request.jar()
+    @requestClient  = request.defaults {
+      jar:                 @jar
+      followAllRedirects:  true
+      json:                true
+    }
     @

   withAccount: (accountClazz...) ->
@@ -89,12 +94,6 @@

     unless @opts.port?
       throw new Error "Required configuration 'port' is missing."
-
-    @requestClient = request.defaults {
-      jar:                 @jar
-      followAllRedirects:  true
-      json:                true
-    }

     @app
       .use bodyParser()


removing debug time option

removing debug time option

--- tutor/src/helpers/time.coffee
+++ tutor/src/helpers/time.coffee
@@ -13,7 +13,6 @@
   'US/Eastern': 'Eastern Time (US & Canada)'
   'US/East-Indiana': 'Indiana (East)'
   'Canada/Atlantic': 'Atlantic Time (Canada)'
-  'Asia/Shanghai': 'Shanghai'

 ISO_DATE_REGEX = /\d{4}[\/\-](0[1-9]|1[012])[\/\-](0[1-9]|[12][0-9]|3[01])/
 ISO_TIME_REGEX = /([01][0-9]|2[0-3]):[0-5]\d/


:fire: leftover

:fire: leftover

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -129,7 +129,6 @@

   addOccurrencePattern: (pattern=null) ->
     pattern ?= @patternForOccurrence
-    console.log 'P', pattern
     unless pattern?
       point = @getCursorBufferPosition()
       pattern = getWordPatternAtBufferPosition(@editor, point, singleNonWordChar: true)


Update baseview background Image

Update baseview background Image

--- Framework/Views/BaseView.coffee
+++ Framework/Views/BaseView.coffee
@@ -6,7 +6,7 @@
       backgroundColor: root.app.settings.viewBackgroundColor
       backgroundGradient: root.app.settings.viewBackgroundGradient
       barColor: root.app.settings.viewTitleBarColor
-      #backgroundImage: root.app.settings.viewBackgroundImage     # Commented out: CMC : Causing backgroundColor to fail on Android when '' | null
+      backgroundImage: root.app.settings.viewBackgroundImage     # Commented out: CMC : Causing backgroundColor to fail on Android when '' | null
       viewTitleBarStyle: root.app.settings.viewTitleBarStyle
       useImageButtons: root.app.settings.useImageButtons
       orientationModes: root.app.settings.defaultOrientationModes


handle remove and start app events

handle remove and start app events

--- client/main.cjsx
+++ client/main.cjsx
@@ -31,6 +31,8 @@
   onEvent 'app name selected', storeDataInSession('selectedAppName'), (app) -> browserHistory.push("/apps/#{app.name}/#{app.version}")
   onEvent 'app search entered', storeDataInSession('appSearchValue')
   onEvent 'stop instance', (instanceName) -> ddp.call 'stopInstance', instanceName
+  onEvent 'remove app', (app) -> console.log 'remove app', app
+  onEvent 'start app', (app) -> console.log 'start app', app

   emit: (evt, data) -> eventEmitter.emit evt, data
   collections:


updated methods

updated methods

--- src/drm-flexible-grid.coffee
+++ src/drm-flexible-grid.coffee
@@ -1,12 +1,14 @@
 ###############################################################################
-# Creates a Pinterest like sortable, draggable grid
+# Creates a Pinterest like sortable, image grid
 ###############################################################################
+#TODO: add check so that one column doesn't get too long. Skip it and move to the next column
 "use strict"

+$ = jQuery
 # adds case insensitive contains to jQuery

 $.extend $.expr[":"], {
-    "containsNC": (elem, i, match, array) ->
+    "containsNC": (elem, i, match) ->
         (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0
 }

@@ -14,138 +16,155 @@
     constructor: (@gridClass = 'drm-flexible-grid', @imagesPerRow = 4, @flex = true) ->
         self = @
         self.grid = $ ".#{self.gridClass}"
-        self.gridNav = $ '.drm-grid-nav'
-        self.items = self.grid.find '.drm-grid-item'

-        $(window).load ->
-            self.positionListItems()
-            self.addFilterButtons()
+        if self.grid.length isnt 0
+            self.gridNav = $ '.drm-grid-nav'
+            self.items = self.grid.find('.drm-grid-item').hide()
+            hash = window.location.hash

-        if self.flex
-            $(window).resize ->
-                self.positionListItems()
-                self.resizeCurtain()
+            $(window).load ->
+                self.tags = self.getTags()
+                filter = if hash then hash.replace /^#/, '' else null
+                self.addFilterButtons self.tags
+                self.filterListItems filter

-        $(window).load self.resizeCurtain
+                if filter
+                    activeButton = $("button.drm-grid-filter[data-filter=#{filter}]")
+                    activeButton.siblings('button').removeClass 'active'
+                    activeButton.addClass 'active'

-        self.grid.on 'mouseenter', '.drm-grid-item', ->
-            $(@).find('.curtain').stop().fadeIn 'fast'
+            if self.flex
+                $(window).resize ->
+                    items = self.grid.find '.drm-grid-item'
+                    self.positionListItems items
+                    self.resizeCurtain()

-        self.grid.on 'mouseleave', '.drm-grid-item', ->
-            $(@).find('.curtain').stop().fadeOut 'fast'
+            $(window).load self.resizeCurtain

-        self.gridNav.on 'click', 'button.drm-grid-filter', ->
-            that = $ @
-            filter = that.data('filter').toLowerCase()
-            self.filterListItems filter
-            that.siblings('button').removeClass 'active'
-            that.addClass 'active'
+            self.grid.on 'mouseenter', '.drm-grid-item', ->
+                $(@).find('.curtain').stop().fadeIn 'fast'

-    capitalize: (str) ->
-        str.toLowerCase().replace /^.|\s\S/g, (a) ->
-            a.toUpperCase()
+            self.grid.on 'mouseleave', '.drm-grid-item', ->
+                $(@).find('.curtain').stop().fadeOut 'fast'

-    addFilterButtons: =>
+            self.gridNav.on 'click', 'button.drm-grid-filter', ->
+                _that = $ @
+                filter = _that.data('filter').toLowerCase()
+                self.filterListItems filter
+                _that.siblings('button').removeClass 'active'
+                _that.addClass 'active'
+
+    getTags: =>
         self = @
         tags = []
-        tagListItems = self.grid.find 'ul.caption-tags li'
+        _tagListItems = self.grid.find 'ul.caption-tags li'

-        $.each tagListItems, (key, value) ->
-            tag = $(value).text()
-            tags.push self.capitalize tag
+        $.each _tagListItems, (key, value) ->
+            _tag = $(value).text()
+            tags.push _tag
             $.unique tags

+        tags
+
+    addFilterButtons: (tags) =>
+        self = @
+
+        _capitalize = (str) ->
+            str.toLowerCase().replace /^.|\s\S/g, (a) ->
+                a.toUpperCase()
+
         $.each tags, (key, value) ->
-            tagButton = $ '<button></button>',
+            _tagButton = $ '<button></button>',
                 class: 'drm-grid-filter'
-                text: value
-                'data-filter': value.toLowerCase()
-            tagButton.appendTo self.gridNav
+                text: _capitalize value
+                'data-filter': value
+            _tagButton.appendTo self.gridNav

         self.gridNav.find('.drm-grid-filter').first().addClass 'active'

     resizeCurtain: =>
-        curtain = @grid.find '.curtain'
+        _curtain = @grid.find '.curtain'

-        $.each curtain, (key, value) ->
-            that = $ value
-            holder = that.parent '.drm-grid-item'
-            imageHeight = holder.find('img').height()
+        $.each _curtain, (key, value) ->
+            _that = $ value
+            _holder = _that.parent '.drm-grid-item'
+            _imageHeight = _holder.find('img').height()

-            that.height(imageHeight).hide()
+            _that.height(_imageHeight).hide()

-    resizeGrid: (items) =>
+    addListItems: (items) =>
         self = @
-        tallestColumn = 0
-        columnHeights = []
+        @grid.empty()
+        items.appendTo(@grid).hide 0, ->
+            self.positionListItems items

-        i = 0
-        until i is self.imagesPerRow
-            columnHeights.push 0
-            i = i + 1
-
-        $.each items, (key, value) ->
-            that = $ value
-            columnNum = that.data 'column'
-            height = that.outerHeight true
+    positionListItems: (items) =>
+        self = @

-            columnHeights[columnNum] += height
+        # add height to grid holder to accomodate images
+        _resizeHolder = (items) ->
+            _tallestColumn = 0
+            _columnHeights = []

-        $.each columnHeights, (key, value) ->
-            if value > tallestColumn
-                tallestColumn = value
-                tallestColumn
+            _i = 0
+            until _i is self.imagesPerRow
+                _columnHeights.push 0
+                _i = _i + 1
+
+            $.each items, (key, value) ->
+                _that = $ value
+                _columnNum = _that.data 'column'
+                _height = _that.outerHeight true

-        self.grid.css 'height': tallestColumn + 40
+                _columnHeights[_columnNum] += _height

-    positionListItems: =>
-        self = @
-        items = self.grid.find '.drm-grid-item'
+            $.each _columnHeights, (key, value) ->
+                if value > _tallestColumn
+                    _tallestColumn = value
+                    _tallestColumn
+
+            self.grid.css 'height': _tallestColumn + 40
+
+        # need to keep track of column length so _that any one column doesn't get too long

         $.each items, (key, value) ->
-            that = $ value
-            index = key + 1
-            columnNum = if index % self.imagesPerRow is 0 then self.imagesPerRow - 1 else (index % self.imagesPerRow) - 1
-            that.attr 'data-column', columnNum
-            that.attr 'data-num', index
-            prevImage = if index > self.imagesPerRow then self.grid.find('.drm-grid-item').eq(index - (self.imagesPerRow + 1)) else null
+            _that = $ value
+            _index = key + 1
+            _columnNum = if _index % self.imagesPerRow is 0 then self.imagesPerRow - 1 else (_index % self.imagesPerRow) - 1
+            _that.attr 'data-column', _columnNum
+            _that.attr 'data-num', _index
+            _prevImage = if _index > self.imagesPerRow then self.grid.find('.drm-grid-item').eq(_index - (self.imagesPerRow + 1)) else null

-            if prevImage?
-                margin = prevImage.outerWidth(true) - prevImage.outerWidth(false)
-                top = if index < ((self.imagesPerRow * 2) + 1) then prevImage.outerHeight(false) + margin else prevImage.outerHeight(false) + margin + prevImage.position().top
-                left = (prevImage.outerWidth(false) * columnNum) + (margin * columnNum)
+            if _prevImage?
+                _margin = _prevImage.outerWidth(true) - _prevImage.outerWidth(false)
+                _top = if _index < ((self.imagesPerRow * 2) + 1) then _prevImage.outerHeight(false) + _margin else _prevImage.outerHeight(false) + _margin + _prevImage.position().top
+                _left = (_prevImage.outerWidth(false) * _columnNum) + (_margin * _columnNum)

-                that.css
-                    'top': top
-                    'left': left
+                _that.css
+                    'top': _top
+                    'left': _left
                     'position': 'absolute'
             else
-                that.css
+                _that.css
                     'top': 0
                     'left': 0
-                    'position': 'relative'
+                    'position': 'relative'

-            that.fadeIn 1000
+            _that.show()

-        self.resizeGrid items
+        _resizeHolder items

     filterListItems: (filter) =>
-        self = @
-        self.grid.empty()
+        # filter images by tag
+        filter = if window.location.hash then filter else 'all'
+        window.location.hash = filter

-        if filter is 'all'
-            $.each self.items, (key, value) ->
-                that = $ value
-                that.appendTo(self.grid).hide()
+        if filter in @tags or filter is 'all'
+            filteredItems = if filter is 'all' then @items else @items.has "ul.caption-tags li:containsNC(#{filter})"
+            @addListItems filteredItems
         else
-            $.each self.items, (key, value) ->
-                that = $ value
-                tagList = that.find 'ul.caption-tags'
-
-                hasTag = if tagList.has("li:containsNC(#{filter})").length isnt 0 then true else false
-
-                if hasTag then that.appendTo(self.grid).hide()
-
-        self.positionListItems()
+            $('

',
+                text: 'no items match').appendTo @grid
+

 new DrmFlexibleGrid()


compile litcoffee to js

compile litcoffee to js

Compile Literate CoffeeScript to JavaScript, which will also remove all
the Markdown content

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -10,7 +10,7 @@
   'CoffeeScript (Literate)':
     render: (text, cb) ->
       coffeescript = require 'coffee-script'
-      result = coffeescript.compile text
+      result = coffeescript.compile text, literate: true
       cb null, result
     lang: -> 'js'
   #'TypeScript':


change order of config options to appear

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -72,14 +72,28 @@
     description: "Automatically change mode on narrow-editor, insert-mode(=prompt), normal-mode(=item-area)"

   # Per providers settings
+  # -------------------------
+  # auto-preview
+  AtomScanAutoPreview: true
+  BookmarksAutoPreview: true
+  FoldAutoPreview: true
+  GitDiffAutoPreview: true
   LinesAutoPreview: true
+  LinterAutoPreview: true
+  SearchAutoPreview: true
+  SymbolsAutoPreview: true
+
+  # close-on-confirm
+  AtomScanCloseOnConfirm: true
+  BookmarksCloseOnConfirm: true
+  FoldCloseOnConfirm: true
+  GitDiffCloseOnConfirm: true
   LinesCloseOnConfirm: true
+  LinterCloseOnConfirm: true
+  SearchCloseOnConfirm: true
+  SymbolsCloseOnConfirm: true

-  FoldAutoPreview: true
-  FoldCloseOnConfirm: true
-
-  SearchAutoPreview: true
-  SearchCloseOnConfirm: true
+  # Other
   SearchAgCommandArgs:
     default: "--nocolor --column"
     description: """
@@ -92,18 +106,3 @@
       Smart case: `ag --nocolor --column -S PATTERN`

       Case sensitive/word only: `ag --nocolor --column -s -w PATTERN`

     """
-
-  AtomScanAutoPreview: true
-  AtomScanCloseOnConfirm: true
-
-  SymbolsAutoPreview: true
-  SymbolsCloseOnConfirm: true
-
-  GitDiffAutoPreview: true
-  GitDiffCloseOnConfirm: true
-
-  BookmarksAutoPreview: true
-  BookmarksCloseOnConfirm: true
-
-  LinterAutoPreview: true
-  LinterCloseOnConfirm: true


Rename getWordRegex to wordRegexForSnippets

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -94,7 +94,7 @@
     @bodyParser ?= require './snippet-body-parser'

   getPrefixText: (snippets, editor) ->
-    wordRegex = @getWordRegex(snippets)
+    wordRegex = @wordRegexForSnippets(snippets)
     cursor = editor.getCursor()
     prefixStart = cursor.getBeginningOfCurrentWordBufferPosition({wordRegex})
     editor.getTextInRange([prefixStart, cursor.getBufferPosition()])
@@ -116,7 +116,7 @@
         event.abortKeyBinding()

   # Get a RegExp of all the characters used in the snippet prefixes
-  getWordRegex: (snippets) ->
+  wordRegexForSnippets: (snippets) ->
     prefixes = {}
     for prefix of snippets
       prefixes[character] = true for character in prefix


Remove unused method

Remove unused method

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -52,16 +52,3 @@
     else
       @removeClass('modified') if @isModified
       @isModified = false
-
-  updateFileName: ->
-    fileNameText = @editSession.buffer.getBaseName()
-    if fileNameText?
-      duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName()
-      if duplicates.length > 1
-        directory = path.basename(path.dirname(@editSession.getPath()))
-        fileNameText = "#{fileNameText} - #{directory}" if directory
-    else
-      fileNameText = 'untitled'
-
-    @fileName.text(fileNameText)
-    @fileName.attr('title', @editSession.getPath())


Error flash message can be closable

Error flash message can be closable

--- wzk/ui/Flash.coffee
+++ wzk/ui/Flash.coffee
@@ -24,10 +24,9 @@
     @param {boolean=} closable if closable is undefined and severity is error then closable is set to false otherwise to true
     @return {Array.<wzk.ui.FlashMessage>}
   ###
-  addMessage: (text, severity = 'info', fadeOut = undefined, closable = undefined) ->
+  addMessage: (text, severity = 'info', fadeOut = undefined, closable = true) ->
     notError = severity isnt 'error'
     fadeOut = notError if fadeOut is undefined
-    closable = notError if closable is undefined

     msgs = if goog.isArray(text) then text else [text]
     flashes = []


style(search): remove whitespace from cancel button template

--- modules/directives/search/index.coffee
+++ modules/directives/search/index.coffee
@@ -10,9 +10,7 @@
   restrict: 'E'
   link: (scope, element, attrs) ->
     $cancel = $compile(
-      '<bp-button bp-tap="cancel()" bp-no-scroll>
-        Cancel
-      </bp-button>'
+      '<bp-button bp-tap="cancel()" bp-no-scroll>Cancel</bp-button>'
       ) scope
     $search = element.find 'input'
     element


Pass all options through

Pass all options through

--- src/root-view.coffee
+++ src/root-view.coffee
@@ -221,17 +221,17 @@
     pane.focus() if changeFocus
     paneItem

-  openSingletonSync: (uri, {split}={}) ->
+  openSingletonSync: (uri, {changeFocus, initialLine, split}={}) ->
     uri = project.relativize(uri)
     pane = @panes.paneForUri(uri)

     if pane
       paneItem = pane.itemForUri(uri)
       pane.showItem(paneItem)
-      pane.focus()
+      pane.focus() if changeFocus
       paneItem
     else
-      @openSync(uri, {split})
+      @openSync(uri, {changeFocus, initialLine, split})

   # Public: Updates the application's title, based on whichever file is open.
   updateTitle: ->


Don't collect results of loops

Don't collect results of loops

--- src/space-pen.coffee
+++ src/space-pen.coffee
@@ -87,6 +87,8 @@
       view[outlet] = element
       element.attr('outlet', null)

+    undefined
+
   bindEventHandlers: (view) ->
     for eventName in Events
       selector = "[#{eventName}]"
@@ -100,6 +102,8 @@
         methodName = view.attr(eventName)
         do (methodName) ->
           view.on eventName, (event) -> view[methodName](event, view)
+
+    undefined

   # `pushStack` and `end` are jQuery methods that construct new wrappers.
   # we override them here to construct plain wrappers with `jQuery` rather


When the server closes a connection, make sure the send buffer still gets flushed.

--- src/transport.coffee
+++ src/transport.coffee
@@ -83,6 +83,7 @@
             clearTimeout(@to_tref)
             @to_tref = null
         if @readyState is Transport.CLOSING
+            @flushToRecv(recv)
             recv.doSendFrame(@close_frame)
             recv.didClose()
             @to_tref = setTimeout(@timeout_cb, @disconnect_delay)
@@ -143,11 +144,15 @@
             clearTimeout(@to_tref)
         @to_tref = setTimeout(@timeout_cb, @disconnect_delay)

-    tryFlush: ->
+    flushToRecv: (recv) ->
         if @send_buffer.length > 0
             [sb, @send_buffer] = [@send_buffer, []]
-            @recv.doSendBulk(sb)
-        else
+            recv.doSendBulk(sb)
+            return true
+        return false
+
+    tryFlush: ->
+        if not @flushToRecv(@recv)
             if @to_tref
                 clearTimeout(@to_tref)
             x = =>


Break validator into smaller fns

Break validator into smaller fns

--- src/validator.coffee
+++ src/validator.coffee
@@ -5,30 +5,33 @@
 _ = require 'underscore'
 semver = require 'semver'

-versionExists = (manifest, gadgets) ->
+versionExists = (manifestInfo, gadgets) ->
   otherGadgetVersions = _.select gadgets, (gadget) ->
-    manifest.name == gadget.name
+    manifestInfo.name == gadget.name
   return _.any otherGadgetVersions, (gadget) ->
-    return semver.gte gadget.version, manifest.version
+    return semver.gte gadget.version, manifestInfo.version
+
+getAllGadgetVersions = (options, callback) ->
+  async.concat ['approved', 'sandbox'], (catalog, cb) ->
+    restapi.getGadgetCatalog catalog, options, cb
+  , callback

 # TODO function and supporting functions are a temporary measure
 # until rest-api#1693 is resolved
+assertValidVersion = (dir, options, callback) ->
+  getAllGadgetVersions options, (err, gadgets) ->
+    manifest.readManifest dir, (err, manifestInfo) ->
+      if err then return callback err
+
+      if versionExists manifestInfo, gadgets
+        manifest.lookupManifest dir, (manifestPath) ->
+          errorMessage = "Version 'v#{manifestInfo.version}' or greater already exists." +
+          "\n       Bump the version in '#{path.basename manifestPath}' before uploading."
+          return callback(new Error(errorMessage))
+
+      else
+        return callback()
+
 module.exports =
-
   checkProject: (dir, options, callback) ->
-    async.concat ['approved', 'sandbox'], (catalog, cb) ->
-      restapi.getGadgetCatalog catalog, options, cb
-    , (err, gadgets) ->
-
-      manifest.readManifest dir, (err, manifestInfo) ->
-        if err then return callback err
-
-        if versionExists manifestInfo, gadgets
-          manifest.lookupManifest dir, (manifestPath) ->
-            errorMessage = "Version 'v#{manifestInfo.version}' or greater " +
-            "already exists. Bump the version in '#{path.basename manifestPath}' " +
-            "before uploading."
-            return callback(new Error(errorMessage))
-
-        else
-          return callback()
+    assertValidVersion dir, options, callback


jira-issues.coffee: fix typo in comments referring to HUBOT_JIRA_ISSUES_IGNORE_USERS

--- src/scripts/jira-issues.coffee
+++ src/scripts/jira-issues.coffee
@@ -1,7 +1,7 @@
 # Description:
 #   Looks up jira issues when they're mentioned in chat
 #
-#   Will ignore users set in HUBOT_JIRA_IGNORE_USERS (by default, JIRA and GitHub).
+#   Will ignore users set in HUBOT_JIRA_ISSUES_IGNORE_USERS (by default, JIRA and GitHub).
 #
 # Dependencies:
 #   None
@@ -11,7 +11,7 @@
 #   HUBOT_JIRA_IGNORECASE (optional; default is "true")
 #   HUBOT_JIRA_USERNAME (optional)
 #   HUBOT_JIRA_PASSWORD (optional)
-#   HUBOT_JIRA_IGNORE_USERS (optional, format: "user1|user2", default is "jira|github")
+#   HUBOT_JIRA_ISSUES_IGNORE_USERS (optional, format: "user1|user2", default is "jira|github")
 #
 # Commands:
 #


changed builds condition to check length

--- models/repository.coffee
+++ models/repository.coffee
@@ -25,6 +25,6 @@

 exports.Repository.prototype.toJSON = ->
   obj = this.toObject
-  if obj.builds
+  if obj.builds && obj.builds.length
     obj.builds = obj.builds.reverse
   obj


Change menu command labels

Change menu command labels

--- menus/css-comb.cson
+++ menus/css-comb.cson
@@ -2,7 +2,7 @@
 'context-menu':
   'atom-text-editor': [
     {
-      'label': 'Run csscomb'
+      'label': 'Run CSSComb'
       'command': 'css-comb:run'
     }
   ]
@@ -10,7 +10,7 @@
   {
     'label': 'Packages'
     'submenu': [
-      'label': 'css-comb'
+      'label': 'CSSComb'
       'submenu': [
         {
           'label': 'Run'


Fixing capture of stdout

Fixing capture of stdout

--- src/task/dist/npm/index.coffee
+++ src/task/dist/npm/index.coffee
@@ -16,7 +16,7 @@
     options.output = util.mergeOptions(config.output, options.output)

     exec = (cmd, args, options, cbDone, cbError) ->
-      if typeof options != object
+      if typeof options != 'object'
         cbError = cbDone
         cbDone = options
         options = {}
@@ -76,7 +76,7 @@
         (done) ->
           # Ensure no changes
           abort = false
-          exec('git', ['status', '--porcelain'], { stdio: [process.stdin, 'pipe', process.stderr] }, (err) ->
+          child = exec('git', ['status', '--porcelain'], { stdio: [process.stdin, 'pipe', process.stderr] }, (err) ->
             if not err? and abort
               err = new Error('Changes detected. Please ensure the staging area is clean before running')
             if err?
@@ -84,7 +84,7 @@
             done(err)
             return
           )
-          .on('data', (data) ->
+          child.stdout.on('data', (data) ->
             abort = true
             process.stdout.write(data)
             return
@@ -95,7 +95,7 @@
         (done) ->
           # Ensure we are committing the master
           name = ''
-          exec('git', ['status', '--porcelain'], { stdio: [process.stdin, 'pipe', process.stderr] }, (err) ->
+          child = exec('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { stdio: [process.stdin, 'pipe', process.stderr] }, (err) ->
             if not err? and name != 'master'
               err = new Error('Current branch is not master. Please only distribute from master.')
             if err?
@@ -103,7 +103,8 @@
             done(err)
             return
           )
-          .on('data', (data) ->
+
+          child.stdout.on('data', (data) ->
             name += data.toString()
             process.stdout.write(data)
             return


removing Trailer things, as they do not work

--- code/serv.coffee
+++ code/serv.coffee
@@ -129,7 +129,6 @@
 app.post "/:org/:project/exec/?", (req, res) ->
   timelog "got POST exec #{req.params.org}/#{req.param.project} #{req.body.cmd}"
   res.removeHeader 'Content-Type'
-  res.setHeader 'Trailer': 'X-Exit-Status'
   user_name = req.params.org + '.' + req.params.project
   cmd = req.body.cmd
   su = child_process.spawn "su", ["-c", "#{cmd}", "#{user_name}"]
@@ -138,7 +137,6 @@
   su.stderr.on 'data', (data) ->
     res.write data
   su.on 'exit', (code) ->
-    res.addTrailer 'X-Exit-Status', "#{code}"
     res.end()

   req.on 'end', -> su.kill()


fixed user tracking

fixed user tracking

--- coffeeApp.coffee
+++ coffeeApp.coffee
@@ -64,6 +64,8 @@
 # Temporary storage of tweets
 tweets = []
 retweets = []
+# Array of re-tweeted screen_names to avoid spam
+retweetedUsers= []

 # Clears cache of tweets every 5 seconds
 eraseTweets = -> tweets = []
@@ -120,11 +122,6 @@
     centerPointY += coord[1]
   callback [centerPointX / coords.length, centerPointY / coords.length]

-
-
-# Array of re-tweeted screen_names to avoid spam
-twitterUsernameArray = []
-
 limit = 1

 # Reset the limit of retweets every 5 minutes
@@ -135,10 +132,7 @@
 # Retweet logic
 retweet = (screen_name, tweetID, followers) ->
   if limit isnt 0 && retweets.length > 0
-    limit--
-    if twitterUsernameArray[screen_name]
-      console.log screen_name + " mgingras: Already Retweeted!"
-    else
+      limit--
       mostPopular = 0
       index = 0
       for tweet in retweets
@@ -150,10 +144,11 @@
           console.log "mgingras (Retweet Error): "
           console.log err
         else
-          twitterUsernameArray[screen_name] = retweets[index].screen_name
+          retweetedUsers.push(screen_name)
           retweets = []
   else
-    retweets.push {screen_name: screen_name, tweetID: tweetID, followers: followers}
+    if retweetedUsers.indexOf screen_name < 0
+      retweets.push {screen_name: screen_name, tweetID: tweetID, followers: followers}

 # Routes


Fix checkout-head-revision command

Fix checkout-head-revision command

--- src/text-editor-element.coffee
+++ src/text-editor-element.coffee
@@ -190,7 +190,7 @@
   'editor:fold-at-indent-level-9': -> @getModel().foldAllAtIndentLevel(8)
   'editor:toggle-line-comments': -> @getModel().toggleLineCommentsInSelection()
   'editor:log-cursor-scope': -> @getModel().logCursorScope()
-  'editor:checkout-head-revision': -> atom.project.getRepositories()[0]?.checkoutHeadForEditor(editor)
+  'editor:checkout-head-revision': -> atom.project.getRepositories()[0]?.checkoutHeadForEditor(@getModel())
   'editor:copy-path': -> @getModel().copyPathToClipboard()
   'editor:move-line-up': -> @getModel().moveLineUp()
   'editor:move-line-down': -> @getModel().moveLineDown()


Inspector: Remember open panels

Inspector: Remember open panels

--- src/trix/inspector/view.coffee
+++ src/trix/inspector/view.coffee
@@ -6,6 +6,7 @@
     {@compositionController, @composition} = @editorController

     @element = document.createElement("details")
+    @element.open = true if @getSetting("open") is "true"
     @element.classList.add(@template)

     @titleElement = document.createElement("summary")
@@ -28,6 +29,7 @@
           handler.call(this, event)

   didToggle: (event) ->
+    @saveSetting("open", @isOpen())
     @render()

   isOpen: ->
@@ -43,3 +45,14 @@

   renderTitle: ->
     @titleElement.innerHTML = @getTitle()
+
+  getSetting: (key) ->
+    key = @getSettingsKey(key)
+    window.sessionStorage?[key]
+
+  saveSetting: (key, value) ->
+    key = @getSettingsKey(key)
+    window.sessionStorage?[key] = value
+
+  getSettingsKey: (key) ->
+    "trix/inspector/#{@template}/#{key}"


Added lumberjack snippet to define cms tab title

--- completions.cson
+++ completions.cson
@@ -2558,3 +2558,19 @@
    */
   private static $show_in_sitetree = ${1:false};${0}
   """
+
+'getLumberjackTitle':
+  'prefix': 'getLumberjackTitle'
+  'module': 'silverstripe/lumberjack'
+  'scope': '.text.html.php'
+  'body': """
+  /**
+   * Define the title for the cms lumberjack gridfield.
+   *
+   * @return string
+   */
+  public function getLumberjackTitle()
+  {
+  \treturn \'${1}\';
+  }${0}
+  """


script simplification to use registered users

--- src/scripts/whos-turn.coffee
+++ src/scripts/whos-turn.coffee
@@ -1,10 +1,10 @@
 # Who's turn to do something ?
 #
-# who <does something> : <someone>, <someone>, <someone> ? - Returns who does !
+# who <does something> ? - Returns who does !
 #
 module.exports = (robot) ->
-  robot.respond /(who|qui) (.+) : (.+) \?/i, (msg) ->
-    action = msg.match[2]
-    member = msg.random msg.match[3].split /[\s]*,[\s]*/
-    msg.send member + " " + action + " !"
-
+  robot.respond /(who|qui) (.+)\?/i, (msg) ->
+    users = []
+    for own key, user of robot.brain.data.users
+      users.push "#{user.name}" if "#{user.name}" != robot.name
+    msg.send (msg.random users).split(" ")[0] + " " + msg.match[2] + "!"


Fix typo

Fix typo

--- src/contexts/init.coffee
+++ src/contexts/init.coffee
@@ -28,7 +28,7 @@
 InitComponent = React.createClass
   mixins: [Arda.mixin, React.addons.LinkedStateMixin, InitController],
   render: ->
-    @BootstrapFooter = require('../components/common').BoostrapFooter
+    @BootstrapFooter = require('../components/common').BootstrapFooter
     require("jade-react!../components/InitComponent.jade") @


uncomment sourcemaps, they hsould work now

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -94,9 +94,9 @@
         .pipe(mold.transformSourcesRelativeTo('./src'))
         .pipe(source('index.js'))
         .pipe(buffer())
-        #.pipe(sourcemaps.init(loadMaps: true))
+        .pipe(sourcemaps.init(loadMaps: true))
         .pipe(if isDeploy(nodeEnv) then require('gulp-uglify')() else util.noop())
-        #.pipe(sourcemaps.write('../maps'))
+        .pipe(sourcemaps.write('../maps'))
         .pipe(gulp.dest('build/scripts'))
         .pipe(if lr then require('gulp-livereload')(lr) else util.noop())


auto browser tests in good shape

auto browser tests in good shape

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -104,7 +104,7 @@
         cb()
   null

-gulp.task 'travis', [ 'test', 'coveralls', 'browsers' ], ->
+gulp.task 'travis', [ 'test', 'coveralls' ], ->

 gulp.task 'testwatch', ['test' ], ->
   gulp.watch ['./src/*', './test/*'], ['test', 'default']


fix for librarians

fix for librarians

Former-commit-id: 423880a98ffcbc8f14e10a0cee6178bb0023b764 [formerly 2d781ca956b9cfa44af65bee4e04b1be13d6a711] [formerly 2b4baaf00f97b60cdb632124545bb20ed4e5464e [formerly 8cb7934742ec41cc9904b4d9d0cd7b570ca62e9f]] [formerly 77e838a5268751766b9a1d274be1278777e7ea04 [formerly 052cb94201f9f279b8c31e84810ec7943e3d6dcf] [formerly 5429679b81f91e172cf46bbd129e7e1b0fdecef0 [formerly 5429679b81f91e172cf46bbd129e7e1b0fdecef0 [formerly c04872eb132f17717f6b563d6618e9c29dbb4aaf]]]]
Former-commit-id: 6e048c0f91d82bb41a661e9bc86dd9f90976199b [formerly 2b6a384fa905deb5618f7f22bcd20f0f8587898c] [formerly 4c405b3bd89e46920c66230cc95e592f44ec9413 [formerly 0160dd73ab3dfa020e69788ac748b25c86eb03de]]
Former-commit-id: 7dec485d54ac19f738fbf781b67a00b32ad483b8 [formerly f9b45d303056acc9bd47de203b8e00d5c6a3e6f5]
Former-commit-id: 971cd44d22b6799ccef8664cb6f85ca354b2a480
Former-commit-id: 91b48d9853078acb35f085b6dbe136d5932e0b8a

--- @client/admin.coffee
+++ @client/admin.coffee
@@ -91,7 +91,7 @@
     section_style = {margin: '10px 0px 20px 0px', position: 'relative'}

     DIV style: {cursor: 'auto', width: 3 * CONTENT_WIDTH / 4, backgroundColor: '#F4F0E9', position: 'absolute', left: CONTENT_WIDTH/4, top: -35, borderRadius: 8},
-      STYLE null, '.claim_result a{font-decoration: underline;}'
+      STYLE null, '.claim_result a{text-decoration: underline;}'

       # status area
       DIV style: {padding: '4px 30px', fontSize: 24, borderRadius: '8px 8px 0 0', height: 35, backgroundColor: 'rgba(0,0,55,.1)'},


remove extra whitespace

remove extra whitespace

--- main.coffee
+++ main.coffee
@@ -13,8 +13,8 @@
 levelColors =
     error: colors.red
     debug: colors.green
-    'warn ': colors.yellow
-    'info ': colors.blue
+    'warn': colors.yellow
+    'info': colors.blue

 class Logger

@@ -38,10 +38,10 @@
         text

     info: (text) ->
-        console.info @format 'info ', text if process.env.NODE_ENV isnt 'test'
+        console.info @format 'info', text if process.env.NODE_ENV isnt 'test'

     warn: (text) ->
-        console.warn @format 'warn ', text if process.env.NODE_ENV isnt 'test'
+        console.warn @format 'warn', text if process.env.NODE_ENV isnt 'test'

     error: (text) ->
         console.error @format 'error', text if process.env.NODE_ENV isnt 'test'


Spacing.

Spacing.

--- src/finitio/type/ad_type.coffee
+++ src/finitio/type/ad_type.coffee
@@ -23,7 +23,6 @@
       $u.argumentError("Invalid contracts:", invalid)

     super(@name)
-

   contractNames: ->
     $u.keys(@contracts)


Default string options on shipping calculator

--- src/coffee/portal-shipping-calculator.coffee
+++ src/coffee/portal-shipping-calculator.coffee
@@ -80,10 +80,10 @@
 $.fn.shippingCalculator.defaults =
 	showCorreiosSearch: true
 	strings:
-		calculateShipping: 'produtoCalculoFrete'
-		enterPostalCode: 'DigiteCep'
-		requiredPostalCode: 'CEPObrigatorio'
-		invalidPostalCode: 'CEPInvalido'
-		requiredQuantity: 'ProdutoQuantidadeObrigatorio'
+		calculateShipping: 'Calcule o valor do frete e prazo de entrega para a sua região:'
+		enterPostalCode: 'Calcular o valor do frete e verificar disponibilidade:'
+		requiredPostalCode: 'O CEP deve ser informado.'
+		invalidPostalCode: 'CEP inválido.'
+		requiredQuantity: 'É necessário informar a quantidade do mesmo Produto.'
 		siteName: 'Vtex.Commerce.Web.CommerceContext.Current.WebSite.Name'
 		close: 'Fechar'


feat: Report OS type and version in dredd --version

Addressing the simplest item from https://github.com/apiaryio/dredd/issues/625.

--- src/dredd-command.coffee
+++ src/dredd-command.coffee
@@ -2,6 +2,7 @@
 optimist = require 'optimist'
 console = require 'console'
 fs = require 'fs'
+os = require 'os'
 spawnArgs = require 'spawn-args'
 {spawn} = require('child_process')

@@ -177,7 +178,10 @@

     # show version
     else if @argv.version is true
-      console.log("#{packageData.name} v#{packageData.version}")
+      console.log("""\
+        #{packageData.name} v#{packageData.version} \
+        (#{os.type()} #{os.release()}; #{os.arch()})
+      """)
       return @_processExit(0)

   loadDreddFile: ->


revert getClasses change for MemberExpression

--- src/languages/javascript.coffee
+++ src/languages/javascript.coffee
@@ -203,7 +203,7 @@
     if node.type of CLASS_EXCEPTIONS
       return CLASS_EXCEPTIONS[node.type].concat([node.type])
     else
-      if node.type is 'CallExpression' or node.type is 'NewExpression' or node.type is 'Identifier' or node.type is 'MemberExpression'
+      if node.type is 'CallExpression' or node.type is 'NewExpression' or node.type is 'Identifier'
         known = @lookupKnownName node
         if not known or (known.fn.value and known.fn.command)
           return [node.type, 'any-drop']


Same thing here, WirePattern doesn't see legacy disconnect events

--- spec/Helpers.coffee
+++ spec/Helpers.coffee
@@ -1841,8 +1841,6 @@
         saved.once 'data', (data) ->
           chai.expect(data).to.be.true
           hadData = true
-        saved.once 'disconnect', ->
-          chai.expect(hadData).to.be.true
           done()

         err.removeAllListeners()


Test for an icon

Test for an icon

--- spec/network.coffee
+++ spec/network.coffee
@@ -188,6 +188,7 @@
           chai.expect(message.data.protocol).to.equal 'component'
           chai.expect(message.data.payload).to.be.an 'object'
           if message.data.payload.name is 'core/Output'
+            chai.expect(message.data.payload.icon).to.equal 'bug'
             chai.expect(message.data.payload.inPorts).to.eql [
               id: 'in'
               type: 'all'


Smarter value rendering stops 0 from becoming ?

--- src/javascript/inspector/inspector_ui.coffee
+++ src/javascript/inspector/inspector_ui.coffee
@@ -108,7 +108,7 @@
 PropValueCell = React.createClass
   displayName: 'PropValueCell'
   render: ->
-    val = if @props.value then @props.value.toString() else "?"
+    val = if @props.value? then @props.value.toString() else "?"
     React.createElement 'td', {className:'prop-value'}, val

 module.exports = InspectorUI


Fixes #173. Remove @ prefix from showError call

--- lib/beautify.coffee
+++ lib/beautify.coffee
@@ -106,7 +106,7 @@
           return
         ), 0
     else
-      @showError(new Error("Unsupported beautification result '#{text}'."))
+      showError(new Error("Unsupported beautification result '#{text}'."))
     # else
       # console.log "Already Beautiful!"
     @loadingView.hide()
@@ -117,7 +117,7 @@
   editor = atom.workspace.getActiveEditor()
   # Check if there is an active editor
   if not editor?
-    return @showError(new Error("Active Editor not found. "
+    return showError(new Error("Active Editor not found. "
                 "Please select a Text Editor first to beautify."))

   isSelection = !!editor.getSelectedText()


Fix _showNotification doesn't exists error

--- lib/css-comb.coffee
+++ lib/css-comb.coffee
@@ -75,7 +75,7 @@
     comb = new CSScomb(config)
     comb.processFile(filePath)

-    @_showNotifications('File processed by csscomb')
+    @_showInfoNotification('File processed by csscomb')

   ###*
   # Process only selection by csscomb


generate: Update to .ino extension

generate: Update to .ino extension

--- lib/generate.coffee
+++ lib/generate.coffee
@@ -366,7 +366,7 @@
   outputBase = undefined
   outputDir = undefined
   outputBase = outputFile.replace(path.extname(outputFile), "")
-  outputFile = outputFile + ".pde"  unless path.extname(outputFile)
+  outputFile = outputFile + ".ino"  unless path.extname(outputFile)
   outputDir = path.dirname(outputBase)
   fs.mkdirSync outputDir  unless fs.existsSync(outputDir)
   definition.loadFile inputFile, (err, def) ->


fix url default

fix url default

--- src/BuscaCep.coffee
+++ src/BuscaCep.coffee
@@ -50,7 +50,7 @@
     base.init()

   $.buscaCep.defaultOptions =
-    url: '/api/address/cep/:cep.json'
+    url: '/api/addresses/cep/:cep.json'
     returnConverter: (data)->
       data


The constructor now cleans up the generated digits (so 0 will have none).

--- lib/long_int.coffee
+++ lib/long_int.coffee
@@ -156,7 +156,7 @@
       if m then Sequence.conj(m % BASE, -> make_digits(Math.floor m / BASE))

     [m, @sign__] = if n < 0 then [-n, -1] else [n, 1]
-    @digits__ = new Sequence make_digits m
+    @digits__ = cleanup new Sequence make_digits m

   create = (digits, sign) ->
     n = new LongInt()


Update handling of code blocks

Update handling of code blocks

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -1,5 +1,4 @@
 path = require 'path'
-_ = require 'underscore-plus'
 cheerio = require 'cheerio'
 createDOMPurify = require 'dompurify'
 fs = require 'fs-plus'
@@ -10,6 +9,8 @@
 highlighter = null
 {resourcePath} = atom.getLoadSettings()
 packagePath = path.dirname(__dirname)
+codeBlocks = new Map()
+grammarSubscription = null

 exports.toDOMFragment = (text='', filePath, grammar, callback) ->
   render text, filePath, (error, html) ->
@@ -72,8 +73,14 @@
   o.innerHTML

 convertCodeBlocksToAtomEditors = (domFragment, defaultLanguage='text') ->
+  codeBlocks.clear()
+  grammarSubscription?.dispose()
+  grammarSubscription = atom.grammars.onDidAddGrammar ->
+    codeBlocks.forEach (fenceName, editor) ->
+      if grammar = atom.grammars.grammarForScopeName(scopeForFenceName(fenceName))
+        editor.setGrammar(grammar)
+
   if fontFamily = atom.config.get('editor.fontFamily')
-
     for codeElement in domFragment.querySelectorAll('code')
       codeElement.style.fontFamily = fontFamily

@@ -82,23 +89,24 @@
     fenceName = codeBlock.getAttribute('class')?.replace(/^lang-/, '') ? defaultLanguage

     editorElement = document.createElement('atom-text-editor')
-    editorElement.setAttributeNode(document.createAttribute('gutter-hidden'))
-    editorElement.removeAttribute('tabindex') # make read-only

     preElement.parentNode.insertBefore(editorElement, preElement)
     preElement.remove()

     editor = editorElement.getModel()
-    editor.setText(codeBlock.textContent)
+    lastNewlineIndex = codeBlock.textContent.search(/\r?\n$/)
+    editor.setText(codeBlock.textContent.substring(0, lastNewlineIndex)) # Do not include a trailing newline
+    editorElement.setAttributeNode(document.createAttribute('gutter-hidden')) # Hide gutter
+    editorElement.removeAttribute('tabindex') # Make read-only
+
     if grammar = atom.grammars.grammarForScopeName(scopeForFenceName(fenceName))
       editor.setGrammar(grammar)

     # Remove line decorations from code blocks.
-    if editor.cursorLineDecorations?
-      for cursorLineDecoration in editor.cursorLineDecorations
-        cursorLineDecoration.destroy()
-    else
-      editor.getDecorations(class: 'cursor-line', type: 'line')[0].destroy()
+    for cursorLineDecoration in editor.cursorLineDecorations
+      cursorLineDecoration.destroy()
+
+    codeBlocks.set(editor, fenceName)

   domFragment


added the user config directory

added the user config directory

--- lib/skeldown.coffee
+++ lib/skeldown.coffee
@@ -48,6 +48,25 @@
 document:

     Word count: 1042
+
+## configuration file
+
+skeldown will check for a configuration file in `~/.skeldown/config.json` that
+updates the command line configurations. so if, for instance, you'd like all of
+your `skeldown` files to have a particular style, you can put the following in
+`~/.skeldown/config.json`:
+
+    {
+      "extracss": "style.css"
+    }
+
+which is equivalent to calling:
+
+    $ skeldown --extracss ~/.skeldown/style.css
+
+all paths in `~/.skeldown/config.json` are evaluated relative to the
+`~/.skeldown` directory.
+
 """

 links = """
@@ -59,6 +78,7 @@

 fs = require "fs"
 {join, basename, resolve, normalize, dirname} = require "path"
+exists = fs.existsSync or require("path").existsSync
 marked = require "marked"
 optimist = require "optimist"
 _ = require "underscore"
@@ -66,6 +86,7 @@
 highlight = require("highlight").Highlight
 read = (filename) -> fs.readFileSync filename, "utf8"
 thisDir = dirname module.filename
+configDir = join process.env.HOME, '.skeldown'
 argv = null

 # like jQuery.fn.html except it includes the outer tags (and outer tag attrs)
@@ -151,9 +172,20 @@

   argv.extracss = argv.extracss?.split(",") or []

+  if exists join(configDir, 'config.json')
+    for key, value of JSON.parse(read(join(configDir, 'config.json')))
+      if key == 'extracss'
+        for file in value.split ','
+          (argv.extracss ||= []).push(join(configDir, file))
+      else if key == 'jspipeline'
+        for file in value.split ','
+          pipeline.push(join(configDir, file))
+      else if not argv[key]?
+        argv[key] = value
+
+
   for script in argv.jspipeline?.split(",") or []
     pipeline.push(require(resolve(script)).pipeline)
-    # pipeline.push(require('/Users/astacy/code/skeldown/etc/skeldown/pipeline.js').pipeline)

   pipeline.unshift prettify if not argv.noprettify


Return a pane item from the snippet opener

No longer use workspace.open in the opener!

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -17,7 +17,7 @@

     @subscriptions.add atom.workspace.addOpener (uri) =>
       if uri is 'atom://.atom/snippets'
-        atom.workspace.open(@getUserSnippetsPath())
+        atom.project.open(@getUserSnippetsPath())

     @loadAll()
     @watchUserSnippets (watchDisposable) =>


Fix #392: Get vim instance properly onlocationchange

--- extension/packages/utils.coffee
+++ extension/packages/utils.coffee
@@ -27,7 +27,9 @@
     if @bucket.has(obj)
       return @bucket.get(obj)
     else
-      return @bucket.set(obj, @newFunc(obj))
+      value = @newFunc(obj)
+      @bucket.set(obj, value)
+      return value

   forget: (obj) ->
     @bucket.delete(obj)


Switching insertBefore to insertAfter, so existing UTM fields in the forms don't mess up with the utm_form added fields

--- lib/utm_form.coffee
+++ lib/utm_form.coffee
@@ -54,10 +54,10 @@
       if allForms.length > 0
         if @_addToForm == 'first'
           firstForm = allForms[0]
-          firstForm.insertBefore(@getFieldEl(fieldName, fieldValue), firstForm.firstChild)
+          @insertAfter(@getFieldEl(fieldName, fieldValue), firstForm.lastChild)
         else
           for form in allForms
-            form.insertBefore(@getFieldEl(fieldName, fieldValue), form.firstChild)
+            @insertAfter(@getFieldEl(fieldName, fieldValue), form.lastChild)
     return

   # NOTE: This should be called for each form element or since it
@@ -69,5 +69,8 @@
     fieldEl.value = fieldValue
     fieldEl

+  insertAfter: (newNode, referenceNode) ->
+    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)
+
 _uf = window._uf || {}
 window.UtmForm = new UtmForm _uf


.

sloppy…

--- @client/banner.coffee
+++ @client/banner.coffee
@@ -1018,7 +1018,6 @@
             DIV
               style:
                 marginBottom: 16
-                marginTop:
                 textAlign: 'center'
                 color: 'black'
               trns.callout


simplify

simplify

Former-commit-id: 0d579f9af7e290452f389bb01704d288e2eb0667 [formerly f00964b06ba47ffadad1997439d21a3c912f1f3d] [formerly d4d561720d4cb6cd0aec0982274ecfbfde08993b [formerly ef212260302454de3808c6c165ac8ff2d719f862]] [formerly 7aa8de62ebc96c804f51ba374360b70453f5810d [formerly e49b2ea1e45534c600d03f866d932d1c4556288b] [formerly b9b55d44b441c04fc174cac67f41f16c7336b284 [formerly b9b55d44b441c04fc174cac67f41f16c7336b284 [formerly 5ff8ebd389b9330a0995d747804d3ae9276c4bc2]]]]
Former-commit-id: 6bff631a8684afa3f562ceea16ffa7b7778f43a8 [formerly 089b07a89e571fe49d86b50ad9e6f789ad52daa1] [formerly f601bf60bccf49ee72460fa8ff93f059eec728d6 [formerly 8d408c2017639aa728362c6692fa39a0f131110d]]
Former-commit-id: f410b54e1d2b74efdc30edb1a8f1feb4f4169109 [formerly adfed0b02ecd743c8114f293a20e1fdb5191767b]
Former-commit-id: 3f9d31ada3d561128f6313749d6e8a0c7b3bc453
Former-commit-id: 86a2b4cbdf42d18752cf79d289482f6c572ed65e

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -144,18 +144,7 @@
       a.href = url || el.src
       url = a.pathname

-      id = "temp-img#{md5(url)}"
-
-      $('body').append """
-        <IMG
-          width=500
-          height=500
-          id='#{id}'
-          src='#{url}'
-          style='position:absolute; left: 0px' />"""
-
-      img = $('body').find("##{id}")
-
+      img =$("<IMG src='#{url}' />")

       imagePoll = ->
         if img[0].complete
@@ -167,8 +156,8 @@
             b: rgb[2]
           hsl = rgb_to_hsl rgb
           color = {rgb, hsl}
+          console.log color
           callback color if callback
-          $("##{id}").remove()
           return color
         else
           setTimeout imagePoll, 50


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animated.coffee
+++ test/animated.coffee
@@ -401,11 +401,13 @@

 module "Animation"

-test "should increment frame position", ->
-  animation = GameObject
+# overwrites window.animation before each test is run
+QUnit.testStart = ->
+  window.animation = GameObject
     data: animationData
     includedModules: ["Animated"]

+test "should increment frame position", ->
   equals animation.I.currentFrameIndex, 0, "should default to initial frame position of 0"

   animation.update()
@@ -413,20 +415,12 @@
   equals animation.I.currentFrameIndex, 1, "After an update the currentFrameIndex has advanced"

 test "should reset frame position after completing animation state", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   animation.I.activeAnimation.frames.length.times ->
     animation.update()

   equals animation.I.currentFrameIndex, 0, "Frame position should be 0 after reaching the end of an animation state"

 test "should be on correct frame after transition is called", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   # Bite cannot be interrupted. Must force transition
   animation.transition("Idle1", true)

@@ -439,10 +433,6 @@
   equals animation.I.currentFrameIndex, 0, "Should be on the first frame of Idle2"

 test "should be able to force transition to new state", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   animation.update()

   animation.transition("Idle2", true)
@@ -454,10 +444,6 @@
 test "should fire Complete event after updating past the last frame", ->
   completeFired = false

-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   animation.bind "Complete", ->
     completeFired = true

@@ -467,20 +453,12 @@
   ok completeFired, "Complete event fired"

 test "should advance to next state after last frame", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   animation.I.activeAnimation.frames.length.times ->
     animation.update()

   equals animation.I.activeAnimation.name, animation.I.activeAnimation.complete, "After the bite cycle we should end up in the next state specified by the animation"

 test "should loop on looping animation states", ->
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
   animation.transition("Idle1", true)

   30.times -> animation.update()
@@ -489,10 +467,6 @@

 test "should fire frame specific event on the proper frame", ->
   whiteParticlesFired = blueParticlesFired = greenParticlesFired = chompSoundFired = false
-
-  animation = GameObject
-    data: animationData
-    includedModules: ["Animated"]

   animation.bind "whiteParticles", ->
     whiteParticlesFired = true
@@ -518,7 +492,6 @@
   animation.update()
   animation.update()

-
   equal animation.I.currentFrameIndex, 4 + 1
   ok blueParticlesFired, "Blue particle effect fired"
   ok greenParticlesFired, "Green particle effect fired"
@@ -528,16 +501,11 @@
   equal animation.I.currentFrameIndex, 5 + 1
   ok chompSoundFired, "Chomp sound effect fired"

-test "should set hflip and vflip values", ->
-
-  obj = GameObject
-    data: animationData
-    includedModules: ["Animated"]
-
-  obj.update()
-
-  ok obj.I.hflip
-  ok obj.I.vflip
+test "should set hflip and vflip values", ->
+  animation.update()
+
+  ok animation.I.hflip
+  ok animation.I.vflip

 module()


Actually validate some properties of the BNK test case.

--- test/bnk_test.coffee
+++ test/bnk_test.coffee
@@ -16,3 +16,16 @@

     it 'Parses correctly', ->
         assert.notEqual(null, output)
+
+    it 'Starts with a manifest tag', ->
+        assert.equal(output.manifest.length, 1)
+
+    it 'Contains a version name attribute', ->
+        assert.equal(output.manifest[0]['@android:versionName'], '1.0')
+
+    it 'Has a package name', ->
+        assert.equal(output.manifest[0]['@package'], 'be.bnk.mobilebanking')
+
+    it 'Has an application tag', ->
+        manifest = output.manifest[0]
+        assert.equal(manifest.application.length, 1)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/distance.coffee
+++ test/distance.coffee
@@ -6,5 +6,7 @@
   player.include Distance

   ok player.distance
+
+test 'it should proxy to Point.distanc'

 module()


small change to stage.coffee

small change to stage.coffee

--- config/stage.coffee
+++ config/stage.coffee
@@ -28,7 +28,7 @@
     closureCompilerPath: "./builders/closure/compiler.jar"
     includesFile: '../CakefileIncludes.coffee'
     useStaticFileServer: no
-    staticFilesBaseUrl: 'https://api.koding.com'
+    staticFilesBaseUrl: 'https://dev-api.koding.com'
     runtimeOptions:
       version   : version
       mainUri   : 'https://dev.koding.com'


Add specs for error serializer

Add specs for error serializer

--- src/spec/helpers/extended-logger.spec.coffee
+++ src/spec/helpers/extended-logger.spec.coffee
@@ -44,6 +44,35 @@
         @log[level] 'Some message', 'Oops, something went wrong'
         expect(@log.bunyanLogger[level]).toHaveBeenCalledWith {data: 'Some message', project_key: 'foo', another_field: 'bar'}, 'Oops, something went wrong'

+      it "should log (#{level}) by serializing Error", ->
+        spyOn(@log.bunyanLogger, level)
+        @log[level] (new Error 'Oops'), 'Oops, something went wrong'
+        expect(@log.bunyanLogger[level]).toHaveBeenCalledWith
+          data:
+            message: 'Oops'
+            name: 'Error'
+            stack: jasmine.any(String)
+            code: undefined
+            signal: undefined
+          project_key: 'foo'
+          another_field: 'bar'
+        , 'Oops, something went wrong'
+
+      it "should log (#{level}) by serializing Error 2", ->
+        spyOn(@log.bunyanLogger, level)
+        @log[level] {err: (new Error 'Oops')}, 'Oops, something went wrong'
+        expect(@log.bunyanLogger[level]).toHaveBeenCalledWith
+          data:
+            err:
+              message: 'Oops'
+              name: 'Error'
+              stack: jasmine.any(String)
+              code: undefined
+              signal: undefined
+          project_key: 'foo'
+          another_field: 'bar'
+        , 'Oops, something went wrong'
+
   describe ':: withField', ->

     _.each ['trace', 'debug', 'info', 'warn', 'error', 'fatal'], (level) ->


Fix dragging attachments

Fix dragging attachments

--- src/trix/controllers/input_controller.coffee
+++ src/trix/controllers/input_controller.coffee
@@ -165,6 +165,7 @@
         @delegate?.inputControllerWillMoveText()
         @responder?.moveTextFromLocationRange(@draggedRange)
         delete @draggedRange
+        @requestRender()

       else if files = event.dataTransfer.files
         @attachFiles(event.dataTransfer.files)


"foo" isn't a good className

"foo" isn't a good className

--- tutor/src/components/icon.cjsx
+++ tutor/src/components/icon.cjsx
@@ -38,7 +38,7 @@
     icon = <button {...buttonProps} className={classNames} />
     tooltip =
       <BS.Tooltip id={@state.uniqueId}
-        className={classnames('foo', {'on-navbar': @props.onNavbar})}
+        className={classnames('icon-tt', {'on-navbar': @props.onNavbar})}
       >{@props.tooltip}</BS.Tooltip>

     <BS.OverlayTrigger {...@props.tooltipProps} overlay={tooltip}>{icon}</BS.OverlayTrigger>


added format

added format

--- tools/strings.coffee
+++ tools/strings.coffee
@@ -5,56 +5,85 @@

 ##
 ##
-module.exports =
+module.exports = strings =

     ##
     sprintf: sprintf.sprintf
-
-
+
+
     ##
     vsprintf: sprintf.vsprintf
-
+
+    ##
+    format: (format, parts...)->
+        if typeof format is 'object'
+            format = floyd.tools.objects.serialize format
+
+        if parts.length == 1 && floyd.tools.objects.isArray parts[0]
+            parts = parts[0]
+
+        if parts.length
+            for i in [0..parts.length-1]
+                if typeof parts[i] is 'object'
+                    parts[i] = floyd.tools.objects.serialize parts[i]
+
+            if format.match
+                match = format.match /%[^%\s]/g
+            else
+                format = format.toString()
+            size = if match then match.length else 0
+            length = parts.length - size
+
+            if length
+                for i in [0..length-1]
+                    format += ' %s'
+
+        parts.unshift format
+
+        strings.sprintf.apply null, parts
+
+    ##
     part: (str, split, idx)->
         list = str.split(split)
-
+
         if idx < 0
             idx = list.length + idx
-
+
         list[idx]
-
+
     ##
     tail: (str, num=1)->
         return if !str
-
+
         if (size = str.length) > num
             return str.substr size - num
         else
             return str
-
+
     ##
     substr: (str, from, to)->
         to ?= str.length - 1
-
+
         if to < 0
             to = (str.length - 1) + to
-
+
         str.substr from, to
-
-
+
+
     ##
     capitalize: (str)->
-
+
         str.charAt(0).toUpperCase() + str.substr 1
-
+
     ##
     shorten: (str, len, append='...')->
         if str && str.length > len
             str = str.substr(0, len) + append
-        return str
-
-
-    ##
+        return str
+
+
+    ##
     ## simple string hashing function
     ##
     ## nice algorithm designed to implement Java's String.hashCode() method
@@ -63,127 +92,126 @@
     hash: (str)->
         if typeof str isnt 'string'
             str = str.toString()
-
+
         hash = i = 0
         len = str.length # cache for efficiency
         while i < len
             hash = ((hash << 5) - hash) + str.charCodeAt(i++)
             hash = hash & hash
-
+
         return hash
-
-
+
+
     ##
     ##
     ##
     isEmail: (str)->
-
+
         !!str.match /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
-
-
+
+
     ##
     ##
     ##
     sanitize: (str)->
         require('sanitizer').sanitize str
-
+

     ###
     ## UUID generator
-    ##
+    ##
     ## nice hack from here
     ## http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript#answer-2117523
-    ##
-
+    ##
+
       i=0; start = +new Date()
-
+
       while (+new Date() - start) < 1000 && ++i
          floyd.tools.strings.uuid_old()
-
+
       console.log i, 'UUIDs per second'
-
-    ##
-    ##  my firebug(acebug) console says:
+
+    ##
+    ##  my firebug(acebug) console says:
     ##  23368 UUIDs per second
     ##  23486 UUIDs per second
     ##  23502 UUIDs per second
     ##  23338 UUIDs per second
     ###
     uuid_old: ()->
-
+
         'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c)->
             r = Math.random()*16|0
             (if c is 'x' then r else r&0x3|0x8).toString(16)

     ###
     ## optimized UUID generator
-    ##
+    ##
     ## improvement on the hack from here
     ## http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript#answer-2117523
-    ##
+    ##
     ## look here
     ## http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
     ##
-    ## i took Jeff Ward's e6() from here(http://jsfiddle.net/jcward/7hyaC/1/) on 24/02/2014
+    ## i took Jeff Ward's e6() from here(http://jsfiddle.net/jcward/7hyaC/1/) on 24/02/2014
     ## because it still had a slight increase on my desktop
     ##
-
+
       i=0; start = +new Date()
-
+
       while (+new Date() - start) < 1000 && ++i
          floyd.tools.strings.uuid_old()
-
+
       console.log j=i, 'UUIDs per second with uuid_old'
-
+
       i=0; start = +new Date()
-
+
       while (+new Date() - start) < 1000 && ++i
          floyd.tools.strings.uuid()
-
+
       console.log i, 'UUIDs per second with uuid'
       console.log 'the new uuid is', (i / j).toFixed(2), 'times faster'
-
-    ##
-    ##
-    ##  my firebug(acebug) console says:
-    ##
+
+    ##
+    ##
+    ##  my firebug(acebug) console says:
+    ##
     ##   26727 UUIDs per second with uuid_old
     ##   138970 UUIDs per second with uuid
     ##   the new uuid is 5.20 times faster
-    ##
+    ##
     ##   26257 UUIDs per second with uuid_old
     ##   133505 UUIDs per second with uuid
     ##   the new uuid is 5.08 times faster
-    ##
+    ##
     ##   28365 UUIDs per second with uuid_old
     ##   135616 UUIDs per second with uuid
     ##   the new uuid is 4.78 times faster
-    ##
+    ##
     ##   28167 UUIDs per second with uuid_old
     ##   138498 UUIDs per second with uuid
     ##   the new uuid is 4.92 times faster
-    ##
+    ##
     ##   26155 UUIDs per second with uuid_old
     ##   137794 UUIDs per second with uuid
     ##   the new uuid is 5.27 times faster
     ###
     uuid: ()->
-
+
         k = ['x','x','-','x','-','4','-','y','-','x','x','x']
         u = ''; i = 0; rb = Math.random()*0xffffffff|0
         while i++ < 12
             c = k[i-1]; r = rb&0xffff
             v = if c is 'x' then r else (if c is 'y' then (r&0x3fff|0x8000) else (r&0xfff|0x4000))
-
+
             u += if c is '-' then c else uuid_LUT[v>>8]+uuid_LUT[v&0xff]
-            rb = if i&1 then rb>>16 else Math.random()*0xffffffff|0
-
+            rb = if i&1 then rb>>16 else Math.random()*0xffffffff|0
+
         return u

 ##
 ## helper table for uuid
-##
+##
 uuid_LUT = []
 for i in [0..256]
     uuid_LUT[i] = (if i<16 then '0' else '')+i.toString(16)
-


Update help

Update help

--- modules/help.coffee
+++ modules/help.coffee
@@ -29,6 +29,10 @@
     #{@prefix}seal                 - Sends seal pictures
     #{@prefix}sauce                - Sends a link to the current item's sauce
     #{@prefix}|                    - Applies filters to the current song (see #{@prefix}filters)
+    #{@prefix}img <query>          - Finds an image matching the query.
+    #{@prefix}rimg <query>         - Same as above, but finds a random image instead.
+    #{@prefix}imgn <query>         - Finds an image (with the adult filter disabled).
+    #{@prefix}rimgn <query>        - Finds a random image (with the adult filter disabled).s

     DJs Only:
     #{@prefix}volume  <vol>        - Sets volume of the bot
@@ -115,6 +119,9 @@
     For example `| time=0:15` will make the song start at 15 seconds.
     You can also specify a duration: `| time=0:15-30` will make the song start at 0:15 and last 30 seconds.

+    **| nofx**
+    This is a dummy filter that prevents making changes to the filters while the song plays
+
     **| nightcore** (Preset, same as speed=1.5)
     **| vaporwave** (Preset, same as speed=0.75)
     **| earrape** (Preset, same as volume=25)


Made getFact helper for FactRelation, that returns a Fact Model

--- core/app/backbone/models/fact_relation.coffee
+++ core/app/backbone/models/fact_relation.coffee
@@ -11,6 +11,9 @@

       type: "post"

+  getFact: ->
+    new Fact(@get('fact_base'))
+
   believe: -> @setOpinion "believes"
   disbelieve: -> @setOpinion "disbelieves"


changing project_search to use state instead of stores

--- salvus/page/project_search.cjsx
+++ salvus/page/project_search.cjsx
@@ -38,8 +38,8 @@
 ProjectSearchInput = rclass

     propTypes :
-        search_cb : rtypes.func
-        flux      : rtypes.object
+        search_cb    : rtypes.func
+        set_state_cb : rtypes.func

     getInitialState: ->
         user_input : ''
@@ -53,13 +53,14 @@
             <Icon name="times-circle" />
         </Button>

-    handle_change : (event) ->
-        @setState(user_input : event.target.value)
-
-    submit : (e) ->
-        e.preventDefault()
-        project_store.getActions(@props.project_id, flux).setTo(user_input : @state.user_input)
-        @props.search_cb(@state.user_input)
+    handle_change : ->
+        user_input = @refs.project_search_input.getValue()
+        @setState(user_input : user_input)
+        @props.set_state_cb(user_input : user_input)
+
+    submit : (event) ->
+        event.preventDefault()
+        @props.search_cb?()

     render : ->
         <form onSubmit={@submit}>
@@ -175,31 +176,55 @@
 ProjectSearchSettings = rclass

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

     handle_change : (name) ->
-        project_store.getActions(@props.project_id, flux).setTo("#{name}": @refs[name].getChecked())
-
-    input : (name, label) ->
+        @props.toggle_checkbox(name)
+        @setState("#{name}":not @state[name])
+
+    render_checkbox : (name, label) ->
         <Input
             ref      = {name}
             key      = {name}
             type     = 'checkbox'
             label    = {label}
-            checked  = {@props[name]}
+            checked  = {@state[name]}
             onChange = {=>@handle_change(name)}
             style    = {fontSize:'16px'} />

     render : ->
         <div style={fontSize:'16px'}>
-            {(@input(name, label) for name, label of @props.checkboxes)}
+            {(@render_checkbox(name, label) for name, label of @props.checkboxes)}
         </div>

 ProjectSearchDisplay = rclass

+    getInitialState : ->
+        user_input         : ''
+        search_results     : undefined
+        search_error       : undefined
+        too_many_results   : false
+        command            : undefined
+        most_recent_search : undefined
+        most_recent_path   : undefined
+
+    componentWillMount: ->
+        if not @checkbox_state?
+            @checkbox_state = {}
+
+    toggle_checkbox : (checkbox) ->
+        @checkbox_state[checkbox] = not @checkbox_state[checkbox]
+        @search()
+
     propTypes: ->
-        user_input : rtypes.string
         project_id : rtypes.string

     settings_checkboxes :
@@ -231,15 +256,22 @@
         return cmd

-    search : (query) ->
+    search : ->
+        query = @state.user_input
         if query.trim() == ''
+            @setState
+                search_results     : []
+                search_error       : undefined
+                command            : ""
+                most_recent_search : ""
+                most_recent_path   : @props.current_path.join("/")
             return

-        cmd = @generate_command(query, @props.subdirectories, not @props.case_sensitive, @props.hidden_files)
+        cmd = @generate_command(query, @checkbox_state.subdirectories, not @checkbox_state.case_sensitive, @checkbox_state.hidden_files)
         max_results = 1000
         max_output  = 110 * max_results  # just in case

-        project_store.getActions(@props.project_id, flux).setTo
+        @setState
             search_results     : undefined
             search_error       : undefined
             command            : cmd
@@ -256,13 +288,13 @@
             err_on_exit     : true
             path            : @props.current_path.join("/") # expects a string
             cb              : (err, output) =>
-                @process_results(err, output, max_results, max_output)
-
-
-    process_results : (err, output, max_results, max_output) ->
+                @process_results(err, output, max_results, max_output, cmd)
+
+
+    process_results : (err, output, max_results, max_output, cmd) ->

         if (err and not output?) or (output? and not output.stdout?)
-            project_store.getActions(@props.project_id, flux).setTo(search_error : err)
+            @setState(search_error : err)
             return

         results = output.stdout.split('\n')
@@ -302,29 +334,32 @@
             if num_results >= max_results
                 break

-        project_store.getActions(@props.project_id, flux).setTo
-            too_many_results : too_many_results
-            search_results   : search_results
-
-
+        if @state.command is cmd # only update the state if the results are from the most recent command
+            @setState
+                too_many_results : too_many_results
+                search_results   : search_results
+
+
+    set_user_input : (new_value) ->
+        @setState(user_input : new_value)

     output_heading : ->
-        if @props.most_recent_search? and @props.most_recent_path?
+        if @state.most_recent_search? and @state.most_recent_path?
             <ProjectSearchOutputHeading
-                most_recent_path   = {@props.most_recent_path}
-                command            = {@props.command}
-                most_recent_search = {@props.most_recent_search}
-                search_results     = {@props.search_results}
-                search_error       = {@props.search_error} />
+                most_recent_path   = {@state.most_recent_path}
+                command            = {@state.command}
+                most_recent_search = {@state.most_recent_search}
+                search_results     = {@state.search_results}
+                search_error       = {@state.search_error} />

     output : ->
-        if @props.search_results? or @props.search_error?
-            <ProjectSearchOutput
+        if @state.search_results? or @state.search_error?
+            return <ProjectSearchOutput
                 project_id       = {@props.project_id}
-                results          = {@props.search_results}
-                too_many_results = {@props.too_many_results}
-                search_error     = {@props.search_error} />
-        else if @props.most_recent_search?
+                results          = {@state.search_results}
+                too_many_results = {@state.too_many_results}
+                search_error     = {@state.search_error} />
+        else if @state.most_recent_search?
             # a search has been made but the search_results or search_error hasn't come in yet
             <Loading />

@@ -332,17 +367,19 @@
         <Well>
             <Row>
                 <Col sm=8>
-                    <ProjectSearchInput search_cb={@search} project_id={@props.project_id} />
+                    <ProjectSearchInput
+                        search_cb    = {@search}
+                        set_state_cb = {(new_state)=>@setState(new_state)}
+                        project_id   = {@props.project_id} />
                     {@output_heading()}
                 </Col>

                 <Col sm=4>
                     <ProjectSearchSettings
-                        project_id     = {@props.project_id}
-                        checkboxes     = {@settings_checkboxes}
-                        case_sensitive = {@props.case_sensitive}
-                        subdirectories = {@props.subdirectories}
-                        hidden_files   = {@props.hidden_files} />
+                        project_id      = {@props.project_id}
+                        checkboxes      = {@settings_checkboxes}
+                        toggle_checkbox = {@toggle_checkbox}
+                        search_cb       = {@search} />
                 </Col>
             </Row>
             <Row>
@@ -360,6 +397,7 @@

     click_filename : (e) ->
+        e.preventDefault()
         project_store.getActions(@props.project_id, flux).open_file(path:@props.filename, foreground:misc_page.open_in_foreground(e))

     render : ->


Add SFDC to list of projects

Add SFDC to list of projects

--- scripts/pivotal-listener.coffee
+++ scripts/pivotal-listener.coffee
@@ -41,7 +41,8 @@
         "SAT": "SAT-",
         "Salesforce": "SF-",
         "CCK12 Design": "CCK12D-",
-        "Data Architecture Revamp": "DAR-"
+        "Data Architecture Revamp": "DAR-",
+        "Salesforce": "SFDC-"

       project =
         projectId: reqBody["project"]["id"]


Add JAM to pivotal list

Add JAM to pivotal list

--- scripts/pivotal-listener.coffee
+++ scripts/pivotal-listener.coffee
@@ -41,7 +41,8 @@
         "CCK12 Design": "CCK12D-",
         "Data Architecture Revamp": "DAR-",
         "DAR - ENG": "DARENG-",
-        "Salesforce": "SFDC-"
+        "Salesforce": "SFDC-",
+        "JAM": "JAM-"

       project =
         projectId: reqBody["project"]["id"]


explicitly calling with a locale may cause flames

--- resources/assets/coffee/lang-js.coffee
+++ resources/assets/coffee/lang-js.coffee
@@ -18,12 +18,12 @@

 # Lang.js monkey patch
 Lang.origGet = Lang.get
-Lang.get = ->
+Lang.get = (key, replacements) ->
   try
     Lang.origGet.apply @, arguments
   catch
     Lang.setLocale fallbackLocale
-    message = Lang.origGet.apply @, arguments
+    message = Lang.origGet(key, replacements, fallbackLocale)
     Lang.setLocale currentLocale

     message


Nodejs Web Server Tests: use csrf middleware for join-team handler

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -61,7 +61,7 @@
 # temp endpoints @cihangir will reorganize these - SY
 app.post '/-/teams/validate-token'               , require './handlers/checktoken'
 app.post '/-/teams/create'                       , csrf,   require './handlers/createteam'
-app.post '/-/teams/join'                         , require './handlers/jointeam'
+app.post '/-/teams/join'                         , csrf,   require './handlers/jointeam'
 app.post '/-/teams/early-access'                 , require './handlers/earlyaccess'
 app.post '/-/teams/verify-domain'                , require './handlers/verifyslug'
 app.get  '/-/teams/check-team-invitation'        , require './handlers/teaminvitationchecker'


SocialWorker: return name document instead of name string

--- workers/social/lib/social/models/name.coffee
+++ workers/social/lib/social/models/name.coffee
@@ -166,7 +166,7 @@
       else if err
         callback err
       else
-        callback null, fullName
+        callback null, nameDoc

   @claimAll = (sources, callback = -> ) ->
     i = 0


Can now remove a specific value

Can now remove a specific value

--- source/coffee/Enumerable.coffee
+++ source/coffee/Enumerable.coffee
@@ -20,7 +20,15 @@
   get : (index) ->
     val = @values[index] if @values[index]?
     if val? then @trigger 'get', val
-
+
+  remove : (value) ->
+    index = _.indexOf @values, value
+    @trigger('remove', false) if index == -1
+    val = @values[index]
+    values = @values.slice(0, index).concat(_.rest(@values, index + 1))
+    @values = values
+    @trigger 'remove', val
+
   pop : ->
     @values.pop()
     @trigger 'pop'


spec for currency handling.

spec for currency handling.

--- spec/donations-form-spec.coffee
+++ spec/donations-form-spec.coffee
@@ -81,6 +81,11 @@

     # Note: the BBD is pegged to the USD at 0.5 BBD to 1 USD

+    it "should convert displayed amounts to normalized amounts", ->
+      formWithConversion.inputtedAmount = 10
+      formWithConversion.currency = 'USD'
+      expect(formWithConversion.normalizedAmount()).toEqual('1000')
+
     it "should convert amounts if currencyconversion=choose", ->
       formWithConversion.selectedCurrency('BBD')
       expect(formWithConversion.amounts()).toEqual([200,400,600])


:white_check_mark: for H, M, L for moveToFirstCharacterOnVerticalMotion

--- spec/motion-general-spec.coffee
+++ spec/motion-general-spec.coffee
@@ -1399,17 +1399,15 @@
   describe "moveToFirstCharacterOnVerticalMotion setting", ->
     beforeEach ->
       settings.set('moveToFirstCharacterOnVerticalMotion', false)
-
-    describe "`g g` and `G`, `N %`", ->
-      beforeEach ->
-        set
-          text: """
-            0 000000000000
-            1 111111111111
-          2 222222222222\n
-          """
-          cursor: [2, 10]
-
+      set
+        text: """
+          0 000000000000
+          1 111111111111
+        2 222222222222\n
+        """
+        cursor: [2, 10]
+
+    describe "gg, G, N%", ->
       it "go to row with keep column and respect cursor.goalColum", ->
         ensure 'g g', cursor: [0, 10]
         ensure '$', cursor: [0, 15]
@@ -1420,6 +1418,22 @@
         ensure '1 0 h', cursor: [0, 5]
         ensure '5 0 %', cursor: [1, 5]
         ensure '1 0 0 %', cursor: [2, 5]
+
+    describe "H, M, L", ->
+      beforeEach ->
+        spyOn(editorElement, 'getFirstVisibleScreenRow').andReturn(0)
+        spyOn(editor, 'getLastVisibleScreenRow').andReturn(3)
+
+      it "go to row with keep column and respect cursor.goalColum", ->
+        ensure 'H', cursor: [0, 10]
+        ensure 'M', cursor: [1, 10]
+        ensure 'L', cursor: [2, 10]
+        ensure '$', cursor: [2, 13]
+        expect(editor.getLastCursor().goalColumn).toBe(Infinity)
+        ensure 'H', cursor: [0, 15]
+        ensure 'M', cursor: [1, 15]
+        ensure 'L', cursor: [2, 13]
+        expect(editor.getLastCursor().goalColumn).toBe(Infinity)

   describe 'the mark keybindings', ->
     beforeEach ->


forgot to replace one occurrence of D.Editor

--- client/init.coffee
+++ client/init.coffee
@@ -1,4 +1,5 @@
 connect = require './connect.coffee'
+Editor = require './editor.coffee'

 D.urlParams = {}
 for kv in (location + '').replace(/^[^\?]*($|\?)/, '').split '&'
@@ -11,7 +12,7 @@
       center: onresize: -> ed?.updateSize(); return
       fxName: ''
     $('title').text wins[win].name
-    ed0 = wins[win].widget; ed = wins[win].widget = D.Editor $('.ui-layout-center'), ed0.getOpts()
+    ed0 = wins[win].widget; ed = wins[win].widget = Editor $('.ui-layout-center'), ed0.getOpts()
     ed.setValue ed0.getValue(); ed.setCursorIndex ed0.getCursorIndex(); ed.updateSize(); ed.highlight ed0.getHighlightedLine()
     ed.focus(); ed0 = null
     window.onbeforeunload = -> ed.saveAndClose(); return


code formatting

code formatting

--- coffee/game.coffee
+++ coffee/game.coffee
@@ -1,20 +1,23 @@
 # THIS SCRIPT INCLUDED WHEN game.html LOADS.

+############################################################
 # "global" configuration constants

 FRAMERATE = 1 # frames per second
 INTERVAL = 1000 / FRAMERATE

+############################################################
 # "global" game state

 canvasEdgeX = $(window).width();
 canvasEdgeY = $(window).height();
-
 gameLoopCounter = 0
 currentLevel = 0
 levelOver = false

+############################################################
 # UI elements
+
 menuCode =
 	"

Hello game, this is game.

@@ -35,7 +38,9 @@
 		$('.menuLinkOne').on 'click' , ->
 			runLevel(100)

+############################################################
 # resize #canvas to window
+
 setSizes = () ->
 	console.log("setSizes runs")
 	canvasEdgeX = $(window).width()
@@ -43,12 +48,8 @@
 	canvas.width = canvasEdgeX
 	canvas.height = canvasEdgeY

+############################################################
 # game loop control
-
-# loopId = => setInterval (
-# 	gameLoop
-# ), INTERVAL
-# Can't seem to get a handle to clearInterval with using CoffeeScript

 startLoop = () ->
 	console.log("startLoop runs")
@@ -72,7 +73,8 @@
 	startLoop() if levelOver == false #prevents duplicate loops
 	levelOver = false
 	currentLevel = levelName
-
+
+############################################################
 #game levels

 gameLoop = () ->
@@ -88,38 +90,17 @@
 		levelOver = true if gameLoopCounter >= 3
 		endGame() if levelOver == true

-# frame drawing functions
+############################################################
+# drawing functions
+
 draw = () ->
 	console.log("draw runs")

+############################################################
+# start game on jQuery document.ready

-# create menu on jQuery document ready
 jQuery ->
 	setSizes()
 	addMenus()

-
-
-
-
-
-
-
-# view menu
-
-# on menu click
-# run chapter
-# hide menus
-
-# to run chapter...
-# create canvas
-# create containers
-# create starting UI
-# run game loop
-# do things
-# end game loop
-# add menus
-
-
-