Rename firmware file based on platform

Rename firmware file based on platform

--- lib/main.coffee
+++ lib/main.coffee
@@ -43,6 +43,28 @@
 		@subscriptions.dispose()

 	serialize: ->
+
+	consumeStatusBar: (@statusBar) ->
+		@statusBarDefer.resolve @statusBar
+
+	consumeConsolePanel: (@consolePanel) ->
+		@consolePanelDefer.resolve @consolePanel
+
+	consumeToolBar: (toolBar) ->
+		@toolBar = toolBar @packageName
+		@toolBar.addButton
+			icon: 'checkmark-circled'
+			callback: @packageName + ':compile-locally'
+			tooltip: 'Compile locally'
+			iconset: 'ion'
+			priority: 53
+		@consoleToolBar.resolve @toolBar
+
+	consumeParticleDev: (@particleDev) ->
+		@particleDevDefer.resolve @particleDev
+
+	consumeProfiles: (@profileManager) ->
+		@profilesDefer.resolve @profileManager

 	config:
 		dockerHost:
@@ -143,6 +165,9 @@
 						compileErrorHandler 'Compilation failed'
 					else
 						@consolePanel.raw fs.readFileSync(path.join(outputDir, 'memory-use.log')).toString()
+						# Rename binary based on platform
+						fs.moveSync path.join(outputDir, 'firmware.bin'),
+							path.join(outputDir, @profileManager.currentTargetPlatformName.toLowerCase() + '_firmware.bin')
 				, (error) =>
 					compileErrorHandler error

@@ -151,28 +176,6 @@
 		@dockerManager.pull().then (value) =>
 			atom.notifications.addInfo 'Available firmware versions updated'

-	consumeStatusBar: (@statusBar) ->
-		@statusBarDefer.resolve @statusBar
-
-	consumeConsolePanel: (@consolePanel) ->
-		@consolePanelDefer.resolve @consolePanel
-
-	consumeToolBar: (toolBar) ->
-		@toolBar = toolBar @packageName
-		@toolBar.addButton
-			icon: 'checkmark-circled'
-			callback: @packageName + ':compile-locally'
-			tooltip: 'Compile locally'
-			iconset: 'ion'
-			priority: 53
-		@consoleToolBar.resolve @toolBar
-
-	consumeParticleDev: (@particleDev) ->
-		@particleDevDefer.resolve @particleDev
-
-	consumeProfiles: (@profileManager) ->
-		@profilesDefer.resolve @profileManager
-
 	addCommand: (name, callback, target='atom-workspace') ->
 		name = @packageName + ':' + name
 		@subscriptions.add atom.commands.add target, name, callback


minor change

minor change

--- lib/main.coffee
+++ lib/main.coffee
@@ -40,11 +40,11 @@

   consumeVim: ({Base, registerCommandFromSpec}) ->
     commands = null
-    commandSpec =
-      commandPrefix: 'vim-mode-plus-user'
-      getClass: (name) =>
-        commands ?= require('./load-vmp-commands')(Base, @toggle.bind(this))
-        commands[name]
+    getClass = (name) =>
+      commands ?= require('./load-vmp-commands')(Base, @toggle.bind(this))
+      commands[name]
+
+    commandSpec = {commandPrefix: 'vim-mode-plus-user', getClass: getClass}

     @subscriptions.add(
       registerCommandFromSpec('QuickHighlight', commandSpec)


Sort workspace font names in settings literally

--- lib/main.coffee
+++ lib/main.coffee
@@ -47,10 +47,10 @@
         'MigMix 2P'
         'MigMix 1M'
         'MigMix 2M'
+        'Migu 1P'
+        'Migu 1C'
         'Migu 1M'
         'Migu 2M'
-        'Migu 1P'
-        'Migu 1C'
         'Ricty Diminished'
         'Source Han Code JP'
         'Source Han Sans JP'


[fix] Do not forward 'authorization' header in a development environment

--- server/controllers/devices.coffee
+++ server/controllers/devices.coffee
@@ -52,6 +52,8 @@
         # Add his creadentials for CouchDB
         if process.env.NODE_ENV is "production"
             req.headers['authorization'] = getCredentialsHeader()
+        else
+            req.headers['authorization'] = null

         # Forward request to Couch
         # the request didn't go through the DS because for some unknown


added dynamic id to form target and iframe id

--- modules/gui/lib/widgets/UploadButton.coffee
+++ modules/gui/lib/widgets/UploadButton.coffee
@@ -21,7 +21,7 @@
                         class: 'button'

                 content: ->
-                    form action:@data.action, target:'upload-frame', method:'post', enctype:'multipart/form-data', style: 'width:0;height:0;visibility:hidden', ->
+                    form action:@data.action, target:'upload-frame-'+@id, method:'post', enctype:'multipart/form-data', style: 'width:0;height:0;visibility:hidden', ->

                         for name, field of @data.fields

@@ -43,12 +43,12 @@
                         input _attr

                     if @data.button.type is 'link'
-                        a class:@data.button.class, href:'#', (@data.button.text)
+                        a class:@data.button.class, href:'#', (@data.button.html || @data.button.text)

                     else
-                        button class:@data.button.class, (@data.button.text)
+                        button class:@data.button.class, (@data.button.html || @data.button.text)

-                    iframe id:'upload-frame', name:'upload-frame', width:'0px', height:'0px', frameborder:0, style: 'width:0;height:0;visibility:hidden'
+                    iframe id:'upload-frame-'+@id, name:'upload-frame-'+@id, width:'0px', height:'0px', frameborder:0, style: 'width:0;height:0;visibility:hidden'

                 popup:
@@ -97,7 +97,7 @@

                 files = form.find '[name=files]'

-                @find('.button').click ()=>
+                @find('.'+@data.button.class).click ()=>
                     files.click()
                     return false


Add drag & zoom to visualization

Add drag & zoom to visualization

--- app/frontend/javascripts/views/visualization-graph-canvas-test.js.coffee
+++ app/frontend/javascripts/views/visualization-graph-canvas-test.js.coffee
@@ -150,14 +150,16 @@
       .on('drag',   @onNodeDragged)
       .on('end',    @onNodeDragEnd)

+    svgDrag = d3.drag()
+      .on('start',  @onCanvasDragStart)
+      .on('drag',   @onCanvasDragged)
+      .on('end',    @onCanvasDragEnd)
+
     # Setup SVG
     @svg = d3.select('svg')
-        .attr('width',  @viewport.width)
-        .attr('height', @viewport.height)
-        #.call(d3.behavior.drag()
-        #  .on('drag',       @onCanvasDrag)
-        #  .on('dragstart',  @onCanvasDragStart)
-        #  .on('dragend',    @onCanvasDragEnd))
+      .attr 'width',  @viewport.width
+      .attr 'height', @viewport.height
+      .call svgDrag

     # if nodesSize = 1, set nodes size based on its number of relations
     if @parameters.nodesSize == 1
@@ -244,10 +246,10 @@
       # set nodes color based on parameters.nodesColor value or image as pattern if defined
       .style 'fill',    @getNodeFill
       .style 'stroke',  @getNodeColor
-      # .on   'mouseover',  @onNodeOver
-      # .on   'mouseout',   @onNodeOut
-      # .on   'click',      @onNodeClick
-      # .on   'dblclick',   @onNodeDoubleClick
+      .on   'mouseover',  @onNodeOver
+      .on   'mouseout',   @onNodeOut
+      .on   'click',      @onNodeClick
+      .on   'dblclick',   @onNodeDoubleClick
       .call @forceDrag

     @nodes = @nodes_cont.selectAll('.node')
@@ -523,11 +525,31 @@
     return 'translate(' + (@viewport.center.x+@viewport.origin.x+@viewport.x-@viewport.offsetx) + ',' + (@viewport.center.y+@viewport.origin.y+@viewport.y-@viewport.offsety) + ')scale(' + @viewport.scale + ')'

+  # Navigation Methods
+  # ---------------
+
+  zoomIn: ->
+    @zoom @viewport.scale*1.2
+
+  zoomOut: ->
+    @zoom @viewport.scale/1.2
+
+  zoom: (value) ->
+    @viewport.scale = value
+    @container
+      .transition()
+        .duration(500)
+        .attr 'transform', @getContainerTransform()
+
+
   # Events Methods
   # ---------------

   # Canvas Drag Events
-  onCanvasDrag: =>
+  onCanvasDragStart: =>
+    @svg.style('cursor','move')
+
+  onCanvasDragged: =>
     @viewport.x  += d3.event.dx
     @viewport.y  += d3.event.dy
     @viewport.dx += d3.event.dx
@@ -535,18 +557,15 @@
     @rescale()
     d3.event.sourceEvent.stopPropagation()  # silence other listeners

-  onCanvasDragStart: =>
-    @svg.style('cursor','move')
-
   onCanvasDragEnd: =>
+    @svg.style('cursor','default')
     # Skip if viewport has no translation
     if @viewport.dx == 0 and @viewport.dy == 0
       Backbone.trigger 'visualization.node.hideInfo'
       return
     # TODO! Add viewportMove action to history
     @viewport.dx = @viewport.dy = 0;
-    @svg.style('cursor','default')
-
+
   # Nodes drag events
   onNodeDragStart: (d) =>
     # d3.event.sourceEvent.stopPropagation() # silence other listeners
@@ -600,7 +619,8 @@

   onNodeDoubleClick: (d) =>
     # unfix the node position when the node is double clicked
-    d.fixed = false
+    @force.unfix d
+    #d.fixed = false

   # Tick Function
   onTick: =>


prevent the user to be able tu reconciliate an item with one having a different nature

--- app/assets/javascripts/backend/purchase_process/reconciliation.js.coffee
+++ app/assets/javascripts/backend/purchase_process/reconciliation.js.coffee
@@ -13,6 +13,7 @@
       $('.reconcile-title').addClass('hidden')
       $('.reconcile-state').addClass('hidden')

+
   refresh_state = ->
     $displayComplianceStates = $(".nested-fields .nested-item-form[data-non-compliant='true']")

@@ -23,8 +24,22 @@
     else
       $('.compliance-title').removeClass('hidden')

+  disable_selector_input = ($selector_input) =>
+    $selector_input.prop('disabled', true)
+    $selector_input.siblings(':last').addClass('disabled')
+
+  prevent_unroll_edition_for_reconciliated_items = (e, data) ->
+    target = data if data
+    target ||= e.target
+    target = $(target).closest('tbody') unless $(target).is('tbody')
+
+    console.log("TARGET", target)
+    if $(target).find('.nested-item-form[data-item-id]').length
+      disable_selector_input $(target).find('input[id*="variant"]')
+
+
+  $(document).on 'cocoon:after-insert', '#new_reception, #new_purchase_invoice, .edit_reception, .edit_purchase_invoice', prevent_unroll_edition_for_reconciliated_items
   $(document).on 'cocoon:after-remove', '#new_reception, #new_purchase_invoice, .edit_reception, .edit_purchase_invoice', refresh_state
-

   $(document).on 'change', '#purchase_invoice_accepted_state', (event) ->
     checked = $(event.target).is(':checked')
@@ -46,12 +61,10 @@
     event.stopPropagation()
     E.reconciliation.displayReconciliationModal(event, {})

-
   $(document).on 'click', '#showItemReconciliationModal', (event) ->
     event.stopPropagation()
     itemFieldId = $(event.target).closest('.form-field').find('.purchase-item-attribute').attr('id')
     E.reconciliation.displayReconciliationModal(event, { reconciliate_item: true, item_field_id: itemFieldId })
-

   $(document).ready ->
     if $('#purchase_process_reconciliation').length > 0
@@ -76,7 +89,6 @@
   $(document).on 'change', '#purchase_process_reconciliation .item-checkbox', (event) ->
     E.reconciliation.displayClosePurchaseOrderBlock(event)

-
   $(document).on 'click', '#purchase_process_reconciliation .valid-modal', (event) ->
     modal = $(event.target).closest('#purchase_process_reconciliation')

@@ -119,7 +131,6 @@
       if $nonCompliantItems.length
         $('.compliance-title').removeClass('hidden')

-
     displayReconciliateState: (event) ->
       $('#purchase_invoice_accepted_state').val('reconcile')
       $('#purchase_invoice_reconciliate_state').val('reconcile')
@@ -147,7 +158,6 @@

       $('.reconcile-state').removeClass('hidden')

-
     displayAcceptedState: (event) ->
       $('#purchase_invoice_accepted_state').val('accepted')
       $('#purchase_invoice_reconciliate_state').val('to_reconcile')
@@ -167,7 +177,6 @@
         $('.reconcile-state').addClass('hidden')

       $('.accepted-state').removeClass('hidden')
-

     displayNoReconciliateState: (event) ->
       $('#purchase_invoice_accepted_state').val('accepted')
@@ -209,7 +218,6 @@
           action = $form.attr('action')
           datas['reception'] = action.substr(action.lastIndexOf('/') + 1)

-
       $.ajax
         url: url
         data: datas
@@ -227,7 +235,6 @@
         $checkbox = modal.getModalContent().find("input[type='checkbox'][data-id=#{id}]")
         $checkbox.prop('checked', true) if $checkbox.length

-
     reconciliateItems: (modal) ->
       checkedItemId = $(modal).find('.item-checkbox:checked').attr('data-id')
       itemFieldId = $('.item-checkbox:checked').attr('data-item-field-id')
@@ -237,7 +244,6 @@
       else
         $("##{itemFieldId}").val(checkedItemId)

-
     createLinesWithSelectedItems: (modal, displayedItemIds, event) ->
       itemsCheckboxes = $(modal).find('.item-checkbox:checked')

@@ -253,7 +259,6 @@
          $('#purchase_invoice_responsible_id').first().selector('value', responsibleId)

         E.reconciliation._fillNewLineForm(itemCheckbox, isPurchaseOrderModal)
-

     removeLineWithUnselectedItems: (modal, displayedItemIds, event) ->
       for id in displayedItemIds
@@ -262,9 +267,7 @@
           $container = $(".nested-fields .nested-item-form[data-item-id='#{id}'").closest('tbody')
           if $container.length
             $container.find('a.remove-item').click()
-
-      0
-
+      return

     _createNewItemLine: (itemCheckbox) ->
       variantType = $(itemCheckbox).closest('.item').attr('data-variant-type')
@@ -286,18 +289,18 @@
       itemConditionningQuantity = $(checkboxLine).attr('data-conditionning-quantity')
       itemCompliantState = $(checkboxLine).attr('data-non-compliant')

+      console.log "HERE"
+      $(lastLineForm).attr('data-item-id', itemId)
+      $(lastLineForm).attr('data-non-compliant', itemCompliantState)
+
       if isPurchaseOrderModal == "true"
         E.reconciliation._fillPurchaseOrderItem(lastLineForm, checkboxLine, itemId, itemQuantity, itemConditionning, itemConditionningQuantity)
       else
         E.reconciliation._fillReceptionItem(lastLineForm, checkboxLine, itemId, itemQuantity)
-
-      $(lastLineForm).attr('data-item-id', itemId)
-      $(lastLineForm).attr('data-non-compliant', itemCompliantState)

       $(lastLineForm).find('input[data-remember="equipment"]').first().selector('value', equipmentId)
       $(lastLineForm).find('.no-reconciliate-item-state').addClass('hidden')
       $(lastLineForm).find('.reconciliate-item-state').removeClass('hidden')
-

     _fillReceptionItem: (lastLineForm, checkboxLine, itemId, itemQuantity) ->
       variantId = $(checkboxLine).find('.variant').attr('data-id')
@@ -323,7 +326,8 @@
       $(lastLineForm).find('.form-field .invoice-unit-amount').val(itemUnitCost)
       $(lastLineForm).find('.form-field .invoice-discount-percentage').val(itemReductionPercentage)
       $(lastLineForm).find('.form-field .pre-tax-invoice-total').val(itemTotalAmount)
-      $(lastLineForm).find('.form-field .invoice-variant').first().selector('value', variantId, (-> $(lastLineForm).find('.form-field .invoice-quantity').trigger('change')))
+      $selectorInput = $(lastLineForm).find('.form-field .invoice-variant').first()
+      $selectorInput.selector('value', variantId, (-> disable_selector_input($selectorInput);$(lastLineForm).find('.form-field .invoice-quantity').trigger('change')))
       $(lastLineForm).find('.form-field .purchase_invoice_items_activity_budget .selector-search').first().selector('value', activityBudgetId)
       $(lastLineForm).find('.form-field .purchase_invoice_items_team .selector-search').first().selector('value', teamId)

@@ -338,19 +342,16 @@
         firstVatValue = $(lastLineForm).find('.form-field .vat-total option:first').val()
         $(invoiceVatField).val(firstVatValue).change()

-      $(lastLineForm).trigger('cocoon:after-insert')
-
       setTimeout (->
         $('.form-field .invoice-total').trigger('change')), 1000
-

     _fillPurchaseOrderItem: (lastLineForm, checkboxLine, itemId, itemQuantity, itemConditionning, itemConditionningQuantity) ->
       variantId = $(checkboxLine).find('.variant').attr('data-id')
       variantType = $(checkboxLine).attr('data-variant-type')

       $(lastLineForm).find('.purchase-item-attribute').val(itemId)
-
-      $(lastLineForm).find('.item-block-role .parcel-item-variant').first().selector('value', variantId)
+      $selectorInput =$(lastLineForm).find('.item-block-role .parcel-item-variant').first()
+      $selectorInput.selector('value', variantId, (-> disable_selector_input($selectorInput);$(lastLineForm).find('.form-field .invoice-quantity').trigger('change')))
       $(lastLineForm).find('.hidden.purchase-item-attribute').val(itemId)

       if variantType == "service" || variantType == "cost"
@@ -367,9 +368,4 @@
       if $(closePurchaseOrderBlock).find('input[type="radio"][value="true"]').is(':checked')
         $(lastLineForm).find('.purchase-order-to-close-id').val(modelId)

-
-
-
-
-
 ) ekylibre, jQuery


Use a single colorScale for both quantitative & qualitative scales

--- app/frontend/javascripts/views/visualization-graph-canvas-test.js.coffee
+++ app/frontend/javascripts/views/visualization-graph-canvas-test.js.coffee
@@ -108,9 +108,6 @@
       @COLORS['quantitative-10']
     ]

-    # Setup color scale
-    @colorQualitativeScale  = d3.scaleOrdinal().range @COLOR_QUALITATIVE
-    @colorQuantitativeScale = d3.scaleOrdinal().range @COLOR_QUANTITATIVE

   setup: (_data, _parameters) ->

@@ -226,9 +223,8 @@
       if d.visible
         @addNodeData d

-    # Setup color ordinal scale domain
-    @colorQualitativeScale.domain   data.nodes.map( (d) -> d.node_type )
-    @colorQuantitativeScale.domain  data.nodes.map( (d) -> d.node_type )
+    # Setup color scale
+    @setColorScale()

     # Setup Relations: change relations source & target N based id to 0 based ids & setup linkedByIndex object
     data.relations.forEach (d) =>
@@ -638,6 +634,11 @@
   # Config Methods
   # ---------------

+  setColorScale: ->
+    if @parameters.nodesColor == 'qualitative' or @parameters.nodesColor == 'quantitative'
+      @colorScale = d3.scaleOrdinal().range if @parameters.nodesColor == 'qualitative' then @COLOR_QUALITATIVE else @COLOR_QUANTITATIVE
+      @colorScale.domain @data_nodes.map( (d) -> return d.node_type )
+
   updateNodesType: ->
     if @parameters.nodesColor == 'qualitative' or @parameters.nodesColor == 'quantitative'
       console.log 'updateNodesType'
@@ -647,6 +648,7 @@

   updateNodesColor: (value) =>
     @parameters.nodesColor = value
+    @setColorScale()
     @nodes
       .style 'fill',   @getNodeFill
       .style 'stroke', @getNodeColor
@@ -867,12 +869,10 @@
     return parseInt(@nodes_cont.select('#node-'+d.id).attr('r'))+13

   getNodeColor: (d) =>
-    if @parameters.nodesColor == 'qualitative'
-       color = @colorQualitativeScale d.node_type
-     else if @parameters.nodesColor == 'quantitative'
-       color = @colorQuantitativeScale d.node_type
-     else
-       color = @COLORS[@parameters.nodesColor]
+    if @parameters.nodesColor == 'qualitative' or @parameters.nodesColor == 'quantitative'
+      color = @colorScale d.node_type
+    else
+      color = @COLORS[@parameters.nodesColor]
     return color

   getNodeFill: (d) =>


Removed old unused file.

Removed old unused file.

--- myou_log.coffee
+++ myou_log.coffee
@@ -1,32 +0,0 @@
-class MyouLog
-    constructor: (entries=[])->
-        @entries = []
-        @last_entry = null
-        @is_active = false
-        @last_task = null
-        @last_entry = null
-        @last_activity_change_date = 0
-        for e in entries
-            @new_entry e
-
-    clear_log: ->
-        @entries.clear()
-
-    new_entry: (entry)->
-        if entry.active != @active
-            @is_active = entry.active
-            @last_activity_change_date = entry.date
-            new_entry = true
-
-        if entry.task? and entry.task != @last_task
-            @last_task = entry.task
-            new_entry = true
-
-        if entry.active and @last_entry? and entry.task != @last_entry.task
-            new_entry = true
-
-        if new_entry
-            @last_entry = entry
-            @entries.push entry
-
-module.exports = MyouLog


took out a stray laptop grid, modified slot record styling

--- app/assets/volume/slot.coffee
+++ app/assets/volume/slot.coffee
@@ -56,14 +56,16 @@
         if l < 0
           styles.left = '0px'
           styles['border-left'] = '0px'
-          styles['border-radius'] = '0px'
+          styles['border-top-left-radius'] = '0px'
+          styles['border-bottom-left-radius'] = '0px'
         else if l <= 1
           styles.left = 100*l + '%'
         r = offsetPosition(p.u)
         if r > 1
           styles.right = '0px'
           styles['border-right'] = '0px'
-          styles['border-radius'] = '0px'
+          styles['border-top-right-radius'] = '0px'
+          styles['border-bottom-right-radius'] = '0px'
         else if r >= 0
           styles.right = 100 - 100*r + '%'
       else


Removed useless modification

Removed useless modification

--- app/models/application.coffee
+++ app/models/application.coffee
@@ -19,7 +19,6 @@
         descriptor =
             user: @slug
             name: @slug
-            displayName: @displayName
             domain: "127.0.0.1"
             repository:
                 type: "git",


Don't send emails to people with email addresses

--- js/inner/build.coffee
+++ js/inner/build.coffee
@@ -783,6 +783,6 @@
       @inviting[name] = @observable !!email

   send: () =>
-    for name, email of @inviting()
+    for name, email of @inviting when email()
       VM.project().invite_team_member name, email


Remove space

Remove space

--- src/sdk.coffee
+++ src/sdk.coffee
@@ -135,7 +135,6 @@

 TeamSnap::getCollectionForItem = (item) ->
-
   unless @collections
     throw new TSError 'You must auth() and loadCollections() before using any
     load*, save*, create*, or delete* methods.'


implement SC.Helper.millisecondsToHMS

implement SC.Helper.millisecondsToHMS

--- src/sdk.coffee
+++ src/sdk.coffee
@@ -290,6 +290,25 @@
       else
         element.addEventListener(eventName, func, false)

+    millisecondsToHMS: (ms) ->
+      hms = {
+        h: Math.floor(ms/(60*60*1000)),
+        m: Math.floor((ms/60000) % 60),
+        s: Math.floor((ms/1000) % 60)
+      }
+      tc = []
+      tc.push(hms.h) if (hms.h > 0)
+      m = hms.m;
+
+      mPrefix = ""
+      sPrefix = ""
+      mPrefix = "0" if hms.m < 10 && hms.h > 0
+      sPrefix = "0" if hms.s < 10
+
+      tc.push(mPrefix + hms.m)
+      tc.push(sPrefix + hms.s)
+      tc.join(':')
+
     setFlashStatusCodeMaps: (query) ->
       query["_status_code_map[400]"] = 200
       query["_status_code_map[401]"] = 200


Fix problem when return value from afterMethod and only stop execution when value isnt undefined

--- konecty:methods-middleware.coffee
+++ konecty:methods-middleware.coffee
@@ -104,14 +104,14 @@
 			logBeforeExecution "<- #{name} - #{beforeMethodName}", scope, arguments
 			result = beforeMethod.apply scope, arguments
 			logAfterExecution "<- #{name} - #{beforeMethodName}", scope, arguments, result
-			if result?
+			if result isnt undefined
 				return processResult result

 		for middlewareName, middleware of middlewares
 			logBeforeExecution "<> #{name} - #{middlewareName}", scope, arguments
 			result = middleware.apply scope, arguments
 			logAfterExecution "<> #{name} - #{middlewareName}", scope, arguments, result
-			if result?
+			if result isnt undefined
 				return processResult result

 		logBeforeExecution "   #{name}", scope, arguments
@@ -130,8 +130,8 @@

 			result = afterMethodParams.result

-			if afterMethodResult?
-				return result
+			if afterMethodResult isnt undefined
+				return afterMethodResult

 		return result


Update modal.coffee

Update modal.coffee

Code review

--- vendor/assets/javascripts/mice/modal.coffee
+++ vendor/assets/javascripts/mice/modal.coffee
@@ -228,7 +228,7 @@

   $.fn.modal.noConflict = ->
     $.fn.modal = old
-    this
+    @

   # MODAL DATA-API
@@ -237,17 +237,16 @@
   $(document).on 'click.bs.modal.data-api',
     '[data-toggle="modal"]',
     (e) ->
-      $this   = $(@)
-      href    = $this.attr('href')
-      $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) # strip for ie7
-      option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
-      e.preventDefault() if $this.is('a')
+      $element  = $(@)
+      href      = $element.attr('href')
+      $target   = $($element.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) # strip for ie7
+      option    = if $target.data('bs.modal') then 'toggle' else $.extend({ remote: !/#/.test(href) && href }, $target.data(), $element.data())
+
+      e.preventDefault() if $element.is('a')

       $target.one 'show.bs.modal', (showEvent) ->
         return if (showEvent.isDefaultPrevented()) # only register focus restorer if modal will actually get shown
-        $target.one 'hidden.bs.modal', ->
-          $this.is(':visible') && $this.trigger('focus')
+        $target.one 'hidden.bs.modal', -> $element.is(':visible') && $element.trigger('focus')

       Plugin.call($target, option, @)


add a test

add a test

--- client/apps/edit/components/content/sections/text/test/index.test.coffee
+++ client/apps/edit/components/content/sections/text/test/index.test.coffee
@@ -62,7 +62,7 @@
           type: 'text'
         },
         {
-          body: '
Erin Shirreff
'
+          body: '
Erin & Shirreff
'
           type: 'text'
         }
       ]
@@ -140,7 +140,6 @@
       @component.onChange(@component.state.editorState)
       @component.state.html.should.eql '
01  here is a link.

In 2016, K mounted a solo show at prescient Berlin gallery KOW, restaging his installation It’s Spring and the Weather is Great so let’s close all object matters (2012), for which he created seven step ladders with microphones and instruments attached for a performance initially meant to take place at Speakers’ Corner in London’s Hyde Park that was eventually mounted in 2010 at the Serpentine Galleries.

'

-
   describe '#availableBlocks', ->

     it 'Returns the correct blocks for a feature article', ->
@@ -365,6 +364,12 @@
       @shortComponent.confirmLink 'link.com'
       @shortComponent.state.html.should.containEql ''

+    it 'Can handle special characters inside links correctly', ->
+      @props.section = @sections.models[2]
+      component = ReactDOM.render React.createElement(@SectionText, @props), (@$el = $ "

")[0]
+      $(ReactDOM.findDOMNode(component)).find('.edit-section--text__input').text().should.containEql 'Erin & Shirreff'
+      $(ReactDOM.findDOMNode(component)).find('.edit-section--text__input').html().should.containEql 'Erin & Shirreff'
+      component.state.html.should.containEql 'Erin & Shirreff'

   describe 'Artist plugin', ->

@@ -387,7 +392,7 @@
     it 'Adds data-id to artist links', ->
       component = ReactDOM.render React.createElement(@SectionText, @artistProps), (@$el = $ "

")[0]
       component.onChange(component.state.editorState)
-      component.state.html.should.eql '
Erin Shirreff
'
+      component.state.html.should.eql '
Erin & Shirreff
'

   describe '#toggleBlockQuote', ->


fix so that local_hub console works with newer node versions.  (Yes, this was ridiculously simple and obvious!)

--- salvus/console_server_child.coffee
+++ salvus/console_server_child.coffee
@@ -70,7 +70,7 @@
             return i+1

     CSI_code = (data) ->
-        s = data.toString('ascii')
+        s = data.toString('utf-8')
         if resize_sequence?
             start = 0
             end = parse_resize(s)
@@ -89,10 +89,10 @@

     socket.on 'data', (data) ->
         data = CSI_code(data)
-        term.write data
+        term.write(data)

     term.on 'data', (data) ->
-        socket.write data
+        socket.write(data)

     term.on 'exit', () ->
         socket.end()


fix(paths): paths on Windows rendered as file paths

C:Should be
/

--- app/templates/gulpfile.coffee
+++ app/templates/gulpfile.coffee
@@ -130,7 +130,7 @@
 onScript = (file) ->
 	filePath = path.relative file.base, file.path
 	filePath = path.join SCRIPTS_MIN_DIRECTORY, filePath if file.revOrigBase
-	filePath = path.resolve '/', filePath
+	filePath = unixifyPath '/' + filePath
 	endsWith = '.spec.js'
 	isSpec   = filePath.slice(-endsWith.length) is endsWith

@@ -141,7 +141,7 @@
 onStyle = (file) ->
 	filePath = path.relative file.base, file.path
 	filePath = path.join STYLES_MIN_DIRECTORY, filePath if file.revOrigBase
-	filePath = path.resolve '/', filePath
+	filePath = unixifyPath '/' + filePath

 	templateOptions.styles.push filePath

@@ -237,7 +237,7 @@
 		.on 'error', onError

 # Generate CHANGELOG
-gulp.task 'changelog', ['stats'], ->
+gulp.task 'changelog', ['normalizeComponents', 'stats'], ->
 	options =
 		repository: pkg.repository.url
 		version: pkg.version


trying to fix load

trying to fix load

--- server/publications.coffee
+++ server/publications.coffee
@@ -48,19 +48,19 @@
 	if typeof rid isnt 'string'
 		return this.ready()

-	cursor = ChatMessage.find {rid: rid}, {sort: {ts: -1}, limit: 50}
+	return ChatMessage.find {rid: rid}, {sort: {ts: -1}, limit: 50}

-	observer = cursor.observeChanges
-		added: (id, record) ->
-			self.added 'data.ChatMessage', id, record
-		changed: (id, record) ->
-			self.changed 'data.ChatMessage', id, record
+	# cursor = ChatMessage.find {rid: rid}, {sort: {ts: -1}, limit: 50}
+	# observer = cursor.observeChanges
+	# 	added: (id, record) ->
+	# 		self.added 'data.ChatMessage', id, record
+	# 	changed: (id, record) ->
+	# 		self.changed 'data.ChatMessage', id, record
 	# 	removed: (id) ->
 	# 		self.removed 'ChatMessage', id
-
-	@ready()
-	@onStop ->
-		observer.stop()
+	# @ready()
+	# @onStop ->
+	# 	observer.stop()

 Meteor.publish 'allUsers', ->
 	unless this.userId


Test commit.

Test commit.

--- server/routes/index.coffee
+++ server/routes/index.coffee
@@ -2,4 +2,4 @@
 module.exports = (app) ->
   # Load time settings.
   app.get '/', (req, res) ->
-    res.end 'Welcome to Type It Quick!'
+    res.end 'Welcome to Type It Quick Test!'


Added :frog:

Added :frog:

--- scripts/idobata-talk.coffee
+++ scripts/idobata-talk.coffee
@@ -51,7 +51,11 @@
     msg.send "はぁはぁはぁ…。き、奇遇ね、わ、私も今ちょうど帰るとこなんだけど、ぜぇぜぇ。"

   robot.hear /:frog/i, (msg) ->
-    msg.send "ぴょんぴょん"
+    msg.send msg.random [
+      "ぴょんぴょん"
+      "…大変ね"
+      "西に向かって懺悔してからissueを閉じなさいっ！"
+    ]
   # respond
   robot.respond /嫌い？$/i, (msg) ->
     words = [


janitoring

janitoring

--- scripts/pagerv2_hook.coffee
+++ scripts/pagerv2_hook.coffee
@@ -13,8 +13,6 @@
 #   mose

 Pagerv2 = require '../lib/pagerv2'
-moment = require 'moment'
-path = require 'path'

 module.exports = (robot) ->


modified status-check.coffee

modified status-check.coffee

--- scripts/status-check.coffee
+++ scripts/status-check.coffee
@@ -2,27 +2,42 @@
 module.exports = (robot) ->
   ### tmp check ###
   robot.hear /sc sites/i, (msg) ->
+    statusCheck(msg)
+
+  statusCheck = (msg) ->
     msg.send 'checking...'
     key = 'sites'
+
+    ##adding
+#    messages = robot.brain.get(key) ? []
+#    i = { url: "http://google.com", status: 200}
+#    messages.push i
+#    i = { url: "http://yahoo.co.jp", status: 200}
+#    messages.push i
+#    robot.brain.set(key, messages)
+#    msg.send "added #{i.url}, #{i.status}"
+
+    #getting
     urls = robot.brain.get(key) ? []
-    url = urls.map (i) ->
-        "#{i.url} #{i.status}"
-      .join '\n'
-    msg.send url
-    msg.send urls.length
-    msg.send urls[0]
+#    url = urls.map (i) ->
+#        "#{i.url} #{i.status}"
+#      .join '\n'
+#
+    robot.logger.info urls
+    for valueObject, key in urls #u: url, s:status
+      robot.send({room: "bot"}, 'key: '+key, 'url: '+ valueObject.url, 'staus: '+ valueObject.status)

-    for u, s in urls #u: url, s:status
-      robot.logger.info u, s #@@
-      robot.emit 'healthcheck:url', {url: u, status: s}
+#    for u, s in urls #u: url, s:status
+#      robot.logger.info u, s #@@
+      robot.emit 'healthcheck:url', {url: valueObject.url, status: valueObject.status}

 #    robot.emit 'healthcheck:url', {url: 'https://www.google.com', status: 200}
 #    robot.emit 'healthcheck:url', {url: 'http://takamachi.com/hogehoge', status: 200}
 #    robot.emit 'healthcheck:url', {url: 'http://sasukene.info', status: 500}
-#

+  ###test module###
+  test = ->

-  test = ->
     messages = []
     key = 'sites'
     i = { url: 'www.google.com', status: 200}
@@ -30,17 +45,13 @@
     i = { url: 'www.yahoo.co.jp', status: 200}
     messages.push i
     robot.logger.info messages
-    messages = [
-      hoge: {url: 'hoge.com'},
-      fuga: {url: 'fuga.com'}
-    ]
-    robot.logger.info messages
-    for valueObject, key1 in messages #u: url, s:status
-      robot.send({room: "bot"}, 'key1: '+key1)
-      for value, key2 of valueObject
-        robot.send({room: "bot"}, 'key: '+key2)
-        # robot.send({room: "bot"}, 'value: ' + value)
-        robot.logger.info value
+#    messages = [
+#      hoge: {url: 'hoge.com'},
+#      fuga: {url: 'fuga.com'}
+#    ]
+
+    for valueObject, key in messages #u: url, s:status
+      robot.send({room: "bot"}, 'key: '+key, 'url: '+ valueObject.url, 'staus: '+ valueObject.status)
     # robot.logger.info key, value, key #@@

     process.exit()
@@ -56,33 +67,34 @@
     # robot.send({room: "bot"}, 'hello')
     process.exit()

-  # test()
+#  test()
+

   ### Event class ###
   robot.on 'healthcheck:url', (data) ->
-      options = {
-        url: data.url
-        status: data.status
-        headers: "User-Agent":"iPhone"
-      }
-      request.get options, (err, res, body) ->
+    options = {
+      url: data.url
+      status: data.status
+      headers: "User-Agent":"iPhone"
+    }
+    request.get options, (err, res, body) ->
 #        robot.logger.info data.status
 #        robot.logger.info options.url
 #        robot.logger.info res.statusCode
-        if err
+      if err
 #          robot.logger.error err
 #          robot.send {room: "notifications"}, "error: #{res.statusCode}"
-          robot.send {room: "bot"}, err
-        else if res.statusCode is options.status
-          msg = "#{options.url} : #{res.statusCode}"
-          robot.send {room: "bot"}, msg + " All right :)"
-        else if res.statusCode isnt options.status #doesn't matched
+        robot.send {room: "bot"}, err
+      else if res.statusCode is options.status
+        msg = "#{options.url} : #{res.statusCode}"
+        robot.send {room: "bot"}, msg + " All right :)"
+      else if res.statusCode isnt options.status #doesn't matched
 #          robot.logger.error err
-          msg = "#{options.url} : #{res.statusCode}"
-          robot.send {room: "bot"}, msg + " Something wrong :("
+        msg = "#{options.url} : #{res.statusCode}"
+        robot.send {room: "bot"}, msg + " Something wrong :("
 #        else if res.statusCode isnt 200 #!200
 ##          robot.logger.error res.headers
 ##          robot.send {room: "bot"}, "success: #{res.statusCode}"


Do not allow whitespace after emph chars

--- grammars/restructuredtext.cson
+++ grammars/restructuredtext.cson
@@ -409,7 +409,7 @@
             'name': 'punctuation.definition.bold.restructuredtext'
           '2':
             'name': 'punctuation.definition.bold.restructuredtext'
-        'match': '(\\*\\*)[^*]+(\\*\\*)'
+        'match': '(\\*\\*)[^\\*\\s][^*]*(\\*\\*)'
         'name': 'markup.bold.restructuredtext'
       }
       {
@@ -418,7 +418,7 @@
             'name': 'punctuation.definition.italic.restructuredtext'
           '2':
             'name': 'punctuation.definition.italic.restructuredtext'
-        'match': '(\\*)[^*]+(\\*)'
+        'match': '(\\*)[^\\*\\s][^*]*(\\*)'
         'name': 'markup.italic.restructuredtext'
       }
     ]


Simplification

Simplification

--- memory_sync.coffee
+++ memory_sync.coffee
@@ -1,6 +1,5 @@
 util = require 'util'
 _ = require 'underscore'
-inflection = require 'inflection'

 MemoryCursor = require './lib/memory_cursor'
 Schema = require './lib/schema'


added time for Shaharit so we don't have to rush thru Shema

--- source/javascripts/vatikin.coffee
+++ source/javascripts/vatikin.coffee
@@ -21,10 +21,10 @@
   @NULL = { }
   @YOM_KIPPUR = { korbanot: 15, hodu: 36, yishtabach: 17 }
   @YOM_TOB = { korbanot: 15, hodu: 26, yishtabach: 17 }
-  @HOL_HAMOED = { korbanot: 16, hodu: 12, yishtabach: 8 }
-  @ASERET_YEMEI_TESHUBA = { selihot: 56, korbanot: 16, hodu: 11, yishtabach: 8 }
-  @ELUL = { selihot: 50, korbanot: 16, hodu: 11, yishtabach: 8 }
-  @WEEKDAY = { korbanot: 16, hodu: 11, yishtabach: 8 }
+  @HOL_HAMOED = { korbanot: 16, hodu: 13, yishtabach: 8.5 }
+  @ASERET_YEMEI_TESHUBA = { selihot: 56, korbanot: 16, hodu: 11.5, yishtabach: 8.5 }
+  @ELUL = { selihot: 50, korbanot: 16, hodu: 11.5, yishtabach: 8.5 }
+  @WEEKDAY = { korbanot: 16, hodu: 11.5, yishtabach: 8.5 }
 ).call(Vatikin)

 window.Vatikin = Vatikin


fix is_account_name

fix is_account_name

--- dl/src/common/validation.coffee
+++ dl/src/common/validation.coffee
@@ -11,7 +11,7 @@
         return no if is_empty value
         length = value.length
         return no if length < 3 or length > 64
-        /^(([a-z][a-z0-9]*([\.-][a-z][a-z0-9]*)*)(\/([a-z][a-z0-9]*([\.-][a-z][a-z0-9]*)*))?)$/.test value
+        /^(([a-z][a-z0-9]*([\.-][a-z0-9]*)*)(\/([a-z][a-z0-9]*([\.-][a-z0-9]*)*))?)$/.test value

     is_cheap_name: (account_name)->
         account_name.length > 8 or


Modernize markdown preview spec

Modernize markdown preview spec

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -4,7 +4,7 @@

 describe "MarkdownPreview package", ->
   beforeEach ->
-    window.loadPackage('gfm')
+    atom.activatePackage('gfm')
     project.setPath(project.resolve('markdown'))
     window.rootView = new RootView
     atom.activatePackage("markdown-preview", immediate: true)


fix debug log ordering

fix debug log ordering

--- server/utils/logging.coffee
+++ server/utils/logging.coffee
@@ -15,9 +15,10 @@
 lastLogs = new Array(15)
 lastDate = +new Date()
 index = -1
+MAX_INDEX = 15

 addToLastLogs = ->
-    index = (index + 1) % 15
+    index = (index + 1) % MAX_INDEX
     lastLogs[index] = util.format.apply this, arguments

 pad = (nb) ->
@@ -54,4 +55,5 @@
         error: logger 3

 module.exports.getLasts = ->
-    return lastLogs.join("\n")
+    return lastLogs[index+1..MAX_INDEX].join("\n") + "\n" +
+           lastLogs[0..index].join("\n")


utils: chmod -x

utils: chmod -x


Verifies Agda executable on Windows

Verifies Agda executable on Windows

--- lib/executable.coffee
+++ lib/executable.coffee
@@ -22,7 +22,7 @@
     validateExecutablePath: (path) -> new Promise (resolve, reject) =>
         command = path + ' -V'
         exec command, (error, stdout, stderr) =>
-            if /^Agda version/.test stdout
+            if /^Agda/.test stdout
                 resolve path
             else
                 reject new InvalidExecutablePathError error if error


[refactor] Extracted 'scoped' from 'Scheduler.Tickets' (10m)

--- app/assets/javascripts/houston-scheduler/models/ticket.coffee
+++ app/assets/javascripts/houston-scheduler/models/ticket.coffee
@@ -6,6 +6,7 @@
     effort = @tasks().reduce ((sum, task)-> sum + +task.get('effort')), 0
     if effort == 0 then null else effort
   estimated: -> @tasks().every (task)-> +task.get('effort') > 0
+  waitingForDiscussion: -> @get('unableToSetEstimatedEffort') or @get('unableToSetPriority')

   severity: ->
     seriousness = @get('seriousness')
@@ -77,38 +78,22 @@

   sorted: -> _.sortBy @withSequence(), (ticket)-> +ticket.get('sequence')
   withSequence: -> @select (ticket)-> !!ticket.get('sequence')
-  unresolved: -> new Scheduler.Tickets(@select (ticket)-> !ticket.get('resolved'))
+  unresolved: -> @scoped (ticket)-> !ticket.get('resolved')
   unsorted: -> @withoutSequence()
   withoutSequence: -> @select (ticket)-> !ticket.get('sequence')
   withoutMilestones: -> @select (ticket)-> !ticket.get('milestoneId')
-
-  bugs: ->
-    new Scheduler.Tickets(@select (ticket)-> ticket.get('type') == 'bug')
-
-  withoutEffortEstimate: ->
-    new Scheduler.Tickets(@select (ticket)-> !ticket.estimated())
-
-  withSeverityEstimate: ->
-    new Scheduler.Tickets(@select (ticket)-> console.log(ticket.severity()); !!ticket.severity())
-
-  withoutSeverityEstimate: ->
-    new Scheduler.Tickets(@select (ticket)-> !ticket.severity())
-
-  ableToPrioritize: ->
-    new Scheduler.Tickets(@select (ticket)-> !ticket.get('unableToSetPriority'))
-
-  ableToEstimate: ->
-    new Scheduler.Tickets(@select (ticket)-> !ticket.get('unableToSetEstimatedEffort'))
-
-  waitingForDiscussion: ->
-    new Scheduler.Tickets(@select (ticket)->
-      ticket.get('unableToSetEstimatedEffort') or ticket.get('unableToSetPriority'))
-
-  withBothEstimates: ->
-    @select (ticket)-> (+ticket.get('estimatedValue') > 0) && ticket.estimatedEffort() > 0
+  features: -> @scoped (ticket)-> ticket.get('type') == 'feature' || ticket.get('type') == 'enhancement'
+  bugs: -> @scoped (ticket)-> ticket.get('type') == 'bug'
+  withoutEffortEstimate: -> @scoped (ticket)-> !ticket.estimated()
+  withSeverityEstimate: -> @scoped (ticket)-> !!ticket.severity()
+  withoutSeverityEstimate: -> @scoped (ticket)-> !ticket.severity()
+  withValueEstimate: -> @scoped (ticket)-> !!ticket.value()
+  withoutValueEstimate: -> @scoped (ticket)-> !ticket.value()
+  ableToPrioritize: -> @scoped (ticket)-> !ticket.get('unableToSetPriority')
+  ableToEstimate: -> @scoped (ticket)-> !ticket.get('unableToSetEstimatedEffort')
+  waitingForDiscussion: -> @scoped (ticket)-> ticket.waitingForDiscussion()
+  postponed: -> @scoped (ticket)-> !!ticket.get('postponed')
+  unpostponed: -> @scoped (ticket)-> !ticket.get('postponed')

-  postponed: ->
-    new Scheduler.Tickets(@select (ticket)-> !!ticket.get('postponed'))

-  unpostponed: ->
-    new Scheduler.Tickets(@select (ticket)-> !ticket.get('postponed'))
+  scoped: (filter)-> new Scheduler.Tickets(@select(filter))


Revert "left and right were flipped"

Revert "left and right were flipped"

This reverts commit f68a51b486f660caabcaddec171dd8ef440778b8.

--- lib/gui/screen.coffee
+++ lib/gui/screen.coffee
@@ -31,8 +31,10 @@

   screen.key ['j'], (ch, key) -> walkDatIcon('top',  -1 * mapStepSize)
   screen.key ['k'], (ch, key) -> walkDatIcon('top',  mapStepSize)
-  screen.key ['h'], (ch, key) -> walkDatIcon('left', -1 * mapStepSize)
-  screen.key ['l'], (ch, key) -> walkDatIcon('left', mapStepSize)
+  screen.key ['l'], (ch, key) -> walkDatIcon('left', -1 * mapStepSize)
+  screen.key ['h'], (ch, key) -> walkDatIcon('left', mapStepSize)
+
+  mapScale = 1

   screen.key ['m'], (ch, key) ->
     map.show()


WIP: scroll entries to top of the list when opening

In particular, scroll entries even if they are one of the last of the
entries list. This will probably require adding blank space below.

--- app/assets/javascripts/ng-services/ng-AnimationsSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-AnimationsSvc.js.coffee
@@ -178,16 +178,23 @@
       entry_summary.css('height', 'auto')
       height_auto = entry_summary.outerHeight() + padding_top + padding_bottom

-      # Set height back to 0px and animate the transition to its final height
-      # After finishing opening animation, scroll to show as much of the entry content as possible.
-      # We leave an offset so that navbar doesn't overlap the entry.
+      # Set height back to 0px and scroll to show entry at the top of the list (without overlapping the navbar)
       entry_link = $("#entry-#{entry.id}-link")
       topOffset = -1 * ($("#navbar").height() + entry_link.outerHeight(true) + 2)
-
       entry_summary
         .css('height', '0')
-        .velocity 'scroll', {offset: topOffset, duration: 0}
-        .velocity({height: height_auto, 'padding-top': padding_top, 'padding-bottom': padding_bottom},
+        .velocity 'scroll', {offset: topOffset, duration: 0, complete: ()->
+          # If entry is not at the top of the entries list (e.g. it's one of the last elements of the list) add
+          # blank space below enough to put it at the top
+          #TODO not yet working as intended
+          if entry_link.offset().top - $(window).scrollTop() > $("#navbar").height() + 3
+            console.log "entry not at the top!"
+          else
+            console.log "everything OK"
+        }
+
+      # Animate the transition to its final height
+      entry_summary.velocity({height: height_auto, 'padding-top': padding_top, 'padding-bottom': padding_bottom},
           {duration: 200, easing: 'swing', complete: add_entry_open_class})

     #---------------------------------------------


Render moderators when cloud is changed.

--- app/assets/javascripts/views/clouds/settings_dialog.js.coffee
+++ app/assets/javascripts/views/clouds/settings_dialog.js.coffee
@@ -59,6 +59,7 @@
     @cloud.on 'change', (cloud) =>
       @.$('img.cloud-avatar').attr('src',cloud.get('avatar').normal)
       @.$('h2.cloud-name').text(cloud.get('name'))
+      @renderModerators()

     $("body").on "click.tab.data-api", "[data-toggle=\"tab\"], [data-toggle=\"pill\"]", (e) ->
       e.preventDefault()


Save action for new user

Save action for new user

--- assets/javascripts/controllers/users_new_controller.js.coffee
+++ assets/javascripts/controllers/users_new_controller.js.coffee
@@ -1,3 +1,14 @@
 App.UsersNewController = Em.Controller.extend
   needs: ["application"]
-  validRoles: ["admin", "member"]
+  validRoles: ["member", "admin"]
+
+  actions:
+    save: ->
+      userAttributes = @getProperties(["firstName", "lastName", "role", "password", "email"])
+
+      user = @store.createRecord("user", userAttributes)
+      console.log userAttributes
+      successCallback = =>
+        @transitionToRoute("users.index")
+      errorCallback = => console.log("error saving user")
+      user.save().then(successCallback, errorCallback)


Better error handling

Better error handling

--- src/commands/import.coffee
+++ src/commands/import.coffee
@@ -22,6 +22,10 @@
     @_validateOptions(@program)
     @_process(@program)

+  @_die: ->
+    log.error.apply(null, arguments)
+    process.exit(1)
+
   @_validateOptions: (options) ->
     errors = []
     errors.push('Missing required option: type') unless options.type
@@ -36,8 +40,7 @@
         service = new StockImport(log, {})
         @_stream(options, service, 'stocks.*')
       else
-        log.error "Unsupported type: #{type}"
-        process.exit(1)
+        @_die "Unsupported type: #{type}"

   @_stream: (options, service, jsonPath) ->
     inputStream = if options.from
@@ -48,8 +51,8 @@
       process.stdin.setEncoding('utf8')
       process.stdin

-    # TODO: error handling
     transformStream = _(inputStream.pipe(JSONStream.parse(jsonPath)))
+    .stopOnError (e) => @_die 'Cannot parse chunk as JSON', e
     .batch(options.batch)
     .pipe(transform (chunk, cb) ->
       log.info 'chunk: %j', chunk, {}
@@ -60,6 +63,7 @@
     # so that when we pull the value after that we know that all chunks have been processed
     # and we can display a final message
     _(transformStream).reduce null, -> ''
+    .stopOnError (e) => @_die 'Something went wrong while transforming chunks', e
     .pull (err, x) ->
       if err then log.error err
       else log.info service.summaryReport(options.from)


Use button authority

Use button authority

--- src/config/controls.coffee
+++ src/config/controls.coffee
@@ -43,6 +43,7 @@
     }
     {
       _LABEL: "game_actions"
+      _AUTHORITY: (world) -> world.get('BUTTON')
       _CHILDREN: [
         {_LABEL: "init"}
         {_LABEL: "restart"}
@@ -59,6 +60,7 @@
     }
     {
       _LABEL: "available_commands"
+      _AUTHORITY: (world) -> world.get('BUTTON')
       _CHILDREN: [
         {_LABEL: "left", col: 0}
         {_LABEL: "front", col: 1}


:bug: #204 mouseclick regex button not worked

--- lib/read-input.coffee
+++ lib/read-input.coffee
@@ -35,10 +35,10 @@
     editorContainer.appendChild(@editorElement)

     @useRegexButton = @container.getElementsByClassName('use-regex')[0]
-    @useRegexButton.addEventListener 'click', (event) ->
+    @useRegexButton.addEventListener 'click', (event) =>
       suppressEvent(event)
       @toggleUseRegex()
-    @editorElement.addEventListener('click', suppressEvent)
+    @container.addEventListener('click', suppressEvent)
     addToolTips(
       element: @useRegexButton
       commandName: 'narrow-input:toggle-use-regex'


Fixed linking on established connection.

--- app/assets/javascripts/seapig/seapig.js.coffee
+++ app/assets/javascripts/seapig/seapig.js.coffee
@@ -39,7 +39,7 @@

         link: (object_id) ->
-                @socket.send(JSON.stringify(action: 'link', id: object_id, latest_known_version: object.version)) if @connected
+                @socket.send(JSON.stringify(action: 'link', id: object_id, latest_known_version: null)) if @connected
                 @objects[object_id] = new SeaPigObject(object_id)


fix channel setting

fix channel setting

--- packages/rocketchat-channel-settings/client/views/channelSettings.coffee
+++ packages/rocketchat-channel-settings/client/views/channelSettings.coffee
@@ -99,8 +99,6 @@
 	'click .edit': (e, t) ->
 		e.preventDefault()
 		room_info = ChatRoom.findOne(@rid)
-		console.log room_info
-		console.log this
 		if room_info.t != "d"
 			window.open ChatRoom.findOne(@rid).details.url
 		else
@@ -108,7 +106,8 @@

 	'click #open_profile' : (e,t) ->
 		e.preventDefault()
-		window.open 'https://stage.ubegin.com/discover/people/'+this.userDetail
+		room_info = ChatRoom.findOne(@rid)
+		window.open 'https://stage.ubegin.com/discover/project/'+room_info.name

 Template.channelSettings.onCreated ->
 	@editing = new ReactiveVar


Only show context menu in editor

Only show context menu in editor

--- menus/edit.cson
+++ menus/edit.cson
@@ -19,7 +19,7 @@
   }
 ]
 'context-menu':
-  'atom-workspace': [
+  'atom-text-editor': [
     {
       label: 'Reformat JSX'
       command: 'react:reformat-JSX'


change feature table

change feature table

--- js/inner/content.coffee
+++ js/inner/content.coffee
@@ -1,18 +1,20 @@
 CI.content = {}
 CI.content.pricing_features = [
   {
-    headline: "Email support",
-    detail: "You email us your question, we email you back. Simple as that."
+    headline: "Unlimited Private Repositories",
+    detail: "No repo limits, follow as many as you like."
   },
   {
-    headline: "Immediate support",
-    detail: "We respond to support requests immediately, every day (yes, on weekends and holidays). Most requests are responded to within the hour, 99% are responded to in 12 hours. We're also available for live chat support.",
-    name: "fast-support"
+    headline: "Unlimited parallelism",
+    detail: "Subject to number of containers. ex. if you have 6 containers you can run up to 6x parallelism."
   },
   {
-    headline: "Phone Support",
-    detail: "Our phone number is +1 415 341 2432. No-one ever calls because our email support is so good. But in theory, if you called, we'd answer. Try it.",
-    name: "phone"
+    headline: "Unlimited collaborators",
+    detail: "Invite as many members of your team as you want to use CircleCI with you, we never limit your users."
+  },
+  {
+    headline: "Phenomenal support",
+    detail: "We respond to support requests immediately, every day (yes, on weekends and holidays). Most requests are responded to within the hour, 99% are responded to in 12 hours. We're also available for live chat support."
   },
   {
     headline: "Custom NDA",
@@ -20,8 +22,23 @@
     name: "nda"
   },
   {
-    headline: "Predictable pricing",
-    detail: "Our pricing is the same every month, no matter how often you push. There are no charges for using machine time."
+    headline: "Service-level agreements",
+    detail: "If you require a service contract we're happy to provide it.",
+    name: "nda"
+  },
+  {
+  headline: "Amazon VPC support",
+  detail: "CircleCI allows you to run your builds on your own Amazon Virtual Private Cloud.",
+  name: "nda"
+  },
+  {
+  headline: "Data retention",
+  detail: "Retain long-term build data and logs.",
+  name: "nda"
+  },
+  {
+    headline: "Scaleable and transparent pricing",
+    detail: "Our pricing is container based, allowing you add as many containers as you need for $50/each. There are no charges for using machine time."
   },
   {
     headline: "Unlimited builds",


removing unused variable

removing unused variable

--- src/components/task-plan/homework.cjsx
+++ src/components/task-plan/homework.cjsx
@@ -330,7 +330,6 @@
     if plan?.due_at
       dueAt = new Date(plan.due_at)

-    today = new Date(plan.due_at)
     footer = <PlanFooter id={id} courseId={courseId} clickedSelectProblem={@showSectionTopics}/>

     formClasses = ['create-homework']


Better error handling

Better error handling

--- js/hocr-reader.coffee
+++ js/hocr-reader.coffee
@@ -80,38 +80,50 @@
     $(document.body).append(container)
     repo = github.getRepo(req.params['github_user'],req.params['github_repo'])
     repo.getTree 'master', (err, tree) ->
+      if err
+        $('.content').append($('<h1>').text('Error retrieving repository contents'))
+        $('.content').append($('<p>').append($('<a>').attr('href',"https://github.com/#{req.params['github_user']}/#{req.params['github_repo']}/").text('View Repository on GitHub')))
       book = _.filter(tree, (node) -> (node.type == 'tree' && node.path.match(/\.book$/)))[0]
       if book
         repo.getTree book.sha, (err, book_tree) ->
           all_pages = _.filter(book_tree, (node) -> node.path.match(new RegExp("^p[0-9]+\.html$")))
-          make_nav_bar(req.params['github_user'],req.params['github_repo'],parseInt(page),all_pages.length)
-          page_image = _.filter(book_tree, (node) -> node.path.match(new RegExp("^i#{page}\.jpg$")))[0]
-          page_hocr = _.filter(book_tree, (node) -> node.path.match(new RegExp("^p#{page}\.html$")))[0]
-          console.log page_image
-          $('.content').append($('<div>').attr('id','page_image'))
-          $('.content').append($('<div>').attr('id','page_right'))
-          $.ajax page_image.url + (if get_cookie('access_token') then "?access_token=#{get_cookie('access_token')}" else ''),
-            type: 'GET'
-            dataType: 'json'
-            crossDomain: 'true'
-            error: (jqXHR, textStatus, errorThrown) ->
-              console.log "Image fetch error: #{textStatus}"
-            success: (data) ->
-              $('#page_image').append($('<img>').attr('style','width:100%').attr('src','data:image/jpeg;charset=utf-8;base64,'+data.content))
-          console.log page_hocr
-          $.ajax page_hocr.url + (if get_cookie('access_token') then "?access_token=#{get_cookie('access_token')}" else ''),
-            type: 'GET'
-            dataType: 'json'
-            crossDomain: 'true'
-            error: (jqXHR, textStatus, errorThrown) ->
-              console.log "hOCR fetch error: #{textStatus}"
-            success: (data) ->
-              hocr_html = atob(decodeURIComponent(escape(data.content.replace(/\s/g, ""))))
-              css_rewrite = if hocr_html.match('<link')
-                hocr_html.replace('http://heml.mta.ca/Rigaudon/hocr.css','{{ site.url }}/hocr.css')
-              else
-                hocr_html.replace('<head>',"<head>\n<link rel='stylesheet' type='text/css' href='{{ site.url }}/hocr.css'>")
-              $('#page_right').append($('<iframe>').attr('style','width:100%').attr('height','800').attr('frameBorder','0').attr('src','data:text/html;charset=utf-8;base64,'+btoa(css_rewrite)))
+          if all_pages.length == 0
+            $('.content').append($('<h1>').text('No pages found for book :('))
+            $('.content').append($('<p>').append($('<a>').attr('href',"https://github.com/#{req.params['github_user']}/#{req.params['github_repo']}/").text('View Repository on GitHub')))
+          else
+            make_nav_bar(req.params['github_user'],req.params['github_repo'],parseInt(page),all_pages.length)
+            page_image = _.filter(book_tree, (node) -> node.path.match(new RegExp("^i#{page}\.jpg$")))[0]
+            page_hocr = _.filter(book_tree, (node) -> node.path.match(new RegExp("^p#{page}\.html$")))[0]
+            console.log page_image
+            $('.content').append($('<div>').attr('id','page_image'))
+            $('.content').append($('<div>').attr('id','page_right'))
+            if page_image
+              $.ajax page_image.url + (if get_cookie('access_token') then "?access_token=#{get_cookie('access_token')}" else ''),
+                type: 'GET'
+                dataType: 'json'
+                crossDomain: 'true'
+                error: (jqXHR, textStatus, errorThrown) ->
+                  console.log "Image fetch error: #{textStatus}"
+                success: (data) ->
+                  $('#page_image').append($('<img>').attr('style','width:100%').attr('src','data:image/jpeg;charset=utf-8;base64,'+data.content))
+            else
+              $('#page_image').append($('<h2>').text('Page image not found'))
+            if page_hocr
+              $.ajax page_hocr.url + (if get_cookie('access_token') then "?access_token=#{get_cookie('access_token')}" else ''),
+                type: 'GET'
+                dataType: 'json'
+                crossDomain: 'true'
+                error: (jqXHR, textStatus, errorThrown) ->
+                  console.log "hOCR fetch error: #{textStatus}"
+                success: (data) ->
+                  hocr_html = atob(decodeURIComponent(escape(data.content.replace(/\s/g, ""))))
+                  css_rewrite = if hocr_html.match('<link')
+                    hocr_html.replace('http://heml.mta.ca/Rigaudon/hocr.css','{{ site.url }}/hocr.css')
+                  else
+                    hocr_html.replace('<head>',"<head>\n<link rel='stylesheet' type='text/css' href='{{ site.url }}/hocr.css'>")
+                  $('#page_right').append($('<iframe>').attr('style','width:100%').attr('height','800').attr('frameBorder','0').attr('src','data:text/html;charset=utf-8;base64,'+btoa(css_rewrite)))
+            else
+              $('#page_right').append($('<h2>').text('Page hOCR not found'))

 hocr_reader = (req) ->
   check_rate_limit(hocr_handler, req)


update daniel's bios with recent revisions (remove YC line)

--- js/outer/about.coffee
+++ js/outer/about.coffee
@@ -58,7 +58,7 @@
       email: "daniel@circleci.com"
       bio: [
         "Despite all our coercions, promises, bribes, and outright threats for nearly a year, it took us putting Daniel in a time-out and forcing him to type things about himself to get a bio out of him. He doesn't really have any hobbies: if he's doing something, it's usually either reading romantic fiction (not to be confused with romance novels!), coding, or binge-watching episodes of tv-show-he-just-discovered-that-is-so-awesome-he-can't-put-it-down. One of his first programming projects was an app written in Python that creates an exact replica of an image using only html tables. It's been almost 2 years since he last touched the thing, and it's still cranking out tables. He's only been rejected from YCombinator 3 times, which is empirically below the threshold of consolation prizes.",
-        "Daniel has a bachelors degree in Math from Texas A&M. He has written an app to graph Kickstarter projects, and was a customer (the 155th!) before he joined the Circle team. He looks forward to helping increase the 'wow, I can do something cool with this!' feeling that users get when they use Circle, and has been tinkering with a few things recently to make that possible--a native websockets library so that our output feels more like you're directly connected to a terminal and hooking in something like jquery.terminal so that you actually can be directly connected to a terminal. He currently helps feed his movie habit by helping organize weekly movie nights at the office. Next up: Fight Club."
+        "Daniel has a bachelors degree in Math from Texas A&M. He has written an app to graph Kickstarter projects, and was a customer (the 155th!) before he joined the Circle team. He looks forward to helping increase the 'wow, I can do something cool with this!' feeling that users get when they use Circle, and has been tinkering with a few things recently to make that possible. He currently helps feed his movie habit by helping organize weekly movie nights at the office. Next up: Cyrano de Bergerac."
       ]
     ,
       name: "Mahmood Ali"


improved gulp build

improved gulp build

--- app/templates/browser/_gulpfile.coffee
+++ app/templates/browser/_gulpfile.coffee
@@ -35,10 +35,10 @@
 gulp.task 'browserify', ->
   browserify
       extensions: ['.coffee', '.js']
-    .transform coffeeify
+    .transform coffeeify, global: true
     .require(src.main, { expose: module.shortcut})
     .ignore('coffee-script')
-    .bundle()
+    .bundle().on('error', gutil.log)
   .pipe source module.filename
   .pipe buffer()
   .pipe uglify()


ComputeProvider: create default workspace on machine create

Fixes the blank page issue on first load for members after registration

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -16,8 +16,8 @@

   {permit} = require '../group/permissionset'

-  JMachine = require './machine'
-  JProposedDomain  = require '../domain'
+  JMachine   = require './machine'
+  JWorkspace = require '../workspace'

   @share()

@@ -255,7 +255,15 @@
           create = (machineInfo) ->
             ComputeProvider.create client, machineInfo, (err, machine) ->
               results.machines.push { err, obj: machine }
-              queue.next()
+
+              # Create default workspace for the machine
+              JWorkspace.createDefault client, machine.uid, (err) ->
+
+                if err
+                  console.log \
+                    'Failed to create default workspace', machine.uid, err
+
+                queue.next()

           # This is optional, since for koding group for example
           # we don't want to add our admins into users machines ~ GG


Improved the comment marker test to expect a result different from what it was without the comment marker check.

--- spec/ExifReader.spec.coffee
+++ spec/ExifReader.spec.coffee
@@ -149,8 +149,9 @@
     #expect(@exif._tiffHeaderOffset).toEqual 39

   it 'should handle IPTC Comment markers', ->
-    @exif._dataView = getDataView '\xff\xd8\xff\xfe\x00+Optimized by JPEGmin'
-    @exif._checkImageHeader()
+    @exif._dataView = getDataView '\xff\xd8\xff\xe0\x00\x07JFIF\x00\xff\xfe\x00\x2bOptimized by JPEGmin\x00'
+    appMarkers = @exif._checkImageHeader()
+    expect(appMarkers.length).toBeGreaterThan(1);

   it 'should fail gracefully for faulty APP markers', ->
     exif = @exif


Don't require space-pen through atom in spec

--- spec/status-bar-spec.coffee
+++ spec/status-bar-spec.coffee
@@ -1,14 +1,16 @@
-{$$, WorkspaceView} = require 'atom'
+{WorkspaceView} = require 'atom'
 fs = require 'fs-plus'
 path = require 'path'
 os = require 'os'

 describe "Status Bar package", ->
-  [editor, editorView, statusBar, buffer, workspaceElement] = []
+  [editor, editorView, statusBar, buffer, workspaceElement, dummyView] = []

   beforeEach ->
     workspaceElement = atom.views.getView(atom.workspace)
     atom.workspaceView = new WorkspaceView
+
+    dummyView = document.createElement("div")

     waitsForPromise ->
       atom.workspace.open('sample.js')
@@ -185,8 +187,7 @@
         expect(statusBar.git.branchArea).toBeVisible()
         expect(statusBar.git.branchLabel.textContent).toBe 'master'

-      view = $$ -> @div id: 'view', tabindex: -1, 'View'
-      atom.workspaceView.getActivePaneView().activateItem(view)
+      atom.workspaceView.getActivePaneView().activateItem(dummyView)
       expect(statusBar.git.branchArea).not.toBeVisible()

     it "doesn't display the current branch for a file not in a repository", ->
@@ -302,37 +303,33 @@
   describe "when the active item view does not implement getCursorBufferPosition()", ->
     it "hides the cursor position view", ->
       atom.workspaceView.attachToDom()
-      view = $$ -> @div id: 'view', tabindex: -1, 'View'
-      editorView.getPane().activateItem(view)
+      editorView.getPane().activateItem(dummyView)
       expect(statusBar.cursorPosition).toBeHidden()

   describe "when the active item implements getTitle() but not getPath()", ->
     it "displays the title", ->
       atom.workspaceView.attachToDom()
-      view = $$ -> @div id: 'view', tabindex: -1, 'View'
-      view.getTitle = => 'View Title'
-      editorView.getPane().activateItem(view)
+      dummyView.getTitle = => 'View Title'
+      editorView.getPane().activateItem(dummyView)
       expect(statusBar.fileInfo.currentPath.textContent).toBe 'View Title'
       expect(statusBar.fileInfo.currentPath).toBeVisible()

   describe "when the active item neither getTitle() nor getPath()", ->
     it "hides the path view", ->
       atom.workspaceView.attachToDom()
-      view = $$ -> @div id: 'view', tabindex: -1, 'View'
-      editorView.getPane().activateItem(view)
+      editorView.getPane().activateItem(dummyView)
       expect(statusBar.fileInfo.currentPath).toBeHidden()

   describe "when the active item's title changes", ->
     it "updates the path view with the new title", ->
       atom.workspaceView.attachToDom()
       callbacks = []
-      view = $$ -> @div id: 'view', tabindex: -1, 'View'
-      view.onDidChangeTitle = (fn) ->
+      dummyView.onDidChangeTitle = (fn) ->
         callbacks.push(fn)
         {dispose: ->}
-      view.getTitle = => 'View Title'
-      editorView.getPane().activateItem(view)
+      dummyView.getTitle = -> 'View Title'
+      editorView.getPane().activateItem(dummyView)
       expect(statusBar.fileInfo.currentPath.textContent).toBe 'View Title'
-      view.getTitle = => 'New Title'
+      dummyView.getTitle = -> 'New Title'
       callback() for callback in callbacks
       expect(statusBar.fileInfo.currentPath.textContent).toBe 'New Title'


:green_heart: Add more error tolerance in edit tests

--- spec/table-view-spec.coffee
+++ spec/table-view-spec.coffee
@@ -557,10 +557,10 @@
       editorOffset = editor.offset()

       expect(editor.length).toEqual(1)
-      expect(editorOffset.top).toBeCloseTo(cellOffset.top, -1)
-      expect(editorOffset.left).toBeCloseTo(cellOffset.left, -1)
-      expect(editor.outerWidth()).toBeCloseTo(cell.outerWidth(), -1)
-      expect(editor.outerHeight()).toBeCloseTo(cell.outerHeight(), -1)
+      expect(editorOffset.top).toBeCloseTo(cellOffset.top, -2)
+      expect(editorOffset.left).toBeCloseTo(cellOffset.left, -2)
+      expect(editor.outerWidth()).toBeCloseTo(cell.outerWidth(), -2)
+      expect(editor.outerHeight()).toBeCloseTo(cell.outerHeight(), -2)

     it 'gives the focus to the editor', ->
       expect(editor.is('.is-focused')).toBeTruthy()


update doc template

update doc template

--- plugins/fed_doc/lib/dataHelper.coffee
+++ plugins/fed_doc/lib/dataHelper.coffee
@@ -7,6 +7,17 @@
 fs = require "fs"
 path = require "path"
 parser = require "./parserHelper"
+
+
+getDataList = (tpath, basePath)->
+	result = []
+	if not basePath
+		packageName = path.basename basePath
+	else
+		packageName = tpath.replace basePath, ""
+	list = fs.readdirSync tpath
+	for f in list
+		file = path.join tpath, f

 # Get list of all files under `basePath`
 # all item is absoulte path


1 -> 0

1 -> 0

--- apps/artwork/test/artwork_rails.coffee
+++ apps/artwork/test/artwork_rails.coffee
@@ -183,7 +183,7 @@
       @rails.fetch().then (response) ->
         response.artwork._id.should.eql '54c2f01972616916df110900'
         _.keys(response.rails).length.should.eql 3
-        _.keys(response.rails)[1].should.eql 'current_auction_artworks'
+        _.keys(response.rails)[0].should.eql 'current_auction_artworks'
         _.keys(response.rails)[1].should.eql 'artist_artworks'
         done()
       .catch done


added Billing.call and Billing.getResults to work with iron-router

--- client/billing.coffee
+++ client/billing.coffee
@@ -1,3 +1,18 @@
+Result = ->
+  _dep: new Deps.Dependency
+  _val: null
+  _hasRun: false
+
+  _get: ->
+    @_dep.depend()
+    @_val
+
+  _set: (val) ->
+    unless EJSON.equals @_val, val
+      @_val = val
+      @_dep.changed()
+
+
 @Billing =
   settings: {}
   config: (opts) ->
@@ -23,6 +38,32 @@
       cvc: $form.find('[name=cc-cvc]').val()
     , callback) # callback(status, response)

+  _results: {}
+
+  getResults: (methodName) ->
+    unless @_results[methodName]
+      @_results[methodName] = new Result
+
+    res = @_results[methodName]._get()
+    if res then @_results[methodName] = null
+    res
+
+  call: (methodName, params) ->
+    results = @_results
+
+    unless results[methodName]
+      results[methodName] = new Result
+
+    unless results[methodName]._hasRun
+      results[methodName]._hasRun = true
+      args = Array.prototype.splice.call arguments, 1
+      Meteor.apply methodName, args, (err, res) ->
+        results[methodName]._set res
+
+    ready: ->
+      res = results[methodName]._get()
+      if res then true else false
+

 Meteor.startup ->
   Meteor.subscribe 'currentUser'


--- client/message.coffee
+++ client/message.coffee
@@ -614,6 +614,7 @@
               .replace /<\/(p|li)>/ig, ''
               .replace /(<li[^<>]*>)<p>/ig, '$1'
               .replace /<(li|ul|\/ul|br|p)\b/ig, '\n$&'
+              .replace /"/ig, '"'
               if match = /^\s*<pre[^<>]*>([^]*)<\/pre>\s*$/.exec paste
                 paste = match[1].split /\r\n?|\n/
               else


fixed: addition of data attr 'data-wh-current-section' changed from $.prop to $.attr (angularjs doesn't have it?)

--- app/scripts/directives/scroll-directive.coffee
+++ app/scripts/directives/scroll-directive.coffee
@@ -103,7 +103,7 @@

                 lastCurrentId = currentId
                 scope.setHeaderCurrentOption headerOpt
-                $html.prop 'data-wh-current-section', headerOpt.id
+                $html.attr 'data-wh-current-section', headerOpt.id
               break

   .directive 'spyCurrentSection', ->


rename private members so they're less visible

--- lib/dispatcher.coffee
+++ lib/dispatcher.coffee
@@ -12,209 +12,208 @@

   # Initializer
   constructor: (@options) ->
-    @test_mode = @options.test_mode
-    @verbose = @options.verbose
-    @idle_timeout = @options.idle_timeout ? (if @test_mode then 500 else 10000)
-    @audit_stream = @options.audit
-    @db = db @options.db_index
-    @req = db @options.db_index
-    @res = db @options.db_index
-    @control_channel = _('control').namespace @options.db_index
-    @count = {}
-    @state = {}
     @deps = {}
-    @cycles = {}
-    @unmet = 0
+    @_db = db @options.db_index
+    @_req = db @options.db_index
+    @_res = db @options.db_index
+    @_test_mode = @options.test_mode
+    @_verbose = @options.verbose
+    @_idle_timeout = @options.idle_timeout ? (if @_test_mode then 500 else 10000)
+    @_audit_stream = @options.audit
+    @_control_channel = _('control').namespace @options.db_index
+    @_count = {}
+    @_state = {}
+    @_cycles = {}
+    @_unmet = 0

   # Subscribe to the `requests` and `responses` channels.
   listen: ->
-    @req.on 'message', (ch, str) => @requested str
-    @res.on 'message', (ch, str) => @responded str
-    @req.subscribe _('requests').namespace(@options.db_index)
-    @res.subscribe _('responses').namespace(@options.db_index)
-
+    @_req.on 'message', (ch, str) => @_requested str
+    @_res.on 'message', (ch, str) => @_responded str
+    @_req.subscribe _('requests').namespace(@options.db_index)
+    @_res.subscribe _('responses').namespace(@options.db_index)
+
+  # Send quit signals to the work queues.
+  quit: ->
+    @_clear_timeout()
+    @_db.publish @_control_channel, 'quit'
+    finish = =>
+      @_db.del 'jobs'
+      @_req.end()
+      @_res.end()
+      @_db.end()
+    setTimeout finish, 500
+
+  # Provide a callback to be called when the dispatcher detects the process is stuck
+  on_stuck: (callback) ->
+    @_stuck_callback = callback
+    this
+
+  # Set the idle handler
+  on_idle: (@_idle_handler) -> this
+
+  # Forget everything we know about dependency state.
+  _reset: ->
+    @_count = {}
+    @_state = {}
+    @deps = {}
+    @_db.publish @_control_channel, 'reset'
+
+  # Print a debugging statement
+  _debug: (args...) ->
+    #console.log 'dispatcher:', args...
+
+  # Write text to the audit stream
+  _audit: (text) ->
+    #console.log text
+    @_audit_stream.write "#{text}\n" if @_audit_stream
+
+  # The given key is a 'seed' request. In test mode, completion of
+  # the seed request signals termination of the workers.
+  _seed: (key) ->
+    @_seed_key = key
+    @_new_request '!seed', [key]
+
   # Called when a worker requests keys. The keys requested are
   # recorded as dependencies, and any new key requests are
   # turned into new jobs. You can request the key `!reset` in
   # order to flush the dependency graph.
-  requested: (str) ->
+  _requested: (str) ->
     [source, keys...] = str.split consts.key_sep
     if keys.length
-      @audit "?#{str}"
-      @new_request source, keys
+      @_audit "?#{str}"
+      @_new_request source, keys
     else if source == '!reset'
-      @reset()
-    else
-      @seed source
-
-  # Forget everything we know about dependency state.
-  reset: ->
-    @count = {}
-    @state = {}
-    @deps = {}
-    @db.publish @control_channel, 'reset'
-
-  # Print a debugging statement
-  debug: (args...) ->
-    #console.log 'dispatcher:', args...
-
+      @_reset()
+    else
+      @_seed source
+
   # Called when a key is completed. Any jobs depending on this
   # key are updated, and if they have no more dependencies, are
   # signalled to run again.
-  responded: (key) ->
-    @audit "!#{key}"
-    @state[key] = 'done'
+  _responded: (key) ->
+    @_audit "!#{key}"
+    @_state[key] = 'done'
     targets = @deps[key] ? []
     delete @deps[key]
-    @progress targets
-
-  # Write text to the audit stream
-  audit: (text) ->
-    #console.log text
-    @audit_stream.write "#{text}\n" if @audit_stream
-
-  # The given key is a 'seed' request. In test mode, completion of
-  # the seed request signals termination of the workers.
-  seed: (key) ->
-    @_seed = key
-    @new_request '!seed', [key]
-
+    @_progress targets
+
   # The seed request was completed. In test mode, quit the workers.
-  unseed: ->
-    @clear_timeout()
-    @quit() if @test_mode
-
-  # Send quit signals to the work queues.
-  quit: ->
-    @clear_timeout()
-    @db.publish @control_channel, 'quit'
-    finish = =>
-      @db.del 'jobs'
-      @req.end()
-      @res.end()
-      @db.end()
-    setTimeout finish, 500
+  _unseed: ->
+    @_clear_timeout()
+    @quit() if @_test_mode

   # Make progress on each of the given keys by decrementing
   # their count of remaining dependencies. When any reaches
   # zero, it is rescheduled.
-  progress: (keys) ->
+  _progress: (keys) ->
     for key in keys
-      @unmet--
-      unless --@count[key]
-        @reschedule key
-
-  # Set the idle handler
-  on_idle: (@idle_handler) -> this
-
+      @_unmet--
+      unless --@_count[key]
+        @_reschedule key
+
   # Clear the timeout for idling
-  clear_timeout: ->
-    clearTimeout @timeout
+  _clear_timeout: ->
+    clearTimeout @_timeout

   # Reset the timer that checks if the process is broken
-  reset_timeout: ->
-    @clear_timeout()
-    @timeout = setTimeout (=> @idle()), @idle_timeout
+  _reset_timeout: ->
+    @_clear_timeout()
+    @_timeout = setTimeout (=> @_idle()), @_idle_timeout

   # Activate a handler for idle timeouts. By default, this means
   # calling the doctor.
-  idle: ->
-    if @idle_handler
-      @idle_handler()
-    else
-      @call_doctor()
+  _idle: ->
+    if @_idle_handler
+      @_idle_handler()
+    else
+      @_call_doctor()

   # Let the doctor figure out what's wrong here
-  call_doctor: ->
-    console.log "Oops... calling the doctor!" if @verbose
-    @doc ?= new Doctor @deps, @state, @_seed
+  _call_doctor: ->
+    console.log "Oops... calling the doctor!" if @_verbose
+    @doc ?= new Doctor @deps, @_state, @_seed_key
     @doc.diagnose()
     if @doc.is_stuck()
-      @doc.report() if @verbose
-      @recover()
-    else
-      console.log "Hmm, the doctor couldn't find anything amiss..." if @verbose
+      @doc.report() if @_verbose
+      @_recover()
+    else
+      console.log "Hmm, the doctor couldn't find anything amiss..." if @_verbose

   # Recover from a stuck process.
-  recover: ->
+  _recover: ->
     if @doc.recoverable()
       for cycle in @doc.cycles
-        return @fail_recovery() if @seen_cycle cycle
+        return @_fail_recovery() if @_seen_cycle cycle
       for key, deps of @doc.cycle_dependencies()
-        @signal_worker_of_cycles key, deps
-    else
-      @fail_recovery()
+        @_signal_worker_of_cycles key, deps
+    else
+      @_fail_recovery()

   # Determine if we've seen this cycle before
-  seen_cycle: (cycle) ->
+  _seen_cycle: (cycle) ->
     key = cycle.sort().join()
-    return true if @cycles[key]
-    @cycles[key] = true
+    return true if @_cycles[key]
+    @_cycles[key] = true
     false

   # Tell the given worker that they have cycle dependencies.
-  signal_worker_of_cycles: (key, deps) ->
-    @remove_dependencies key, deps
+  _signal_worker_of_cycles: (key, deps) ->
+    @_remove_dependencies key, deps
     msg = ['cycle', key, deps...].join consts.key_sep
-    @db.publish @control_channel, msg
+    @_db.publish @_control_channel, msg

   # Remove given dependencies from the key
-  remove_dependencies: (key, deps) ->
-    @count[key] -= deps.length
+  _remove_dependencies: (key, deps) ->
+    @_count[key] -= deps.length
     @deps[dep] = _.without @deps[dep], key for dep in deps

   # Recovery failed, let the callback know about it.
-  fail_recovery: ->
-    @stuck_callback?(@doc, @db)
+  _fail_recovery: ->
+    @_stuck_callback?(@doc, @_db)

   # Signal a job to run again by sending a resume message
-  reschedule: (key) ->
-    delete @count[key]
-    return @unseed() if key == '!seed'
-    return if @state[key] == 'done'
-    @db.publish @control_channel, "resume#{consts.key_sep}#{key}"
+  _reschedule: (key) ->
+    delete @_count[key]
+    return @_unseed() if key == '!seed'
+    return if @_state[key] == 'done'
+    @_db.publish @_control_channel, "resume#{consts.key_sep}#{key}"

   # Handle a request we've never seen before from a given source
   # job that depends on the given keys.
-  new_request: (source, keys) ->
-    @reqs = []
-    @reset_timeout()
-    @count[source] = 0
-    @handle_request source, keys
+  _new_request: (source, keys) ->
+    @_reqs = []
+    @_reset_timeout()
+    @_count[source] = 0
+    @_handle_request source, keys

   # Handle the requested keys by marking them as dependencies
   # and turning any unsatisfied ones into new jobs.
-  handle_request: (source, keys) ->
+  _handle_request: (source, keys) ->
     for key in _.uniq keys
-      @mark_dependency source, key
-    if @count[source]
-      @request_dependencies()
-    else
-      @reschedule source
+      @_mark_dependency source, key
+    if @_count[source]
+      @_request_dependencies()
+    else
+      @_reschedule source

   # Mark the key as a dependency of the given source job. If
   # the key is already completed, then do nothing; if it has
   # not been previously requested, create a new job for it.
-  mark_dependency: (source, key) ->
-    switch @state[key]
+  _mark_dependency: (source, key) ->
+    switch @_state[key]
       when 'done' then return
-      when undefined then @reqs.push key
+      when undefined then @_reqs.push key
     (@deps[key] ?= []).push source
-    @unmet++
-    @count[source]++
+    @_unmet++
+    @_count[source]++

   # Take the unmet dependencies from the latest request and push
   # them onto the `jobs` queue.
-  request_dependencies: ->
-    for req in @reqs
-      @state[req] = 'wait'
-      @db.rpush 'jobs', req
-
-  # Provide a callback to be called when the dispatcher detects the process is stuck
-  on_stuck: (callback) ->
-    @stuck_callback = callback
-    this
-
+  _request_dependencies: ->
+    for req in @_reqs
+      @_state[req] = 'wait'
+      @_db.rpush 'jobs', req

 module.exports =


array_extensions

--- src/array_extensions.coffee
+++ src/array_extensions.coffee
@@ -352,15 +352,13 @@
 Returns the last element of the array, undefined if the array is empty.

-   ["first", "second", "third"].last()
-=> "third"
+["first", "second", "third"].last()
+# => "third"

 @name last
 @methodOf Array#
-
-@returns The last element, or undefined if the array is empty.
-@type Object
+@returns {Object} The last element, or undefined if the array is empty.
 ###
 Array::last = ->
   this[this.length - 1]


Remove object keys projection for list view

--- coffee/turbase.coffee
+++ coffee/turbase.coffee
@@ -50,7 +50,7 @@

     # @TODO add endret paramter
     # @TODO add support for queries
-    collection.find(query,{eier:1,navn:1,endret:1},opts).toArray (err, result) ->
+    collection.find(query,{},opts).toArray (err, result) ->
         # @TODO move to propper error handling
         return res.jsonp err if err
         return res.jsonp documents: result, count: result.length if result


Teamwork: Toggling for playgrounds manifest file in for localhost and prod.

--- client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
+++ client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
@@ -1,4 +1,7 @@
 class TeamworkApp extends KDObject
+
+  filename            = if location.hostname is "localhost" then "manifest-dev" else "manifest"
+  playgroundsManifest = "https://raw.github.com/koding/Teamwork/master/Playgrounds/#{filename}.json"

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


formatYear

formatYear

--- models/fair.coffee
+++ models/fair.coffee
@@ -41,6 +41,9 @@

   formatLocation: ->
     @location()?.get('city')
+
+  formatYear: ->
+    moment(@get('start_at')).year()

   formatDates: ->
     DateHelpers.timespanInWords @get('start_at'), @get('end_at')


unique team name validation

unique team name validation

--- models/team.coffee
+++ models/team.coffee
@@ -10,6 +10,7 @@
   name:
     type: String
     required: true
+    unique: true
   emails:
     type: [ mongoose.SchemaTypes.Email ]
     validate: [ ((v) -> v.length <= 4), 'max' ]
@@ -37,6 +38,11 @@
     max = 225 + 1 # +1 because team fortnight labs doesn't count
     next null, count < max, max - count

+TeamSchema.static 'uniqueName', (name, next) ->
+  Team.count { name: name }, (err, count) ->
+    return next err if err
+    next null, !count
+
 # min people validation
 TeamSchema.pre 'save', (next) ->
   if @people_ids.length + @emails.length == 0
@@ -58,6 +64,18 @@
       error.errors._base = 'max'
       next error

+# unique name
+TeamSchema.pre 'save', (next) ->
+  return next() unless @isNew
+  Team.uniqueName @name, (err, yeah) =>
+    return next err if err
+    if yeah
+      next()
+    else
+      error = new mongoose.Document.ValidationError this
+      error.errors.name = 'unique'
+      next error
+
 # create invites
 TeamSchema.pre 'save', (next) ->
   for email in @emails


popularity score from percentile not percentage   #181

--- models/team.coffee
+++ models/team.coffee
@@ -77,7 +77,7 @@
   Team.find { 'entry.votable': true, lastDeploy: {$ne:null} }, {}, {sort: [['scores.overall', -1]]}, (error,teams) ->
     return next error if error
     next null, teams
-
+
 TeamSchema.static 'updateAllSavedScores', (next) ->
   map = ->
     ret =
@@ -108,7 +108,7 @@
       for field of ret
         ret[ field ] += val[ field ]
     ret
-
+
   finalize = (key,val) ->
     ret = {}
     [ 'contestant_utility', 'contestant_design', 'contestant_innovation', 'contestant_completeness' ].forEach (field) ->
@@ -125,24 +125,29 @@
     ret[ 'judge_count' ] = val.judge_count
     ret[ 'popularity_count' ] = val.popularity_count
     ret
-
+
   mrCommand =
     mapreduce:'votes'
     map:map.toString()
     reduce:reduce.toString()
     finalize:finalize.toString()
     out:{inline:1}
-
+
   mongoose.connection.db.executeDbCommand mrCommand, (err,result) ->
     if err or not result.documents[0].ok
       console.log err
       console.log result
       return next [err,result]
-
-    max_popularity_count = 0
+
     computedScores = result.documents[0].results
-    computedScores.forEach (computedScore) ->
-      max_popularity_count = Math.max max_popularity_count, computedScore.value.popularity_count
+
+    popularities = _.uniq computedScores.map((s) -> s.value.popularity_count).sort((a, b) -> a - b)
+    popularityRanks = {}
+    popularityCount = popularities.length
+    for p, rank in popularities
+      popularityRanks[p] = rank / (popularityCount - 1)
+    console.log popularityRanks
+
     Team.find {}, (err,teams) ->
       teams.forEach (team) ->
         id = team._id
@@ -154,11 +159,10 @@
             team.scores[ field ] = computedScore.value[ field ]
             if field != 'contestant_count' and field != 'judge_count' and field != 'popularity_count'
               overall += computedScore.value[ field ]
-          if max_popularity_count == 0
-            team.scores.popularity = 0
-          else
-            team.scores.popularity = computedScore.value.popularity_count / max_popularity_count * 10
+
+          team.scores.popularity = (popularityRanks[computedScore.value.popularity_count] or 0) * 8 + 2
           overall += team.scores.popularity
+
           team.scores.overall = overall
         else
           TeamSchema.eachPath (path) ->


:lipstick: Correct indentation

:lipstick: Correct indentation

--- lib/go-to-view.coffee
+++ lib/go-to-view.coffee
@@ -53,5 +53,5 @@
         @setItems(tags)
         @attach()

-   afterTagOpen: (previous) ->
-     @stack.push previous
+  afterTagOpen: (previous) ->
+    @stack.push previous


hdp select: use store instead of db

hdp select: use store instead of db

--- lib/hdp_select.coffee
+++ lib/hdp_select.coffee
@@ -18,7 +18,7 @@
     # options = name: options if typeof options is 'string'
     options.version ?= 'latest'
     if options.version and options.version not in ['latest', 'current']
-      options.db['hdp_select.version.default'] = options.version
+      options.store['hdp_select.version.default'] = options.version
     ctx
     .call (_, callback) ->
       # Get the current or latest version
@@ -41,14 +41,14 @@
         fi
         echo $version
         """
-        not_if: options.db['hdp_select.version.default']
+        not_if: options.store['hdp_select.version.default']
         shy: true
       , (err, executed, stdout, stderr) ->
         return callback err if err
-        options.db['hdp_select.version.default'] = stdout.trim() if executed
+        options.store['hdp_select.version.default'] = stdout.trim() if executed
         callback()
     .call (_, callback) ->
-      version = options.db['hdp_select.version.default']
+      version = options.store['hdp_select.version.default']
       # Set the service to its expected version
       ctx.execute
         cmd: """