refactor to introduce a "SmartCompositeView"

--- scripts/views/workspace/sidebar/toc-branch.coffee
+++ scripts/views/workspace/sidebar/toc-branch.coffee
@@ -6,28 +6,21 @@
   'hbs!templates/workspace/sidebar/toc-branch'
 ], ($, Marionette, controller, EnableDnD, tocBranchTemplate) ->

-  return class TocBranchView extends Marionette.CompositeView
-    tagName: 'li'
-    itemViewContainer: '> ol'
+  # This class introduces a `renderModelOnly()` method that will
+  # re-render only the Model part of the CompositeView.
+  #
+  # **NOTE**: It requires that the `itemViewContainer` be a child (**not descendant**)
+  # in order to work!
+  class SmartCompositeView extends Marionette.CompositeView
+    initialize: (options) ->

-    initialize: (options) ->
-      @template = (data) =>
-        data.id = @model.id or @model.cid
-        return tocBranchTemplate(data)
-
-      @collection = @model.getChildren?()
-      # Brought in by either toc's itemViewOptions or tocBranch's itemViewOptions
-      @container = options.container
-
-      @listenTo @model, 'change', (model, collection, options) => @renderModelOnly()
+      if @model
+        @listenTo @model, 'change', (model, collection, options) => @renderModelOnly()

       if @collection
         # Figure out if the expanded state has changed (see if we need to re-render the model)
         @listenTo @collection, 'add', (model, collection, options) => @renderModelOnly() if @collection.length == 1
         @listenTo @collection, 'remove', (model, collection, options) => @renderModelOnly() if @collection.length == 0
-
-    # Pass down the Book so we can look up the overridden title
-    itemViewOptions: () -> {container: @collection}

     renderModelOnly: () ->
       # **DO NOT** just detach children. They (and descendants) will
@@ -67,29 +60,6 @@
         @$el.removeClass('editor-node-expanded')
       return result

-    onRender: () ->
-      # Add DnD options to content
-      EnableDnD.enableContentDnD(@model, @$el.find('> .editor-node-body > *[data-media-type]'))
-
-      if @model.getParent?()
-        EnableDnD.enableDropAfter(@model, @model.getParent(), @$el.find('> .editor-drop-zone-after'))
-
-    templateHelpers: () ->
-      # For a book, show the ToC unsaved/remotely-changed icons (in the navModel, instead of the OPF file)
-      model = @model.navModel or @model
-
-      return {
-        mediaType: @model.mediaType
-        hasParent: !! @model.getParent?()
-        hasChildren: !! @model.getChildren?()?.length
-        isExpanded: @expanded
-        # Look up the overridden title
-        title: @container?.getTitle?(@model) or @model.get('title')
-        # Possibly delegate to the navModel for dirty bits
-        _isDirty: model.get('_isDirty')
-        _hasRemoteChanges: model.get('_hasRemoteChanges')
-      }
-
     # Override internal Marionette method.
     # This method adds a child list item at a given index.
     appendHtml: (cv, iv, index)->
@@ -99,22 +69,6 @@
         iv.$el.insertBefore($prevChild)
       else
         $container.append(iv.el)
-
-    events:
-      # The `.editor-node-body` is needed because `li` elements render differently
-      # when there is a space between `<li>` and the first child.
-      # `.editor-node-body` ensures there is never a space.
-      'click > .editor-node-body > .editor-expand-collapse': 'toggleExpanded'
-      'click > .editor-node-body > .edit-settings': 'editSettings'
-      'click > .editor-node-body .go-edit': 'goEdit'
-
-    goEdit: () ->
-      # Edit the model in the context of this folder/book. Explicitly close
-      # the picker. This is initiated from here because at this point we're
-      # certain that the request to edit was initiated by a click in the
-      # toc/picker.
-      controller.layout.showWorkspace(false)
-      controller.goEdit(@model, @model.getRoot?())

     # Toggle expanded/collapsed in the View
     # -------
@@ -155,8 +109,72 @@
       @model.expanded = expanded
       @render()

+
+  return class TocBranchView extends SmartCompositeView
+    tagName: 'li'
+    itemViewContainer: '> ol'
+
+    initialize: (options) ->
+      @template = (data) =>
+        data.id = @model.id or @model.cid
+        return tocBranchTemplate(data)
+
+      @collection = @model.getChildren?()
+      # Brought in by either toc's itemViewOptions or tocBranch's itemViewOptions
+      @container = options.container
+
+      super(options)
+
+    # Pass down the Book so we can look up the overridden title
+    itemViewOptions: () -> {container: @collection}
+
+
+    onRender: () ->
+      # Add DnD options to content
+      EnableDnD.enableContentDnD(@model, @$el.find('> .editor-node-body > *[data-media-type]'))
+
+      if @model.getParent?()
+        EnableDnD.enableDropAfter(@model, @model.getParent(), @$el.find('> .editor-drop-zone-after'))
+
+    templateHelpers: () ->
+      # For a book, show the ToC unsaved/remotely-changed icons (in the navModel, instead of the OPF file)
+      # The cases below are:
+      #
+      # 1. TocPointerNode
+      # 2. OpfFile
+      model = @model.dereferencePointer?() or @model.navModel or @model
+
+      return {
+        mediaType: @model.mediaType
+        hasParent: !! @model.getParent?()
+        hasChildren: !! @model.getChildren?()?.length
+        isExpanded: @expanded
+        # Look up the overridden title
+        title: @container?.getTitle?(@model) or @model.get('title')
+        # Possibly delegate to the navModel for dirty bits
+        _isDirty: model.get('_isDirty')
+        _hasRemoteChanges: model.get('_hasRemoteChanges')
+      }
+
+    events:
+      # The `.editor-node-body` is needed because `li` elements render differently
+      # when there is a space between `<li>` and the first child.
+      # `.editor-node-body` ensures there is never a space.
+      'click > .editor-node-body > .editor-expand-collapse': 'toggleExpanded'
+      'click > .editor-node-body > .edit-settings': 'editSettings'
+      'click > .editor-node-body .go-edit': 'goEdit'
+
+    goEdit: () ->
+      # Edit the model in the context of this folder/book. Explicitly close
+      # the picker. This is initiated from here because at this point we're
+      # certain that the request to edit was initiated by a click in the
+      # toc/picker.
+      controller.layout.showWorkspace(false)
+      controller.goEdit(@model, @model.getRoot?())
+
+
     editSettings: ->
       title = prompt('Edit Title:', @model.getTitle?(@container) or @model.get('title'))
       if title then @model.setTitle?(@container, title) or @model.set('title', title)

-      @render()
+      @renderModelOnly()


fix crash when using fs uploader without aws creds

--- lib/aws_client.coffee
+++ lib/aws_client.coffee
@@ -1,7 +1,8 @@
 knox = require('knox')
 config = require('./config')

-module.exports = knox.createClient
-  key: config.aws.key
-  secret: config.aws.secret
-  bucket: config.aws.bucket
+if config.aws
+  module.exports = knox.createClient
+    key: config.aws.key
+    secret: config.aws.secret
+    bucket: config.aws.bucket


Fixes build task

Fixes build task

--- grunt/amd_tamer.coffee
+++ grunt/amd_tamer.coffee
@@ -9,7 +9,7 @@
       'dist/snowflake.all.js': 'src/**/*.js'
   base:
     files:
-      'dist/files/snowflake.js': ['src/**/*.js', '!src/graphics/**/*.js']
+      'dist/files/snowflake.js': ['src/**/*.js', '!src/renderer/**/*.js']
   graphics:
     files: [{
       expand: true


JavaScript closures do not work that way

--- test/model.test.coffee
+++ test/model.test.coffee
@@ -31,7 +31,7 @@
   else
     it 'should be tested with a Postgres database at ${DATABASE_URL}'

-  for storageClass in storageClasses
+  generate = (storageClass) ->
     describe "with #{storageClass.name} storage", ->
       [storage, model] = []

@@ -242,3 +242,5 @@
               expect(err).to.not.exist
               expect(results.every (r) -> r is '1 2 3 4')
               done()
+
+  generate(storageClass) for storageClass in storageClasses


substitute .dev in hrefs

substitute .dev in hrefs

--- source/javascripts/main.js.coffee
+++ source/javascripts/main.js.coffee
@@ -6,3 +6,9 @@
     header.selectTab tab if tab != ""
     ClearElection.what()
     ClearElection.technical()
+
+    # if running as clearelection.org.dev, change clearelection.org links
+    # to clearelection.org.dev
+    if window.location.hostname.match /clearelection.org.dev$/
+        $("a[href*='clearelection.org']").each ->
+            $(this).attr 'href', $(this).attr('href').replace /clearelection.org/, "clearelection.org.dev"


allow for feed to be filtered by tutorials and discussions

--- client/app/Applications/Activity.kdapplication/views/activityinnernavigation.coffee
+++ client/app/Applications/Activity.kdapplication/views/activityinnernavigation.coffee
@@ -38,8 +38,9 @@
         { title : "Everything" }
         { title : "Status Updates",   type : "CStatusActivity" }
         { title : "Code Snippets",    type : "CCodeSnipActivity" }
+        { title : "Discussions",      type : "CDiscussionActivity" }
+        { title : "Tutorials",        type : "CTutorialActivity" }
         { title : "Q&A",              type : "qa",disabledForBeta : yes }
-        { title : "Discussions",      type : "CDiscussionActivity", disabledForBeta : yes  }
         { title : "Links",            type : "CLinkActivity", disabledForBeta : yes }
         # { title : "Code Shares",      type : "codeshare", disabledForBeta : yes }
         # { title : "Commits",          type : "commit", disabledForBeta : yes }


Workspace: Fixed floating pane launch stuff.

--- client/landing/app/CommonViews/workspace/views/workspacefloatingpanelauncher.coffee
+++ client/landing/app/CommonViews/workspace/views/workspacefloatingpanelauncher.coffee
@@ -30,12 +30,11 @@

     @paneStateRef.on "value", (snapshot) =>
       state  = snapshot.val()
-      map    = @paneVisibilityState
       return unless state

       for own key, value of state
         pane = @getPaneByType key
-        if value is no then @hidePane pane, key, no else @showPane pane, key, no
+        if value is no then @hidePane pane, key else @showPane pane, key

   click: ->
     @toggleClass "active"
@@ -57,27 +56,22 @@
     @["create#{paneKey.capitalize()}Pane"]()

   handleLaunch: (paneKey) ->
-    pane = @[paneKey]
+    pane = @getPaneByType paneKey
     if @lastActivePaneKey is paneKey
-      @hidePane pane, paneKey
+      @lastActivePaneKey = null
+      @updatePaneVisiblityState paneKey, no
     else
-      lastActivePane = @getPaneByType @lastActivePaneKey
-      @hidePane lastActivePane, paneKey, no if lastActivePane
-      @showPane pane, paneKey
+      @lastActivePaneKey = paneKey
+      @updatePaneVisiblityState paneKey, yes

-  hidePane: (pane, paneKey, writeToCloud = yes) ->
+  hidePane: (pane, paneKey) ->
     pane.unsetClass "active"
-    @lastActivePaneKey = null
-    @updatePaneVisiblityState paneKey, no if writeToCloud

-  showPane: (pane, paneKey, writeToCloud = yes) ->
+  showPane: (pane, paneKey) ->
     if paneKey is "chat"
       @chat.dock.emit "click"
-      return @updatePaneVisiblityState "chat", yes
-
-    pane.setClass "active"
-    @lastActivePaneKey = paneKey
-    @updatePaneVisiblityState paneKey, yes  if writeToCloud
+    else
+      pane.setClass "active"

   updatePaneVisiblityState: (paneKey, value) ->
     map          = @paneVisibilityState
@@ -92,6 +86,7 @@
       floating : yes

     @chat.on "WorkspaceChatClosed", =>
+      @lastActivePaneKey = null
       @updatePaneVisiblityState "chat", no

   createTerminalPane: ->


Added didSet handler simpleProperty

Added didSet handler simpleProperty


Clean context aware defaults

Clean context aware defaults


Send analytics event after submitting group inquiry form

--- services/web/public/coffee/main/contact-us.coffee
+++ services/web/public/coffee/main/contact-us.coffee
@@ -103,5 +103,6 @@

 			request.then (response)->
 				$scope.sent = true
+				event_tracking.send 'subscription-funnel', 'plans-page', 'group-inquiry-sent'
 				$scope.error = (response.status != 200)
 				$scope.$apply()


:lipstick:

:lipstick:

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -52,33 +52,33 @@
       expect(rootView.find('.markdown-preview')).not.toExist()
       expect(MarkdownPreview.prototype.loadHtml).not.toHaveBeenCalled()

-   describe "core:cancel event", ->
-     it "removes markdown preview", ->
-       rootView.open('file.md')
-       editor = rootView.getActiveView()
-       expect(rootView.find('.markdown-preview')).not.toExist()
-       editor.trigger('markdown-preview:toggle')
+  describe "core:cancel event", ->
+   it "removes markdown preview", ->
+     rootView.open('file.md')
+     editor = rootView.getActiveView()
+     expect(rootView.find('.markdown-preview')).not.toExist()
+     editor.trigger('markdown-preview:toggle')

-       markdownPreviewView = rootView.find('.markdown-preview')?.view()
-       expect(markdownPreviewView).toExist()
-       markdownPreviewView.trigger('core:cancel')
-       expect(rootView.find('.markdown-preview')).not.toExist()
+     markdownPreviewView = rootView.find('.markdown-preview')?.view()
+     expect(markdownPreviewView).toExist()
+     markdownPreviewView.trigger('core:cancel')
+     expect(rootView.find('.markdown-preview')).not.toExist()

-   describe "when the editor receives focus", ->
-     it "removes the markdown preview view", ->
-       rootView.attachToDom()
-       rootView.open('file.md')
-       editor = rootView.getActiveView()
-       expect(rootView.find('.markdown-preview')).not.toExist()
-       editor.trigger('markdown-preview:toggle')
+  describe "when the editor receives focus", ->
+   it "removes the markdown preview view", ->
+     rootView.attachToDom()
+     rootView.open('file.md')
+     editor = rootView.getActiveView()
+     expect(rootView.find('.markdown-preview')).not.toExist()
+     editor.trigger('markdown-preview:toggle')

-       markdownPreviewView = rootView.find('.markdown-preview')
-       editor.focus()
-       expect(markdownPreviewView).toExist()
-       expect(rootView.find('.markdown-preview')).not.toExist()
+     markdownPreviewView = rootView.find('.markdown-preview')
+     editor.focus()
+     expect(markdownPreviewView).toExist()
+     expect(rootView.find('.markdown-preview')).not.toExist()

-   describe "when no editor is open", ->
-     it "does not attach", ->
-       expect(rootView.getActiveView()).toBeFalsy()
-       rootView.trigger('markdown-preview:toggle')
-       expect(rootView.find('.markdown-preview')).not.toExist()
+  describe "when no editor is open", ->
+   it "does not attach", ->
+     expect(rootView.getActiveView()).toBeFalsy()
+     rootView.trigger('markdown-preview:toggle')
+     expect(rootView.find('.markdown-preview')).not.toExist()


Don't force markdown preview to load.

Don't force markdown preview to load.

Make the specs use activation events.

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -6,7 +6,7 @@
     atom.packages.activatePackage('language-gfm', sync: true)
     atom.workspaceView = new WorkspaceView
     atom.workspace = atom.workspaceView.model
-    atom.packages.activatePackage("markdown-preview", immediate: true)
+    atom.packages.activatePackage("markdown-preview")
     spyOn(MarkdownPreviewView.prototype, 'renderMarkdown')

   describe "when the active item can't be rendered as markdown", ->


:art:

:art:

--- src/package-manager.coffee
+++ src/package-manager.coffee
@@ -276,9 +276,8 @@
   getPackageDependencies: ->
     unless @packageDependencies?
       try
-        @packageDependencies = require('../package.json')?.packageDependencies ? {}
-      catch error
-        @packageDependencies = {}
+        @packageDependencies = require('../package.json')?.packageDependencies
+      @packageDependencies ?= {}

     @packageDependencies


Updated test cases for "asyncIf"

Updated test cases for "asyncIf"

--- test/t4-asyncIf.coffee
+++ test/t4-asyncIf.coffee
@@ -5,7 +5,7 @@

 { AsyncCondition, asyncIf } = baselib

-describe 'AsyncCondition', ->
+describe 'asyncIf', ->

   it 'Existence', ->


HACK: Add the source paths from subpackages to dcd

Signed-off-by: Dan Printzell <69f25cbe4b2608181d39803083cb5ee0c30f2794@gmail.com>

--- lib/dub-config.coffee
+++ lib/dub-config.coffee
@@ -78,7 +78,12 @@

 		imports.push.apply imports, @config?.importPaths or []
 		imports.push.apply imports, @config?.sourcePaths or ["source/"]
+		imports.push.apply imports, @getConfig(config).sourcePaths if config? and @getConfig(config)?.sourcePaths
 		imports.push.apply imports, @getConfig(config).importPaths if config? and @getConfig(config)?.importPaths
+
+		for sub in @config?.subPackages or []
+			imports.push.apply imports, sub.importPaths or []
+			imports.push.apply imports, sub.sourcePaths or []

 		found = []
 		for imp in imports


FIX: updated to new api name

FIX: updated to new api name

--- src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee
+++ src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee
@@ -56,7 +56,7 @@
         send_notifications: $scope.unit.send_notifications
         enable_sync_timetable: $scope.unit.enable_sync_timetable
         enable_sync_enrolments: $scope.unit.enable_sync_enrolments
-        draft_task_id: $scope.unit.draft_task_id
+        draft_task_definition_id: $scope.unit.draft_task_definition_id
       }

       if $scope.unit.teaching_period_id


Fix parsing bold and italic in FF

Fix parsing bold and italic in FF

--- src/trix/html_parser.coffee
+++ src/trix/html_parser.coffee
@@ -2,10 +2,6 @@
 #= require trix/dom

 class Trix.HTMLParser
-  styleMap =
-    bold: ["font-weight", "bold"]
-    italic: ["font-style", "italic"]
-
   allowedAttributes = "style href src width height".split(" ")

   @parse: (html) ->
@@ -64,9 +60,11 @@
     attributes = {}
     style = window.getComputedStyle(element)

-    for attribute, [property, value] of styleMap
-      if style[property] is value
-        attributes[attribute] = true
+    if style["fontWeight"] is "bold" or style["fontWeight"] >= 700
+      attributes["bold"] = true
+
+    if style["fontStyle"] is "italic"
+      attributes["italic"] = true

     if link = Trix.DOM.closest(element, "a")
       attributes["href"] = link.getAttribute("href")


Disable vim-mode-visual-block atom package.

This plugin currently conflicts with Sublime-Style-Column-Selection.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -23,6 +23,7 @@
       "nuclide-diff-view"
       "nuclide-code-format"
       "nuclide-click-to-symbol"
+      "vim-mode-visual-block"
     ]
     themes: [
       "atom-dark-ui-slim"


updated menu toggle

updated menu toggle

--- app/assets/javascripts/app/common/menu.coffee
+++ app/assets/javascripts/app/common/menu.coffee
@@ -14,10 +14,20 @@
       $('#wrapper').toggleClass('opened-menu')

   bindModelLessLinks : () ->
-    @$menu.find('.with-dd[href=""]').click (e) =>
-      e.preventDefault()
-      @_toggleMenuItem @$menu.find('>> .is-active')
-      @_toggleMenuItem $(e.currentTarget)
+    @$menu.find('.with-dd').click (e) =>
+      $clickedMenuItem = $(e.currentTarget)
+      href = $clickedMenuItem.attr('href')
+      if href is ''
+        e.preventDefault()
+        @_toggleGroupMenuItem $clickedMenuItem
+      else if href is window.location.pathname
+        e.preventDefault()
+        @_toggleMenuItem $clickedMenuItem
+
+  _toggleGroupMenuItem : ($menuItem) ->
+    $activeMenuItem = @$menu.find('>> .is-active')
+    @_toggleMenuItem($activeMenuItem) unless $menuItem.is $activeMenuItem
+    @_toggleMenuItem $menuItem

   _toggleMenuItem : ($menuItem) ->
     return unless $menuItem


Contemplar los perfiles sin serie en el mapa

--- app/assets/javascripts/comunes/mapa.js.coffee
+++ app/assets/javascripts/comunes/mapa.js.coffee
@@ -6,11 +6,15 @@
   map = L.map('mapa').setView(centro, zoom)

   preparar_puntos = (punto, capa) ->
+    serie = if punto.properties.serie
+      "#{
+        punto.properties.serie.nombre || 'Serie'} - "
+    else
+      ''
     capa.bindPopup(
-      "#{
-        punto.properties.serie.nombre || 'Serie'} - " +
-      "#{
-        punto.properties.numero || 'Perfil'}")
+      serie + "#{
+        punto.properties.numero || 'Perfil'}"
+    )

   # Capa de tiles de MapBox
   # TODO Ver cómo cargar la de geointa o el ign


Fixed smartlist shortcuts

Fixed smartlist shortcuts

-Inaccurate smartlist trigger cleaning
-Removed spans inserted on backspace in list li elements.

--- app/assets/javascripts/dante/editor.js.coffee
+++ app/assets/javascripts/dante/editor.js.coffee
@@ -784,7 +784,10 @@
       #  @markAsSelected(anchor_node)
       #  @setupFirstAndLast()
       #  @displayTooltipAt($(@el).find(".is-selected"))
-
+
+      if $(anchor_node).hasClass("graf--li")
+        @handleListSpanTag($(anchor_node), e);
+
     #arrows key
     if _.contains([37,38,39,40], e.which)
       @handleArrow(e)
@@ -1038,47 +1041,52 @@
   setElementName: (element)->
     $(element).attr("name", utils.generateUniqueName())

-  #LIST METHODS
-
-  listify: ($paragraph, listType, tagLength)->
+  # LIST METHODS
+
+  listify: ($paragraph, listType, regex)->
+
     utils.log "LISTIFY PARAGRAPH"
-    content = $paragraph.html().replace(/ /g, " ")
-    utils.log(tagLength)
-
-    content = content.slice(tagLength, content.length)
-
+
+    content = $paragraph.html().replace(/ /g, " ").replace(regex, "")
+
     switch(listType)
       when "ul" then $list = $("

")
       when "ol" then $list = $("

")
       else return false
-
+
     @addClassesToElement($list[0])
     @replaceWith("li", $paragraph)
     $li = $(".is-selected")
-
+
     @setElementName($li[0])

     $li.html(content).wrap($list)

     if($li.find("br").length == 0)
       $li.append("
")
+
     @setRangeAt($li[0])

     $li[0]

   handleSmartList: ($item, e)->
     utils.log("HANDLE A SMART LIST")
-    match = $item.text().match(/^\s*(\-|\*)\s*/)
-
-    if match
-      utils.log("CREATING UL LIST ITEM")
-      e.preventDefault()
-      $li = @listify($item, "ul", match[0].length)
-    else if match = $item.text().match(/^\s*1(\.|\))\s*/)
-      utils.log("CREATING OL LIST ITEM")
-      e.preventDefault()
-      $li = @listify($item, "ol", match[0].length)
-
+
+    chars = @getCharacterPrecedingCaret()
+    match = chars.match(/^\s*(\-|\*)\s*$/)
+    if(match)
+        utils.log("CREATING LIST ITEM")
+        e.preventDefault()
+        regex = new RegExp(/\s*(\-|\*)\s*/)
+        $li = @listify($item, "ul", regex)
+    else
+      match = chars.match(/^\s*1(\.|\))\s*$/)
+      if(match)
+        utils.log("CREATING LIST ITEM")
+        e.preventDefault()
+
+        regex = new RegExp(/\s*1(\.|\))\s*/)
+        $li = @listify($item, "ol", regex)
     $li

   handleListLineBreak: ($li, e)->
@@ -1100,7 +1108,7 @@
         $list.after($paragraph)
         $li.addClass("graf--removed").remove()

-      else if ($li.prev().length isnt 0 and $li.prev().text() is "")
+      else if ($li.prev().length isnt 0 and $li.prev().text() is "" and @getCharacterPrecedingCaret() is "")
         e.preventDefault()
         utils.log("PREV IS EMPTY")
         content = $li.html()
@@ -1137,3 +1145,11 @@
         $list.remove()

       @setupFirstAndLast()
+
+  handleListSpanTag: ($li, e)->
+
+    $list = $li.parent("ol, ul")
+    $spans = $list.find("span")
+    $(span).replaceWith($(span).html()) for span in $spans when not $(span).hasClass("defaultValue")
+    $li
+


change tooltip positioning to prevent left viewport breakout

--- app/assets/javascripts/modules/tooltip.coffee
+++ app/assets/javascripts/modules/tooltip.coffee
@@ -4,8 +4,8 @@
   if tooltip.length
     tooltip.qtip
       position:
-        my: 'bottom center'
-        at: 'top center'
+        my: 'bottom left'
+        at: 'top left'
         effect: false
         viewport: $(window)
         adjust:


OX-247 bugfix2

OX-247 bugfix2

--- app/assets/javascripts/oxalis/view/gui.coffee
+++ app/assets/javascripts/oxalis/view/gui.coffee
@@ -305,10 +305,10 @@
     @model.route.setComment(value)

   prevComment : =>
+    @trigger "setActiveNode", @model.route.nextCommentNodeID(false)
+
+  nextComment : =>
     @trigger "setActiveNode", @model.route.nextCommentNodeID(true)
-
-  nextComment : =>
-    @trigger "setActiveNode", @model.route.nextCommentNodeID(false)

   updateRadius : (value) ->
     if value then @settings.radius = value


fixed download button in tracing UI; fixes #395

--- app/assets/javascripts/oxalis/view/gui.coffee
+++ app/assets/javascripts/oxalis/view/gui.coffee
@@ -182,11 +182,12 @@
         if confirm("Are you sure you want to permanently finish this tracing?")
           window.location.href = event.target.href

+
     $("#trace-download-button").click (event) =>

       event.preventDefault()
       @saveNow().done =>
-          window.location.href = event.target.href
+          window.location.href = event.currentTarget.href

     $("#trace-save-button").click (event) =>


OX-670 paste position without commata

OX-670 paste position without commata

--- app/assets/javascripts/oxalis/view/gui.coffee
+++ app/assets/javascripts/oxalis/view/gui.coffee
@@ -215,7 +215,11 @@
       new $.Deferred().resolve()

   setPosFromString : (posString) =>
-    stringArray = posString.split(",")
+    # remove leading/trailing whitespaces
+    strippedString = posString.trim()
+    # replace remaining whitespaces with commata
+    unifiedString = strippedString.replace /,?\s+,?/g, ","
+    stringArray = unifiedString.split(",")
     if stringArray.length == 3
       pos = [parseInt(stringArray[0]), parseInt(stringArray[1]), parseInt(stringArray[2])]
       if !isNaN(pos[0]) and !isNaN(pos[1]) and !isNaN(pos[2])


Fix ContainersRestartWidget to properly initialize when the output is streamed

--- app/assets/javascripts/plugins/borg.js.coffee
+++ app/assets/javascripts/plugins/borg.js.coffee
@@ -100,7 +100,7 @@
     this

   getList: ->
-    unless @$list
+    unless @$list?.length
       @$list = $('<div>').addClass('container-tasks').appendTo(@$container)
     @$list


return false (testing)

return false (testing)

--- app/assets/javascripts/sammy_router.js.coffee
+++ app/assets/javascripts/sammy_router.js.coffee
@@ -82,6 +82,7 @@
       context.redirect("#/")
       return false
     render( new Sview('lots_index', {auction: auction, lots: auction.lots, status: PB.status }) )
+    return false

   @post "#/lots",  (context) ->
     new_lot = new PB.Lot(context.params.lot)


Revert "Trying to get timestamps working"

This reverts commit 290be6ef863b36ba038aed6755cd9b901c0fd89e.

--- src/adapters/campfire.coffee
+++ src/adapters/campfire.coffee
@@ -50,9 +50,9 @@
       unless bot.info.id == author.id
         self.receive new Robot.LeaveMessage(author)

-    bot.on "TimestampMessage", () ->
-      console.log "Timestamp"
-      self.receive new Robot.TimestampMessage(null)
+    bot.on "TimestampMessage", withAuthor (id, created, room, user, body, author) ->
+      unless bot.info.id == author.id
+        self.receive new Robot.TimestampMessage(author)

     bot.Me (err, data) ->
       bot.info = data.user


try reconnecting to campfire on a per room basis when streams close

--- src/adapters/campfire.coffee
+++ src/adapters/campfire.coffee
@@ -55,6 +55,10 @@
           bot.Room(roomId).join (err, callback) ->
             bot.Room(roomId).listen()

+    bot.on "reconnect", (roomId) =>
+      bot.Room(roomId).join (err, callback) ->
+        bot.Room(roomId).listen()
+
     @bot = bot

 exports.use = (robot) ->
@@ -159,8 +163,10 @@
                   @robot.logger.error "Campfire error: #{err}"

         response.on "end", =>
-          @robot.logger.error "Streaming connection closed. :("
-          process.exit(1)
+          @robot.logger.error "Streaming connection closed for room #{id}. :("
+          setTimeout (->
+            self.emit "reconnect", id
+          ), 5000

         response.on "error", (err) =>
           @robot.logger.error "Campfire response error: #{err}"


changed sidebar info to only show in click, instead of on hover of nodes

--- app/coffee/main.coffee
+++ app/coffee/main.coffee
@@ -149,6 +149,10 @@
         .style 'fill', (d) => @color @group_by(d)
         .on 'mouseover', @node_tip.show
         .on 'mouseenter', (d) =>
+          setTimeout (->
+            set_related_links_status d, 'active'
+          ), 1
+        .on 'click', (d) =>
           $('#node-title').html @node_tip_html(d)
           $('#node-url').attr 'href', d.relative_url
           $node_attrs = $('#node-attrs').html ''
@@ -159,9 +163,6 @@

#{key[0].toUpperCase() + key[1..-1]}

#{if typeof(d[key]) == 'object' then d[key].join(', ') else d[key]}

             """
-          setTimeout (->
-            set_related_links_status d, 'active'
-          ), 1
         .on 'mouseout', (d) =>
           @node_tip.hide()
           set_related_links_status d, 'inactive'


Datasources use the model events

Datasources use the model events

--- src/client/datasource.coffee
+++ src/client/datasource.coffee
@@ -1,4 +1,4 @@
-define ['underscore'], (_)->
+define ['underscore', 'jquery'], (_, $)->
   #
   # Parses the URI to replace placeholders with actual values
   #
@@ -52,16 +52,27 @@
     # @returns {mixed} May return an object, a Promise most likely or anything else
     #
     fetch: ()->
+      dfd = $.Deferred()
       if _.isFunction(@def)
         ret = @def()
-        ret && (ret.deferred || ret)
+        dfd = ret.deferred if ret?.deferred
+        dfd.resolve ret
       else
-        return false if /undefined/.test(@def.path)
+        dfd.resolve(false) if /undefined/.test(@def.path)
         if @type == 'model'
-          @transport.model(@def).deferred
+          data = @transport.model(@def)
         else if @type == 'collection'
-          @transport.collection(@def).deferred
+          data = @transport.collection(@def)
         else
-          throw new TypeError('Unknown type of datasource: ' + @type);
+          dfd.reject new TypeError('Unknown type of datasource: ' + @type);
+        if data._fetched
+          dfd.resolve data
+        else
+          data.once 'sync', ->
+            dfd.resolve data
+          data.once 'error', (model, xhr)->
+            dfd.reject xhr
+      dfd.promise()
+
   Datasource


move invalid alert to top

move invalid alert to top

--- src/components/question.cjsx
+++ src/components/question.cjsx
@@ -91,6 +91,10 @@
           }

       }
+      {<BS.Alert bsStyle="danger">
+         Invalid: {invalid.reason}
+        </BS.Alert> unless invalid.valid}
+
       <QuestionFormatType questionId={id} />

       <BS.Input type="checkbox" label="Order Matters"
@@ -114,8 +118,5 @@
         Detailed Solution
         <textarea onChange={@updateSolution} value={QuestionStore.getSolution(id)}></textarea>

-      {<BS.Alert bsStyle="danger">
-         Invalid: {invalid.reason}
-        </BS.Alert> unless invalid.valid}


rename "Preserve Answer Order" to "Order Matters"

--- src/components/question.cjsx
+++ src/components/question.cjsx
@@ -106,8 +106,8 @@
           <input onChange={@preserveOrderClicked}
             id="preserveOrder#{id}"
             type="checkbox"
-            defaultChecked={QuestionStore.isOrderPreserved(id)} />
-          Preserve Answer Orders
+            defaultChecked={QuestionStore.isOrderPreserved(id)}
+          /> Order Matters

           {answers}


改进c-class的处理规则

改进c-class的处理规则

--- src/core/dom-template.coffee
+++ src/core/dom-template.coffee
@@ -216,9 +216,9 @@
 					else
 						feature = buildAttrFeature(dom, attrName, attrValue)

-#					if feature
-#						features ?= []
-#						features.push(feature)
+	#					if feature
+	#						features ?= []
+	#						features.push(feature)

 	for customDomCompiler in cola._userDomCompiler.$
 		result = customDomCompiler(scope, dom, null, context)


Sorting Improvements

Sorting Improvements

--- app/models/task.coffee
+++ app/models/task.coffee
@@ -41,8 +41,8 @@
         diff = a.priority - b.priority
         if diff is 0
           # If the priorities are the same then sort by date, then by name
-          newA = if a.date is false then Infinity else a.date
-          newB = if b.date is false then Infinity else b.date
+          newA = if a.date is false or a.date is "" then Infinity else a.date
+          newB = if b.date is false or b.date is "" then Infinity else b.date

           diff = newB - newA


enable text selection and copy in panel

enable text selection and copy in panel

--- lib/panel/view.coffee
+++ lib/panel/view.coffee
@@ -11,7 +11,7 @@
             @div outlet: 'head', class: 'inset-panel padded', =>
                 @span outlet: 'title'
                 @span outlet: 'inputMethod'
-            @div outlet: 'body', class: "block padded", =>
+            @div outlet: 'body', class: "block padded native-key-bindings", tabindex: "-1", =>
                 @div outlet: 'content', class: 'agda-panel-content', =>
                     @ul outlet: 'contentList', class: 'list-group'
                 @subview 'inputBox', new TextEditorView mini: true


Tweaking solarce's title

Tweaking solarce's title

**Infrastructure Conductor** =D

--- app/routes/team.coffee
+++ app/routes/team.coffee
@@ -143,7 +143,7 @@
       },
       {
         name: 'Brandon Burton'
-        title: 'Regional Cloud Manager'
+        title: 'Infrastructure Conductor'
         handle: 'solarce'
         nationality: 'usa'
         country: 'usa'


fix: fallback to name embedded in match in MyMatchesTabView.coffee

--- app/views/ladder/MyMatchesTabView.coco.coffee
+++ app/views/ladder/MyMatchesTabView.coco.coffee
@@ -86,8 +86,7 @@
           name = opponentUser?.name
           name ||= opponentUser.firstName + ' ' + opponentUser.lastName if opponentUser?.firstName
           name ||= "Anonymous #{opponent.userID.substr(18)}" if opponentUser
-          unless name
-            console.log 'found', nameMap[opponent.userID], 'for', opponent.userID, "http://codecombat.com/db/user/#{opponent.userID}"
+          name ||= opponent.name
           name ||= '<bad match data>'
           if name.length > 21
             name = name.substr(0, 18) + '...'


Corrected mistake in reply creation time (article.created_at) and removed extra <br> from quote header formatting

--- app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
@@ -148,11 +148,11 @@
         selected = App.Utils.text2html(selected)

     if selected
-      date = @date_format(article.updated_by.created_at)
+      date = @date_format(article.created_at)
       name = article.updated_by.displayName()
       email = article.updated_by.email
       quote_header = App.i18n.translateInline('On %s, %s <%s> wrote:', date, name, email)
-      selected = "

#{quote_header}

#{selected}

"
+      selected = "

#{quote_header}

#{selected}

"

       # add selected text to body
       body = selected + body


updated slider text on input #165

updated slider text on input #165

--- app/assets/javascripts/oxalis/view/settings/setting_views/slider_setting_view.coffee
+++ app/assets/javascripts/oxalis/view/settings/setting_views/slider_setting_view.coffee
@@ -30,9 +30,15 @@

   events :
+    "input @ui.slider" : "updateText"
     "change @ui.slider" : "handleChange"
     "change @ui.text" : "handleChange"
     "dblclick @ui.slider" : "resetValue"
+
+
+  updateText : (evt) ->
+
+    @ui.text.val(evt.target.value)

   handleChange : (evt) ->


:fire: Remove hook on editor:attached to stop propagation

--- lib/table-view.coffee
+++ lib/table-view.coffee
@@ -39,10 +39,6 @@
         @activateCellAtPosition position

       @focus()
-
-    @subscriptions.add @asDisposable @on 'editor:attached', (e) ->
-      e.stopImmediatePropagation()
-      return false

     @subscribeToColumn(column) for column in @table.getColumns()

@@ -351,7 +347,7 @@
     .show()

     @editView.find('.hidden-input').focus()
-
+
     @editView.getModel().getBuffer().setText(activeCell.getValue().toString())

   stopEdit: ->


December bug fix :)

December bug fix :)


ListViewHeaderColumn: Allow parameter "element" for custom elements in draggable headers.

--- src/elements/ListView/ListViewHeaderColumn.coffee
+++ src/elements/ListView/ListViewHeaderColumn.coffee
@@ -11,7 +11,7 @@
 		super()

 		@removeOpt("text")
-		@removeOpt("element")
+		# @removeOpt("element")

 		@addOpts
 			spacer:
@@ -67,8 +67,10 @@
 		else
 			arr = []

-		if @__label
-			arr.push(@__label.DOM)
+		if @_element
+			arr.push(@_element)
+		else if @__label
+			arr.push(@__label)

 		arr


Maybe attach to the DOM?

Maybe attach to the DOM?

--- spec/about-spec.coffee
+++ spec/about-spec.coffee
@@ -51,6 +51,7 @@
     spyOn(atom, 'isReleasedVersion').andReturn(true)

     workspaceElement = atom.views.getView(atom.workspace)
+    jasmine.attachToDOM(workspaceElement)

     waitsForPromise ->
       atom.packages.activatePackage('status-bar')


Use the MockUpdater

Use the MockUpdater

--- spec/about-spec.coffee
+++ spec/about-spec.coffee
@@ -266,7 +266,7 @@
       runs -> expect(workspaceElement).not.toContain('.about-release-notes')

 triggerUpdate = (version) ->
-  atom.updateAvailable({releaseVersion: version})
+  MockUpdater.finishDownloadingUpdate(version)

 MockUpdater =
   checkForUpdate: ->


Some comments for SDP adjusting

Some comments for SDP adjusting

--- src/echo.coffee
+++ src/echo.coffee
@@ -138,16 +138,20 @@
         remove_line()

       else if m = line.match(/a=setup:actpass/)
+        # we are acting a dtls client
         lines[i] = 'a=setup:active'

       else if m = line.match(/a=candidate:(.*)/)
+        # add incoming candidates to libnice
         stream.nice.addRemoteIceCandidate line
         remove_line()

       else if m = line.match(/a=crypto:(.*)/)
+        # we are using dtls-srtp, so this line has to go
         remove_line()

       else if m = line.match(/a=fingerprint:/)
+        # replace fingerprint of the peer with our own
         lines[i] = 'a=fingerprint:' + stream.dtls_srtp.fingerprint()

       i++


Don't use path as a param name

Don't use path as a param name

--- src/file.coffee
+++ src/file.coffee
@@ -108,13 +108,13 @@
   getDigest: ->
     @digest ? @setDigest(@readSync())

-  handleNativeChangeEvent: (eventType, path) ->
+  handleNativeChangeEvent: (eventType, eventPath) ->
     switch eventType
       when 'delete'
         @unsubscribeFromNativeChangeEvents()
         @detectResurrectionAfterDelay()
       when 'rename'
-        @setPath(path)
+        @setPath(eventPath)
         @emit "moved"
       when 'change'
         oldContents = @cachedContents


Minifying tests.

Minifying tests.

--- spec/spec-index.coffee
+++ spec/spec-index.coffee
@@ -1,6 +1,9 @@

 assert = require 'assert'
 $ = require '../src'
+
+y = (d, q) -> assert.equal true, $.ev d, q
+n = (d, q) -> assert.equal false, $.ev d, q

 describe 'ev', ->

@@ -9,73 +12,73 @@
     describe '$and', ->

       it 'should match two positives', ->
-        assert.equal true, $.ev { foo: bar: '123' }, { $and: [ { 'foo': $exists: true }, { 'foo.bar': { $eq: '123' } } ] }
+        y { foo: bar: '123' }, { $and: [ { 'foo': $exists: true }, { 'foo.bar': { $eq: '123' } } ] }

       it 'should not match one positive and one negative', ->
-        assert.equal false, $.ev { foo: bar: '123' }, { $and: [ { 'foo': $exists: true }, { 'foo.bar': { $eq: '1234' } } ] }
+        n { foo: bar: '123' }, { $and: [ { 'foo': $exists: true }, { 'foo.bar': { $eq: '1234' } } ] }

       it 'should match nested positive', ->
-        assert.equal true, $.ev { foo: 1, bar: 2}, { $and: [ $and: [ { 'foo': { $eq: 1 } } ] ] }
+        y { foo: 1, bar: 2}, { $and: [ $and: [ { 'foo': { $eq: 1 } } ] ] }

     describe '$or', ->

       it 'should match one positive', ->
-        assert.equal true, $.ev { foo: 1 }, { $or: [ { 'foo': $gt: 0 } ] }
+        y { foo: 1 }, { $or: [ { 'foo': $gt: 0 } ] }

       it 'should match one positive and one negative', ->
-        assert.equal true, $.ev { foo: 1 }, { $or: [ { 'foo': $gt: 0 }, { 'foo': $lt: -1 } ] }
+        y { foo: 1 }, { $or: [ { 'foo': $gt: 0 }, { 'foo': $lt: -1 } ] }

       it 'should not match two negatives', ->
-        assert.equal false, $.ev { foo: 1 }, { $or: [ { 'foo': $gt: 2 }, { 'foo': $lt: 0 } ] }
+        n { foo: 1 }, { $or: [ { 'foo': $gt: 2 }, { 'foo': $lt: 0 } ] }

       it 'should not match single negatives', ->
-        assert.equal false, $.ev { foo: 1 }, { $or: [ { 'foo2': $eq: 1 } ] }
+        n { foo: 1 }, { $or: [ { 'foo2': $eq: 1 } ] }

     describe '$nor', ->

       it 'should not match single positive', ->
-        assert.equal false, $.ev { foo: 1 }, { $nor: [ { 'foo': $eq: 1 } ] }
+        n { foo: 1 }, { $nor: [ { 'foo': $eq: 1 } ] }

       it 'should match single negative', ->
-        assert.equal true, $.ev { foo: 1 }, { $nor: [ { 'foo': $eq: 2 } ] }
+        y { foo: 1 }, { $nor: [ { 'foo': $eq: 2 } ] }

       it 'should match two negatives', ->
-        assert.equal true, $.ev { foo: 1 }, { $nor: [ { 'foo': $eq: 2 }, { 'bar': $eq: 1 } ] }
+        y { foo: 1 }, { $nor: [ { 'foo': $eq: 2 }, { 'bar': $eq: 1 } ] }

       it 'should not match one positive and one negative', ->
-        assert.equal false, $.ev { foo: 1 }, { $nor: [ { 'foo': $eq: 2 }, { 'foo': $eq: 1 } ] }
+        n { foo: 1 }, { $nor: [ { 'foo': $eq: 2 }, { 'foo': $eq: 1 } ] }

     describe '$not', ->

       it 'should not match negated positive equality', ->
-        assert.equal false, $.ev { foo: 1 }, { 'foo': $not: $eq: 1 }
+        n { foo: 1 }, { 'foo': $not: $eq: 1 }

       it 'should match negated negative equality', ->
-        assert.equal true, $.ev { foo: 1 }, { 'foo': $not: $eq: 2 }
+        y { foo: 1 }, { 'foo': $not: $eq: 2 }

   it 'should work with nothing', ->
-    assert.equal true, $.ev()
+    y null, null

   it 'should match eq', ->
-    assert.equal true, $.ev { foo: 1 }, { 'foo': { $eq: 1 } }
+    y { foo: 1 }, { 'foo': { $eq: 1 } }

   it 'should not match eq', ->
-    assert.equal false, $.ev { foo: 1 }, { 'foo': { $eq: 2 } }
+    n { foo: 1 }, { 'foo': { $eq: 2 } }

   it 'should not match non existing eq', ->
-    assert.equal false, $.ev { foo: 1 }, { 'foo2': { $eq: 1 } }
+    n { foo: 1 }, { 'foo2': { $eq: 1 } }

   it 'should work with simple $and', ->
-    assert.equal true, $.ev { foo: bar: 1 }, { $and: [ { 'foo.bar': { $eq: 1 } }, { 'foo': $exists: true } ] }
+    y { foo: bar: 1 }, { $and: [ { 'foo.bar': { $eq: 1 } }, { 'foo': $exists: true } ] }

   it 'should work with simple $exists false', ->
-    assert.equal false, $.ev { foo: bar: 1 }, { 'foo.bar': $exists: false }
+    n { foo: bar: 1 }, { 'foo.bar': $exists: false }

   it 'should work with simple $exists false 2', ->
-    assert.equal false, $.ev { foo: bar: 1 }, { 'foo.baz': $exists: true }
+    n { foo: bar: 1 }, { 'foo.baz': $exists: true }

   it 'should work with simple $exists false', ->
-    assert.equal true, $.ev { foo: bar: 1 }, { 'foo.bar': $exists: true }
+    y { foo: bar: 1 }, { 'foo.bar': $exists: true }

   it 'should not match lt', ->
-    assert.equal false, $.ev { foo: bar: 123 }, { 'foo.bar': { $lt: 100 } }
+    n { foo: bar: 123 }, { 'foo.bar': { $lt: 100 } }


authentication now occurs after client properly opened

--- src/server/db/mongo.coffee
+++ src/server/db/mongo.coffee
@@ -32,7 +32,10 @@
   client = options.client or new mongodb.Db(options.db, new mongodb.Server(options.hostname, options.port, options.mongoOptions))

   if options.user and options.password
-    client.auth(options.user, options.password)
+    client.open (err, db) ->
+      if not err
+        client = db
+        client.authenticate(options.user, options.password)

   opsCollectionForDoc = (docName) -> 'ops.' + encodeURIComponent(docName).replace(/\./g, '%2E').replace(/-/g, '%2D')


better code

better code

--- src/game.coffee
+++ src/game.coffee
@@ -51,7 +51,7 @@
     if game.board.cases[casePosition].constructor isnt Tile
       return

-    if game.data[casePosition] is game.entities.Mine
+    if game.isMine casePosition
       game.willDie = casePosition
       return


Check platform not env

Check platform not env

--- build/Gruntfile.coffee
+++ build/Gruntfile.coffee
@@ -41,7 +41,7 @@
   buildDir = grunt.option('build-dir') ? path.join(tmpDir, 'atom-build')
   installDir = grunt.option('install-dir')

-  home = if process.env is 'win32' then process.env.USERPROFILE else process.env.HOME
+  home = if process.platform is 'win32' then process.env.USERPROFILE else process.env.HOME
   atomShellDownloadDir = path.join(home, '.atom', 'atom-shell')

   symbolsDir = path.join(buildDir, 'Atom.breakpad.syms')


subscription note: add space

subscription note: add space

--- src/smc-webapp/r_misc.cjsx
+++ src/smc-webapp/r_misc.cjsx
@@ -870,7 +870,7 @@
         if total > 0
             suggestion = Your {total} members-only {misc.plural(total,'upgrade')} are already in use on other projects.  You can purchase further upgrades  by adding a subscription (you can add the same subscription multiple times), or disable member-only hosting for another project to free a spot up for this one.
         else
-            suggestion = Subscriptions start at only $7/month.
+            suggestion = <Space />Subscriptions start at only $7/month.

     <Alert bsStyle='warning' style={marginTop:'10px'}>

Warning: this project is running on a free server

@@ -895,7 +895,7 @@
         if total > 0
             suggestion = Your {total} network {misc.plural(total,'upgrade')} are already in use on other projects.  You can purchase further upgrades  by adding a subscription (you can add the same subscription multiple times), or disable a network upgrade for another project to free a spot up for this one.
         else
-            suggestion = Subscriptions start at only $7/month.
+            suggestion = <Space />Subscriptions start at only $7/month.

     <Alert bsStyle='warning' style={marginTop:'10px'}>

Warning: this project does not have network access


Support to pass padding for all of edges at once

--- core/KDView.coffee
+++ core/KDView.coffee
@@ -698,8 +698,11 @@
         if 'string' is typeof view
           dragState.containment.viewBounds = @[view].getBounds()
         dragState.containment.viewBounds or= @parent.getBounds()
+        if 'number' is typeof options.containment.padding
+        then padding = options.containment.padding
+        else padding = 0
         dragState.containment.padding = \
-          options.containment.padding or top: 0, right: 0, bottom: 0, left: 0
+            top: padding, right: padding, bottom: padding, left: padding

       # TODO: should move these lines
       dragState.handle      = options.handle


Add atom-elixir package

Add atom-elixir package

--- atom/packages.cson
+++ atom/packages.cson
@@ -1,5 +1,6 @@
 packages: [
   "atom-beautify"
+  "atom-elixir"
   "atom-wrap-in-tag"
   "atomic-chrome"
   "autocomplete-elixir"


Use false as default value for PHP def snippet

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

   'define constant':
     'prefix': 'def'
-    'body': "define( '$1', ${2:''} );"
+    'body': "define( '$1', ${2:false} );"

   'define constant conditionally':
     'prefix': 'ifndef'


Add useful PHP snippets

Add useful PHP snippets

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -166,6 +166,14 @@
     'prefix': 'foreach'
     'body': "foreach ( ${1:\$object} as ${2:\$value} ) {\n\t$3\n}"

+  'array function call':
+    'prefix': 'fca'
+    'body': "${1:name}( array(\n\t$2\n)$3 );"
+
+  'key-value pair':
+    'prefix': 'kv'
+    'body': "'${1:key}' => ${2:value}$3"
+
 # Inline PHP Blocks (meant to be intermixed with HTML)

 '.text.html.php':


Fix custom manifest filename

Fix custom manifest filename

--- src/lib/loader/NodeJs.coffee
+++ src/lib/loader/NodeJs.coffee
@@ -50,7 +50,7 @@
     options.runtimes = loader.options.runtimes or []
     options.runtimes.push 'noflo' if options.runtimes.indexOf('noflo') is -1
     options.recursive = if typeof loader.options.recursive is 'undefined' then true else loader.options.recursive
-    options.manifest = 'fbp.json' unless options.manifest
+    options.manifest = loader.options.manifest or 'fbp.json'
     options

   listComponents: (loader, manifestOptions, callback) ->


corrige bug na remoção de item do minicart grava id do orderform no update do mesmo

--- src/coffee/portal-minicart.coffee
+++ src/coffee/portal-minicart.coffee
@@ -77,6 +77,7 @@
 			@handleOrderForm(data, slide)

 	handleOrderForm: (orderForm, slide = true) =>
+		@cartData.orderFormId = orderForm?.orderFormId
 		if orderForm?.items?
 			@cartData.items = orderForm.items
 			@prepareCart()


changed validateamilhandlerhelper require path

--- servers/lib/server/handlers/validateemail.test.coffee
+++ servers/lib/server/handlers/validateemail.test.coffee
@@ -8,11 +8,9 @@
   generateRandomString
   generateRandomUsername

-  RegisterHandlerHelper
-  ValidationHandlerHelper }               = require '../../../testhelper'
-
+  RegisterHandlerHelper }                 = require '../../../testhelper'
 { generateRegisterRequestParams }         = RegisterHandlerHelper
-{ generateValidateEmailRequestParams }    = ValidationHandlerHelper
+{ generateValidateEmailRequestParams }    = require '../../../testhelper/validateemailhandlerhelper'

 JUser                                     = null


Fix ObjectID hex string validation

Fix ObjectID hex string validation

--- coffee/document.coffee
+++ coffee/document.coffee
@@ -3,7 +3,7 @@
 ObjectID = require('mongodb').ObjectID

 exports.param = (req, res, next, id) ->
-  return res.json 400, error: 'Invalid ObjectID' if not /[a-f0-9]{24}/.test id
+  return res.json 400, error: 'Invalid ObjectID' if not /^[a-f0-9]{24}$/.test id
   req.id = ObjectID.createFromHexString id
   next()


HIRE-48 removed console.log

HIRE-48 removed console.log

--- src/main/java/app/app.coffee
+++ src/main/java/app/app.coffee
@@ -8,8 +8,8 @@
   $locationProvider.html5Mode
     enabled: true
     requireBase: false
-            RestangularProvider.setBaseUrl('/api/')
-         ).controller('NavigationCtrl', ($scope, $location, Restangular) ->
+  RestangularProvider.setBaseUrl('/api/')
+).controller('NavigationCtrl', ($scope, $location, Restangular) ->
   gitProperties = Restangular.one('gitProperties')
   gitProperties.get().then (data) ->
     $scope.gitPropertyDTO = data.gitPropertyDTO


fixed maxSeverity vs logLevel in setSettings

--- src/Observatory.coffee
+++ src/Observatory.coffee
@@ -70,7 +70,7 @@
     if s.maxSeverity?
       @settings.maxSeverity = s.maxSeverity
     else
-      if s.logLevel? then @settings.maxSeverity = s.logLevel
+      if s.logLevel? then @settings.maxSeverity = @LOGLEVEL[s.logLevel]
     @emitters.Toolbox?.maxSeverity = @settings.maxSeverity
     if s.printToConsole? and (s.printToConsole isnt @settings.printToConsole)
       @settings.printToConsole = s.printToConsole


fix (PostMessage) Switch postMessage dispatch implementation between web and mobile to get rid of duplicates

--- src/PostMessage.coffee
+++ src/PostMessage.coffee
@@ -1,3 +1,5 @@
+isMobile = /AppGyver|Crosswalk/.test(navigator.userAgent)
+
 class PostMessage

   @originalPostMessage: do (win = window)->
@@ -10,20 +12,24 @@
       catch e
         console.log "Could not pass postMessage to original window.postMessage: #{e}", args[0]

-  @postMessage: (message, targetOrigin) =>
-    escapedJSONMessage = escape(JSON.stringify(message))
+  # Switch between native and web implementations for postMessage dispatching.
+  # If we are in web, there's no native bridge to dispatch messages.
+  # If we are in mobile, we don't want to dispatch through window as well;
+  # we would get duplicate postMessage events in the originating window.
+  @postMessage: switch
+    when !isMobile
+      @originalPostMessage
+    else
+      (message, targetOrigin) =>
+        escapedJSONMessage = escape(JSON.stringify(message))

-    steroids.nativeBridge.nativeCall
-      method: "broadcastJavascript"
-      parameters:
-        javascript: "steroids.PostMessage.dispatchMessageEvent('#{escapedJSONMessage}', '*');"
-      successCallbacks: []
-      failureCallbacks: []
-      recurringCallbacks: []
-
-    @originalPostMessage message, targetOrigin
-
-
+        steroids.nativeBridge.nativeCall
+          method: "broadcastJavascript"
+          parameters:
+            javascript: "steroids.PostMessage.dispatchMessageEvent('#{escapedJSONMessage}', '*');"
+          successCallbacks: []
+          failureCallbacks: []
+          recurringCallbacks: []

   @dispatchMessageEvent: (escapedJSONMessage, targetOrigin) =>
     #wrap in a setTimeout to garantee that runs in the webkit thread.


Remove enableRemoteModule since it's not needed anymore.

--- src/main.coffee
+++ src/main.coffee
@@ -153,7 +153,6 @@
         spellcheck: true
         autohideMenuBar: true
         webPreferences: {
-            enableRemoteModule: true
             nodeIntegration: true
             contextIsolation: false
             # preload: path.join(app.getAppPath(), 'ui', 'app.js')


Delete suffix before prefix

Delete suffix before prefix

This allows the cursor buffer position to only be
obtained once from the editor.

--- src/packages/autocomplete/src/autocomplete.coffee
+++ src/packages/autocomplete/src/autocomplete.coffee
@@ -135,8 +135,9 @@
     buffer = @editor.getBuffer()
     @editor.activeEditSession.transact =>
       selection.deleteSelectedText()
-      buffer.delete(Range.fromPointWithDelta(@editor.getCursorBufferPosition(), 0, -match.prefix.length))
-      buffer.delete(Range.fromPointWithDelta(@editor.getCursorBufferPosition(), 0, match.suffix.length))
+      cursorPosition = @editor.getCursorBufferPosition()
+      buffer.delete(Range.fromPointWithDelta(cursorPosition, 0, match.suffix.length))
+      buffer.delete(Range.fromPointWithDelta(cursorPosition, 0, -match.prefix.length))
       @editor.insertText(match.word)
     @undoCount++


add missing error handler

add missing error handler

--- app/coffee/DocManager.coffee
+++ app/coffee/DocManager.coffee
@@ -33,6 +33,8 @@

 	getAllNonDeletedDocs: (project_id, filter, callback = (error, docs) ->) ->
 		DocArchive.unArchiveAllDocs project_id, (error) ->
+			if error?
+				return callback(error)
 			MongoManager.getProjectsDocs project_id, {include_deleted: false}, filter, (error, docs) ->
 				if err?
 					return callback(error)


Make search results view's model

Make search results view's model

--- src/scripts/modules/search/results/results.coffee
+++ src/scripts/modules/search/results/results.coffee
@@ -10,14 +10,6 @@
   return class SearchResultsView extends BaseView
     template: template

-    initialize: (options = {}) ->
-      super()
-
-      if not options.results
-        throw new Error('A search results view must be instantiated with search results')
-
-      @results = options.results
-
     regions:
       header: '.header'
       filter: '.filter'
@@ -25,7 +17,7 @@
       list: '.list'

     onRender: () ->
-      @regions.header.show(new SearchHeaderView({model: @results}))
-      @regions.filter.show(new SearchResultsFilterView({model: @results}))
-      @regions.breadcrumbs.show(new SearchResultsBreadcrumbsView({model: @results}))
-      @regions.list.show(new SearchResultsListView({model: @results}))
+      @regions.header.show(new SearchHeaderView({model: @model}))
+      @regions.filter.show(new SearchResultsFilterView({model: @model}))
+      @regions.breadcrumbs.show(new SearchResultsBreadcrumbsView({model: @model}))
+      @regions.list.show(new SearchResultsListView({model: @model}))


fixing viewing options

fixing viewing options

--- src/poll.coffee
+++ src/poll.coffee
@@ -92,8 +92,7 @@
 		options = @robot.brain.data.poll.options
 		@robot.logger.info "#{options}"
 		optionString = ""
-		for option in options
-			index = options.indexOf(option)
+		for index, option of options
 			text = option.text
 			numVotes = if option.users == undefined then 0 else option.users.length
 			users = option.users


Block: gruntfile, fixes.

Block: gruntfile, fixes.

--- src/block/index.coffee
+++ src/block/index.coffee
@@ -1,9 +1,9 @@
 # Installs block.
-# Also adds it to index stylesheet.
+# Also updates Gruntfile and index stylesheet.

 'use strict'

-
+fs = require 'fs'
 grunt = require 'grunt'
 base = require '../base'
 Gruntfile = require '../lib/gruntfile'
@@ -42,15 +42,35 @@

 		done()

+Generator::init = ->
+	@blockBase = "tamia/blocks/#{@block}"
+
+Generator::gruntfile = ->
+	return  unless (fs.existsSync "#{@blockBase}/script.js")
+
+	filename = 'Gruntfile.coffee'
+	return  unless (fs.existsSync filename)
+
+	gf = grunt.file.read filename
+	importStr = "'tamia/blocks/#{@block}/script.js'"
+	return  unless (gf.indexOf importStr) is -1
+
+	gf = gf.replace /(\n\t*)('tamia\/tamia\/tamia.js',?)/, '$1$2$1' + importStr
+	grunt.file.write filename, gf
+
+	console.log "File \"#{filename}\" updated."
+
 Generator::styles = ->
+	return  unless (fs.existsSync "#{@blockBase}/index.styl")
+
 	filename = 'styles/index.styl'
+	return  unless (fs.existsSync filename)
+
 	stylus = grunt.file.read filename
-	return  unless stylus
-
 	importStr = "@import \"blocks/#{@block}\";"
-	return  unless stylus.indexOf importStr is -1
+	return  unless (stylus.indexOf importStr) is -1

 	stylus = stylus.replace /(@import ['"]tamia['"];?)/, '$1\n' + importStr
 	grunt.file.write filename, stylus

-	console.log 'File "styles/index.styl" updated.'
+	console.log "File \"#{filename}\" updated."


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -130,16 +130,24 @@
   hsl.toString()
   # => 'rgba(0, 255, 255, 1)'

-  skyBlue = Color('Sky Blue')
-
-  skyBlue.toHex()
-  # => '#75bbfd'
-
+  anotherColor = Color('blue')
+
+  Color(anotherColor)
+  # => a new color with the same r, g, b, and alpha values as `anotherColor`
+
+  # You have access to all sorts of weird colors.
+  # We give you all the named colors the browser recognizes
+  # and the ones from this survey http://blog.xkcd.com/2010/05/03/color-survey-results/
+  namedBrown = Color('Fuzzy Wuzzy Brown')
+
+  namedBrown.toHex()
+  # => '#c45655'
+
+  # Default behavior
   transparent = Color()

   transparent.toString()
   # => 'rgba(0, 0, 0, 0)'
-
   </pre></code>

   @name Color


root: fix load race condition

root: fix load race condition

--- src/root.coffee
+++ src/root.coffee
@@ -26,15 +26,21 @@
 #################
 # ROUTING SETUP #
 #################
-z.router.init
-  $$root: document.getElementById 'zorium-root'

-$app = new App()
-z.router.use (req, res) ->
-  res.send z $app, {req, res}
-z.router.go()
+init = ->
+  z.router.init
+    $$root: document.getElementById 'zorium-root'

-log.info 'App Ready'
+  $app = new App()
+  z.router.use (req, res) ->
+    res.send z $app, {req, res}
+  z.router.go()
+
+if document.readyState isnt 'complete' and
+    not document.getElementById 'zorium-root'
+  window.addEventListener 'load', init
+else
+  init()

 #############################
 # ENABLE WEBPACK HOT RELOAD #


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -226,7 +226,7 @@
       hexFromNumber = (number) ->
         return padString(number.toString(16))

-      if !leadingHash
+      if leadingHash == false
         "#{hexFromNumber(@r)}#{hexFromNumber(@g)}#{hexFromNumber(@b)}"
       else
         "##{hexFromNumber(@r)}#{hexFromNumber(@g)}#{hexFromNumber(@b)}"


Remove log statment.

Remove log statment.

--- layouts/default.coffee
+++ layouts/default.coffee
@@ -19,7 +19,6 @@
             ]
             # Append view-specific scripts, if any are included in the view.
             @allScripts.push @scripts if @scripts?
-            console.log @allScripts
             # Add all of the scripts to the head.
             for s in @allScripts
                 # Google maps API uses its own format, i.e.:


tests for changing layer origin and preserving 3D

--- test/tests/LayerTest.coffee
+++ test/tests/LayerTest.coffee
@@ -73,56 +73,61 @@
 			layer.width.should.equal 200
 			layer.style.width.should.equal "200px"

-		# it "should set x and y", ->
-
-		# 	layer = new Layer
-
-		# 	layer.x = 100
-		# 	layer.x.should.equal 100
-		# 	layer.y = 50
-		# 	layer.y.should.equal 50
-
-		# 	# layer.style.webkitTransform.should.equal "matrix(1, 0, 0, 1, 100, 0)"
-		# 	layer.style.webkitTransform.should.equal "translate3d(100px, 50px, 0px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
-
-		# it "should set scale", ->
-
-		# 	layer = new Layer
-
-		# 	layer.scaleX = 100
-		# 	layer.scaleY = 100
-		# 	layer.scaleZ = 100
-
-		# 	# layer.style.webkitTransform.should.equal "matrix(1, 0, 0, 1, 100, 50)"
-		# 	layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 0px) scale(1) scale3d(100, 100, 100) skew(0deg, 0deg) skewX(0deg) skewY(0deg) rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
-
-		# it "should set origin", ->
-
-		# 	layer = new Layer
-
-		# 	layer.style.webkitTransformOrigin.should.equal "50% 50% 0px"
-		# 	layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 0px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
-
-		# 	layer.originX = 0.1
-		# 	layer.originY = 0.2
-		# 	layer.originZ = 80
-
-		# 	layer.style.webkitTransformOrigin.should.equal "10% 20% 80px"
-		# 	layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 80px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
-
-		# 	layer.originX = 0.5
-		# 	layer.originY = 0.5
-		# 	layer.originZ = -50
-
-		# 	layer.style.webkitTransformOrigin.should.equal "50% 50% -50px"
-		# 	layer.style.webkitTransform.should.equal "translate3d(0px, 0px, -50px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) rotateX(0deg) rotateY(0deg) rotateZ(0deg)"
-
-		# 	it "should set transform-style when superlayer has perspective", ->
-		# 		superLayer = new Layer
-		# 			perspective: 100
-		# 		layer = new Layer
-		# 			superLayer: superLayer
-		# 		layer._element.style.webkitTransformStyle.should.equal "preserve-3d"
+		it "should set x and y", ->
+
+			layer = new Layer
+
+			layer.x = 100
+			layer.x.should.equal 100
+			layer.y = 50
+			layer.y.should.equal 50
+
+			# layer.style.webkitTransform.should.equal "matrix(1, 0, 0, 1, 100, 0)"
+			layer.style.webkitTransform.should.equal "translate3d(100px, 50px, 0px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg) translateZ(0px)"
+
+		it "should set scale", ->
+
+			layer = new Layer
+
+			layer.scaleX = 100
+			layer.scaleY = 100
+			layer.scaleZ = 100
+
+			# layer.style.webkitTransform.should.equal "matrix(1, 0, 0, 1, 100, 50)"
+			layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 0px) scale(1) scale3d(100, 100, 100) skew(0deg, 0deg) skewX(0deg) skewY(0deg) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg) translateZ(0px)"
+
+		it "should set origin", ->
+
+			layer = new Layer
+				originZ: 80
+
+			layer.style.webkitTransformOrigin.should.equal "50% 50%"
+
+			layer.originX = 0.1
+			layer.originY = 0.2
+
+			layer.style.webkitTransformOrigin.should.equal "10% 20%"
+			layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 0px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) translateZ(80px) rotateX(0deg) rotateY(0deg) rotateZ(0deg) translateZ(-80px)"
+
+			layer.originX = 0.5
+			layer.originY = 0.5
+
+			layer.style.webkitTransformOrigin.should.equal "50% 50%"
+			layer.style.webkitTransform.should.equal "translate3d(0px, 0px, 0px) scale(1) scale3d(1, 1, 1) skew(0deg, 0deg) skewX(0deg) skewY(0deg) translateZ(80px) rotateX(0deg) rotateY(0deg) rotateZ(0deg) translateZ(-80px)"
+
+		it "should preserve 3D by default", ->
+
+			layer = new Layer
+
+			layer._element.style.webkitTransformStyle.should.equal "preserve-3d"
+
+		it "should flatten layer", ->
+
+			layer = new Layer
+				flat: true
+
+			layer._element.style.webkitTransformStyle.should.equal "flat"
+

 		it "should set local image", ->


Delete in any direction from the current position

--- src/trix/controller.coffee
+++ src/trix/controller.coffee
@@ -28,16 +28,20 @@

     @setPosition(position + (if updatePosition then string.length else 0))

+  deleteFromCurrentPosition: (distance = -1) ->
+    unless range = @getSelectedRange()
+      position = @getPosition()
+      offset = position + distance
+      range = if distance < 0 then [offset, position] else [position, offset]
+
+    @text.removeTextAtRange(range)
+    @setPosition(range[0])
+
   deleteBackward: ->
-    if selectedRange = @getSelectedRange()
-      position = selectedRange[0]
-      @text.removeTextAtRange(selectedRange)
-      @setPosition(position)
-    else
-      position = @getPosition()
-      if position > 0
-        @text.removeTextAtRange([position - 1, position])
-        @setPosition(position - 1)
+    @deleteFromCurrentPosition(-1)
+
+  deleteForward: ->
+    @deleteFromCurrentPosition(1)

   deleteWordBackward: ->
     if @getSelectedRange()
@@ -46,17 +50,7 @@
       position = @getPosition()
       stringBeforePosition = @text.getStringAtRange([0, position])
       positionBeforeLastWord = stringBeforePosition.search(/(\b\w+)\W*$/)
-
-      @text.removeTextAtRange([positionBeforeLastWord, position])
-      @setPosition(positionBeforeLastWord)
-
-  deleteForward: ->
-    if @getSelectedRange()
-      @deleteBackward()
-    else
-      position = @getPosition()
-      @text.removeTextAtRange([position, position + 1])
-      @setPosition(position)
+      @deleteFromCurrentPosition(positionBeforeLastWord - position)

   render: ->
     @dom.render(@text)


Added 1/64 notes to Tempo.

Added 1/64 notes to Tempo.

--- src/time.coffee
+++ src/time.coffee
@@ -27,6 +27,7 @@

         @reset()

+    # when changing the tempo (bpm, signature) or resolution - reset needs to be called
     reset: ->
         # beats per millisecond
         @beatInterval = 1000 / (@bpm / 60)
@@ -45,11 +46,10 @@

         # booleans wether the current timestep is on that particular note
         @onBeat = @onBar = false
-        @on32 = @on16 = @on8 = @on4 = @on2 = false
+        @on64 = @on32 = @on16 = @on8 = @on4 = @on2 = false

-
-    # call update continously
+    # call update continously with time since last timestep
     update: (dt) ->
         @time += dt

@@ -67,6 +67,7 @@
             @onBeat = u % (r / @sigNum) == 0
             @onBar = u %

+            @on64 = u % (r / 64) == 0
             @on32 = u % (r / 32) == 0
             @on16 = u % (r / 16) == 0
             @on8 = u % (r / 8) == 0
@@ -77,7 +78,7 @@

         else
             @onBeat = @onBar = false
-            @on32 = @on16 = @on8 = @on4 = @on2 = false
+            @on64 = @on32 = @on16 = @on8 = @on4 = @on2 = false

         @beat


Expose tool superclasses

Expose tool superclasses

--- src/index.coffee
+++ src/index.coffee
@@ -12,6 +12,7 @@
 {defineOptionsStyle} = require './optionsStyles/optionsStyles'

+baseTools = require './tools/base'
 tools =
   Pencil: require './tools/Pencil'
   Eraser: require './tools/Eraser'
@@ -20,6 +21,9 @@
   Text: require './tools/Text'
   Pan: require './tools/Pan'
   Eyedropper: require './tools/Eyedropper'
+
+  Tool: baseTools.Tool
+  ToolWithStroke: baseTools.ToolWithStroke

 init = (el, opts = {}) ->


Added at shutdown password deletion and added get_setting/get_all_settings

--- src/index.coffee
+++ src/index.coffee
@@ -26,6 +26,15 @@
 re_clipboard = require('sdk/clipboard')

 set_interval = require("sdk/timers").setInterval
+
+#
+# Handler for disable/shutdown
+#
+
+exports.onUnload = (reason) ->
+  if reason in ['disable', 'shutdown']
+    if not Storage.get_setting 'save'
+      Storage.set_setting 'password', ''

 #
 #
@@ -77,7 +86,7 @@
   # passes resulting string to return function
   get_pass: (uname, url, return_func) ->
     s = re_storage.storage.settings
-    pass = Storage.get_settings 'password'
+    pass = Storage.get_setting 'password'

     content = s.content
     content = content.replace(/\[uname\]/g, uname)
@@ -161,8 +170,8 @@
   handle_boot: () ->
     if not Storage._s.settings
       Storage._s.settings =
-        'hidden': false
-        'save': false
+        'hidden': true
+        'save': true
         'mode': 'sha1'
         'length': '12'
         'content': '[site.url][uname][pass]'
@@ -195,8 +204,11 @@
       return
     Storage._s.settings[key] = value

-  get_settings: () ->
+  get_all_settings: () ->
     Storage._s.settings
+
+  get_setting: (key) ->
+    return Storage._s.settings[key]

   store_disabled_sites: () ->
     Storage._s.ds_list = Storage._s.disabled_sites.get_list()
@@ -207,7 +219,7 @@
     delete Storage._s.disabled_sites
     Storage.handle_boot()

-    panel.port.emit 'fill-settings', Storage.get_settings()
+    panel.port.emit 'fill-settings', Storage.get_all_settings()

 #
 #
@@ -340,10 +352,10 @@

 # Store disabled_sites list every so often
-set_interval () -> Storage.store_disabled_sites(), 1000
+set_interval (() -> Storage.store_disabled_sites()), 1000

 # Init Storage
 Storage.handle_boot()

 # Inform panel to initialize itself!
-panel.port.emit 'show-first', Storage.get_settings()
+panel.port.emit 'show-first', Storage.get_all_settings()


Remove specific CSS classes for slides and slide-pack

--- src/index.coffee
+++ src/index.coffee
@@ -11,13 +11,13 @@

 $('[data-slide-pack]').each ->
-  slides = processor.process $(@).html()
+  $slidePack = $(@)
+  slides = processor.process $slidePack.html()

-  $article = $('

').addClass 'slide-pack'
+  $article = $('

')
   for slide in slides
     $slide = $('

')
       .addClass(slide.cssClass)
-      .addClass('slide')

     $slide.html(slide.html)

@@ -27,7 +27,7 @@

   executeHooks()

-ui.init slidePack : $('.slide-pack')
+ui.init slidePack : $('article')

 # keyboard navigation
 mousetrap.bind ['left', 'up', 'k', 'h'], ui.prev


stupid port variable

stupid port variable

--- src/index.coffee
+++ src/index.coffee
@@ -114,7 +114,7 @@

   # listen for requests
-  PORT = process.argv.port or 8000
+  PORT = process.env.PORT or 8000
   http.listen PORT, ->
     console.log chalk.blue "-> :#{PORT}"


Quick fix for passing functions as module opts

--- src/index.coffee
+++ src/index.coffee
@@ -95,12 +95,17 @@
     for name in options.components or []
         app.component require name

-    for moduleName, moduleInfo of app.modules
+    for moduleInfo in options.modules
+        if _.isString moduleInfo
+            moduleInfo = name: moduleInfo
+        moduleName = moduleInfo.name
+        _.defaults moduleInfo, app.modules[moduleName]
+
         require moduleName if moduleInfo.index

         if moduleInfo.opts
             opts = require moduleName + '/opts'
-            _.extend opts, moduleInfo
+            _.assign opts, moduleInfo

         for name in moduleInfo.components
             compPath = path.join moduleInfo.path, 'components', name


correct nodefirm url typo

correct nodefirm url typo

--- models/sponsor.coffee
+++ models/sponsor.coffee
@@ -39,7 +39,7 @@
   name:  'The Node Firm'
   image: 'logos/sm/nodefirm.png'
   type: ["platinum"]
-  url:   'http://www.nodefirm.com/'
+  url:   'http://www.thenodefirm.com/'
   description:
     '''
     The Node Firm provides the absolute best technical and business insights into using Node.js effectively. We want to be sure that you have people you can trust when you need to learn Node.js.


Use WritableTrackingBuffer to simplify the creation of AllHeaders.

--- lib/all-headers.coffee
+++ lib/all-headers.coffee
@@ -1,6 +1,8 @@
 # s2.2.5.3

 # For now, only the "Transaction Descriptor" header (s2.2.5.3.2) is supported.
+
+WritableTrackingBuffer = require('../lib/tracking-buffer/tracking-buffer').WritableTrackingBuffer

 TYPE =
   QUERY_NOTIFICATIONS: 1
@@ -11,27 +13,18 @@
 TXNDESCRIPTOR_HEADER_LEN = 4 + 2 + TXNDESCRIPTOR_HEADER_DATA_LEN

 module.exports = (txnDescriptor, outstandingRequestCount) ->
-
-  buffer = new Buffer(4 + (4 + 2 + TXNDESCRIPTOR_HEADER_DATA_LEN))
-
-  position = 0
+  buffer = new WritableTrackingBuffer(50)

-  buffer.writeUInt32LE(buffer.length, position)
-  position += 4
-
-  buffer.writeUInt32LE(TXNDESCRIPTOR_HEADER_LEN, position)
-  position += 4
-
-  buffer.writeUInt16LE(TYPE.TXN_DESCRIPTOR, position)
-  position += 2
-
-  buffer.writeUInt32LE(txnDescriptor % 0x100000000, position)
-  position += 4
-
-  buffer.writeUInt32LE(txnDescriptor / 0x100000000, position)
-  position += 4
-
-  buffer.writeUInt32LE(outstandingRequestCount, position)
-  position += 4
-
-  buffer+  buffer.writeUInt32LE(0)                             # Will write buffer length in here later.
+  buffer.writeUInt32LE(TXNDESCRIPTOR_HEADER_LEN)
+  buffer.writeUInt16LE(TYPE.TXN_DESCRIPTOR)
+  buffer.writeUInt32LE(txnDescriptor % 0x100000000)
+  buffer.writeUInt32LE(txnDescriptor / 0x100000000)
+  buffer.writeUInt32LE(outstandingRequestCount)
+
+  data = buffer.data
+
+  # Write deferred buffer length.
+  data.writeUInt32LE(data.length, 0)
+
+  data


Points to the correct URL

Points to the correct URL

--- lib/bookmarklet.coffee
+++ lib/bookmarklet.coffee
@@ -1 +1 @@
-module.exports = "javascript:(function(){var s=document.createElement('script');s.setAttribute('type','text/javascript');s.setAttribute('charset','UTF-8');s.setAttribute('src','https://marklet.are.na/loader.js');document.documentElement.appendChild(s);})()"
+module.exports = "javascript:(function(){var s=document.createElement('script');s.setAttribute('type','text/javascript');s.setAttribute('charset','UTF-8');s.setAttribute('src','https://www.are.na/loader.js');document.documentElement.appendChild(s);})()"


Document Type's public API a little bit.

--- src/type.coffee
+++ src/type.coffee
@@ -1,4 +1,4 @@
-{ArgumentError, NotImplementedError} = require './errors'
+{ArgumentError, NotImplementedError, TypeError} = require './errors'

 #
 # 'Abstract' class for Finitio types
@@ -12,12 +12,18 @@
     @name ?= @defaultName()

   #
+  # Returns true if `value` is valid member of this type, false otherwise.
+  #
+  include: (value)->
+    throw new NotImplementedError(this, "include")
+
+  #
   # Dress `value` with this information type and returns the result.
   #
   # @return the dressing result
   # @pre    true
   # @post   this.include(output)
-  # @throws `Finitio.Error` if the dressing fails
+  # @throws `TypeError` if the dressing fails
   #
   dress: (value)->
     throw new NotImplementedError(this, "dress")
@@ -29,13 +35,22 @@
   # @return the undressed result
   # @pre    this.include(value)
   # @post   as.include(output)
+  # @throw  `TypeError` if undressing fails
   #
   undress: (value, as)->
-    throw new NotImplementedError(this, "undress")
+    return value if this.equals(as)
+    throw new TypeError("Unable to undress `#{value}` to `#{as}`")

+  #
+  # Returns a String representation of this Type.
+  #
   toString: ->
     @name.toString()

+  #
+  # Returns true if `other` is structurally equivalent to this type, false
+  # otherwise.
+  #
   equal: (other)->
     this is other


Added option for the computer to play ttt alone

- just type 'alone' for that
- this option is not advertised yet in the interface

--- src/games/play-tic-tac-toe.coffee
+++ src/games/play-tic-tac-toe.coffee
@@ -48,7 +48,7 @@
     log ''
     finish() if game.isTerminal()
     write "#{chalk.blue.bold decode game.nextPlayer} plays. "
-    log "Enter a position like #{chalk.blue.bold 'A1'}; or #{chalk.blue.bold '<ENTER>'} for me to play. #{chalk.blue.bold 'q'} quits."
+    log "Enter a position like #{chalk.blue.bold 'A1'}, or #{chalk.blue.bold '<ENTER>'} for me to play. #{chalk.blue.bold 'q'} quits."
   write '> '

 humanPlays = (i) ->
@@ -56,12 +56,16 @@
   game = game.play action
   Game.position = i

-computerPlays = ->
+computerPlays = (alone = false) ->
   console.time 'time'
   [action, nextGame] = playTurn agent, game
   console.timeEnd 'time'
   Game.position = game.positionForAction action
   game = nextGame
+  if alone
+    log game.toString()
+    finish() if game.isTerminal()
+    computerPlays yes

 input = (text) ->
   action = game.parseAction text
@@ -69,6 +73,8 @@
     humanPlays action
   else if text in ['bye', 'exit', 'quit', 'q']
     finish()
+  else if text in ['alone']
+    computerPlays yes
   else if text
     log chalk.red.bold 'Bad play: ' + text
   else


Project::getRepo -> Project::getRepositories

--- lib/github-file.coffee
+++ lib/github-file.coffee
@@ -11,7 +11,7 @@

   # Internal
   constructor: (@filePath) ->
-    @repo = atom.project.getRepo()
+    @repo = atom.project.getRepositories()[0]

   # Public
   open: (lineRange) ->


Refactor out the event handlers on marker view

--- lib/marker-view.coffee
+++ lib/marker-view.coffee
@@ -14,21 +14,29 @@

     @isMarkerValid = @marker.isValid()
     @updateDisplayPosition = @isMarkerValid
-    @marker.on 'changed', ({newHeadScreenPosition, newTailScreenPosition, valid}) =>
-      @updateDisplayPosition = valid
-      if valid != @isMarkerValid
-        # @isMarkerValid is an optimization so we dont call into show or hide unless necessary
-        if valid then @show() else @hide()
-        @isMarkerValid = valid

-    @marker.on 'destroyed', => @remove()
+    @subscribe @marker, 'changed', @onMarkerChanged
+    @subscribe @marker, 'destroyed', => @remove()
+    @subscribe @editor, 'editor:display-updated', @onEditorDisplayUpdated

-    @subscribe @editor, 'editor:display-updated', (eventProperties) =>
-      [first, last] = [@editor.firstRenderedScreenRow, @editor.lastRenderedScreenRow]
-      range = @getScreenRange()
-      if @updateDisplayPosition and (range.start.row >= first or range.end.row <= last)
-        @updateDisplay()
-        @updateDisplayPosition = false
+  remove: ->
+    @marker = null
+    @editor = null
+    super()
+
+  onMarkerChanged: ({valid}) =>
+    @updateDisplayPosition = valid
+    if valid != @isMarkerValid
+      # @isMarkerValid is an optimization so we dont call into show or hide unless necessary
+      if valid then @show() else @hide()
+      @isMarkerValid = valid
+
+  onEditorDisplayUpdated: (eventProperties) =>
+    [first, last] = [@editor.firstRenderedScreenRow, @editor.lastRenderedScreenRow]
+    range = @getScreenRange()
+    if @updateDisplayPosition and (range.start.row >= first or range.end.row <= last)
+      @updateDisplay()
+      @updateDisplayPosition = false

   updateDisplay: ->
     @clearRegions()


Use a fat arrow on remove()

Use a fat arrow on remove()

--- lib/marker-view.coffee
+++ lib/marker-view.coffee
@@ -16,10 +16,10 @@
     @updateDisplayPosition = @isMarkerValid

     @subscribe @marker, 'changed', @onMarkerChanged
-    @subscribe @marker, 'destroyed', => @remove()
+    @subscribe @marker, 'destroyed', @remove
     @subscribe @editor, 'editor:display-updated', @onEditorDisplayUpdated

-  remove: ->
+  remove: =>
     @marker = null
     @editor = null
     super()


when has same syntax and logic as given

when has same syntax and logic as given

--- lib/mocha-given.coffee
+++ lib/mocha-given.coffee
@@ -64,12 +64,12 @@
 	label = o(specArgs).firstThat (arg) -> o(arg).isString()
 	fn    = o(specArgs).firstThat (arg) -> o(arg).isFunction()
 	itFunc "then #{label ? stringifyExpectation(fn)}", (done) ->
-		i.call @ for i in whenList if whenList.length
+		i.apply @ for i in whenList if whenList.length
 		try
 			if o(fn).hasArguments()
 				expect(fn.apply(@, Array.prototype.slice.call(arguments))).to.be.ok()
 			else
-				expect(fn.call(@)).to.be.ok()
+				expect(fn.apply(@)).to.be.ok()
 				done()
 		catch exception
 			msg = exception.message
@@ -80,6 +80,7 @@
 	suites = [suite]

 	suite.on 'pre-require', (context, file, mocha) ->
+

 		# reset context for watched tests
 		suite.ctx = new Context
@@ -156,18 +157,23 @@
 			delete @currentTest.ctx[i] for i of @currentTest.ctx when i not in @currentTest.ctxKeys

 		Given = ->
-			args = Array.prototype.slice.call arguments
-			if args.length == 1
-				context.beforeEach.apply @, args
+			assignTo = o(arguments).firstThat (arg) -> o(arg).isString()
+			fn = o(arguments).firstThat (arg) -> o(arg).isFunction()
+			if assignTo
+				context.beforeEach -> @[assignTo] = fn.apply @
 			else
-				assignTo = o(args).firstThat (arg) -> o(arg).isString()
-				fn = o(args).firstThat (arg) -> o(arg).isFunction()
-				context.beforeEach ->
-					@[assignTo] = fn.call @
-
-		When = (fn) ->
-			context.beforeEach -> whenList.push(fn)
-			context.afterEach  -> whenList.pop()
+				context.beforeEach.apply @, Array.prototype.slice.call arguments
+
+		When = ->
+			assignTo = o(arguments).firstThat (arg) -> o(arg).isString()
+			fn = o(arguments).firstThat (arg) -> o(arg).isFunction()
+			if assignTo
+				context.beforeEach -> whenList.push(-> @[assignTo] = fn.apply @)
+			else
+				context.beforeEach -> whenList.push(fn)
+
+			context.afterEach ->
+				whenList.pop()

 		Then = ->
 			declareSpec arguments, context.it


Fix calling dismiss on null

Fix calling dismiss on null

--- lib/robe-runner.coffee
+++ lib/robe-runner.coffee
@@ -36,7 +36,7 @@
             continue unless match?
             port = match[1]
             @started = true
-            @lastNotification.dismiss()
+            @lastNotification?.dismiss()
             clearTimeout(timerId)
             resolve(port)
             break


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -178,7 +178,7 @@
       else
         self.bind(eventName, eval( "(function() {#{event}})" ))

-  self.
+  self

 ###*
 Construct an object instance from the given entity data.


Remove ".el" from recognised filetypes

Remove ".el" from recognised filetypes

Common Lisp and Emacs Lisp are two distinct dialects. The latter is best
handled with a dedicated language package.

--- grammars/lisp.cson
+++ grammars/lisp.cson
@@ -13,7 +13,6 @@
   'cl'
   'l'
   'mud'
-  'el'
 ]

 foldingStartMarker: '\\(\\s*$'


Requires helps

Requires helps

--- src/hello-world.coffee
+++ src/hello-world.coffee
@@ -16,6 +16,7 @@

 module.exports = (robot) ->
   robot.hear /beer/, (msg) ->
+    moment = require('moment-timezone');
     five_pm = moment.tz("17:00", "h:mm", "America/New_York")
     midnight = moment.tz("23:59", "h:mm", "America/New_York")
     if moment.tz("America/New_York").isBetween(five_pm, midnight)


Remove hello-world.coffee

Remove hello-world.coffee

--- src/hello-world.coffee
+++ src/hello-world.coffee
@@ -1,6 +0,0 @@
-module.exports = (robot) ->
-  robot.respond /hello/, (msg) ->
-    msg.reply "hello!"
-
-  robot.hear /orly/, ->
-    msg.send "yarly"


fix give action response string escaping

--- lib/text-buffer.coffee
+++ lib/text-buffer.coffee
@@ -209,6 +209,7 @@

     giveAction: (index, content) -> @protectCursor =>
+        content = content.replace(/\\n/g, '')
         log 'Text Buffer', "handling give-action #{content}"
         goal = @findGoal index
         if content


:fire: duplicates line by introducing convention

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -48,10 +48,23 @@
       @vimState.submode is 'linewise'

   select: ->
+    canSelect = true
+    stopSelection = ->
+      canSelect = false
+
     @countTimes =>
-      for selection in @editor.getSelections()
-        @selectTextObject(selection)
+      for selection in @editor.getSelections() when canSelect
+        @selectTextObject(selection, stopSelection)
+    @editor.mergeIntersectingSelections()
     @updateSelectionProperties() if @isMode('visual')
+
+  selectTextObject: (selection, stopSelection) ->
+    range = @getRange(selection, stopSelection)
+    swrap(selection).setBufferRangeSafely(range)
+
+  getRange: ->
+    # I want to
+    # throw new Error('text-object must respond to range by getRange()!')

 # -------------------------
 class Word extends TextObject
@@ -64,9 +77,6 @@
       /[\t ]*/
     else
       @wordRegExp ? getWordRegExpForPointWithCursor(selection.cursor, point)
-
-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely(@getRange(selection))

   getRange: (selection) ->
     pattern = @getPattern(selection)
@@ -278,9 +288,6 @@
       pairInfo = @getPairInfo(pairInfo.aRange.end)
     pairInfo?.targetRange

-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely(@getRange(selection))
-
 # -------------------------
 class AnyPair extends Pair
   @extend(false)
@@ -297,12 +304,9 @@
   getRanges: (selection) ->
     (range for klass in @member when (range = @getRangeBy(klass, selection)))

-  getNearestRange: (selection) ->
+  getRange: (selection) ->
     ranges = @getRanges(selection)
     _.last(sortRanges(ranges)) if ranges.length
-
-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely @getNearestRange(selection)

 class AAnyPair extends AnyPair
   @extend()
@@ -318,7 +322,7 @@
   allowNextLine: false
   skipEmptyPair: false
   searchFrom: 'start'
-  getNearestRange: (selection) ->
+  getRange: (selection) ->
     ranges = @getRanges(selection)
     from = selection.cursor.getBufferPosition()
     [forwardingRanges, enclosingRanges] = _.partition ranges, (range) ->
@@ -346,7 +350,7 @@
   @extend(false)
   allowForwarding: true
   member: ['DoubleQuote', 'SingleQuote', 'BackTick']
-  getNearestRange: (selection) ->
+  getRange: (selection) ->
     ranges = @getRanges(selection)
     # Pick range which end.colum is leftmost(mean, closed first)
     _.first(_.sortBy(ranges, (r) -> r.end.column)) if ranges.length
@@ -640,10 +644,10 @@
 class Comment extends TextObject
   @extend(false)

-  selectTextObject: (selection) ->
+  getRange: (selection) ->
     row = selection.getBufferRange().start.row
     if rowRange = @getRowRangeForCommentAtBufferRow(row)
-      swrap(selection).selectRowRange(rowRange)
+      getBufferRangeForRowRange(selection.editor, rowRange)

   getRowRangeForCommentAtBufferRow: (row) ->
     switch
@@ -686,9 +690,6 @@

     getBufferRangeForRowRange(@editor, rowRange)

-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely(@getRange(selection))
-
 class AFold extends Fold
   @extend()

@@ -727,11 +728,24 @@
 # -------------------------
 class CurrentLine extends TextObject
   @extend(false)
-  selectTextObject: (selection) ->
+  getRange: (selection) ->
     {cursor} = selection
-    cursor.moveToBeginningOfLine()
-    cursor.moveToFirstCharacterOfLine() if @isInner()
-    selection.selectToEndOfBufferLine()
+    if @isA()
+      cursor.getCurrentLineBufferRange()
+    else
+      scanRange = cursor.getCurrentLineBufferRange()
+      pattern = /\S/
+      [start, end] = []
+      @editor.backwardsScanInBufferRange pattern, scanRange, ({range, stop}) ->
+        end = range.end
+        stop()
+
+      @editor.scanInBufferRange pattern, scanRange, ({range, stop}) ->
+        start = range.start
+        stop()
+
+      if start and end
+        new Range(start, end)

 class ACurrentLine extends CurrentLine
   @extend()
@@ -742,8 +756,9 @@
 # -------------------------
 class Entire extends TextObject
   @extend(false)
-  selectTextObject: (selection) ->
-    @editor.selectAll()
+  getRange: (selection, stopSelection) ->
+    stopSelection()
+    @editor.buffer.getRange()

 class AEntire extends Entire
   @extend()
@@ -760,9 +775,6 @@
   @extend(false)
   getRange: ->
     @vimState.mark.getRange('[', ']')
-
-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely(@getRange())

 class ALatestChange extends LatestChange
   @extend()
@@ -850,10 +862,6 @@
     # The reason I need -2 at bottom is because of status bar?
     range.translate([+1, 0], [-3, 0])

-  selectTextObject: (selection) ->
-    range = @getRange(selection)
-    swrap(selection).setBufferRangeSafely(range)
-
 class AVisibleArea extends VisibleArea
   @extend()

@@ -875,10 +883,6 @@
         unionRange = range
     unionRange

-  selectTextObject: (selection) ->
-    range = @getUnionRange(selection)
-    swrap(selection).setBufferRangeSafely(range)
-
 class AFunctionOrInnerParagraph extends UnionTextObject
   @extend()
   member: ['AFunction', 'InnerParagraph']
@@ -895,12 +899,9 @@
   getRanges: (selection) ->
     (range for klass in @member when (range = @getRangeBy(klass, selection)))

-  getNearestRange: (selection) ->
+  getRange: (selection) ->
     ranges = @getRanges(selection)
     _.last(sortRanges(ranges)) if ranges.length
-
-  selectTextObject: (selection) ->
-    swrap(selection).setBufferRangeSafely @getNearestRange(selection)

 class InnerNonEmptySmartWordOrInnerParenthesis extends SomeTextObject
   @extend()


:bug: Fix typos in panel

:bug: Fix typos in panel

--- lib/views/panel.coffee
+++ lib/views/panel.coffee
@@ -16,7 +16,7 @@
     messages.forEach (message)=>
       return unless message.currentFile # A custom property added while creating arrays of them
       return unless message.position
-      return if @type is 'file' and (not message.currentFile)
+      return if @scope is 'file' and (not message.currentFile)
       p = message.position
       range = [[p[0][0] - 1, p[0][1] - 1], [p[1][0] - 1, p[1][1]]]
       marker = @linter.activeEditor.markBufferRange range, {invalidate: 'never'}
@@ -26,6 +26,6 @@
       @decorations.push @linter.activeEditor.decorateMarker(
         marker, type: 'highlight', class: 'highlight-' + message.type.toLowerCase()
       )
-      @appendChild @linter.view.messageLine message, @linter.views.type is 'project'
+      @appendChild @linter.view.messageLine message, @linter.views.scope is 'project'

 module.exports = PanelView = document.registerElement('linter-panel-view', {prototype: PanelView.prototype})


1 to "1"

1 to "1"

Missed to change one 1 to "1"

--- assets/coffee/apps/post/list/list_view.coffee
+++ assets/coffee/apps/post/list/list_view.coffee
@@ -5,7 +5,7 @@
     tagName: "tr"

     attributes: ->
-      if String(@model.get("active")) is 1 and @model.get("publish_date") > moment().format('YYYY-MM-DD HH:mm:ss')
+      if String(@model.get("active")) is "1" and @model.get("publish_date") > moment().format('YYYY-MM-DD HH:mm:ss')
         class: "post-item scheduled post-#{@model.id}"
       else if String(@model.get("active")) is "1"
         class: "post-item published post-#{@model.id}"


Prevent slidechange on key event in input element

--- _includes/coffeescript/main.coffee
+++ _includes/coffeescript/main.coffee
@@ -89,33 +89,33 @@
   resize: (event) =>

   keydown: (event) =>
-    console.log(event.keyCode)
-    switch event.keyCode
-      when 27 # escape
-        @element.toggleClass("overview")
-      when 37 # left
-        curr = @currentChapter()
-        next = @previousChapter()
-        if next?
-          @current = next
-          @arrange()
-      when 39 # right
-        curr = @currentChapter()
-        next = @nextChapter()
-        if next?
-          @current = next
-          @arrange()
-      when 38 # up
-        curr = @currentChapter().currentSlide()
-        next = @currentChapter().previousSlide()
-        if next?
-          @currentChapter().current = next
-          @arrange()
-      when 40 # down
-        curr = @currentChapter().currentSlide()
-        next = @currentChapter().nextSlide()
-        if next?
-          @currentChapter().current = next
-          @arrange()
+    if not $(document.activeElement).is(":input,[contenteditable]")
+      switch event.which
+        when 27 # escape
+          @element.toggleClass("overview")
+        when 37 # left
+          curr = @currentChapter()
+          next = @previousChapter()
+          if next?
+            @current = next
+            @arrange()
+        when 39 # right
+          curr = @currentChapter()
+          next = @nextChapter()
+          if next?
+            @current = next
+            @arrange()
+        when 38 # up
+          curr = @currentChapter().currentSlide()
+          next = @currentChapter().previousSlide()
+          if next?
+            @currentChapter().current = next
+            @arrange()
+        when 40 # down
+          curr = @currentChapter().currentSlide()
+          next = @currentChapter().nextSlide()
+          if next?
+            @currentChapter().current = next
+            @arrange()

 window.Presentation = Presentation


Pass through octal and binary literals as-is

See https://github.com/coffeescript6/discuss/issues/45

--- src/lexer.coffee
+++ src/lexer.coffee
@@ -211,9 +211,8 @@
       when 'o' then 8
       when 'x' then 16
       else null
+
     numberValue = if base? then parseInt(number[2..], base) else parseFloat(number)
-    if number.charAt(1) in ['b', 'o']
-      number = "0x#{numberValue.toString 16}"

     tag = if numberValue is Infinity then 'INFINITY' else 'NUMBER'
     @token tag, number, 0, lexedLength


coco 8a8cc53: meta-heregex

coco 8a8cc53: meta-heregex


Bug fix on sub tag

Bug fix on sub tag

--- app/assets/javascripts/backoffice/views/election/show_view.js.coffee
+++ app/assets/javascripts/backoffice/views/election/show_view.js.coffee
@@ -76,6 +76,31 @@
     @election.tags.each @addMainTag if @candidacy
     @updateTag() if @tag
     @updateTagsButtonsVisibility()
+
+    form = $('form.add-tag', @el)
+
+    # autocomplete
+    $('.tag-name', form).autocomplete
+      source: (request, response) ->
+        tags = new TagsCollection()
+        tags.bind 'reset', ->
+          exactTag = (@find (t) -> t.get('name') == request.term)
+          if exactTag
+            $('.tag-id').val(exactTag.id)
+          else
+            $('.tag-id').val('')
+          response @map (tag) ->
+            {label: tag.get('name'), value: tag.id}
+        tags.search request.term
+      select: (event, ui) ->
+        $('.tag-name').val ui.item.label
+        $('.tag-id').val(ui.item.value)
+        return false
+      focus: (event, ui) ->
+        $('.tag-name').val ui.item.label
+        return false
+
+    @

   renderPropositions: =>
     @addPropositionsList()
@@ -146,6 +171,10 @@
             @election.addTag tag
         @
       tag.fetch()
+      @addSubTag tag
+      $('#modal-tags').modal('hide')
+      @initMoveTags()
+      $('.tag-name', form).val("")
     else # create
       tagName = tag_id = $('.tag-name', form).val()
       tag = new TagModel()


Updated Build Locator to support branch dimension

Branch dimension has been supported via TeamCity API since version 7.1: https://confluence.jetbrains.com/display/TW/REST+API#RESTAPI-BuildLocator

--- src/locators/build-locator.coffee
+++ src/locators/build-locator.coffee
@@ -10,7 +10,8 @@
     'personal'
     'canceled'
     'running'
-    'pinned'
+    'pinned',
+    'branch'
   ]

 module.exports = BuildLocator


bloques plegables

bloques plegables

--- app/assets/javascripts/comunes/layout.js.coffee
+++ app/assets/javascripts/comunes/layout.js.coffee
@@ -1,2 +1,6 @@
-$ ->
+jQuery ->
   $('.fecha').datepicker();
+  $('.plegable legend').click( ->
+    $(this).nextAll().toggle('slow');
+    return false;
+  )


removing call to non-existent header_fix

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -132,8 +132,6 @@
             )

         if gon.page is 'products_show'
-            header_fix()
-
             if gon.authenticated and gon.instagram_protocol_with_params?
                 window.location = gon.instagram_protocol_with_params


Added cache lookup to /products/:permalink route

--- app/assets/javascripts/sprangular/routes.coffee
+++ app/assets/javascripts/sprangular/routes.coffee
@@ -28,8 +28,10 @@
       controller: 'ProductCtrl'
       templateUrl: 'products/show.html'
       resolve:
-        product: (Catalog, $route) ->
-          Catalog.find($route.current.params.id)
+        product: (Status, Catalog, $route) ->
+          slug = $route.current.params.id
+
+          Status.findCachedProduct(slug) || Catalog.find(slug)

     .when '/t/:path*',
       controller: 'ProductListCtrl'


fix: Origination and destination can be changed

--- app/assets/javascripts/widgets/direction.coffee
+++ app/assets/javascripts/widgets/direction.coffee
@@ -349,7 +349,7 @@
 drawRoute = (route, callback) ->

 searchRoute = (search_params, callback) ->
-  return callback(FOUND_ROUTE) if FOUND_ROUTE
+  return callback(FOUND_ROUTE) if FOUND_ROUTE?

   request =
     origin: search_params.start
@@ -376,10 +376,8 @@
   window.parent.postMessage(JSON.stringify(
     event: "on_params_changed", params: search_params
   ), "*")
-

   searchRoute search_params, (route) ->
-    console.log(gmap.getLatLngBounds().toString())
     search_params.bounding_box = gmap.getLatLngBounds().toString()
     $.ajax
       url: Routes.api_v1_relics_path(search_params)
@@ -392,10 +390,9 @@
   false

 jQuery ->
-
   $('a.tooltip').tooltip()
   $('#new_search').submit(searchRelics)
-
+  $('#search_begin, #search_end').change(-> FOUND_ROUTE = null)
   window.ensuring_google_maps_loaded ->
     do extend_google_maps
     do construct_relic_marker


Executing ext:dev when config.coffee changes

--- gulp/tasks/watch.coffee
+++ gulp/tasks/watch.coffee
@@ -21,7 +21,7 @@
   gulp.watch 'requirements.txt', ['pip']
   gulp.watch 'package.json', ['npm']
   gulp.watch 'bower.json', ['ext_watch_rebuild']
-  gulp.watch 'gulp/config.coffee', ['style:dev', 'script:dev']
+  gulp.watch 'gulp/config.coffee', ['ext:dev', 'style:dev', 'script:dev']
   gulp.watch paths.static.ext, ['ext:dev']
   gulp.watch "#{paths.src.script}/**/*.coffee", ['script:dev']
   gulp.watch "#{paths.src.style}/**/*.less", ['style:dev']


hotfix: game poster upload

hotfix: game poster upload

--- app/assets/components/game-wizard-service-step-4/game-wizard-service-step-4.js.coffee
+++ app/assets/components/game-wizard-service-step-4/game-wizard-service-step-4.js.coffee
@@ -60,6 +60,7 @@
       validFiles = event.detail.valid
       if validFiles.length
         reader = new FileReader()
+        that.fileData = validFiles[0]
         reader.onload = (e)->
           previewArea = document.querySelector('#poster-preview')
           previewArea.innerHTML = ''