Imlemented LAS, TAS instructions.

Imlemented LAS, TAS instructions.

--- emulator/core/units/cpu.coffee
+++ emulator/core/units/cpu.coffee
@@ -400,6 +400,11 @@
         @$storeValueIntoAccumulator value
         @$storeValueIntoRegisterX value

+    LAS: (address) =>
+        @stackPointer &= @$readByte address
+        @$storeValueIntoAccumulator @stackPointer
+        @$storeValueIntoRegisterX @stackPointer
+
     ###########################################################
     # Register transfer instructions
     ###########################################################
@@ -621,6 +626,10 @@
         @ROR()
         @carryFlag = (@accumulator >>> 6) & 1
         @overflowFlag = ((@accumulator >>> 5) & 1) ^ @carryFlag
+
+    TAS: (address) => # Also known as SHS
+        @stackPointer = @accumulator & @registerX
+        @SHA address

     ###########################################################
     # Instruction helper functions
@@ -808,13 +817,15 @@
         @registerOperation 0xAC, @LDY, @absoluteMode,  0, 0, 0 # 4      cycles
         @registerOperation 0xBC, @LDY, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles

-        @registerOperation 0xAB, @LAX, @immediateMode, 0, 0, 0, # 2      cycles (undocumented operation)
-        @registerOperation 0xA7, @LAX, @zeroPageMode,  0, 0, 0, # 3      cycles (undocumented operation)
-        @registerOperation 0xB7, @LAX, @zeroPageYMode, 0, 1, 0, # 4      cycles (undocumented operation)
-        @registerOperation 0xAF, @LAX, @absoluteMode,  0, 0, 0, # 4      cycles (undocumented operation)
-        @registerOperation 0xBF, @LAX, @absoluteYMode, 1, 0, 0, # 4 (+1) cycles (undocumented operation)
-        @registerOperation 0xA3, @LAX, @indirectXMode, 0, 1, 0, # 6      cycles (undocumented operation)
-        @registerOperation 0xB3, @LAX, @indirectYMode, 1, 0, 0, # 5 (+1) cycles (undocumented operation)
+        @registerOperation 0xAB, @LAX, @immediateMode, 0, 0, 0 # 2      cycles (undocumented operation)
+        @registerOperation 0xA7, @LAX, @zeroPageMode,  0, 0, 0 # 3      cycles (undocumented operation)
+        @registerOperation 0xB7, @LAX, @zeroPageYMode, 0, 1, 0 # 4      cycles (undocumented operation)
+        @registerOperation 0xAF, @LAX, @absoluteMode,  0, 0, 0 # 4      cycles (undocumented operation)
+        @registerOperation 0xBF, @LAX, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0xA3, @LAX, @indirectXMode, 0, 1, 0 # 6      cycles (undocumented operation)
+        @registerOperation 0xB3, @LAX, @indirectYMode, 1, 0, 0 # 5 (+1) cycles (undocumented operation)
+
+        @registerOperation 0xBB, @LAS, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles (undocumented operation)

         ###########################################################
         # Register transfer instructions
@@ -1063,6 +1074,8 @@
         @registerOperation 0x4B, @ALR, @immediateMode, 0, 0, 0 # 2 cycles (undocumented operation)
         @registerOperation 0x6B, @ARR, @immediateMode, 0, 0, 0 # 2 cycles (undocumented operation)

+        @registerOperation 0x9B, @TAS, @absoluteYMode, 0, 1, 0 # 5 cycles (undocumented operation)
+
     registerOperation: (operationCode, instruction, addressingMode, pageCrossEnabled, emptyReadCycles, emptyWriteCycles) ->
         @operationsTable[operationCode] =
             instruction: instruction


shorter defaults setting, also allows manual timestamps should someone need them

--- src/lib/logger.coffee
+++ src/lib/logger.coffee
@@ -28,10 +28,10 @@
 			if _.isString(message)
 				message = { message }

-			message.timestamp = Date.now()
-
-			# Stop pubnub logging loads of "Missing Message" errors, as they are quite distracting
-			message.message or= ' '
+			_.defaults message,
+				timestamp: Date.now()
+				# Stop pubnub logging loads of "Missing Message" errors, as they are quite distracting
+				message: ' '

 			pubnub.publish({ channel, message })


remove the testing artifact

remove the testing artifact

--- library/membrane/duplex.coffee
+++ library/membrane/duplex.coffee
@@ -293,7 +293,6 @@
         try @socket = io.connect @duplex, options catch error
             message = "blew up Socket.IO: #{error.message}"
             error.message = message.toString(); throw error
-        @socket.on "abc", -> console.log "ECHO"
         @emit "socketing", this.socket, this.duplex, options
         failed = "failed to establish the Socket.IO connection"
         assert this.socket.emit, failed; this.socketFeedback()


Upgrade broker to set content length

Upgrade broker to set content length

--- library/nucleus/content.coffee
+++ library/nucleus/content.coffee
@@ -48,10 +48,24 @@
         registry = @constructor.registry ?= []
         for own index, negotiator of registry
             args = [request, response, content]
-            flusher = negotiator arguments...
+            bounded = negotiator.bind this
+            flusher = bounded arguments...
             handles = _.isFunction flusher
             return flusher args... if handles
-        response.write content.toString()
+        @push response, content.toString()
+
+    # Push the encoded content to the response write stream. This is
+    # an utility method whose implementation is tweaked to the way it
+    # is being used by this class. It has to do with the way this method
+    # writes out the `Content-Length` header deduced from encoded size.
+    push: (response, encoded) ->
+        valid = _.isString encoded
+        areSent = response.headersSent
+        invalid = "Invalid encoded content"
+        throw new Error invalid unless valid
+        args = ["Content-Length", encoded.length]
+        response.setHeader args... unless areSent
+        response.write encoded

     # Register the specified content negotiator with the broker. The
     # The negotiator returns a function if it can handle the request
@@ -71,10 +85,10 @@
         isArray = _.isArray content
         isObject = _.isObject content
         return unless isArray or isObject
-        (request, response, content) ->
+        (request, response, content) =>
             jsonType = "application/json"
             doesHtml = response.accepts /html/
             spaces = if doesHtml then 4 else null
             response.setHeader "Content-Type", jsonType
             jsoned = (x) -> JSON.stringify x, null, spaces
-            response.write jsoned content
+            @push response, jsoned content


some more surgeries on the ancient codes

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -239,6 +239,8 @@
         template = "Exception in a #{method} at %s: %s"
         logger.error template.red, identify, error.stack
         @emit "failure", this, error, request, response
+        message = "Executed error rescue handler in %s"
+        logger.debug message.red, identify.toString()
         return next() unless nconf.get(expose) is yes
         response.setHeader "Content-Type", "text/plain"
         response.writeHead 500, http.STATUS_CODES[500]


Added Enums

Added Enums

--- app/enums.coffee
+++ app/enums.coffee
@@ -41,4 +41,12 @@
     TIME_LIMIT: 0
     SCAN_LIMIT: 1

+  CONTACT:
+    UNKNOWN: -1
+    HOME_PAGE: 0
+    NOTIFY: 1
+    REGISTER: 2
+    CONTACT_US: 3
+
+
 `export default ENUMS;`


Add FOR-OF test

Add FOR-OF test

--- spec/Parser-spec.coffee
+++ spec/Parser-spec.coffee
@@ -1,6 +1,6 @@
 Parser = require '../lib/Parser'
 { Range } = require 'atom'
-{ inspect } = require 'util'
+# { inspect } = require 'util'

 expectNoRefs = (parser, range) ->
   resultRanges = parser.find range
@@ -45,7 +45,7 @@
       expectNoRefs parser, new Range([0, 2], [0, 3])
       expectNoRefs parser, new Range([1, 6], [1, 7])

-    it 'should find references in FUNCTION', ->
+    it 'should support FUNCTION statement', ->
       parser.parse """
       a = b = 100
       calc = (a) ->
@@ -70,7 +70,7 @@
         new Range([0, 4], [0, 5]),
         new Range([2, 6], [2, 7])

-    it 'should find references in OBJECT', ->
+    it 'should support OBJECT statement', ->
       parser.parse """
       a = 10
       b = 5
@@ -101,7 +101,7 @@
         new Range([1, 0], [1, 1]),
         new Range([4, 6], [4, 7])

-    it 'should find references in EXTENDS', ->
+    it 'should support EXTENDS statement', ->
       parser.parse """
       class A
       class B extends A
@@ -114,7 +114,7 @@
         new Range([0, 6], [0, 7]),
         new Range([2, 16], [2, 17])

-    it 'should find references in IF', ->
+    it 'should support IF statement', ->
       parser.parse """
       if a
         a = a / a
@@ -128,9 +128,9 @@
         new Range([1, 2], [1, 3]),
         new Range([1, 6], [1, 7])

-    it 'should find references in FOR-IN', ->
+    it 'should support FOR-IN statement', ->
       parser.parse """
-      for elem, i in elems
+      for elem, i in arr
         console.log i, elem
       """
       expectEqualRefs parser, new Range([0, 4], [0, 8]),
@@ -141,3 +141,17 @@
         new Range([0, 4], [0, 8])
       expectEqualRefs parser, new Range([1, 14], [1, 15]),
         new Range([0, 10], [0, 11])
+
+    it 'should support FOR-OF statement', ->
+      parser.parse """
+      for key, val of obj
+        console.log key, val
+      """
+      expectEqualRefs parser, new Range([0, 4], [0, 7]),
+        new Range([1, 14], [1, 17])
+      expectEqualRefs parser, new Range([0, 9], [0, 12]),
+        new Range([1, 19], [1, 22])
+      expectEqualRefs parser, new Range([1, 14], [1, 17]),
+        new Range([0, 4], [0, 7])
+      expectEqualRefs parser, new Range([1, 19], [1, 22]),
+        new Range([0, 9], [0, 12])


Add a SGP test case for when the number has letters

--- spec/countries/SGP-spec.coffee
+++ spec/countries/SGP-spec.coffee
@@ -76,6 +76,16 @@

             # Assert
             expect(result).to.be.null
+
+        it 'get an invalid number with letters', ->
+            # Arrange
+            number = "+65 1sss234567"
+
+            # Act
+            result = Phone.getPhoneInternational(number)
+
+            # Assert
+            expect(result).to.be.null


Cleanup randomized DisplayLayer tests

Cleanup randomized DisplayLayer tests

--- spec/display-layer-spec.coffee
+++ spec/display-layer-spec.coffee
@@ -152,30 +152,42 @@
       seed = Date.now()
       seedFailureMessage = "Seed: #{seed}"
       random = new Random(seed)
-      buffer = new TextBuffer(text: buildRandomLines(10, random))
+      buffer = new TextBuffer(text: buildRandomLines(random, 10))
       actualDisplayLayer = buffer.addDisplayLayer(tabLength: 4, patchSeed: seed)
-      lastDisplayLayerChange = null
-      actualDisplayLayer.onDidChangeTextSync (change) -> lastDisplayLayerChange = change

       for k in [0...10] by 1
-        lastDisplayLayerChange = null
-        range = getRandomRange(buffer, random)
-        text = buildRandomLines(4, random)
-        bufferWithDisplayLayerText = new TextBuffer(text: actualDisplayLayer.getText())
-        buffer.setTextInRange(range, text)
+        performRandomChange(random, buffer, actualDisplayLayer, seedFailureMessage)
+        return if currentSpecFailed()
+
+        # incrementally-updated text matches freshly computed text
         expectedDisplayLayer = buffer.addDisplayLayer(tabLength: 4)
-
-        # incrementally-updated text matches freshly computed text
         expect(actualDisplayLayer.getText()).toBe(expectedDisplayLayer.getText(), seedFailureMessage)
         return if currentSpecFailed()

-        # emitted text change event describes delta between the old and new text of display layer
-        verifyChangeEvent(bufferWithDisplayLayerText, lastDisplayLayerChange, actualDisplayLayer, seedFailureMessage)
-        return if currentSpecFailed()
+        # positions all translate correctly
+        verifyPositionTranslations(actualDisplayLayer, expectedDisplayLayer, seedFailureMessage)

         # token iterator matches contents of display layer
         verifyTokenIterator(actualDisplayLayer, seedFailureMessage)
         return if currentSpecFailed()
+
+performRandomChange = (random, buffer, displayLayer, seedFailureMessage) ->
+  previousDisplayLayerText = displayLayer.getText()
+  lastChange = null
+  displayLayer.onDidChangeTextSync (change) -> lastChange = change
+
+  range = getRandomRange(random, buffer)
+  text = buildRandomLines(random, 4)
+  buffer.setTextInRange(range, text)
+
+  # emitted text change event describes delta between the old and new text of display layer
+  replacedRange = Range.fromPointWithTraversalExtent(lastChange.start, lastChange.replacedExtent)
+  replacementRange = Range.fromPointWithTraversalExtent(lastChange.start, lastChange.replacementExtent)
+  replacementText = substringForRange(displayLayer.getText(), replacementRange)
+
+  bufferWithDisplayLayerText = new TextBuffer(text: previousDisplayLayerText)
+  bufferWithDisplayLayerText.setTextInRange(replacedRange, replacementText)
+  expect(bufferWithDisplayLayerText.getText()).toBe(displayLayer.getText(), seedFailureMessage)

 expectPositionTranslations = (displayLayer, tranlations) ->
   for [screenPosition, bufferPositions] in tranlations
@@ -190,13 +202,6 @@
       expect(displayLayer.translateScreenPosition(screenPosition)).toEqual(bufferPosition)
       expect(displayLayer.translateBufferPosition(bufferPosition)).toEqual(screenPosition)

-verifyChangeEvent = (bufferWithDisplayLayerText, lastDisplayLayerChange, actualDisplayLayer, seedFailureMessage) ->
-  replacedRange = Range.fromPointWithTraversalExtent(lastDisplayLayerChange.start, lastDisplayLayerChange.replacedExtent)
-  replacementRange = Range.fromPointWithTraversalExtent(lastDisplayLayerChange.start, lastDisplayLayerChange.replacementExtent)
-  replacementText = substringForRange(actualDisplayLayer.getText(), replacementRange)
-  bufferWithDisplayLayerText.setTextInRange(replacedRange, replacementText)
-  expect(bufferWithDisplayLayerText.getText()).toBe(actualDisplayLayer.getText(), seedFailureMessage)
-
 verifyTokenIterator = (displayLayer, failureMessage) ->
   {buffer} = displayLayer
   tokenIterator = displayLayer.buildTokenIterator()
@@ -228,8 +233,8 @@

   expect(text).toBe(displayLayer.getText(), failureMessage)

-verifyPositionTranslations = (actualDisplayLayer, expectedDisplayLayer) ->
-  {buffer} = displayLayer
+verifyPositionTranslations = (actualDisplayLayer, expectedDisplayLayer, seedFailureMessage) ->
+  {buffer} = actualDisplayLayer

   bufferLines = buffer.getText().split('\n')
   screenLines = actualDisplayLayer.getText().split('\n')
@@ -238,16 +243,15 @@
     for character, bufferColumn in bufferLine
       actualPosition = actualDisplayLayer.translateBufferPosition(Point(bufferRow, bufferColumn))
       expectedPosition = expectedDisplayLayer.translateBufferPosition(Point(bufferRow, bufferColumn))
-      expect(actualPosition).toEqual(expectedPosition)
+      expect(actualPosition).toEqual(expectedPosition, seedFailureMessage)

   for screenLine, screenRow in screenLines
     for character, screenColumn in screenLine
-      actualPosition = actualDisplayLayer.translateScrneePosition(Point(screenRow, screenColumn))
+      actualPosition = actualDisplayLayer.translateScreenPosition(Point(screenRow, screenColumn))
       expectedPosition = expectedDisplayLayer.translateScreenPosition(Point(screenRow, screenColumn))
-      expect(actualPosition).toEqual(expectedPosition)
-
-
-buildRandomLines = (maxLines, random) ->
+      expect(actualPosition).toEqual(expectedPosition, seedFailureMessage)
+
+buildRandomLines = (random, maxLines) ->
   lines = []
   for i in [0...random(maxLines)] by 1
     lines.push(buildRandomLine(random))
@@ -266,10 +270,10 @@
       line.push(WORDS[random(WORDS.length)])
   line.join('')

-getRandomRange = (buffer, random) ->
-  Range(getRandomPoint(buffer, random), getRandomPoint(buffer, random))
-
-getRandomPoint = (buffer, random) ->
+getRandomRange = (random, buffer) ->
+  Range(getRandomPoint(random, buffer), getRandomPoint(random, buffer))
+
+getRandomPoint = (random, buffer) ->
   row = random(buffer.getLineCount())
   column = random(buffer.lineForRow(row).length + 1)
   Point(row, column)


Revert focus on language-mode-spec.coffee

--- spec/language-mode-spec.coffee
+++ spec/language-mode-spec.coffee
@@ -1,4 +1,4 @@
-fdescribe "LanguageMode", ->
+describe "LanguageMode", ->
   [editor, buffer, languageMode] = []

   afterEach ->


Remove unused process.exit spy

Remove unused process.exit spy

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -5,7 +5,6 @@
   spyOn(console, 'error')
   spyOn(process.stdout, 'write')
   spyOn(process.stderr, 'write')
-  spyOn(process, 'exit')

 global.spyOnToken = ->
   spyOn(auth, 'getToken').andCallFake (callback) -> callback(null, 'token')


Use a packages fixtures directory as the default project directory

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -3,6 +3,7 @@
 window.restoreDimensions()

 nakedLoad 'jasmine-jquery'
+path = require 'path'
 $ = jQuery = require 'jquery'
 _ = require 'underscore'
 Keymap = require 'keymap'
@@ -37,7 +38,9 @@

 beforeEach ->
   jQuery.fx.off = true
-  window.project = new Project(fsUtils.resolveOnLoadPath('fixtures'))
+
+  specDirectory = atom.getLoadSettings().specDirectory ? path.resolve("./specs")
+  window.project = new Project(path.join(specDirectory, 'fixtures'))

   window.resetTimeouts()
   atom.packageStates = {}


Add toHaveFocus jasmine expectation

Add toHaveFocus jasmine expectation

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -159,6 +159,17 @@
       @message = -> return "Expected path '" + @actual + "'" + notText + " to exist."
       fs.existsSync(@actual)

+    toHaveFocus: ->
+      notText = this.isNot and " not" or ""
+      if not document.hasFocus()
+        console.error "Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner."
+
+      @message = -> return "Expected element '" + @actual + "' or its descendants" + notText + " to have focus."
+      element = @actual
+      element = element.get(0) if element.jquery
+      element.webkitMatchesSelector(":focus") or element.querySelector(":focus")
+
+
 window.keyIdentifierForKey = (key) ->
   if key.length > 1 # named key
     key


Spec helper uses window's keymap

Spec helper uses window's keymap

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -13,10 +13,7 @@
 afterEach ->
   $('#jasmine-content').empty()

-specsKeymap = new Keymap
-specsKeymap.bindDefaultKeys()
-$(window).on 'keydown', (e) -> specsKeymap.handleKeyEvent(e)
-specsKeymap.bindKeys '*', 'meta-w': 'close'
+window.keymap.bindKeys '*', 'meta-w': 'close'
 $(document).on 'close', -> window.close()

 # Use underscore's definition of equality for toEqual assertions


this spec doesn't belong

this spec doesn't belong

--- spec/settings-view-spec.coffee
+++ spec/settings-view-spec.coffee
@@ -184,8 +184,6 @@
           expect(settingsView.activePanelName).toBe 'Install'
           expect(InstallPanel::beforeShow).toHaveBeenCalledWith {uri: 'atom://config/install/package:something'}

-      xit "Shows a package page if URI is opened while config is already active"
-
     describe "when the package is then deactivated", ->
       beforeEach ->
         settingsView = null


Scope focus tests to darwin platform

Scope focus tests to darwin platform

--- spec/table-element-spec.coffee
+++ spec/table-element-spec.coffee
@@ -767,11 +767,11 @@
           expect(editorElement.offsetHeight).toBeCloseTo(cell.offsetHeight, -2)

         it 'gives the focus to the editor', ->
-          editorElementRoot = () ->
-            if parseFloat(atom.getVersion()) < 1.13
-              expect(document.activeElement).toBe(editorElement)
-            else
-              expect(document.activeElement).toBe(editorElement.querySelector('input'))
+          if parseFloat(atom.getVersion()) < 1.13
+            expect(document.activeElement).toBe(editorElement)
+          else if process.platform is 'darwin'
+            expect(document.activeElement).toBe(editorElement.querySelector('input'))
+          else console.log(document.activeElement.outerHTML)

         it 'fills the editor with the cell value', ->
           expect(editor.getText()).toEqual('key')
@@ -1747,8 +1747,9 @@
     it 'gives the focus to the editor', ->
       if parseFloat(atom.getVersion()) < 1.13
         expect(document.activeElement).toBe(editorElement)
-      else
+      else if process.platform is 'darwin'
         expect(document.activeElement).toBe(editorElement.querySelector('input'))
+      else console.log(document.activeElement.outerHTML)

     it 'fills the editor with the cell value', ->
       expect(editor.getText()).toEqual('row0')


Animate the cat on touch devices

Animate the cat on touch devices

--- js/cat-3d.coffee
+++ js/cat-3d.coffee
@@ -10,6 +10,11 @@

 #Globals
 mouseXpos = false
+ANIMATION_SPEED = 4
+isAnimating = no
+startAngle = 0
+currentAngle = 90
+currentAngle = 0

 # Basic elements
 $container = document.getElementById 'js-3dcat'
@@ -57,12 +62,14 @@
 # Geometry
 theBody = null

+easeOutQuad = (t) -> t * (2 - t)
+
 drawCatBody = (bodyGeo) ->
   bodyGeo.applyMatrix new T.Matrix4().makeTranslation(0, 0, 1)
   theBody = new T.Mesh bodyGeo, textureBody
   theBody.position.set 0, 0, 0
   theBody.scale.set 140, 140, 140
-  theBody.rotation.set 0, 90 * Math.PI / 180, 0
+  theBody.rotation.set 0, currentAngle * Math.PI / 180, 0
   scene.add theBody

 JSONLoader.load '/geometry/3dcat-body.json', drawCatBody
@@ -70,8 +77,37 @@
 # Update cat on mouse move
 updateCat = ->
   if theBody and mouseXpos isnt false
-    angle = 180 * mouseXpos / window.innerWidth
-    theBody.rotation.set 0, (angle - 45) * Math.PI/ 180, 0
+    targetAngle = (180 * mouseXpos / window.innerWidth) - 45
+
+    if Modernizr.touchevents
+      return if targetAngle is currentAngle
+
+      startAngle = currentAngle unless isAnimating
+      updateAngle = currentAngle
+
+      if isAnimating
+        updateAngle = startAngle +
+        easeOutQuad(Math.abs(currentAngle - startAngle) /
+        Math.abs(targetAngle - startAngle)) *
+        (targetAngle - startAngle)
+
+      if currentAngle < targetAngle
+        currentAngle += ANIMATION_SPEED
+        isAnimating = yes
+        if targetAngle < currentAngle
+          isAnimating = no
+          currentAngle = targetAngle
+
+      if currentAngle > targetAngle
+        currentAngle -= ANIMATION_SPEED
+        isAnimating = yes
+        if targetAngle > currentAngle
+          isAnimating = no
+          currentAngle = targetAngle
+
+      theBody.rotation.set 0, updateAngle * Math.PI / 180, 0
+    else
+      theBody.rotation.set 0, targetAngle * Math.PI / 180, 0

 document.addEventListener 'mousemove', (e) ->
   mouseXpos = e.clientX


Added lots of fun API calls

Added lots of fun API calls

probably should rename this file or something

--- js/coffee.coffee
+++ js/coffee.coffee
@@ -1 +1,60 @@
-# Empty file to start with+# Summoner Name
+
+function summonerLookUp() {
+	var SUMMONER_NAME = "";
+	SUMMONER_NAME = $("#summonerName").val();
+
+	var REGION = "";
+	REGION = $("#region").val();
+
+	REQUEST_URL_SHORT = 'https://' + REGION + 'api.pvp.net/api/lol/' + REGION;
+
+	if (SUMMONER_NAME !== "") {
+
+		$.ajax({
+		url: REQUEST_URL_SHORT + '/v1.4/summoner/by-name/' + SUMMONER_NAME + '?api_key=' + $RIOT_SECRET,
+		type: 'GET',
+		dataType: 'json',
+		data: {
+
+			},
+			success: function (json) {
+				var SUMMONER_NAME_NOSPACES = SUMMONER_NAME.replace(" ", "");
+
+				SUMMONER_NAME_NOSPACES =
+				SUMMONER_NAME_NOSPACES.toLowerCase().trim();
+
+				summonerID =
+				json[SUMMONER_NAME_NOSPACES].id;
+
+
+			},
+			error: function (XMLHttpRequest, textStatus, errorThrown) {
+				alert("Error Getting Summoner Data");
+		}
+		});
+
+		$.ajax({
+		url: REQUEST_URL_SHORT + '/v1.3/stats/by-summoner/' + summonerID + '/ranked',
+		type: 'GET',
+		dataType: 'json',
+		data: {
+		},
+			success: function (json) {
+				champList =
+				json[summonerID].champions;
+
+				mostPlayedChamp =
+				function () {
+					for (i = 0, i < champList.length, i++) {
+						var MPC;
+						if (champList[i].totalSessionsPlayed > MPC.totalSessionsPlayed) {
+						MPC = champList[i];
+						}
+					}
+					return MPC;
+				}
+			}
+		})
+	}
+}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/oscillator.coffee
+++ src/oscillator.coffee
@@ -5,7 +5,7 @@
 @constructor
 @param {Number} amplitude How much to scale the oscillator function value
 @param {Number} period How fast the osciallator function repeats
-@param {Number} offset How much to offset the created osciallator function. Useful for translat
+@param {Number} offset How much to offset the created osciallator function. Useful for translating between sin and cosine fun
 ###
 Oscillator = (options={}) ->
   {amplitude, period, offset} = options


Fix some dragging behavior

Fix some dragging behavior

--- js/conway.coffee
+++ js/conway.coffee
@@ -78,7 +78,7 @@
   s.previousCell = []
   width = height = 40
   paused = false
-  speed = 8
+  speed = 1

   # Generate a blank world
   rows = _.map _.range(40), -> return no
@@ -119,12 +119,12 @@
     frameRate = s.createSpan("#{speed} generations/second")

   s.draw = ->
-    s.frameRate(1)
+    s.frameRate(speed)
     s.background(255)
     renderWorld(s, world, width, height, cellSize)

-    # unless paused
-    world = advanceWorld(world,width,height)
+    unless paused
+      world = advanceWorld(world,width,height)

   s.mouseClicked = (e) ->
     if e.toElement.tagName is "CANVAS"


Dive on unadorned "left"

Dive on unadorned "left"

--- keymaps/git.cson
+++ keymaps/git.cson
@@ -55,6 +55,7 @@
   'ctrl-enter': 'github:commit'

 '.github-CommitView-commitPreview':
+  'left': 'github-dive'
   'enter': 'native!'
 '.platform-darwin .github-CommitView-commitPreview':
   'cmd-left': 'github:dive'


Un-toggle InStateMenu on quit to retain smooth transition.

--- src/state-play.coffee
+++ src/state-play.coffee
@@ -148,6 +148,7 @@

     quit: (trigger) ->
       return no unless @ended or trigger instanceof Key
+      @inStateMenu.toggle off
       _quit = => @state.startWithTransition null, 'menu', yes
       if @music.volume is 0
         _quit()


Rename `Editor` attach and remove events in accordance w/ new scheme

'editor-open' -> 'editor:attached'
'before-remove' -> 'editor:will-be-removed'

--- src/status-bar.coffee
+++ src/status-bar.coffee
@@ -8,7 +8,7 @@
     for editor in rootView.getEditors()
       @appendToEditorPane(rootView, editor) if rootView.parents('html').length

-    rootView.on 'editor-open', (e, editor) =>
+    rootView.on 'editor:attached', (e, editor) =>
       @appendToEditorPane(rootView, editor)

   @appendToEditorPane: (rootView, editor) ->


Add an event when ItemListChanged

Add an event when ItemListChanged

--- client/Framework/components/autocomplete/KDAutoCompleteController.coffee
+++ client/Framework/components/autocomplete/KDAutoCompleteController.coffee
@@ -57,6 +57,7 @@
       when 13, 9 #enter, tab
         unless autoCompleteView.getValue() is ""
           @submitAutoComplete autoCompleteView.getValue()
+          @emit 'ItemListChanged'
         else
           return yes
       when 27 #escape
@@ -195,7 +196,7 @@
       @getSingleton("windowController").setKeyView null
       new KDNotificationView
         type      : "mini"
-        title   : "You can add up to #{@getOptions().selectedItemsLimit} items!"
+        title     : "You can add up to #{@getOptions().selectedItemsLimit} items!"
         duration  : 4000

     @hideDropdown()
@@ -263,7 +264,7 @@
     path.join('.')

   addSuggestion:(title)->
-    @propagateEvent KDEventType: 'AutocompleteSuggestionWasAdded', title
+    @emit 'AutocompleteSuggestionWasAdded', title

   addItemToSubmitQueue:(item,data)->
     data or= item.getData()
@@ -275,8 +276,7 @@
     else
       itemValue = item.getOptions().userInput
       data = JsPath itemDataPath, itemValue
-      @addSuggestion itemValue
-
+
     return no if @isItemAlreadySelected data

     path = @getCollectionPath()
@@ -325,6 +325,7 @@
     @removeSelectedItemData data
     @selectedItemCounter--
     item.destroy()
+    @emit 'ItemListChanged'

   rearrangeInputWidth:()->
     # mainView = @getView()


payment controller: avoid leaking listeners

--- client/app/Applications/Account.kdapplication/views/subscriptions.coffee
+++ client/app/Applications/Account.kdapplication/views/subscriptions.coffee
@@ -52,7 +52,7 @@

     payment = KD.getSingleton 'paymentController'

-    payment.on 'SubscriptionDebited', @bound 'loadItems'
+    payment.once 'SubscriptionDebited', @bound 'loadItems'

     payment.fetchSubscriptionsWithPlans (err, subscriptions) =>
       @instantiateListItems subscriptions.filter (s) ->


minor cleanup on demo page

minor cleanup on demo page

--- client/landing/app/Applications/Demos.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Demos.kdapplication/AppController.coffee
@@ -14,41 +14,4 @@
     super options, data

   loadView:(mainView)->
-    options =
-      name               : "Teamwork"
-      version            : "0.1"
-      joinModalTitle     : "Join a coding session"
-      joinModalContent   : "
Paste the session key that you received and start coding together.
"
-      shareSessionKeyInfo: "
This is your session key, you can share this key with your friends to work together.
"
-      firebaseInstances  : "teamwork-local"
-      # firebaseInstances  : ["kd-prod-1", "kd-prod-2", "kd-prod-3", "kd-prod-4", "kd-prod-5"]
-      enableChat         : yes
-      panels             : [
-        {
-          title          : "Teamwork"
-          hint           : "
This is a collaborative coding environment where you can team up with others and work on the same code.
"
-          buttons        : [
-            {
-              title      : "Join"
-              cssClass   : "cupid-green join-button"
-              callback   : (panel, workspace) => workspace.showJoinModal()
-            }

-          ]
-          panes: [
-            {
-              type  : "finder"
-            }
-            {
-              type  : "tabbedEditor"
-            }
-            {
-              type  : "terminal"
-            }
-          ]
-        }
-      ]
-    kolab = new CollaborativeWorkspace options
-    kolab.on "PanelCreated", =>
-      kolab.activePanel.splitView.resizePanel "20%", 0
-    mainView.addSubView kolab


Minor change

Minor change

--- src/ProjectUtils.coffee
+++ src/ProjectUtils.coffee
@@ -137,7 +137,7 @@

   getDatedIdentifier: (id) ->
     id ?= Projects.getCurrentId()
-    'project-' + id + '-' + Dates.toIdentifier(moment())
+    'project-' + id + '-' + Dates.toIdentifier()

   assertAuthorization: (projectId, userId) ->
     unless projectId?


Added support for additional metadata types

--- lib/build.coffee
+++ lib/build.coffee
@@ -101,7 +101,7 @@
           switch folderName[0]
             when 'classes'
               metaDataType = 'ApexClass'
-            when 'trigger'
+            when 'triggers'
               metaDataType = 'ApexTrigger'
             when 'pages'
               metaDataType = 'ApexPage'
@@ -124,7 +124,7 @@
             when 'labels'
               metaDataType = 'CustomLabels'
             when 'workflows'
-              metaDataType = 'WorkflowRule'
+              metaDataType = 'Workflow'
             when 'remoteSiteSettings'
               metaDataType = 'RemoteSiteSetting'
             when 'permissionsets'
@@ -137,6 +137,20 @@
               metaDataType = 'Group'
             when 'objectTranslations'
               metaDataType = 'CustomObjectTranslation'
+            when 'communities'
+              metaDataType = 'Network'
+            when 'reportTypes'
+              metaDataType = 'ReportType'
+            when 'settings'
+              metaDataType = 'Settings'
+            when 'assignmentRules'
+              metaDataType = 'AssignmentRule'
+            when 'approvalProcesses'
+              metaDataType = 'ApprovalProcess'
+            when 'escalationRules'
+              metaDataType = 'EscalationRule'
+            when 'flows'
+              metaDataType = 'Flow'
             else
               metaDataType = null


bring ./app (RTD) support up to documented state; also small bug if running from outside the app (which wasn't possible before this commit anyway)

--- lib/index.coffee
+++ lib/index.coffee
@@ -9,20 +9,34 @@
     exit_code: 1

 class MeteorApp
-    constructor: (@root) ->
+    constructor: (@root, extra_conf_path) ->
         console.log "Meteor app at #{@root}"
         yamlfile = switch
-            when fs.existsSync 'setup.yaml'
-                'setup.yaml'
-            when fs.existsSync '.setup.yaml'
-                '.setup.yaml'
-            when fs.existsSync '.meteor/setup.yaml'
-                '.meteor/setup.yaml'
+            when fs.existsSync "#{@root}/setup.yaml"
+                "#{@root}/setup.yaml"
+            when fs.existsSync "#{@root}/.setup.yaml"
+                "#{@root}/.setup.yaml"
+            when fs.existsSync "#{@root}/.meteor/setup.yaml"
+                "#{@root}/.meteor/setup.yaml"
+            when extra_conf_path?
+                for extra_conf_dir in extra_conf_path
+                    console.log "also searching for config in #{extra_conf_dir}"
+                    switch
+                        when fs.existsSync "#{extra_conf_dir}/setup.yaml"
+                            found = "#{extra_conf_dir}/setup.yaml"
+                            break
+                        when fs.existsSync "#{extra_conf_dir}/.setup.yaml"
+                            found = "#{extra_conf_dir}/.setup.yaml"
+                            break
+                unless found?
+                    throw new RunError 'no setup.yaml found'
+                found
             else
                 throw new RunError 'no setup.yaml found'
         @config = yaml.load yamlfile

     install: ->
+        return unless @config.packages?
         for package_name, options of @config.packages
             if fs.existsSync "#{@root}/packages/#{package_name}"
                 console.log "#{package_name} already installed; updating not yet implemented"
@@ -40,7 +54,9 @@

     run: ->
         @install()
+        shell.pushd @root
         shell.exec 'meteor'
+        shell.popd

 module.exports =
     MeteorApp: MeteorApp
@@ -51,10 +67,11 @@
                 when fs.existsSync '.meteor'
                     process.cwd()
                 when fs.existsSync 'app/.meteor'
+                    extra_conf_path = [process.cwd()]
                     "#{process.cwd()}/app"
                 else
                     throw new RunError 'No Meteor app found'
-            app = new MeteorApp meteor_dir
+            app = new MeteorApp meteor_dir, extra_conf_path
             # TODO: parse commands
             app.run()
         catch e


Committed progress to write tests

Committed progress to write tests

--- lib/index.coffee
+++ lib/index.coffee
@@ -11,40 +11,41 @@
       @ran = false

     compile_hooks: ->
-      before_file: (ctx) ->
+      before_file: (ctx) =>
         if @ran then return
         p = []
         for key, obj of opts
-          p.push _process(ctx.roots, key, obj)
+          p.push _process.call(@, key, obj)
         @ran = true
         W.all(p)

-    _process = (roots, key, obj) ->
+    _process = (key, obj) ->
       if obj.url?
-        return _url roots, key, obj
+        return _url.call(@, key, obj)
       else if obj.file?
-        return _file roots, key, obj
+        return _file.call(@, key, obj)
       else if obj.data?
-        return _data roots, key, obj
+        return _data.call(@, key, obj)

-    _url = (roots, key, obj) ->
+    _url = (key, obj) ->
       nodefn.call(request, obj.url)
-        .tap (response) ->
-          _respond(roots, key, obj, JSON.parse(response[0].body))
+        .tap (response) =>
+          _respond.call(@, key, obj, JSON.parse(response[0].body))

-    _file = (roots, key, obj) ->
+    _file = (key, obj) ->
       W ->
         f = fs.readFileSync obj.file, 'utf8'
-        _respond(roots, key, obj, JSON.parse(f))
+        _respond.call(@, key, obj, JSON.parse(f))

-    _data = (roots, key, obj) ->
+    _data = (key, obj) ->
       W ->
-        _respond(roots, key, obj, obj.data)
+        _respond.call(@, key, obj, obj.data)

-    _respond = (roots, key, obj, json) ->
-      roots.config.locals ||= {}
-      roots.config.locals.records ||= {}
-      roots.config.locals[key] = _to json, (obj.path or "/")
+    _respond = (key, obj, json) ->
+      @roots.config.locals ||= {}
+      @roots.config.locals.records ||= {}
+      @roots.config.locals[key] = json
+      console.log @

     _to = (json, path) ->
       keys = path.split "/"


Remove unnecessary debug messages, and add TODO messages

--- lib/latex.coffee
+++ lib/latex.coffee
@@ -7,16 +7,24 @@

   build: ->
     editor = atom.workspace.activePaneItem
-    # console.debug editor
-
     file = editor.buffer.file
-    # console.debug file

     if file?
-      # file = editor.getUri()
       dir = path.dirname(file.path)
-      outdir = path.join(dir, "output")
-      # console.debug outdir
+      outdir = path.join(dir, "output") # TODO: Make this configurable.

-      code = runas("/usr/texbin/latexmk", ["--pdf", "--f", "--interaction=nonstopmode", "--outdir=#{outdir}", file.path])
-      # console.debug code
+      # TODO: Find a reasonable way to resolve `latexmk` regardless of platform.
+      status = runas("/usr/texbin/latexmk", [
+        "--pdf",
+        "--f",
+        "--interaction=nonstopmode",
+        "--outdir=#{outdir}",
+        file.path
+      ])
+
+      if status == 0
+        # TODO: Display a more visible success message.
+        console.info "Success!"
+      else
+        # TODO: Introduce proper error and warning handling.
+        console.error "TeXification failed! Check the log file for more info..."


add missing imports

add missing imports

--- app/github.coffee
+++ app/github.coffee
@@ -10,8 +10,11 @@
 #   git.example.com/api/v3/gists/1051?access_token=...

 URI = require 'URIjs'
+_ = require 'underscore'
 Q = require 'q'
+moment = require 'moment'
 React = require 'react'
+Bacon = require 'bacon.model'
 modules = require './modules'
 http = require './http'
 global_settings = require './settings'


refactoring

refactoring

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -245,16 +245,14 @@
 getBufferRows = (editor, {startRow, direction, includeStartRow}) ->
   switch direction
     when 'previous'
-      unless includeStartRow
-        return [] if startRow is 0
-        startRow -= 1 if startRow > 0
-      [startRow..0]
+      if not includeStartRow and startRow <= 0
+        return []
+      [(startRow - 1)..0]
     when 'next'
       vimLastBufferRow = getVimLastBufferRow(editor)
-      unless includeStartRow
-        return [] if startRow is vimLastBufferRow
-        startRow += 1 if startRow < vimLastBufferRow
-      [startRow..vimLastBufferRow]
+      if not includeStartRow and startRow >= vimLastBufferRow
+        return []
+      [(startRow + 1)..vimLastBufferRow]

 # Return Vim's EOF position rather than Atom's EOF position.
 # This function change meaning of EOF from native TextEditor::getEofBufferPosition()


Changed default resize_delay timeout to 300.

--- stackgrid.adem.coffee
+++ stackgrid.adem.coffee
@@ -219,7 +219,7 @@
     is_fluid: true
     is_optimized: true
     number_of_columns: 4
-    resize_delay: 100
+    resize_delay: 300
     move: (element, left, top, callback) ->
       element.css
         left: left


修正新出现的树不能展开的BUG

修正新出现的树不能展开的BUG

--- src/widget/list/tree.coffee
+++ src/widget/list/tree.coffee
@@ -470,34 +470,31 @@
 				itemsScope.addAuxExpression(expressions[1])

 		nodeDom = itemDom.firstElementChild
-		if expand and not node._expanded
-			$fly(nodeDom).addClass("expanding")
-
-			node._bind.retrieveChildNodes(node, ()->
-				if expand
-					$fly(nodeDom).removeClass("expanding")
-					node._expanded = true if expand
-				node._hasExpanded = true
-
-				if node._children?.length > 0
-					tree._refreshChildNodes(itemDom, node, true)
-
-					$nodeDom = $fly(nodeDom)
-					$nodeDom.removeClass("leaf")
-					$nodeDom.addClass("expanded") if expand
-
-					$nodesWrapper = $fly(itemDom.lastChild)
-					if expand and $nodesWrapper.hasClass("child-nodes")
-						if noAnimation
-							$nodesWrapper.show()
-						else
-							$nodesWrapper.slideDown(150)
-				else
-					$fly(nodeDom).addClass("leaf")
-
-				callback?.call(tree)
-				return
-			)
+		$fly(nodeDom).addClass("expanding") if expand and not node._expanded
+		node._bind.retrieveChildNodes(node, ()->
+			$fly(nodeDom).removeClass("expanding") if expand
+			if node._children?.length > 0
+				tree._refreshChildNodes(itemDom, node, true)
+
+				$nodeDom = $fly(nodeDom)
+				$nodeDom.removeClass("leaf")
+				$nodeDom.addClass("expanded") if expand
+
+				$nodesWrapper = $fly(itemDom.lastChild)
+				if expand and $nodesWrapper.hasClass("child-nodes")
+					if noAnimation
+						$nodesWrapper.show()
+					else
+						$nodesWrapper.slideDown(150)
+			else
+				$fly(nodeDom).addClass("leaf")
+
+			node._expanded = true if expand
+			node._hasExpanded = true
+
+			callback?.call(tree)
+			return
+		)
 		return

 	expand: (node, noAnimation = true)->


Escape now closes dialogs

Escape now closes dialogs


Function composition works!

Function composition works!

--- controllers/myController.coffee
+++ controllers/myController.coffee
@@ -1,5 +1,6 @@
 module.exports =
         action: () ->
                 console.log 'yo'
-        action2: () ->
-                console.log 'mamma'
+                return 1
+        action2: (item) ->
+                console.log "#{item}"


Add generate and buffer example

Add generate and buffer example

--- example_observables.coffee
+++ example_observables.coffee
@@ -132,4 +132,21 @@
         args: ["6000"]
       }
     ]
+  generateAndBuffer:
+    description: "Values come later and later, buffer length changes"
+    root:
+      type: 'generateWithRelativeTime',
+      args: [
+        1,
+        "function(x) { return x <= 10 }"
+        "function(x) { return x + 1 }"
+        "function(x) { return x }"
+        "function(x) { return 200 * x }"
+      ]
+    operators: [
+      {
+        type: 'bufferWithTimeOrCount'
+        args: [ 2000, 3 ]
+      }
+    ]


Prevent manager from editing owner member item

--- src/collections/members.coffee
+++ src/collections/members.coffee
@@ -138,6 +138,7 @@
 exports.canEditItem = (member, team, item) ->
   return false unless member and team and @isItem item
   return false if item.readOnly
+  return false if item.type is 'member' and item.isOwner and not member.isOwner
   return true if teamsnap.canEditTeam member, team
   return false if team.isArchivedSeason
   if @isItem item, 'member'


Move clearing the state to the undelayed start function (fixes progress when manually adding images)

--- framer/Extras/Preloader.coffee
+++ framer/Extras/Preloader.coffee
@@ -86,6 +86,9 @@

 	start: =>

+		@_media = []
+		@_mediaLoaded = []
+
 		# A static delay avoids the progress from being shown if the loading
 		# took less then the delay. So if all images were cached then we don't
 		# hope to see a loading screen at all.
@@ -96,8 +99,6 @@
 		return if @isLoading

 		@_isLoading = true
-		@_media = []
-		@_mediaLoaded = []
 		@_startTime = Date.now()

 		@emit("start")


dont need scroll to logic in task index anymo

--- src/components/task/index.cjsx
+++ src/components/task/index.cjsx
@@ -25,7 +25,7 @@

 {UnsavedStateMixin} = require '../unsaved-state'

-{PinnedHeaderFooterCard, PinnedHeader, ScrollToMixin} = require 'openstax-react-components'
+{PinnedHeaderFooterCard, PinnedHeader} = require 'openstax-react-components'

 module.exports = React.createClass
   propTypes:
@@ -33,7 +33,7 @@

   displayName: 'Task'

-  mixins: [StepFooterMixin, CrumbMixin, UnsavedStateMixin, ScrollToMixin]
+  mixins: [StepFooterMixin, CrumbMixin, UnsavedStateMixin]

   contextTypes:
     router: React.PropTypes.func
@@ -140,8 +140,6 @@
       unless @state.currentStep is nextState.currentStep
         nextStep = TaskStore.getStepByIndex(id, nextState.currentStep)
         TaskStepActions.load(nextStep.id)
-        unless nextState.stepEntered is nextState.currentStep
-          @scrollToSelector("#exercise-part-with-scroll-#{nextState.currentStep}", {updateHistory: false})

     # if we reach this point, assume that we should go ahead and do a normal component update
     true
@@ -189,35 +187,6 @@
       @context.router.transitionTo('viewTaskStep', params)
       true

-  onPartEnter: (stepKey, scrollInfo) ->
-    return if @context.router.getCurrentParams().milestones?
-    {previousPosition} = scrollInfo
-    return unless previousPosition is 'below'
-
-    stepKey = parseInt(stepKey)
-    params = _.clone(@context.router.getCurrentParams())
-    params.stepIndex = stepKey + 1
-    params.id = @props.id # if we were rendered directly, the router might not have the id
-
-    return unless TaskStore.isSameStep(@props.id, @state.currentStep, stepKey)
-
-    @setState(stepEntered: stepKey)
-    @context.router.transitionTo('viewTaskStep', params)
-
-  onPartLeave: (stepKey, scrollInfo) ->
-    return if @context.router.getCurrentParams().milestones?
-    {currentPosition} = scrollInfo
-    return unless currentPosition is 'below'
-
-    stepKey = parseInt(stepKey)
-    params = _.clone(@context.router.getCurrentParams())
-    params.stepIndex = stepKey
-    params.id = @props.id # if we were rendered directly, the router might not have the id
-    return unless TaskStore.isSameStep(@props.id, @state.currentStep, stepKey - 1)
-
-    @setState(stepEntered: stepKey - 1)
-    @context.router.transitionTo('viewTaskStep', params)
-
   toggleMilestonesEntered: ->
     @setState(milestonesEntered: not @state.milestonesEntered)

@@ -243,8 +212,6 @@
       taskId={@props.id}
       courseId={courseId}
       goToStep={@goToStep}
-      onPartEnter={@onPartEnter}
-      onPartLeave={@onPartLeave}
       onNextStep={@onNextStep}
       refreshStep={@refreshStep}
       recoverFor={@recoverFor}


refactor search

refactor search

--- bootstrap-magic.coffee
+++ bootstrap-magic.coffee
@@ -102,13 +102,10 @@
   "previewTmpl" : -> Template["bootstrap_magic_preview_#{camelToSnake @_id}"] || null
   "inputTmpl" : -> Template["bootstrap_magic_input_#{@type}"] || null
   "typeIs" : (type) -> @type is type
-  "searchInactive" : -> true if searchTerms.get() is ""
+  "searchInactive" : -> !searchTerms.get()

 Template._bootstrap_magic.events
-  'keyup .magic-search' : (e) ->
-    e.preventDefault
-    searchVal = $(e.currentTarget).val()
-    searchTerms.set searchVal
+  'keyup .magic-search' : (e) -> searchTerms.set e.currentTarget.value

   'click .magic-filter-item' :(e) ->
     $filter = $(e.currentTarget)
@@ -117,9 +114,10 @@
     $('.magic-filter').html $filterTerms
     if $('.magic-filter-item').hasClass 'filtered'
       $('.magic-filter').removeClass "glyphicon glyphicon-filter"
+      # $filter.append $('')
     else
       $('.magic-filter').addClass "glyphicon glyphicon-filter"
-
+      # $filter.removeClass

   'change .bootstrap-magic-input' : (e) ->
     $input = $(e.currentTarget)


More comments on var naming.

More comments on var naming.

--- src/chaplin/application.coffee
+++ src/chaplin/application.coffee
@@ -1,13 +1,20 @@
 'use strict'

+# Third-party libraries.
 _ = require 'underscore'
 Backbone = require 'backbone'
-mediator = require 'chaplin/mediator'
+
+# JavaScript classes which are instantiated with `new`
 Dispatcher = require 'chaplin/dispatcher'
 Layout = require 'chaplin/views/layout'
 Composer = require 'chaplin/composer'
 Router = require 'chaplin/lib/router'
+
+# A mix-in that should be mixed to class.
 EventBroker = require 'chaplin/lib/event_broker'
+
+# Independent global event bus that is used by itself, so lowercased.
+mediator = require 'chaplin/mediator'

 # The bootstrapper is the entry point for Chaplin apps.
 module.exports = class Application
@@ -117,8 +124,8 @@
     # Mark app as initialized.
     @started = true

-    # Freeze the application instance to prevent further changes.
-    Object.freeze? this
+    # Seal the application instance to prevent further changes.
+    Object.seal? this

   # Disposal
   # --------
@@ -128,13 +135,9 @@
     # Am I already disposed?
     return if @disposed

-    # Check if object is already frozen.
-    frozen = Object.isFrozen? this
-
     properties = ['dispatcher', 'layout', 'router', 'composer']
     for prop in properties when this[prop]?
       this[prop].dispose()
-      delete this[prop] unless frozen

     @disposed = true


Small performance improvement in jquery selectors.

--- app/assets/javascripts/ng-services/ng-HighlightedEntrySvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-HighlightedEntrySvc.js.coffee
@@ -12,11 +12,10 @@
   set = (entry)->
     $rootScope.highlighted_entry = entry

-    entry_css_selector = "#feed-entries a[data-entry-id=#{entry.id}]"
-
+    entry_link = $("#feed-entries a[data-entry-id=#{entry.id}]")
     # Add CSS class "highlighted-entry" only to currently highlighted entry
-    $('#feed-entries a[data-entry-id].highlighted-entry').removeClass 'highlighted-entry'
-    $(entry_css_selector).addClass 'highlighted-entry'
+    entry_link.addClass 'highlighted-entry'
+    $("#feed-entries a[data-entry-id!=#{entry.id}].highlighted-entry").removeClass 'highlighted-entry'

   service =


Some basic information about ComponentLoader

--- src/lib/ComponentLoader.coffee
+++ src/lib/ComponentLoader.coffee
@@ -2,14 +2,24 @@
 #     (c) 2013-2017 Flowhub UG
 #     (c) 2013 Henri Bergius, Nemein
 #     NoFlo may be freely distributed under the MIT license
-#
-# This is the browser version of the ComponentLoader.
-internalSocket = require './InternalSocket'
 fbpGraph = require 'fbp-graph'
 {EventEmitter} = require 'events'
 registerLoader = require './loader/register'
 platform = require './Platform'

+# ## The NoFlo Component Loader
+#
+# The Component Loader is responsible for discovering components
+# available in the running system, as well as for instantiating
+# them.
+#
+# Internally the loader uses a registered, platform-specific
+# loader. NoFlo ships with a loader for Node.js that discovers
+# components from the current project's `components/` and
+# `graphs/` folders, as well as those folders of any installed
+# NPM dependencies. For browsers and embedded devices it is
+# possible to generate a statically configured component
+# loader using the [noflo-component-loader](https://github.com/noflo/noflo-component-loader) webpack plugin.
 class ComponentLoader extends EventEmitter
   constructor: (baseDir, options = {}) ->
     super()
@@ -21,12 +31,23 @@
     @ready = false
     @setMaxListeners 0 if typeof @setMaxListeners is 'function'

+  # Get the library prefix for a given module name. This
+  # is mostly used for generating valid names for namespaced
+  # NPM modules, as well as for convenience renaming all
+  # `noflo-` prefixed modules with just their base name.
+  #
+  # Examples:
+  #
+  # * `my-project` becomes `my-project`
+  # * `@foo/my-project` becomes `my-project`
+  # * `noflo-core` becomes `core`
   getModulePrefix: (name) ->
     return '' unless name
     return '' if name is 'noflo'
     name = name.replace /\@[a-z\-]+\//, '' if name[0] is '@'
-    name.replace 'noflo-', ''
-
+    name.replace /^noflo-/, ''
+
+  # Get the list of all available components
   listComponents: (callback) ->
     if @processing
       @once 'ready', =>
@@ -48,6 +69,10 @@
       callback null, @components if callback
     return

+  # Load an instance of a specific component. If the
+  # registered component is a JSON or FBP graph, it will
+  # be loaded as an instance of the NoFlo subgraph
+  # component.
   load: (name, callback, metadata) ->
     unless @ready
       @listComponents (err) =>
@@ -124,6 +149,7 @@

     callback null, instance

+  # Check if a given filesystem path is actually a graph
   isGraph: (cPath) ->
     # Live graph instance
     return true if typeof cPath is 'object' and cPath instanceof fbpGraph.Graph
@@ -133,10 +159,10 @@
     # Graph file path
     cPath.indexOf('.fbp') isnt -1 or cPath.indexOf('.json') isnt -1

+  # Load a graph as a NoFlo subgraph component instance
   loadGraph: (name, component, callback, metadata) ->
     @createComponent name, @components['Graph'], metadata, (err, graph) =>
       return callback err if err
-      graphSocket = internalSocket.createSocket()
       graph.loader = @
       graph.baseDir = @baseDir
       graph.inPorts.remove 'graph'
@@ -147,6 +173,11 @@
       return
     return

+  # Set icon for the component instance. If the instance
+  # has an icon set, then this is a no-op. Otherwise we
+  # determine an icon based on the module it is coming
+  # from, or use a fallback icon separately for subgraphs
+  # and elementary components.
   setIcon: (name, instance) ->
     # See if component has an icon
     return if not instance.getIcon or instance.getIcon()
@@ -179,17 +210,35 @@
     fullName = name unless packageId
     fullName

+  # ### Registering components at runtime
+  #
+  # In addition to components discovered by the loader,
+  # it is possible to register components at runtime.
+  #
+  # With the `registerComponent` method you can register
+  # a NoFlo Component constructor or factory method
+  # as a component available for loading.
   registerComponent: (packageId, name, cPath, callback) ->
     fullName = @normalizeName packageId, name
     @components[fullName] = cPath
     do callback if callback

+  # With the `registerGraph` method you can register new
+  # graphs as loadable components.
   registerGraph: (packageId, name, gPath, callback) ->
     @registerComponent packageId, name, gPath, callback

+  # With `registerLoader` you can register custom component
+  # loaders. They will be called immediately and can register
+  # any components or graphs they wish.
   registerLoader: (loader, callback) ->
     loader @, callback

+  # With `setSource` you can register a component by providing
+  # a source code string. Supported languages and techniques
+  # depend on the runtime environment, for example CoffeeScript
+  # components can only be registered via `setSource` if
+  # the environment has a CoffeeScript compiler loaded.
   setSource: (packageId, name, source, language, callback) ->
     unless registerLoader.setSource
       return callback new Error 'setSource not allowed'
@@ -202,6 +251,8 @@

     registerLoader.setSource @, packageId, name, source, language, callback

+  # `getSource` allows fetching the source code of a registered
+  # component as a string.
   getSource: (name, callback) ->
     unless registerLoader.getSource
       return callback new Error 'getSource not allowed'


Added brief documentation to proxy.coffee

--- proxy.coffee
+++ proxy.coffee
@@ -1,3 +1,28 @@
+# Crude proxy server for imitating implicit auth on the Readmill API. This
+# allows a browser client to authenticate without requiring a local server
+# to handle the authentication.
+#
+# This server requires four environment varibles to be present when running.
+#
+# PROXY_DOMAIN - Domain that the proxy is hosted on eg. (https://localhost:8080)
+# READMILL_CLIENT_ID - Client ID issued by Readmill when creating an app.
+# READMILL_CLIENT_SECRET - Secret issued by Readmill when creating an app.
+# READMILL_CLIENT_CALLBACK - Full url to the callback.html file on the client
+# server.
+# PORT - The port to run the app (default: 8000)
+#
+# Dependancies can be installed by running
+#
+#   $ npm install .
+#
+# Examples:
+#
+#   $ PORT=8000 \
+#     PROXY_DOMAIN=http://localhost:8000 \
+#     READMILL_CLIENT_ID=1234567890 \
+#     READMILL_CLIENT_SECRET=abcdefghijk \
+#     READMILL_CLIENT_CALLBACK=http://localhost:8001/callback.html \
+#     coffee proxy.coffee
 uuid = require("node-uuid").v4
 http = require "http"
 url  = require "url"
@@ -13,7 +38,7 @@
 throw "Requires PROXY_DOMAIN environment variable" unless PROXY_DOMAIN
 throw "Requires READMILL_CLIENT_ID environment variable" unless CLIENT_ID
 throw "Requires READMILL_CLIENT_SECRET environment variable" unless CLIENT_SECRET
-throw "Requires READMILL_CLIENT_CALLBACK environment variable" unless CLIENT_CALLBACK
+throw "Requires READMILL_CLIENT_CALLBACK environment variable" unless CLIENT_CALLBACK

 callbacks = {}


md: bind local links to zorium server

md: bind local links to zorium server

--- src/components/md/index.coffee
+++ src/components/md/index.coffee
@@ -4,6 +4,14 @@
   require './index.styl'

 module.exports = class Md
+  onMount: ($el) ->
+    _.map $el.querySelectorAll('a'), (anchor) ->
+      isLocal = anchor.host is window.location.host
+      if isLocal
+        anchor.onclick = (e) ->
+          e.preventDefault()
+          z.server.go anchor.href
+
   render: ({html}) ->
     z '.z-md',
       innerHTML: html


Tests: Complete tests of AccountCredentialListController

--- client/account/lib/test/accountcredentiallistcontroller.test.coffee
+++ client/account/lib/test/accountcredentiallistcontroller.test.coffee
@@ -2,9 +2,9 @@
 mock    = require '../../../mocks/mockingjay'
 expect  = require 'expect'
 remote  = require('app/remote').getInstance()
+KDView  = kd.View
 Promise = require 'bluebird'
-
-KDView  = kd.View
+Tracker = require 'app/util/tracker'

 KodingListController            = require 'app/kodinglist/kodinglistcontroller'
 AccountCredentialList           = require 'account/accountcredentiallist'
@@ -12,8 +12,19 @@

 mockCredential  = mock.getMockCredential()

-modelWithData   = some  : (query, options, callback) -> callback null, [ mockCredential ]
-modelWithNoData = some  : (query, options, callback) -> callback null, [ ]
+modelWithData   = some : (query, options, callback) -> callback null, [ mockCredential ]
+modelWithNoData = some : (query, options, callback) -> callback null, [ ]
+
+modal           = new kd.ModalView
+  buttons       :
+    Remove      :
+      title     : 'Remove'
+      loader    : yes
+    DestroyAll  :
+      title     : 'Destroy Everything'
+      loader    : yes
+    Cancel      :
+      title     : 'Cancel'

 describe 'AccountCredentialListController', ->
@@ -92,6 +103,7 @@
         callback null, mockCredential

       showCredentialEditModalSpy  = expect.spyOn listView, 'showCredentialEditModal'
+      trackerSpy                  = expect.spyOn Tracker, 'track'

       listController.loadItems()

@@ -101,10 +113,9 @@

       expect(fetchCredentialDataSpy).toHaveBeenCalled()
       expect(showCredentialEditModalSpy).toHaveBeenCalled()
+      expect(trackerSpy).toHaveBeenCalledWith Tracker.USER_EDIT_CREDENTIALS

     it 'should handle EditItem event and not call showCredentialEditModal method of listView', ->
-
-

       listView       = new AccountCredentialList
       listController = new AccountCredentialListController { model : modelWithData, view : listView }
@@ -123,6 +134,18 @@
       expect(fetchCredentialDataSpy).toHaveBeenCalled()
       expect(showCredentialEditModalSpy).toNotHaveBeenCalled()

+    it 'should show add form if there is no item', ->
+
+      provider       = 'aws'
+      listView       = new AccountCredentialList
+      listController = new AccountCredentialListController { model : modelWithData, view : listView, provider }
+
+      spy = expect.spyOn listController, 'showAddCredentialFormFor'
+
+      listController.emit 'FetchProcessSucceeded', { items: [] }
+
+      expect(spy).toHaveBeenCalledWith provider
+

   describe '::removeItem', ->

@@ -169,6 +192,122 @@

       expect(askForConfirmSpy).toHaveBeenCalled()

+    it 'should call removeCredential method if answer is Remove', ->
+
+      listView       = new AccountCredentialList
+      listController = new AccountCredentialListController { model : modelWithData, view : listView }
+
+      listController.loadItems()
+
+      item        = listController.getListItems().first
+      credential  = item.getData()
+
+      credential.inuse = no
+
+      item.setData credential
+
+      askForConfirmSpy  = expect.spyOn(listView, 'askForConfirm').andCall (params, callback) ->
+        modal.hide()
+        callback { action : 'Remove', modal }
+
+      removeCredentialSpy = expect.spyOn listController, 'removeCredential'
+
+      expect.spyOn(credential, 'isBootstrapped').andCall (callback) -> callback null, yes
+
+      listController.removeItem item
+
+      expect(removeCredentialSpy.calls.first.arguments.first).toBe item
+
+    it 'should call destroyResources method if answer is DestroyAll', ->
+
+      listView       = new AccountCredentialList
+      listController = new AccountCredentialListController { model : modelWithData, view : listView }
+
+      listController.loadItems()
+
+      item        = listController.getListItems().first
+      credential  = item.getData()
+
+      credential.inuse = no
+
+      item.setData credential
+
+      askForConfirmSpy  = expect.spyOn(listView, 'askForConfirm').andCall (params, callback) ->
+        modal.hide()
+        callback { action : 'DestroyAll', modal }
+
+      destroyResourcesSpy = expect.spyOn listController, 'destroyResources'
+
+      expect.spyOn(credential, 'isBootstrapped').andCall (callback) -> callback null, yes
+
+      listController.removeItem item
+
+      expect(destroyResourcesSpy.calls.first.arguments.first).toBe credential
+
+    it 'should hide loader of DestroyAll button and enable Remove button', ->
+
+      listView       = new AccountCredentialList
+      listController = new AccountCredentialListController { model : modelWithData, view : listView }
+
+      listController.loadItems()
+
+      item        = listController.getListItems().first
+      credential  = item.getData()
+
+      credential.inuse = no
+
+      item.setData credential
+
+      askForConfirmSpy  = expect.spyOn(listView, 'askForConfirm').andCall (params, callback) ->
+        modal.hide()
+        callback { action : 'DestroyAll', modal }
+
+      destroyResourcesSpy = expect.spyOn(listController, 'destroyResources').andCall (credential, callback) ->
+        callback new Error 'error!'
+
+      expect.spyOn(credential, 'isBootstrapped').andCall (callback) -> callback null, yes
+
+      hideLoaderSpy = expect.spyOn modal.buttons.DestroyAll, 'hideLoader'
+      enableSpy     = expect.spyOn modal.buttons.Remove, 'enable'
+
+      listController.removeItem item
+
+      expect(destroyResourcesSpy).toHaveBeenCalled()
+      expect(hideLoaderSpy).toHaveBeenCalled()
+      expect(enableSpy).toHaveBeenCalled()
+
+    it 'should call removeCredential method with given item if answer is DestroyAll', ->
+
+      listView       = new AccountCredentialList
+      listController = new AccountCredentialListController { model : modelWithData, view : listView }
+
+      listController.loadItems()
+
+      item        = listController.getListItems().first
+      credential  = item.getData()
+
+      credential.inuse = no
+
+      item.setData credential
+
+      askForConfirmSpy  = expect.spyOn(listView, 'askForConfirm').andCall (params, callback) ->
+        modal.hide()
+        callback { action : 'DestroyAll', modal }
+
+      destroyResourcesSpy = expect.spyOn(listController, 'destroyResources').andCall (credential, callback) ->
+        callback null
+
+      removeCredentialSpy = expect.spyOn listController, 'removeCredential'
+
+      expect.spyOn(credential, 'isBootstrapped').andCall (callback) -> callback null, yes
+
+      hideLoaderSpy = expect.spyOn modal.buttons.DestroyAll, 'hideLoader'
+      enableSpy     = expect.spyOn modal.buttons.Remove, 'enable'
+
+      listController.removeItem item
+
+      expect(removeCredentialSpy.calls.first.arguments.first).toBe item
+

   describe '::removeCredential', ->

@@ -179,17 +318,18 @@

       listController.loadItems()

-      kallback  = expect.createSpy()
-      item      = listController.getListItems().first
-      spy       = expect.spyOn listView, 'emit'
+      item        = listController.getListItems().first
+      kallback    = expect.createSpy()
+      emitSpy     = expect.spyOn listView, 'emit'
+      trackerSpy  = expect.spyOn Tracker, 'track'

       expect.spyOn(mockCredential, 'delete').andCall (callback) -> callback null

       listController.removeCredential item, kallback

       expect(kallback).toHaveBeenCalled()
-      expect(spy.calls.first.arguments.first).toEqual 'ItemDeleted'
-
+      expect(emitSpy.calls.first.arguments.first).toEqual 'ItemDeleted'
+      expect(trackerSpy).toHaveBeenCalledWith Tracker.USER_DELETE_CREDENTIALS

     it 'should not emit an event if any error', ->


ActivityAppController: Put back accidentally removed code.

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -52,6 +52,8 @@
     @status = KD.getSingleton "status"
     @status.on "reconnected", (conn)=>
       if conn?.reason is "internetDownForLongTime" then @refresh()
+
+    @on "activitiesCouldntBeFetched", => @listController?.hideLazyLoader()

   loadView:->
     @getView().feedWrapper.ready (controller)=>


Update UI: Minor UI update

Update UI: Minor UI update

--- views/battle-detail-area.cjsx
+++ views/battle-detail-area.cjsx
@@ -19,8 +19,8 @@
   if isCombined is false
     stageFlow = [StageType.AerialCombat, StageType.AerialCombat, StageType.Support, StageType.TorpedoSalvo, StageType.Shelling, StageType.Shelling, StageType.TorpedoSalvo, StageType.Shelling]
     stageTitle = [
-      "#{__ "Aerial Combat"} - Stage 3",
-      "#{__ "Aerial Combat"} - Stage 3",
+      "#{__ "Aerial Combat"}",
+      "#{__ "Aerial Combat"}",
       "#{__ 'Expedition Supporting Fire'}",
       "#{__ 'Opening Torpedo Salvo'}",
       "#{__ 'Shelling'}",
@@ -32,8 +32,8 @@
   if isCombined is true and isCarrier true
     stageFlow = [StageType.AerialCombat, StageType.AerialCombat, StageType.Support, StageType.TorpedoSalvo, StageType.Shelling, StageType.TorpedoSalvo, StageType.Shelling, StageType.Shelling, StageType.Shelling]
     stageTitle = [
-      "#{__ "Aerial Combat"} - Stage 3",
-      "#{__ "Aerial Combat"} - Stage 3",
+      "#{__ "Aerial Combat"}",
+      "#{__ "Aerial Combat"}",
       "#{__ 'Expedition Supporting Fire'}",
       "#{__ 'Opening Torpedo Salvo'}",
       "#{__ 'Shelling'} - #{__ 'Escort Fleet'}",
@@ -46,8 +46,8 @@
   if isCombined is true and isCarrier is false
     stageFlow = [StageType.AerialCombat, StageType.AerialCombat, StageType.Support, StageType.TorpedoSalvo, StageType.Shelling, StageType.Shelling, StageType.Shelling, StageType.TorpedoSalvo, StageType.Shelling]
     stageTitle = [
-      "#{__ "Aerial Combat"} - Stage 3",
-      "#{__ "Aerial Combat"} - Stage 3",
+      "#{__ "Aerial Combat"}",
+      "#{__ "Aerial Combat"}",
       "#{__ 'Expedition Supporting Fire'}",
       "#{__ 'Opening Torpedo Salvo'}",
       "#{__ 'Shelling'} - #{__ 'Main Fleet'}",


DEMO: add some more blocks to the block demo

--- demo/src/demos/BlockDemo.coffee
+++ demo/src/demos/BlockDemo.coffee
@@ -16,10 +16,11 @@

 		@demo_table.addExample("Blocks", @createBlocks() )
 		@demo_table.addExample("Blocks with line separator mixin", @createSimpleBlocks("cui-block-demo-separator") )
+		@demo_table.addExample("Blocks appearance wide and padded", @createSimpleBlocksWide() )
+		@demo_table.addExample("Blocks appearance wide and NOT padded", @createSimpleBlocksWideNotPadded() )

 		@createWaitBlockExample()

-
 		@demo_table.table

 	createSimpleBlocks: (style_class= "") ->
@@ -45,6 +46,89 @@
 						],
 					new CUI.Block
 						text: "Title of block C"
+						content: [
+							new CUI.Label
+								text: "content of main block"
+
+						]
+
+				]
+		list.DOM
+
+
+	createSimpleBlocksWide: (style_class= "") ->
+
+		list = new CUI.VerticalList
+			maximize: true
+			class: style_class
+			content:
+				[
+					new CUI.Block
+						text: "Wide block A"
+						appearance: "wide"
+						level: 1
+						content: [
+							new CUI.Label
+								text: "content of main block"
+
+						],
+					new CUI.Block
+						text: "Wide block B"
+						appearance: "wide"
+						level: 2
+						content: [
+							new CUI.Label
+								text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+								multiline: true
+
+						],
+					new CUI.Block
+						text: "Wide block C"
+						appearance: "wide"
+						level: 2
+						content: [
+							new CUI.Label
+								text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+								multiline: true
+
+						]
+
+				]
+		list.DOM
+
+
+	createSimpleBlocksWideNotPadded: (style_class= "") ->
+
+		list = new CUI.VerticalList
+			maximize: true
+			class: style_class
+			content:
+				[
+					new CUI.Block
+						text: "Wide block A - Level 1"
+						appearance: "wide"
+						padded: false
+						level: 1
+						content: [
+							new CUI.Label
+								text: "content of main block"
+
+						],
+					new CUI.Block
+						text: "Wide block B - Level 2"
+						appearance: "wide"
+						padded: false
+						level: 2
+						content: [
+							new CUI.Label
+								text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+								multiline: true
+						],
+					new CUI.Block
+						text: "Wide block C - Level 3"
+						appearance: "wide"
+						padded: false
+						level: 3
 						content: [
 							new CUI.Label
 								text: "content of main block"
@@ -90,19 +174,20 @@
 			content:
 				[
 					new CUI.Block
-						text: "Title of main block"
+						text: "Title of main block (level 1)"
 						appearance: "normal"
+						description: "Some sort of block description text"
 						content: [
 							new CUI.Label
 								text: "content of main block"
 							new CUI.Block
-								text: "Subtitle of main block"
+								text: "Subtitle of main block (level 2)"
 								level: 2
 								content: [
 									new CUI.Label
 										text: "content of subtitle block"
 									new CUI.Block
-										text: "normal block header"
+										text: "normal block header (level 3)"
 										level: 3
 										content: [
 											new CUI.Label
@@ -110,20 +195,20 @@
 										]
 								]
 							new CUI.Block
-								text: "2nd Subtitle of main block"
+								text: "2nd Subtitle of main block (level 2)"
 								level: 2
 								content: [
 									new CUI.Label
 										text: "content of subtitle block"
 									new CUI.Block
 										level: 3
-										text: "normal block header"
+										text: "normal block header (level 3)"
 										content: [
 											new CUI.Label
 												text: "content of normal block."
 										]
 									new CUI.Block
-										text: "2nd normal block header"
+										text: "2nd normal block header (level 3)"
 										level: 3
 										content: [
 											new CUI.Label
@@ -136,4 +221,4 @@
 		list.DOM

-Demo.register(new Demo.BlockDemo())+Demo.register(new Demo.BlockDemo())


Don't validate version until checking for empty  range

--- src/deprecated-packages.coffee
+++ src/deprecated-packages.coffee
@@ -12,11 +12,11 @@

 exports.isDeprecatedPackage = (name, version) ->
   return false unless deprecatedPackages.hasOwnProperty(name)
-  return false unless semver.valid(version)

   deprecatedVersionRange = deprecatedPackages[name].version
   return true unless deprecatedVersionRange
-  satisfies(version, deprecatedVersionRange)
+
+  semver.valid(version) and satisfies(version, deprecatedVersionRange)

 satisfies = (version, rawRange) ->
   unless parsedRange = ranges[rawRange]


fixes pillbox spec

fixes pillbox spec

--- components/commercial_filter/views/pillbox/test/view.coffee
+++ components/commercial_filter/views/pillbox/test/view.coffee
@@ -3,6 +3,7 @@
 sinon = require 'sinon'
 Backbone = require 'backbone'
 Params = require '../../../models/params'
+categories = require '../../../../../apps/browse2/fixtures/categories.json'
 { resolve } = require 'path'

 describe 'PillboxView', ->
@@ -19,14 +20,18 @@
     benv.teardown()

   beforeEach ->
-    @params = new Params
+    paramAttrs =
       medium: 'painting'
       gene_id: 'abstract-art'
       price_range: '1000-20000'
       width: '24.00-120.00'
       height: '1.00-107.00'
+    @params = new Params paramAttrs, categoryMap: categories
     @artworks = new Backbone.Collection
-    @view = new @PillboxView params: @params, artworks: @artworks
+    @view = new @PillboxView
+      params: @params
+      artworks: @artworks
+      categoryMap: categories

   describe '#category', ->
     it 'gets the proper category if medium and gene_id are set', ->
@@ -42,9 +47,9 @@

   describe '#size', ->
     it 'gets the proper size if attribute is set', ->
-      @view.size('Height', 'height').should.eql 'Height: 1 – 107 in.'
-      @view.size('Width', 'width').should.eql 'Width: 24 – 120+ in.'
+      @view.size('Height', 'height').should.eql 'Height: 1 – 107 in'
+      @view.size('Width', 'width').should.eql 'Width: 24 – 120+ in'

   describe '#price', ->
     it 'gets the proper size if attribute is set', ->
-      @view.price().should.eql '$1,000 – $20,000'
+      @view.price().should.eql '$1,000 – 20,000'


implement a few more integration tests

implement a few more integration tests

--- integration_test/cobalt.coffee
+++ integration_test/cobalt.coffee
@@ -75,9 +75,23 @@
         settings.publish_token.should.match /[0-9a-z]{15}/
         done()

-    it 'I can see my README.md'
-    it 'I can see my git repo'
-    it 'I cannot see any other box'
+    it 'I can see my README.md', (done) ->
+      ssh_cmd "ls ~/README.md", (err, stdout, stderr) ->
+        should.not.exist err
+        stderr.should.be.empty
+        done()
+
+    it 'I can see my git repo', (done) ->
+      ssh_cmd "git status", (err, stdout, stderr) ->
+        should.not.exist err
+        stderr.should.be.empty
+        done()
+
+    it "I cannot see any other box (i.e. I'm chrooted)", (done) ->
+      ssh_cmd "ls -di", (err, stdout, stderr) ->
+        should.not.exist err
+        stdout.should.not.match /2 \//
+        done()

   describe 'When I publish some files', ->
     before (done) ->


Only dump symbols on Mac OS X

Only dump symbols on Mac OS X

--- build/Gruntfile.coffee
+++ build/Gruntfile.coffee
@@ -295,7 +295,7 @@
   ciTasks.push('download-electron-chromedriver')
   ciTasks.push('build')
   ciTasks.push('fingerprint')
-  ciTasks.push('dump-symbols') if process.platform isnt 'win32'
+  ciTasks.push('dump-symbols') if process.platform is 'darwin'
   ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar')
   ciTasks.push('mkdeb') if process.platform is 'linux'
   ciTasks.push('codesign:exe') if process.platform is 'win32' and not process.env.CI


updated market

updated market

--- client/app/collections/application.coffee
+++ client/app/collections/application.coffee
@@ -47,12 +47,19 @@
                 comment:"official application"
                 description:"Backup your inbox and browse them from your cozy."
             ,
-                icon:"img/boonk-icon.png"
-                name:"boonk"
-                slug:"boonk"
-                git:"https://github.com/frankrousseau/boonk.git"
-                comment:"community contribution"
-                description:"Aggregate your bank account data (for French citizen only)."
+                icon:"img/photos-icon.png"
+                name:"photos"
+                slug:"photos"
+                git:"https://github.com/mycozycloud/cozy-photos.git"
+                comment:"official application"
+                description:"Share photo with your friends."
+            ,
+                icon:"img/agenda-icon.png"
+                name:"agenda"
+                slug:"agenda"
+                git:"https://github.com/mycozycloud/cozy-agenda.git"
+                comment:"official application"
+                description:"Set up reminders and let cozy be your assistant"
         ]
         @reset apps
         callback null, apps  if callback?


Socialapi: createChannelWithParticipants endpoint moved to channel and renamed mapperFunctions

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -52,7 +52,7 @@
     fn = switch dataPath
       when 'followedChannels' then mapChannels
       when 'popularPosts', 'pinnedMessages', 'navigated' then mapActivities
-      when 'privateMessages'                   then mapPrivateMessages
+      when 'privateMessages'                   then mapCreatedChannel
       when 'bot' then mapBotChannel

     return fn(data) or []
@@ -207,8 +207,8 @@
       callback  kd.getSingleton("groupsController").getCurrentGroup()

-  mapPrivateMessages: mapPrivateMessages
-  mapPrivateMessages = (messages) ->
+  mapCreatedChannel: mapCreatedChannel
+  mapCreatedChannel = (messages) ->

     messages = [].concat(messages)
     return [] unless messages?.length > 0
@@ -617,34 +617,29 @@
       fnName             : 'listLikers'
       validateOptionsWith: ['id']

-    createChannelWithParticipants   : messageRequesterFn
-      fnName                        : 'createChannelWithParticipants'
-      validateOptionsWith           : ['body', 'recipients']
-      mapperFn                      : mapPrivateMessages
-
     sendMessageToChannel : messageRequesterFn
       fnName             : 'sendMessageToChannel'
       validateOptionsWith: ['body', 'channelId']
-      mapperFn           : mapPrivateMessages
+      mapperFn           : mapCreatedChannel

     initPrivateMessage   : messageRequesterFn
       fnName             : 'initPrivateMessage'
       validateOptionsWith: ['body', 'recipients']
-      mapperFn           : mapPrivateMessages
+      mapperFn           : mapCreatedChannel

     sendPrivateMessage   : messageRequesterFn
       fnName             : 'sendPrivateMessage'
       validateOptionsWith: ['body', 'channelId']
-      mapperFn           : mapPrivateMessages
+      mapperFn           : mapCreatedChannel

     search               : messageRequesterFn
       fnName             : 'search'
       validateOptionsWith: ['name']
-      mapperFn           : mapPrivateMessages
+      mapperFn           : mapCreatedChannel

     fetchPrivateMessages : messageRequesterFn
       fnName             : 'fetchPrivateMessages'
-      mapperFn           : mapPrivateMessages
+      mapperFn           : mapCreatedChannel

     create               : channelRequesterFn
       fnName             : 'create'
@@ -675,6 +670,11 @@
     list                 : channelRequesterFn
       fnName             : 'fetchChannels'
       mapperFn           : mapChannels
+
+    createChannelWithParticipants   : channelRequesterFn
+      fnName                        : 'createChannelWithParticipants'
+      validateOptionsWith           : ['body', 'recipients']
+      mapperFn                      : mapCreatedChannel

     fetchActivities      : (options = {}, callback = kd.noop)->


Workspace: Use KDView instead JView, no need to compile a pistachio template for one widget

--- client/landing/Workspace/workspace.coffee
+++ client/landing/Workspace/workspace.coffee
@@ -1,4 +1,4 @@
-class Workspace extends JView
+class Workspace extends KDView

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

@@ -73,10 +73,5 @@
     container.setHeight panel.getHeight() - header.getHeight()  if header

   viewAppended: ->
-    super
+    @addSubView @container
     @_windowDidResize()
-
-  pistachio: ->
-    """
-      {{> @container}}
-    """


Fixed a bug in the config script

Fixed a bug in the config script

--- lib/config.coffee
+++ lib/config.coffee
@@ -80,16 +80,16 @@
     @updateFontDisposable = atom.config.observe 'ambiance-pro-ui.fontFamily', @updateFont
     @updateFontSizeDisposable = atom.config.observe 'ambiance-pro-ui.fontSize', @updateFontSize
     @updateIconsDisposable = atom.config.observe 'ambiance-pro-ui.iconTheme', @updateIcons
-    @setThemeDisposable = atom.config.onDidChange 'ambiance-pro-ui.theme', @setTheme
+    # @setThemeDisposable = atom.config.onDidChange 'ambiance-pro-ui.theme', @setTheme

     @onDidChangeActiveThemesDisposable = atom.themes.onDidChangeActiveThemes @refresh
-    return @setTheme()
+    # return @setTheme()

   destroy: () ->
     @updateFontDisposable.dispose()
     @updateFontSizeDisposable.dispose()
     @updateIconsDisposable.dispose()
-    @setThemeDisposable.dispose()
+    # @setThemeDisposable.dispose()
     @onDidChangeActiveThemesDisposable.dispose()

   refresh: () =>


fix events list method

fix events list method

--- UoACalendarClient.coffee
+++ UoACalendarClient.coffee
@@ -285,7 +285,7 @@
     # ```
     #
     listEvents: (calendarId, onSuccess, onError) ->
-        @sendRequest('/calendars/' + calendarId + '/events/', 'GET', 0, onSuccess, onError)
+        @sendRequest('/calendars/' + calendarId + '/events/?format=json', 'GET', 0, onSuccess, onError)

     # Add a new event to an existing calendar given its ID
     #


Activate timecop package to track Atom performance

--- atom/config.cson
+++ atom/config.cson
@@ -31,7 +31,6 @@
       "open-on-github"
       "release-notes"
       "script"
-      "timecop"
       "update-package-dependencies"
       "welcome"
       "whitespace"


Change default port to 9000

Change default port to 9000

This will prevent conflicts with Tutor, allowing both to run concurrently.

--- webpack-helper/configs.coffee
+++ webpack-helper/configs.coffee
@@ -2,7 +2,7 @@
 ExtractTextPlugin = require 'extract-text-webpack-plugin'
 webpackUMDExternal = require 'webpack-umd-external'

-DEV_PORT = process.env['PORT'] or 8000
+DEV_PORT = process.env['PORT'] or 9000
 DEV_LOADERS = ['react-hot', 'webpack-module-hot-accept']

 # base config, true for all builds no matter what conditions


chore(atom/config.cson): update atom/config.cson

Notable change:

  - add `file-header` plugin settings

--- atom/config.cson
+++ atom/config.cson
@@ -54,7 +54,9 @@
       "autocomplete-java"
       "linter-javac"
     ]
-    packagesWithKeymapsDisabled: []
+    packagesWithKeymapsDisabled: [
+      "file-header"
+    ]
     telemetryConsent: "limited"
     themes: [
       "atom-material-ui"
@@ -75,12 +77,20 @@
     splitright: true
   "exception-reporting":
     userId: "5f1fd872-de33-9d23-b5da-da0fbe791e6c"
+  "file-header":
+    dateTimeFormat: "YYYY-MM-DD HH:mm:ss ZZ"
+    email: "shoichiaizawa@gmail.com"
+    license: "MIT"
+    realname: "Shoichi Aizawa"
+    username: "shoichiaizawa"
   "file-icons": {}
   "git-plus":
     general:
       _analyticsUserId: "531f1de0-9539-4faa-9854-c3bf2d523b05"
   jumpy:
     fontSize: 1
+  "linter-ui-default":
+    panelHeight: 81
   "markdown-preview":
     liveUpdate: false
     useGitHubStyle: true


update atom config

update atom config

--- atom/config.cson
+++ atom/config.cson
@@ -1,8 +1,11 @@
 "*":
+  "autocomplete-plus":
+    autoActivationDelay: 500
   core:
     disabledPackages: [
       "wrap-guide"
       "spell-check"
+      "language-hyperlink"
     ]
     ignoredNames: [
       ".git"
@@ -14,6 +17,7 @@
       "desktop.ini"
       ".byebug_history"
     ]
+    openEmptyEditorOnStart: false
     projectHome: "/Users/meyer/Code"
     telemetryConsent: "no"
   editor:


Change Atom theme to Solarized Dark

Change Atom theme to Solarized Dark

--- atom/config.cson
+++ atom/config.cson
@@ -32,7 +32,7 @@
     telemetryConsent: "limited"
     themes: [
       "atom-dark-ui"
-      "atom-dark-syntax"
+      "solarized-dark-syntax"
     ]
     titleBar: "custom"
   date:


Re-enable whitespace package with features disabled

This gives me access to the 'Remove Trailing Whitespace' command without
having it modify my files automatically (since that responsibility is
reserved for editorconfig).

--- atom/config.cson
+++ atom/config.cson
@@ -31,7 +31,6 @@
       "timecop"
       "update-package-dependencies"
       "welcome"
-      "whitespace"
       "teletype"
     ]
     followSymlinks: false
@@ -135,7 +134,9 @@
   welcome:
     showOnStartup: false
   whitespace:
+    ensureSingleTrailingNewline: false
     ignoreWhitespaceOnCurrentLine: false
+    removeTrailingWhitespace: false
 ".basic.html.text":
   editor:
     nonWordCharacters: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"


Add TODO

Add TODO

--- atom/init.coffee
+++ atom/init.coffee
@@ -18,6 +18,9 @@

 # Delete to end of line **without** modifying the pasteboard. Useful as an
 # alternative to Atom's built-in 'editor:cut-to-end-of-line' command.
+#
+# TODO Change this to delete to the VERY end of the line, regardless of whether
+# the line is wrapped.
 atom.workspaceView.command 'dot-atom:delete-to-end-of-line', '.editor', ->
   editor = atom.workspaceView.getActiveView().getEditor()
   editor.selectToEndOfLine()


Don't convert format for Collection either

--- src/interfaces/json_api.coffee
+++ src/interfaces/json_api.coffee
@@ -60,7 +60,7 @@
         if _.isArray(v)
           _.map v, (i) ->
             toUnderscored(i)
-        else if _.isObject(v) && !v.isA?(ActiveResource::Base)
+        else if _.isObject(v) && !v.isA?(ActiveResource::Base) && !v.isA?(ActiveResource::Collection)
           toUnderscored(v)
         else
           v
@@ -81,7 +81,7 @@
         if _.isArray(v)
           _.map v, (i) ->
             toCamelCase(i)
-        else if _.isObject(v) && !v.isA?(ActiveResource::Base)
+        else if _.isObject(v) && !v.isA?(ActiveResource::Base) && !v.isA?(ActiveResource::Collection)
           toCamelCase(v)
         else
           v


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


surface-go.coffee: Updating links to getting started guide

Signed-off-by: Gareth Davies <2f9181a725196cd0a5e07c6a6e161d83fcc71157@balena.io>


interpolate

interpolate

--- test/point.coffee
+++ test/point.coffee
@@ -141,6 +141,13 @@
     equalEnough p.x, 0, TOLERANCE
     equals p.y, 1

+  test ".interpolate", ->
+    p1 = Point(10, 7)
+    p2 = Point(-6, 29)
+
+    ok p1.equal(Point.interpolate(p1, p2, 0))
+    ok p2.equal(Point.interpolate(p1, p2, 1))
+
   test "ZERO is immutable", ->
     zero= Point.ZERO


Added in missing tests, data was in place but no test cases.

--- test/tests.coffee
+++ test/tests.coffee
@@ -295,6 +295,12 @@
 rename from a/My Folder/File
 rename to My Folder/a/File
 """
+		files = parse diff
+		expect(files.length).to.be(1)
+		file = files[0]
+		expect(file.from).to.be('My Folder/File')
+		expect(file.to).to.be('My Folder/a/File')
+		expect(file.chunks.length).to.be(0)

 	it 'should parse rename diff with space in path with changes', ->
 		diff = """
@@ -306,3 +312,14 @@
 - line1
 + line2
 """
+		files = parse diff
+		expect(files.length).to.be(1)
+		file = files[0]
+		expect(file.from).to.be('My Folder/File')
+		expect(file.to).to.be('My Folder/a/File')
+		expect(file.chunks.length).to.be(1)
+		chunk = file.chunks[0]
+		expect(chunk.content).to.be('@@ -1,2 +1,2 @@')
+		expect(chunk.changes.length).to.be(2)
+		expect(chunk.changes[0].content).to.be('- line1')
+		expect(chunk.changes[1].content).to.be('+ line2')


Test that jsonparser honors the content type

--- test/tests.coffee
+++ test/tests.coffee
@@ -72,3 +72,19 @@
         .get "#{ testServerUrl }/getjson", (err, res) ->
           assert.deepEqual res.body, hello: 'world'
           done()
+
+    parseWithContentType = (ct, isJsonType = true) ->
+      res =
+        contentType: ct
+        body: '{"hello": "world"}'
+      plugins.jsonparser.processResponse res
+      if isJsonType then assert.deepEqual res.body, hello: 'world'
+      else assert.equal res.body, '{"hello": "world"}'
+
+    it 'honors the content type', ->
+      parseWithContentType 'application/json'
+      parseWithContentType 'text/json'
+      parseWithContentType 'text/json'
+      parseWithContentType 'text/something+json'
+      parseWithContentType 'application/json; charset=utf-8'
+      parseWithContentType 'application/jsonp', false


SocialWorker: remove console.log

SocialWorker: remove console.log

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -360,8 +360,8 @@
       , (err, machine)->

         if err? or not machine
-          console.log "Failed to find machine for #{username}", err
-
+          # discard any error or not found cases
+          # console.log "Failed to find machine for #{username}", err
         else

           newDomain = "#{machine.uid}.#{username}.#{KONFIG.userSitesDomain}"


Fig bug where global DOM id "canvas" is read.

--- engine/render.coffee
+++ engine/render.coffee
@@ -8,6 +8,7 @@
 {Events} = require './events'

 VECTOR_MINUS_Z = vec3.new 0,0,-1
+canvas = undefined # avoid bugs where the global id "canvas" is read

 # Render manager singleton. Performs all operations related to rendering to screen or to a buffer.
 #
@@ -74,7 +75,7 @@
         else if @gl?
             console.warn "There's already a GL context. Set reinstance to true to change GL flags."
         try
-            gl = canvas.getContext("webgl", glflags) or canvas.getContext("experimental-webgl", glflags)
+            gl = @canvas.getContext("webgl", glflags) or @canvas.getContext("experimental-webgl", glflags)
         catch e
             null

@@ -85,7 +86,7 @@
             # Try disabling multisampling
             # (Chrome is not following the specification by rejecting to create the context)
             glflags.antialias = false
-            gl = canvas.getContext("webgl", glflags)
+            gl = @canvas.getContext("webgl", glflags)

         if not gl
             @context.MYOU_PARAMS.on_webgl_failed?()


Render: Allow scaling of camera without affecting lights.

--- engine/render.coffee
+++ engine/render.coffee
@@ -616,7 +616,22 @@
         debug = @debug
         filter_fb = @common_filter_fb

-        cam2world = mat4.copy @_cam2world, cam.world_matrix
+        # Create cam2world from camera world matrix but ignoring scale
+        cam_rm = cam.rotation_matrix
+        cam_wm = cam.world_matrix
+        cam2world = @_cam2world
+        cam2world[0] = cam_rm[0]
+        cam2world[1] = cam_rm[1]
+        cam2world[2] = cam_rm[2]
+        cam2world[4] = cam_rm[3]
+        cam2world[5] = cam_rm[4]
+        cam2world[6] = cam_rm[5]
+        cam2world[8] = cam_rm[6]
+        cam2world[9] = cam_rm[7]
+        cam2world[10] = cam_rm[8]
+        cam2world[12] = cam_wm[12]
+        cam2world[13] = cam_wm[13]
+        cam2world[14] = cam_wm[14]
         world2cam = @_world2cam
         world2cam3 = @_world2cam3
         world2cam_mx = @_world2cam_mx


use activerest API mock for user data

use activerest API mock for user data

Former-commit-id: 0f8bca330d90d10800a1cbd73004e538baa9da86 [formerly 6e862cae23eee2d4d6ed0aa8c9e463e010102f84] [formerly a0a8ea0c54728c5290dea2baefa3a36152ab2067 [formerly 634eb76dcfb9d3fe416861c8d337666f198c3889]] [formerly 98aee853ae182706bf743f7f652eeb860c428939 [formerly 686ab57eaee911aecb45a5e042a14cfcd6df295a] [formerly 27e542880d7c61b3abedab05d73a106a82135095 [formerly 27e542880d7c61b3abedab05d73a106a82135095 [formerly 6c2bf5339d8a30501c2d656606017c2404aeae42]]]]
Former-commit-id: 73b235941f510cac280f65f0cb189cd07bf4e5a1 [formerly 09d6921b53f8dc83f5b77fc5fd71faf2051d38dd] [formerly 8f59a7d07011bd7a269bba012f0ed6135c347938 [formerly 58403b68140921fe637ef6d30da980017f512b92]]
Former-commit-id: 0a7e0e20c5443d2e303b49d3f1fa36386db15df6 [formerly 6f6f3bfb1ef1f32ad6849af28781eabc9a1a0cc0]
Former-commit-id: f5c0c33bf6eada4ae16834230c2c93a38337bf32
Former-commit-id: 7a73865a8610509ec333fc1cca0355afbf2fecd4

--- @client/components/franklin.coffee
+++ @client/components/franklin.coffee
@@ -26,9 +26,8 @@
 biggest_possible_avatar_size = 50

 ####################
-# REACT COMPONENTS #
-####################
-
+# React Components
+#
 # These are the components and their relationships:
 #                       Proposal
 #                   /      |            \
@@ -46,7 +45,7 @@
 # Proposal
 # The mega component for a proposal.
 # Has proposal description, feelings area (slider + histogram), and reasons area
-window.REACTProposal = React.createClass
+Proposal = React.createClass
   displayName: 'Proposal'

   getDefaultProps : ->
@@ -647,10 +646,8 @@
       className : "#{@props.className} avatar"
       id : "avatar-#{@props.user}"

-
     if @props.img_style
-      # TODO: use activeREST here
-      user = all_users[@props.user]
+      user = fetch {url: "users/#{@props.user}?partial"}
       if !user || !user.avatar_file_name
         derived_state.filename = "/system/default_avatar/#{@props.img_style}_default-profile-pic.png"
       else
@@ -673,26 +670,13 @@
 # Responsibilities that will later be managed by ActiveREST
 all_users = {}

-parseProposal = (data) ->
-  # Build hash of user information
-  data.users = $.parseJSON data.users
-  for user in data.users
-    all_users[user.id] = user
-
-  all_points = {}
-
-  #TODO: return from server as a hash already?
-  for point in data.points
-    all_points[point.id] = point
-
-  data.points = all_points
-
-  data
-
 ##
 #API mocks for activeREST

 fetch = (options, callback, error_callback) ->
+  if options.url[0..3] == 'user'
+    return all_users[options.url]
+
   error_callback ||= (xhr, status, err) -> console.error 'Could not fetch data', status, err.toString()

   $.ajax
@@ -700,7 +684,19 @@
     dataType: 'json'
     success: (data) =>
       if options.type == 'proposal'
-        data = parseProposal data
+        # Build hash of user information
+        data.users = $.parseJSON data.users
+        for user in data.users
+          all_users["users/#{user.id}?partial"] = user
+
+        all_points = {}
+
+        #TODO: return from server as a hash already?
+        for point in data.points
+          all_points[point.id] = point
+
+        data.points = all_points
+
       console.log data
       callback data

@@ -727,7 +723,7 @@
   proposal : (long_id, state = 'crafting') ->

     if !top_level_component
-      top_level_component = React.renderComponent window.REACTProposal(
+      top_level_component = React.renderComponent Proposal(
         state : state
         priorstate : null
       ), document.getElementById('l_content_main_wrap')


(- fix) Hack around a bug in tput

(- fix) Hack around a bug in tput

--- Paws/Source/additional.coffee
+++ Paws/Source/additional.coffee
@@ -9,6 +9,10 @@
       use_colour = true # Default
       verbosity = 4 # Default
       environment_verbosity = Infinity
+
+      constructor: ->
+         # FIXME: This `require` will break browserify.
+         @tput = new (require('blessed').Tput) term: process.env['TERM']

       # This is an exposed, bi-directional mapping of verbosity-names:
       #
@@ -18,8 +22,6 @@
          "emergency alert critical error warning notice info debug verbose wtf".split(' ')
       verbosities[name] = minimum for name, minimum in verbosities

-      # FIXME: This'll break on the web.
-      tput: new (require('blessed').Tput)

       write_browser = (console?.error || console?.log || noop).bind console
       write_cli = (objects...)->


Fix Atom config for Makefiles

Fix Atom config for Makefiles

--- dotfiles/atom/.atom/config.cson
+++ dotfiles/atom/.atom/config.cson
@@ -36,7 +36,6 @@
     softWrap: true
     softWrapAtPreferredLineLength: true
     softWrapHangingIndent: 2
-    tabType: "soft"
   "exception-reporting":
     userId: "f96e777f-ace7-9fe4-3f87-ac9f33d8e474"
   "haskell-ghc-mod":
@@ -75,6 +74,11 @@
 ".latex.tex.text":
   editor:
     softWrapAtPreferredLineLength: false
+".makefile.source":
+  editor:
+    softTabs: false
+    softWrapHangingIndent: 4
+    tabLength: 4
 ".tex.text":
   editor:
     softWrapAtPreferredLineLength: false


Don't assume that expect is available as a global


remove unnecessary space

remove unnecessary space

--- app/assets/javascripts/controllers/journal_thumbnail_controller.js.coffee
+++ app/assets/javascripts/controllers/journal_thumbnail_controller.js.coffee
@@ -1,7 +1,7 @@
 ETahi.JournalThumbnailController = Ember.ObjectController.extend
   needs: ['application']
   currentUser: Ember.computed.alias 'controllers.application.currentUser'
-  isEditing: (-> @get 'model.isDirty' ).property()
+  isEditing: (-> @get 'model.isDirty').property()

   nameErrors: null
   descriptionErrors: null


[fix] Prevented the linear regressions from stretching the width of the Milestone Burndown Chart into the ridiculous future (40m)

--- app/assets/javascripts/houston-scheduler/views/show_milestone_view.coffee
+++ app/assets/javascripts/houston-scheduler/views/show_milestone_view.coffee
@@ -73,8 +73,12 @@
       regLast3 = @computeRegression(data.slice(-4))     if data.length >= 4  # last 3 weeks only
       regLast2 = @computeRegression(data.slice(-3))     if data.length >= 3  # last 2 weeks only

+    width = mostRecentDataPoint - firstSprint
+    maxDate = @getEndOfSprint(mostRecentDataPoint + width)
+    console.log 'earliestDataPoint', new Date(firstSprint)
     console.log 'mostRecentDataPoint', new Date(mostRecentDataPoint)
     console.log 'lastCompleteSprint', new Date(lastCompleteSprint)
+    console.log "width: #{(width / Duration.DAY).toFixed(1)} days"

     console.log 'regAll', new Date(regAll.x2) if regAll
     console.log 'regLast3', new Date(regLast3.x2) if regLast3
@@ -88,6 +92,7 @@
     sprints = (d.sprint for d in data).sort()
     if projectedEnd = projections.max()
       lastSprint = @getEndOfSprint(projectedEnd)
+      lastSprint = maxDate if lastSprint > maxDate
       sprint = _.last(sprints)
       while sprint < lastSprint
         sprint = @nextSprint(sprint)