fix problems relating to Helper nodes.

fix problems relating to Helper nodes.

some copy and paste code that made little sense for Helper.

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -240,12 +240,11 @@
     element

   lastElement: ->
-    item = @lastItem()
-    if item then item.lastElement() else @anchor
-
-  remove: ->
-    @element.parentNode.removeChild(@element)
-    item.remove() for item in @items
+    @element
+
+  remove: ->
+    unless @element.parentNode is null
+      @element.parentNode.removeChild(@element)

   append: (inside) ->
     inside.appendChild(@element)


:tv::arrow_down_small: Updated at https://danielx.net/editor/

--- track_controller.coffee
+++ track_controller.coffee
@@ -95,12 +95,6 @@

     return count

-  # Read through all the events to find the song duration
-  preload = ->
-    consumeEventsUntilTime(900)
-    console.log currentState
-  # preload()
-
   self =
     consumeEventsUntilTime: consumeEventsUntilTime

@@ -114,3 +108,24 @@
         currentState

     initialState: initialState
+
+  # Read through all the events to find the song duration and meta data
+  finalState = null
+  preload = ->
+    consumeEventsUntilTime(900)
+    console.log finalState = currentState
+    self.reset()
+  preload()
+
+  # Gather an array of state snapshots so we can seek to any time
+  duration = finalState.meta.duration
+  snapshots = 100
+  seekStates = [0...snapshots].map (i) ->
+    consumeEventsUntilTime(duration * i / snapshots)
+    clone currentState
+
+  console.log seekStates
+
+  self.reset()
+
+  return self


fix bug with select2

fix bug with select2

--- BackofficeBundle/Resources/public/coffee/InternalLinkFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/InternalLinkFormView.coffee
@@ -71,7 +71,7 @@
       @closeModal()
       link = $('<a href="#">').html($('.label-tinyMce', @$el).val())
       options = {}
-      _.each $('.to-tinyMce', @$el), (element, key) ->
+      _.each $('.to-tinyMce[data-key]', @$el), (element, key) ->
         element = $(element)
         options[element.data('key')] = element.val()
       link.attr 'data-options', JSON.stringify(options)


Fixes per #3581 review.

Fixes per #3581 review.

--- tests/integration/uk/sso.coffee
+++ tests/integration/uk/sso.coffee
@@ -68,7 +68,7 @@
 # ------------------------------------------------------------------------
 # Test the user created

-casper.test.begin "Test the registred user", 7, (test) ->
+casper.test.begin "Test the registered user", 7, (test) ->
   casper.start url
   login test
   user_profile test
@@ -154,7 +154,7 @@
     return
   return

-# Performs 5 or 6 (depends on the phone nuber) tests to check user's profile.
+# Performs 5 or 6 (depends on the phone number) tests to check user's profile.
 user_profile = (test) ->

   # Test user's profile.


Client: fix coffee gotcha

Client: fix coffee gotcha

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -518,7 +518,7 @@
     fetchActivities      : (options = {}, callback = ->)->

       # show exempt content if only requester is admin or exempt herself
-      showExempt = KD.checkFlag? "super-admin" or KD.whoami()?.isExempt
+      showExempt = KD.checkFlag?("super-admin") or KD.whoami()?.isExempt

       options.showExempt or= showExempt


More robust/hardcoded w/h

More robust/hardcoded w/h

--- client/app/js/views/battle_view.coffee
+++ client/app/js/views/battle_view.coffee
@@ -521,14 +521,15 @@
   changeWeather: (newWeather, done) =>
     $overlays = @$('.battle_overlays')
     $overlays.find('.weather').transition(opacity: 0, 500, -> $(this).remove())
+    [overlayWidth, overlayHeight] = [600, 300]
     $weather = switch newWeather
       when Weather.RAIN
         $weather = $("
").addClass("battle_overlay weather rain")
         $overlays.append($weather)
         for i in [0...100]
           setTimeout((->
-            dropLeft = _.random(-300, $overlays.width())
-            dropTop = _.random(- 3 * $overlays.height() - 100, -100)
+            dropLeft = _.random(-300, overlayWidth)
+            dropTop = _.random(- 3 * overlayHeight - 100, -100)

             $drop = $('

')
             $drop.css(left: dropLeft, top: dropTop)
@@ -541,17 +542,17 @@
         for i in [0...10]
           setTimeout((->
             $ray = $('

')
-            $ray.css(left: Math.floor(Math.random() * $overlays.width()))
+            $ray.css(left: Math.floor(Math.random() * overlayWidth))
             $weather.append($ray)
           ), Math.floor(Math.random() * 3000))
         $weather
       when Weather.SAND
         $weather = $("
").addClass("battle_overlay weather sand")
-        [width, height] = [$overlays.width(), $overlays.height()]
-        [overlayWidth, overlayHeight] = [600, 600]
+        [width, height] = [overlayWidth, overlayHeight]
+        [sandWidth, sandHeight] = [600, 600]
         streams = []
-        for x in [-(2 * width)..width] by overlayWidth
-          for y in [-(2 * height)...height] by overlayHeight
+        for x in [-(2 * width)..width] by sandWidth
+          for y in [-(2 * height)...height] by sandHeight
             percentX = Math.floor(100 * x / width) + "%"
             percentY = Math.floor(100 * y / height) + "%"
             streams.push([percentX, percentY])
@@ -566,8 +567,8 @@
         $overlays.append($weather)
         for i in [0...100]
           setTimeout((->
-            hailstoneLeft = _.random(-300, $overlays.width())
-            hailstoneTop = _.random(-$overlays.height(), -10)
+            hailstoneLeft = _.random(-300, overlayWidth)
+            hailstoneTop = _.random(-overlayHeight, -10)

             $hailstone = $('

')
             size = Math.floor(Math.random() * 5) + 5


KiteError: Only assume machine as Stopped if it's marked as Running

--- client/app/lib/kite/kites/kloud.coffee
+++ client/app/lib/kite/kites/kloud.coffee
@@ -191,7 +191,7 @@
         # at this point we can assume that the machine is Stopped. But on
         # the other hand, Kloud should also mark this machine as Stopped if
         # it couldn't find it in Kontrol registry ~ GG FIXME: FA
-        else if err.message is 'not found'
+        else if err.message is 'not found' and currentState is Machine.State.Running

           @resolveRequestingInfos machineId, State: Machine.State.Stopped
           KiteLogger.failed 'kloud', 'info'


raven should go after apps are mounted and before error handler

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -109,9 +109,6 @@
         require('antigravity').fabricate('user', accessToken: 'footoken')
       )
       next()
-
-  if "production" is NODE_ENV
-    app.use(raven.middleware.express(SENTRY_URL))

   # Body parser has to be after proxy middleware for
   # node-http-proxy to work with POST/PUT/DELETE)
@@ -205,6 +202,9 @@
   app.use favicon(path.resolve __dirname, '../public/images/favicon.ico')
   app.use express.static(path.resolve __dirname, "../public")

+  if "production" is NODE_ENV
+    app.use(raven.middleware.express(SENTRY_URL))
+
   # Finally 404 and error handling middleware when the request wasn't handled
   # successfully by anything above.
   require('artsy-error-handler') app,


Fix teacher autofill solution button to get correct code language


[➠] Improved “scrolly”.

[➠] Improved “scrolly”.

--- vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/scrollify/scrolly.js.coffee
@@ -3,7 +3,7 @@

   defaults:
     offsets:
-      roof: -1
+      sections: 0
     debug: false

   # === Public ===
@@ -11,6 +11,7 @@
   constructor: (theatre, options) ->
     @theatre = $ theatre
     @roof    = @theatre.find '.roof'
+    @stage   = @theatre.find '.stage'
     @options = $.extend @defaults, options

     initialize.call @
@@ -19,25 +20,55 @@

   # === Events ===

-  onRoofReached: (roof, direction) =>
-    if direction is 'down'
-      roof.addClass 'slim'
+  onWindowScroll: (event) =>
+    scrollTop = do $(window).scrollTop
+
+    if scrollTop > 0
+      minimizeRoof.call @
     else
-      roof.removeClass 'slim'
+      expandRoof.call @

+    return
+
+  onSectionReached: (section, direction) =>
     return

   # === Private ===

   initialize = ->
+    setupWindow.call @
+
     setupWaypoints.call @

     return

+  setupWindow = ->
+    $(window).on 'scroll', @onWindowScroll
+
+    return
+
   setupWaypoints = ->
-    @roof.waypoint
-      handler: (direction) =>
-        @onRoofReached @roof, direction
-      offset: @options.offsets.roof
+    if do @stage.present
+      sections = @stage.find '> section'
+
+      sections.each (index, section) =>
+        section = $ section
+
+        section.waypoint
+          handler: (direction) =>
+            @onSectionReached section, direction
+          offset: @options.offsets.sections
+
+        return
+
+    return
+
+  minimizeRoof = ->
+    @roof.addClass 'slim'
+
+    return
+
+  expandRoof = ->
+    @roof.removeClass 'slim'

     return


updated grunt serve to point to build/

updated grunt serve to point to build/

--- bokehjs/Gruntfile.coffee
+++ bokehjs/Gruntfile.coffee
@@ -199,7 +199,7 @@
       server:
         options:
           port: 8000,
-          base: '.'
+          base: 'build/'

     qunit:
       all:


:bug: fix bugs in router lib

:bug: fix bugs in router lib

--- src/renderer/lib/router.coffee
+++ src/renderer/lib/router.coffee
@@ -34,12 +34,13 @@
    * @param {String?} route      route
   ###
   addRoute: (path, route) ->
-    unless route?
-      routes = path
-    else
-      routes = {}
-      routes[path] = route
-    @routes = objectAssign(@routes, routes)
+    if path?
+      unless route?
+        routes = path
+      else
+        routes = {}
+        routes[path] = route
+      @routes = objectAssign(@routes, routes)

   ###*
    * set routes for authenticated only
@@ -48,10 +49,10 @@
    * @param {String} renavigate   path of renavigation(like redirect)
   ###
   setAuth: (route, required, renavigate) ->
-    unless required? && renavigate?
+    auth = {}
+    if route? && !required? && !renavigate?
       auth = route
-    else
-      auth = {}
+    else if route? && required? && renavigate?
       auth[route] =
         required: required
         renavigate: renavigate
@@ -78,6 +79,8 @@
       match = fragment.match new RegExp("^#{re}$")
       if match?
         match.shift()
+        delete match.index
+        delete match.input
         argu = {}
         argu.route = r
         argu.route_arr = r.split(':')
@@ -85,13 +88,18 @@
         argu.fragment_arr = fragment.split('/')
         argu.match = match
         if logined?
-          auth = @auth[r]
+          auth = null
+          for r_, a of @auth
+            if (r_.split(':').every (v, i) -> argu.route_arr[i] == v)
+              auth = a
           if (auth?.required == true && !logined) || (auth?.required == false && logined)
             if auth.renavigate?
               for re_, r_ of @routes
                 match_ = auth.renavigate.match new RegExp("^#{re_}$")
                 if match_?
                   match_.shift()
+                  delete match_.index
+                  delete match_.input
                   argu = {}
                   argu.route = r_
                   argu.route_arr = r_.split(':')


Don't force tool selection

Don't force tool selection

--- src/decision-types/draw.coffee
+++ src/decision-types/draw.coffee
@@ -22,14 +22,12 @@
   events:
     'reset-step': ->
       @radioInputs.prop 'checked', false
-      @confirmButton.prop 'disabled', true
       @nextLabel.toggle true
       @doneLabel.toggle false

     'change input': (e) ->
       choice = @choices[e.currentTarget.value]
       @el.trigger 'select-tool', [choice.shape, choice]
-      @confirmButton.prop 'disabled', false

       @nextLabel.toggle @next?
       @doneLabel.toggle !@next?


fix logic for appending %s to searchUrl

fix logic for appending %s to searchUrl

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -131,7 +131,7 @@
   # It would be better to pull the default search engine from chrome itself.  However, chrome does not provide
   # an API for doing so.
   createSearchUrl: (query, searchUrl = Settings.get("searchUrl")) ->
-    searchUrl += "%s" if -1 == searchUrl.indexOf("%s") + searchUrl.indexOf("%S")
+    searchUrl += "%s" unless ['%s', '%S'].some (token) -> searchUrl.indexOf(token) >= 0
     searchUrl = searchUrl.replace /%S/g, query
     searchUrl.replace /%s/g, @createSearchQuery query


Fix for parsing doctags in code blocks

Fix for parsing doctags in code blocks


OPCE19: merge if's and rename variable name in getSelections

--- lib/y-rte.coffee
+++ lib/y-rte.coffee
@@ -89,9 +89,9 @@
   #   Return all the selections and filter using fun
   #   @param [Function] fun the function to use for filtering
   #   @return [Array<Selection>] an array of selection
-  getSelections: (fun = null)->
-    if _.isFunction(fun)
-      @_rte.selections.filter(fun) or []
+  getSelections: (filter = null)->
+    if _.isFunction(filter)
+      @_rte.selections.filter(filter) or []
     else
       @_rte.selections or []

@@ -141,7 +141,7 @@
     else throw new Error "Wrong set of parameters
       #{start}, #{end}, #{rte}, #{style}"

-  # Print a string reprensetation of string
+  # Print a string representation of string
   print: () ->
     r = @.right or {word: 'rightmost'};
     l = @.left or {word: 'leftmost'};
@@ -256,9 +256,7 @@
   #
   # @param [Selection] selection the selection to split
   split: (selection) ->
-    if !selection
-      return
-    if selection == @
+    if !selection or selection == @
       return

     # Check that they have all keys in common (but not necessarily same value!)
@@ -707,13 +705,13 @@
   #   Return all the selections
   #   @return [Array<Selection>] an array of selection
   #
-  # @overload getSelections(fun)
-  #   Return all the selections and filter using fun
-  #   @param [Function] fun the function to use for filtering
+  # @overload getSelections(filter)
+  #   Return all the selections and filter using filter
+  #   @param [Function] filter the function to use for filtering
   #   @return [Array<Selection>] an array of selection
-  getSelections: (fun = null)->
-    if _.isFunction(fun)
-      @_rte.selections.filter(fun) or []
+  getSelections: (filter = null)->
+    if _.isFunction(filter)
+      @_rte.selections.filter(filter) or []
     else
       @_rte.selections or []


Remove event listners when the view is destroyed

--- src/scripts/modules/media/tabs/contents/tree/draggable.coffee
+++ src/scripts/modules/media/tabs/contents/tree/draggable.coffee
@@ -55,7 +55,7 @@
       e.target.style.backgroundColor = 'transparent'

     onDrop: (e) ->
-      if e.stopPropagation then e.stopPropagation()
+      e.stopPropagation()

       position = @getPosition(e)

@@ -66,12 +66,24 @@
       return false

     onRender: () ->
-      super()
-
       if @editable and @model.get('book')
         draggable = @$el.children('.draggable').get(0)

-        draggable.addEventListener('dragstart', ((e) => @onDragStart.call(@, e)), false)
-        draggable.addEventListener('dragover', ((e) => @onDragOver.call(@, e)), false)
+        onDragStart = ((e) => @onDragStart.call(@, e))
+        onDragOver = ((e) => @onDragOver.call(@, e))
+        onDrop = ((e) => @onDrop.call(@, e))
+
+        # Attach event listeners using vanilla JS after the view has been rendered
+        draggable.addEventListener('dragstart', onDragStart, false)
+        draggable.addEventListener('dragover', onDragOver, false)
         draggable.addEventListener('dragleave', @onDragLeave, false)
-        draggable.addEventListener('drop', ((e) => @onDrop.call(@, e)), false)
+        draggable.addEventListener('drop', onDrop, false)
+
+        # Remove event listeners when the view is destroyed
+        @onBeforeClose = () =>
+          draggable.removeEventListener('dragstart', onDragStart, false)
+          draggable.removeEventListener('dragover', onDragOver, false)
+          draggable.removeEventListener('dragleave', @onDragLeave, false)
+          draggable.removeEventListener('drop', onDrop, false)
+
+      return @


Properly uninstall sortable when unmounted

--- resources/assets/coffee/react/profile-page/extra.coffee
+++ resources/assets/coffee/react/profile-page/extra.coffee
@@ -43,6 +43,7 @@

   componentWillUnmount: =>
     @_removeListeners()
+    $(@refs.pages).sortable 'destroy'

   componentWillReceiveProps: (newProps) =>


Remove logging code accidentally committed.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -733,10 +733,7 @@
       exitOnClick: true

       keydown: (event) =>
-        console.log "aaa", options.returnToViewport
-        if options.returnToViewport
-          console.log "window.scrollTo", @scrollX, @scrollY
-          window.scrollTo @scrollX, @scrollY
+        window.scrollTo @scrollX, @scrollY if options.returnToViewport
         if event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey
           @exit() unless handleDeleteForFindMode()
           @suppressEvent


Remove 'old' powerups

Remove 'old' powerups

--- src/lazerscripts/stage1.coffee
+++ src/lazerscripts/stage1.coffee
@@ -234,13 +234,8 @@
       @setSpeed 200
       @wait 500
       @parallel(
-        @if((-> @player(1).active), @drop(item: 'rapidb', inFrontOf: @player(1)))
-        @if((-> @player(2).active), @drop(item: 'rapidb', inFrontOf: @player(2)))
-      )
-      @wait 500
-      @parallel(
-        @if((-> @player(1).active), @drop(item: 'speedb', inFrontOf: @player(1)))
-        @if((-> @player(2).active), @drop(item: 'speedb', inFrontOf: @player(2)))
+        @if((-> @player(1).active), @drop(item: 'life', inFrontOf: @player(1)))
+        @if((-> @player(2).active), @drop(item: 'life', inFrontOf: @player(2)))
       )
     )


Remove trailing commas.

Remove trailing commas.

--- src/spec/csvexport.spec.coffee
+++ src/spec/csvexport.spec.coffee
@@ -1,11 +1,11 @@
 OrderExport = require '../lib/orderexport'
 Config = require '../config'

-describe '#mapOrder', ->
+xdescribe '#mapOrder', ->
   beforeEach ->
     @orderExport = new OrderExport Config

-  xit 'export base attributes', ->
+  it 'export base attributes', ->
     template =
       """
       id,orderNumber
@@ -18,69 +18,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-1-1'
-          productId: 'ProductId-1-1',
-          name:
-            { en: 'Product-1-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-1-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-1-1'
+          name:
+            { en: 'Product-1-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-1-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 1190
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 1190
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 1000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 1190
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 190
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       },{
@@ -89,69 +89,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-2-1'
-          productId: 'ProductId-2-1',
-          name:
-            { en: 'Product-2-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-2-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-2-1'
+          name:
+            { en: 'Product-2-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-2-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 2380
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 2380
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 2000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 2380
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 380
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       }]
@@ -179,69 +179,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-1-1'
-          productId: 'ProductId-1-1',
-          name:
-            { en: 'Product-1-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-1-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-1-1'
+          name:
+            { en: 'Product-1-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-1-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 1190
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 1190
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 1000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 1190
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 190
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       },{
@@ -250,69 +250,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-2-1'
-          productId: 'ProductId-2-1',
-          name:
-            { en: 'Product-2-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-2-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-2-1'
+          name:
+            { en: 'Product-2-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-2-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 2380
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 2380
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 2000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 2380
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 380
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       }]
@@ -330,7 +330,7 @@
     it 'export addresses', ->
     template =
       """
-      id,orderNumber,billingAddress.firstName,billingAddress.lastName,billingAddress.streetName,billingAddress.streetNumber,billingAddress.postalCode,billingAddress.city,billingAddress.country,shippingAddress.firstName,shippingAddress.lastName,shippingAddress.streetName,shippingAddress.streetNumber,shippingAddress.postalCode,shippingAddress.city,shippingAddress.country,
+      id,orderNumber,billingAddress.firstName,billingAddress.lastName,billingAddress.streetName,billingAddress.streetNumber,billingAddress.postalCode,billingAddress.city,billingAddress.country,shippingAddress.firstName,shippingAddress.lastName,shippingAddress.streetName,shippingAddress.streetNumber,shippingAddress.postalCode,shippingAddress.city,shippingAddress.country
       """

     orders =
@@ -340,69 +340,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-1-1'
-          productId: 'ProductId-1-1',
-          name:
-            { en: 'Product-1-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-1-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-1-1'
+          name:
+            { en: 'Product-1-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-1-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 1190
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 1190
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 1000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 1190
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 190
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       },{
@@ -411,69 +411,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-2-1'
-          productId: 'ProductId-2-1',
-          name:
-            { en: 'Product-2-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-2-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-2-1'
+          name:
+            { en: 'Product-2-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-2-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 2380
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 2380
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 2000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 2380
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 380
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       }]
@@ -501,69 +501,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-1-1'
-          productId: 'ProductId-1-1',
-          name:
-            { en: 'Product-1-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-1-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-1-1'
+          name:
+            { en: 'Product-1-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-1-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 1190
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 1190
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 1000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 1190
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 190
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       },{
@@ -572,69 +572,69 @@
         version: 1
         lineItems: [
           id: 'LineItemId-2-1'
-          productId: 'ProductId-2-1',
-          name:
-            { en: 'Product-2-1' },
-          variant: {
-            variantId: 1,
-            sku: 'SKU-2-1',
-            images: [],
-            attributes: []
-          },
-          quantity: 1,
-          price: {
-            country: 'US',
-            value: {
-              currencyCode: 'USD',
+          productId: 'ProductId-2-1'
+          name:
+            { en: 'Product-2-1' }
+          variant: {
+            variantId: 1
+            sku: 'SKU-2-1'
+            images: []
+            attributes: []
+          }
+          quantity: 1
+          price: {
+            country: 'US'
+            value: {
+              currencyCode: 'USD'
               centAmount: 2380
             }
-          },
-          taxRate: {
-            name: 'Standard Tax Rate',
-            amount: 0.19,
-            includedInPrice: true,
-            id: 'taxRateId',
-            country: 'US'
-          }
-        ],
-        customLineItems: [],
+          }
+          taxRate: {
+            name: 'Standard Tax Rate'
+            amount: 0.19
+            includedInPrice: true
+            id: 'taxRateId'
+            country: 'US'
+          }
+        ]
+        customLineItems: []
         totalPrice: {
           currencyCode: 'USD'
           centAmount: 2380
-        },
-        taxedPrice: {
-          totalNet: {
-            currencyCode: 'USD',
+        }
+        taxedPrice: {
+          totalNet: {
+            currencyCode: 'USD'
             centAmount: 2000
-          },
-          totalGross: {
-            currencyCode: 'USD',
+          }
+          totalGross: {
+            currencyCode: 'USD'
             centAmount: 2380
-          },
-          taxPortions: [{
-            amount: {
-              currencyCode: 'USD',
+          }
+          taxPortions: [{
+            amount: {
+              currencyCode: 'USD'
               centAmount: 380
-            },
-            rate: 0.19
-          }]
-        },
-        shippingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
-          country: 'US'
-        },
-        billingAddress: {
-          firstName: 'John',
-          lastName: 'Doe',
-          streetName: 'Some Street',
-          streetNumber: '11',
-          postalCode: '11111',
-          city: 'Some City',
+            }
+            rate: 0.19
+          }]
+        }
+        shippingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
+          country: 'US'
+        }
+        billingAddress: {
+          firstName: 'John'
+          lastName: 'Doe'
+          streetName: 'Some Street'
+          streetNumber: '11'
+          postalCode: '11111'
+          city: 'Some City'
           country: 'US'
         }
       }]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/function_extensions.coffee
+++ src/function_extensions.coffee
@@ -1,6 +1,6 @@
 Function::once = ->
   ran = false
-  memo = null
+  memo = unde

   _.once = function(func) {
     var ran = false, memo;


fix: URL specified rule ignored

fix: URL specified rule ignored

--- scripts-src/application.coffee
+++ scripts-src/application.coffee
@@ -374,7 +374,7 @@
                 r = Rules.parse keys.rule, ","
               @gol.rule = r
             catch e
-              alert "No rule " + keys.rule
+              alert "Incorrect rule: #{keys.rule}"
           if keys.frame_delay?
             try
               @setDelay parseInt keys.frame_delay, 10
@@ -1305,8 +1305,8 @@

     golApp.step_size = parseInt E("speed-show-every").value
     golApp.step_delay = parseInt E("speed-frame-delay").value
+    golApp.set_rule E("select-rule").value
     golApp.initialize()
-    golApp.set_rule E("select-rule").value
     E("rule").value = Rules.stringify golApp.gol.rule

     selectOrAddOption E("speed-show-every"), golApp.step_size


Cleanup

Cleanup

--- src/lib/services/github.coffee
+++ src/lib/services/github.coffee
@@ -140,19 +140,3 @@
 #  console.log data

-###
-repo.show (err, repo)->
-  if err?
-    console.log "ERROR"
-    console.log err
-  else
-    console.log repo
-###
-#api.call  'campaigns', 'list', {start: 0, limit: 25}, (err, data)->
-#  if err?
-#    console.log "ERROR"
-#    console.log err
-#  else
-#    console.log "Mailchimp data"
-#    console.log data.length
-


fixup docs and a robot.name check

fixup docs and a robot.name check

--- src/hubot/scripts/roles.coffee
+++ src/hubot/scripts/roles.coffee
@@ -1,7 +1,8 @@
 # Assign roles to people you're chatting with
 #
-# hubot <user> is a extraordinary role
-# hubot <user> is not a extraordinary role
+# hubot <user> is a extraordinary role - assign a role to a user
+# hubot <user> is not a extraordinary role - remove a role from a user
+# hubot who is <user> - see what roles a user has

 # hubot holman is an ego surfer
 # hubot holman is not an ego surfer
@@ -37,7 +38,7 @@
             msg.send "I know"
           else
             user.roles.push(newRole)
-            if name.toLowerCase() == "hubot"
+            if name.toLowerCase() == robot.name
               msg.send "Ok, I am #{newRole}."
             else
               msg.send "Ok, #{name} is #{newRole}."


Add sign in start to action redirectable on ember auth

--- app/assets/javascripts/auth.coffee
+++ app/assets/javascripts/auth.coffee
@@ -27,3 +27,5 @@
   actionRedirectable:
     signInRoute: 'index'
     signOutRoute: 'sessionsNew'
+    signInSmart: true
+    signInBlacklist: ['sessionsNew', 'sessionsDestroy']


chat: don't run regexep on innerHTML but on datetime attribute

In norloge, innerHTML is used to display text to user and datetime attribute
is a date and time string in iso format.

Before, code assumed that innerHTML contained only the date and time
informations. Now, with board/large, we have human readable date time format.

Now, we process directly the datetime norloge attribute to have more accurate
informations.

--- app/assets/javascripts/chat.coffee
+++ app/assets/javascripts/chat.coffee
@@ -99,9 +99,8 @@
         $(@).replaceWith html+orig.slice(idx) if html

   norlogize_left: (x) ->
-    r = /((\d{4}-\d{2}-\d{2}) )?(\d{2}:\d{2}:\d{2})/g
-    date = x.innerHTML.replace(r, "$2")
-    time = x.innerHTML.replace(r, "$3")
+    date = /\d{4}-\d{2}-\d{2}/.exec(x.dateTime)
+    time = /\d{2}:\d{2}:\d{2}/.exec(x.dateTime)
     index = @board.find(".board-left time[data-clock-date=\"" + date + "\"][data-clock-time=\"" + time + "\"]").length + 1
     x.dataset.clockDate = date
     x.dataset.clockTime = time


switching arrow function in home.coffee

switching arrow function in home.coffee

--- app/assets/javascripts/home.coffee
+++ app/assets/javascripts/home.coffee
@@ -91,7 +91,7 @@
   $('.img_left').attr("src", "assets/#{left_gal_img}")
   $('.img_right').attr("src", "assets/#{right_gal_img}")

-  $('.left-arrow').click ->
+  $('.right-arrow').click ->
     if img_number == 4
       console.log 'hello'
       left_gal_img = 'gal2.jpg'
@@ -109,7 +109,7 @@
     $('.img_right').attr("src", "assets/#{right_gal_img}")
     return

-  $('.right-arrow').click ->
+  $('.left-arrow').click ->
     if img_number == 0
       left_gal_img = 'gal1.jpg'
       right_gal_img = 'gal5.jpg'


Fix table fixed top offset

Fix table fixed top offset

--- app/assets/javascripts/main.coffee
+++ app/assets/javascripts/main.coffee
@@ -280,11 +280,11 @@
   # Setup sticky tables
   $contracts = $('#contracts')
   if $contracts.length and $contracts.find('tbody tr').length > 3
-    $contracts.stickyTableHeaders()
+    $contracts.stickyTableHeaders({fixedOffset: 45})

   $contractsUTE = $('#contracts-utes')
   if $contractsUTE.length and $contractsUTE.find('tbody tr').length > 3
-    $contractsUTE.stickyTableHeaders()
+    $contractsUTE.stickyTableHeaders({fixedOffset: 45})

   # Setup the law page navigation
   if $('.page-navigation-cont')


reduce map size at smallest zoom to accomodate mobile

--- app/assets/javascripts/maps.coffee
+++ app/assets/javascripts/maps.coffee
@@ -30,7 +30,7 @@

 	//these methods resise the map and image mage
 	$('#make-small').bind('click',function() {
-        $('#big-map').mapster('resize', 800, 0, 1000);
+        $('#big-map').mapster('resize', 600, 0, 1000);
     });
     $('#make-big').bind('click',function() {
         $('#big-map').mapster('resize', 4000, 0, 1000);


Don't initialize menu if there's none

Don't initialize menu if there's none

--- app/assets/javascripts/menu.coffee
+++ app/assets/javascripts/menu.coffee
@@ -106,6 +106,8 @@

   init: ->
     @menu = $('#main-menu')
+    return if @menu.length == 0
+
     @setHighlight()
     @setPostModerateCount()
     @sync_forum_menu()


BF-130 adding other planes

BF-130 adding other planes

--- app/assets/javascripts/view.coffee
+++ app/assets/javascripts/view.coffee
@@ -144,7 +144,7 @@
         @changePrev VIEW_3D
         @first = false

-      for dimension in [PLANE_XY]
+      for dimension in [PLANE_XY, PLANE_YZ, PLANE_XZ]
         for kind in [0..1]
           #i++
           offsets = cam2d.getOffsets dimension


Change the message

Change the message

--- app/components/upgrade-plan.coffee
+++ app/components/upgrade-plan.coffee
@@ -34,7 +34,7 @@
       Ember.$.post postUrl, data
       .then ->
         that.send "closeModal"
-        Notify.success "Feedback submitted!"
+        Notify.success "We will get in touch with you soon. Thanks."
       .fail (xhr, message, status) ->
         if xhr.status is 403
           Notify.error xhr.responseJSON.message


Correct the “addslashes_single_quotes” method

--- cURLCodeGenerator.coffee
+++ cURLCodeGenerator.coffee
@@ -6,7 +6,7 @@
     ("#{str}").replace(/[\\"]/g, '\\$&')

 addslashes_single_quotes = (str) ->
-    ("#{str}").replace(/[\\']/g, '\\$&')
+    ("#{str}").replace(/\\/g, '\\$&').replace(/'/g, "'\"'\"'")

 cURLCodeGenerator = ->
     self = this


Fix targetId bug

Fix targetId bug

--- client/views/recommendations/show.coffee
+++ client/views/recommendations/show.coffee
@@ -10,6 +10,7 @@

   'click .remove-recommendation': (e) ->
     e.preventDefault()
+    targetId = @targetId
     Recommendations.remove @_id, (error, result) ->
       if error
         console.log error


fixed KidsComponent event listener not falling off on unmount

--- urb/zod/pub/tree/src/js/components/KidsComponent.coffee
+++ urb/zod/pub/tree/src/js/components/KidsComponent.coffee
@@ -23,6 +23,9 @@
     (not _keys.isEmpty()) and _keys.every (k) =>
       @state.cont[@state.path+"/"+k]?

+  componentWillUnmount: ->
+    TreeStore.removeChangeListener @_onChangeStore
+
   componentDidMount: ->
     TreeStore.addChangeListener @_onChangeStore
     TreeActions.getPath @state.path,"kids" unless @gotPath()


Improve ganglia modif detection

Improve ganglia modif detection

--- hdp/ganglia_collector.coffee
+++ hdp/ganglia_collector.coffee
@@ -37,15 +37,33 @@
   , (err, written) ->
     next err, if written then ctx.OK else ctx.PASS

+module.exports.push name: 'Ganglia Collector # Fix User', callback: (ctx, next) ->
+  ctx.execute
+    cmd: 'usermod -s /bin/bash nobody'
+  , (err, executed, stdout, stderr) ->
+    next err, if /no changes/.test(stdout) then ctx.PASS else ctx.OK
+
 module.exports.push name: 'Ganglia Collector # Host', timeout: -1, callback: (ctx, next) ->
   cmds = []
   # On the Ganglia server, to configure the gmond collector
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPHistoryServer -m"
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPNameNode -m"
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPResourceManager -m"
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPSlaves -m"
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPHBaseMaster -m"
-  cmds.push cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -t"
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPHistoryServer -m"
+    not_if_exists: '/etc/ganglia/hdp/HDPHistoryServer'
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPNameNode -m"
+    not_if_exists: '/etc/ganglia/hdp/HDPNameNode'
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPResourceManager -m"
+    not_if_exists: '/etc/ganglia/hdp/HDPResourceManager'
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPSlaves -m"
+    not_if_exists: '/etc/ganglia/hdp/HDPSlaves'
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -c HDPHBaseMaster -m"
+    not_if_exists: '/etc/ganglia/hdp/HDPHBaseMaster'
+  cmds.push
+    cmd: "/usr/libexec/hdp/ganglia/setupGanglia.sh -t"
+    not_if_exists: '/etc/ganglia/hdp/gmetad.conf'
   ctx.execute cmds, (err, executed) ->
     next err, if executed then ctx.OK else ctx.PASS


cleanup

cleanup

--- core/app/backbone/modules/modal.coffee
+++ core/app/backbone/modules/modal.coffee
@@ -25,7 +25,6 @@
       title: @options.title

     onRender: ->
-
       @modalRegion.show @options.content_view
       @$('.modal').show()
       @$('.transparent-layer').show()
@@ -37,7 +36,6 @@
     Modal.close()

   Modal.show = (title, content_view)->
-    console.info 'showing modal'
     wrapped_view = new FactlinkApp.Modal.WrapperView
       title: title
       content_view: content_view


imageLinkShell: set defaultThumbnail to image link

--- coffee/src/shells/imagelink.shell.coffee
+++ coffee/src/shells/imagelink.shell.coffee
@@ -53,5 +53,9 @@
     @

+  defaultThumbnail: =>
+    @model.link()
+
+

 acorn.registerShellModule ImageLinkShell


tested passing custom formatter to markdox

--- test/main.coffee
+++ test/main.coffee
@@ -58,3 +58,22 @@
 				compiledCode[1].should.be.eql [ files[1].name, '/** comment1 */' ]
 				done()

+	it 'should call custom formatter passed in options', (done) ->
+		formattedCode = []
+
+		testedStream = markdox formatter: (docfile) ->
+			formattedCode.push [
+				docfile.filename.replace(/^(\.\.\/)+/, '/'),
+				docfile.javadoc[0].description.full
+			]
+			defaultFormatter docfile
+
+		gulp.src(files.map (file) -> file.name)
+			.pipe testedStream
+			.pipe assert.end ->
+				should.exist formattedCode[0]
+				formattedCode[0].should.be.eql [ files[0].name, 'comment0' ]
+				should.exist formattedCode[1]
+				formattedCode[1].should.be.eql [ files[1].name, 'comment1' ]
+				done()
+


Logic dump for focused ai. Doesn't take into account already won subboards (invariants may not hold).

--- ai.coffee
+++ ai.coffee
@@ -89,8 +89,59 @@
 ais["focused"].move = () ->
 	if subboard_next.length < 1
 		return [4,4]
-	else
+
+	subboard_index = subboard_next[-1..][0]
+	subboard = boards[subboard_index]
+	v = 2 * turn # number for matching one left
+	wins = []
+	losses = []
+	rows = [
+		subboard[0] + subboard[1] + subboard[2],
+		subboard[3] + subboard[4] + subboard[5],
+		subboard[6] + subboard[7] + subboard[8]
+	]
+	cols = [
+		subboard[0] + subboard[3] + subboard[6],
+		subboard[1] + subboard[4] + subboard[7],
+		subboard[2] + subboard[5] + subboard[8]
+	]
+	diags = [
+		subboard[0] + subboard[4] + subboard[8],
+		subboard[2] + subboard[4] + subboard[6]
+	]
+	for total,i in rows
+		val_array = [subboard[i], subboard[i+1], subboard[i+2]]
+		if total == v
+			wins.push( (3*i+j for a, j in val_array when a is 0)[0] )
+		if total == -v
+			losses.push( (3*i+j for a, j in val_array when a is 0)[0] )
+	for total, i in cols
+		val_array = [subboard[i], subboard[i+3], subboard[i+6]]
+		if total == v
+			wins.push( (3*j+i for a, j in val_array when a is 0)[0] )
+		if total == -v
+			losses.push( (3*j+i for a, j in val_array when a is 0)[0] )
+	if diags[0] == v or diags[0] == -v
+		indices = [0, 4, 8]
+		if total == v
+			wins.push( (i for i in indices when subboard[i] is 0)[0] )
+		if total == -v
+			losses.push( (i for i in indices when subboard[i] is 0)[0] )
+	if diags[1] == v or diags[1] == -v
+		indices = [2,4,6]
+		if total == v
+			wins.push( (i for i in indices when subboard[i] is 0)[0] )
+		if total == -v
+			losses.push( (i for i in indices when subboard[i] is 0)[0] )
+
+	moves = [wins...,losses...]
+	console.log("Moves:", moves)
+	if moves.length == 0
 		return ais["random"].move()
-
+	selection = moves[0]
+	x = selection % 3 + 3 * (subboard_index % 3)
+	y = selection // 3 + 3 * (subboard_index // 3)
+	add_move(x,y)
+	return[x,y]

 reset()


Adjust content check user date

Adjust content check user date

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -1001,6 +1001,8 @@
     level = _.find _.values(@getLevels()), slug: levelSlug

     defaultAccess = if me.get('hourOfCode') or @campaign?.get('type') is 'hoc' or @campaign?.get('slug') is 'intro' then 'long' else 'short'
+    if new Date(me.get('dateCreated')) < new Date('2021-09-21')
+      defaultAccess = 'all'
     access = me.getExperimentValue 'home-content', defaultAccess
     freeAccessLevels = (fal.slug for fal in utils.freeAccessLevels when _.any [
       fal.access is 'short'


Changed behavior to always reflect search results

Previously, a SHA with no results did not wipe the page; previous
results would continue to be displayed.

--- app/views/search/commits.js.coffee
+++ app/views/search/commits.js.coffee
@@ -20,7 +20,6 @@
   commitScroll = commitTable.infiniteScroll makeCommitURL,
     windowScroll: true
     renderer: (commits) ->
-      formatTable(commitTable)
       for commit in commits
         do (commit) -> addCommit(commitTable, commit)
     dataSourceOptions: {type: 'GET'}
@@ -30,6 +29,7 @@
     $.ajax commitTable.data('url'),
       data: commitSearchForm.serialize()
       success: (commits) ->
+        formatTable(commitTable)
         commitScroll.loadNextPage()
       error: =>
         $('<div/>').addClass('alert alert-error').text("Couldn't load search results").appendTo($('flashes'))


Listen for finished on stream

Listen for finished on stream

--- server/modfetch/fetcher.coffee
+++ server/modfetch/fetcher.coffee
@@ -103,8 +103,8 @@
     servPath = stage+servname
     fs.unlinkSync servPath if fs.existsSync servPath
     servzip = archiver 'zip'
-    stream = fs.createWriteStream servPath
-    servzip.pipe stream
+    servstream = fs.createWriteStream servPath
+    servzip.pipe servstream
     servzip.bulk [{expand: true, cwd: stage, src: fetch.info.name+'/**'}]
     clizip = archiver 'zip'
     finished = ->
@@ -120,15 +120,14 @@
       new Fiber(->
         done(null, null)
       ).run()
-    servzip.on 'finish', ->
+    servstream.on 'finish', ->
       log.info "Creating client bundle #{clientname}..."
       stream = fs.createWriteStream clientPath
       rmdir stagem+"scripts/vscripts/"
       clizip.pipe stream
       clizip.bulk [{expand: true, cwd: stagem, src: '**'}]
       clizip.finalize()
-    clizip.on 'finish', ->
-      new Fiber(finished).run()
+      stream.on 'finish', new Fiber(finished).run
     servzip.finalize()

 @clearExistingRepo = (id)->


Better email names

Better email names

--- server/routes/api/users.coffee
+++ server/routes/api/users.coffee
@@ -60,8 +60,8 @@
   ,
     (token, user, done) ->
       mailOptions =
-        to: user.email
-        from: 'noreply@buckets.io'
+        to: "#{user.name} <#{user.email}>"
+        from: 'Buckets <noreply@buckets.io>'
         subject: 'Buckets Password Reset'
         text: """
           You are receiving this because you (or someone else) have requested the reset of the password for your account.\n


Add tests for content-type

Add tests for content-type

--- test/test.coffee
+++ test/test.coffee
@@ -31,6 +31,7 @@
       request "#{baseurl}/", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/homepage", encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
         done()
@@ -40,6 +41,7 @@
       request "#{baseurl}/recents", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/recents", encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
         done()
@@ -49,6 +51,7 @@
       request "#{baseurl}/2013/05/29/introducing_bitter_blog_engine", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/introducing_bitter_blog_engine",
           encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
@@ -59,6 +62,7 @@
       request "#{baseurl}/2013/05/28/blog_engine_bitter", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/blog_engine_bitter",
           encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
@@ -69,6 +73,7 @@
       request "#{baseurl}/2013/05/27/markdown_example", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/markdown_example",
           encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
@@ -79,6 +84,7 @@
       request "#{baseurl}/archives", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/archives", encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
         done()
@@ -88,6 +94,7 @@
       request "#{baseurl}/2013/", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/2013", encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
         done()
@@ -97,6 +104,7 @@
       request "#{baseurl}/2013/05/", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         expected = fs.readFileSync "#{__dirname}/expected/201305", encoding:'utf8'
         assert.strictEqual body, expected, 'HTML'
         done()
@@ -145,37 +153,41 @@
       request "#{baseurl}/a", (err, resp, body) ->
         assert.strictEqual err, null, 'No errors'
         assert.strictEqual resp.statusCode, 404, 'Status code is 404'
+        assert.strictEqual resp.headers['content-type'], 'text/html; charset=utf-8', 'content-type'
         done()

   describe '/index.atom', ->
     it 'should return Atom feed', (done) ->
       meta = {}
       articles = []
-      request("#{baseurl}/index.atom")
-      .pipe(new FeedParser)
-      .on('error', (err) ->
-        assert.fail err, null, 'Error on parsing Atom feed'
-      ).on('meta', (m) ->
-        meta = m
-      ).on('article', (article) ->
-        articles.push article
-      ).on('end', ->
-        assert.strictEqual meta.title, 'MyLittleNotes', 'meta.title'
-        assert.strictEqual meta['atom:link'][0]['@'].href,
-          'http://notes.kyu-mu.net/index.atom', 'atom:link'
-        assert.strictEqual meta['atom:@'].xmlns, 'http://www.w3.org/2005/Atom', 'xmlns'
-        assert.strictEqual articles.length, 3, '3 articles'
-        assert.strictEqual articles[0].title, 'Bitter blog engine', 'articles[0].title'
-        assert (articles[0].description.indexOf('
Bitter blog engine
') isnt -1),
-          'articles[0].description'
-        assert.strictEqual articles[0].date.getTime(),
-          new Date('2013-05-29 00:00:00 +0900').getTime(),
-          'date'
-        assert.strictEqual articles[0].link,
-          'http://notes.kyu-mu.net/2013/05/29/introducing_bitter_blog_engine',
-          'articles[0].link'
-        assert.strictEqual articles[0].author, 'Nao Iizuka'
-        assert.strictEqual articles[1].title, 'ブログエンジンBitter'
-        assert.strictEqual articles[2].title, 'Markdown Example'
-        done()
-      )
+      request "#{baseurl}/index.atom", (err, resp, body) ->
+        assert.strictEqual err, null, 'No errors'
+        assert.strictEqual resp.statusCode, 200, 'Status code is 200'
+        assert.strictEqual resp.headers['content-type'], 'text/xml; charset=utf-8', 'content-type'
+        FeedParser.parseString(body)
+        .on('error', (err) ->
+          assert.fail err, null, 'Error on parsing Atom feed'
+        ).on('meta', (m) ->
+          meta = m
+        ).on('article', (article) ->
+          articles.push article
+        ).on('end', ->
+          assert.strictEqual meta.title, 'MyLittleNotes', 'meta.title'
+          assert.strictEqual meta['atom:link'][0]['@'].href,
+            'http://notes.kyu-mu.net/index.atom', 'atom:link'
+          assert.strictEqual meta['atom:@'].xmlns, 'http://www.w3.org/2005/Atom', 'xmlns'
+          assert.strictEqual articles.length, 3, '3 articles'
+          assert.strictEqual articles[0].title, 'Bitter blog engine', 'articles[0].title'
+          assert (articles[0].description.indexOf('
Bitter blog engine
') isnt -1),
+            'articles[0].description'
+          assert.strictEqual articles[0].date.getTime(),
+            new Date('2013-05-29 00:00:00 +0900').getTime(),
+            'date'
+          assert.strictEqual articles[0].link,
+            'http://notes.kyu-mu.net/2013/05/29/introducing_bitter_blog_engine',
+            'articles[0].link'
+          assert.strictEqual articles[0].author, 'Nao Iizuka'
+          assert.strictEqual articles[1].title, 'ブログエンジンBitter'
+          assert.strictEqual articles[2].title, 'Markdown Example'
+          done()
+        )


updated

updated

--- test/test.coffee
+++ test/test.coffee
@@ -42,7 +42,7 @@
           limit : "1"
         .end (res) ->
           res.status.should.equal 200
-          res.body.artist.name.should.eql 'Thomas Bangalter'
+          res.body.artist.name.should.eql 'Justice'
           done()

     describe 'Event', ->


drop the label tests temporarily

drop the label tests temporarily

--- test/test.coffee
+++ test/test.coffee
@@ -13,15 +13,15 @@
     expect(1) to equal 1
     expect(-> expect(2) to equal 1) to error

-    # the alias
-    expect(catch_it -> expect(2) to equal 1) to equal "Error: expected 2 to equal 1"
+    # the label
+    # expect(catch_it -> expect(2) to equal 1) to equal "Error: expected 2 to equal 1"

   it "eql/deep_equal", ->
     expect([1, 2, 3]) to eql [1, 2, 3]
     expect(-> expect([1, 2, 3]) to eql [2, 3, 4]) to error

-    # the alias
-    expect(catch_it -> expect([1, 2, 3]) to eql [2, 3, 4]) to equal "Error: expected 2,3,4 to deep equal 1,2,3"
+    # the label
+    # expect(catch_it -> expect([1, 2, 3]) to eql [2, 3, 4]) to equal "Error: expected 2,3,4 to deep equal 1,2,3"

   xit "not_equal", ->
     expect(1) to not_equal 2
@@ -33,8 +33,8 @@
     expect(greater) to equal gt
     expect(greater) to equal greater_than

-    # the alias
-    expect(catch_it -> expect(1) to be greater than 2) to equal "Error: expected 1 to be greater than 2"
+    # the label
+    # expect(catch_it -> expect(1) to be greater than 2) to equal "Error: expected 1 to be greater than 2"

   it "less", ->
     expect(1) to be less than 2
@@ -42,8 +42,8 @@
     expect(less) to equal lt
     expect(less) to equal less_than

-    # the alias
-    expect(catch_it -> expect(2) to be less than 1) to equal "Error: expected 2 to be less than 1"
+    # the label
+    # expect(catch_it -> expect(2) to be less than 1) to equal "Error: expected 2 to be less than 1"

   it "contain/include", ->
     expect("abcde") to include "bcd"
@@ -56,7 +56,7 @@
     expect include to equal contain

     # the label
-    expect(catch_it -> expect([1]) to include 2) to equal "Error: expected 1 to contain 2"
+    # expect(catch_it -> expect([1]) to include 2) to equal "Error: expected 1 to contain 2"

   it "length", ->
@@ -68,14 +68,14 @@
     expect(-> expect(o) to have length 6) to error

     # the label
-    expect(catch_it -> expect([]) to have length 1) to equal "Error: expected  to have `length` 1"
+    # expect(catch_it -> expect([]) to have length 1) to equal "Error: expected  to have `length` 1"

   it "match", ->
     expect("hello") to match /ell/
     expect(-> expect("heyo") to match /ell/) to error

     # the label
-    expect(catch_it -> expect("heyo") to match /ell/) to equal "Error: expected heyo to match /ell/"
+    # expect(catch_it -> expect("heyo") to match /ell/) to equal "Error: expected heyo to match /ell/"

   it "have", ->
     o = prop: "val"
@@ -83,20 +83,20 @@
     expect(-> expect(o) to have("prop") "nope") to error

     # the label
-    expect(catch_it -> expect({}) to have("prop") "nope") to equal "Error: expected property prop of [object Object] to equal nope"
+    # expect(catch_it -> expect({}) to have("prop") "nope") to equal "Error: expected property prop of [object Object] to equal nope"

   it "error", ->
     expect(-> expect(1) to equal 2) to error

     # the label
-    expect(catch_it -> expect(->) to error) to equal "Error: expected function to throw an error"
+    # expect(catch_it -> expect(->) to error) to equal "Error: expected function to throw an error"

   it "ok", ->
     expect(true) to be ok
     expect(-> expect(false) to be ok) to error

     # the label
-    expect(catch_it -> expect(false) to be ok) to equal "Error: expected false to be truthy"
+    # expect(catch_it -> expect(false) to be ok) to equal "Error: expected false to be truthy"

   it "exist", ->
     expect(-> expect(null) to exist) to error
@@ -104,7 +104,7 @@
     expect(1) to exist

     # the label
-    expect(catch_it -> expect(null) to exist) to equal "Error: expected null to exist"
+    # expect(catch_it -> expect(null) to exist) to equal "Error: expected null to exist"

   it "empty", ->
     expect([]) to be empty
@@ -113,7 +113,7 @@
     expect(-> expect(a: "b") to be empty) to error

     # the label
-    expect(catch_it -> expect([1, 2]) to be empty) to equal "Error: expected 1,2 to be empty"
+    # expect(catch_it -> expect([1, 2]) to be empty) to equal "Error: expected 1,2 to be empty"

   it "a/an", ->
     expect([]) to be an Array
@@ -127,7 +127,7 @@
     class Thing and expect(new Thing()) to be a Thing

     # the label
-    expect(catch_it -> expect("x") to be an Object) to equal "Error: expected x to be an instance of Object"
+    # expect(catch_it -> expect("x") to be an Object) to equal "Error: expected x to be an instance of Object"

   it "nt", ->
     describe "nt have", ->
@@ -135,13 +135,14 @@
       expect(-> expect([]) to nt have length 0) to error

       # the label
-      expect(catch_it -> expect([]) to nt have length 0) to equal "Error: did not expect  to have `length` 0"
+      # expect(catch_it -> expect([]) to nt have length 0) to equal "Error: did not expect  to have `length` 0"

     describe "nt include", ->
       expect("abc") to nt include "z"
       expect(-> expect("abc") to nt include "a") to error

-      expect(catch_it -> expect("abc") to nt include "a") to equal "Error: did not expect abc to contain a"
+      # the label
+      # expect(catch_it -> expect("abc") to nt include "a") to equal "Error: did not expect abc to contain a"


Use proper coffeescript for jCounter

Use proper coffeescript for jCounter

--- file/js/jCounter.jQuery.coffee
+++ file/js/jCounter.jQuery.coffee
@@ -15,44 +15,36 @@
 			width: '100%'
 		, options

-		if @.attr('maxlength')
-			max = @.attr('maxlength')
-		else max = options.max
+		max = if @.attr('maxlength')? then @.attr 'maxlength' else options.max

-		if !container
-			if !@.hasClass('jCounterInput')
-				@.addClass('jCounterInput')
-			@.wrap('

').parent().append('
' + max + '
');
-			jCounterContainer = $(@).parent().children('.' + options.counterClass)
+		if not container?
+			@.addClass 'jCounterInput'
+
+			@.wrap("""

""").parent().append """
#{max}
"""
+			jCounterContainer = $(@).parent().children ".#{options.counterClass}"
 		else
-			if typeof container is 'object'
-				jCounterContainer = container
-			else
-				jCounterContainer = $ container
+			jCounterContainer = if typeof container is 'object' then container else $ container

 		@.on 'keypress keyup', $.proxy () ->
-			if options.countUp
-				length = @.val().length
-			else
-				length = max - @.val().length
+			length = if options.countUp then @.val().length else max - @.val().length

 			if options.countUp && max > 0
 				if length < max / 2
 					color = 1
-				else if length >= max / 2 and length <= max / 1.2
+				else if max / 2 < length <= max / 1.2
 					color = 2
 				else
 					color = 3
 			else if options.countUp
 				color = 1
 			else
-				if length > max / 2
+				if max / 2 < length
 					color = 1
-				else if length <= max / 2 and length >= max / 6
+				else if max / 6 <= length <= max / 2
 					color = 2
 				else
 					color = 3

-			jCounterContainer.text(length).attr('class', '').addClass(options.counterClass + ' color-'+color)
+			jCounterContainer.text(length).removeClass().addClass "#{options.counterClass} color-#{color}"
 		, @
 )(jQuery)


Prevent whitespace removal in log file

Prevent whitespace removal in log file

--- settings/language-latex2e.cson
+++ settings/language-latex2e.cson
@@ -9,3 +9,8 @@
 '.text.tex.latex.tikz':
   'editor':
     'commentStart': '% '
+
+'.text.tex.latex.log':
+  'whitespace':
+    'ensureSingleTrailingNewline': false
+    'removeTrailingWhitespace': false


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/text.coffee
+++ test/text.coffee
@@ -17,17 +17,4 @@

 module "FloatingTextEffect"

-test "text fades out", ->
-  text = FloatingTextEffect()
-
-  text.update(1)
-  text.trigger "afterUpdate", 1
-
-  equals text.I.alpha, 1
-
-  text.update(1)
-  text.trigger "afterUpdate", 1
-
-  equals text.I.alpha, 0.5
-
 module()


removed duplication

removed duplication

--- views/coffeescript/main.coffee
+++ views/coffeescript/main.coffee
@@ -45,9 +45,10 @@

   drawNode: (node, point) ->
       MARGIN = 10
-
+
+      nodeView = view node.data
       ctx.font = "12pt Times"
-      {width, height, count} = util.textSize ctx, view(node.data)
+      {width, height, count} = util.textSize ctx, nodeView
       width = Math.max(height, 160)
       height = Math.max(height, 60)

@@ -57,7 +58,7 @@
       ctx.fillStyle ='white'
       x = util.centerToEdge(point.x, width)
       y = util.centerToEdge(point.y, height) + MARGIN*2
-      util.drawText(ctx, view(node.data), x, y)
+      util.drawText(ctx, nodeView, x, y)

   drawEdge: (edge, fromPoint, toPoint) ->


Add keyboard accelerators

Add keyboard accelerators

--- menus/win32.cson
+++ menus/win32.cson
@@ -2,72 +2,72 @@
   {
     label: '&File'
     submenu: [
-      { label: 'New Window', command: 'application:new-window' }
-      { label: 'New File', command: 'application:new-file' }
-      { label: 'Open...', command: 'application:open' }
-      { label: 'Reopen Last Item', command: 'pane:reopen-closed-item' }
+      { label: 'New &Window', command: 'application:new-window' }
+      { label: '&New File', command: 'application:new-file' }
+      { label: '&Open...', command: 'application:open' }
+      { label: 'Reopen Last &Item', command: 'pane:reopen-closed-item' }
       { type: 'separator' }
-      { label: 'Preferences...', command: 'application:show-settings' }
+      { label: '&Preferences...', command: 'application:show-settings' }
       { type: 'separator' }
-      { label: 'Save', command: 'core:save' }
-      { label: 'Save As...', command: 'core:save-as' }
-      { label: 'Save All', command: 'window:save-all' }
+      { label: '&Save', command: 'core:save' }
+      { label: 'Save &As...', command: 'core:save-as' }
+      { label: 'Save A&ll', command: 'window:save-all' }
       { type: 'separator' }
-      { label: 'Close Buffer', command: 'core:close' }
-      { label: 'Close All Buffers', command: 'pane:close' }
-      { label: 'Close Window', command: 'window:close' }
+      { label: '&Close Buffer', command: 'core:close' }
+      { label: 'Close All &Buffers', command: 'pane:close' }
+      { label: 'Clos&e Window', command: 'window:close' }
       { type: 'separator' }
-      { label: 'Exit', command: 'application:quit' }
+      { label: 'E&xit', command: 'application:quit' }
     ]
   }

   {
     label: '&Edit'
     submenu: [
-      { label: 'Undo', command: 'core:undo' }
-      { label: 'Redo', command: 'core:redo' }
+      { label: '&Undo', command: 'core:undo' }
+      { label: '&Redo', command: 'core:redo' }
       { type: 'separator' }
-      { label: 'Cut', command: 'core:cut' }
-      { label: 'Copy', command: 'core:copy' }
-      { label: 'Copy Path', command: 'editor:copy-path' }
-      { label: 'Paste', command: 'core:paste' }
-      { label: 'Select All', command: 'core:select-all' }
+      { label: '&Cut', command: 'core:cut' }
+      { label: 'C&opy', command: 'core:copy' }
+      { label: 'Copy Pat&h', command: 'editor:copy-path' }
+      { label: '&Paste', command: 'core:paste' }
+      { label: 'Select &All', command: 'core:select-all' }
       { type: 'separator' }
-      { label: 'Toggle Comments', command: 'editor:toggle-line-comments' }
+      { label: '&Toggle Comments', command: 'editor:toggle-line-comments' }
       {
         label: 'Lines',
         submenu: [
-          { label: 'Indent', command: 'editor:indent-selected-rows' }
-          { label: 'Outdent', command: 'editor:outdent-selected-rows' }
-          { label: 'Auto Indent', command: 'editor:auto-indent' }
+          { label: '&Indent', command: 'editor:indent-selected-rows' }
+          { label: '&Outdent', command: 'editor:outdent-selected-rows' }
+          { label: '&Auto Indent', command: 'editor:auto-indent' }
           { type: 'separator' }
-          { label: 'Move Line Up', command: 'editor:move-line-up' }
-          { label: 'Move Line Down', command: 'editor:move-line-down' }
-          { label: 'Duplicate Line', command: 'editor:duplicate-line' }
-          { label: 'Delete Line', command: 'editor:delete-line' }
-          { label: 'Join Lines', command: 'editor:join-line' }
+          { label: 'Move Line &Up', command: 'editor:move-line-up' }
+          { label: 'Move Line &Down', command: 'editor:move-line-down' }
+          { label: 'Du&plicate Line', command: 'editor:duplicate-line' }
+          { label: 'D&elete Line', command: 'editor:delete-line' }
+          { label: '&Join Lines', command: 'editor:join-line' }
         ]
       }
       {
         label: 'Text',
         submenu: [
-          { label: 'Upper Case', command: 'editor:upper-case' }
-          { label: 'Lower Case', command: 'editor:lower-case' }
+          { label: '&Upper Case', command: 'editor:upper-case' }
+          { label: '&Lower Case', command: 'editor:lower-case' }
           { type: 'separator' }
-          { label: 'Delete to End of Word', command: 'editor:delete-to-end-of-word' }
-          { label: 'Delete Line', command: 'editor:delete-line' }
+          { label: 'Delete to End of &Word', command: 'editor:delete-to-end-of-word' }
+          { label: '&Delete Line', command: 'editor:delete-line' }
           { type: 'separator' }
-          { label: 'Transpose', command: 'editor:transpose' }
+          { label: '&Transpose', command: 'editor:transpose' }
         ]
       }
       {
         label: 'Folding',
         submenu: [
-          { label: 'Fold', command: 'editor:fold-current-row' }
-          { label: 'Unfold', command: 'editor:unfold-current-row' }
-          { label: 'Unfold All', command: 'editor:unfold-all' }
+          { label: '&Fold', command: 'editor:fold-current-row' }
+          { label: '&Unfold', command: 'editor:unfold-current-row' }
+          { label: 'Unfold &All', command: 'editor:unfold-all' }
           { type: 'separator' }
-          { label: 'Fold All', command: 'editor:fold-all' }
+          { label: 'Fol&d All', command: 'editor:fold-all' }
           { label: 'Fold Level 1', command: 'editor:fold-at-indent-level-1' }
           { label: 'Fold Level 2', command: 'editor:fold-at-indent-level-2' }
           { label: 'Fold Level 3', command: 'editor:fold-at-indent-level-3' }
@@ -85,55 +85,55 @@
   {
     label: '&View'
     submenu: [
-      { label: 'Reload', command: 'window:reload' }
-      { label: 'Toggle Full Screen', command: 'window:toggle-full-screen' }
+      { label: '&Reload', command: 'window:reload' }
+      { label: 'Toggle &Full Screen', command: 'window:toggle-full-screen' }
       {
         label: 'Developer'
         submenu: [
-          { label: 'Open In Dev Mode...', command: 'application:open-dev' }
-          { label: 'Run Atom Specs', command: 'application:run-all-specs' }
-          { label: 'Run Package Specs', command: 'window:run-package-specs' }
-          { label: 'Toggle Developer Tools', command: 'window:toggle-dev-tools' }
+          { label: 'Open In &Dev Mode...', command: 'application:open-dev' }
+          { label: 'Run &Atom Specs', command: 'application:run-all-specs' }
+          { label: 'Run Package &Specs', command: 'window:run-package-specs' }
+          { label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
         ]
       }
       { type: 'separator' }
-      { label: 'Toggle Soft Wrap', command: 'editor:toggle-soft-wrap' }
+      { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' }
     ]
   }

   {
     label: '&Selection'
     submenu: [
-      { label: 'Add Selection Above', command: 'editor:add-selection-above' }
-      { label: 'Add Selection Below', command: 'editor:add-selection-below' }
+      { label: 'Add Selection &Above', command: 'editor:add-selection-above' }
+      { label: 'Add Selection &Below', command: 'editor:add-selection-below' }
       { type: 'separator' }
-      { label: 'Select to Top', command: 'core:select-to-top' }
-      { label: 'Select to Bottom', command: 'core:select-to-bottom' }
+      { label: 'Select to &Top', command: 'core:select-to-top' }
+      { label: 'Select to Botto&m', command: 'core:select-to-bottom' }
       { type: 'separator' }
-      { label: 'Select Line', command: 'editor:select-line' }
-      { label: 'Select Word', command: 'editor:select-word' }
-      { label: 'Select to Beginning of Word', command: 'editor:select-to-beginning-of-word' }
-      { label: 'Select to Beginning of Line', command: 'editor:select-to-beginning-of-line' }
-      { label: 'Select to First Character of Line', command: 'editor:select-to-first-character-of-line' }
-      { label: 'Select to End of Word', command: 'editor:select-to-end-of-word' }
-      { label: 'Select to End of Line', command: 'editor:select-to-end-of-line' }
+      { label: 'Select &Line', command: 'editor:select-line' }
+      { label: 'Select &Word', command: 'editor:select-word' }
+      { label: 'Select to Beginning of W&ord', command: 'editor:select-to-beginning-of-word' }
+      { label: 'Select to Beginning of L&ine', command: 'editor:select-to-beginning-of-line' }
+      { label: 'Select to First &Character of Line', command: 'editor:select-to-first-character-of-line' }
+      { label: 'Select to End of Wor&d', command: 'editor:select-to-end-of-word' }
+      { label: 'Select to End of Lin&e', command: 'editor:select-to-end-of-line' }
     ]
   }

   {
     label: '&Movement'
     submenu: [
-      { label: 'Move to Top', command: 'core:move-to-top' }
-      { label: 'Move to Bottom', command: 'core:move-to-bottom' }
+      { label: 'Move to &Top', command: 'core:move-to-top' }
+      { label: 'Move to &Bottom', command: 'core:move-to-bottom' }
       { type: 'separator' }
-      { label: 'Move to Beginning of Line', command: 'editor:move-to-beginning-of-line' }
-      { label: 'Move to First Character of Line', command: 'editor:move-to-first-character-of-line' }
-      { label: 'Move to End of Line', command: 'editor:move-to-end-of-line' }
+      { label: 'Move to Beginning of &Line', command: 'editor:move-to-beginning-of-line' }
+      { label: 'Move to &First Character of Line', command: 'editor:move-to-first-character-of-line' }
+      { label: 'Move to &End of Line', command: 'editor:move-to-end-of-line' }
       { type: 'separator' }
-      { label: 'Move to Beginning of Word', command: 'editor:move-to-beginning-of-word' }
-      { label: 'Move to End of Word', command: 'editor:move-to-end-of-word' }
-      { label: 'Move to Next Word', command: 'editor:move-to-next-word-boundary' }
-      { label: 'Move to Previous Word', command: 'editor:move-to-previous-word-boundary' }
+      { label: 'Move to Beginning of &Word', command: 'editor:move-to-beginning-of-word' }
+      { label: 'Move to End of Wor&d', command: 'editor:move-to-end-of-word' }
+      { label: 'Move to &Next Word', command: 'editor:move-to-next-word-boundary' }
+      { label: 'Move to &Previous Word', command: 'editor:move-to-previous-word-boundary' }
     ]
   }

@@ -150,22 +150,22 @@
   {
     label: '&Window'
     submenu: [
-      { label: 'Minimize', command: 'application:minimize' }
-      { label: 'Zoom', command: 'application:zoom' }
+      { label: 'Mi&nimize', command: 'application:minimize' }
+      { label: 'Ma&ximize', command: 'application:zoom' }
       { type: 'separator' }
-      { label: 'Bring All to Front', command: 'application:bring-all-windows-to-front' }
+      { label: 'Bring &All to Front', command: 'application:bring-all-windows-to-front' }
     ]
   }

   {
     label: '&Help'
     submenu: [
-      { label: 'About Atom', command: 'application:about' }
+      { label: '&About Atom...', command: 'application:about' }
       { label: "VERSION", enabled: false }
-      { label: "Install update", command: 'application:install-update', visible: false }
+      { label: "Install &update", command: 'application:install-update', visible: false }
       { type: 'separator' }
-      { label: 'Documentation', command: 'application:open-documentation' }
-      { label: 'Report an Issue', command: 'application:report-issue' }
+      { label: '&Documentation', command: 'application:open-documentation' }
+      { label: 'Report an &Issue', command: 'application:report-issue' }
       { type: 'separator' }
     ]
   }


CLI making the 'install' command to activate the latest version of a package after the installation

--- cli/commands/install.coffee
+++ cli/commands/install.coffee
@@ -12,12 +12,13 @@
   package  = require('../package')

   location[location.length - 1] == '/' || (location += '/')
-  location += "#{package.name}/#{package.version}"
+  location += "packages/#{package.name}/#{package.version}"

   system "rm -rf #{location}", ->
     system "mkdir -p #{location}", ->
       system "../../bin/lovely build", ->
-        system "cp -r ./* #{location}"
+        system "cp -r ./* #{location}", ->
+          system "../../bin/lovely activate #{package.name}"

 exports.help = (args) ->


Login: github button added

Login: github button added

--- client/Login/AppView.coffee
+++ client/Login/AppView.coffee
@@ -46,6 +46,11 @@
       tagName     : "a"
       partial     : "Create Account"
       click       : registerHandler
+
+    @github       = new KDButtonView
+      title       : 'Sign in with GitHub'
+      style       : 'solid'
+      callback    : -> KD.singletons.oauthController.openPopup "github"

     # @loginOptions = new LoginOptions
     #   cssClass : "login-options-holder log"
@@ -164,6 +169,7 @@

{{> @goToRecoverLink}}

{{> @goToRegisterLink}}•{{> @backToLoginLink}}

+        {{> @github}}