reenabled stricter caching on `For` compilation as well as reduced a line from it

--- nodes.coffee
+++ nodes.coffee
@@ -622,16 +622,16 @@
     parts = []
     parts.push @from if @from isnt @fromVar
     parts.push @to if @to isnt @toVar
-    if parts.length then "#{parts.join('; ')}; " else ''

   # When compiled normally, the range returns the contents of the *for loop*
   # needed to iterate over the values in the range. Used by comprehensions.
   compileNode: (o) ->
+    @compileVariables o
     return    @compileArray(o)  unless o.index
     return    @compileSimple(o) if @fromNum and @toNum
     idx      = del o, 'index'
     step     = del o, 'step'
-    vars     = "#{idx} = #{@fromVar}"
+    vars     = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
     intro    = "(#{@fromVar} <= #{@toVar} ? #{idx}"
     compare  = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"
     stepPart = if step then step.compile(o) else '1'
@@ -651,21 +651,21 @@

   # When used as a value, expand the range into the equivalent array.
   compileArray: (o) ->
-    idt    = @idt 1
-    vars   = @compileVariables merge o, indent: idt
     if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20
       range = [+@fromNum..+@toNum]
       range.pop() if @exclusive
       return "[#{ range.join(', ') }]"
-    i = o.scope.freeVariable 'i'
+    idt    = @idt 1
+    i      = o.scope.freeVariable 'i'
     result = o.scope.freeVariable 'result'
-    pre    = "\n#{idt}#{result} = []; #{vars}"
+    pre    = "\n#{idt}#{result} = [];"
     if @fromNum and @toNum
       o.index = i
       body = @compileSimple o
     else
+      vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
       clause = "#{@fromVar} <= #{@toVar} ?"
-      body   = "var #{i} = #{@fromVar}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
+      body   = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
     post   = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
     "(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)"

@@ -1431,11 +1431,15 @@
     body          = Expressions.wrap([@body])
     idt1          = @idt 1
     if range
-      sourcePart  = source.compileVariables(o)
       forPart     = source.compile merge o, index: ivar, step: @step
     else
-      [sourcePart, svar] = @source.compileReference merge(o, top: yes), precompile: yes
-      sourcePart = if sourcePart is svar then '' else "#{sourcePart};"
+      svar = @source.compile o
+      if IDENTIFIER.test(svar) and scope.check(svar, immediate: on)
+        sourcePart = svar
+      else
+        sourcePart = "#{ref = scope.freeVariable 'ref'} = #{svar}"
+        sourcePart = "(#{sourcePart})" unless @object
+        svar = ref
       namePart = if @pattern
         new Assign(@name, literal "#{svar}[#{ivar}]").compile merge o, top: on
       else if name
@@ -1443,9 +1447,8 @@
       unless @object
         lvar      = scope.freeVariable 'len'
         stepPart  = if @step then "#{ivar} += #{ @step.compile(o) }" else "#{ivar}++"
-        forPart   = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
-    sourcePart    = (if rvar then "#{rvar} = []; " else '') + sourcePart
-    sourcePart    = if sourcePart then "#{@tab}#{sourcePart}\n#{@tab}" else @tab
+        forPart   = "#{ivar} = 0, #{lvar} = #{sourcePart}.length; #{ivar} < #{lvar}; #{stepPart}"
+    resultPart    = if rvar then "#{@tab}#{rvar} = [];\n" else ''
     returnResult  = @compileReturnValue(rvar, o)
     body          = Push.wrap(rvar, body) unless topLevel
     if @guard
@@ -1458,12 +1461,12 @@
     else
       varPart     = "#{idt1}#{namePart};\n" if namePart
     if @object
-      forPart     = "#{ivar} in #{svar}"
+      forPart     = "#{ivar} in #{sourcePart}"
       guardPart   = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
     body          = body.compile merge o, indent: idt1, top: true
     vars          = if range then name else "#{name}, #{ivar}"
     """
-    #{sourcePart}for (#{forPart}) {#{guardPart}
+    #{resultPart}#{@tab}for (#{forPart}) {#{guardPart}
     #{varPart}#{body}
     #{@tab}}#{returnResult}
     """


fixing multiple evaluation of splat sources, when it's an invoked function

--- nodes.coffee
+++ nodes.coffee
@@ -363,6 +363,10 @@
   compile_splat: (o) ->
     meth: @variable.compile o
     obj:  @variable.source or 'this'
+    if obj.match(/\(/)
+      temp: o.scope.free_variable()
+      obj:  temp
+      meth: '(' + temp + ' = ' + @variable.source + ')' + @variable.last
     args: for arg, i in @args
       code: arg.compile o
       code: if arg instanceof SplatNode then code else '[' + code + ']'


Adding configuration doc

Adding configuration doc

--- twitch.coffee
+++ twitch.coffee
@@ -5,7 +5,8 @@
 #   None
 #
 # Configuration:
-#   None
+#   TWITCH_API_KEY
+#   HUBOT_TWITCH_KEY
 #
 # Commands:
 #   hubot ttv follows - Returns live streams belonging to your followed channels (list populated from your linked Twitch user)


Fixed not rerendering on slide exit

Fixed not rerendering on slide exit

--- coffee/main.coffee
+++ coffee/main.coffee
@@ -49,12 +49,13 @@
       model.showIndex = 'indexed'
     else
       model.showIndex = ''
-  mode: (mode) ->
+  mode: (mode, old) ->
     model.mode = {
       write: 'full-input'
       read: 'full-view'
       present: 'present'
     }[mode] or ''
+    updateView() if old is 'present'
   slide: (nr) -> updateView()
   theme: (v) ->
     model.theme = v


Label: add support for setTextMaxChars

Label: add support for setTextMaxChars

--- src/elements/Label/Label.coffee
+++ src/elements/Label/Label.coffee
@@ -124,6 +124,9 @@
 			@setContent($text(@__currentText))
 			@removeClass("cui-label-markdown")
 		@
+
+	setTextMaxChars: (max_chars) ->
+		CUI.DOM.setAttribute(@__label.map.content[0], "max-chars", max_chars)

 	getText: ->
 		@__currentText


extracting SingleCamera module

extracting SingleCamera module

--- src/engine_single_camera.coffee
+++ src/engine_single_camera.coffee
@@ -8,9 +8,10 @@
   # Add events and methods here
   self.bind "draw", ->
     I.canvas.withTransform I.cameraTransform, (canvas) ->
-      # TODO Turn this zSort into a per camera object stream filter
       drawObjects = self.objects()

+      # TODO Turn this zSort into a per camera object stream filter
+      # This will also enable filters like clipping region tests
       if I.zSort
         drawObjects.sort (a, b) ->
           a.I.zIndex - b.I.zIndex


Add CMs to multinomial prediction output.

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -736,17 +736,22 @@
   extendPrediction = (modelKey, frameKey, prediction) ->
     opts = { model: modelKey, frame: frameKey }
     render_ prediction, -> H2O.PredictOutput _, prediction
+
+    inspections = {}
     switch prediction.model_category
-      when 'Regression', 'Multinomial', 'Clustering'
-        inspect_ prediction,
-          prediction: inspectRegressionPrediction prediction
-      else
-        inspections = {}
+      when 'Regression', 'Clustering'
+        inspections.prediction = inspectRegressionPrediction prediction
+
+      when 'Multinomial'
+        inspections.prediction = inspectRegressionPrediction prediction
+        inspectMultinomialConfusionMatrix 'Confusion Matrix', prediction.cm.table, "getPrediction #{stringify modelKey}, #{stringify frameKey}", inspections
+      else
         inspections[ 'Prediction' ] = inspectBinomialPrediction prediction
         inspections[ prediction.thresholdsAndMetricScores.name ] = inspectBinomialScores opts, [ prediction ]
         inspections[ prediction.maxCriteriaAndMetricScores.name ] = inspectBinomialMetrics opts, [ prediction ]
         inspections[ 'Confusion Matrices' ] = inspectBinomialConfusionMatrices opts, [ prediction ]
-        inspect_ prediction, inspections
+
+    inspect_ prediction, inspections

   inspectFrameColumns = (tableLabel, frameKey, frame, frameColumns) -> ->
     attrs = [


Removes rpm depndency lsb-core-noarch

Removes rpm depndency lsb-core-noarch

--- tasks/pack.coffee
+++ tasks/pack.coffee
@@ -234,7 +234,6 @@
         ]
       else
         deps = [
-          'lsb-core-noarch'
           'libappindicator1'
         ]


teamwork: display "invite link" if user is logged in

--- client/Teamwork/Views/teamworkchatpane.coffee
+++ client/Teamwork/Views/teamworkchatpane.coffee
@@ -185,11 +185,12 @@
       tooltip  :
         title  : messages.botTooltip

-    @avatars.addSubView new KDCustomHTMLView
-      cssClass : "tw-add-user"
-      tooltip  :
-        title  : "Click here to invite your friends"
-      click    : => new TeamworkInviteModal delegate: this
+    if KD.isLoggedIn()
+      @avatars.addSubView new KDCustomHTMLView
+        cssClass : "tw-add-user"
+        tooltip  :
+          title  : "Click here to invite your friends"
+        click    : => new TeamworkInviteModal delegate: this

   getMessage = (key, data) ->
     return messages[key].replace "$0", data


Add close sidebar on fork initiation

Add close sidebar on fork initiation

--- client/angular/components/thread_page/thread_item/new_comment.coffee
+++ client/angular/components/thread_page/thread_item/new_comment.coffee
@@ -30,7 +30,9 @@
       name: 'fork_comment'
       icon: 'mdi-call-split'
       canPerform: -> AbilityService.canForkComment($scope.eventable)
-      perform:    -> $scope.event.toggleFromFork()
+      perform:    ->
+        EventBus.broadcast $rootScope, 'toggleSidebar'
+        $scope.event.toggleFromFork()
     ,
       name: 'translate_comment'
       icon: 'mdi-translate'


collaboration: use fetchParticipants helper

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -99,16 +99,12 @@
   # return if result set exists.
   listChatParticipants: (callback) ->

-    channelId = @socialChannel.getId()
-
-    {socialapi} = kd.singletons
-    socialapi.channel.listParticipants {channelId}, (err, participants) ->
-
-      idList = participants.map ({accountId}) -> accountId
-      query  = socialApiId: $in: idList
-
-      remote.api.JAccount.some query, {}
-        .then callback
+    id = @getSocialChannelId()
+
+    socialHelpers.fetchParticipants id, (err, accounts) =>
+      return throwError err  if err
+
+      callback accounts

   continuePrivateMessage: (callback) ->


Reset collaboration state.

Reset collaboration state.

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -659,7 +659,8 @@
   onCollaborationPreparing: ->

     # Don't allow when the mounted machine isn't running.
-    return  unless @isMachineRunning()
+    unless @isMachineRunning()
+      return @stateMachine.state = @stateMachine.initialState

     @prepareChatSession
       success : => @stateMachine.transition 'Prepared'
@@ -680,7 +681,8 @@
   onCollaborationCreating: ->

     # Don't allow when the mounted machine isn't running.
-    return  unless @isMachineRunning()
+    unless @isMachineRunning()
+      return @stateMachine.state = @stateMachine.initialState

     @createCollaborationSession
       success : (doc) =>


Fixed typo

Fixed typo

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -198,7 +198,7 @@
     @chat.emit 'ParticipantJoined', targetUser
     @statusBar.emit 'ParticipantJoined', targetUser

-    Tracker.track track.USED_COLLABORATION
+    Tracker.track Tracker.USED_COLLABORATION

     if @amIHost and targetUser isnt nick()
       @ensureMachineShare [targetUser], (err) =>


Updating

Updating

--- config.cson
+++ config.cson
@@ -40,7 +40,7 @@
   "julia-client":
     enableMenu: true
     enableToolBar: true
-    launchOnStartup: true
+    launchOnStartup: false
   "markdown-writer":
     textStyles:
       codeblock:


corrections for octal escape sequences; allows "\0" alone; see #1547

Relevant sections of the spec:
* http://es5.github.com/#C
* http://es5.github.com/#B.1.2
* http://es5.github.com/#x7.8.4

--- lexer.coffee
+++ lexer.coffee
@@ -164,7 +164,7 @@
           @token 'STRING', @escapeLines string
       else
         return 0
-    if octalEsc = /^(?:\\.|[^\\])*\\[0-7]/.test string
+    if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string
       @error "octal escape sequences #{string} are not allowed"
     @line += count string, '\n'
     string.length


empty regular expressions with flags still need to be compiled to /(?:)/

--- lexer.coffee
+++ lexer.coffee
@@ -198,11 +198,11 @@
     prev = last @tokens
     return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
     return 0 unless match = REGEX.exec @chunk
-    [regex] = match
-    if regex.match /^\/\*/ then @error 'regular expressions cannot begin with `*`'
+    [match, regex, flags] = match
+    if regex[..1] is '/*' then @error 'regular expressions cannot begin with `*`'
     if regex is '//' then regex = '/(?:)/'
-    @token 'REGEX', regex
-    regex.length
+    @token 'REGEX', "#{regex}#{flags}"
+    match.length

   # Matches multiline extended regular expressions.
   heregexToken: (match) ->
@@ -607,7 +607,7 @@

 # Regex-matching-regexes.
 REGEX = /// ^
-  / (?! [\s=] )       # disallow leading whitespace or equals signs
+  (/ (?! [\s=] )   # disallow leading whitespace or equals signs
   [^ [ / \n \\ ]*  # every other thing
   (?:
     (?: \\[\s\S]   # anything escaped
@@ -617,7 +617,7 @@
          ]
     ) [^ [ / \n \\ ]*
   )*
-  / [imgy]{0,4} (?!\w)
+  /) ([imgy]{0,4}) (?!\w)
 ///

 HEREGEX      = /// ^ /{3} ([\s\S]+?) /{3} ([imgy]{0,4}) (?!\w) ///


reset access token on user logout

reset access token on user logout

--- src/remote/services/hull.coffee
+++ src/remote/services/hull.coffee
@@ -8,6 +8,9 @@
     config = app.config

     identified = false
+
+    accessToken     = app.config.access_token
+    originalUserId  = app.config.data?.me?.id

     identify = (me) ->
       return unless me
@@ -41,8 +44,8 @@
         req_data = req.params

       request_headers = { 'Hull-App-Id': config.appId }
-      if config.access_token
-        request_headers['Hull-Access-Token'] = config.access_token
+      if accessToken
+        request_headers['Hull-Access-Token'] = accessToken

       request = $.ajax
         url: url
@@ -60,6 +63,10 @@
           memo[name] = value if value?
           memo
         , {}
+
+        if accessToken && originalUserId && originalUserId != headers['Hull-User-Id']
+          # Reset token if the user has changed...
+          accessToken = false

         callback({ response: response, headers: headers, provider: 'hull' })


When the player completes a level, the next one shows up.

--- src/script/GameplayState.coffee
+++ src/script/GameplayState.coffee
@@ -73,6 +73,9 @@
     game.physics.arcade.overlap(@ball, @wallRight, @collideX)
     game.physics.arcade.collide(@ball, @boxes, @collideBlock)

+    # If the ball falls below the level, lose a life!
+    # If the player runs out of lives, take her back
+    # to the title screen.
     if @ball.body.position.y > 1100
       lives--
       @ball.body.position.y = 780
@@ -85,6 +88,13 @@
         @ball.body.velocity.x *= 0

         game.state.start("TitleScreen")
+
+    # If the player finishes all the blocks,
+    # start the next level for him.
+    if @boxes.countLiving() <= 0
+      currentLevel++
+      game.state.start('Gameplay')
+

   render: () ->
     game.debug.body(@square)


toggle payment radio button css

toggle payment radio button css


add: DropBox

add: DropBox

--- rsync/Gruntfile.coffee
+++ rsync/Gruntfile.coffee
@@ -30,11 +30,28 @@
         options:
           src:  '~/Music/'
           dest: '/Volumes/LaCieHD1TB/Music/'
+      dropboxDryrun:
+        options:
+          src:  '~/Dropbox/'
+          dest: '/Volumes/LaCieHD1TB/Dropbox/'
+          dryRun: true
+      dropbox:
+        options:
+          src:  '~/Dropbox/'
+          dest: '/Volumes/LaCieHD1TB/Dropbox/'

   # These plugins provide necessary tasks.
   grunt.loadNpmTasks "grunt-rsync"

   # Default task.
-  grunt.registerTask 'default', ['rsync:archiveDryrun', 'rsync:musicDryrun']
-  grunt.registerTask 'run', ['rsync:archive', 'rsync:music']
+  grunt.registerTask 'default', [
+    'rsync:archiveDryrun',
+    'rsync:musicDryrun',
+    'rsync:dropboxDryrun'
+  ]
+  grunt.registerTask 'run', [
+    'rsync:archive',
+    'rsync:music',
+    'rsync:dropbox'
+  ]
   return


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_selector.coffee
+++ src/engine_selector.coffee
@@ -70,7 +70,7 @@
     Object.extend results, instanceMethods

   first: (selector) ->
-    se
+    self.find()

 Object.extend Engine.Selector,
   parse: (selector) ->


Extracted function

Extracted function

--- core/app/backbone/views/evidence/ndp_evidence_collection_view.coffee
+++ core/app/backbone/views/evidence/ndp_evidence_collection_view.coffee
@@ -5,14 +5,16 @@
   regions:
     contentRegion: '.js-content-region'

-  templateHelpers:
-    type_css: ->
-      switch @type
-        when 'believe' then 'supporting'
-        when 'disbelieve' then 'weakening'
-        when 'doubt' then 'unsure'
+  templateHelpers: =>
+    type_css: => @typeCss()
     is_unsure: -> @type == 'doubt'
     formatted_impact: -> format_as_authority @impact
+
+  typeCss: ->
+    switch @model.get('type')
+      when 'believe' then 'supporting'
+      when 'disbelieve' then 'weakening'
+      when 'doubt' then 'unsure'

   onRender: ->
     @$el.toggle @model.has('impact')


fix string highlighting and scapes in strings

--- client/front.coffee
+++ client/front.coffee
@@ -178,7 +178,10 @@
                        colored.push(["string", ""])
                        last = colored[colored.length-1]
                     last[1] += c
-                    if c == mode
+                    if c == spec.ESCAPECHAR
+                       c = next()
+                       last[1] += c
+                    else if c == mode
                         mode = "plain"

             old_c = c
@@ -816,7 +819,7 @@
                     oldline = @lines[i]
                     oldline[1] = start
                     oldline[2] = end
-                    if oldline[3] != line
+                    if oldline[3] != line or oldline[4][0] != prev_mode
                         [colored, mode, html] = @tokenizer.tokenize(line, prev_mode)
                         oldline[3] = line
                         oldline[4] = mode
@@ -919,4 +922,3 @@

 $ ->
     window.editor = new Editor()
-


Keep cursor at the end of the input

Keep cursor at the end of the input

--- SingularityUI/app/views/view.coffee
+++ SingularityUI/app/views/view.coffee
@@ -35,7 +35,7 @@

     afterRender: ->
       Sortable.init()
-
+
       # Paginate client side collections
       $('table.paginated:not([id])').DataTable
         ordering: false
@@ -49,4 +49,10 @@
           next: ''
       $('table.paginated').css('display', 'table');

+      searchInput = $('.big-search-box')
+      strLength= searchInput.val().length * 2
+      if strLength > 0
+        searchInput.focus()
+        searchInput[0].setSelectionRange(strLength, strLength)
+
 module.exports = View


prefix isMounted sentinel

prefix isMounted sentinel

--- tutor/src/components/book-content-mixin.cjsx
+++ tutor/src/components/book-content-mixin.cjsx
@@ -25,14 +25,14 @@

 LinkContentMixin =
   componentDidMount:  ->
-    @_isMounted = true
+    @_linkContentIsMounted = true
     @processLinks()

   componentDidUpdate: ->
     @processLinks()

   componentWillUnmount: ->
-    @_isMounted = false
+    @_linkContentIsMounted = false
     @cleanUpLinks()

   getCnxIdOfHref: (href) ->
@@ -126,7 +126,7 @@
     _.defer(@_processLinks)

   _processLinks: ->
-    return unless @_isMounted
+    return unless @_linkContentIsMounted
     root = ReactDOM.findDOMNode(@)
     mediaLinks = root.querySelectorAll(MediaStore.getSelector())
     exerciseLinks = root.querySelectorAll(EXERCISE_LINK_SELECTOR)


Adding basic routes for routing's tests

Adding basic routes for routing's tests

--- tests/www/probatus/src/app/config/routes.coffee
+++ tests/www/probatus/src/app/config/routes.coffee
@@ -8,14 +8,37 @@
       to: "pages/container"
       at: null
       el: "body"
+
+    '/pages/index':
+      to: "pages/index"
+      at: "/pages"
+      el: "#container"
+
+
+
+    '/routing/simple':
+      to: "routing/simple"
+      at: "/pages"
+      el: "#container"
+
+    '/routing/deep/?(:name)?':
+      to: "routing/deep"
+      at: "/routing/simple"
+      el: "#simple-container"
+
+    '/routing/dynamic':
+      to: "routing/dynamic"
+      at: "/routing/deep"
+      el: "#deep-container"
+
+    '/routing/dynamic/:name':
+      to: "routing/dynamic"
+      at: "/routing/deep/:name"
+      el: "#deep-container"
+

     '/404':
       to: "pages/notfound"
-      at: "/pages"
-      el: "#container"
-
-    '/pages/index':
-      to: "pages/index"
       at: "/pages"
       el: "#container"


Added modal, veil, and montage thumbs.

Added modal, veil, and montage thumbs.

--- src/Templates.coffee
+++ src/Templates.coffee
@@ -1,28 +1,48 @@
+exports.body = "
+

+

+

+            Generator
+

+

+            Top Row Editor
+

+

+

+

+

+

+"
+
 exports.generatorBoard = "

 "
+
+
 exports.colorPickers = "

Active Cell

-        <select id='wolfcage-colorpicker-active-hex' ></select>
+        <select id='wolfcage-colorpicker-select-active-hex' ></select>

Cell Border

-        <select id='wolfcage-colorpicker-border-hex'  ></select>
+        <select id='wolfcage-colorpicker-select-border-hex'  ></select>

Inactive Cell

-        <select id='wolfcage-colorpicker-inactive-hex'  ></select>
+        <select id='wolfcage-colorpicker-select-inactive-hex'  ></select>

 "

 exports.colorPickerOption = (color)=>
     return "<option value='#{color.hex}' style='background-color:#{color.hex}'>
-                   #{color.name}
+
             </option>"

 exports.generatorPreviewCell = ({leftBitActive, middleBitActive, rightBitActive, previewIndex}) =>
@@ -61,6 +81,8 @@
                     class=''></select>
             <button id='wolfcage-generator-colorpicker-button'
                     class=''>Color Picker</button>
+            <button id='wolfcage-generator-thumbmontage-button'
+                    class=''>Thumbs</button>

@@ -84,40 +106,22 @@

     "

-exports.tabs = "
-

-    Thumbnails
-

-

-    Generator
-

-

-    Top Row Editor
-

+exports.thumbMontage = "
+

 "

-thumbnail = (path, rule)=>
+thumbnail = (rule)=>
     return "
-        <div class='wolfcage-rulethumb-box'
+

-

#{rule}

     "

-exports.thumbnails = ({path, ruleList}) =>
+exports.thumbnails = (ruleList) =>
     nails = ""
     for rule in ruleList
-        nails += thumbnail(path, rule)
+        nails += thumbnail(rule)
     return nails


closes #162

closes #162

--- src/general/console.coffee
+++ src/general/console.coffee
@@ -50,7 +50,7 @@
       stack = stack.filter((e) ->
         e.indexOf("Error") isnt 0 and e.indexOf("d3plus.js:") < 0 and e.indexOf("d3plus.min.js:") < 0
       )
-      if stack.length
+      if stack.length and stack[0].length
         splitter = (if window.chrome then "at " else "@")
         url = stack[0].split(splitter)[1]
         stack = url.split(":")


remove legacy lobby polling

remove legacy lobby polling

--- app/utils/ServerAPIBridge.coffee
+++ app/utils/ServerAPIBridge.coffee
@@ -1,7 +1,4 @@
 request = require('superagent')
-
-lobbyPoll = false
-LOBBY_TIMEOUT = 2000

 processIdentity = (error, res)->
   # TODO: handle errors
@@ -12,8 +9,6 @@
   # TODO: handle errors
   return if error
   AppActionCreators.processLobby(res.body.identities)
-  if lobbyPoll
-    setTimeout ServerAPIBridge.getLobby, LOBBY_TIMEOUT

 ServerAPIBridge =

@@ -27,13 +22,6 @@
     request.open('GET', "/unidentify/#{identity}", false) #false for synchronous
     request.send(null)

-  beginLobbyPoll: ->
-    lobbyPoll = true
-    ServerAPIBridge.getLobby()
-
-  cancelLobbyPoll: ->
-    lobbyPoll = false
-
   getLobby: ->
     console.log("GETTING LOBBY")
     request.get("/lobby").end(processLobby)


Not actually successfully testing the message, but does test for a valid WS server

--- test/front.coffee
+++ test/front.coffee
@@ -19,12 +19,12 @@
     stub.on 'connection', (ws) ->
       console.log 'input was' + ws
     stub.on 'message', (message) ->
-      message.should == 'foo'
+      console.log message

     @front.start {port: 3020, host: "0.0.0.0", apiEndpoint: "ws://localhost:3021"}
     client = new WebSocket("ws://localhost:3020")
     client.on 'connection', () ->
-      client.send 'foo'
+      client.send 'my message is foo'

   it 'should connect to the API', ->


null check

null check

--- urb/zod/pub/tree/src/js/stores/TreeStore.coffee
+++ urb/zod/pub/tree/src/js/stores/TreeStore.coffee
@@ -24,7 +24,7 @@
     for k,t of query when QUERIES[k]
       if t isnt QUERIES[k] then throw TypeError "Wrong query type: #{k}, '#{t}'"
       data[k] = _data[path]?[k]
-    if query.kids and not _data[path].EMPTY
+    if query.kids and not _data[path]?.EMPTY
       data.kids = {}
       for k,sub of tree
         data.kids[k] = @fulfillAt sub, path+"/"+k, query.kids


Modify command description

Modify command description

--- scripts/lookslike.coffee
+++ scripts/lookslike.coffee
@@ -2,9 +2,9 @@
 #   hubot に誰かが何に似てるか教えたり聞いたりする
 #
 # Commands:
-#   hubot xxx looks like keyword
-#   hubot who does xxx look like?
-#   hubot xxx does not look like anyone
+#   hubot <user> looks like keyword
+#   hubot who does <user> look like?
+#   hubot <user> does not look like anyone

 module.exports = (robot) ->


coco b8039b9: merged @closeOpenCalls and @closeOpenIndexes into @closeOpenPairs

--- rewriter.coffee
+++ rewriter.coffee
@@ -20,8 +20,7 @@
   rewrite: (@tokens) ->
     @removeLeadingNewlines()
     @removeMidExpressionNewlines()
-    @closeOpenCalls()
-    @closeOpenIndexes()
+    @closeOpenPairs()
     @addImplicitIndentation()
     @tagPostfixConditionals()
     @addImplicitBraces()
@@ -68,27 +67,19 @@
       tokens.splice i, 1
       0

-  # The lexer has tagged the opening parenthesis of a method call. Match it with
-  # its paired close. We have the mis-nested outdent case included here for
-  # calls that close on the same line, just before their outdent.
-  closeOpenCalls: ->
-    condition = (token, i) ->
-      token[0] in [')', 'CALL_END'] or
-      token[0] is 'OUTDENT' and @tag(i - 1) is ')'
-    action = (token, i) ->
-      @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END'
-    @scanTokens (token, i) ->
-      @detectEnd i + 1, condition, action if token[0] is 'CALL_START'
-      1
-
-  # The lexer has tagged the opening parenthesis of an indexing operation call.
-  # Match it with its paired close.
-  closeOpenIndexes: ->
-    condition = (token, i) -> token[0] in [']', 'INDEX_END']
-    action    = (token, i) -> token[0] = 'INDEX_END'
-    @scanTokens (token, i) ->
-      @detectEnd i + 1, condition, action if token[0] is 'INDEX_START'
-      1
+  # The lexer has tagged the opening parenthesis of a method call, or the open
+  # bracket of an indexing operation. Match it with its paired close.
+  closeOpenPairs: ->
+    stack = []
+    for token in @tokens
+      switch token[0]
+        when 'CALL_START', 'INDEX_START', '(', '['
+          stack.push token[0]
+        when 'CALL_END', 'INDEX_END', ')', ']'
+          switch stack.pop()
+            when 'CALL_START'   then token[0] = 'CALL_END'
+            when 'INDEX_START'  then token[0] = 'INDEX_END'
+    this

   # Object literals may be written with implicit braces, for simple cases.
   # Insert the missing braces here, so that the parser doesn't have to.


New test

New test


test: Fix sort arg.

test: Fix sort arg.

--- test/index.coffee
+++ test/index.coffee
@@ -680,7 +680,7 @@
     cursor = cursor.skip 1
     cursor.should.have.property 'document'
     cursor.should.have.property 'cursor'
-    cursor = cursor.sort '_id'
+    cursor = cursor.sort {_id: 1}
     cursor.should.have.property 'document'
     cursor.should.have.property 'cursor'
     cursor.next (err, doc) ->


Add 404 route handling integration tests

--- test/index.coffee
+++ test/index.coffee
@@ -34,6 +34,21 @@
       .expect 403
       .end done

+describe 'Not Found', ->
+  it 'should return 404 for non existing endpoint', (done) ->
+    req.get '/does/not/exist'
+      .expect 404
+      .expect (res) ->
+        assert.deepEqual res.body, message: 'Not Found'
+      .end done
+
+  it 'should not return body for HEAD request', (done) ->
+    req.head '/does/not/exist'
+      .expect 404
+      .expect (res) ->
+        assert.deepEqual res.body, {}
+      .end done
+
 describe 'API v1', ->
   require './routes/api_v1-spec'


Make tests work

Make tests work

Signed-off-by: Ian Macalinao <08370e385f4778cad8fe504ec5445edd3d45bd9a@gmail.com>

--- test/items.coffee
+++ test/items.coffee
@@ -71,7 +71,7 @@
         itemNames = []
         for item in findOne("Vampiric Scepter").getBuildsInto()
           itemNames.push item.name
-        itemNames.should.eql ["Bilgewater Cutlass", "The Bloodthirster", "Wriggle's Lantern", "Zeke's Herald"]
+        itemNames.sort().should.eql ["Bilgewater Cutlass", "The Bloodthirster", "Wriggle's Lantern", "Zeke's Herald"].sort()

     describe "getTotalCost", ->


Fix a lint warning reported by `./script/grunt lint`.

Now it runs without reporting any issues.

--- src/input-component.coffee
+++ src/input-component.coffee
@@ -5,7 +5,7 @@
     @domNode.classList.add('hidden-input')
     @domNode.setAttribute('data-react-skip-selection-restoration', true)
     @domNode.style['-webkit-transform'] = 'translateZ(0)'
-    @domNode.addEventListener 'paste', (event) => event.preventDefault()
+    @domNode.addEventListener 'paste', (event) -> event.preventDefault()
     @updateSync()

   updateSync: ->


Specify plural of metadata_category

Specify plural of metadata_category

--- app/assets/javascripts/rglossa/data/adapter.coffee
+++ app/assets/javascripts/rglossa/data/adapter.coffee
@@ -2,6 +2,7 @@
   corpus:     'corpora'
   search:     'searches'
   cwb_search: 'cwb_searches'
+  metadata_category: 'metadata_categories'

 DS.RESTAdapter.configure 'App.MetadataCategory',
   sideloadAs: 'metadata_categories'


Allow consumers to dictate usage.

Allow consumers to dictate usage.

--- lib/assets/javascripts/aha/color_picker.js.coffee
+++ lib/assets/javascripts/aha/color_picker.js.coffee
@@ -135,23 +135,3 @@
     if typeof option == 'string'
       data[option].apply(data, args)
 $.fn.extend extendOptions
-
-#
-# Instantiate common colorpicker.
-#
-$ ->
-  $('.small-colorpicker-trigger:not(.disabled)').livequery ->
-    $(@).colorPicker().on 'changeColor', (event) ->
-      $(this).css('background-color', "##{event.color.hex}");
-
-      data = {}
-      data[$(@).data('model')] = {}
-      data[$(@).data('model')]['color'] = event.color.converted
-
-      url = $(@).data('action') || "/#{$(@).data('model')}s/#{$(@).data('id')}"
-      if $(@).data('format')
-        url += ".#{$(@).data('format')}"
-      $.ajax
-        url: url
-        type: 'PUT'
-        data: data


FIX: vertical scrolling with selection

FIX: vertical scrolling with selection

Former-commit-id: 58638aeb33adcd4a577e578d70a4de6f225f50ba [formerly f80747149cac3431b634f3bccd4be71ff2b70335]
Former-commit-id: 5b66b59b9dfac9d03ffcfec90727e34a32d25772

--- src/views/CanvasSeqBlock.coffee
+++ src/views/CanvasSeqBlock.coffee
@@ -50,13 +50,12 @@
     start = Math.max 0, Math.abs(Math.ceil( - @g.zoomer.get('_alignmentScrollTop') / rectHeight))
     y = - Math.abs( - @g.zoomer.get('_alignmentScrollTop') % rectHeight)

-    console.log start,y

     rectHeight = @g.zoomer.get "rowHeight"
     @ctx.globalAlpha = 1
     for i in [start.. @model.length - 1] by 1
       continue if @model.at(i).get('hidden')
-      @drawSeq {model: @model.at(i), y: y}
+      @drawSeq model: @model.at(i), y: y
       y = y + rectHeight
       # out of viewport - stop
       if y > @el.height
@@ -66,7 +65,7 @@
     # draw again - overlays
     for i in [start.. @model.length - 1] by 1
       continue if @model.at(i).get('hidden')
-      @drawSeqExtended {model: @model.at(i), y: y}
+      @drawSeqExtended model: @model.at(i), y: y
       y = y + rectHeight
       # out of viewport - stop
       if y > @el.height
@@ -90,7 +89,6 @@
       if color?
         @ctx.fillStyle = color
         @ctx.fillRect x,y,rectWidth,rectHeight
-        #@ctx.strokeText c,x + 3,y + 12,rectWidth
         @ctx.drawImage @cache.getFontTile(letter:c, width:rectWidth, height:
           rectHeight), x, y,rectWidth,rectHeight

@@ -112,7 +110,7 @@
     [mPrevSel,mNextSel] = @_getPrevNextSelection data.model
     features = data.model.get "features"

-    yZero = Math.ceil(data.y / rectHeight) * rectHeight
+    yZero = data.y

     for j in [start.. seq.length - 1] by 1
       starts = features.startOn j


disable reporting exceptions to exceptional when using laptop.

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -648,9 +648,10 @@
     process.exit 1
   , 30*1000

-process.on 'uncaughtException', (err) ->
-  console.warn err
-  Exceptional.handle err
-  setTimeout ->
-    process.kill process.pid, 'SIGTERM'
-  , 500
+if /staging|production/.test process.env.NODE_ENV
+  process.on 'uncaughtException', (err) ->
+    console.warn err
+    Exceptional.handle err
+    setTimeout ->
+      process.kill process.pid, 'SIGTERM'
+    , 500


Add missing return statement

Add missing return statement

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -855,6 +855,7 @@
   Dataset.findOneById req.params.dataset, (err, dataset) ->
     if err?
       resp.send 500, error: "Error creating view: #{err}"
+      return
     if not dataset
       return resp.send 404, error: "Error creating view: #{req.params.dataset} not found"


added CSRF helper to underscore

added CSRF helper to underscore

--- lib/assets/javascripts/underscore_patch.js.coffee
+++ lib/assets/javascripts/underscore_patch.js.coffee
@@ -19,15 +19,18 @@
 # alias away the sync method
 Backbone._sync = Backbone.sync

+# Add CSRF params to the given hash
+_.csrf = (hash) ->
+  hash[$("meta[name='csrf-param']").attr('content')] = $("meta[name='csrf-token']").attr('content')
+  hash
+
 # define a new sync method which handles Rails CSRF
 Backbone.sync = (method, model, success, error) ->
   # only need a token for non-get requests
   if (method == 'create' || method == 'update' || method == 'delete')
     # grab the token from the meta tag rails embeds
-    auth_options = {}
-    auth_options[$("meta[name='csrf-param']").attr('content')] = $("meta[name='csrf-token']").attr('content')
     # set it as a model attribute without triggering events
-    model.set(auth_options, {silent: true});
+    model.set(_.csrf({}), {silent: true});

   # proxy the call to the old sync method
   return Backbone._sync(method, model, success, error);


Use more descriptive variable name

Use more descriptive variable name

--- app/js/jail_iframe/classes/loading_promises.coffee
+++ app/js/jail_iframe/classes/loading_promises.coffee
@@ -1,11 +1,11 @@
 setTimeout ->
-  ok =
+  isDOMContentLoaded =
     loaded: true
     interactive: !(document.documentMode < 11)
     complete: true

-  if ok[document.readyState]
+  if isDOMContentLoaded[document.readyState]
     FactlinkJailRoot.host_ready_promise.resolve()
   else
     document.addEventListener('DOMContentLoaded', -> FactlinkJailRoot.host_ready_promise.resolve())


Resolves all but the negative case test.

This commit would appear to capture all three messages, but there
is still a change appearing in the output that fails the expectation.

--- scripts/grabURI.coffee
+++ scripts/grabURI.coffee
@@ -24,5 +24,5 @@
       .header('Content-Type', 'application/json')
       .post(data) (err, res, body) ->
         if err
-          res.send "Otis has failed you :( #{err}"
+          robot.send 'hubot', 'Otis has failed'
           return


make bottom timeline width around a year

--- src/bkk-metro.coffee
+++ src/bkk-metro.coffee
@@ -42,10 +42,20 @@
     tm = TimeMap.init
         mapId: 'map'
         timelineId: 'tl'
-        bandIntervals: 'yr'
         datasets: [ { title: "dummy", type: "basic" } ]
+    tm.initTimeline [
+        Timeline.createBandInfo
+            width: "58%"
+            intervalPixels: 50
+            intervalUnit: Timeline.DateTime.MONTH
+        Timeline.createBandInfo
+            overview: true
+            width: "42%"
+            intervalPixels: 75
+            intervalUnit: Timeline.DateTime.YEAR
+    ]
     tm.addFilter 'map', (item) ->
-        item.opts.type != 'marker' or map.getZoom() > 10
+        item.opts.type != 'marker' or item.map.getZoom() > 10
     load_all(tm)
     map = tm.getNativeMap()
     map.setOptions


Account: removed logs

Account: removed logs

--- client/Account/views/sshkeys.coffee
+++ client/Account/views/sshkeys.coffee
@@ -139,7 +139,6 @@
     {key, title} = @getData()

     if key and title
-      log key, title
       @info.$('span.title').text title
       @info.$('span.key').text "#{key.substr(0,45)} . . . #{key.substr(-25)}"
       @swappable.swapViews()


Rewrote controllers to use a wrapper function for dependencies.

--- public/src/controllers.coffee
+++ public/src/controllers.coffee
@@ -5,188 +5,187 @@
 # Main controller, used to catch route change (error)
 # and similar global events
 ctrls.controller "AppCtrl", ['$rootScope', '$location', '$scope', '$timeout',
-  class AppCtrl
-    loading: {isLoading: true}
-
-    error: {isError: false, errorMessage: '' }
-
-    pageTitle: null
-
-    constructor: ($rootScope, $location, $scope, $timeout) ->
-      $rootScope.$on "$routeChangeStart", (event, next, current) =>
-        @pageTitle = 'Loading...'
-        @loading.isLoading = true
-        @error.isError = false
-
-      $rootScope.$on "$routeChangeSuccess", (event, current, previous) =>
-        # Next-frame timeout, as without it seems to run before view is fully ready.
-        $timeout () =>
-          this.loading.isLoading = false
-
-      $rootScope.$on "$routeChangeError", (event, current, previous, rejection) =>
-        console.error("ROUTE CHANGE ERROR: ", rejection)
-        @loading.isLoading = false
-        @error.isError = true
-
-        if rejection instanceof Error
-          @error.errorMessage = rejection['message']
-        else if angular.isString(rejection)
-          @error.errorMessage = rejection
-        else
-          @error.errorMessage = "An unexpected error occurred while loading the page."
+  ($rootScope, $location, $scope, $timeout) ->
+    new class AppCtrl
+      loading: {isLoading: true}
+
+      error: {isError: false, errorMessage: '' }
+
+      pageTitle: null
+
+      constructor: ->
+        $rootScope.$on "$routeChangeStart", (event, next, current) =>
+          @pageTitle = 'Loading...'
+          @loading.isLoading = true
+          @error.isError = false
+
+        $rootScope.$on "$routeChangeSuccess", (event, current, previous) =>
+          # Next-frame timeout, as without it seems to run before view is fully ready.
+          $timeout () =>
+            this.loading.isLoading = false
+
+        $rootScope.$on "$routeChangeError", (event, current, previous, rejection) =>
+          console.error("ROUTE CHANGE ERROR: ", rejection)
+          @loading.isLoading = false
+          @error.isError = true
+
+          if angular.isString(rejection?['message'])
+            @error.errorMessage = rejection['message']
+          else if angular.isString(rejection)
+            @error.errorMessage = rejection
+          else
+            @error.errorMessage = "An unexpected error occurred while loading the page."
 ]

 # Controller for handling the top nav-bar
 ctrls.controller "TopNavbarCtrl", ['$scope', '$modal', 'steamUser',
-  class TopNavbarCtrl
-    # An object for the signed in user
-    user: null
-
-    @error: {}
-
-    constructor: ($scope, $modal, steamUser) ->
-      @steamUser = steamUser
-
-      steamUser.getUser()
-      .then (user) =>
-        @user = user
-
-      @signInModal = $modal {
+  ($scope, $modal, steamUser) ->
+    new class TopNavbarCtrl
+      # An object for the signed in user
+      user: null
+
+      error: {}
+
+      signInModal = $modal(
         scope: $scope
         template: '/partials/modals/sign-in.html'
         container: 'body'
         show: false
-      }
-
-    showSignInModal: () ->
-      @signInModal.$promise.then(@signInModal.show);
-
-    signIn: () ->
-      @steamUser.signIn()
-      .then (steamPlayer) =>
-        @signInModal.$promise.then(@signInModal.hide);
-        @user = steamPlayer
-      .catch (err) =>
-        @error.signIn = err
-
-    signOut: () ->
-      @steamUser.signOut()
-      @user = null
+      )
+
+      constructor: ->
+        steamUser.getUser()
+        .then (user) =>
+          @user = user
+
+      showSignInModal: () ->
+        signInModal.$promise.then(signInModal.show);
+
+      signIn: () ->
+        steamUser.signIn()
+        .then (steamPlayer) =>
+          signInModal.$promise.then(signInModal.hide);
+          @user = steamPlayer
+        .catch (err) =>
+          @error.signIn = err
+
+      signOut: () ->
+        steamUser.signOut()
+        @user = null
 ]

 # "/"
-ctrls.controller "ViewHomeCtrl", [
-  class ViewHomeCtrl
-    @isSearching = false
+ctrls.controller "ViewHomeCtrl", ['$location',
+  ($location) ->
+    new class ViewHomeCtrl
+      @isSearching = false

     searchSteamId: (searchStr) ->
-      @$location.path('/player/' + searchStr)
+      $location.path('/player/' + searchStr)
 ]

 # "/player/:steamId
 ctrls.controller "ViewPlayerCtrl", ['$q', '$timeout', '$location', '$scope', '_', 'playerData',
-  class ViewPlayerCtrl
-    REFRESH_MATCHES_INTERVAL = 2 * 60 * 1000
-
-    # The player we are viewing
-    player: {}
-    # Matches that we are loading details for
-    matches: []
-    # Flag for if we are currently loading more matches
-    matchLoadProgress: true
-    # Flag for if there was an error loading matches
-    loadingMatchesError: false
-    # Flag for if we have more matches to load
-    hasMoreMatches: false
-
-    constructor: ($q, $timeout, $location, $scope, _, playerData) ->
-      @$q = $q
-      @$timeout = $timeout
-      @$location = $location
-      @_ = _
-
-      @player = playerData.player
-      @matches = @filterMatchesByPlayer(playerData.matchData.matches, @player.steamid32)
-      @matchLoadProgress = 0
-      @loadingMatchesError = false
-      @hasMoreMatches = (playerData.matchData.meta.results_remaining > 0)
-
-      matchLoadPromises = _.invoke(@matches, 'loadDetails')
-      # Whenever details are loaded for a match, increase the progressbar
-      @_.forEach(matchLoadPromises, (matchPromise) =>
-        matchPromise.then () =>
-          @matchLoadProgress += 1 / matchLoadPromises.length
-      )
-      # Wait for loading of matches all pending before allowing loading more
-      $q.all(matchLoadPromises).then () =>
-        this.matchLoadProgress = false
-        # Refresh matches REFRESH_MATCHES_INTERVAL
-        @refreshMatchTimeout = $timeout(() =>
-          @refreshMatches()
-        , REFRESH_MATCHES_INTERVAL)
-
-      $scope.$on '$destroy', () =>
-        $timeout.cancel(@refreshMatchTimeout)
-
-    # Takes an array of SteamMatches and replaces the players property with a
-    # player property for only the provided account_id
-    filterMatchesByPlayer: (matches, account_id) ->
-      @_.map(matches, (match) =>
-        match.loadDetails().then () =>
-          match.player = @_.find(match.players, {account_id: account_id})
-          delete match['players']
-        return match
-      )
-
-    # Method for loading more matches later than the current loaded ones
-    loadMoreMatches: () ->
-      if @matchLoadProgress == false
+  ($q, $timeout, $location, $scope, _, playerData) ->
+    new class ViewPlayerCtrl
+      REFRESH_MATCHES_INTERVAL = 2 * 60 * 1000
+
+      # The player we are viewing
+      player: {}
+      # Matches that we are loading details for
+      matches: []
+      # Flag for if we are currently loading more matches
+      matchLoadProgress: true
+      # Flag for if there was an error loading matches
+      loadingMatchesError: false
+      # Flag for if we have more matches to load
+      hasMoreMatches: false
+
+      constructor: ->
+        @player = playerData.player
+        @matches = @filterMatchesByPlayer(playerData.matchData.matches, @player.steamid32)
         @matchLoadProgress = 0
-        lastMatchId = @_.last(this.matches).match_id
-        @player.getMatches(10, (lastMatchId - 1)).then (matchData) =>
-          # loadDetails for each of the matches
-          matchLoadPromises = @_.invoke(matchData.matches, 'loadDetails')
-          # Whenever details are loaded for a match, increase the progressbar
-          @_.forEach(matchLoadPromises, (matchPromise) =>
-            matchPromise.then () =>
-              @matchLoadProgress += 1 / matchLoadPromises.length
-          )
-          @$q.all(matchLoadPromises)
-          .then () =>
+        @loadingMatchesError = false
+        @hasMoreMatches = (playerData.matchData.meta.results_remaining > 0)
+
+        matchLoadPromises = _.invoke(@matches, 'loadDetails')
+        # Whenever details are loaded for a match, increase the progressbar
+        _.forEach(matchLoadPromises, (matchPromise) =>
+          matchPromise.then () =>
+            @matchLoadProgress += 1 / matchLoadPromises.length
+        )
+        # Wait for loading of matches all pending before allowing loading more
+        $q.all(matchLoadPromises).then () =>
+          this.matchLoadProgress = false
+          # Refresh matches REFRESH_MATCHES_INTERVAL
+          @refreshMatchTimeout = $timeout(() =>
+            @refreshMatches()
+          , REFRESH_MATCHES_INTERVAL)
+
+        $scope.$on '$destroy', () =>
+          $timeout.cancel(@refreshMatchTimeout)
+
+      # Takes an array of SteamMatches and replaces the players property with a
+      # player property for only the provided account_id
+      filterMatchesByPlayer: (matches, account_id) ->
+        _.map(matches, (match) =>
+          match.loadDetails().then () =>
+            match.player = _.find(match.players, {account_id: account_id})
+            delete match['players']
+          return match
+        )
+
+      # Method for loading more matches later than the current loaded ones
+      loadMoreMatches: () ->
+        if @matchLoadProgress == false
+          @matchLoadProgress = 0
+          lastMatchId = _.last(this.matches).match_id
+          @player.getMatches(10, (lastMatchId - 1)).then (matchData) =>
+            # loadDetails for each of the matches
+            matchLoadPromises = _.invoke(matchData.matches, 'loadDetails')
+
+            # Whenever details are loaded for a match, increase the progressbar
+            _.forEach(matchLoadPromises, (matchPromise) =>
+              matchPromise.then () =>
+                @matchLoadProgress += 1 / matchLoadPromises.length
+            )
+
             # When all matches has finished loaded, append them to the list
-            filteredMatches = @filterMatchesByPlayer(matchData.matches, @player.steamid32)
-            @matches = @matches.concat(filteredMatches)
-            @hasMoreMatches = (matchData.meta.results_remaining > 0)
-            @matchLoadProgress = false
-          .catch () =>
-            # If there was an error loading any of the matches, throw all away.
-            # (successful calls should be cached anyway, so doesn't matter much)
-            @loadingMatchesError = true
-            @$timeout(() =>
-              @loadingMatchesError = false
+            $q.all(matchLoadPromises).then () =>
+              filteredMatches = @filterMatchesByPlayer(matchData.matches, @player.steamid32)
+              @matches = @matches.concat(filteredMatches)
+              @hasMoreMatches = (matchData.meta.results_remaining > 0)
               @matchLoadProgress = false
-            , 3000)
-
-    # Method for refreshing the first few match
-    refreshMatches: () ->
-      @player.getMatches(10, null, false)
-      .then (matchData) =>
-        highMatchId = @matches[0].match_id
-        newMatches = @_.filter(matchData.matches, (match) ->
-          match.match_id > highMatchId)
-        if newMatches.length
-          filteredMatches = @filterMatchesByPlayer(newMatches, @player.steamid32)
-          @$q.all(@_.invoke(filteredMatches, 'loadDetails')).then () =>
-            @matches = filteredMatches.concat(@matches)
-        else
-          @$q.reject('')
-      .finally () =>
-        @refreshMatchTimeout = @$timeout(() =>
-          @refreshMatches()
-        , REFRESH_MATCHES_INTERVAL)
-
-    goToMatch: (match_id) ->
-      @$location.path('/match/' + match_id)
+            .catch () =>
+              # If there was an error loading any of the matches, throw all away.
+              # (successful calls should be cached anyway, so doesn't matter much)
+              @loadingMatchesError = true
+              $timeout(() =>
+                @loadingMatchesError = false
+                @matchLoadProgress = false
+              , 3000)
+
+      # Method for refreshing the first few match
+      refreshMatches: () ->
+        @player.getMatches(10, null, false).then (matchData) =>
+          highMatchId = @matches[0].match_id
+          newMatches = _.filter matchData.matches, (match) ->
+            match.match_id > highMatchId
+
+          if newMatches.length
+            filteredMatches = @filterMatchesByPlayer(newMatches, @player.steamid32)
+            $q.all(_.invoke(filteredMatches, 'loadDetails')).then () =>
+              @matches = filteredMatches.concat(@matches)
+          else
+            $q.reject('')
+
+        .finally () =>
+          @refreshMatchTimeout = $timeout(() =>
+            @refreshMatches()
+          , REFRESH_MATCHES_INTERVAL)
+
+      goToMatch: (match_id) ->
+        $location.path('/match/' + match_id)
 ]

 # Resolve before ViewPlayerCtrl
@@ -219,10 +218,11 @@
 ]

 # /match/:matchId
-ctrls.controller "ViewMatchCtrl", ['matchData'
-  class ViewMatchCtrl
-    constructor: (matchData) ->
-      @match = matchData.match
+ctrls.controller "ViewMatchCtrl", ['matchData',
+  (matchData) ->
+    new class ViewMatchCtrl
+      constructor: ->
+        @match = matchData.match
 ]

 # Resolve before ViewMatchCtrl


client: home: add create stacks section if only allowed

--- client/home/lib/stacks/index.coffee
+++ client/home/lib/stacks/index.coffee
@@ -18,6 +18,9 @@

 AddManagedMachineModal = require 'app/providers/managed/addmanagedmachinemodal'
 VirtualMachinesSelectedMachineFlux = require 'home/virtualmachines/flux/selectedmachine'
+
+canCreateStacks = require 'app/util/canCreateStacks'
+isAdmin = require 'app/util/isAdmin'

 module.exports = class HomeStacks extends kd.CustomScrollView

@@ -105,11 +108,12 @@
     actions.loadTeamStackTemplates()
     actions.loadPrivateStackTemplates()

-    @stacks.addSubView view = new HomeStacksCreate
+    if canCreateStacks()
+      @stacks.addSubView view = new HomeStacksCreate

-    view.on 'CreateButtonClick', =>
-      @destroy()
-      kd.singletons.router.handleRoute '/Stack-Editor/New'
+      view.on 'CreateButtonClick', =>
+        @destroy()
+        kd.singletons.router.handleRoute '/Stack-Editor/New'

     @stacks.addSubView headerize 'Team Stacks'
     @stacks.addSubView sectionize 'Team Stacks', HomeStacksTeamStacks, { delegate : this }


Changed cart link to a button.

Changed cart link to a button.

--- public/views/cart_view.coffee
+++ public/views/cart_view.coffee
@@ -4,17 +4,17 @@
     @listenTo @model, "update", @render

   events:
-    "click a": "onClick"
+    "click .epages-cart-button": "openCartDetails"

   template: _.template """
-
Your cart contains <%= count %> products.

+    <button class="epages-cart-button">Shopping cart (<%= count %>)</button>
   """

   render: ->
     @$el.html @template(count: @model.count())
     this

-  onClick: (event) ->
+  openCartDetails: (event) ->
     event.preventDefault()

     view = new CartDetailView(model: @model).render()


fix mispelling

fix mispelling

--- resources/assets/coffee/react/beatmap-discussions/discussions.coffee
+++ resources/assets/coffee/react/beatmap-discussions/discussions.coffee
@@ -123,7 +123,7 @@
               div className: "#{bn}__timeline-line hidden-xs"

             div null,
-              @filterDiscussions(@sortedDisussions()).map @discussionPage
+              @filterDiscussions(@sortedDiscussions()).map @discussionPage

             @timelineCircle()

@@ -198,7 +198,7 @@
     @props.mode == 'timeline' && @currentSort() == 'timeline'

-  sortedDisussions: ->
+  sortedDiscussions: (discussions) ->
     @props.currentDiscussions[@props.mode].slice().sort (a, b) =>
       mapperNoteCompare =
         # no sticky for timeline sort


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -12,7 +12,7 @@
   Object.reverseMerge I,
     flashTargetAlpha: 0

-  fadeIndefault =
+  fadeInDefaults =
     duration: 30
     color: 'black'


Added compatible interface for VoteView in Comment

--- core/app/backbone/models/comment.coffee
+++ core/app/backbone/models/comment.coffee
@@ -17,9 +17,23 @@

   can_destroy: -> @get 'can_destroy?'

-  believe: -> @save opinion: 'believes'
-  disbelieve: -> @save opinion: 'disbelieves'
+  setOpinion: (type) ->
+    @previous_user_opinion = @get('current_user_opinion')

+    @save opinion: type
+
+  undoOpinion: ->
+    return if @previous_user_opinion == @get('current_user_opinion')
+
+    if @previous_user_opinion?
+      @setOpinion @previous_user_opinion
+    else
+      @removeOpinion()
+
+  believe: -> @setOpinion 'believes'
+  disbelieve: -> @setOpinion 'disbelieves'
+
+  current_opinion: -> @get('current_user_opinion')
   isBelieving: -> @get('current_user_opinion') == 'believes'
   isDisBelieving: -> @get('current_user_opinion') == 'disbelieves'


Mark games with ! when player is invited

--- static/script/pages/home.coffee
+++ static/script/pages/home.coffee
@@ -15,7 +15,7 @@

           {{? it.is_present}}
             {{? it.is_invited}}
-              <button class="btn" id="{{= it.eid}}_join" title="{{= window.hlib._g("Join")}}" rel="tooltip" data-placement="top"></button>
+
             {{??}}
               {{? it.is_game}}

@@ -139,7 +139,6 @@
           data:			data
           handlers:
             h200:		(response, ajax) ->
-              console.log 'joined, show info and update'
               window.hlib.INFO.show 'You have joined a game', ''

               __update = () ->
@@ -168,7 +167,11 @@
     if p.has_password
       $('#' + p.eid + '_join').replaceWith(window.settlers.templates.recent_events.password p)

-    if p.is_present
+    if p.is_invited
+      window.settlers.show_menu_alert p.eid + ' #' + p.eid + '_join', '!', 'badge-join'
+      __join_click '#' + p.eid
+
+    else if p.is_present
       __generic_click()

     else
@@ -196,21 +199,7 @@
   render_playable = (eid, p) ->
     p.eid = 'playable_' + (if p.is_game then 'game' else 'tournament') + '_' + p.id

-    __fmt_player = (player) ->
-      s = player.user.name
-
-      if player.user.is_online == true
-        s = '' + s + ''
-
-      if player.is_confirmed != true
-        s = '' + s + ''
-
-      if player.is_on_turn == true
-        s = '' + s + ''
-
-      return s
-
-    p.players_list = (__fmt_player player for player in p.players).join ', '
+    p.players_list = (window.settlers.fmt_player player for player in p.players).join ', '

     $(eid).append window.settlers.templates.recent_events.playable p
     decorate_playable p


Unhandled return code

Unhandled return code

--- static/script/pages/home.coffee
+++ static/script/pages/home.coffee
@@ -162,6 +162,9 @@
               window.hlib.error 'Unauthorized', response.error, () ->
                 field.unmark_error()

+            h402:		(response, ajax) ->
+              window.hlib.error 'Error!', response.error
+
         return false

     if p.has_password


Update

Update

--- test/katon.coffee
+++ test/katon.coffee
@@ -1,5 +1,8 @@
 assert = require 'assert'
+logan = require 'logan'
 katon = require '../src/katon'
+
+logan.silent = true

 describe 'katon', ->


just added a comment

just added a comment

--- src/build-token.coffee
+++ src/build-token.coffee
@@ -25,6 +25,7 @@
     2: {project: "dc-app", held_by: "no one"}
   }

+  # map hipchat usernames to github usernames here
   username_mappings = {
     1: {hipchat: "RossSinger", github: "rsinger"},
     2: {hipchat: "RichardTattersall", github: "lordtatty"},


Generate Doc Library for KiCad

Generate Doc Library for KiCad

--- src/kicad-generator.coffee
+++ src/kicad-generator.coffee
@@ -36,12 +36,31 @@
     fs.closeSync fd
     log.ok()

+    log.start "KiCad library doc '#{@name}.dcm'"
+    fd = fs.openSync "#{dir}/#{@name}.dcm", 'w'
+    fs.writeSync fd, "EESchema-DOCLIB Version 2.0 Date: #{timestamp}\n"
+    for element in @library.elements
+      @_generateDoc fd, element
+    fs.writeSync fd, '# End Doc Library\n'
+    fs.closeSync fd
+    log.ok()
+
     for patternName, pattern of patterns
       log.start "KiCad footprint '#{patternName}.kicad_mod'"
       fd = fs.openSync "#{dir}/#{@name}.pretty/#{patternName}.kicad_mod", 'w'
       @_generatePattern fd, pattern
       fs.closeSync fd
       log.ok()
+
+  #
+  # Write doc entry to library doc file
+  #
+  _generateDoc: (fd, element) ->
+    fs.writeSync fd, "$CMP #{element.name}\n"
+    if element.description? then fs.writeSync fd, "D #{element.description}\n"
+    if element.keywords? then fs.writeSync fd, "K #{element.keywords}\n"
+    if element.datasheet? then fs.writeSync fd, "F #{element.datasheet}\n"
+    fs.writeSync fd, "$ENDCMP\n"

   #
   # Write pattern file


Correctly convert dates in statistics. Fixes #264

--- server/statistics.coffee
+++ server/statistics.coffee
@@ -25,11 +25,11 @@

       if not minPublicationDate or created < minPublicationDate
         minPublicationDate = created
-        changed.minPublicationDate = minPublicationDate
+        changed.minPublicationDate = minPublicationDate.toDate()

       if not maxPublicationDate or created > maxPublicationDate
         maxPublicationDate = created
-        changed.maxPublicationDate = maxPublicationDate
+        changed.maxPublicationDate = maxPublicationDate.toDate()

       Statistics.update statisticsDataId, $set: changed if !initializingPublications


add exorcist mock and bundle.pipe mock

add exorcist mock and bundle.pipe mock

--- test/mocks.coffee
+++ test/mocks.coffee
@@ -28,6 +28,10 @@
   stream: PassThrough:PassThroughMock

   'envify/custom': (options) -> Result.transforms.envify = options
+
+  'exorcist': (outputName, sourceMapURL) ->
+    Result.exorcist = name:outputName,url:sourceMapURL
+    return 'exorcist'

   # instead of the real browserify
   browserify: (array, options) ->
@@ -60,6 +64,11 @@

             # only call the error() fn when we're testing an error
             if eventType is 'error' and Result?.errorWanted then fn 'test error'
+
+          # pipe to exorcist
+          pipe: (exorcist) ->
+            Result.exorcist.piped = exorcist
+            return this
         }

       # store received transform name and options


Account: Add email verification check to fetchOtaToken.

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -1264,21 +1264,28 @@
     errorCallback = ->
       callback new KodingError 'Invalid session'

-    unless sessionToken
-      return errorCallback()
-
-    JSession         = require './session'
-    { v4: createId } = require 'node-uuid'
-
-    JSession.one { clientId: sessionToken }, (err, session) ->
-
-      if err or not session
-        return errorCallback()
-
-      [otaToken] = createId().split '-'
-      session.update { $set: { otaToken } }, (err) ->
-        if err then errorCallback()
-        else callback null, otaToken
+    return errorCallback()  unless sessionToken
+
+    @isEmailVerified (err, isVerified) ->
+
+      return callback err  if err
+
+      if not isVerified
+        message = 'Sorry, you need to confirm your email address first.'
+        return callback new KodingError message
+
+      JSession         = require './session'
+      { v4: createId } = require 'node-uuid'
+
+      JSession.one { clientId: sessionToken }, (err, session) ->
+
+        if err or not session
+          return errorCallback()
+
+        [otaToken] = createId().split '-'
+        session.update { $set: { otaToken } }, (err) ->
+          if err then errorCallback()
+          else callback null, otaToken

   ###*


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/state.coffee
+++ test/state.coffee
@@ -1,9 +1,3 @@
-test "State", ->
-  callback = Callback {}, "Test Machine", ->
-    console.log "testing"
-
-  equals callback != null, true, "callback shouldn't be null"
-
 test "State events should check if event can be fired", ->
   car = {}


test/ide/terminal: update for teams

test/ide/terminal: update for teams

--- client/test/lib/ide/terminal.coffee
+++ client/test/lib/ide/terminal.coffee
@@ -1,129 +1,128 @@
-helpers         = require '../helpers/helpers.js'
-assert          = require 'assert'
+assert = require 'assert'
 terminalHelpers = require '../helpers/terminalhelpers.js'
+helpers = require '../helpers/helpers.js'
+ideHelpers = require '../helpers/idehelpers.js'
+utils = require '../utils/utils.js'
+async = require 'async'
+teamsHelpers = require '../helpers/teamshelpers.js'

 paneSelector = '.pane-wrapper .kdsplitview-panel.panel-1 .application-tab-handle-holder'

-
 module.exports =

-  terminateAll: (browser) ->
+  before: (browser, done) ->

-    user = helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
+    ###
+    * we are creating users list here to send invitation and join to team
+    * so we will be able to run our test for different kind of member role
+    ###
+    targetUser1 = utils.getUser no, 1
+    targetUser1.role = 'member'

-    terminalHelpers.createTerminalSession(browser, user)
+    users = [
+      targetUser1
+    ]

-    terminalHelpers.terminateAll(browser)
-    browser.end()
+    queue = [
+      (next) ->
+        teamsHelpers.inviteAndJoinWithUsers browser, users, (result) ->
+          next null, result
+      (next) ->
+        teamsHelpers.buildStack browser, (res) ->
+          next null, res
+
+      # go to IDE url
+      (next) ->
+        teamUrl = helpers.getUrl yes
+        url = "#{teamUrl}/IDE"
+        browser.url url, -> next null
+    ]
+
+    async.series queue, (err, result) ->
+      done()  unless err

-  createNewTerminalSession: (browser) ->
+  terminal: (browser, done) ->

-    user = helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
+    user = utils.getUser()

-    terminalHelpers.createTerminalSession(browser, user)
-    browser.end()
+    queue = [
+      # terminateAll
+      (next) ->
+        terminalHelpers.createTerminalSession(browser, user)
+        terminalHelpers.terminateAll browser, ->
+          next null

+      # createNewTerminalSession
+      (next) ->
+        terminalHelpers.createTerminalSession browser, user, ->
+          next null

-  terminateSession: (browser) ->
-
-    helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
-
-    terminalHelpers.openNewTerminalMenu(browser)
-
-    getSessionData = ->
-
-      selector = '.kdcontextmenu ul + li.disabled'
-      matcher  = /session-(\w+)\S+/
-
-      return document.querySelector(selector).getAttribute('class').match(matcher)
-
-    browser.execute getSessionData, [], (result) ->
-
-      [cssClass, sessionId] = result.value
-      sessionListSelector   = '.kdcontextmenu ul ul:nth-of-type(1).expanded'
-
-      browser
-        .waitForElementVisible  '.' + cssClass, 25000
-        .moveToElement          '.' + cssClass, 10, 10
-        .pause                  1000
-        .click                  '.context-list-wrapper ul > ul.expanded ul.expanded .terminate'
-        .pause                  5000
+      # terminateSession
+      (next) ->

         terminalHelpers.openNewTerminalMenu(browser)

-        browser
-          .pause   1000
-          .getText sessionListSelector, (result) ->
-            assert.equal(result.value.indexOf(sessionId), -1)
+        getSessionData = ->
+          selector = '.kdcontextmenu ul + li.disabled'
+          matcher  = /session-(\w+)\S+/

-            browser.end()
+          return document.querySelector(selector).getAttribute('class').match(matcher)
+
+        browser.execute getSessionData, [], (result) ->
+
+          [cssClass, sessionId] = result.value
+          sessionListSelector   = '.kdcontextmenu ul ul:nth-of-type(1).expanded'
+
+          browser
+            .waitForElementVisible  '.' + cssClass, 25000
+            .moveToElement          '.' + cssClass, 10, 10
+            .pause                  1000
+            .click                  '.context-list-wrapper ul > ul.expanded ul.expanded .terminate'
+            .pause                  5000
+
+            terminalHelpers.openNewTerminalMenu(browser)
+
+            browser
+              .pause   1000
+              .getText sessionListSelector, (result) ->
+                assert.equal(result.value.indexOf(sessionId), -1)
+                browser.pause 1, -> next null
+
+        # runCommandOnTerminal
+        (next) ->
+          terminalHelpers.createTerminalSession browser, user, ->
+            helpers.runCommandOnTerminal browser, null, ->
+              next null
+
+        # renameTerminalTab
+        (next) ->
+          name            = helpers.getFakeText().split(' ')[0]
+          tabSelector     = "#{paneSelector} .kdtabhandle.terminal"
+          optionsSelector = "#{tabSelector} .options"
+          renameSelector  = '.kdcontextmenu.terminal-context-menu .rename'
+          editSelector    = "#{tabSelector}.edit-mode .hitenterview.tab-handle-input"
+          tabNameSelector = "#{tabSelector} .tab-handle-text"

-  runCommandOnTerminal: (browser) ->
+          terminalHelpers.createTerminalSession(browser, user)

-    user = helpers.beginTest(browser)
+          browser
+            .waitForElementVisible    tabSelector, 20000
+            .moveToElement            tabSelector, 64, 18
+            .waitForElementVisible    optionsSelector, 20000
+            .click                    optionsSelector
+            .waitForElementVisible    renameSelector, 20000
+            .click                    renameSelector
+            .waitForElementPresent    editSelector, 20000
+            .clearValue               editSelector
+            .setValue                 editSelector, [name, browser.Keys.RETURN]
+            .waitForElementNotPresent editSelector, 20000
+            .assert.containsText      tabNameSelector, name #Assertion
+            .pause 1, -> next null

-    helpers.waitForVMRunning(browser)
-    terminalHelpers.createTerminalSession(browser, user)
+    ]

-    helpers.runCommandOnTerminal(browser)
-    browser.end()
+    async.series queue

-
-  renameTerminalTab: (browser) ->
-
-    name            = helpers.getFakeText().split(' ')[0]
-    tabSelector     = "#{paneSelector} .kdtabhandle.terminal"
-    optionsSelector = "#{tabSelector} .options"
-    renameSelector  = '.kdcontextmenu.terminal-context-menu .rename'
-    editSelector    = "#{tabSelector}.edit-mode .hitenterview.tab-handle-input"
-    tabNameSelector = "#{tabSelector} .tab-handle-text"
-
-    user = helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
-    terminalHelpers.createTerminalSession(browser, user)
-
-    browser
-      .waitForElementVisible    tabSelector, 20000
-      .moveToElement            tabSelector, 64, 18
-      .waitForElementVisible    optionsSelector, 20000
-      .click                    optionsSelector
-      .waitForElementVisible    renameSelector, 20000
-      .click                    renameSelector
-      .waitForElementPresent    editSelector, 20000
-      .clearValue               editSelector
-      .setValue                 editSelector, [name, browser.Keys.RETURN]
-      .waitForElementNotPresent editSelector, 20000
-      .assert.containsText      tabNameSelector, name #Assertion
-      .end()
-
-
-  # this test is deprecated with persistent storage
-  # openOldTerminalSession: (browser) ->
-
-  #   openSelector    = '.context-list-wrapper li.new-terminal + ul li + ul li.open:first-child'
-  #   elementSelector = '.context-list-wrapper li.new-terminal + ul li.has-sub-items:not(.disabled)'
-  #   user            = helpers.beginTest(browser)
-  #   userName        = user.username
-
-  #   helpers.waitForVMRunning(browser)
-
-  #   createTerminalSession(browser, user)
-
-  #   openNewTerminalMenu(browser)
-
-  #   browser
-  #     .waitForElementVisible   elementSelector, 20000
-  #     .moveToElement           elementSelector, 25, 20
-  #     .pause  2000 # required
-  #     .waitForElementVisible   openSelector, 200000
-  #     .moveToElement           openSelector, 25, 20
-  #     .click                   openSelector
-  #     .pause 6000 # required
-  #     .waitForElementVisible   paneSelector + ' .terminal.active',20000 # Assertion
-  #     .assert.containsText     '.application-tabview .terminal.active .terminal-pane', userName # Assertion
-  #     .end()
+  after: (browser) -> browser.end()


Adhere to CofeeScript style guide

Adhere to CofeeScript style guide

--- src/lib/byte-buffer.coffee
+++ src/lib/byte-buffer.coffee
@@ -17,7 +17,7 @@
   # - from given source (assumed to be number of bytes when numeric)
   # - with given byte order (defaults to big-endian)
   # - with given implicit growth strategy (defaults to false)
-  constructor: (source=0, order=self.BIG_ENDIAN, implicitGrowth=false) ->
+  constructor: (source = 0, order = self.BIG_ENDIAN, implicitGrowth = false) ->

     # Holds buffer
     @_buffer = null
@@ -55,7 +55,7 @@
       @_index = @length

   # Extracts buffer from given source and optionally clones it
-  extractBuffer = (source, clone=false) ->
+  extractBuffer = (source, clone = false) ->

     # Whether source is a byte-aware object
     if source.byteLength?
@@ -159,7 +159,7 @@

   # Generic reader
   reader = (method, bytes) ->
-    return (order=@_order) ->
+    return (order = @_order) ->
       if bytes > @available
         throw new Error('Cannot read ' + bytes + ' byte(s), ' + @available + ' available')

@@ -169,7 +169,7 @@

   # Generic writer
   writer = (method, bytes) ->
-    return (value, order=@_order) ->
+    return (value, order = @_order) ->
       available = @available
       if bytes > available
         if @_implicitGrowth
@@ -202,7 +202,7 @@
   writeDouble: writer('setFloat64', 8)

   # Reads sequence of given number of bytes (defaults to number of bytes available)
-  read: (bytes=@available) ->
+  read: (bytes = @available) ->
     if bytes > @available
       throw new Error('Cannot read ' + bytes + ' byte(s), ' + @available + ' available')

@@ -244,7 +244,7 @@
   # Reads UTF-8 encoded string of given number of bytes (defaults to number of bytes available)
   #
   # Based on David Flanagan's BufferView (https://github.com/davidflanagan/BufferView/blob/master/BufferView.js#L195)
-  readString: (bytes=@available) ->
+  readString: (bytes = @available) ->
     if bytes > @available
       throw new Error('Cannot read ' + bytes + ' byte(s), ' + @available + ' available')

@@ -451,7 +451,7 @@
     return @

   # Clips this buffer
-  clip: (begin=@_index, end=@length) ->
+  clip: (begin = @_index, end = @length) ->
     if begin < 0
       begin = @length + begin
     buffer = @_buffer.slice(begin, end)
@@ -460,7 +460,7 @@
     return @

   # Slices this buffer
-  slice: (begin=0, end=@length) ->
+  slice: (begin = 0, end = @length) ->
     slice = new self(@_buffer.slice(begin, end), @order)
     return slice

@@ -486,13 +486,13 @@
     return '[ByteBuffer; Order: ' + order + '; Length: ' + @length + '; Index: ' + @_index + '; Available: ' + @available + ']'

   # Hex representation of this buffer with given spacer
-  toHex: (spacer=' ') ->
+  toHex: (spacer = ' ') ->
     return Array::map.call(@_raw, (byte) ->
       ('00' + byte.toString(16).toUpperCase()).slice(-2)
     ).join(spacer)

   # ASCII representation of this buffer with given spacer and optional byte alignment
-  toASCII: (spacer=' ', align=true, unknown='\uFFFD') ->
+  toASCII: (spacer = ' ', align = true, unknown = '\uFFFD') ->
     prefix = if align then ' ' else ''
     return Array::map.call(@_raw, (byte) ->
       return if (byte < 0x20 || byte > 0x7E) then prefix + unknown else prefix + String.fromCharCode(byte)


small header on member activity disabled

--- client/landing/app/Applications/Members.kdapplication/ContentDisplays/ContentDisplayControllerMember.coffee
+++ client/landing/app/Applications/Members.kdapplication/ContentDisplays/ContentDisplayControllerMember.coffee
@@ -25,11 +25,11 @@
     memberProfile = @addProfileView member
     memberStream  = @addActivityView member

-    unless KD.isMine member
-      @listenTo
-        KDEventTypes       : "mouseenter"
-        listenedToInstance : memberProfile
-        callback           : => @mouseEnterOnHeader()
+    # unless KD.isMine member
+    #   @listenTo
+    #     KDEventTypes       : "mouseenter"
+    #     listenedToInstance : memberProfile
+    #     callback           : => @mouseEnterOnHeader()

     memberProfile.on 'FollowButtonClicked', @followAccount
     memberProfile.on 'UnfollowButtonClicked', @unfollowAccount
@@ -42,25 +42,25 @@
       delegate : @getView()
     , member

-  mouseEnterOnFeed:->
-
-    clearTimeout @intentTimer
-    @intentTimer = setTimeout =>
-      @getView().$('.profilearea').css "overflow", "hidden"
-      @getView().setClass "small-header"
-      @utils.nextTick 300,=>
-        @getSingleton('windowController').notifyWindowResizeListeners()
-    , 500
-
-  mouseEnterOnHeader:->
-
-    clearTimeout @intentTimer
-    @intentTimer = setTimeout =>
-      @getView().unsetClass "small-header"
-      @utils.nextTick 300,=>
-        @getSingleton('windowController').notifyWindowResizeListeners()
-        @getView().$('.profilearea').css "overflow", "visible"
-    , 500
+  # mouseEnterOnFeed:->
+  #
+  #   clearTimeout @intentTimer
+  #   @intentTimer = setTimeout =>
+  #     @getView().$('.profilearea').css "overflow", "hidden"
+  #     @getView().setClass "small-header"
+  #     @utils.nextTick 300,=>
+  #       @getSingleton('windowController').notifyWindowResizeListeners()
+  #   , 500
+  #
+  # mouseEnterOnHeader:->
+  #
+  #   clearTimeout @intentTimer
+  #   @intentTimer = setTimeout =>
+  #     @getView().unsetClass "small-header"
+  #     @utils.nextTick 300,=>
+  #       @getSingleton('windowController').notifyWindowResizeListeners()
+  #       @getView().$('.profilearea').css "overflow", "visible"
+  #   , 500

   followAccount:(account, callback)->
     account.follow callback
@@ -97,11 +97,11 @@
     }, (controller)=>
       #put listeners here, look for the other feeder instances

-      unless KD.isMine account
-        @listenTo
-          KDEventTypes       : "mouseenter"
-          listenedToInstance : controller.getView()
-          callback           : => @mouseEnterOnFeed()
+      # unless KD.isMine account
+      #   @listenTo
+      #     KDEventTypes       : "mouseenter"
+      #     listenedToInstance : controller.getView()
+      #     callback           : => @mouseEnterOnFeed()

       @getView().addSubView controller.getView()


removed validateTeamDomain from verifyslug file

--- servers/lib/server/handlers/verifyslug.coffee
+++ servers/lib/server/handlers/verifyslug.coffee
@@ -1,19 +1,6 @@
-koding = require './../bongo'
-
-validateTeamDomain = (name) ->
-
-  teamDomainPattern = ///
-    ^                     # beginning of the string
-    [a-z0-9]+             # one or more 0-9 and/or a-z
-    (
-      [-]                 # followed by a single dash
-      [a-z0-9]+           # one or more (0-9 and/or a-z)
-    )*                    # zero or more of the token in parentheses
-    $                     # end of string
-  ///
-
-  return teamDomainPattern.test name
-
+koding    = require './../bongo'
+Validator = require '../../../../workers/social/lib/social/models/user/validators'
+{ validateTeamDomain } = Validator

 module.exports = (req, res) ->


Refactors tracking, adds appiId and appName

--- src/remote/services/hull.coffee
+++ src/remote/services/hull.coffee
@@ -76,20 +76,24 @@

       return

+    doTrack = (event, params)->
+      return unless event
+      params.hull_app_id    = config?.appId
+      params.hull_app_name  = config?.data?.app?.name
+      console.info "Tracking:", event, params
+      require('analytics').track(event, params)

     trackAction = (request, response)->
       return unless track = request.getResponseHeader('Hull-Track')
       try
         [eventName, trackParams] = JSON.parse(atob(track))
-        trackParams.hull_app_id    = config?.appId
-        trackParams.hull_app_name  = config?.data?.app?.name
-        require('analytics').track(eventName, trackParams) if eventName
+        doTrack(eventName, trackParams)
       catch error
         "Invalid Tracking header"

     trackHandler = (req, callback, errback)->
       eventName = req.path
-      require('analytics').track(eventName, req.params)
+      doTrack(eventName, req.params)
       req.path = "t"
       req.params.event ?= eventName
       req.params = { t: btoa(JSON.stringify(req.params)) }


Remove image capabilities for kpis in data-not-found directive

--- src/components/common/data-not-found/data-not-found.directive.coffee
+++ src/components/common/data-not-found/data-not-found.directive.coffee
@@ -22,11 +22,9 @@
         image.remove() if image?

       displayDefaultImage = ->
+        return if scope.isKpi
         usingDefaults = true
-        if scope.isKpi
-          imagePath = ImpacAssets.get('defaultImagesPath') + '/kpi-bg.png'
-        else
-          imagePath = ImpacAssets.get('defaultImagesPath') + '/widget-bg-width-' + scope.widgetWidth + '.png'
+        imagePath = ImpacAssets.get('defaultImagesPath') + '/widget-bg-width-' + scope.widgetWidth + '.png'
         image.src = imagePath

       # Custom widget images are provided with a directory of images.
@@ -50,16 +48,13 @@

       load = ->
         # When providing custom images for widgets
-        if scope.isKpi
-          # TODO: implement custom KPI data not found image.
-          # return loadCustomKpiImage() if kpiImgProvided()
-        else
+        unless scope.isKpi
           hasMyobEssentialsOnly = ImpacMainSvc.config.currentOrganization.has_myob_essentials_only
           scope.showAlertsTrigger = (hasMyobEssentialsOnly && scope.engine.match(/.*accounts\/.*/) && angular.isDefined(scope.onDisplayAlerts))
           return loadCustomWidgetImage() if widgetImgsBaseDirProvided()
-        scope.hasCallbackUrl = scope.content.linkUrlCallback?
-        # When providing no custom images, uses library defaults.
-        displayDefaultImage()
+          scope.hasCallbackUrl = scope.content.linkUrlCallback?
+          # When providing no custom images, uses library defaults.
+          displayDefaultImage()

       load()


Optimize utils.getPrototypeChain

Optimize utils.getPrototypeChain

--- src/chaplin/lib/utils.coffee
+++ src/chaplin/lib/utils.coffee
@@ -60,10 +60,10 @@

   # Get the whole chain of object prototypes.
   getPrototypeChain: (object) ->
-    chain = [object.constructor.prototype]
-    while object = object.constructor?.superclass?.prototype ? object.constructor?.__super__
-      chain.push object
-    chain.reverse()
+    chain = []
+    while proto = Object.getPrototypeOf object
+      chain.unshift proto
+    chain

   # Get all property versions from object’s prototype chain.
   # E.g. if object1 & object2 have `prop` and object2 inherits from


some simplification peillis/helpapp#3455

--- test/tests.coffee
+++ test/tests.coffee
@@ -180,171 +180,84 @@
       foo = () -> client._sanitizeQuery(query, null)
       expect(foo).to.throw 'Maximum word length exceeded: 55.'

+    scope = nock('http://fooserver')
+      .persist()
+      .get('/5/search')
+      .query(true)
+      .reply((uri, requestBody)->
+        querypart = uri.split('?')[1]
+        { path: uri, headers: this.req.headers, parameters:querypart.split('&') }
+      )
+
     it 'search with no type', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-          hashid: "ffffffffffffffffffffffffffffffff",
-          page:1,
-          rpp:10,
-          query:""})
-        .reply(200, response)
+
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, null, 'fooserver'
       client.search '', (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=', 'page=1', 'rpp=10'
+        res.parameters.should.have.length 4
         done()

     it 'search with type', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-          hashid: "ffffffffffffffffffffffffffffffff",
-          page:1,
-          rpp:10,
-          query:"",
-          type:"product"})
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search '', (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=', 'type=product'
         done()

     it 'search with multi-type', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search?hashid=ffffffffffffffffffffffffffffffff&type=product&type=category&page=1&rpp=10&query=')
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, ['product', 'category'], 'fooserver'
       client.search '', (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'type=category', 'type=product'
         done()

     # SORT PARAMS
     it 'search with type and query', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-      .get('/5/search')
-      .query({
-        hashid: "ffffffffffffffffffffffffffffffff",
-        page:1,
-        rpp:10,
-        query:"querystring",
-        type:"product"})
-      .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=querystring', 'type=product'
         done()

     it 'search with type query and params (sort type object of: object, array, string)', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search?hashid=ffffffffffffffffffffffffffffffff&type=product&page=1&rpp=10&query=querystring&sort%5Bprice%5D=asc&sort%5Btitle%5D=desc&sort%5Bdescription%5D=asc')
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', {sort: mock.sort.Object}, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=querystring', 'sort%5Bprice%5D=asc', 'sort%5Btitle%5D=desc', 'sort%5Bdescription%5D=asc', 'type=product'
         done()

     it 'search with type query and params (sort type array of: object, array, string)', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search?hashid=ffffffffffffffffffffffffffffffff&type=product&page=1&rpp=10&query=querystring&sort%5B0%5D%5Btitle%5D=asc&sort%5B1%5D%5Bdescription%5D=desc')
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', {sort: mock.sort.Array}, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'type=product', 'query=querystring', 'sort%5B0%5D%5Btitle%5D=asc', 'sort%5B1%5D%5Bdescription%5D=desc'
         done()

     it 'search with type query and params (sort type string of: object, array, string)', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-            hashid: "ffffffffffffffffffffffffffffffff",
-            type: "product",
-            page: 1,
-            rpp: 10,
-            query: "querystring",
-            sort: "price"})
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', {sort: mock.sort.String}, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'sort=price', 'query=querystring', 'type=product'
         done()

     # SINGLE PARAMS
     it 'search with type query and params (param valid of: valid, null)', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-            hashid: "ffffffffffffffffffffffffffffffff",
-            type: "product",
-            page: 4,
-            rpp: 30,
-            query: "querystring"})
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', mock.params.valid, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=querystring', 'rpp=30', 'page=4', 'type=product'
         done()

     it 'search with type query and params (param null of: valid, null)', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-            hashid: "ffffffffffffffffffffffffffffffff",
-            type: "product",
-            page: 1,
-            rpp: 10,
-            query: "querystring"})
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', mock.params.null, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'type=product', 'query=querystring'
         done()

     it 'search with type query and params and one sort of type string', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search')
-        .query({
-            hashid: "ffffffffffffffffffffffffffffffff",
-            type: "product",
-            page: 4,
-            rpp: 30,
-            sort: "price",
-            query: "querystring"})
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', {rpp: mock.params.valid.rpp, page: mock.params.valid.page, sort: mock.sort.String}, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'type=product', 'page=4', 'rpp=30', 'sort=price', 'query=querystring'
         done()

     # FILTER PARAMS
     it 'search with type query and filters', (done) ->
-      response =
-        field: "value"
-      scope = nock('http://fooserver')
-        .get('/5/search?hashid=ffffffffffffffffffffffffffffffff&type=product&page=1&rpp=10&query=querystring&filter%5Bcolor%5D=blue&filter%5Bcolor%5D=red&filter%5Bprice%5D%5Bgte%5D=4.36&filter%5Bprice%5D%5Blt%5D=99')
-        .reply(200, response)
       client = new doofinder.Client mock.request.hashid, mock.request.api_key, 5, 'product', 'fooserver'
       client.search 'querystring', {filters: mock.filters}, (err, res) ->
-        res.should.to.be.deep.equal response
+        res.parameters.should.contain 'query=querystring', 'filter%5Bcolor%5D=blue', 'filter%5Bcolor%5D=red', 'filter%5Bprice%5D%5Bgte%5D=4.36', 'filter%5Bprice%5D%5Blt%5D=99'
         done()

     it 'hit', (done) ->


do-the-git

do-the-git

--- src/coffee/main.coffee
+++ src/coffee/main.coffee
@@ -277,7 +277,7 @@
     for s in [0..(1<<2)-1]
       @context.save()
       @context.beginPath()
-      self.transform().apply @context
+      @transform().apply @context

       @_loop domain.x0, domain.x1, 1<<8, 1<<12, expr.bind(null, s), valid


Indicate current team eligibility status on profile page

--- picoCTF-web/web/coffee/account.coffee
+++ picoCTF-web/web/coffee/account.coffee
@@ -140,10 +140,13 @@
           <form onSubmit={@onTeamPasswordChange}>
             <Input type="password" valueLink={@linkState "team_password"} addonBefore={lockGlyph} label="New Team Password" required/>
             <Input type="password" valueLink={@linkState "confirm_team_password"} addonBefore={lockGlyph} label="Confirm New Team Password" required/>
-            <Col md={6}>
+            <Col className="form-group">
                 <Button type="submit">Change Team Password</Button>
             </Col>
           </form>
+
+

+
Your team is considered {if @state.team.eligible then 'eligible' else 'ineligible'} for this competition.

         </Panel>
       else
         <Panel header="Team Management">


Social: notification participants order is reversed

--- client/Main/CommonViews/linkviews/linkgroup.coffee
+++ client/Main/CommonViews/linkviews/linkgroup.coffee
@@ -43,14 +43,12 @@
     #   debugger
     #   return

-    index = 0
-    for participant in participants.slice(0).reverse()
+    for participant, index in participants when participant
       if participant?.bongo_?.constructorName is "ObjectRef"
         itemOptions.origin = participant
         @["participant#{index}"] = new itemClass itemOptions
       else
         @["participant#{index}"] = new itemClass itemOptions, participant
-      index++

     # tmp fix
     return unless @participant0


Client: remove unused no item found widget option

--- client/admin/lib/views/api/apitokenlistview.coffee
+++ client/admin/lib/views/api/apitokenlistview.coffee
@@ -11,9 +11,8 @@

   constructor: (options = {}, data) ->

-    options.cssClass            = 'members-commonview'
-    options.itemLimit          ?= 20
-    options.noItemFoundWidget or= new KDCustomHTMLView
+    options.cssClass   = 'members-commonview'
+    options.itemLimit ?= 20

     super options, data

@@ -35,8 +34,3 @@

     @addSubView @listView

-
-  refresh: ->
-
-    @resetListItems()
-    @fetchAPITokens()


Fix tests

Fix tests

--- src/coffee/queryutils.coffee
+++ src/coffee/queryutils.coffee
@@ -1,4 +1,9 @@
 _ = require 'underscore'
+GLOBALS = require './globals'
+
+class Helpers
+
+  @exists: (x) -> !!x

 class QueryUtils

@@ -30,8 +35,8 @@
   @matchBySku: (products) ->
     skus = _.flatten(products.map((p) ->
       [p.product.masterVariant.sku].concat(p.product.variants.map((v) ->
-        v.sku)))).filter(x ->
-          !!x)
+        v.sku))))
+        .filter(Helpers.exists)
     predicate = QueryUtils.formatAttributePredicate("sku", skus)
     QueryUtils.applyPredicateToVariants(predicate)

@@ -44,8 +49,8 @@
         [
           QueryUtils.valueOf(p.product.masterVariant.attributes, attribute)
         ].concat(p.product.variants.map((v) ->
-          QueryUtils.valueOf(v.attributes, attribute))))).filter(x ->
-            !!x)
+          QueryUtils.valueOf(v.attributes, attribute)))))
+          .filter(Helpers.exists)
       predicate = QueryUtils.formatAttributePredicate(attribute, values)
       QueryUtils.applyPredicateToVariants(predicate)

@@ -54,12 +59,12 @@
   # @param {String} name - name of the attribute
   # @return {Any} attribute value if found
   @valueOf: (attributes, name) ->
-    attrib = _.find(attributes || [], (attribute) ->
+    attrib = _.find(attributes, (attribute) ->
       attribute.name is name)
     attrib?.value

   @formatAttributePredicate: (name, items) ->
-    "#{attribute} in (\"#{items.join('", "')}\")"
+    "#{name} in (\"#{items.join('", "')}\")"

   @applyPredicateToVariants: (predicate) ->
     "masterVariant(#{predicate}) or variants(#{predicate})"


:art:

:art:

--- src/lines-component.coffee
+++ src/lines-component.coffee
@@ -21,13 +21,12 @@

     if performedInitialMeasurement
       {editor, presenter, overlayDecorations, highlightDecorations, placeholderText, backgroundColor} = @props
-
+      {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount, cursorPixelRects} = @props
+
+      @oldState ?= {lines: {}}
       @newState = presenter.state.content
-      @oldState ?= {lines: {}}
-
       {scrollWidth, scrollHeight} = @newState
-      {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
-      {cursorPixelRects} = @props
+
       style =
         height: Math.max(scrollHeight, scrollViewHeight)
         width: scrollWidth


fix for 'Web UI not handling parameterized newcontact page request #348'

--- app/js/app.coffee
+++ app/js/app.coffee
@@ -18,7 +18,7 @@
     $rootScope.magic_unicorn = if magic_unicorn? then magic_unicorn else false
     $rootScope.magic_unicorn.log_message(navigator.userAgent) if $rootScope.magic_unicorn

-    window.navigate_to = (path) -> $location.path(path)
+    window.navigate_to = (path) ->  window.location.href = "/#" + path

     editableOptions.theme = 'default'
     editableThemes['default'].submitTpl = '<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-check fa-lg"></i></button>'


Clear username on direct message sideflex close

--- client/views/app/sideNav/directMessagesFlex.coffee
+++ client/views/app/sideNav/directMessagesFlex.coffee
@@ -30,9 +30,11 @@

 	'click .cancel-direct-message': (e, instance) ->
 		SideNav.closeFlex()
+		instance.clearForm()

 	'click header': (e, instance) ->
 		SideNav.closeFlex()
+		instance.clearForm()

 	'mouseenter header': ->
 		SideNav.overArrow()


Don't crash when not finding [up-switch] target

--- lib/assets/javascripts/unpoly/form.coffee
+++ lib/assets/javascripts/unpoly/form.coffee
@@ -445,7 +445,7 @@
     if switcher
       $(switcher)
     else
-      u.fail('Could not find [up-switch] field for %o', $element.get(0))
+      u.fail('Could not find [up-switch] field for %o', $target.get(0))

   ###*
   Forms with an `up-target` attribute are [submitted via AJAX](/up.submit)


Change index to display latest recipes

Change index to display latest recipes

--- src/handlers/frontpage/IndexHandler.coffee
+++ src/handlers/frontpage/IndexHandler.coffee
@@ -23,7 +23,7 @@
 					results: body.beers

 	onRequest: (request, reply) ->
-		@api.beers.get { limit: 10 }, (err, res, body) =>
+		@api.beers.get { partial: 'last', limit: 10 }, (err, res, body) =>
 			reply @render(err, res, body, request.user)
 		, request.token


fix typo

fix typo

--- app/generator.coffee
+++ app/generator.coffee
@@ -39,7 +39,7 @@
 			message: "What is the domain name for the production website (without protocol)?"
 			default: "example.com"

-		@prompt prompts, (props) () =>
+		@prompt prompts, (props) =>
 			@props = props
 			cb()