subject specific talk link

subject specific talk link

feed classify summary an object

--- classify/summary.coffee
+++ classify/summary.coffee
@@ -6,9 +6,15 @@

   addSummary: (kelpNum, subject) ->
     [lat, long] = subject.coords
-    image = subject.location.standard

-    @summary(kelpNum, image, lat, long)
+    summaryData =
+      kelpNum: kelpNum
+      lat: lat
+      long: long
+      image: subject.location.standard
+      talkLink: subject.talkHref()
+
+    @summary(summaryData)
       .fadeIn(300).appendTo(".readymade-subject-viewer-container")

   userSetAGoal: ->
@@ -16,7 +22,7 @@

   sCheck: (int) -> if +int is 1 then '' else 's'

-  summary: (kelpNum, image, lat, long) ->
+  summary: ({kelpNum, image, lat, long, talkLink}) ->
     $ "

#{translate 'classifyPage.summary.header'}

@@ -25,7 +31,7 @@

#{translate 'classifyPage.summary.locatedNear'}

#{@roundTo(3, lat)} N
#{@roundTo(3, long)} W

           #{if @userSetAGoal() then @goalText() else ''}
-           #{translate 'classifyPage.summary.talk'}
+           #{translate 'classifyPage.summary.talk'}

"


Add development configuration requirement commands

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

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -83,6 +83,10 @@
   KONFIG.workers = require('./workers')(KONFIG, options, credentials)
   KONFIG.client.runtimeOptions = require('./generateRuntimeConfig')(KONFIG, credentials, options)

+  options.requirementCommands = [
+    "$KONFIG_PROJECTROOT/scripts/generate-kite-keys.sh"
+  ]
+
   KONFIG.supervisord =
     logdir   : "$KONFIG_PROJECTROOT/.logs"
     rundir   : "$KONFIG_PROJECTROOT/.supervisor"


manyboxplots: Adjust x-axis scale in lower figure

--- manyboxplots/manyboxplots.coffee
+++ manyboxplots/manyboxplots.coffee
@@ -204,7 +204,7 @@
   low = data.br[0] - (data.br[1] - data.br[0])

   lowxScale = d3.scale.linear()
-             .domain([low, -low])
+             .domain([-1.25, -low])
              .range([pad.left, w-pad.right])

   maxCount = 0;
@@ -227,7 +227,7 @@
      .attr("fill", d3.rgb(200, 200, 200))

   # axis on left
-  lowBaxisData = [-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2]
+  lowBaxisData = [-1, -0.5, 0, 0.5, 1, 1.5, 2]
   lowBaxis = lowsvg.append("g")

   # axis: white lines
@@ -241,7 +241,9 @@
      .attr("y2", h-pad.bottom)
      .attr("x1", (d) -> lowxScale(d))
      .attr("x2", (d) -> lowxScale(d))
-     .attr("stroke", "white")
+     .attr("stroke", (d) ->
+           return "white" if d != 0
+           "rgb(255,220,255)")

   # axis: labels
   lowBaxis.append("g").selectAll("empty")
@@ -328,6 +330,15 @@
      .attr("stroke", "none")
      .attr("fill", "white")

+  # white box to left smother overlap
+  lowsvg.append("rect")
+     .attr("x", 0)
+     .attr("y", 0)
+     .attr("width", pad.left)
+     .attr("height", h)
+     .attr("stroke", "none")
+     .attr("fill", "white")
+
   # box around the outside
   lowsvg.append("rect")
      .attr("x", pad.left)
@@ -350,7 +361,7 @@

   lowsvg.append("text")
      .text("Gene expression (mlratio)")
-     .attr("x", lowxScale(0))
+     .attr("x", (w-pad.left-pad.bottom)/2+pad.left)
      .attr("y", h-pad.bottom*0.2)
      .attr("fill", "blue")
      .attr("dominant-baseline", "middle")
@@ -358,7 +369,7 @@

   svg.append("text")
      .text("Arrays, sorted by median expression")
-     .attr("x", xScale(data.ind.length/2))
+     .attr("x", (w-pad.left-pad.bottom)/2+pad.left)
      .attr("y", h-pad.bottom*0.2)
      .attr("fill", "blue")
      .attr("dominant-baseline", "middle")


manyboxplots: Make linked histogram more histogram-like

--- manyboxplots/manyboxplots.coffee
+++ manyboxplots/manyboxplots.coffee
@@ -5,6 +5,23 @@
   w = 1000
   h = 450
   pad = 40
+
+  # adjust counts object to make proper histogram
+  br2 = []
+  for i in data.br
+    br2.push(i)
+    br2.push(i)
+
+  fix4hist = (d) ->
+    x = [0]
+    for i in d
+       x.push(i)
+       x.push(i)
+    x.push(0)
+    x
+
+  for i of data.counts
+    data.counts[i] = fix4hist(data.counts[i])

   # number of quantiles
   nQuant = data.quant.length
@@ -169,8 +186,10 @@
              .attr("height", h)
              .attr("width", w)

+  low = data.br[0] - (data.br[1] - data.br[0])
+
   lowxScale = d3.scale.linear()
-             .domain([-2, 2])
+             .domain([low, -low])
              .range([pad, w-pad])

   maxCount = 0;
@@ -221,7 +240,7 @@
      .attr("text-anchor", "middle")

   histline = d3.svg.line()
-        .x((d,i) -> lowxScale(data.br[i]))
+        .x((d,i) -> lowxScale(br2[i]))
         .y((d) -> lowyScale(d))

   randomInd = data.ind[Math.floor(Math.random()*data.ind.length)]


fix sale descriptions

fix sale descriptions

--- models/search_result.coffee
+++ models/search_result.coffee
@@ -71,9 +71,11 @@
       @formatArticleAbout()
     else if @get('display_model') == 'Fair'
       @formatEventAbout('Art fair')
+    else if @get('display_model') == 'Sale'
+      @formatEventAbout('Sale')
     else if @get('display_model') == 'Show'
       @formatShowAbout()
-    else if @get('display_model') in ['Sale', 'Artwork', 'Feature', 'Profile']
+    else if @get('display_model') in ['Artwork', 'Feature', 'Profile']
       @get('description')
     else undefined

@@ -96,6 +98,8 @@

     if publishedTime and excerpt
       "#{formattedPublishedTime} ... #{excerpt}"
+    else if publishedTime
+      formattedPublishedTime
     else
       excerpt


Don't add event args that don't exist

Don't add event args that don't exist

--- coffee/core/core.coffee
+++ coffee/core/core.coffee
@@ -177,7 +177,7 @@
     @execute(new LC.ClearAction(this, oldShapes, newShapes))
     @repaint()
     @trigger('clear', null)
-    @trigger('drawingChange', {shape: shape})
+    @trigger('drawingChange', {})

   execute: (action) ->
     @undoStack.push(action)
@@ -190,7 +190,7 @@
     action.undo()
     @redoStack.push(action)
     @trigger('undo', {action})
-    @trigger('drawingChange', {shape: shape})
+    @trigger('drawingChange', {})

   redo: ->
     return unless @redoStack.length
@@ -198,7 +198,7 @@
     @undoStack.push(action)
     action.do()
     @trigger('redo', {action})
-    @trigger('drawingChange', {shape: shape})
+    @trigger('drawingChange', {})

   getPixel: (x, y) ->
     p = @drawingCoordsToClientCoords x, y


Fixed a bug I made last commit. Also, Window can be unmaximized.

--- coffeescript/app.coffee
+++ coffeescript/app.coffee
@@ -340,10 +340,18 @@
 		window.noted.window = gui.Window.get()
 		window.noted.window.show()
 		window.noted.window.title = "Springseed"
-		window.noted.window.showDevTools()
+		#window.noted.window.showDevTools()
+
+		window.noted.window.on 'maximize', ->
+			window.noted.isMaximized = true
+		window.noted.window.on 'unmaximize', ->
+			window.noted.isMaximized = false
+

 		# Key Combos
-		mt.bind ['ctrl+w', 'ctrl+q'], (e) ->
+		mt.bind 'ctrl+w', (e) ->
+			window.noted.window.close()
+		mt.bind 'ctrl+q', (e) ->
 			window.noted.window.close()

 		window.noted.load.notebooks()
@@ -434,7 +442,10 @@
 			window.noted.window.minimize()

 		$('body').on "click", "#maximize", ->
-			window.noted.window.maximize()
+			if window.noted.isMaximized
+				window.noted.window.unmaximize()
+			else
+				window.noted.window.maximize()

 		$('body').on "keydown", "#notebooks input", (e) ->
 			if e.keyCode is 13


Add test for controller/collection interaction

--- test/integration/collection.spec.coffee
+++ test/integration/collection.spec.coffee
@@ -119,3 +119,15 @@
     expect(@body).to.have.text("")
     model.things = ["foo", "bar"]
     expect(@body).to.have.text("foobar")
+
+  it 'passes collection item into controller', ->
+    model = { things: [{ name: "foo" }, { name: "baz" }, {name: "bar"}] }
+    controller = { mark: (_, item) -> item.marked = true }
+
+    @render """
+      ul
+        - collection @things
+          li[event:click=mark id=@name]
+    """, model, controller
+    @fireEvent @body.querySelector('#baz'), 'click'
+    expect(model.things[1].marked).to.be.ok


Remove double-leading slash from share image. Fixes #207.

--- collections/post.coffee
+++ collections/post.coffee
@@ -39,7 +39,7 @@
       if Meteor.settings?.public?.blog?.useS3
         @featuredImage
       else
-        Meteor.absoluteUrl() + @featuredImage
+        Meteor.absoluteUrl() + @featuredImage.slice(1)
     else
       regex = new RegExp /img src=[\'"]([^\'"]+)/ig
       while match = regex.exec @body


more regexp and string interpolation tweaks

--- lexer.coffee
+++ lexer.coffee
@@ -126,17 +126,13 @@
   # to distinguish from division, so we borrow some basic heuristics from
   # JavaScript and Ruby.
   regex_token: ->
-    return false unless starts @chunk, '/'
-    return false if include NOT_REGEX, @tag()
+    return false unless @chunk.match REGEX_START
+    return false if     include NOT_REGEX, @tag()
     return false unless regex: @balanced_token ['/', '/']
-    return false if regex.length < 3 or regex.match /^\/\s+/m
-    flags: ['i', 'm', 'g', 'y']
-    while (index: flags.indexOf @chunk.substr regex.length, 1) >= 0
-      regex += flags[index]
-      flags.splice index, 1
-    if (0 < regex.indexOf('${') < regex.indexOf('}')) or regex.match /[^\\]\$[a-zA-Z_@]/
-      [str, flags]: regex.substring(1).split('/')
-      str: str.replace /\\[^\$]/g, (escaped) -> '\\' + escaped
+    regex += (flags: @chunk.substr(regex.length).match(REGEX_FLAGS))
+    if (0 < regex.indexOf('${') < regex.indexOf('}')) or regex.match REGEX_INTERPOLATION
+      str: regex.substring(1).split('/')[0]
+      str: str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped
       @tokens: @tokens.concat [['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]
       interp_tokens: @interpolate_string "\"$str\"", merge: false
       for each, i in interp_tokens
@@ -383,8 +379,7 @@
           pi: i + 1
         i += 1
       tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i and pi < str.length - 1
-      (has_string: yes) for each in tokens when each[0] is 'STRING'
-      tokens.unshift ['STRING', "''"] if not has_string
+      tokens.unshift ['STRING', "''"] unless tokens[0][0] is 'STRING'
       if (merge ? true)
         for each, i in tokens
           if each[0] is 'TOKENS'
@@ -478,6 +473,12 @@
 LAST_DENT     : /\n([ \t]*)/
 ASSIGNMENT    : /^(:|=)$/

+# Regex-matching-regexes.
+REGEX_START        : /^\/[^\/ ]/
+REGEX_INTERPOLATION: /[^\\]\$[a-zA-Z_@]/
+REGEX_FLAGS        : /^[imgy]{0,4}/
+REGEX_ESCAPE       : /\\[^\$]/g
+
 # Token cleaning regexes.
 JS_CLEANER      : /(^`|`$)/g
 MULTILINER      : /\n/g


fixing regex-interpolation-sans-flags issue.

--- lexer.coffee
+++ lexer.coffee
@@ -171,7 +171,8 @@
       str: str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped
       @tokens: @tokens.concat [['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]
       @interpolateString "\"$str\"", yes
-      @tokens: @tokens.concat [[',', ','], ['STRING', "\"$flags\""], [')', ')'], [')', ')']]
+      @tokens.splice @tokens.length, 0, [',', ','], ['STRING', "\"$flags\""] if flags
+      @tokens.splice @tokens.length, 0, [')', ')'], [')', ')']
     else
       @token 'REGEX', regex
     @i: + regex.length


fix total display

fix total display

--- src/common/services/dynamicFields.coffee
+++ src/common/services/dynamicFields.coffee
@@ -56,7 +56,7 @@
     '{total}':
       value: ->
         if _.isNumber sprint?.resources?.totalPoints
-          sprint.resources.totalPoints
+          sprint.resources.totalPoints.toFixed(1)
       description: 'The number of points to finish the sprint'
       icon: 'cart'


comment

comment

--- packages/tower-view/client/emberHelper.coffee
+++ packages/tower-view/client/emberHelper.coffee
@@ -42,7 +42,7 @@
     outletName: options.outlet || 'view' # default value in ember
     viewClass:  @findEmberView(options)
     #context:    options.data || @#get('content')
-    controller: @_context # this is the Tower.View instance
+    controller: @_context # `this` is the Tower.View instance

   # Gets the ember template from `Ember.TEMPLATES`, which might be a computed property.
   _getEmberTemplate: (name) ->


修改函数名称

修改函数名称

--- core/model/Model.coffee
+++ core/model/Model.coffee
@@ -57,7 +57,7 @@
               results.push @create doc
           callback null,results

-  @FindById: (id, callback = null) ->
+  @findById: (id, callback = null) ->
     throw 'id must be string' if !_.isString id
     db.open (err,db) =>
       @collection().findOne {_id: new ObjectID id}, (err, result) =>


URI encode hash

URI encode hash

--- src/javascripts/includes/hash_util.coffee
+++ src/javascripts/includes/hash_util.coffee
@@ -1,6 +1,6 @@
 HashUtil =
   encode: (string) ->
-    string.replace(' ', '+')
+    encodeURI(string.replace(' ', '+'))

   decode: (string) ->
-    string.replace('+', ' ')
+    decodeURI(string.replace('+', ' '))


Add text-decoration-skip support

Add text-decoration-skip support

--- data/prefixes.coffee
+++ data/prefixes.coffee
@@ -281,8 +281,9 @@
 # Text decoration
 feature require('caniuse-db/features-json/text-decoration.json'), (browsers) ->
   prefix 'text-decoration-style',
+         'text-decoration-color',
          'text-decoration-line',
-         'text-decoration-color',
+         'text-decoration-skip',
           browsers: browsers

 # Text Size Adjust


Update Safari prefixes

Update Safari prefixes

--- data/prefixes.coffee
+++ data/prefixes.coffee
@@ -3955,8 +3955,6 @@
       "opera 20"
       "opera 21"
       "opera 22"
-      "safari 6.1"
-      "safari 7"
     ]

   "font-kerning":
@@ -4023,8 +4021,6 @@
       "opera 20"
       "opera 21"
       "opera 22"
-      "safari 6.1"
-      "safari 7"
     ]

   "font-language-override":
@@ -4091,8 +4087,6 @@
       "opera 20"
       "opera 21"
       "opera 22"
-      "safari 6.1"
-      "safari 7"
     ]

   "font-variant-ligatures":
@@ -4159,8 +4153,6 @@
       "opera 20"
       "opera 21"
       "opera 22"
-      "safari 6.1"
-      "safari 7"
     ]

   grab:


Add failing test for issue #22

Add failing test for issue #22

--- spec/powershell-spec.coffee
+++ spec/powershell-spec.coffee
@@ -318,6 +318,11 @@
       {tokens} = grammar.tokenizeLine("`_")
       expect(tokens[0]).toHaveScopes ["source.powershell", "constant.character.escape.powershell"]

+    it "escapes quotes within a string", ->
+      {tokens} = grammar.tokenizeLine("$command = \".\\myfile.ps1 -param1 `\"$myvar`\" -param2 whatever\"")
+      expect(tokens[10]).toHaveScopes ["source.powershell", "constant.character.escape.powershell", "string.quoted.double.single-line.powershell"]
+      expect(tokens[11]).toHaveScopes ["source.powershell", "string.quoted.double.single-line.powershell"]
+
   describe "Line continuations", ->

     it "considers a backtick followed by a newline as a line continuation", ->


remove comments in tests

remove comments in tests

--- spec/repository-spec.coffee
+++ spec/repository-spec.coffee
@@ -20,13 +20,13 @@
     beforeEach ->
       repo.unwatchAll()

-#    it "should remove a project I want to unwatch", ->
-#      p = {owner: 'iojs', repo: 'io.js'}
-#      result = repo.watch p
-#      result.length.should.be.equal 1
-#
-#      result = repo.unwatch p
-#      result.length.should.be.equal 0
+    it "should remove a project I want to unwatch", ->
+      p = {owner: 'iojs', repo: 'io.js'}
+      result = repo.watch p
+      result.length.should.be.equal 1
+
+      result = repo.unwatch p
+      result.length.should.be.equal 0

     it "should remove a project among multiple projects", ->
       repo.watch {owner: 'iojs', repo: 'io.js'}


Fix bug when a namespace-view is render a second time (for the blackout)

--- admin/static/coffee/namespaces/shards.coffee
+++ admin/static/coffee/namespaces/shards.coffee
@@ -58,6 +58,7 @@
             super @model.get('computed_shards'), NamespaceView.Shard, 'table.shards tbody',
                 element_args:
                     namespace: @model
+            @render()

             @check_has_unsatisfiable_goals()
             issues.on 'all', @check_has_unsatisfiable_goals
@@ -70,14 +71,23 @@
                         found_unsatisfiable_goals = true
                 if found_unsatisfiable_goals is false
                     @has_unsatisfiable_goals = false
+                    @.$el.toggleClass('namespace-shards-blackout')
                     @.$('.blackout').toggleClass('blackout-active')
-                    @.$el.toggleClass('namespace-shards-blackout')
             else
                 for issue in issues.models
                     if issue.get('type') is 'UNSATISFIABLE_GOALS' and issue.get('namespace_id') is @model.get('id')
                         @has_unsatisfiable_goals = true
+                        @.$el.toggleClass('namespace-shards-blackout')
                         @.$('.blackout').toggleClass('blackout-active')
-                        @.$el.toggleClass('namespace-shards-blackout')
+
+        render: =>
+            super()
+
+            if @has_unsatisfiable_goals is true
+                @.$('.blackout').addClass('blackout-active')
+            else
+                @.$('.blackout').removeClass('blackout-active')
+            return @

         change_sharding_scheme: (event) =>
             event.preventDefault()


更新校車時間

更新校車時間

居然偷偷改成五分


Kill dead code

Kill dead code

--- src/packages/tabs/lib/tab-bar-view.coffee
+++ src/packages/tabs/lib/tab-bar-view.coffee
@@ -20,19 +20,6 @@
     @pane.on 'pane:active-item-changed', => @updateActiveTab()

     @updateActiveTab()
-
-#     @setActiveTab(@editor.getActiveEditSessionIndex())
-
-#     @editor.on 'editor:edit-session-added', (e, editSession) => @addTabForEditSession(editSession)
-#     @editor.on 'editor:edit-session-removed', (e, editSession, index) => @removeTabAtIndex(index)
-#     @editor.on 'editor:edit-session-order-changed', (e, editSession, fromIndex, toIndex) =>
-#       fromTab = @find(".tab:eq(#{fromIndex})")
-#       toTab = @find(".tab:eq(#{toIndex})")
-#       fromTab.detach()
-#       if fromIndex < toIndex
-#         fromTab.insertAfter(toTab)
-#       else
-#         fromTab.insertBefore(toTab)

     @on 'click', '.tab', (e) =>
       tab = $(e.target).closest('.tab').view()
@@ -81,13 +68,6 @@
   updateActiveTab: ->
     @setActiveTab(@tabForItem(@pane.activeItem))

-  removeTabAtIndex: (index) ->
-    @find(".tab:eq(#{index})").remove()
-
-  containsEditSession: (editor, editSession) ->
-    for session in editor.editSessions
-      return true if editSession.getPath() is session.getPath()
-
   shouldAllowDrag: ->
     (@paneContainer.getPanes().length > 1) or (@pane.getItems().length > 1)


fix lightbox title

fix lightbox title

--- app/assets/javascripts/folio/lightbox.coffee
+++ app/assets/javascripts/folio/lightbox.coffee
@@ -44,7 +44,7 @@
       src: $el.data('lightbox-src')
       w: parseInt($el.data('lightbox-width'))
       h: parseInt($el.data('lightbox-height'))
-    item.title = $el.next('figcaption').text()
+    item.title = $el.data('lightbox-title') or $el.next('figcaption').text()
     item

   destroy: ->


Fix regression in nav menu dropdown.    [#71592180]

https://www.pivotaltracker.com/story/show/71592180

--- app/assets/javascripts/save-on-change.coffee
+++ app/assets/javascripts/save-on-change.coffee
@@ -196,7 +196,7 @@
     @dirty_forms = {}

   intercept_navigation: ->
-    $("a").not('.colorbox').not('[target]').on 'click', (e) =>
+    $("a").not('.colorbox').not('[target]').not("#menu-trigger").on 'click', (e) =>
       e.preventDefault()
       @click_element   = e.currentTarget
       @force_save_dirty()


unifinished work toward getting testing of jupyter to work at all...

--- src/smc-webapp/jupyter/test/setup.coffee
+++ src/smc-webapp/jupyter/test/setup.coffee
@@ -9,6 +9,7 @@

 # require('coffee-cache').setCacheDir("#{process.env.HOME}/.coffee/cache")

+require('smc-hub/share/jsdom-support')
 misc = require('smc-util/misc')
 smc_react = require('../../smc-react')
 require('../../project_store')  # needed so that project store is available.


removed duplicate issue

removed duplicate issue

--- app/assets/javascripts/application.coffee
+++ app/assets/javascripts/application.coffee
@@ -60,9 +60,7 @@
 					document.open()
 					document.write(response)
 					document.close()
-		)
-		(err) ->
-			console.log(err)
+			)
 		)
 	)
 $( 'li' ).on( 'click', '.clickable-row', ( event ) ->


Now checkboxes are selected when switching category, fixes #256

--- app/assets/javascripts/calendar.js.coffee
+++ app/assets/javascripts/calendar.js.coffee
@@ -193,12 +193,12 @@
     $all_checkboxes.attr 'disabled', (presetId != 'diy')

     if presetId == 'diy' and calendarPresets[presetId].length == 0
-      $all_checkboxes.attr('checked', true)
+      $all_checkboxes.prop('checked', true)
     else
-      $all_checkboxes.attr('checked', false)
+      $all_checkboxes.prop('checked', false)

       $.each calendarPresets[presetId], (id, categoryId)->
-        $('input[name=calendar_category][value=' + categoryId + ']').attr('checked', true)
+        $('input[name=calendar_category][value=' + categoryId + ']').prop('checked', true)

     # Reload the calendar with the new data
     Calendar.replaceEntries() if shouldReload


Fix indentation

Fix indentation

--- app/assets/javascripts/code_status.coffee
+++ app/assets/javascripts/code_status.coffee
@@ -7,5 +7,5 @@
     $("#show-all-gem-versions").on "click", (e) ->
       e.preventDefault()

-    $("table#gems-versions-table .minor").toggleClass 'hide'
-    $(this).toggleClass 'shown'
+      $("table#gems-versions-table .minor").toggleClass 'hide'
+      $(this).toggleClass 'shown'


Only try to score models that have the attribute

--- app/assets/javascripts/exo/matcher.coffee
+++ app/assets/javascripts/exo/matcher.coffee
@@ -20,13 +20,14 @@
           # Score models in sources against a passed in query if there is one,
           # otherwise return all models
           if query
-            score = exports.Extensions.String.score(model.get(@modelFilterAttr), query)
+            if attr = model.get(@modelFilterAttr)
+              score = exports.Extensions.String.score(attr, query)

-            if score > @threshold
-              results.push {
-                score: score
-                object: model
-              }
+              if score > @threshold
+                results.push {
+                  score: score
+                  object: model
+                }
           else
             results.push {
               score: null


More precise Regex but also more tolerant. Check this page: http://regexr.com/38v6m

--- app/assets/javascripts/url-preview.coffee
+++ app/assets/javascripts/url-preview.coffee
@@ -1,6 +1,6 @@
 class @UrlPreview
-  URL_PATTERN = /\b(https?:\/\/[^\s]+)\b/i
-
+  URL_PATTERN = /((https?:\/\/)|([-a-zA-Z0-9@:%._\+~#=]+\.))?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,10}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g
+
   constructor: (options) ->
     @reset()
     @options = options
@@ -23,7 +23,9 @@
   # Checking if str matches url regex
   parseStr: (str) ->
     urls = str.match(URL_PATTERN)
-    return urls[1] if urls
+    if urls
+      "http://".concat(urls[0]) unless urls[0].match(/https?:\/\//)
+      return urls[0]

   # Send request to remote service
   requestPreview: (url, callback) ->


indentation

indentation

--- app/scripts/services/budget_loader.coffee
+++ app/scripts/services/budget_loader.coffee
@@ -7,7 +7,7 @@
   loadAll: ->
     self = @
     Budget.all().then (budgets) ->
-        self.rootScope.budgets = budgets
+      self.rootScope.budgets = budgets

   ###
         #console.log(budgets)


Add teacher class tab click event

Add teacher class tab click event

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -305,6 +305,9 @@
   onClickNavTabLink: (e) ->
     e.preventDefault()
     hash = $(e.target).closest('a').attr('href')
+    if hash isnt window.location.hash
+      tab = hash.slice(1)
+      window.tracker?.trackEvent 'Teachers Class Switch Tab', { category: 'Teachers', classroomID: @classroom.id, tab }, ['Mixpanel']
     @updateHash(hash)
     @state.set activeTab: hash


Fixed yet another InventoryModal race condition

--- app/views/play/menu/InventoryModal.coffee
+++ app/views/play/menu/InventoryModal.coffee
@@ -72,6 +72,7 @@
       item.notInLevel = true
       programmableConfig = _.find(item.get('components'), (c) -> c.config?.programmableProperties)?.config
       item.programmableProperties = (programmableConfig?.programmableProperties or []).concat programmableConfig?.moreProgrammableProperties or []
+    @itemsProgrammablePropertiesConfigured = true
     @equipment = @options.equipment or @options.session?.get('heroConfig')?.inventory or me.get('heroConfig')?.inventory or {}
     @equipment = $.extend true, {}, @equipment
     @requireLevelEquipment()
@@ -399,7 +400,7 @@

   requireLevelEquipment: ->
     # This is called frequently to make sure the player isn't using any restricted items and knows she must equip any required items.
-    return unless @inserted and @items.loaded
+    return unless @inserted and @itemsProgrammablePropertiesConfigured
     equipment = if @supermodel.finished() then @getCurrentEquipmentConfig() else @equipment  # Make sure we're using latest equipment.
     hadRequired = @remainingRequiredEquipment?.length
     @remainingRequiredEquipment = []


style: make the karma.conf.coffee more coffee-like

--- test/e2e/coffee-config/karma.conf.coffee
+++ test/e2e/coffee-config/karma.conf.coffee
@@ -1,26 +1,26 @@
 module.exports = (karma) ->
-  karma.configure {
-    frameworks: ['jasmine'],
+  karma.configure
+
+    frameworks: ['jasmine']

     files: [
-      '*.js',
+      '*.js'
       '*.coffee'
-    ],
+    ]

-    autoWatch: true,
+    autoWatch: true

-    browsers: ['Chrome'],
+    browsers: ['Chrome']

-    reporters: ['dots'],
+    reporters: ['dots']

     preprocessors: {
       '**/*.coffee': 'coffee'
-    },
+    }

     plugins: [
-      'karma-jasmine',
-      'karma-coffee-preprocessor',
-      'karma-chrome-launcher',
+      'karma-jasmine'
+      'karma-coffee-preprocessor'
+      'karma-chrome-launcher'
       'karma-firefox-launcher'
-    ],
-  }
+    ]


unwrap editor.tokenForBufferPosition to add more error tolerance

--- lib/atom-react.coffee
+++ lib/atom-react.coffee
@@ -194,7 +194,11 @@
     return if not @isReactEnabledForEditor editor

     if eventObj?.newText is '>' and !eventObj.oldText
-      token = editor.tokenForBufferPosition([eventObj.newRange.end.row, eventObj.newRange.end.column - 1]);
+      tokenizedLine = editor.displayBuffer?.tokenizedBuffer?.tokenizedLineForRow(eventObj.newRange.end.row)
+      return if not tokenizedLine?
+
+      token = tokenizedLine.tokenAtBufferColumn(eventObj.newRange.end.column - 1)
+
       if not token? or token.scopes.indexOf('tag.open.js') == -1 or token.scopes.indexOf('punctuation.definition.tag.end.js') == -1
         return

@@ -224,11 +228,11 @@
       lines = editor.buffer.getLines()
       row = eventObj.newRange.end.row
       fullLine = lines[row]
-      lastCharIndex = eventObj.newRange.end.column - 1;
-
-      return if not row? or lastCharIndex < 0 or lastCharIndex > fullLine.length - 1;
-
-      token = editor.tokenForBufferPosition([row, lastCharIndex]);
+
+      tokenizedLine = editor.displayBuffer?.tokenizedBuffer?.tokenizedLineForRow(eventObj.newRange.end.row)
+      return if not tokenizedLine?
+
+      token = tokenizedLine.tokenAtBufferColumn(eventObj.newRange.end.column - 1)
       if not token? or token.scopes.indexOf('tag.open.js') == -1
         return
       line = fullLine.substr 0, eventObj.newRange.end.column


Really "re-order" the photos

Really "re-order" the photos

--- src/js/controllers/photosets-ctrl.coffee
+++ src/js/controllers/photosets-ctrl.coffee
@@ -15,8 +15,8 @@
       photoset = _.find $scope.photosets, { id: photosetId }
       Photosets.getPhotos photosetId, parseInt(photoset.photos, 10)
       .then (photos) ->
-        ids = _.map photos, 'id'
-        Photosets.reorderPhotos photosetId, ids
+        ids = _(photos).sortBy('date_upload').map 'id'
+        Photosets.reorderPhotos photosetId, ids.reverse()

     $scope.$watch 'page', -> getList()


logout should be working now

logout should be working now

--- app/assets/javascripts/components/login.cjsx
+++ app/assets/javascripts/components/login.cjsx
@@ -13,19 +13,6 @@
     loading: false
     error: null

-  signOut:(e)->
-    e.preventDefault()
-
-    request = $.ajax({url: '/users/sign_out', method: 'delete'})
-
-    request.done =>
-      @setState
-        user:null
-
-    request.error =>
-      @setState
-        error : "Could not log out"
-
   fetchUser:->
     @setState
       loading: true
@@ -33,9 +20,13 @@
     request = $.getJSON "/current_user"

     request.done (result)=>
-      @setState
-        user: result.user
-        loading: false
+      if result
+        @setState
+          user: result.user
+          loading: false
+      else
+        @setState
+          loading: false

     request.fail (error)=>
@@ -44,7 +35,7 @@
         error: "Having trouble logging you in"

   render:->
-

+

       {@renderError() if @state.error}

       {@renderLoggedIn() if @state.user}
@@ -54,8 +45,26 @@
       }

+  signOut:(e)->
+    alert("ere")
+    e.preventDefault()
+
+    request = $.ajax
+      url: '/users/sign_out'
+      method: 'delete'
+      dataType: "json"
+
+    request.done =>
+      @setState
+        user: null
+
+    request.error (request,error)=>
+      @setState
+        error : "Could not log out"
+
+
   renderLoggedIn:->
-
Hello {@state.user.name} Logout

+
Hello {@state.user.name} Logout

   renderLoggedOut:->


Move target line out of viewport if no target set

If no target is set (present_value() or future_value() equals null), no target
line is visible as it is moved out of the viewport. If the target is set to
0, the target line is displayed as expected. Closes #1452.

--- app/assets/javascripts/d3/stacked_bar.coffee
+++ app/assets/javascripts/d3/stacked_bar.coffee
@@ -156,9 +156,9 @@
         .transition()
         .attr 'y', (d) =>
           value = if d.get('target_line_position') is '1'
-            if d.safe_present_value() == 0 then 3*@series_height else d.safe_present_value()
+            if d.present_value() == null and d.safe_present_value() == 0 then 3*@series_height else d.safe_present_value()
           else
-            if d.safe_future_value() == 0 then 3*@series_height else d.safe_future_value()
+            if d.future_value() == null and d.safe_future_value() == 0 then 3*@series_height else d.safe_future_value()

           @series_height - @y(value)


Added schema.org props to profile.

Added schema.org props to profile.

--- server/lib/crawler/staticpages/profile.coffee
+++ server/lib/crawler/staticpages/profile.coffee
@@ -24,14 +24,16 @@
   username   = if account.profile.nickname  then account.profile.nickname  else "A koding nickname"
   firstName  = if account.profile.firstName then account.profile.firstName else "first name of koding user"
   lastName   = if account.profile.lastName  then account.profile.lastName  else "last name of koding user"
+  numberOfLikes = if account.counts.likes then account.counts.likes else "0"

   content  =
-    """

-

+    """

+

             #{username}

-            [ #{firstName} - #{lastName} ]
+            [ #{firstName} - #{lastName} ]

+
#{numberOfLikes} likes.

     """


Always shows level intro doc scrollbars

Always shows level intro doc scrollbars

--- app/views/play/level/LevelLoadingView.coffee
+++ app/views/play/level/LevelLoadingView.coffee
@@ -160,7 +160,7 @@
     if @intro
       $intro = @$el.find('.intro-doc')
       $intro.css height: minHeight - $intro.offset().top - @$el.find('.progress-or-start-container').outerHeight() - 30 - 20
-      $intro.find('.nano').nanoScroller alwaysVisible: true
+      _.defer -> $intro.find('.nano').nanoScroller alwaysVisible: true

   unveilWings: (duration) ->
     @playSound 'loading-view-unveil', 0.5


Snip off vestigial method

Snip off vestigial method

--- angular/core/components/group_page/description_card/description_card.coffee
+++ angular/core/components/group_page/description_card/description_card.coffee
@@ -18,6 +18,3 @@
       prepareFn: -> $scope.group.description = $scope.editableDescription
       flashSuccess: 'description_card.messages.description_updated'
       successCallback: -> $scope.disableEditor()
-
-    submitForm = FormService.submit $scope, $scope.group,
-      draftFields: ['description']


Fix Tetrus.Flash

Fix Tetrus.Flash

--- coffee/lib/flash.coffee
+++ coffee/lib/flash.coffee
@@ -1,13 +1,4 @@
 Tetrus.Flash = Batman
-  _message: ""
-  _class: "message"
-
-  _flash: (message) ->
-    @set('_message', message)
-    node = $('#flash')
-    bottom = node.css('bottom')
-    node.animate(bottom: 0, 200).delay(5000).animate({bottom}, 800)
-
   message: (message) ->
     @set('_class', 'message')
     @_flash(message)
@@ -16,3 +7,14 @@
     @set('_class', 'error')
     @_flash(error)

+  open: -> $('#flash').animate(bottom: 0, 200)
+  close: -> $('#flash').animate(bottom: @_bottom, 800)
+
+  _flash: (message) ->
+    clearTimeout(@_closeTimeout) if @_closeTimeout
+    @_closeTimeout = setTimeout(@close.bind(this), 5000)
+
+    @_bottom ?= $('#flash').css('bottom')
+    @set('_message', message)
+    @open()
+


:lipstick:

:lipstick:

--- src/app/atom-package.coffee
+++ src/app/atom-package.coffee
@@ -17,7 +17,7 @@
       if @deferActivation = @metadata.activationEvents?
         @registerDeferredDeserializers()
       else
-        @requirePackageMain()
+        @requireMainModule()
     catch e
       console.warn "Failed to load package named '#{@name}'", e.stack
     this
@@ -47,13 +47,13 @@
       @subscribeToActivationEvents()
     else
       try
-        if @requirePackageMain()
+        if @requireMainModule()
           config.setDefaults(@name, @mainModule.configDefaults)
           atom.activateAtomPackage(this)
       catch e
         console.warn "Failed to activate package named '#{@name}'", e.stack

-  requirePackageMain: ->
+  requireMainModule: ->
     return @mainModule if @mainModule
     mainPath = @path
     mainPath = fs.join(mainPath, @metadata.main) if @metadata.main
@@ -62,7 +62,7 @@

   registerDeferredDeserializers: ->
     for deserializerName in @metadata.deferredDeserializers ? []
-      registerDeferredDeserializer deserializerName, => @requirePackageMain()
+      registerDeferredDeserializer deserializerName, => @requireMainModule()

   subscribeToActivationEvents: () ->
     return unless @metadata.activationEvents?


Call fs.list() without prior call to fs.exists()

fs.list() returns an empty array if calle for a
non-existent or non-directory path.

--- src/app/atom-package.coffee
+++ src/app/atom-package.coffee
@@ -35,10 +35,7 @@
       keymaps.map (relativePath) =>
         fs.resolve(@keymapsDirPath, relativePath, ['cson', 'json', ''])
     else
-      if fs.exists(@keymapsDirPath)
-        fs.list(@keymapsDirPath)
-      else
-        []
+      fs.list(@keymapsDirPath)

   loadStylesheets: ->
     for stylesheetPath in @getStylesheetPaths()
@@ -46,7 +43,4 @@

   getStylesheetPaths: ->
     stylesheetDirPath = fs.join(@path, 'stylesheets')
-    if fs.exists stylesheetDirPath
-      fs.list stylesheetDirPath
-    else
-      []
+    fs.list(stylesheetDirPath)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/array_extensions.coffee
+++ src/array_extensions.coffee
@@ -1,5 +1,5 @@
 ###*
-Calculate the average value of an arr
+Calculate the average value of an array.

 [null, undefined, 3, 3, undefined, 5].compact()


array_extensions

--- src/array_extensions.coffee
+++ src/array_extensions.coffee
@@ -107,8 +107,7 @@

 @name rand
 @methodOf Array#
-@type Object
-@returns A random element from an array
+@returns {Object} A random element from an array
 ###
 Array::rand = ->
   this[rand(this.length)]


Use Like instead of ...

Use Like instead of ...

--- client/app/Applications/Activity.kdapplication/views/activityactions.coffee
+++ client/app/Applications/Activity.kdapplication/views/activityactions.coffee
@@ -65,7 +65,7 @@
       cssClass  : "action-link"
       attributes:
         href    : "#"
-      partial   : "..."
+      partial   : "Like"
     , options
     super options,data


fix my previous messed up commit

fix my previous messed up commit

--- static/coffee/renderers/primitives.coffee
+++ static/coffee/renderers/primitives.coffee
@@ -1,5 +1,4 @@

-<<<<<<< Updated upstream
 annular_wedge = require("./annular_wedge")
 annulus       = require("./annulus")
 arc           = require("./arc")


Real-time update for activity in followed topics

Using Relationship instead of exchange-to-exchange because the
addGlobalListener does not work yet.

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -165,15 +165,34 @@
           flags = KD.whoami().globalFlags
           exempt = flags?.indexOf 'exempt'
           exempt = (exempt? and ~exempt) or storage.getAt 'bucket.showLowQualityContent'
-          $.ajax KD.apiUri+'/1.0'
-            data      :
-              t       : if exempt then 1 else undefined
-              data    : JSON.stringify(_.extend options, selector)
-              env     : KD.config.env
-            dataType  : 'jsonp'
-            success   : (data) -> callback null, data
+          # $.ajax KD.apiUri+'/1.0'
+          #   data      :
+          #     t       : if exempt then 1 else undefined
+          #     data    : JSON.stringify(_.extend options, selector)
+          #     env     : KD.config.env
+          #   dataType  : 'jsonp'
+          #   success   : (data) -> callback null, data
+          unless exempt
+            selector['isLowQuality'] = {'$ne':yes}
+          KD.remote.api.CActivity.some selector, options, (err, data) ->
+            if err
+              callback err
+            else
+              for datum in data
+                datum.snapshot = datum.snapshot.replace /"/g, '"'
+              callback null, data

     else if type is 'private'
+      # KD.whoami().fetchFeeds (err, feeds) =>
+      #   for feed in feeds
+      #     continue unless feed.title is 'followed'
+      #     feed.fetchActivities selector, options, (err, data) =>
+      #       if err
+      #         callback err
+      #       else
+      #         for datum in data
+      #           datum.snapshot = datum.snapshot.replace /"/g, '"'
+      #       callback null, data
       KD.whoami().getFeedByTitle "followed", (err, feed) ->
         feed.fetchActivities selector, options, (err, data) ->
           if err
@@ -383,8 +402,22 @@
     id = KD.whoami().getId()
     id? and id in [activity.originId, activity.anchor?.id]

-  isInFollowing:(activity)->
-    activity.originId in @_following or activity.anchor?.id in @_following
+  isInFollowing:(activity, callback)->
+    # if activity.originId in @_following or activity.anchor?.id in @_following
+    #   return true
+    # else
+
+    account = KD.whoami()
+    {originId, anchor} = activity
+    account.isFollowing originId, 'JAccount', (result) ->
+      if result
+        callback true
+      else
+        activity.fetchTeaser? (err, {tags}) =>
+          callback false unless tags?
+          tagIds = tags.map((tag) -> tag._id)
+          account.isFollowing {$in: tagIds}, 'JTag', (result) ->
+            callback result

   ownActivityArrived:(activity)->
     view = @getListView().addHiddenItem activity, 0
@@ -394,9 +427,17 @@

   newActivityArrived:(activity)->
     unless @isMine activity
-      if (@_state is 'private' and @isInFollowing activity) or @_state is 'public'
+      if @_state is 'public'
         view = @addHiddenItem activity, 0
         @activityHeader.newActivityArrived()
+      else if @_state is 'private'
+        @isInFollowing activity, (result) =>
+          if result
+            view = @addHiddenItem activity, 0
+            @activityHeader.newActivityArrived()
+      # if (@_state is 'private' and @isInFollowing activity) or @_state is 'public'
+      #   view = @addHiddenItem activity, 0
+      #   @activityHeader.newActivityArrived()
     else
       switch activity.constructor
         when KD.remote.api.CFolloweeBucket


[LoadingFree] check if prefetched activity is set

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -204,7 +204,8 @@
     {CStatusActivity} = KD.remote.api

     if @getFeedFilter() is "Public" and @getActivityFilter() is "Everything"
-      if KD.prefetchedFeeds["activity.main"] and 'activities.main' not in USEDFEEDS
+      prefetchedActivity = KD.prefetchedFeeds["activity.main"]
+      if prefetchedActivity and ('activities.main' not in USEDFEEDS) and prefetchedActivity.activities
         log "exhausting feed:", "activity.main"
         USEDFEEDS.push 'activities.main'
         return @prepareCacheForListing KD.prefetchedFeeds["activity.main"]


Fix "required" question behavior

Fix "required" question behavior

--- app/classifier/index.cjsx
+++ app/classifier/index.cjsx
@@ -56,11 +56,14 @@

             onFirstAnnotation = currentClassification.annotations.indexOf(currentAnnotation) is 0

-            if currentTask.type is 'single'
-              currentAnswer = currentTask.answers?[currentAnnotation.value]
-              waitingForAnswer = not currentAnswer
+            switch currentTask.type
+              when 'single'
+                currentAnswer = currentTask.answers?[currentAnnotation.value]
+                waitingForAnswer = currentTask.required and not currentAnswer
+              when 'multiple'
+                waitingForAnswer = currentTask.required and currentAnnotation.value.length is 0

-            nextTaskKey = if currentAnswer? and currentTask.type is 'single'
+            nextTaskKey = if currentTask.type is 'single' and currentAnswer?
               currentAnswer.next
             else
               currentTask.next


Added a filter to capitalize text

Added a filter to capitalize text

--- app/coffee/filters.coffee
+++ app/coffee/filters.coffee
@@ -42,6 +42,10 @@
     return (input) ->
         return if input then input.toLowerCase() else ""

+CapitalizeFilter = ->
+    return (input) ->
+        return if input then input.charAt(0).toUpperCase() + input.slice(1) else ""
+
 SizeFormatFilter = ->
     return (input, precision) ->
         if isNaN(parseFloat(input)) or !isFinite(input)
@@ -61,6 +65,7 @@

 module = angular.module('greenmine.filters', [])
 module.filter("lowercase", LowercaseFilter)
+module.filter("capitalize", CapitalizeFilter)
 module.filter("momentFormat", MomentFormatFilter)
 module.filter("momentFromNow", MomentFromNowFilter)
 module.filter("slugify", SlugifyFilter)


Simplify SelectionManager#focus and ensure an initial location range

--- src/trix/models/selection_manager.coffee
+++ src/trix/models/selection_manager.coffee
@@ -75,10 +75,7 @@
     not @selectionIsCollapsed()

   focus: ->
-    return if @getLocationRange()
-    locationRange = new Trix.LocationRange [0,0]
-    domRange = @createDOMRangeFromLocationRange(locationRange)
-    setDOMRange(domRange)
+    @setLocationRange([0, 0]) unless @getLocationRange()

   # Private


Improve expanding selection in IE

Improve expanding selection in IE

--- src/trix/models/selection_manager.coffee
+++ src/trix/models/selection_manager.coffee
@@ -32,13 +32,21 @@
     if selection.modify
       selection.modify("extend", direction, granularity)
     else if document.body.createTextRange
-      textRange = document.body.createTextRange()
-      textRange.moveToPoint(@getPointAtEndOfSelection()...)
+      [leftPoint, rightPoint] = @getSelectionEndPoints()
+
+      leftRange = document.body.createTextRange()
+      leftRange.moveToPoint(leftPoint...)
+
+      rightRange = document.body.createTextRange()
+      rightRange.moveToPoint(rightPoint...)
+
       if direction is "forward"
-        textRange.moveEnd(granularity, 1)
+        rightRange.move(granularity, 1)
       else
-        textRange.moveStart(granularity, -1)
-        textRange.select()
+        leftRange.move(granularity, -1)
+
+      leftRange.setEndPoint("EndToEnd", rightRange)
+      leftRange.select()
     Trix.selectionChangeObserver.update()

   locationIsCursorTarget: (location) ->
@@ -56,7 +64,7 @@
       @setLocationRange(lockedLocationRange) if lockedLocationRange?

   preserveSelection: (block) ->
-    point = @getPointAtEndOfSelection()
+    point = @getSelectionEndPoints()[0]
     block()
     range = @getLocationRangeAtPoint(point)
     @setDOMRange(range)
@@ -182,20 +190,17 @@

     @createLocationRangeFromDOMRange(domRange ? getDOMRange())

-  getPointAtEndOfSelection: ->
+  getSelectionEndPoints: ->
     return unless range = getDOMRange()
     rects = range.getClientRects()
     if rects.length > 0
-      rect = rects[rects.length - 1]
-
-      clientX = rect.right
-      clientY = rect.top + rect.height / 2
-
-      if clientRectIsRelativeToBody()
-        clientX -= document.body.scrollLeft
-        clientY -= document.body.scrollTop
-
-      [clientX, clientY]
+      leftRect = rects[0]
+      rightRect = rects[rects.length - 1]
+
+      leftPoint = [leftRect.left, leftRect.top + leftRect.height / 2]
+      rightPoint = [rightRect.right, rightRect.top + rightRect.height / 2]
+
+      [leftPoint, rightPoint]

   nodeIsCursorTarget = (node) ->
     return unless node


Updated to the new morgan API

Updated to the new morgan API

--- lib/jsonserver.coffee
+++ lib/jsonserver.coffee
@@ -18,7 +18,7 @@
   app.use bodyParser.urlencoded extended: true
   app.use do bodyParser.json
   app.use do multipart
-  app.use do logger if log
+  app.use logger 'combined' if log

   app.use (req, res, next) ->
     res.setHeader 'Access-Control-Allow-Credentials', true


:art: Cleanup

:art: Cleanup

--- lib/jumpy-view.coffee
+++ lib/jumpy-view.coffee
@@ -36,6 +36,9 @@
     @content: ->
         @div ''

+    getOverlayer: (editorView) ->
+        editorView.shadowRoot.querySelector('content[select=".overlayer"]')
+
     initialize: (serializeState) ->
         @disposables = new CompositeDisposable()
         @commands = new CompositeDisposable()
@@ -72,7 +75,7 @@
                 editorView = atom.views.getView(editor)
                 return if $(editorView).is ':not(:visible)'

-                overlayer = editorView.shadowRoot.querySelector('content[select=".overlayer"]')
+                overlayer = @getOverlayer editorView
                 $(overlayer).find('.label:not(.irrelevant)').each (i, label) ->
                     if label.innerHTML[labelPosition] == character
                         found = true
@@ -94,7 +97,7 @@
                 editorView = atom.views.getView(editor)
                 return if $(editorView).is ':not(:visible)'

-                overlayer = editorView.shadowRoot.querySelector('content[select=".overlayer"]')
+                overlayer = @getOverlayer editorView
                 for label in overlayer.querySelectorAll '.jumpy.label'
                     if label.innerHTML.indexOf(@firstChar) != 0
                         label.classList.add 'irrelevant'
@@ -111,9 +114,9 @@

     reset: ->
         @clearKeys()
-        @disposables.add atom.workspace.observeTextEditors (editor) =>
+        @disposables.add atom.workspace.observeTextEditors (editor) ->
             editorView = atom.views.getView(editor)
-            overlayer = editorView.shadowRoot.querySelector('content[select=".overlayer"]')
+            overlayer = @getOverlayer editorView
             $(overlayer).find '.irrelevant'
                 .removeClass 'irrelevant'
         @statusBarJumpy?.classList.remove 'no-match'
@@ -161,8 +164,9 @@
             return if $editorView.is ':not(:visible)'

             editorView.classList.add 'jumpy-jump-mode'
-            overlayer = editorView.shadowRoot.querySelector('content[select=".overlayer"]')
-            $(overlayer).append '

'
+            overlayer = @getOverlayer editorView
+            $(overlayer)
+                .append '

'
             labelContainer = overlayer.querySelector '.jumpy-label-container'

             drawLabels = (column, labelContainer) =>
@@ -222,7 +226,7 @@
         @disposables.add atom.workspace.observeTextEditors (editor) =>
             editorView = atom.views.getView(editor)
             return if $(editorView).is ':not(:visible)'
-            overlayer = editorView.shadowRoot.querySelector('content[select=".overlayer"]')
+            overlayer = @getOverlayer editorView
             $(overlayer).find('.jumpy').remove()
             editorView.classList.remove 'jumpy-jump-mode'
             for e in ['blur', 'click']
@@ -254,7 +258,8 @@
             else
                 currentEditor.setCursorScreenPosition location.position

-            useHomingBeacon = atom.config.get 'jumpy.useHomingBeaconEffectOnJumps'
+            useHomingBeacon =
+                atom.config.get 'jumpy.useHomingBeaconEffectOnJumps'
             if useHomingBeacon
                 cursor = editorView.shadowRoot.querySelector '.cursors .cursor'
                 if cursor


View: Override Object::off to remove events binded to DOM element.

--- src/coffee/core/View.coffee
+++ src/coffee/core/View.coffee
@@ -179,6 +179,16 @@

   ###*
+    @inheritDoc
+    @override
+    Override Object::off to remove events binded to DOM element.
+  ###
+  off: (eventName, callback) ->
+    @unlisten eventName, callback
+    goog.events.unlisten @getElement(), eventName, callback
+
+
+  ###*
     This method is responsible from binding DOM events to the element of this view.
     It uses native DOM event names which is all lowercase. If your options
     has an event name and a callback function in eventHandlers object


aaaaa

aaaaa

--- src/coffee/test-main.coffee
+++ src/coffee/test-main.coffee
@@ -1,164 +0,0 @@
-test3 = ()->
-	console.log "/?"
-
-isLoaded = false
-class Router extends Kazitori
-	# beforeAnytime:['checkMaterial']
-	befores:
-		# 'admin' :['ninshou']
-		'/<string:user>/<int:post>/<friend>':['beforeMinchi']
-	routes :
-		'/':'index'
-		# '/<int:id>':'show'
-		# '/admin/<int:id>':'show'
-		'/admin':'admin'
-		'/login':'login'
-		'/logout':'logout'
-		# '/<string:user>/<int:post>':'post'
-		'/<string:user>/<int:post>/<friend>':'firend'
-		# '/hyoge':'hyoge'
-
-
-	index:()->
-		console.log "index"
-		$('#dialog').hide()
-		$('#adminContainer').empty()
-		$('.currentPage').empty().append "this page is index"
-
-	show:(id)->
-		console.log "showwww", id
-		$('.currentPage').empty().append "this page is test" + id
-
-	hyoge:()->
-		console.log "oppai"
-		$('.currentPage').empty().append "(´･ω｀･)ｴｯ?"
-
-	admin:()->
-		console.log "admin"
-		$('.currentPage').empty().append "this is admin page"
-		$('#adminContainer').empty().append('123')
-
-	login:()->
-		$('#dialog').show()
-
-	logout:()->
-		setCookie(COOKIE_KEY, '')
-		window.App.change('')
-		console.log "logout"
-		$('#adminContainer').empty()
-		return
-
-	post:(username, postid)->
-		$('.currentPage').empty().append username, postid
-		console.log username, postid
-
-	firend:(username, postid, firend)->
-		console.log "friend"
-		$('.currentPage').empty().append username, postid, firend
-
-	###
-		some before functions
-	###
-	test:(hiroshi)->
-		console.log "before 1", hiroshi
-
-	beforeMinchi:()->
-		console.log "before minchi"
-
-	ninshou:()->
-		isLogined = Boolean(getCookie(COOKIE_KEY))
-		if isLogined is true
-			return
-		else
-			# @change('login')
-			@reject()
-
-
-		# @change(@poolFragment)
-
-
-COOKIE_KEY = 'kazitoriExpCookie'
-USER = "hage"
-PASS = "hikaru"
-
-$(document).ready ()->
-	$('#dialog').css({
-		top : window.innerHeight / 2 - 90
-		left : window.innerWidth / 2 - 150
-	})
-	$('#dialog').hide()
-
-
-
-
-	window.App = new Router({root:'/'})
-	#チェンジイベント
-	window.App.addEventListener( KazitoriEvent.CHANGE, (event)->
-		console.log event, "change"
-		)
-	window.App.addEventListener( KazitoriEvent.PREV, (event)->
-		console.log event, "prev"
-		)
-	window.App.addEventListener( KazitoriEvent.NEXT, (event)->
-		console.log event, "next"
-		)
-	#リジェクトイベント
-	window.App.addEventListener(KazitoriEvent.REJECT, (event)->
-		console.log event
-		)
-
-	#not foudn
-	window.App.addEventListener(KazitoriEvent.NOT_FOUND, (event)->
-		console.log "not found"
-		)
-
-	$('.test').on "click", clickHandler
-
-	$('.prev').on "click", prevHandler
-
-	$('.next').on "click", nextHandler
-
-	$('form').on 'submit', (event)->
-		event.preventDefault()
-		userID = $('input[name=user]').val()
-		pw = $('input[name=pw]').val()
-		if userID is USER and pw is PASS
-			setCookie(COOKIE_KEY, true)
-			$('#dialog').hide()
-			window.App.change('admin')
-		else
-			alert('バルス')
-
-clickHandler =(event)->
-	event.preventDefault()
-	target = event.currentTarget.pathname
-	window.App.change(target)
-
-prevHandler =(event)->
-	event.preventDefault()
-	window.App.omokazi()
-
-nextHandler =(event)->
-	event.preventDefault()
-	window.App.torikazi()
-
-getCookie =(key)->
-	cookies = document.cookie.split(";")
-	for cookie in cookies
-		items = cookie.split('=')
-		if items.shift() is key
-			return items.join('=')
-	return null
-
-
-## TODO あとで secure とか expire のオプションに対応させようね
-setCookie =(key, value, opt)->
-	if not value?
-		return
-	expire = new Date()
-	expire.setTime(expire.getTime()+60*60*24*1000)
-	exipre = expire.toGMTString()
-	document.cookie = key + '=' + escape(value) + ';expires=' + expire
-
-test2 =()->
-	console.log "before 2"


Update default Darwin path accordingly

Update default Darwin path accordingly

--- lib/latextools.coffee
+++ lib/latextools.coffee
@@ -83,7 +83,7 @@
       properties:
         texpath:
           type: 'string'
-          default: "/Library/TeX/texbin:/usr/texbin:/usr/local/bin:/opt/local/bin"
+          default: "/Library/TeX/texbin:/usr/texbin:/usr/local/bin:/opt/local/bin:$PATH"
       order: 13

     win32:
@@ -106,6 +106,7 @@
           type: 'number'
           default: 0.5
       order:14
+
     linux:
       type: 'object'
       properties:


Bugfix: corrected order of the buttons.

Bugfix: corrected order of the buttons.

Fixed file cofee

--- www_src/locales.coffee
+++ www_src/locales.coffee
@@ -33,9 +33,9 @@
 		title: "Ressenya %@",
 		message: "Si t'agrada %@, podries escriure una ressenya? No et prendrà més d'un minut. Gràcies pel teu suport!",
 		buttonLabels: [
-			"No, gràcies"
 			"Escriure una ressenya ara"
 			"Recorda-m'ho més tard"
+      "No, gràcies"
 		]
 	cs:
 		title: "Ohodnotit %@"
@@ -81,9 +81,9 @@
 		title: "Reseña %@"
 		message: "Si te gusta %@, ¿podrías escribirnos una reseña? No te tomará más de un minuto. ¡Gracias por tu apoyo!"
 		buttonLabels: [
-			"No, gracias"
 			"Escribir reseña ahora"
 			"Recordarme más tarde"
+      "No, gracias"
 		]
 	fa:
 		title: "نرخ %@"
@@ -264,4 +264,4 @@

-module.exports = AppRateLocales+module.exports = AppRateLocales


Retry username check after verification

Retry username check after verification

--- resources/assets/coffee/_classes/store-supporter-tag.coffee
+++ resources/assets/coffee/_classes/store-supporter-tag.coffee
@@ -86,7 +86,9 @@
       @user = data

     .fail (xhr, status) =>
-      $(@usernameInput).trigger 'ajax:error', [xhr, status]
+      $(@usernameInput)
+        .trigger 'ajax:error', [xhr, status]
+        .one 'click', @onInput

     .always =>
       @searching = false


Tone down chat colors.

Tone down chat colors.

--- services/web/app/coffee/infrastructure/ExpressLocals.coffee
+++ services/web/app/coffee/infrastructure/ExpressLocals.coffee
@@ -302,8 +302,8 @@
 			westResizerCursor          : if isOl then "ew-resize" else null
 			chatResizerSizeOpen        : if isOl then 2 else 12
 			chatResizerSizeClosed      : 0
-			chatMessageBorderSaturation: if isOl then "100%" else "70%"
-			chatMessageBorderLightness : if isOl then "45%" else "70%"
-			chatMessageBgSaturation    : if isOl then "100%" else "60%"
-			chatMessageBgLightness     : if isOl then "45%" else "97%"
-		next()
+			chatMessageBorderSaturation: if isOl then "85%" else "70%"
+			chatMessageBorderLightness : if isOl then "40%" else "70%"
+			chatMessageBgSaturation    : if isOl then "85%" else "60%"
+			chatMessageBgLightness     : if isOl then "40%" else "97%"
+		next()


:lipstick: Move config defaults to top of exports

--- lib/whitespace.coffee
+++ lib/whitespace.coffee
@@ -1,9 +1,9 @@
 module.exports =
+  configDefaults:
+    ensureSingleTrailingNewline: true
+
   activate: ->
     rootView.eachEditSession (editSession) => @whitespaceBeforeSave(editSession)
-
-  configDefaults:
-    ensureSingleTrailingNewline: true

   whitespaceBeforeSave: (editSession) ->
     buffer = editSession.buffer


Test de actualización de la barra del navegador.

Obsérvese que no pasa en rekonq, por un fallo de rekonq.

--- spec/javascripts/jquery.paginator_spec.coffee
+++ spec/javascripts/jquery.paginator_spec.coffee
@@ -25,6 +25,12 @@
       request.response status: 200, responseText: '
Success!
'
       expect($('#list')).toHaveHtml request.responseText

+    it "updates the browser's address bar", ->
+      if browser_supports_history()
+        expect(location.href).toEqual link[0].href
+      else
+        expect(location.hash).toEqual link[0].href
+
     afterEach ->
       if browser_supports_history()
         history.replaceState(null, null, '/')


Add delta.attributes if absent in deltaHelper

--- lib/y-richtext.coffee
+++ lib/y-richtext.coffee
@@ -143,6 +143,10 @@
   #
   # @return [Integer] the position of the cursor after parsing the delta
   deltaHelper: (delta, position = 0) ->
+    # add delta.attributes if absent
+    if not delta.attributes?
+      delta.attributes = []
+
     val = (position) =>
       (@_get "characters").val(position)

@@ -166,7 +170,7 @@
         @insertHelper position, delta.insert
         from = val position
         to = val (position + delta.insert.length)
-        operation.call selections, from, to, delta.attributes
+        operation.call (@_get "selections"), from, to, delta.attributes
         return position + delta.insert.length

       else if delta.delete?


Don't destroy tracebacks in build_views()

--- bokehjs/src/coffee/common/build_views.coffee
+++ bokehjs/src/coffee/common/build_views.coffee
@@ -19,28 +19,24 @@
     #   the views constructor here, as an 'options' field in the dict
     # * options: any additional option to be used in the construction of views
     # * view_option: array, optional view specific options passed in to the construction of the view
-    "use strict";
+
     created_views = []
-    #debugger
-    try
-      newmodels = _.filter(view_models, (x) -> return not _.has(view_storage, x.id))
-    catch error
-      debugger
-      console.log(error)
-      throw error
+    newmodels = _.filter(view_models, (x) -> return not _.has(view_storage, x.id))
+
     for model, i_model in newmodels
       view_specific_option = _.extend({}, options, {'model': model})
-      try
-        if i_model < view_types.length
-          view_storage[model.id] = new view_types[i_model](view_specific_option)
-        else
-          view_storage[model.id] = new model.default_view(view_specific_option)
-      catch error
-        console.log("error on model of", model, error)
-        throw error
+
+      if i_model < view_types.length
+        view_storage[model.id] = new view_types[i_model](view_specific_option)
+      else
+        view_storage[model.id] = new model.default_view(view_specific_option)
+
       created_views.push(view_storage[model.id])
+
     to_remove = _.difference(_.keys(view_storage), _.pluck(view_models, 'id'))
+
     for key in to_remove
       view_storage[key].remove()
       delete view_storage[key]
+
     return created_views


test(docker): increase wait timeout

test(docker): increase wait timeout

--- packages/docker/test/test.coffee
+++ packages/docker/test/test.coffee
@@ -20,13 +20,14 @@
 they 'wait for docker daemon to listen', ({ssh}) ->
   # Note, this particularly apply to docker-compose environnements
   # where the daemon take some time to be up and running
-  # Wait 5s before timeout
+  # Wait 10s before timeout
+  # It takes some time under heavy load like testing in parallel
   nikita
     ssh: ssh
     docker: config.docker
   .execute.wait
     command: 'docker ps'
-    retry: 20
+    retry: 40
     interval: 250
 they 'cache image to avoid timeout later', ({ssh}) ->
   @timeout 0


Fix assignment_condition test.

Fix assignment_condition test.

--- test/features/assignment_condition.coffee
+++ test/features/assignment_condition.coffee
@@ -1,4 +1,4 @@
-unless (options = arguments[i])?
+if (options = arguments[i])?
   for x of y
     2 + 2
     3 + 3


refactor link applying method

refactor link applying method

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -164,6 +164,13 @@
 		$('#toolpad li:first-child').addClass 'toggled'
 	cancelLinkInput: ->
 		$('#toolpad li:first-child').removeClass 'toggled'
+	applyOrCancelUrl: (range, url)->
+		@selection().removeAllRanges()
+		@selection().addRange range
+		if url
+			document.execCommand('createlink', false, url)
+		else
+			document.execCommand('unlink', false)

 	delegateEvents: ()->
 		self = @
@@ -216,13 +223,7 @@
 				# self.lastLinkElement.setAttribute 'href', $(@).val()
 			if e.keyCode == 13
 				if self.linkRange
-					self.selection().removeAllRanges()
-					self.selection().addRange self.linkRange
-					url = $(@).val()
-					if url
-						document.execCommand('createlink', false, url)
-					else
-						document.execCommand('unlink', false)
+					self.applyOrCancelUrl self.linkRange, $(@).val()
 				self.hideToolpad()
 		$('#toolpad').delegate '.cancel', 'click', (e)=>
 			@cancelLinkInput()


Use filename as gridfs _id

Use filename as gridfs _id

--- packages/file/file.server.coffee
+++ packages/file/file.server.coffee
@@ -28,10 +28,11 @@
 		this.findOneSync = Meteor.wrapAsync this.store.collection(this.name).findOne.bind this.store.collection(this.name)

 	findOne: (fileName) ->
-		return this.findOneSync {filename: fileName}
+		return this.findOneSync {_id: fileName}

 	createWriteStream: (fileName, contentType) ->
 		return this.store.createWriteStream
+			_id: fileName
 			filename: fileName
 			mode: 'w'
 			root: this.name
@@ -39,7 +40,7 @@

 	createReadStream: (fileName) ->
 		return this.store.createReadStream
-			filename: fileName
+			_id: fileName
 			root: this.name
 		return undefined


Removed leftover newlines

Removed leftover newlines

--- test/unit/hooks-worker-client-test.coffee
+++ test/unit/hooks-worker-client-test.coffee
@@ -1,7 +1,6 @@
 describe 'Hooks worker client', () ->

   describe "when it's loaded", () ->
-

     describe 'when --language ruby option is given', () ->
       it 'should spawn the server process with command "dredd-worker-ruby"'
@@ -11,7 +10,6 @@
         it 'should exit with 1'
         it 'should write a hint how to install'

-
     describe 'when --language python option is given', () ->
       it 'should spawn the server process with command "dredd-worker-python"'
       it 'should pass --hookfiles option as a array of arguments'
@@ -19,7 +17,6 @@
       describe 'when the worker  is not installed', () ->
         it 'should exit with 1'
         it 'should write a hint how to install'
-

     describe 'when --language ./eny/other-command is giveb', () ->
       it 'should run this command given as language option'
@@ -32,8 +29,9 @@

     it 'should connect to the server'

-    it 'should assign the client under "hookClient" on the hook object'
-    it 'should assign the spawned server under "hookServer" on the hook object'
+    it 'should assign the client under "worker" on the hook object'
+
+    it 'should assign the spawned server under "workerClient" on the hook object'

     eventTypes = [
       'before'


copy pasta mistake

copy pasta mistake

--- src/browser/auto-updater-win32.coffee
+++ src/browser/auto-updater-win32.coffee
@@ -15,9 +15,10 @@

   quitAndInstall: ->
     updateDotExe = path.join(path.dirName(process.execPath), '..', 'update.exe')
-      unless fs.existsSync(updateDotExe)
-        console.log 'Running developer or Chocolatey version of Atom, skipping'
-        return
+
+    unless fs.existsSync(updateDotExe)
+      console.log 'Running developer or Chocolatey version of Atom, skipping'
+      return

     updateOutput = ""
     ps = new BufferedProcess


Add spec for onRedirectionError option

Add spec for onRedirectionError option

--- src/coffee/bootstrap-tour.spec.coffee
+++ src/coffee/bootstrap-tour.spec.coffee
@@ -626,6 +626,18 @@
     @tour.prev()
     expect(tour_test).toBe 2 # tour runs onPrev when prev step is called

+  it 'with `onRedirectError` option should run the callback when redirection failed', ->
+    tour_test = 0
+    @tour = new Tour
+    @tour.addStep
+      element: $('

').appendTo('body')
+      path: '/path'
+      onRedirectError: -> tour_test = 2
+
+    @tour._setState 'redirect_to', 0 # tour has previously redirected to step '0'
+    @tour.start()
+    expect(tour_test).toBe 2 # tour runs onRedirectError when redirection failed
+
   it 'should render custom navigation template', ->
     @tour = new Tour
       template:


Tag::query() cache purging mechanism added

--- Element/element/tag/query.coffee
+++ Element/element/tag/query.coffee
@@ -173,7 +173,10 @@
 OPTS_REVERSED = 1<<(i++)
 OPTS_ADD_ANCHOR = 1<<(i++)

+MAX_QUERIES_CACHE_LENGTH = 2000
+QUERIES_CACHE_OVERFLOW_REDUCTION = 100
 queriesCache = []
+queriesCacheLengths = []
 getQueries = (selector, opts=0) ->
 	reversed = !!(opts & OPTS_REVERSED)

@@ -263,8 +266,20 @@
 			funcs[reversedArrFunc] byTag, null, null

 	# save to the cache
-	queriesCache[opts] ?= {}
-	queriesCache[opts][selector] = queries
+	unless cache = queriesCache[opts]
+		cache = queriesCache[opts] = {}
+		queriesCacheLengths[opts] = 0
+	cache[selector] = queries
+
+	# clean cache if needed
+	if (queriesCacheLengths[opts] += 1) > MAX_QUERIES_CACHE_LENGTH
+		removed = 0
+		for key of cache
+			delete cache[key]
+			removed += 1
+			if removed >= QUERIES_CACHE_OVERFLOW_REDUCTION
+				break
+		queriesCacheLengths[opts] -= removed

 	queries


Tag::watch bug fixed

Tag::watch bug fixed

--- Element/element/tag/query.coffee
+++ Element/element/tag/query.coffee
@@ -319,7 +319,7 @@
 				if watcher is null
 					watchers.splice i, 1
 					i--; n--
-				else if watcher.test(tag)
+				else if (not tag._inWatchers or !utils.has(tag._inWatchers, watcher)) and watcher.test(tag)
 					tag._inWatchers ?= []
 					tag._inWatchers.push watcher
 					emitSignal watcher, 'onAdd', tag


add key to grid layout

add key to grid layout

--- app/builtins.coffee
+++ app/builtins.coffee
@@ -181,8 +181,8 @@
       if i % cols == 0
         row = []
         rows.push row
-      row.push React.DOM.div {style: {flex: 1}}, component
-    React.DOM.div null, _.map rows, (row) -> React.DOM.div {style: {display: 'flex'}}, row
+      row.push React.DOM.div {style: {flex: 1}, key: i}, component
+    React.DOM.div null, _.map rows, (row, i) -> React.DOM.div {key: i, style: {display: 'flex'}}, row

 FlowComponent = React.createClass
   displayName: 'FlowComponent'


DB fixed to be the same database that the ruby server posts to. Hash fixed to not include the {job:} prefix. Mimics cloudq_client.

--- lib/cloudq.coffee
+++ lib/cloudq.coffee
@@ -7,7 +7,7 @@
   EMPTY: 'empty'
   SUCCESS: 'success'

-  constructor: (db = 'localhost:27017/cloudq', collection_name = 'jobs') ->
+  constructor: (db = 'localhost:27017/cloudq', collection_name = 'cloudq.jobs') ->
     # Init MongoDb
     @db = mongo.db(db)
     @jobs = @db.collection(collection_name)
@@ -23,7 +23,7 @@
       if job
         job.workflow_state = @RESERVED
         @jobs.updateById job._id, job
-        result = { job: job }
+        result = job
       callback result

   remove: (id, callback) ->


port shallow build sorting to js so that we can include running builds

--- js/inner/project.coffee
+++ js/inner/project.coffee
@@ -134,14 +134,22 @@
     @toggle_show_all_branches = () =>
       @show_all_branches(!@show_all_branches())

+    @sorted_builds = (branch_name) =>
+      if @branches()[branch_name]
+        recent = @branches()[branch_name].recent_builds or []
+        running = @branches()[branch_name].running_builds or []
+        recent.concat(running).sort(@buildSort)
+      else
+        []
+
     @latest_branch_build = (branch_name) =>
-      if @branches()[branch_name] and @branches()[branch_name].recent_builds
-        new CI.inner.Build(@branches()[branch_name].recent_builds[0])
+      build = @sorted_builds(branch_name)[0]
+      if build
+        new CI.inner.Build(build)

     @recent_branch_builds = (branch_name) =>
-      builds = if @branches()[branch_name] and @branches()[branch_name].recent_builds
-        new CI.inner.Build(b) for b in @branches()[branch_name].recent_builds
-      if builds then builds.reverse()
+      builds = @sorted_builds(branch_name).reverse()[0..4]
+      new CI.inner.Build(b) for b in builds

     @build_path = (build_num) =>
       @project_path() + "/" + build_num
@@ -166,6 +174,35 @@
       1
     else
       if l.vcs_url().toLowerCase() > r.vcs_url().toLowerCase() then 1 else -1
+
+  @buildTimeSort: (l, r) ->
+    if !l.pushed_at and !r.pushed_at
+      0
+    else if !l.pushed_at
+      1
+    else if !r.pushed_at
+      -1
+    else if new Date(l.pushed_at) > new Date(r.pushed_at)
+      -1
+    else if new Date(l.pushed_at) < new Date(r.pushed_at)
+      1
+    else
+      0
+
+  @buildNumSort: (l, r) ->
+    if l.build_num > r.build_num
+      -1
+    else if l.build_num < r.build_num
+      1
+    else
+      0
+
+  @buildSort: (l, r) ->
+    time_sort = @buildTimeSort(l, r)
+    if time_sort is 0
+      @buildNumSort(l, r)
+    else
+      time_sort

   compute_latest_build: () =>
     if @branches()? and @branches()[@default_branch()] and @branches()[@default_branch()].recent_builds?


Tweak fire control timers a bit

Tweak fire control timers a bit

--- app/js/utils.coffee
+++ app/js/utils.coffee
@@ -5,26 +5,23 @@
   targeting: false

 window.FireControls = class FireControls
-  keys: [ "main", "spread", "bfg" ]
   timeouts:
     default: 0.15
     bfg: 0.5
-  timers: {}

   fireMain: false
   fireBFG: false
   fireSpread: false

   constructor: ->
-    for key in @keys
-      @timers[key] = 0
+    @timers = {}

   update: (dt) ->
-    @timers[key] -= dt for key in @keys when @timers[key] > 0
+    @timers[key] = value - dt for key, value of @timers when value > 0

   fire: (weapon) ->
-    if @timers[weapon] <= 0
-      before = @timers[weapon] # account for time already served
+    if not @timers[weapon]? or @timers[weapon] <= 0
+      before = @timers[weapon] or 0 # account for time already served
       @timers[weapon] = (@timeouts[weapon] or @timeouts["default"]) + before
       true
     else


Relax rules around Bob Ross

Relax rules around Bob Ross

--- scripts/nostalgia.coffee
+++ scripts/nostalgia.coffee
@@ -205,7 +205,7 @@
     robot.respond /guess (.*)/i, guessRespond
     robot.respond /end guess who/i, endGuessWhoRespond

-    robot.hear /.*I found a bug.*/i, (res) ->
+    robot.hear /.*a bug.*/i, (res) ->
         res.send "There are no bugs, just happy little accidents!"
         res.send "http://a2.files.biography.com/image/upload/c_fit,cs_srgb,dpr_1.0,q_80,w_620/MTI1NDg4NTg2MDAxODA1Mjgy.jpg"


fix for RN 0.14.2

fix for RN 0.14.2

--- natal.coffee
+++ natal.coffee
@@ -20,7 +20,7 @@
 camelRx         = /([a-z])([A-Z])/g
 projNameRx      = /\$PROJECT_NAME\$/g
 projNameHyphRx  = /\$PROJECT_NAME_HYPHENATED\$/g
-rnVersion       = '0.13.0'
+rnVersion       = '0.14.2'
 rnPackagerPort  = 8081
 podMinVersion   = '0.38.2'
 process.title   = 'natal'
@@ -227,7 +227,7 @@
     exec "
          node -e
          \"process.argv[3]='#{projName}';
-         require('react-native/local-cli/init')('.', '#{projName}')\"
+         require('react-native/local-cli/cli').init('.', '#{projName}')\"
          "

     exec 'rm -rf android'


Fix user register

Fix user register

--- www/client/user/controllers/login.coffee
+++ www/client/user/controllers/login.coffee
@@ -11,5 +11,7 @@

   $scope.createUser = ->
     ImprovedUser.create
+      firstName: $scope.createFirstName
+      lastName: $scope.createLastName
       email: $scope.createEmail
       password: $scope.createPassword


Remove unnecesary code from issues controller.

--- app/coffee/controllers/issues.coffee
+++ app/coffee/controllers/issues.coffee
@@ -55,14 +55,12 @@
         generateStatusTags()

     filterIssues = ->
-        console.log "filterIssues"
         for issue in $scope.issues
             issue.__hidden = false

         # Filter by generic tags
         selectedTags = _.filter($scope.tags, "selected")
         selectedTagsIds = _.map(selectedTags, "name")
-        console.log selectedTagsIds

         if selectedTagsIds.length > 0
             for item in $scope.issues
@@ -95,7 +93,6 @@
         groupToPages()

     groupToPages = ->
-        console.log "groupToPages"
         $scope.pagedItems = []

         issues = _.reject($scope.issues, "__hidden")
@@ -108,21 +105,17 @@
                 $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push(issue)

     $scope.prevPage = ->
-        console.log "prevPage"
         if $scope.currentPage > 0
             $scope.currentPage--

     $scope.nextPage = ->
-        console.log "nextPage"
         if $scope.currentPage < ($scope.pagedItems.length - 1)
             $scope.currentPage++

     $scope.setPage = ->
-        console.log "setPage"
         $scope.currentPage = this.n

     $scope.range = (start, end) ->
-        console.log "range"
         ret = []
         if not end?
             end = start
@@ -140,18 +133,22 @@
     $scope.$watch("sortingOrder", groupToPages)
     $scope.$watch("reverse", groupToPages)

-    $q.all([
+    promise = $q.all([
         rs.getIssueTypes(projectId),
         rs.getIssueStatuses(projectId),
         rs.getSeverities(projectId),
         rs.getPriorities(projectId),
-        rs.getUsers(projectId)
-    ]).then((results) ->
+        rs.getUsers(projectId),
+        rs.getIssues(projectId)
+    ])
+
+    promise = promise.then (results) ->
         issueTypes = results[0]
         issueStatuses = results[1]
         severities = results[2]
         priorities = results[3]
         users = results[4]
+        issues = results[5]

         _.each(users, (item) -> $rootScope.constants.users[item.id] = item)
         _.each(issueTypes, (item) -> $rootScope.constants.type[item.id] = item)
@@ -165,12 +162,9 @@
         $rootScope.constants.priorityList = _.sortBy(priorities, "order")
         $rootScope.constants.usersList = _.sortBy(users, "id")

-        return rs.getIssues(projectId)
-    ).then((issues) ->
         $scope.issues = issues
         regenerateTags()
         filterIssues()
-    )

     $scope.updateIssueAssignation = (issue, id) ->
         issue.assigned_to = id || null


Update animals' characteristics

Update animals' characteristics


allow env vars set through ~/.atom/.env

allow env vars set through ~/.atom/.env

--- lib/config.coffee
+++ lib/config.coffee
@@ -3,6 +3,10 @@

 require('dotenv').config
   path: path.join(__dirname, '..', '.env')
+  silent: true
+
+require('dotenv').config
+  path: path.join(atom.getConfigDirPath(), '.env')
   silent: true

 module.exports = _.defaults


changed api host for production

changed api host for production

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -3,7 +3,7 @@
 if window.location.host.match /angellist\.magnetar\.lxc.*/
   api_host = "angellist.magnetar.lxc:3000"
 else
-  api_host = "startups-cologne-api.herokuapp.com"
+  api_host = "piratesinn-startups.yggdrasil.teemow.com"

 angular.module('configuration', [])
   .value("API", api_host)


Add controllers to states

Add controllers to states

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -22,15 +22,18 @@
     $stateProvider
       .state('home', {
         url: '/',
-        templateUrl: 'views/main.html'
+        templateUrl: 'views/main.html',
+        controller: 'MainCtrl'
         })
       .state('contact', {
         url: '/contact',
-        templateUrl: 'views/contact.html'
+        templateUrl: 'views/contact.html',
+        controller: 'ContactCtrl'
         })
       .state('login', {
         url: '/login',
-        templateUrl: 'views/login.html'
+        templateUrl: 'views/login.html',
+        controller: 'LoginCtrl'
         })
       .state('user', {


Bind company with user.

Bind company with user.

--- app/lib/collections/companies.coffee
+++ app/lib/collections/companies.coffee
@@ -19,3 +19,9 @@
   remove: denyChecker

 Companies.attachSchema schemas.Company
+
+Companies.after.insert (userId, doc) ->
+  user = Meteor.users.findOne _id: userId
+  if user
+     Meteor.users.update userId, $push:
+       'profile.companies': doc._id


fix(karma.conf): No logging to file on Travis (for now)

Need to figure out where we can log to.

--- karma.conf.coffee
+++ karma.conf.coffee
@@ -30,7 +30,9 @@
     if process.env.TRAVIS
         config.transports = 'xhr-polling'
         # Debug logging into a file, that we print out at the end of the build.
+        ###
         config.loggers.push
             type: 'file'
             filename: process.env.LOGS_DIR + '/' + options.logFile || 'karma.log'
             level: config.LOG_DEBUG
+        ###


fixed watch generate

fixed watch generate

--- lib/docpad.coffee
+++ lib/docpad.coffee
@@ -506,11 +506,11 @@
 		# Watch the src directory
 		watcher = require('watch-tree').watchTree(docpad.srcPath)
 		watcher.on 'fileDeleted', (path) ->
-			docpad.generate ->
+			docpad.generateAction ->
 		watcher.on 'fileCreated', (path,stat) ->
-			docpad.generate ->
+			docpad.generateAction ->
 		watcher.on 'fileModified', (path,stat) ->
-			docpad.generate ->
+			docpad.generateAction ->

 		# Log
 		console.log 'Watching setup'


Fixes missing ) and type error

Fixes missing ) and type error

--- lib/ensime.coffee
+++ lib/ensime.coffee
@@ -100,7 +100,7 @@
       order: 120
     enableAutoInstallOfDependencies:
       description: "Enable auto install of dependencies"
-      type: boolean
+      type: 'boolean'
       default: true
       order: 130

@@ -132,11 +132,11 @@
     @startedCommands.add atom.commands.add 'atom-workspace', "ensime:import-suggestion", => @getImportSuggestions()
     @startedCommands.add atom.commands.add 'atom-workspace', "ensime:organize-imports", => @organizeImports()

-
+

   activate: (state) ->
     logLevel = atom.config.get('Ensime.logLevel')
-
+
     log.getLogger('ensime.client').setLevel(logLevel)
     log.getLogger('ensime.server-update').setLevel(logLevel)
     log.getLogger('ensime.startup').setLevel(logLevel)
@@ -144,9 +144,9 @@
     log.getLogger('ensime.refactorings').setLevel(logLevel)
     log = log.getLogger('ensime.main')
     log.setLevel(logLevel)
-
+
     # Install deps if not there
-    if(atom.config.get('Ensime.eenableAutoInstallOfDependencies')
+    if(atom.config.get('Ensime.eenableAutoInstallOfDependencies'))
       (require 'atom-package-deps').install('Ensime').then ->
         log.trace('Ensime dependencies installed, good to go!')

@@ -161,7 +161,7 @@

     @addCommandsForStoppedState()
     @someInstanceStarted = false
-
+
     @controlSubscription = atom.workspace.observeTextEditors (editor) =>
       if isScalaSource(editor)
         instanceLookup = => @instanceManager.instanceOfFile(editor.getPath())
@@ -182,7 +182,6 @@
         instance = @instanceManager.instanceOfFile(pane.getPath())
         @switchToInstance(instance)

-
   switchToInstance: (instance) ->
     log.trace(['changed from ', @activeInstance, ' to ', instance])
     if(instance != @activeInstance)
@@ -192,7 +191,7 @@
       if(instance)
         instance.statusbarView.show()

-
+
   deactivate: ->
     @instanceManager.destroyAll()

@@ -249,18 +248,18 @@

     # remove start command and add others
     @stoppedCommands.dispose()
-
+
     # FIXME: - we have had double commands for each instance :) This is a quick and dirty fix
     if(not @someInstanceStarted)
       @addCommandsForStartedState()
       @someInstanceStarted = true
-
+
     dotEnsime = parseDotEnsime(dotEnsimePath)

     typechecking = undefined
     if(@indieLinterRegistry)
       typechecking = TypeCheckingFeature(@indieLinterRegistry.register("Ensime: #{dotEnsimePath}"))
-
+
     statusbarView = new StatusbarView()
     statusbarView.init()

@@ -311,7 +310,7 @@
     promise.then (dotEnsimesUnflattened) ->
       dotEnsimes = ({path: path} for path in _.flattenDeep(dotEnsimesUnflattened))
       filteredDotEnsime = _.filter(dotEnsimes, filter)
-
+
       if(filteredDotEnsime.length == 0)
         modalMsg("No .ensime file found. Please generate with `sbt gen-ensime` or similar")
       else if (filteredDotEnsime.length == 1)
@@ -398,7 +397,7 @@
             provider.getCompletions(editor.getBuffer(), bufferPosition, resolve)
         else
           []
-
+
       onDidInsertSuggestion: (x) ->
         provider = getProvider()
         provider.onDidInsertSuggestion x
@@ -425,11 +424,11 @@
           undefined

     }
-
+
   # Just add registry to delegate registration on instances
   consumeLinter: (@indieLinterRegistry) ->
-
-
+
+
   formatCurrentSourceFile: ->
     editor = atom.workspace.getActiveTextEditor()
     cursorPos = editor.getCursorBufferPosition()
@@ -437,7 +436,7 @@
       editor.setText(msg.text)
       editor.setCursorBufferPosition(cursorPos)
     @clientOfEditor(editor)?.formatSourceFile(editor.getPath(), editor.getText(), callback)
-
+

   searchPublicSymbol: ->
     unless @publicSymbolSearch


Exclude non-selected code language documentation blocks from level guides

--- app/views/play/menu/GuideView.coffee
+++ app/views/play/menu/GuideView.coffee
@@ -41,7 +41,7 @@
     @docs = specific.concat(general)
     @docs = $.extend(true, [], @docs)
     @docs = [@docs[0]] if @firstOnly and @docs[0]
-    doc.html = marked(utils.i18n doc, 'body') for doc in @docs
+    doc.html = marked(@filterCodeLanguages(utils.i18n(doc, 'body'))) for doc in @docs
     doc.name = (utils.i18n doc, 'name') for doc in @docs
     doc.slug = _.string.slugify(doc.name) for doc in @docs
     super()
@@ -71,6 +71,12 @@
       @$el.find('.tab-content .tab-pane:first').addClass('active')
       @$el.find('.nav-tabs a').click(@clickTab)
     @playSound 'guide-open'
+
+  filterCodeLanguages: (text) ->
+    currentLanguage = me.get('aceConfig')?.language or 'python'
+    excludedLanguages = _.without ['javascript', 'python', 'coffeescript', 'clojure', 'lua', 'io'], currentLanguage
+    exclusionRegex = new RegExp "```(#{excludedLanguages.join('|')})\n[^`]+```\n?", 'gm'
+    text.replace exclusionRegex, ''

   clickSubscribe: (e) ->
     level = @levelSlug # Save ref to level slug


Add 'Your build has been stopped' to texts which expand folds

--- assets/scripts/lib/travis/log.coffee
+++ assets/scripts/lib/travis/log.coffee
@@ -75,7 +75,7 @@

         @initial = false

-        if payload.foldContinuation && payload.content.match(/Done. Build script exited/)
+        if payload.foldContinuation && payload.content.match(/Done. Build script exited|Your build has been stopped/)
           # script ended, but fold is still closed, which most probably means
           # error, end the fold and open it.
           # TODO: we need log marks to make it easier


change number of args

change number of args

--- lib/browse.coffee
+++ lib/browse.coffee
@@ -112,12 +112,15 @@
     switch process.platform
       when "darwin"
          exec "open -R #{path}"
+         fileManager = "Finder"
       when "win32"
         exec "explorer /select,#{path}"
+        fileManager = "Explorer"
       when "linux"
         shell.showItemInFolder(path)
+        fileManager = "file manager"

-    @isVerbose("Revealed", path)
+    @isVerbose("Revealed", path, fileManager)

   openFolder: (path) ->
     # Custom file manager
@@ -131,26 +134,20 @@
     switch process.platform
       when "darwin"
         exec "open #{path}"
+        fileManager = "Finder"
       when "win32"
         exec "explorer #{path}"
+        fileManager = "Explorer"
       when "linux"
         shell.openItem(path)
+        fileManager = "file manager"

-    @isVerbose("Opened", path)
+    @isVerbose("Opened", path, fileManager)

-  isVerbose: (verb, fullPath) ->
+  isVerbose: (verb, fullPath, fileManager) ->
     if atom.config.get('browse.notify') is true
       # Get base name
       path = require 'path'
       baseName = path.basename(fullPath)

-      # Default file manager
-      switch process.platform
-        when "darwin"
-          fileManager = "Finder"
-        when "win32"
-          fileManager = "Explorer"
-        when "linux"
-          fileManager = "file manager"
-
       atom.notifications.addInfo("**#{@self}**: #{verb} `#{baseName}` in #{fileManager}", dismissable: false)


refactor

refactor

--- lib/browse.coffee
+++ lib/browse.coffee
@@ -1,9 +1,5 @@
-{CompositeDisposable} = require 'atom'
-
-# Dependencies
-{spawnSync} = require('child_process')
-fs = require 'fs'
-shell = require 'shell'
+{ name } = require "../package.json"
+{ CompositeDisposable } = require "atom"

 module.exports = BrowsePackages =
   config:
@@ -17,33 +13,34 @@
       description: "Show info notifications for all actions"
       type: "boolean"
       default: false
-  self: 'browse'
   subscriptions: null

   activate: ->
-    # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
+    # Events subscribed to in Atom's system can be easily cleaned up with a CompositeDisposable
     @subscriptions = new CompositeDisposable

     # Register command that toggles this view
-    @subscriptions.add atom.commands.add 'atom-workspace', 'browse:configuration-folder': => @browseConfig()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'browse:packages-folder': => @browsePackages()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'browse:project-folders': => @browseProjects()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'browse:reveal-file': => @revealFile()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'browse:reveal-all-open-files': => @revealFiles()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:configuration-folder": => @browseConfig()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:packages-folder": => @browsePackages()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:project-folders": => @browseProjects()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-file": => @revealFile()
+    @subscriptions.add atom.commands.add "atom-workspace", "#{name}:reveal-all-open-files": => @revealFiles()

   deactivate: ->
     @subscriptions?.dispose()
     @subscriptions = null

   browsePackages: ->
+    { accessSync, F_OK } = require "fs"
+
     packageDirs = atom.packages.getPackageDirPaths()

     for packageDir in packageDirs
       # Does packages folder exist?
       try
-        fs.accessSync(packageDir, fs.F_OK)
+        accessSync(packageDir, F_OK)
       catch error
-        atom.notifications.addError(@self, detail: error, dismissable: true)
+        atom.notifications.addError(name, detail: error, dismissable: true)

       # Open packages folder
       @openFolder(packageDir)
@@ -52,14 +49,14 @@
     # Get parent folder of active file
     editor = atom.workspace.getActivePaneItem()

-    if editor?.constructor.name is 'TextEditor' or editor?.constructor.name is 'ImageEditor'
+    if editor?.constructor.name is "TextEditor" or editor?.constructor.name is "ImageEditor"
       file = if editor?.buffer?.file then editor.buffer.file else if editor?.file then editor.file

       if file?.path
         @selectFile(file.path)
         return

-    atom.notifications.addWarning("**#{@self}**: No active file", dismissable: false)
+    atom.notifications.addWarning("**#{name}**: No active file", dismissable: false)

   revealFiles: ->
     # Get all open file
@@ -68,7 +65,7 @@
     if editors.length > 0
       count = 0
       for editor in editors
-        continue unless editor.constructor.name is 'TextEditor' or editor.constructor.name is 'ImageEditor'
+        continue unless editor.constructor.name is "TextEditor" or editor.constructor.name is "ImageEditor"

         file = if editor?.buffer?.file then editor.buffer.file else if editor?.file then editor.file

@@ -78,14 +75,13 @@

       return if count > 0

-    atom.notifications.addWarning("**#{@self}**: No open files", dismissable: false)
+    atom.notifications.addWarning("**#{name}**: No open files", dismissable: false)

   browseProjects: ->
+    { accessSync, F_OK } = require "fs"
+
     projects = atom.project.getPaths()
-
-    unless projects.length > 0
-      atom.notifications.addWarning("**#{@self}**: No active project", dismissable: false)
-      return
+    return atom.notifications.addWarning("**#{name}**: No active project", dismissable: false) unless projects.length > 0

     for project in projects
       # Skip Atom dialogs
@@ -94,79 +90,76 @@

       # Does project folder exist?
       try
-        fs.accessSync(project, fs.F_OK)
+        accessSync(project, F_OK)
       catch
-        atom.notifications.addError(@self, detail: error, dismissable: true)
+        atom.notifications.addError(name, detail: error, dismissable: true)
         continue

       # Open project folder
       @openFolder(project)

   browseConfig: ->
-    path = require 'path'
+    { accessSync, F_OK } = require "fs"
+    { dirname } = require "path"

     configFile = atom.config.getUserConfigPath()
-    configPath = path.dirname(configFile)
+    configPath = dirname(configFile)

     if configPath
       # Does config folder exist?
       try
-        fs.accessSync(configPath, fs.F_OK)
+        accessSync(configPath, F_OK)
       catch error
-        atom.notifications.addError(@self, detail: error, dismissable: true)
+        atom.notifications.addError(name, detail: error, dismissable: true)
         return

       # Open config folder
       @openFolder(configPath)

   selectFile: (path) ->
+    { basename } = require "path"
+
     # Custom file manager
-    fileManager = atom.config.get('browse.fileManager')
-
-    if fileManager
-      spawnSync fileManager, [ path ]
-      return
+    fileManager = atom.config.get("#{name}.fileManager")
+    return @spawnCmd fileManager, [ path ], basename(path), "file manager" if fileManager

     # Default file manager
     switch process.platform
       when "darwin"
-        spawnSync "open", [ "-R", path ]
-        fileManager = "Finder"
+        @spawnCmd "open", [ "-R", path ], basename(path), "Finder"
       when "win32"
-        spawnSync "explorer", [ "/select,#{path}" ]
-        fileManager = "Explorer"
+        @spawnCmd "explorer", [ "/select,#{path}" ], basename(path), "Explorer"
       when "linux"
-        shell.showItemInFolder(path)
-        fileManager = "file manager"
-
-    @isVerbose("Revealed", path, fileManager)
+        { showItemInFolder } = require "shell"
+        showItemInFolder(path)
+        atom.notifications.addInfo("**#{name}**: Opened `#{basename(path)}` in file manager", dismissable: false)

   openFolder: (path) ->
+    { basename } = require "path"
+
     # Custom file manager
-    fileManager = atom.config.get('browse.fileManager')
-
-    if fileManager
-      spawnSync fileManager, [ path ]
-      return
+    fileManager = atom.config.get("#{name}.fileManager")
+    return @spawnCmd fileManager, [ path ], basename(path), "file manager" if fileManager

     # Default file manager
     switch process.platform
       when "darwin"
-        spawnSync "open", [ path ]
-        fileManager = "Finder"
+        @spawnCmd "open", [ path ], basename(path), "Finder"
       when "win32"
-        spawnSync "explorer", [ path ]
-        fileManager = "Explorer"
+        @spawnCmd "explorer", [ path ], basename(path), "Explorer"
       when "linux"
-        shell.openItem(path)
-        fileManager = "file manager"
+        { openItem } = require "shell"
+        openItem(path)
+        atom.notifications.addInfo("**#{name}**: Opened `#{basename(path)}` in file manager", dismissable: false)

-    @isVerbose("Opened", path, fileManager)
+  spawnCmd: (cmd, args, baseName, fileManager) ->
+    { spawn } = require("child_process")

-  isVerbose: (verb, fullPath, fileManager) ->
-    if atom.config.get('browse.notify') is true
-      # Get base name
-      path = require 'path'
-      baseName = path.basename(fullPath)
+    open = spawn cmd, args

-      atom.notifications.addInfo("**#{@self}**: #{verb} `#{baseName}` in #{fileManager}", dismissable: false)
+    open.stderr.on "data", (error) ->
+       atom.notifications.addError("**#{name}**: #{error}", dismissable: true)
+
+    open.on "close", ( errorCode ) ->
+      if errorCode is 0 and atom.config.get("#{name}.notify")
+        atom.notifications.addInfo("**#{name}**: Opened `#{baseName}` in #{fileManager}", dismissable: false)


remove log command

remove log command

--- lib/client.coffee
+++ lib/client.coffee
@@ -20,9 +20,6 @@
   getServerProcess: (callback) ->
     forever.list false, (e, processes) =>
       callback?(forever.findByScript(@serverPath, processes))
-
-  tailLog: ->
-

   start: (callback) ->
     pollStatus = =>


cleanup

cleanup

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -77,11 +77,10 @@

   modifySelections: (fn) ->
     wasVisual = @isMode('visual')
-    console.log 'b', @editor.getCursorBufferPosition()
+    # console.log 'b', @editor.getCursorBufferPosition()
     @vimState.modeManager.normalizeSelections() if wasVisual
-    console.log 'a', @editor.getCursorBufferPosition()
-    # console.log 'before', @editor.getLastSelection().getText(), getLengthForRange(@editor.getSelectedBufferRange())
-    console.log @editor.getLastSelection().isEmpty()
+    # console.log 'a', @editor.getCursorBufferPosition()
+    # console.log @editor.getLastSelection().isEmpty()

     fn()

@@ -120,24 +119,23 @@
   selectInclusively: (selection) ->
     {cursor} = selection
     originalPoint = cursor.getBufferPosition()
-    # save tailRange(range under cursor) before we start to modify selection
     tailRange = swrap(selection).getTailBufferRange()

     selection.modifySelection =>
       @moveCursor(cursor)

     cursorMoved = not cursor.getBufferPosition().isEqual(originalPoint)
+    return unless cursorMoved or @isMode('visual')

     if @isMode('visual') and cursorIsAtEndOfLineAtNonEmptyRow(cursor)
       swrap(selection).translateSelectionEndAndClip('backward')

-    if @isMode('visual') or cursorMoved
-      unless selection.isReversed()
-        # When cursor is at empty row, we allow to wrap to next line
-        # since when we `v`, we have to select line.
-        swrap(selection).translateSelectionEndAndClip('forward', hello: 'in select inclusive')
-
-      swrap(selection).mergeBufferRange(tailRange, {preserveFolds: true})
+    unless selection.isReversed()
+      # When cursor is at empty row, we allow to wrap to next line
+      # since when we `v`, we have to select line.
+      swrap(selection).translateSelectionEndAndClip('forward', hello: 'in select inclusive')
+
+    swrap(selection).mergeBufferRange(tailRange, {preserveFolds: true})

 # Used as operator's target in visual-mode.


Shuts Travis up

Shuts Travis up

--- lib/config.coffee
+++ lib/config.coffee
@@ -4,7 +4,7 @@
 CSON = require 'cson'
 {log, warn, error} = require './utils'

-{ROOT, EXROOT} = global
+{ROOT, EXROOT, dbg} = global

 config = null
 configCache = {}


Simplification

Simplification

--- lib/schema.coffee
+++ lib/schema.coffee
@@ -33,21 +33,23 @@
     model_name2 = inflection.pluralize(inflection.underscore(relation.reverse_relation.model_type.model_name))
     return if model_name1.localeCompare(model_name2) < 0 then "#{model_name1}_#{model_name2}" else "#{model_name2}_#{model_name1}"

-  @joinTableModelName: (relation) -> inflection.classify(inflection.singularize(Schema.joinTableURL(relation)))
-
   generateJoinTable: (relation) ->
     schema = {}
     schema[relation.foreign_key] = ['Integer', indexed: true]
     schema[relation.reverse_relation.foreign_key] = ['Integer', indexed: true]
+    url = Schema.joinTableURL(relation)
+    name = inflection.pluralize(inflection.classify(url))

     try
       class JoinTable extends Backbone.Model
-        urlRoot: "#{Utils.parseUrl(_.result(relation.model_type.prototype, 'url')).database_path}/#{Schema.joinTableURL(relation)}"
+        @model_name: name
+        urlRoot: "#{Utils.parseUrl(_.result(relation.model_type.prototype, 'url')).database_path}/#{url}"
         @schema: schema
         sync: relation.model_type.createSync(JoinTable)
     catch
       class JoinTable extends Backbone.Model
-        urlRoot: "/#{Schema.joinTableModelName(relation)}"
+        @model_name: name
+        urlRoot: "/#{url}"
         @schema: schema
         sync: relation.model_type.createSync(JoinTable)


Set logger tag

Set logger tag

--- lib/server.coffee
+++ lib/server.coffee
@@ -35,7 +35,7 @@
 start = (config) ->
   # Logger: log4js
   log4js.configure(__dirname + '/../config/logging.json')
-  logger = log4js.getLogger()
+  logger = log4js.getLogger("www")

   # App: express
   app = express.createServer()


fix references to backbone.paginator and handlebars to use vendor path

--- lib/teeble.coffee
+++ lib/teeble.coffee
@@ -1,5 +1,5 @@
 # = require './setup'
-# = require './lib/backbone.paginator'
-# = require './lib/handlebars'
+# = require '../vendor/backbone.paginator'
+# = require '../vendor/handlebars'
 # = require './table-renderer'
-# = require './views/table_view'+# = require './views/table_view'


#8 move linewisely in visual-linewise mode.

Fortunately no spec broken.

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -186,16 +186,28 @@
   linewise: true

   moveCursor: (cursor) ->
+    isSoftWrapped = @editor.isSoftWrapped()
+    isVisualMode    = @vimState.isMode('visual', 'linewise')
     @countTimes =>
-      cursor.moveUp() unless @at('FirstScreenRow', cursor)
+      return if @at('FirstScreenRow', cursor)
+      if isVisualMode and isSoftWrapped and (not cursor.selection.isReversed())
+        point = cursor.selection.getHeadBufferPosition()
+        cursor.setBufferPosition([point.row, 0])
+      cursor.moveUp()

 class MoveDown extends Motion
   @extend()
   linewise: true

   moveCursor: (cursor) ->
+    isSoftWrapped = @editor.isSoftWrapped()
+    isVisualMode    = @vimState.isMode('visual', 'linewise')
     @countTimes =>
-      cursor.moveDown() unless @at('LastScreenRow', cursor)
+      return if @at('LastScreenRow', cursor)
+      if isVisualMode and isSoftWrapped and cursor.selection.isReversed()
+        point = cursor.selection.getHeadBufferPosition()
+        cursor.setBufferPosition([point.row, Infinity])
+      cursor.moveDown()

 class MoveToPreviousWord extends Motion
   @extend()