jupyter: basic nbviewer without graphics

--- src/smc-webapp/jupyter/nbviewer-actions.coffee
+++ src/smc-webapp/jupyter/nbviewer-actions.coffee
@@ -10,6 +10,8 @@
 immutable = require('immutable')

 util = require('./util')
+
+{IPynbImporter} = require('./import-from-ipynb')

 class exports.NBViewerActions extends Actions
     _init: (project_id, path, store, client) =>
@@ -44,15 +46,18 @@
                     @set_from_ipynb(ipynb)

     set_from_ipynb: (ipynb) =>
-        cells      = immutable.Map()
+        importer = new IPynbImporter()
+        importer.import
+            ipynb   : ipynb
+        cells      = immutable.fromJS(importer.cells())
         cell_list  = util.sorted_cell_list(cells)
-        cm_options = immutable.fromJS
+        options = immutable.fromJS
             markdown : undefined
             options  : cm_options()   # TODO
         @setState
             cells      : cells
             cell_list  : cell_list
-            cm_options : cm_options
+            cm_options : options

     close: =>
         delete @store


Fix for child elements.

Fix for child elements.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -1597,7 +1597,8 @@
     loadLinksInApp: ->
       $(document).on 'click', '[data-behavior~=entry_final_content] a', (event) ->
         newTab = (event.ctrlKey || event.metaKey)
-        if feedbin.data.view_links_in_app && event.target.nodeName == "A" && !newTab
+        linkActions = $(event.target).is(".link-actions")
+        if feedbin.data.view_links_in_app && !linkActions && !newTab
           href = $(@).attr('href')
           feedbin.loadLink(href)
           event.preventDefault()


new red point icon

new red point icon

--- app/assets/javascripts/nodes.js.coffee
+++ app/assets/javascripts/nodes.js.coffee
@@ -16,6 +16,17 @@
         attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
         maxZoom: 18
     }).addTo(map)
+
+    redPointIcon = L.icon
+      iconUrl: 'http://upload.wikimedia.org/wikipedia/commons/d/d7/Red_Point.gif',
+      iconRetinaUrl: 'http://upload.wikimedia.org/wikipedia/commons/d/d7/Red_Point.gif',
+      iconSize: [20, 20],
+      iconAnchor: [10, 10],
+      popupAnchor: [10, 0],
+      #shadowUrl: 'my-icon-shadow.png',
+      #shadowRetinaUrl: 'my-icon-shadow@2x.png',
+      #shadowSize: [68, 95],
+      #shadowAnchor: [22, 94]

     # Some content from $map data
     nodes = $map.data("nodes")
@@ -254,6 +265,7 @@
         @marker = L.marker([@node.latitude, @node.longitude], {"draggable": true, "title": @character_names})
         #@marker.addTo(map)
         map.addLayer(@marker)
+        @marker.setIcon(redPointIcon)
         @marker.on('dragend', (e) =>
           latlng = @marker.getLatLng()
           if @node.real


Removed console.log from notes

Removed console.log from notes

--- app/assets/javascripts/notes.js.coffee
+++ app/assets/javascripts/notes.js.coffee
@@ -65,8 +65,6 @@

     # add diff note
     $(document).on "click", ".js-add-diff-note-button", @addDiffNote
-    $(document).on "mouseover", ".js-add-diff-note-button", ->
-      console.log $(this).data('line-code')

     # hide diff note form
     $(document).on "click", ".js-close-discussion-note-form", @cancelDiscussionForm
@@ -505,7 +503,6 @@
   addDiffNote: (e) =>
     e.preventDefault()
     $link = $(e.currentTarget)
-    console.log $link.data('line-code')
     row = $link.closest("tr")
     nextRow = row.next()
     hasNotes = nextRow.is(".notes_holder")


Use camelCase for variable names

Use camelCase for variable names

--- app/assets/javascripts/notes.js.coffee
+++ app/assets/javascripts/notes.js.coffee
@@ -16,8 +16,8 @@
     @view = view
     @noteable_url = document.URL
     @notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge")
-    @base_polling_interval = 15000
-    @max_polling_steps = 4
+    @basePollingInterval = 15000
+    @maxPollingSteps = 4

     @cleanBinding()
     @addBinding()
@@ -93,7 +93,7 @@
     clearInterval(Notes.interval)
     Notes.interval = setInterval =>
       @refresh()
-    , @polling_interval
+    , @pollingInterval

   refresh: ->
     return if @refreshing is true
@@ -119,19 +119,19 @@
         @refreshing = false

   ###
-  Increase @polling_interval up to 120 seconds on every function call,
+  Increase @pollingInterval up to 120 seconds on every function call,
   if `shouldReset` has a truthy value, 'null' or 'undefined' the variable
-  will reset to @base_polling_interval.
+  will reset to @basePollingInterval.

   Note: this function is used to gradually increase the polling interval
   if there aren't new notes coming from the server
   ###
   setPollingInterval: (shouldReset = true) ->
-    nthInterval = @base_polling_interval * Math.pow(2, @max_polling_steps - 1)
+    nthInterval = @basePollingInterval * Math.pow(2, @maxPollingSteps - 1)
     if shouldReset
-      @polling_interval = @base_polling_interval
-    else if @polling_interval < nthInterval
-      @polling_interval *= 2
+      @pollingInterval = @basePollingInterval
+    else if @pollingInterval < nthInterval
+      @pollingInterval *= 2

     @initRefresh()


Display upload error.

Display upload error.

--- app/assets/javascripts/s3_relay.coffee
+++ app/assets/javascripts/s3_relay.coffee
@@ -72,7 +72,8 @@
             fileColumn.html(link)
             progressBar.remove()
           else
-            alert "File could not be uploaded"
+            progressBar.remove()
+            progressColumn.text("File could not be uploaded")
             console.log $("Message", xhr.responseXML).text()

       xhr.open "POST", endpoint, true


Fix vote box hovering

Fix vote box hovering

--- app/assets/javascripts/votes.js.coffee
+++ app/assets/javascripts/votes.js.coffee
@@ -6,7 +6,7 @@
       vote_box.find("div.anonymous-votes").show()
       vote_box.find("div.organizations-votes").show()
       vote_box.find("div.not-logged").show()
-    $(selector).on "mouseleave", ".votes", ->
+    $(selector).on "mouseleave", ".vote-box, .votes", ->
       $(this).find("div.anonymous-votes").hide()
       $(this).find("div.organizations-votes").hide()
       $(this).find("div.not-logged").hide()


fix(admin) Check if user is admin on plugins page :lock:

--- app/coffee/modules/base/contrib.coffee
+++ app/coffee/modules/base/contrib.coffee
@@ -40,6 +40,9 @@
     loadProject: ->
         project = @projectService.project.toJS()

+        if not project.i_am_admin
+            @errorHandlingService.permissionDenied()
+
         @scope.projectId = project.id
         @scope.project = project
         @scope.$emit('project:loaded', project)


Just use the text container content box, as that's basically what the whole range hack does

--- app/js/jail_iframe/classes/buttons.coffee
+++ app/js/jail_iframe/classes/buttons.coffee
@@ -97,21 +97,18 @@
     unless FactlinkJailRoot.can_haz.client_buttons
       @$el.addClass 'fl-button-hide-default'

-  _textContainer: ($el) ->
+  $textContainer: ($el) ->
     for el in $el.parents()
-      return el if window.getComputedStyle(el).display == 'block'
+      return $(el) if window.getComputedStyle(el).display == 'block'
     console.error 'FactlinkJailRoot: No text container found for ', $el

   _updatePosition: ->
     top = @$nearEl.offset().top + @$nearEl.outerHeight()/2 - @frame.$el.outerHeight()/2

-    textContainer = @_textContainer(@$nearEl)
-    range = document.createRange()
-    range.setStartBefore textContainer
-    range.setEndAfter textContainer
-    rangeBox = FactlinkJailRoot.rangeBox(range)
+    $textContainer = @$textContainer(@$nearEl)
+    textContainerOffset = $textContainer.offset()

-    left = rangeBox.left + rangeBox.width
+    left = textContainerOffset.left + $textContainer.width()
     left = Math.min left, $(window).width() - @frame.$el.outerWidth()

     @_showAtCoordinates top, left


Can set rep in individual view through route params without API call.

--- app/scripts/controllers/individual.coffee
+++ app/scripts/controllers/individual.coffee
@@ -104,13 +104,12 @@

     $scope.setRepToRouteParams = () ->
       if $routeParams.bioguide_id.length > 0
-        ApiGet.congress "legislators?bioguide_id=#{$routeParams.bioguide_id}", (error, data) ->
-          if not error
-            if data.length
-              this_name = "#{data[0].title}. #{data[0].first_name} #{data[0].last_name}"
-              $scope.selected.rep1 = {bioguide_id: data[0].bioguide_id, name: this_name}
-          else
-            console.log "Error, Senator/Rep not found."
+        if $scope.reps[$routeParams.bioguide_id]
+          $scope.selected.rep1 =
+            bioguide_id: bioguide_id
+            name: $scope.reps[bioguide_id].overview.fullname
+        else
+          console.log "Error, Senator/Rep not found."
           # set default focus

 ##############


remove outdated comment

remove outdated comment

--- js-library/app/js/jail_iframe/classes/control_iframe.coffee
+++ js-library/app/js/jail_iframe/classes/control_iframe.coffee
@@ -38,8 +38,6 @@

   fadeOut: ->
     @$el.removeClass 'factlink-control-visible'
-
-  #feature:should we communicate visibility to the control contents?
     FactlinkJailRoot.delay control_visibility_transition_time

   destroy: ->


Remove jshint options that are same as defaults

--- config/application.coffee
+++ config/application.coffee
@@ -70,7 +70,6 @@
       latedef: true
       newcap: true
       noarg: true
-      undef: false
       # relaxing options
       boss: true
       eqnull: true


Refactored TourInterestingUsersView to allow for unit testing

--- core/app/backbone/views/tour/tour_interesting_users_view.coffee
+++ core/app/backbone/views/tour/tour_interesting_users_view.coffee
@@ -17,15 +17,15 @@
     finish: '.js-finish'
     scrollingInner: '.js-scrolling-inner'

-  numberOfUsersInX: 4
-  numberOfUsersInY: 2
-
   templateHelpers: ->
     next_tourstep_path: window.next_tourstep_path

   initialize: ->
     @page = 0
     @shuffledCollection = new TourUsers
+
+    @options.numberOfUsersInX ?= 4
+    @options.numberOfUsersInY ?= 2

   onRender: ->
     @ui.finish.hide()
@@ -60,7 +60,7 @@

   showPage: (page) ->
     @page = page
-    xOffset = @userListItemWidth() * @numberOfUsersInX * @page
+    xOffset = @userListItemWidth() * @options.numberOfUsersInX * @page
     @ui.scrollingInner.css 'left', -xOffset
     @updateButtonStates()

@@ -76,12 +76,15 @@
     @page > 0

   hasNextPage: ->
-    (@page+1) * @numberOfUsersInX < @totalNumberOfItemsInX()
+    (@page+1) * @options.numberOfUsersInX < @totalNumberOfItemsInX()

   totalNumberOfItemsInX: ->
-    Math.ceil(@shuffledCollection.size() / @numberOfUsersInY)
+    Math.ceil(@shuffledCollection.size() / @options.numberOfUsersInY)

   userListItemWidth: ->
+    # Fixed width from options overrides calculation
+    return @options.userListItemWidth if @options.userListItemWidth?
+
     # Return some random number so on subsequent renders the
     # TourUserViews are not clipped
     return 500 if @shuffledCollection.isEmpty()


We should take latest open transform not the first one

--- lib/foundry-xray/app/assets/javascripts/lib/input.js.coffee
+++ lib/foundry-xray/app/assets/javascripts/lib/input.js.coffee
@@ -29,9 +29,7 @@

       if x.event == 'transformStart'
         id = @events.length-1
-
-        unless transforms[id]
-          transforms[id] = {id: id, label: x.name}
+        transforms[id] = {id: id, label: x.name}

     @transforms = transforms.values()
     @transforms = @transforms.filter (x, i) =>


Icon

Icon

- fix ng switch

--- src/base/Icon/Icon.coffee
+++ src/base/Icon/Icon.coffee
@@ -2,7 +2,7 @@
 	constructor: (@opts={}) ->
 		super(@opts)
 		if @_icon
-			@__class = @icon_map[@_icon]
+			@__class = @icon_map()[@_icon]
 			if isEmpty(@__class)
 				@__class = @_icon
 			if not isEmpty(@_class)
@@ -37,7 +37,7 @@
 	copy: ->
 		new Icon(@opts)

-	icon_map:
+	icon_map: ->
 		crop: "fa-crop"
 		fullscreen: "fa-arrows-alt"
 		trash: "fa-trash-o"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/clamp.coffee
+++ test/clamp.coffee
@@ -1,6 +1,6 @@
 module "Clamp"

 test 'it should exist', ->
-
+  obj = GameObject()

 module()


Use Spree.url() to build taxonomies jstree urls

URLs were hardcoded which caused errors when users mounted Spree in a
path other then "/"

[Fixes #3070] [Fixes #3071]

--- backend/app/assets/javascripts/admin/taxonomy.js.coffee
+++ backend/app/assets/javascripts/admin/taxonomy.js.coffee
@@ -70,11 +70,12 @@
 root = exports ? this
 root.setup_taxonomy_tree = (taxonomy_id) ->
   if taxonomy_id != undefined
+    # this is defined within admin/taxonomies/edit
+    root.base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
+
     $.ajax
-      url: '/api/taxonomies/' + taxonomy_id + '/jstree',
+      url: base_url.path().replace("/taxons", "/jstree"),
       success: (taxonomy) ->
-        # this is defined within admin/taxonomies/edit
-        root.base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
         last_rollback = null

         conf =
@@ -82,7 +83,7 @@
             data: taxonomy,
             ajax:
               url: (e) ->
-                '/api/taxonomies/' + taxonomy_id + '/taxons/' + e.attr('id') + '/jstree'
+                base_url.path() + '/' + e.attr('id') + '/jstree'
           themes:
             theme: "apple",
             url: "/assets/jquery.jstree/themes/apple/style.css"


don't fail dateparser on funky dates

don't fail dateparser on funky dates

--- content/dateparser.coffee
+++ content/dateparser.coffee
@@ -45,16 +45,11 @@

 parse_edtf = (date) ->
   try
-    parsed = edtf.parse(edtfy(date.replace(/\. /, ' '))) # 8. july 2011
-  catch err
-    throw err unless err.name == 'SyntaxError' || err.token || err.message == 'Invalid year'
-    try
-      parsed = edtf.parse(date.replace('?~', '~').replace(/u/g, 'X'))
-    catch err
-      throw err unless err.name == 'SyntaxError' || err.token
-      return false
+    return normalize_edtf(edtf.parse(edtfy(date.replace(/\. /, ' ')))) # 8. july 2011
+  try
+    return normalize_edtf(edtf.parse(date.replace('?~', '~').replace(/u/g, 'X')))

-  return normalize_edtf(parsed)
+  return false

 parse = (raw) ->
   debug('dateparser: parsing', raw)
@@ -91,6 +86,12 @@
 #    month = months.english.indexOf(m[1]) + 1
 #    month += 8 if month > 12
 #    return { type: 'date', year, month }
+
+  if m = /^(-?[0-9]{3,})-([0-9]{2})-([0-9]{2})T/.exec(trimmed)
+    year = parseInt(m[1])
+    month = parseInt(m[2])
+    day = parseInt(m[3])
+    return { type: 'date', year, month, day }

   if m = /^(-?[0-9]{3,})([-\/\.])([0-9]{1,2})(\2([0-9]{1,2}))?$/.exec(trimmed)
     year = parseInt(m[1])


Fix so these run

Fix so these run

--- bokehjs/test/test_mapper/test_categorical_mapper.coffee
+++ bokehjs/test/test_mapper/test_categorical_mapper.coffee
@@ -17,6 +17,6 @@
     )

   it "should map factors evenly", ->
-    expect(mapper.map_to_target('foo')).to equal 30
-    expect(mapper.map_to_target('bar')).to equal 50
-    expect(mapper.map_to_target('baz')).to equal 70+    expect(mapper.map_to_target('foo')).to.equal 30
+    expect(mapper.map_to_target('bar')).to.equal 50
+    expect(mapper.map_to_target('baz')).to.equal 70


add test case

add test case

--- test/index.coffee
+++ test/index.coffee
@@ -92,7 +92,7 @@
         )
       )

-    it "call cache, auto cached function, exec fail", (done) ->
+    it "call cache, auto cached function, exec fail, no-cache", (done) ->
       count = 0
       asyncFn = (path, callback) ->
         count += 1
@@ -116,3 +116,37 @@
           , 1000
         )
       )
+
+    it "call cache, auto cached function, exec fail, restore cache", (done) ->
+      count = 0
+      asyncFn2 = (path, callback) ->
+        count += 1
+        process.nextTick ->
+          return callback(null, 'hello world') if count > 1
+          callback(Error 'something is wrong')
+
+      asyncFn2 = cache "asyncFn2:{0}", asyncFn2, 1
+
+      asyncFn2('./index.coffee', (error, data) ->
+        assert.equal 1, count
+        assert.equal 'something is wrong', error.message
+        assert.equal undefined, data
+        asyncFn2('./index.coffee', (error, data) ->
+          assert.equal 2, count
+          assert.equal null, error
+          assert.equal 'hello world', data
+          asyncFn2('./index.coffee', (error, data) ->
+            assert.equal 2, count
+            assert.equal null, error
+            assert.equal 'hello world', data
+            setTimeout ->
+              asyncFn2('./index.coffee', (error, data) ->
+                assert.equal 3, count
+                assert.equal null, error
+                assert.equal 'hello world', data
+                done()
+              )
+            , 1000
+          )
+        )
+      )


remove slow, pointless, redundant code

remove slow, pointless, redundant code

--- node_modules_koding/jraphical/lib/graphlet.coffee
+++ node_modules_koding/jraphical/lib/graphlet.coffee
@@ -122,10 +122,6 @@
       extend selector, sourceId: $in: (edge.targetId for edge in last.edges)

     Relationship.some selector, options, (err, relationships)->
-      unless relationships?.length
-        setTimeout ->
-          Relationship.some selector, options, console.log.bind console
-        , 10000
       if err
         next err
       else


Remove tick of zero on yAxis

Remove tick of zero on yAxis

--- src/chart-d3-chart.coffee
+++ src/chart-d3-chart.coffee
@@ -91,6 +91,7 @@
       .append('g')
       .classed('scale-group': true, 'scale-y-group': true)
       .call(D3Chart.yAxis(yScale))
+      .select('.tick > text').remove()  # Remove tick of zero

   updateGridTickStyle: (options) =>
     @getRootElement()


fixed typos

fixed typos

--- app/config/Research.coffee
+++ app/config/Research.coffee
@@ -1,10 +1,10 @@
 Components = require 'config/Components'

 module.exports =
-  GenAbsorbtion1:
+  GenAbsorption1:
     codename: 'GenAbsorption1'
     name: 'Generator Heat Absorption'
-    desc: 'Increases all generators heat absorption by 10% per level.'
+    description: 'Increases all generators heat absorption by 10% per level.'
     image: Components.Gen1.image
     basePrice: 2000
     priceIncrease: 1.15
@@ -12,7 +12,7 @@
   CellProduction1:
     codename: 'CellProduction1'
     name: 'Cell Heat Production'
-    desc: 'Increases all cells heat production by 10% per level.'
+    description: 'Increases all cells heat production by 10% per level.'
     image: Components.Cell1.image
     basePrice: 2000
     priceIncrease: 1.15


Tidy up snippets

Tidy up snippets


:memo: Move transact to public section with delegates tag

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -612,31 +612,34 @@
   # {Delegates to: Editor.getPath}
   getPath: -> @editor?.getPath()

-  #  {Delegates to: TextBuffer.getLineCount}
+  # {Delegates to: Editor.transact}
+  transact: (fn) -> @editor.transact(fn)
+
+  # {Delegates to: TextBuffer.getLineCount}
   getLineCount: -> @getBuffer().getLineCount()

-  #  {Delegates to: TextBuffer.getLastRow}
+  # {Delegates to: TextBuffer.getLastRow}
   getLastBufferRow: -> @getBuffer().getLastRow()

-  #  {Delegates to: TextBuffer.getTextInRange}
+  # {Delegates to: TextBuffer.getTextInRange}
   getTextInRange: (range) -> @getBuffer().getTextInRange(range)

-  #  {Delegates to: TextBuffer.getEofPosition}
+  # {Delegates to: TextBuffer.getEofPosition}
   getEofPosition: -> @getBuffer().getEofPosition()

-  #  {Delegates to: TextBuffer.lineForRow}
+  # {Delegates to: TextBuffer.lineForRow}
   lineForBufferRow: (row) -> @getBuffer().lineForRow(row)

-  #  {Delegates to: TextBuffer.lineLengthForRow}
+  # {Delegates to: TextBuffer.lineLengthForRow}
   lineLengthForBufferRow: (row) -> @getBuffer().lineLengthForRow(row)

-  #  {Delegates to: TextBuffer.rangeForRow}
+  # {Delegates to: TextBuffer.rangeForRow}
   rangeForBufferRow: (row) -> @getBuffer().rangeForRow(row)

-  #  {Delegates to: TextBuffer.scanInRange}
+  # {Delegates to: TextBuffer.scanInRange}
   scanInBufferRange: (args...) -> @getBuffer().scanInRange(args...)

-  #  {Delegates to: TextBuffer.backwardsScanInRange}
+  # {Delegates to: TextBuffer.backwardsScanInRange}
   backwardsScanInBufferRange: (args...) -> @getBuffer().backwardsScanInRange(args...)

   ### Internal ###
@@ -1839,9 +1842,10 @@
   logCursorScope: ->
     console.log @editor.getCursorScopes()

-  transact: (fn) -> @editor.transact(fn)
   beginTransaction: -> @editor.beginTransaction()
+
   commitTransaction: -> @editor.commitTransaction()
+
   abortTransaction: -> @editor.abortTransaction()

   logScreenLines: (start, end) ->


engine data module

engine data module

--- src/engine_data.coffee
+++ src/engine_data.coffee
@@ -11,6 +11,6 @@
   Object.reverseMerge I,
     data: {}

-  get: (k) ->
-
+  get: (key) ->
+    data[]
   set: ->


Add last exit code and jobs count sections

--- prompt.coffee
+++ prompt.coffee
@@ -58,8 +58,19 @@
     when: git.isRepo
     foreground: 'blue'

+  section 'exit code',
+    content: system.lastExitCode
+    format: (lastExitCode) ->
+      "exit code #{lastExitCode}"
+    when: system.lastExitCode
+    background: 'red'
+    foreground: 'white'
+
   section 'end',
-    content: '\n$'
+    content: ['\n$', system.lastExitCode]
+    format: (string, lastExitCode) ->
+      if lastExitCode then @foreground = 'red'
+      string
     foreground: 'blue'
     options:
       newlines: true


No nouns for method names.

No nouns for method names.

--- src/environment.coffee
+++ src/environment.coffee
@@ -33,14 +33,15 @@
     # Apply the environment's forces to the element for the given number of
     # milliseconds.
     applyForces : (element, milliseconds) ->
-        # FIXME: possible optimization? ignore zero gravity,
-        # zero density environments.
-        forces = [@drag(element), @gravity(element)]
+        forces = [
+            @getDragForce(element),
+            @getGravitationalForce(element)
+        ]
         resultant = forces.reduce (t, s) -> t.add(s) # FIXME: not portable.
         element.applyForce(resultant, milliseconds)

     # Return the force of drag on the element.
-    drag : (element) ->
+    getDragForce : (element) ->

         # FIXME: this is broken at low speeds, and will in fact return a force
         # that is larger than the element's velocity.
@@ -54,7 +55,7 @@

     # Return the force of gravity on the given element.
-    gravity : (element) ->
+    getGravitationalForce : (element) ->
         # FIXME: technically, we should add drag as well.
         # FIXME: Optimize? Singleton?
         return new timber.Vector(0, @gravitationalConstant)


No options now

No options now

--- src/expectation.coffee
+++ src/expectation.coffee
@@ -42,11 +42,9 @@
   throw new Error "fbp-spec: No operator matching #{Object.keys(expectation)}. Available: #{Object.keys(operators)}"

 extractMatches = (expectation, data) ->
-  options =
-    flatten: true
   if expectation.path
     debug 'extracting JSONPath from', expectation.path, data
-    matches = JSONPath.query data, expectation.path, options
+    matches = JSONPath.query data, expectation.path
     throw new Error("expected JSONPath '#{expectation.path}' to match data in #{JSON.stringify(data)}") if not matches.length
   else
     matches = [ data ]


Fix: バージョン表記が誤っててもある程度動作するように修正 close #41

--- src/core/plistList.coffee
+++ src/core/plistList.coffee
@@ -45,6 +45,9 @@
           [version, platform] = v_.split(":")
         else
           [version, platform] = ["", ""]
+        version = version.replace(/^(\d+\.\d+)$/, "$1.9")
+        version = "" unless /^(?:\d+\.\d+\.\d+)?$/.test(version)
+        platform = "" unless /^(?:[iawm]+)?$/.test(platform)
         obj[name][n][n_] =
           name: "#{id}.#{i}.#{i_}"
           version: version


Tests: Environments: VM: Added CheckVMDiskUsage test.

--- tests/src/environments/vm.coffee
+++ tests/src/environments/vm.coffee
@@ -2,13 +2,13 @@
 assert  = require 'assert'
 environmentHelpers = require '../helpers/environmenthelpers.js'

+modalSelector = '.activity-modal.vm-settings'

 module.exports =

   turnOffVm: (browser) ->

-    modalSelector = '.activity-modal.vm-settings'
     linkSelector  = modalSelector + ' .statustoggle .input-wrapper'

     helpers.beginTest(browser)
@@ -31,3 +31,24 @@
     helpers.beginTest(browser)
     helpers.waitForVMRunning(browser)
     browser.end()
+
+
+  CheckVMDiskUsage: (browser) ->
+
+    diskUsageSelector     = modalSelector + ' .diskusage'
+    diskUsageBarSelector  = diskUsageSelector + ' .input-wrapper .progressbar-container.disk-usage'
+
+    helpers.beginTest(browser)
+    helpers.waitForVMRunning(browser)
+
+    environmentHelpers.openVmSettingsModal(browser)
+
+    browser
+      .waitForElementVisible   diskUsageSelector, 20000
+      .waitForElementVisible   diskUsageSelector + ' label.disk-usage', 20000
+      .waitForElementVisible   diskUsageBarSelector, 20000
+      .waitForElementVisible   diskUsageBarSelector + ' .bar', 20000 # Assertion
+      .moveToElement           diskUsageBarSelector + ' .bar span.light-label', 70, 7 # Assertion
+      .pause  3000
+      .waitForElementVisible   '.kdtooltip', 20000 # Assertion
+


exercises were not rendering, might still not be, will need specs

--- tutor/src/components/book-page.cjsx
+++ tutor/src/components/book-page.cjsx
@@ -6,7 +6,7 @@

 {BookContentMixin} = require './book-content-mixin'

-{default: {BookPageExerciseShell}} = require './book-page/exercise'
+{default: {ReferenceBookExerciseShell}} = require './book-page/exercise'
 RelatedContent = require './related-content'
 {default: Loading} = require './loading-screen'

@@ -67,7 +67,7 @@
   renderExercise: (link) ->
     exerciseAPIUrl = link.href
     exerciseNode = link.parentNode.parentNode
-    ReactDOM.render(<BookPageExerciseShell exerciseAPIUrl={exerciseAPIUrl}/>, exerciseNode) if exerciseNode?
+    ReactDOM.render(<ReferenceBookExerciseShell exerciseAPIUrl={exerciseAPIUrl}/>, exerciseNode) if exerciseNode?

   render: ->
     { ux, ux: { activePage: page } } = @props


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -161,7 +161,7 @@
       I.active = false
   }

-  defaultModules = [Bindable, Bounded, Cooldown, Drawable, Durable, Metered]
+  defaultModules = [Bindable, Bounded, Cooldown, Drawable, Durable, Metered, ]
   modules = defaultModules.concat(I.includedModules.invoke('constantize'))
   modules = modules.without(I.excludedModules.invoke('constantize'))


HEAD method highlighter support origin

HEAD method highlighter support origin

--- src/highlighter.coffee
+++ src/highlighter.coffee
@@ -10,7 +10,7 @@

 verbose = false

-httpMethods = 'GET|POST|PUT|DELETE|OPTIONS|PATCH|PROPPATCH|LOCK|UNLOCK|COPY|MOVE|MKCOL' # assembled from RFC 2616, 5323, 5789
+httpMethods = 'GET|POST|PUT|DELETE|OPTIONS|PATCH|PROPPATCH|LOCK|UNLOCK|COPY|MOVE|MKCOL|HEAD' # assembled from RFC 2616, 5323, 5789
 httpRequestRe = new RegExp "^(#{httpMethods})\\s+(.*?)\\s*$"
 aceRules = (json,xml) -> ->
   @$rules =
@@ -61,7 +61,6 @@
     token: ['comment']
     regex: '^.*$'
   ]
-
   "introStart": [
     token: 'separator'
     regex: '^---\s*$'


Add beforeNotify callback that can halt notification

--- src/honeybadger.coffee
+++ src/honeybadger.coffee
@@ -11,6 +11,7 @@
     action: null
     disabled: true
     onerror: false
+    beforeNotify: null

   @configured: false

@@ -48,7 +49,7 @@

   # TODO: Test setting options from notify
   @notify: (error, options = {}) ->
-    return false if @configuration.disabled == true
+    return false if (@configuration.disabled == true || @configuration.beforeNotify?(error, options) == false)
     options['error'] = error if error
     notice = new Notice(options)
     @_sendRequest(notice.toJSON())


added another trigger phrase

added another trigger phrase

--- src/ihavenoidea.coffee
+++ src/ihavenoidea.coffee
@@ -24,6 +24,7 @@

 gaffes = [
   'i ha(ve|s) no idea',
+  'i don\'t know',
   '(wh|)oops(|ie)',
   'my (bad|mistake|fault)',
   'd(\')oh'


Make a too-long line shorter

Make a too-long line shorter

--- src/kissmetrics.coffee
+++ src/kissmetrics.coffee
@@ -41,7 +41,10 @@
 		data._k = @key
 		data._p = @person

-		queryParts  = ("#{encodeURIComponent(key)}=#{encodeURIComponent(val)}" for key, val of data)
+		queryParts = []
+		for key, val of data
+			queryParts.push "#{encodeURIComponent(key)}=#{encodeURIComponent(val)}"
+
 		queryString = queryParts.join '&'

 		@request "#{@query_types[type]}?#{queryString}"


Prevent multiple dones

Prevent multiple dones

--- src/lib/Helpers.coffee
+++ src/lib/Helpers.coffee
@@ -160,17 +160,17 @@

     unless config.async
       # Set up custom error handlers
-      errorHandler = setupErrorHandler component, config, output, ->
-        return output.done()
+      errorHandler = setupErrorHandler component, config, output
       # Synchronous WirePattern, call done here
       func.call component, data, groups, outProxy, null, null, input.scope
+      # No need to call done if component called fail
+      return if output.result.__resolved
       do errorHandler
       output.done()
       return

     # Async WirePattern will call the output.done callback itself
-    errorHandler = setupErrorHandler component, config, output, ->
-      output.done()
+    errorHandler = setupErrorHandler component, config, output
     func.call component, data, groups, outProxy, (err) ->
       do errorHandler
       output.done err
@@ -219,7 +219,7 @@
       component.forwardBrackets[inPort].push 'error'
   return

-setupErrorHandler = (component, config, output, failCallback) ->
+setupErrorHandler = (component, config, output) ->
   errors = []
   errorHandler = (e, groups = []) ->
     platform.deprecated 'noflo.helpers.WirePattern error method is deprecated. Please send error to callback instead'
@@ -231,7 +231,7 @@
     platform.deprecated 'noflo.helpers.WirePattern fail method is deprecated. Please send error to callback instead'
     errorHandler e, groups if e
     sendErrors()
-    failCallback()
+    output.done()

   sendErrors  = ->
     return unless errors.length


Altered interface to insert.

Altered interface to insert.

--- src/lib/strata_.coffee
+++ src/lib/strata_.coffee
@@ -483,8 +483,8 @@
   # size and total size when we delete a record. We can't recalculate because
   # we're not strict about ownership. The application programmer may decide to
   # alter the object we returned.
-  cacheRecord: (page, position, record) ->
-    key = @extractor record
+  cacheRecord: (page, position, record, key) ->
+    key ?= @extractor record

     size = 0
     size += JSON.stringify(record).length
@@ -1794,32 +1794,10 @@

 #
 class Mutator extends Iterator
-  # For the current leaf page, give the mutator permission to peek at the right
-  # sibling leaf page if an insert determines that a records key is greater than
-  # the largest record in the current page. The record may belong in a right
-  # sibling page. Peeking at the next page is the only way to resolve the
-  # ambiguity, but loading a leaf has a cost, so we
-  #
-  # If the insert index of the record is after the last record, but we do not
-  # have permission to peek at the right sibling leaf page to determine if it is
-  # less than the first element of the right sibling, the insert location is
-  # ambiguous and `insert` returns `null`.
-
-  #
-  peek: ->
-    peeking = @_peek is @count
-    @_peek = @count
-    peeking
-
   # Insert the object into the leaf. Returns the index where the object was
   # inserted in the current leaf page if successful. Returns the bitwise
   # compliment of the location of a record with same key, if a record with the
   # same key already exists in the current leaf page.
-  #
-  # If the insert index of the record is after the last record, but we do not
-  # have permission to peek at the right sibling leaf page to determine if it is
-  # less than the first element of the right sibling, the insert location is
-  # ambiguous and `insert` returns `null`.
   #
   # If the insert index of the record is after the last record, and upon peeking
   # at the first record of the right sibling leaf page we determine that the
@@ -1837,61 +1815,80 @@

     # If we are at the first leaf page and the key is the search key that got us
     # here, then this is, without a doubt, the correct leaf page for the record.
-    unambiguous = @count is 1 and @key and @_io.comparator(@key, key) is 0
-
-    if unambiguous
-      [ index, found ] = [ @index, @found ]
+    if unambiguous = @key and @_io.comparator(@key, key) is 0
+      index = ~ @index
+
+    # Otherwise we find the index. We skip the ghost record, which will allow us
+    # to reinsert the key of the ghost record.
     else
-      index = @_io.find @_page, key, @_page.deleted, _
-      unless found = (index >= 0)
-        index = ~index
-      unambiguous = index <= page.count
-
-    if found
-      # TODO Special case: adding a first second copy of a record that has been
-      # deleted, but still exists. We put the new record after the first record
-      # and it exists as a special kind of duplicate.
-      # TODO Think harder about this. It seems like it would work.
-      # TODO No, we're not including the `0` in the range.
-      index = ~index
-
+      index = ~ @_io.find @_page, key, @_page.deleted, _
+      unambiguous = index <= @_page.count
+
+    if index < 0
+      index
+    else
+      @insertAt record, key, index, unambiguous, _
+
+  # Exposed interal implementation of insert for application developers who want
+  # to control right sibling leaf page peeking.
+  #
+  # There is a cost involved with peeking at the right sibling leaf page to
+  # determine if a record greater than the greatest record in the current leaf
+  # page belongs in the current page, or in a subsequent leaf page. If the
+  # application developer does't want to peek, they can take matters into their
+  # own hands. They can determine the insert location using `indexOf`, and if it
+  # is after the last record, they can use a new mutator to find the insert
+  # location of the next page.
+  #
+  # There is no cost involved when inserting a range into the last leaf page, a
+  # common operation, because the right sibling leaf page does not exist, so
+  # there is no doubt that the records belong on the last page.
+  #
+  # When the application developer uses `insertAt`, the application developer is
+  # responsible for maintaining the collation order of the leaf page. The
+  # application developer must not insert duplicates. No asssertions are
+  # performed on the validity of the insert.
+
+  #
+  insertAt: (record, index, unambiguous, _) ->
     # On every leaf page except the first leave page, the least record is the
     # key, and inserted records are always greater than the key. We assert this
     # here. Do not catch this exception, debug your code.
     if index is 0 and @_page.address isnt -1
       throw new Error "lesser key"

-    # TODO Should not be an else.
-    else if index >= 0
-      if not unambiguous and @_peek is @count
-        # The lock must held because the balancer can swoop in and prune the
-        # ghost first records and thereby change the key. It could not delete
-        # the page nor merge the page, but it can prune dead first records.
-
-        #
-        unless unambiguous = page.next is -1
-          @_next or= @_io.lock @_page.right, @_exclusive, true, _
-          unambiguous = @_io.compare(key, @_io.key(@_next, 0, _)) < 0
-
-      if unambiguous
-        # Cache the current count.
-        @_io.balancer.unbalanced(@_page)
-
-        # Since we need to fsync anyway, we open the file and and close the file
-        # when we append a JSON object to it. Because no file handles are kept
-        # open, the b‑tree object can left to garbage collection.
-        filename = @_io.filename @_page.address
-        fd = fs.open filename, "a", 0644, _
-        position = @_io.writeInsert fd, @_page, index, record, _
-        fs.close fd, _
-
-        @_page.positions.splice index, 0, position
-        # TODO Why am I not caching the record?
-        @_page.count++
-        @length = @_page.positions.length
-      else
-        index = 0
-    index
+    if not (unambiguous or unambiguous = not page.right)
+      # The lock must held because the balancer can swoop in and prune the
+      # ghost first records and thereby change the key. It could not delete
+      # the page nor merge the page, but it can prune dead first records.
+
+      #
+      @_next or= @_io.lock @_page.right, @_exclusive, true, _
+      unambiguous = @_io.compare(key, @_io.key(@_next, 0, _)) < 0
+
+    # If insert location is unambiguous, insert the record and return the insert
+    # index, otherwise return `undefined`.
+    if unambiguous
+      # Cache the current count.
+      @_io.balancer.unbalanced(@_page)
+
+      # Since we need to fsync anyway, we open the file and and close the file
+      # when we append a JSON object to it. Because no file handles are kept
+      # open, the b‑tree object can left to garbage collection.
+      filename = @_io.filename @_page.address
+      fd = fs.open filename, "a", 0644, _
+      position = @_io.writeInsert fd, @_page, index, record, _
+      fs.close fd, _
+
+      # Insert the position into the page a cache the record.
+      @_io.insert(@_page, 0, position)
+      @_io.cacheRecord(@_page, position, record, key)
+
+      # Update the length of the current page.
+      @length = @_page.positions.length
+
+      # Return the inserted index.
+      index

   delete: (index, _) ->
     if not (@_page.deleted <= index < @_page.count)


add end step as well

add end step as well

--- tutor/src/flux/task-panel.coffee
+++ tutor/src/flux/task-panel.coffee
@@ -28,8 +28,10 @@
   stepId = step.id or 'default'

   panels = StepPanel.getPanelsWithStatus(stepId)
+  step = _.pick(step, 'id', 'type', 'is_completed', 'related_content', 'group')
+  task = _.pick(task, 'title', 'type', 'due_at', 'description')

-  _.extend({panels}, _.pick(step, 'id', 'type', 'is_completed', 'related_content', 'group'))
+  _.extend({panels, task}, step)

 makeUiSettings = (initial) ->
   deepMerge({}, ONE_TIME_CARD_DEFAULTS, initial)
@@ -95,7 +97,9 @@
     if incompleteIndex is -1 or stepIndex <= incompleteIndex
       makeStep(task, step, stepIndex)

-afters = {}
+afters =
+  'end': (task, step, stepIndex) ->
+    makeAvailableStep(task, {type: 'end'}, stepIndex)

 stepMappers = _.flatten([
   _.values(befores)
@@ -122,6 +126,8 @@

   exports:
     get: (id) -> @_get(id)
+    getStep: (id, stepIndex) -> @_get(id)[stepIndex]
+    getStepByKey: (id, stepKey) -> @exports.getStep.call(@, id, stepKey - 1)

 {actions, store} = makeSimpleStore(TaskPanel)


CS2: super must always have parentheses

CS2: super must always have parentheses

--- lib/assets/javascripts/unpoly/classes/fragment_scrolling.coffee
+++ lib/assets/javascripts/unpoly/classes/fragment_scrolling.coffee
@@ -3,15 +3,16 @@

 class up.FragmentScrolling extends up.FragmentProcessor

-  keys: -> super.concat [
-    'hash'
-    'mode'
-    'revealTop'
-    'revealMax'
-    'revealSnap'
-    'scrollBehavior'
-    'scrollSpeed'
-  ]
+  keys: ->
+    super().concat [
+      'hash'
+      'mode'
+      'revealTop'
+      'revealMax'
+      'revealSnap'
+      'scrollBehavior'
+      'scrollSpeed'
+    ]

   constructor: (options) ->
     up.migrate.handleScrollOptions?(options)


Can handle walking into a subdirectory

Can handle walking into a subdirectory

--- quidoc.coffee
+++ quidoc.coffee
@@ -12,8 +12,10 @@
   files = fs.readdirSync directory
   for file in files
     filePath = path.join directory, file
-    fn filePath
-    walk filePath if fs.statSync( filePath ).isDirectory()
+    if fs.statSync( filePath ).isDirectory()
+      walk filePath, fn
+    else
+      fn filePath

 class DocsExtractor


Log events work after switching routes.

Log events work after switching routes.

--- admin/static/coffee/log_view.coffee
+++ admin/static/coffee/log_view.coffee
@@ -34,6 +34,8 @@
                         @render_header()

             , updateInterval
+
+            @.delegateEvents()

             return @


Adicionando configuração do video.js

Adicionando configuração do video.js

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -3,8 +3,11 @@
 #= require bootstrap-all
 #= require flash_msg
 #= require handlebars.runtime
+#= require video
 #= require_tree ../templates
 #= require_tree .
+
+_V_.options.flash.swf = "/assets/video-js.swf"

 jQuery ->
   $("a[rel=popover]").popover()


Street view updates

Street view updates

--- app/assets/javascripts/street_view.js.coffee
+++ app/assets/javascripts/street_view.js.coffee
@@ -1,6 +1,5 @@
 window.mapInit = ->
   return if !google? || !google.maps.LatLng
-  issue = new (google.maps.LatLng)(svLongNew, svLatNew)
   svs = new google.maps.StreetViewService()
   panorama = null
   map = null
@@ -60,9 +59,10 @@

     newStreetViewPano = document.getElementById("newStreetViewPano")

-    return unless newStreetViewPano
+    return if !newStreetViewPano || !svLongNew
+    issue = new (google.maps.LatLng)(svLongNew, svLatNew)

-    panorama = new google.maps.StreetViewPanorama(newStreetViewPano) if newStreetViewPano
+    panorama = new google.maps.StreetViewPanorama(newStreetViewPano)

     svs.getPanoramaByLocation(issue, 200, processSVData)


Fix lowercase typo

Fix lowercase typo

--- app/api/group.coffee
+++ app/api/group.coffee
@@ -43,7 +43,7 @@
     return res.sendStatus 400
   if req.user.group?
     return res.sendStatus 403
-  groupobj = null
+  groupObj = null
   db.collections.group.findOne
     inviteCode: code
   .populate 'users'


Cleaned up.

Cleaned up.

--- app/clipboard.coffee
+++ app/clipboard.coffee
@@ -1,12 +1,11 @@
-clipboard_items = -> ($ "clipboard clients").children()
+clipboard_clients = -> $ "clipboard clients"
+clipboard_items = -> clipboard_clients().children()

 menubutton_text = ->
-  "Ablage (" + (if i = clipboard_items().length then i else "leer") + ")"
+  "Ablage (" + (clipboard_items().length || "leer") + ")"

 @update_clipboard_button = ->
   ($ ".menubutton_clipboard").text menubutton_text()
-
-clipboard_clients = -> RECORDS["clipboard"].find "clients"

 client_by_name = (name) ->
   (RECORDS["clients"].find "user:contains('#{name}')").parent()