:palm_tree::punch: Updated in browser at strd6.github.io/editor

--- pixie.cson
+++ pixie.cson
@@ -8,7 +8,7 @@
 dependencies:
   "jquery-utils": "STRd6/jquery-utils:v0.1.2"
   runtime: "STRd6/runtime:v0.1.1"
-  "touch-canvas": "STRd6/touch-canvas:v0.2.0-alpha.16"
+  "touch-canvas": "STRd6/touch-canvas:v0.2.0-alpha.17"
   "commando": "STRd6/commando:v0.9.0"
 width: 480
 height: 320


Also log error.code

Also log error.code

--- nylas-connection.coffee
+++ nylas-connection.coffee
@@ -82,6 +82,9 @@
 logOnError = (error, response, body) ->
   console.log('nylas-connection#request error: ', error.toString())

+  if error.code?
+    console.log('nylas-connection#request error.code: ', error.code)
+
   if error.stack
     console.log('nylas-connection#request stack: ', error.stack)


remove console log

remove console log

--- lib/views/git-diff-branch-file-chooser.coffee
+++ lib/views/git-diff-branch-file-chooser.coffee
@@ -14,5 +14,4 @@
       args = ['diff', '--name-status', repo.branch, name]
       git.cmd(args, cwd: repo.getWorkingDirectory())
       .then (data) ->
-        console.log("diff-branch-view.then", data)
         new DiffBranchFilesView(repo, data, name)


chore(grunt): Enabled livereload options on watch task

--- misc/grunt/contrib-watch.coffee
+++ misc/grunt/contrib-watch.coffee
@@ -5,6 +5,8 @@
   # Watch all js, css and jade changes
   #
   grunt.config "watch",
+    options:
+      livereload: true
     js:
       files: ["src/**/*.coffee", "src/*.coffee"]
       tasks: [


.

Former-commit-id: f026a211376df626e43b626a9bc9ffd57d0005bc [formerly 208c8de3c600f4cee199774b6898f317b0f5fff8] [formerly f549fdbca7dec150484bf57652b97404a6584504 [formerly 487341d9938897247d575ae1fc235255bb369683]] [formerly de5dbd20f5a901562941e9bbbceda1d4f97c56cc [formerly 5b2e8b4b7e9ced5062f4a140ff54b71cab091a8f] [formerly c91245899f0ab6ba7a9cda70ea1e851f899be6a4 [formerly c91245899f0ab6ba7a9cda70ea1e851f899be6a4 [formerly b70007dde1ff0f4536dce4557c10e91b55e83c57]]]]
Former-commit-id: 43bc2947432f02d51380a737d77373c7e9ad4a87 [formerly 6133b74f8269c2611f345bcef6dae8d56d44b6ba] [formerly d98320d1604f701d609823e7b38158928f8d6772 [formerly 114b66299df3cd31df076fd190f826d5bb6bd014]]
Former-commit-id: fdd9e00b3d435c91643c1a331985f19c8833bf79 [formerly 5ec2748614ca0e479e0ab2cd00ba65dac74dfcea]
Former-commit-id: 0ec073e26e4eba83c54851d21e9b396741ae6f61
Former-commit-id: 25f71666a1141f7f2bc82006c6b9a07134e1e777

--- @client/development.coffee
+++ @client/development.coffee
@@ -31,8 +31,9 @@
         opacity: if @local.hover_top then 1 else 0
         backgroundColor: 'black'
         color: 'white'
-        padding: 10
+        padding: 20

+      onClick: (e) => @local.hover_top = true; save @local
       onMouseEnter: (e) => @local.hover_top = true; save @local
       onMouseLeave: (e) => @local.hover_top = @local.hover_second = false; save @local


handle new checklist host question type when checking if user has answered all questions

--- @client/permissions.coffee
+++ @client/permissions.coffee
@@ -73,11 +73,17 @@
       if !current_user.is_admin && !matchSomeRole(proposal.roles, ['editor', 'writer', 'opiner'])
         return Permission.INSUFFICIENT_PRIVILEGES

-      required_info = _.pluck _.where(customization('auth_questions'), {required: true}), 'tag'
-      existing_required_info = _.intersection required_info, _.keys(current_user.tags)
-
-      if existing_required_info.length != required_info.length
-        return Permission.INSUFFICIENT_INFORMATION
+      required_info = []
+      for question in _.where(customization('auth_questions'), {required: true})
+        answered = false
+        for tag,val of current_user.tags
+          continue if !tag.startsWith('sanleandro')
+          if tag == question.tag || (question.input == "checklist" && tag.startsWith(question.tag.split('.')[0]))
+            answered = true
+            break
+
+        if !answered
+          return Permission.INSUFFICIENT_INFORMATION

     when 'update opinion'
       proposal = fetch arguments[1]


remove script node

remove script node

--- src/nodes/BinauralSourceNode.coffee
+++ src/nodes/BinauralSourceNode.coffee
@@ -1,31 +1,19 @@
 jsSourceUtils = require '../js-source-utils'
 ConstantSourceNode = require './ConstantSourceNode'
 audioConfig = require '../audioConfig'
-
-process = (audioProcessingEvent) ->
-  audibleFrequencyValues = audioProcessingEvent.inputBuffer.getChannelData 0
-  beatFrequencyValues = audioProcessingEvent.inputBuffer.getChannelData 1
-  leftFrequencyValues = audioProcessingEvent.outputBuffer.getChannelData 0
-  rightFrequencyValues = audioProcessingEvent.outputBuffer.getChannelData 1
-
-  for i in [0..audibleFrequencyValues.length]
-    beatHalf = 0.5 * beatFrequencyValues[i]
-    leftFrequencyValues[i] = audibleFrequencyValues[i] - beatHalf
-    rightFrequencyValues[i] = audibleFrequencyValues[i] + beatHalf
-  # supress useless return value array generation
-  undefined

 class BinauralSourceNode
   constructor: (@context) ->
     @constant = new ConstantSourceNode @context, 1.0
     @audibleFrequencyNode = @context.createGain()
     @beatFrequencyNode = @context.createGain()
-    @inputMerge = @context.createChannelMerger 2

-    @script = @context.createScriptProcessor audioConfig.bufferSize, 2, 2
-    @script.onaudioprocess = process
+    @half = @context.createGain()
+    @half.gain.value = 0.5

-    @split = @context.createChannelSplitter 2
+    @inverseHalf = @context.createGain()
+    @inverseHalf.gain.value = -0.5
+
     @left = @context.createOscillator()
     @left.frequency.value = 0.0
     @right = @context.createOscillator()
@@ -34,14 +22,14 @@

     @constant.connect @audibleFrequencyNode
     @constant.connect @beatFrequencyNode
-    @audibleFrequencyNode.connect @inputMerge, 0, 0
-    @beatFrequencyNode.connect @inputMerge, 0, 1
-    @inputMerge.connect @script
+    @beatFrequencyNode.connect @half
+    @beatFrequencyNode.connect @inverseHalf

-    @script.connect @split
+    @audibleFrequencyNode.connect @left.frequency
+    @audibleFrequencyNode.connect @right.frequency
+    @inverseHalf.connect @left.frequency
+    @half.connect @right.frequency

-    @split.connect @left.frequency, 0
-    @split.connect @right.frequency, 1
     @left.connect @merge, 0, 0
     @right.connect @merge, 0, 1


Spelling, documentation

Spelling, documentation

Fixed spelling mistake,
didn't see why we send 2 messages when receiving a notification,
added ampersand for notstrat example

--- src/scripts/jenkins-notifier.coffee
+++ src/scripts/jenkins-notifier.coffee
@@ -12,7 +12,7 @@
 #   None
 #
 # URLS:
-#   POST /hubot/jenkins-notify?room=<room>[&type=<type>][notstrat=<notificationSTrategy>]
+#   POST /hubot/jenkins-notify?room=<room>[&type=<type>][&notstrat=<notificationSTrategy>]
 #
 # Notification Strategy is [Ff][Ss] which stands for "Failure" and "Success"
 # Capitalized letter means: notify always
@@ -66,7 +66,6 @@
       data = req.body

       if data.build.phase == 'FINISHED'
-        robot.send envelope, data.name
         if data.build.status == 'FAILURE'
           if data.name in @failing
             build = "is still"
@@ -77,9 +76,8 @@
         if data.build.status == 'SUCCESS'
           if data.name in @failing
             build = "was restored"
-            robot.send envelope, "woop2"
           else
-            build = "suceeded"
+            build = "succeeded"
           robot.send envelope, "#{data.name} build ##{data.build.number} #{build} (#{encodeURI(data.build.full_url)})"  if shouldNotify(envelope.notstrat, data, @failing)
           index = @failing.indexOf data.name
           @failing.splice index, 1 if index isnt -1


Add binary as part of the 'value' and 'any' types

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -312,8 +312,8 @@
         suggestions: {} # Suggestions[state] = function for this state

         types:
-            value: ['number', 'bool', 'string', 'array', 'object', 'time']
-            any: ['number', 'bool', 'string', 'array', 'object', 'stream', 'selection', 'table', 'db', 'r', 'error' ]
+            value: ['number', 'bool', 'string', 'array', 'object', 'time', 'binary']
+            any: ['number', 'bool', 'string', 'array', 'object', 'stream', 'selection', 'table', 'db', 'r', 'error', 'binary']
             sequence: ['table', 'selection', 'stream', 'array']
             grouped_stream: ['stream', 'array']


Refactor - remove unused parameters.

Refactor - remove unused parameters.

--- src/spec/product-import.spec.coffee
+++ src/spec/product-import.spec.coffee
@@ -283,7 +283,7 @@
   describe '::_prepareNewProduct', ->

     beforeEach ->
-      spyOn(@import, "_resolveReference").andCallFake (service, refKey, ref, predicate) =>
+      spyOn(@import, "_resolveReference").andCallFake (service, refKey, ref) =>
         switch refKey
           when "productType"
             if ref then Promise.resolve(sampleProductTypeResponse.body.results[0].id) else Promise.resolve()


:lipstick: Clean up LineWrapper spec

:lipstick: Clean up LineWrapper spec

--- spec/atom/line-wrapper-spec.coffee
+++ spec/atom/line-wrapper-spec.coffee
@@ -4,30 +4,18 @@
 Range = require 'range'
 _ = require 'underscore'

-describe "LineWrapper", ->
+fdescribe "LineWrapper", ->
   [wrapper, buffer] = []

   beforeEach ->
     buffer = new Buffer(require.resolve('fixtures/sample.js'))
     wrapper = new LineWrapper(50, new Highlighter(buffer))

-  describe ".screenLinesForBufferRow(bufferRow)", ->
-    it "returns an array of tokens for each screen line associated with the buffer row", ->
-      wrapper.setMaxLength(30)
-      screenLines = wrapper.wrappedLines[6].screenLines
-
-      expect(screenLines.length).toBe 3
-      [line1, line2, line3] = screenLines
-
-      # TODO: Get this working again after finalizing split tokens
-      # expect(line1.endColumn).toBe 24
-      # expect(tokensText(line1)).toBe '      current < pivot ? '
-
-      # expect(line2.endColumn).toBe 45
-      # expect(tokensText(line2)).toBe 'left.push(current) : '
-
-      # expect(line3.endColumn).toBe 65
-      # expect(tokensText(line3)).toBe 'right.push(current);'
+  describe ".tokensForScreenRow(row)", ->
+    it "returns tokens for the line fragment corresponding to the given screen row", ->
+      expect(tokensText wrapper.tokensForScreenRow(3)).toEqual('    var pivot = items.shift(), current, left = [], ')
+      expect(tokensText wrapper.tokensForScreenRow(4)).toEqual('right = [];')
+      expect(tokensText wrapper.tokensForScreenRow(5)).toEqual('    while(items.length > 0) {')

   describe "when the buffer changes", ->
     changeHandler = null
@@ -39,7 +27,7 @@
       changeHandler = jasmine.createSpy('changeHandler')
       wrapper.on 'change', changeHandler

-    describe "when a single buffer line is updated", ->
+    describe "when a buffer line is updated", ->
       describe "when the number of screen lines remains the same for the changed buffer line", ->
         it "re-wraps the existing lines and emits a change event for all its screen lines", ->
           buffer.insert([6, 28], '1234567')
@@ -76,7 +64,7 @@
           expect(event.oldRange).toEqual([[7, 0], [8, 20]])
           expect(event.newRange).toEqual([[7, 0], [7, 47]])

-    describe "when buffer lines are updated and inserted", ->
+    describe "when buffer lines are inserted", ->
       fit "re-wraps existing and new screen lines and emits a change event", ->
         buffer.insert([6, 21], '1234567890 abcdefghij 1234567890\nabcdefghij')
         expect(tokensText(wrapper.tokensForScreenRow(7))).toBe '      current < pivot1234567890 abcdefghij '
@@ -91,111 +79,40 @@

     describe "when buffer lines are removed", ->

-    describe "when an unwrapped line is updated", ->
-      describe "when the update does not cause the line to wrap", ->
-        it "updates tokens for the corresponding screen line and emits a change event", ->
-          buffer.insert([0, 10], 'h')
-          expect(tokensText(wrapper.tokensForScreenRow(0))).toContain 'quickshort'
+  describe ".screenPositionFromBufferPosition(point, allowEOL=false)", ->
+    it "translates the given buffer position to a screen position, accounting for wrapped lines", ->
+      # before any wrapped lines
+      expect(wrapper.screenPositionFromBufferPosition([0, 5])).toEqual([0, 5])
+      expect(wrapper.screenPositionFromBufferPosition([0, 29])).toEqual([0, 29])

-          expect(changeHandler).toHaveBeenCalled()
-          [event] = changeHandler.argsForCall[0]
-          expect(event.oldRange).toEqual(new Range([0, 10], [0, 10]))
-          expect(event.newRange).toEqual(new Range([0, 10], [0, 11]))
-          changeHandler.reset()
+      # on a wrapped line
+      expect(wrapper.screenPositionFromBufferPosition([3, 5])).toEqual([3, 5])
+      expect(wrapper.screenPositionFromBufferPosition([3, 50])).toEqual([3, 50])
+      expect(wrapper.screenPositionFromBufferPosition([3, 62])).toEqual([4, 11])

-          # below a wrapped line
-          buffer.insert([4, 10], 'foo')
-          expect(tokensText(wrapper.tokensForScreenRow(5))).toContain 'fooitems'
-          expect(changeHandler).toHaveBeenCalled()
-          [event] = changeHandler.argsForCall[0]
-          expect(event.oldRange).toEqual(new Range([5, 10], [5, 10]))
-          expect(event.newRange).toEqual(new Range([5, 10], [5, 13]))
+      # following a wrapped line
+      expect(wrapper.screenPositionFromBufferPosition([4, 5])).toEqual([5, 5])

+    describe "when allowEOL is true", ->
+      it "preserves a position at the end of a wrapped screen line ", ->
+        expect(wrapper.screenPositionFromBufferPosition([3, 51], true)).toEqual([3, 51])

-      describe "when the update causes the line to wrap once", ->
-        it "updates tokens for the corresponding screen lines and emits a change event", ->
-          buffer.insert([2, 4], longText)
-          expect(tokensText(wrapper.tokensForScreenRow(2))).toBe '    0123456789ABCDEFif (items.length <= 1) return '
-          expect(tokensText(wrapper.tokensForScreenRow(3))).toBe 'items;'
-          expect(tokensText(wrapper.tokensForScreenRow(4))).toBe '    var pivot = items.shift(), current, left = [], '
+    describe "when allowEOL is false", ->
+      it "translates a position at the end of a wrapped screen line to the begining of the next screen line", ->
+        expect(wrapper.screenPositionFromBufferPosition([3, 51])).toEqual([4, 0])

-          expect(changeHandler).toHaveBeenCalled()
-          [event] = changeHandler.argsForCall[0]
-          expect(event.oldRange).toEqual(new Range([2, 4], [2, 4]))
-          expect(event.newRange).toEqual(new Range([2, 4], [3, 6]))
+  describe ".bufferPositionFromScreenPosition(point)", ->
+    it "translates the given screen position to a buffer position, account for wrapped lines", ->
+      # before any wrapped lines
+      expect(wrapper.bufferPositionFromScreenPosition([0, 5])).toEqual([0, 5])

-      describe "when the update causes the line to wrap multiple times", ->
-        it "updates tokens for the corresponding screen lines and emits a change event", ->
-          buffer.insert([2, 4], ["/*",longText, longText, longText, longText, "*/"].join(' '))
-          expect(tokensText(wrapper.tokensForScreenRow(2))).toBe '    /* 0123456789ABCDEF 0123456789ABCDEF '
-          expect(tokensText(wrapper.tokensForScreenRow(3))).toBe '0123456789ABCDEF 0123456789ABCDEF */if '
-          expect(tokensText(wrapper.tokensForScreenRow(4))).toBe '(items.length <= 1) return items;'
-          expect(tokensText(wrapper.tokensForScreenRow(5))).toBe '    var pivot = items.shift(), current, left = [], '
+      # on a wrapped line
+      expect(wrapper.bufferPositionFromScreenPosition([3, 5])).toEqual([3, 5])
+      expect(wrapper.bufferPositionFromScreenPosition([4, 0])).toEqual([3, 51])
+      expect(wrapper.bufferPositionFromScreenPosition([4, 5])).toEqual([3, 56])

-          expect(changeHandler).toHaveBeenCalled()
-          [event] = changeHandler.argsForCall[0]
-          expect(event.oldRange).toEqual(new Range([2, 4], [2, 4]))
-          expect(event.newRange).toEqual(new Range([2, 4], [4, 33]))
-
-    describe "when a wrapped line is updated", ->
-      describe "when the old text spans multiple screen lines", ->
-        describe "when the new text spans fewer screen lines than the old text", ->
-          it "updates tokens for the corresponding screen lines and emits a change event", ->
-            wrapper.setMaxLength(15)
-
-            range = new Range([3, 8], [3, 47])
-            buffer.change(range, "a")
-            expect(tokensText(wrapper.tokensForScreenRow(9))).toBe '    var a [], '
-            expect(tokensText(wrapper.tokensForScreenRow(10))).toBe 'right = [];'
-            expect(tokensText(wrapper.tokensForScreenRow(11))).toBe '    '
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[9, 8], [11, 16]]
-            expect(event.newRange).toEqual [[9, 8], [9, 9]]
-
-        describe "when the new text spans as many screen lines than the old text", ->
-          it "updates tokens for the corresponding screen lines and emits a change event", ->
-            range = new Range([3, 40], [3, 57])
-            buffer.change(range, text10)
-            expect(tokensText(wrapper.tokensForScreenRow(3))).toBe '    var pivot = items.shift(), current, '
-            expect(tokensText(wrapper.tokensForScreenRow(4))).toBe '0123456789= [];'
-            expect(tokensText(wrapper.tokensForScreenRow(5))).toBe '    while(items.length > 0) {'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[3, 40], [4, 6]]
-            expect(event.newRange).toEqual [[3, 40], [4, 10]]
-
-        describe "when the new text spans more screen lines than the old text", ->
-          it "updates tokens for the corresponding screen lines and emits a change event", ->
-            range = new Range([3, 40], [3, 57])
-            buffer.change(range, text60)
-            expect(tokensText(wrapper.tokensForScreenRow(3))).toBe '    var pivot = items.shift(), current, 0123456789 '
-            expect(tokensText(wrapper.tokensForScreenRow(4))).toBe '123456789 123456789 123456789 123456789 123456789= '
-            expect(tokensText(wrapper.tokensForScreenRow(5))).toBe '[];'
-            expect(tokensText(wrapper.tokensForScreenRow(6))).toBe '    while(items.length > 0) {'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[3, 40], [4, 6]]
-            expect(event.newRange).toEqual [[3, 40], [5, 3]]
-
-    describe "when a line is inserted", ->
-      describe "when the line is wrapped", ->
-
-      describe "when the line is not wrapped", ->
-
-    describe "when a line is removed", ->
-      describe "when the line is wrapped", ->
-
-      describe "when the line is not wrapped", ->
-
-  describe ".tokensForScreenRow(row)", ->
-    it "returns tokens for the line fragment corresponding to the given screen row", ->
-      expect(wrapper.tokensForScreenRow(3)).toEqual(wrapper.wrappedLines[3].screenLines[0])
-      expect(wrapper.tokensForScreenRow(4)).toEqual(wrapper.wrappedLines[3].screenLines[1])
-      expect(wrapper.tokensForScreenRow(5)).toEqual(wrapper.wrappedLines[4].screenLines[0])
+      # following a wrapped line
+      expect(wrapper.bufferPositionFromScreenPosition([5, 5])).toEqual([4, 5])

   describe ".splitTokens(tokens)", ->
     makeTokens = (array) ->
@@ -263,38 +180,3 @@
           expect(line2.endColumn).toBe 14
           expect(line2.textLength).toBe 3

-  describe ".screenPositionFromBufferPosition(point, allowEOL=false)", ->
-    it "translates the given buffer position to a screen position, accounting for wrapped lines", ->
-      # before any wrapped lines
-      expect(wrapper.screenPositionFromBufferPosition([0, 5])).toEqual([0, 5])
-      expect(wrapper.screenPositionFromBufferPosition([0, 29])).toEqual([0, 29])
-
-      # on a wrapped line
-      expect(wrapper.screenPositionFromBufferPosition([3, 5])).toEqual([3, 5])
-      expect(wrapper.screenPositionFromBufferPosition([3, 50])).toEqual([3, 50])
-      expect(wrapper.screenPositionFromBufferPosition([3, 62])).toEqual([4, 11])
-
-      # following a wrapped line
-      expect(wrapper.screenPositionFromBufferPosition([4, 5])).toEqual([5, 5])
-
-    describe "when allowEOL is true", ->
-      it "preserves a position at the end of a wrapped screen line ", ->
-        expect(wrapper.screenPositionFromBufferPosition([3, 51], true)).toEqual([3, 51])
-
-    describe "when allowEOL is false", ->
-      it "translates a position at the end of a wrapped screen line to the begining of the next screen line", ->
-        expect(wrapper.screenPositionFromBufferPosition([3, 51])).toEqual([4, 0])
-
-  describe ".bufferPositionFromScreenPosition(point)", ->
-    it "translates the given screen position to a buffer position, account for wrapped lines", ->
-      # before any wrapped lines
-      expect(wrapper.bufferPositionFromScreenPosition([0, 5])).toEqual([0, 5])
-
-      # on a wrapped line
-      expect(wrapper.bufferPositionFromScreenPosition([3, 5])).toEqual([3, 5])
-      expect(wrapper.bufferPositionFromScreenPosition([4, 0])).toEqual([3, 51])
-      expect(wrapper.bufferPositionFromScreenPosition([4, 5])).toEqual([3, 56])
-
-      # following a wrapped line
-      expect(wrapper.bufferPositionFromScreenPosition([5, 5])).toEqual([4, 5])
-


fixed #597 could not add link markup in note_card

--- app/assets/javascripts/card.js.coffee
+++ app/assets/javascripts/card.js.coffee
@@ -236,11 +236,7 @@
     for attachment in attachments
       markupid = attachment.getAttribute "data-markupid"
       content = attachment.getAttribute "data-content"
-      url = ""
-      if content
-        url = content
-      else
-        url = attachment.getAttribute "data-link"
-      $("#" + markupid).attr "href", url
+      if content && content.length > 0
+        $("#" + markupid).attr "href", content
     $(document.body).trigger "attachment-markuped"
   markup()


black bars

black bars

--- app/assets/javascripts/dash.js.coffee
+++ app/assets/javascripts/dash.js.coffee
@@ -43,9 +43,11 @@
   chart.selectAll("rect")
        .data(data)
        .enter().append("rect")
-       .attr("y", (data, idx) ->
+       .attr("x", (data, idx) ->
                  return idx * 25 )
-       .attr("width", (data, idx)->
+       .attr("y", (data, idx) ->
+                 75 - data*10)
+       .attr("height", (data, idx)->
                  data*10 )
-       .attr("height", 20)
+       .attr("width", 20)


Update ignore tag names list

Update ignore tag names list

--- app/assets/javascripts/home.js.coffee
+++ app/assets/javascripts/home.js.coffee
@@ -91,14 +91,14 @@
     console.log("#{spamCount} / #{data.length}") if isDev
     $('#is-pic-list-last-item').appendTo('#js-pic-list').show()

-  spamTagThreshold = 30
-  spamTagNames = [ 'support', 'skin', 'random', 'shadow', 'fashion' ]
+  ignoreTagNames = [ 'support', 'skin', 'random', 'shadow', 'fashion', 'perfect' ]
+  tagCountThreshold = 30
   spamFilter = (d)->
     isSpam = false
-    if d.tags.length >= spamTagThreshold
+    if d.tags.length >= tagCountThreshold
       console.log("Threshold: " + d.link) if isDev
       return true
-    _(spamTagNames).each (tag)->
+    _(ignoreTagNames).each (tag)->
       if _(d.tags).include(tag)
         console.log("Tag: " + d.link) if isDev
         isSpam = true


'npm run bundle' now builds all platforms by default

--- scripts/bundle.coffee
+++ scripts/bundle.coffee
@@ -59,6 +59,7 @@

 do ->
     stack = []
+    buildAll = process.argv.length is 2

     registerBundle = (type, opts) ->
         bundleOpts = {}
@@ -67,9 +68,9 @@
         stack.push (callback) -> createBundle(bundleOpts, callback)

     for type in TYPES
-        if process.argv.indexOf("--#{type.platform}") >= 0
+        if buildAll or process.argv.indexOf("--#{type.platform}") >= 0
             registerBundle type, {release: false}
-        if process.argv.indexOf("--#{type.platform}-release") >= 0
+        if buildAll or process.argv.indexOf("--#{type.platform}-release") >= 0
             registerBundle type, {release: true}

     index = -1


Material exchange change the way categories are filtered

--- scripts/bungie.coffee
+++ scripts/bungie.coffee
@@ -97,8 +97,8 @@
       for vendorHash in vendors
         getVendorDetails(res, vendorHash).then (vendorDetails) ->

-          categories = vendorDetails.saleItemCategories.filter (category) -> category.categoryTitle is 'material exchange'
-          console.log "#{vendorDetails.vendorName}: #{categories}"
+          for category in vendorDetails.saleItemCategories when category.categoryTitle is 'Material Exchange'
+            console.log "#{vendorDetails.vendorName}: #{categories}"

     else
       # command not recognized. Lists all available commands


Github event types.  Unfinished.  But all events are there, as well as variables containing the useful information for each event type.  Clean up and finishing is needed

--- scripts/repo-event-notifier/src/event-actions/all.coffee
+++ scripts/repo-event-notifier/src/event-actions/all.coffee
@@ -1,4 +1,6 @@
 #! /usr/bin/env coffee
+
+#commit_comment,create,delete,deployment,deployment_status,fork,gollum,issue_comment,issues,member,membership,page_build,pull_request_review_comment,pull_request,push,repository,release,status,ping,team_add,watch

 unique = (array) ->
   output = {}
@@ -29,17 +31,151 @@
     callback "New #{eventType.replace('_', ' ')} \"#{pr_or_issue.title}\" by #{pr_or_issue.user.login}: #{pr_or_issue.html_url}#{mentioned_line}"

 module.exports =
+  commit_comment: (data, callback) ->
+      comment = data.comment
+
+      callback ""
+
+  create: (data, callback) ->
+      repo = data.repository
+
+      callback ""
+
+  delete: (data, callback) ->
+      repo = data.repository
+
+      callback ""
+
+  deployment: (data, callback) ->
+      deploy = data.deployment
+      repo = data.repository
+
+      callback ""
+
+  deployment_status: (data, callback) ->
+      deploy = data.deployment
+      deploy_status = data.deployment_status
+      repo = data.repository
+
+      callback ""
+
+  fork: (data, callback) ->
+      forkee = data.forkee
+      repo = data.repository
+
+      callback ""
+
+  gollum: (data, callback) ->
+      pages = data.pages
+      repo = data.repository
+
+      callback ""
+
   issues: (data, callback) ->
-    buildNewIssueOrPRMessage(data, 'issue', callback)
+      issue = data.issue
+      repo = data.repository

-  pull_request: (data, callback) ->
-    buildNewIssueOrPRMessage(data, 'pull_request', callback)
+      mentioned_line = extractMentionsFromBody(issue.body)
+
+      callback "New issue \##{issue.number} \"#{issue.title}\" by #{issue.user.login}: #{issue.html_url}#{mentioned_line}"
+
+  issue_comment: (data, callback) ->
+      issue = data.issue
+      comment = data.comment
+      repo = data.repository
+
+      mentioned_line = extractMentionsFromBody(comment.body)
+
+      callback "New Comment on Issue \##{issue.number} by #{comment.user.login}: \"#{comment.body}\" - #{comment.html_url}#{mentioned_line}"
+
+  member: (data, callback) ->
+      member = data.member
+      repo = data.repository
+
+      callback ""
+
+  # Org level event
+  membership: (data, callback) ->
+      scope = data.scope
+      member = data.member
+
+      callback ""

   page_build: (data, callback) ->
-    build = data.build
+      build = data.build
+      repo = data.repository
     if build?
       if build.status is "built"
         callback "#{build.pusher.login} built #{data.repository.full_name} pages at #{build.commit} in #{build.duration}ms."
       if build.error.message?
         callback "Page build for #{data.repository.full_name} errored: #{build.error.message}."

+  public: (data, callback) ->
+      repo = data.repository
+
+      callback ""
+
+  pull_request_review_comment: (data, callback) ->
+      comment = data.comment
+      pull_req = data.pull_request
+      base = data.base
+      repo = data.repository
+
+      mentioned_line = extractMentionsFromBody(comment.body)
+
+      callback "New Comment on Pull Request \"#{comment.body}\" by #{comment.user.login}: #{comment.html_url}#{mentioned_line}"
+
+  pull_request: (data, callback) ->
+      pull_num = data.number
+      pull_req = data.pull_request
+      base = data.base
+      repo = data.repository
+
+      mentioned_line = extractMentionsFromBody(pull_req.body)
+
+      callback "New Pull Request \"#{pull_req.title}\" by #{pull_req.user.login}: #{pull_req.html_url}#{mentioned_line}"
+
+  push: (data, callback) ->
+      commit = data.after
+      commits = data.commits
+      head_commit = data.head_commit
+      repo = data.repository
+      pusher = data.pusher
+
+      mentioned_line = extractMentionsFromBody(issue.body)
+
+      callback "New Commit \"#{head_commit.message}\" by #{pusher.name}: #{head_commit.url}#{mentioned_line}"
+
+  # Org level event
+  repository: (data, callback) ->
+      repo = data.repository
+      org = data.organization
+
+      callback ""
+
+  release: (data, callback) ->
+      release = data.release
+      repo = data.repository
+
+      callback ""
+
+  status: (data, callback) ->
+      commit = data.commit
+      state = data.state
+      branches = data.branches
+      repo = data.repository
+
+      callback ""
+
+  team_add: (data, callback) ->
+      team = data.team
+      repo = data.repository
+      org = data.organization
+
+      callback ""
+
+  watch: (data, callback) ->
+      repo = data.repository
+      sender = data.sender
+
+      callback ""


Adding a comment about animationOptions

Adding a comment about animationOptions

--- vnc-example01.framer/app.coffee
+++ vnc-example01.framer/app.coffee
@@ -4,6 +4,7 @@

 vnc = new ViewNavigationController

+# This is optional, but allows you to customize the transition
 vnc.animationOptions =
 	curve: "ease-in-out"
 	time: 0.3


spec: comment out fragile spec temporarily

Change-Id: Ie81a1afb0d043bdbcd253a6434bf806e2e8ac165
Reviewed-on: https://gerrit.instructure.com/29153
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Product-Review: Bryan Madsen <0a3ba1af216659500dd8f41e29f3979f42452870@instructure.com>
Reviewed-by: Bryan Madsen <0a3ba1af216659500dd8f41e29f3979f42452870@instructure.com>
QA-Review: Bryan Madsen <0a3ba1af216659500dd8f41e29f3979f42452870@instructure.com>

--- spec/coffeescripts/views/assignments/EditViewSpec.coffee
+++ spec/coffeescripts/views/assignments/EditViewSpec.coffee
@@ -89,23 +89,23 @@

     ENV.IS_LARGE_ROSTER = null

-  test 'adds and removes student group', ->
-    ENV.GROUP_CATEGORIES = [{id: 1, name: "fun group"}]
-    ENV.ASSIGNMENT_GROUPS = [{id: 1, name: "assignment group 1"}]
-    view = editView()
-    equal view.assignment.toView()['groupCategoryId'], null
+  # test 'adds and removes student group', ->
+  #   ENV.GROUP_CATEGORIES = [{id: 1, name: "fun group"}]
+  #   ENV.ASSIGNMENT_GROUPS = [{id: 1, name: "assignment group 1"}]
+  #   view = editView()
+  #   equal view.assignment.toView()['groupCategoryId'], null

-    #adds student group
-    view.$('#assignment_has_group_category').click()
-    view.$('#assignment_group_category_id option:eq(0)').attr("selected", "selected")
-    equal view.getFormData()['group_category_id'], "1"
+  #   #adds student group
+  #   view.$('#assignment_has_group_category').click()
+  #   view.$('#assignment_group_category_id option:eq(0)').attr("selected", "selected")
+  #   equal view.getFormData()['group_category_id'], "1"

-    #removes student group
-    view.$('#assignment_has_group_category').click()
-    equal view.getFormData()['groupCategoryId'], null
+  #   #removes student group
+  #   view.$('#assignment_has_group_category').click()
+  #   equal view.getFormData()['groupCategoryId'], null

-    ENV.GROUP_CATEGORIES = null
-    ENV.ASSIGNMENT_GROUPS = null
+  #   ENV.GROUP_CATEGORIES = null
+  #   ENV.ASSIGNMENT_GROUPS = null

   # test 'shows a warning when dangerously changing group status', ->
   #   # bleh


sort_array2 replaces old sort_array

sort_array2 replaces old sort_array

--- app/js/services/market_service.coffee
+++ app/js/services/market_service.coffee
@@ -212,13 +212,7 @@
     capitalize: (str) ->
         str.charAt(0).toUpperCase() + str.slice(1)

-    sort_array: (array, field, reverse = false) ->
-         array.sort (a, b) ->
-            a = a[field]
-            b = b[field]
-            if reverse then b - a else a - b
-
-    sort_array2: (array, field, field2, reverse = false) ->
+    sort_array: (array, field, field2, reverse = false) ->
          array.sort (a, b) ->
             a = a[field]
             b = b[field]
@@ -395,7 +389,7 @@
         @orders.unshift order
         #sorted_orders = @filter('orderBy')(@orders, 'price', false)
         #console.log "------ sorted_orders ------>", sorted_orders
-        @helper.sort_array(@orders, "price")
+        @helper.sort_array(@orders, "price", "quantity")

     cancel_order: (id) ->
         order = @helper.get_array_element_by_id(@orders, id)
@@ -521,7 +515,7 @@
                 #td.type = "cover"
                 covers.push td
             @helper.update_array {target: @covers, data: covers }
-            @helper.sort_array2(@covers, "price", "quantity", !inverted)
+            @helper.sort_array(@covers, "price", "quantity", !inverted)

     pull_orders: (market, inverted, account_name) ->
         orders = []
@@ -548,7 +542,7 @@
                 can_remove: (o) ->
                     #!(o.status == "unconfirmed" or (o.status == "pending" and !o.expired()))
                     !(o.status == "unconfirmed" or (o.status == "pending" and !o.expired()))
-            @helper.sort_array(@orders, "price", false)
+            @helper.sort_array(@orders, "price", "quantity", false)
             if magic_unicorn?
                 magic_unicorn.log_message("in MarketService.pull_orders - received orders: #{results.length}, orders shown: #{@orders.length}")

@@ -619,8 +613,8 @@
                 self.market.lowest_ask = market.lowest_ask = self.lowest_ask if self.lowest_ask != Number.MAX_VALUE
                 self.market.highest_bid = market.highest_bid = self.highest_bid

-                self.helper.sort_array(self.asks, "price", false)
-                self.helper.sort_array(self.bids, "price", true)
+                self.helper.sort_array(self.asks, "price", "quantity", false)
+                self.helper.sort_array(self.bids, "price", "quantity", true)

                 if @counter % 5 == 0 and self.market.avg_price_1h and self.market.avg_price_1h > 0.0


fixes pending order bug

fixes pending order bug

--- app/js/services/market_service.coffee
+++ app/js/services/market_service.coffee
@@ -392,7 +392,7 @@
                 #console.log "---- order: ", r
                 #console.log "----- market_order_list: ", inverted, r
                 td = @helper.order_to_trade_data(r, market.base_asset, market.quantity_asset, inverted, inverted, inverted)
-                #td.status = "posted"
+                td.status = "posted"
                 orders.push td
             @helper.update_array
                 target: @orders


Adding code that doesn't work to update reordered publications, please advise.

--- server/person.coffee
+++ server/person.coffee
@@ -47,7 +47,16 @@
   'reorder-library': (publications) ->
     check publications, [String]

-    #TODO: Update user's library to the new order of publications
+    #TODO: This code does not work and corrupts Person records. Please correct.
+
+    personId = Meteor.personId
+    return unless personId
+
+    Person.documents.update
+      _id: personId
+    ,
+      $set:
+        library: publications

 Meteor.publish 'persons-by-id-or-slug', (slug) ->
   check slug, String


Handle slides outside player controls

Handle slides outside player controls

--- app/scripts/lazerscripts/lunch.coffee
+++ app/scripts/lazerscripts/lunch.coffee
@@ -219,16 +219,14 @@

   nextSlide: (task) ->
     @sequence(
-      => @player(1).ship()?.superUsed = 0
       # While now works with 2 promises.
       @while(
-        @_waitForSuperWeapon()
+        @_waitForKeyPress(Crafty.keys.N)
         @sequence(
           task ? @wait(1000)
           @_addVisibleMarker()
         )
       )
-      => @player(1).ship()?.superUsed = 0
     )

   _addVisibleMarker: ->
@@ -248,20 +246,15 @@
     if text[text.length - 1] is '*'
       Crafty('LevelTitle').text(text.slice(0, text.length - 2) + ' -')

-  _waitForSuperWeapon: ->
+  _waitForKeyPress: (key) ->
     =>
       d = WhenJS.defer()
-      used = no
-      i = setInterval(
-        =>
-          if @player(1).ship()?
-            used = @player(1).ship().superUsed isnt 0
-          if used
-            clearInterval i
-            @_clearVisibleMarker()
-            d.resolve()
-        300
-      )
+      handler = (e) ->
+        if e.key == key
+          Crafty.unbind('KeyDown', handler)
+          d.resolve()
+
+      Crafty.bind('KeyDown', handler)
       d.promise

   mineSwarm: (options = { direction: 'right' })->


server don't print stuff

server don't print stuff

--- server/server.coffee
+++ server/server.coffee
@@ -44,7 +44,6 @@
   socket.emit('LobbyList', users.toJSON())

   socket.on 'PlayRequest', (nick) ->
-    console.log(users)
     h = me.get("want_to_play")
     h[nick] = true
     me.set("want_to_play", h)


Better paragraph detection.

Better paragraph detection.

--- server/server.coffee
+++ server/server.coffee
@@ -135,7 +135,7 @@
   paragraphs =
     for paragraph in paragraphs
       paragraph = paragraph.trim()
-      if not paragraph or 0 == paragraph.indexOf "<"
+      if paragraph.length == 0 or /^<.*>$/.test paragraph
         paragraph
       else
         "<p>\n#{paragraph}\n</p>"


Revert "Finalized email options for now"

This reverts commit 340d80fa891b079dbcd8a476b7d1c567fc120b81.

--- server/server.coffee
+++ server/server.coffee
@@ -22,18 +22,15 @@
 module.exports = app = express()

 smtpTransport = nodemailer.createTransport('SMTP',
-  service: 'Gmail'
-  auth:
-    user: 'server.tranzit@gmail.com'
-    pass: 'dev@tranzit')
+  service: 'Gmail')

 # function for sending out emails
 sendEmails = ->
   mailOptions =
-    from: 'Tranzit Server <server.tranzit@gmail.com>'
+    from: 'Tranzit Server'
     to: 'aottinge@purdue.edu'
     subject: 'Package Pickup'
-    html: 'Come pick up your package(s) you lazy asshole'
+    html: 'Come pick up your package you lazy asshole.'
   smtpTransport.sendMail mailOptions, (error, response) ->
     if error
       console.log error
@@ -66,7 +63,7 @@
   schedule.scheduleJob({
     hour: 9
     minute: 0
-  }, sendEmails())
+  }, sendEmails)

   # begin listening for connections
   app.listen 3000, ->


timeline slide should be faster/more responsive

--- app/assets/javascripts/commit.js.coffee
+++ app/assets/javascripts/commit.js.coffee
@@ -336,31 +336,30 @@
     return Repo.prepared_files[index]

   display_with_filtered_commits: (filtered_commits) ->
-    Repo.filtered_commits = filtered_commits
-    Repo.display_with_filtered_commits_and_text_filter(f.val())
-    console.log(f.val())
-
-  display_with_filtered_commits_and_text_filter: (text) ->
-    scale = d3.scale.log().base(10).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
     Repo.files = []
-    for commit in Repo.filtered_commits
+    for commit in filtered_commits
       for file in commit.files
         name = file[0]
         Repo.files[name]   or= [0, 0]
         Repo.files[name][0] += file[1]
         Repo.files[name][1] += file[2]
-    temp_files = ([name, f[0], f[1], f[0]+f[1]] for name, f of Repo.files)
-
-    console.log(Repo.prepared_files.length)
-    Repo.prepared_files = Repo.filter(text, temp_files)
-    console.log(Repo.prepared_files.length)
+    temp_files = ([name, fi[0], fi[1], fi[0]+fi[1]] for name, fi of Repo.files)
+    Repo.saved_files = temp_files
+
+    Repo.display_with_filtered_commits_and_text_filter(f.val())
+
+
+  display_with_filtered_commits_and_text_filter: (text) ->
+
+    scale = d3.scale.log().base(10).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
+    console.log(Repo.saved_files)
+    Repo.prepared_files = Repo.filter(text, Repo.saved_files)
+    console.log(Repo.prepared_files)

     Repo.prepared_files = Repo.prepared_files.sort (a,b) -> (b[3] - a[3])

     Repo.move_to_new_position()
-

-
     Repo.chart.selectAll("text.bar-label")
       .text (f) ->
         file = Repo.correct_object(f)


update interface coffee

update interface coffee

--- app/assets/javascripts/interface.coffee
+++ app/assets/javascripts/interface.coffee
@@ -12,7 +12,8 @@
       $(this).tab('show')

   tooltip: ->
-    $('[data-toggle="tooltip"], [title]').tooltip()
+    #$('[data-toggle="tooltip"], [title]').tooltip()
+    $('[data-toggle="tooltip"]').tooltip()

   dropdown: ->
     $('.dropdown-toggle').dropdown()


remove attachedBindings if initBindings() is called repeatedly

--- app/assets/javascripts/lib/bb.js.coffee
+++ app/assets/javascripts/lib/bb.js.coffee
@@ -33,11 +33,10 @@
     #now actually update the view with the value
     updateView($el, elAttribute, filter, result)

-constructCallbackToAttachBindingsToView = (view, toView, bindingProperties) ->
-  existingBindings = []
-
+constructCallbackToAttachBindingsToView = (view, toView, attachedBindings, bindingProperties) ->
   attachBindings = ->
-    view.stopListening(b.model, "change:#{b.property}", b.callback) while b = existingBindings.pop()
+    toView()
+    view.stopListening(b.model, "change:#{b.property}", b.callback) while b = attachedBindings.pop()
     bindingChain = []
     context = view
     chainIncomplete = _.find(bindingProperties, (property) ->
@@ -64,32 +63,36 @@
     if not chainIncomplete?
       bindingLeaf = bindingChain.pop()
       view.listenTo(bindingLeaf.model, "change:#{bindingLeaf.property}", toView) if bindingLeaf?
-      existingBindings.push({model: bindingLeaf.model, property: bindingLeaf.property, callback: toView})
+      attachedBindings.push({model: bindingLeaf.model, property: bindingLeaf.property, callback: toView})

     #any node above the leaf node we setup our Backbone event listener to re-attach bindings
     #eg: if we're binding to 'model.manager.name', and 'manager' changes, we need to re-attach to the new manager model
     _.each(bindingChain, (bindingNode) ->
       view.listenTo(bindingNode.model, "change:#{bindingNode.property}", attachBindings)
-      existingBindings.push({model: bindingNode.model, property: bindingNode.property, callback: attachBindings})
+      attachedBindings.push({model: bindingNode.model, property: bindingNode.property, callback: attachBindings})
     )

   return attachBindings

 updateView = ($el, elAttribute, filter, value) ->
-  $el.text(value)
+  $el.text(if value? then value.toString() else '')

 processPropertyOfBackboneContext = (bindingChain, context, model, property) ->
   if _.isFunction(context[property])
     model?.startRecording?()
     result = context[property].call(context)
     if model?.finishRecording?
-      modelAttributes = model.finishRecording()
-      _.each(modelAttributes, (ignored, attribute) -> bindingChain.push({model, attribute}))
+      modelProperties = model.finishRecording()
+      _.each(modelProperties, (ignored, modelProperty) -> bindingChain.push({model, property: modelProperty}))
     return result
   else
     return context[property]

 initBindings = (view) ->
+  #remove existing bindings
+  while bindingChain = view._attachedBindings.pop()
+    view.stopListening(b.model, "change:#{b.property}", b.callback) while b = bindingChain.pop()
+
   view.$el.find('[data-bb]').each ->
     $el = $(@)
     for binding in $el.data('bb')?.split(',')
@@ -101,12 +104,13 @@
       filter = bindingArray[3]

       toView = constructCallbackToPropagateBbChangesToView(view, $el, elAttribute, bindingSourceProps, filter)
-      toView()

-      attachBindings = constructCallbackToAttachBindingsToView(view, toView, bindingSourceProps)
+      view._attachedBindings.push(bindingChain = [])
+      attachBindings = constructCallbackToAttachBindingsToView(view, toView, bindingChain, bindingSourceProps)
       attachBindings()

 viewMixin =
+  _attachedBindings: []
   initBindings: -> initBindings(@)

 modelMixin =


Add tooltip displaying values on categroy charts on mouseover

--- app/assets/javascripts/report.js.coffee
+++ app/assets/javascripts/report.js.coffee
@@ -3,8 +3,18 @@
 #= require plugins/jqplot.pieRenderer.min
 #= require plugins/jqplot.categoryAxisRenderer.min
 #= require plugins/jqplot.pointLabels.min
+#= require plugins/jqplot.highlighter.min

 $ ->
+  defaultHighlighterOptions = {
+    show: true,
+    tooltipAxes: 'y',
+    useAxesFormatters: false,
+    tooltipFormatString: '%f p/h',
+    fadeTooltip: true,
+    tooltipOffset: 4
+  }
+
   data = $('div#chart_data').data()
   if $('#hours_per_project').size() > 0
     $.jqplot 'hours_per_project',
@@ -28,7 +38,8 @@
             pad: 1.05,
             tickOptions: {formatString: '%d h'}
           }
-        }
+        },
+        highlighter: defaultHighlighterOptions
       }

   if $('#hour_distribution').size() > 0
@@ -65,7 +76,8 @@
             pad: 1.05,
             tickOptions: {formatString: '%d p'}
           }
-        }
+        },
+        highlighter: defaultHighlighterOptions
       }

   if $('#points_distribution').size() > 0
@@ -103,9 +115,9 @@
             tickOptions: {formatString: '%d p/h'},
             min: 0,
             tickInterval: 1
-
           }
-        }
+        },
+        highlighter: defaultHighlighterOptions
       }

   if $('#tickets_per_project').size() > 0


Set proper path for soundmanager flash files

--- app/assets/javascripts/sounds.js.coffee
+++ app/assets/javascripts/sounds.js.coffee
@@ -8,7 +8,7 @@
   constructor: ->
     @manager = window.soundManager

-    @manager.url = '/assets'
+    @manager.url = '/assets/flash'
     @manager.useHTML5Audio = true
     @manager.preferFlash = false
     @manager.flashVersion = 9


handle >>

handle >>

--- app/assets/javascripts/task_list.coffee
+++ app/assets/javascripts/task_list.coffee
@@ -117,7 +117,7 @@
   ^
   (?:                     # optional list prefix, consisting of
     \s*                   # optional leading whitespace
-    (?:>\s+)*             # zero or more blockquotes
+    (?:>\s*)*             # zero or more blockquotes
     (?:[-+*]|(?:\d+\.))   # item indicator
   )?
   \s*                     # optional whitespace prefix


Reconnecting UserWebSocket

Reconnecting UserWebSocket

--- app/assets/javascripts/ws.helper.coffee
+++ app/assets/javascripts/ws.helper.coffee
@@ -5,8 +5,9 @@
     return options

   .factory 'UserWebSocket', [
+    '$timeout'
     'WebSocketOptions'
-    (options) ->
+    ($timeout, options) ->
       class UserWebSocket

         constructor: (url) ->
@@ -18,13 +19,18 @@
           @handlers[handler.protocol] = handler for handler in handlers
           return

-        connect: ->
+        connect: =>
           @socket = new WebSocket @url
           @socket.onmessage = (event) =>
             msg = JSON.parse(event.data)
             handler = @handlers[msg.protocol]
             handler.onmessage(msg) if handler?
             return
+
+          @socket.onclose = (event) =>
+            $timeout @connect, 10000
+            return
+
           return

         send: (msg) ->


[grunt] convert `smartPlurals` Nunjucks' global function into filter; fix missing argument

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -204,9 +204,9 @@
            * @param {number} count                  Current count
            * @param {array}  forms                  List of possible plural forms
            * @param {string} locale = currentLocale Locale name
-           * @return {string} Pluralized string
-          ###
-          env.addGlobal '_p', (count, locale = currentLocale) ->
+           * @return {string} Correct plural form
+          ###
+          env.addFilter '_p', (count, forms, locale = currentLocale) ->
             smartPlurals.Plurals.getRule(locale)
             smartPlurals(count, forms)


'neft-*' dependencies now may contains 'styles' dir

--- cli/tasks/build/parse/styles.coffee
+++ cli/tasks/build/parse/styles.coffee
@@ -31,8 +31,9 @@

 	packageConfig = JSON.parse fs.readFileSync('./package.json', 'utf-8')
 	for key of packageConfig.dependencies
-		if /^neft\-styles\-/.test(key)
-			inputDirs.push path: "node_modules/#{key}", prefix: "#{key}/"
+		stylesPath = "node_modules/#{key}/styles"
+		if /^neft\-/.test(key) and fs.existsSync(stylesPath)
+			inputDirs.push path: stylesPath, prefix: "#{key}/"

 	if utils.isObject(packageConfig.styles)
 		for key, val of packageConfig.styles


remove old smoke tags

remove old smoke tags

--- app/coffee/HealthCheckController.coffee
+++ app/coffee/HealthCheckController.coffee
@@ -10,7 +10,7 @@
 buildUrl = (path) ->
 	"http://localhost:#{port}#{path}"

-module.exports =
+module.exports = HealthCheck =
 	check : (callback)->
 		project_id = ObjectId()
 		user_id = ObjectId(settings.tags.healthCheck.user_id)
@@ -64,4 +64,20 @@
 					}, (err, res, body) ->
 						if err?
 							logger.log "Failed executing delete tags health check"
-						callback(err, res, body)
+						otherTags = (tag for tag in tags when tag._id isnt tag_id)
+						HealthCheck._removeOldTags otherTags, () ->
+							callback(err, res, body)
+
+	_removeOldTags: (tags, callback) ->
+		now = new Date()
+		getAge = (tag) ->
+			(now - ObjectId(tag._id).getTimestamp())
+		oldTags = (tag for tag in tags when getAge(tag) > 5*60*1000)
+		removeTag = (tag, cb) ->
+			logger.log {tag:tag}, "removing old tag"
+			request.del {
+				url: buildUrl("/user/#{user_id}/tag/#{tag._id}")
+				json: true
+			}, (err) ->
+				cb() # ignore failures removing old tags
+		async.mapSeries oldTags, removeTag, callback


Updated commment description

Updated commment description

--- src/middleware/messageStore.coffee
+++ src/middleware/messageStore.coffee
@@ -40,7 +40,7 @@
 		tx.taskID = ctx.taskID

-	# check if transaction request body is false and remove
+	# check if channel request body is false and remove
 	if ctx.authorisedChannel.requestBody == false
 		# reset request body
 		tx.request.body = ''


set inverse

set inverse

--- client/skr/models/PickTicket.coffee
+++ client/skr/models/PickTicket.coffee
@@ -15,4 +15,4 @@
         location:    { model: "Location" }
         customer:    { model: "Customer" }
         terms:       { model: "PaymentTerm" }
-        lines:       { collection: "PtLine" }
+        lines:       { collection: "PtLine", inverse: 'pick_ticket' }


Uncache total when lines change

Uncache total when lines change

--- client/skr/models/SalesOrder.coffee
+++ client/skr/models/SalesOrder.coffee
@@ -52,12 +52,15 @@
     constructor: ->
         super
         @on("change:customer", @onCustomerChange)
-        @listenTo @lines, 'change:total', -> @trigger('change:order_total')
+        @listenTo @lines, 'change:total', ->
+            @trigger('change', @, {})
+            delete this._cache.total
+            @unset('order_total')

-    onCustomerChange: (c) ->
+    onCustomerChange: ->
         return unless @isNew()
         associations = ['billing_address', 'shipping_address']
-        c.withAssociations(associations).then( =>
+        @customer.withAssociations(associations).then( =>
             for name in associations
-                this[name].copyFrom(c[name])
+                this[name].copyFrom(@customer[name])
         )


proofread help markdown

proofread help markdown

--- src/smc-webapp/editor_latex.coffee
+++ src/smc-webapp/editor_latex.coffee
@@ -63,13 +63,14 @@

 LaTeX is a sophisticated markup language and processor for typesetting documents.
 For a general introduction, read this [LaTeX wiki book](https://en.wikibooks.org/wiki/LaTeX) or any other resource.
-In general, it works by editing a "source code", visible on the left, and compiles it to a PDF document.
+In general, it works by editing source code, visible on the left, and compiling it to a PDF document,
+visible on the right.
 #{SiteName} manages this task for you, by regularly saving and running the LaTeX processor for you.

-On the right hand side, there are several tabs like this one here for help:
-
-* **Preview** quickly renders a few some pages to see how the current part of the document looks like.
-* **Issues** lists you all compilation warnings and errors.
+On the right-hand side there are several tabs like this one here for help:
+
+* **Preview** quickly renders a few pages to see how the current part of the document looks.
+* **Issues** lists all compilation warnings and errors.
   Click on the buttons to jump to the corresponding line in the input code on the left.
   _LaTeX won't compile (or only partially or in a wrong way) as long as there are any errors left!_
 * **PDF** shows you an embedded view of the compiled PDF file.
@@ -82,7 +83,7 @@
   * **Sage**: runs "SageMath" for [SageTeX](https://www.ctan.org/pkg/sagetex?lang=en), usually managed by the build process
   * **Clean**: deletes temporary files
   * **Build Command**: The drop-down list on the right hand side lets you specify the compilation program. On the left, you can edit the command even further. It is saved as part of the document, at the bottom.
-By default, it runs [LatexMK](https://www.ctan.org/pkg/latexmk/) which manages temporary files and bibtex, and also runs SageTeX if necessary.
+By default, it runs [LatexMK](https://www.ctan.org/pkg/latexmk/) which manages temporary files and bibtex, and runs SageTeX if necessary.

 ## LaTeX Engines

@@ -93,15 +94,15 @@

 ### Forward & Inverse Search

-Forward and inverse search help you enormeously with navigating around in a larger document.
-
-**Forward**: place your cursor at a specific location in the editor on the left hand side.
+Forward and inverse search are extremely helpful for navigating in a larger document.
+
+**Forward**: place your cursor at a specific location in the editor on the left-hand side.
 Click the "Forward" button or the `[ALT]`+`[Return]` keyboard shortcut to jump to the corresponding
-location in the preview on the right hand side.
+location in the preview on the right-hand side.
 (It might not always work in case the full positional information is not available.)

 **Inverse**: Double-click on an area of interest on the right hand side in the **Preview** area.
-The cursor on the left hand side will jump to the paragraph in the source-code.
+The cursor on the left-hand side will jump to the paragraph in the source-code.

 ## Quickstart

@@ -157,17 +158,17 @@

 The `\\` character has a special meaning.
 It signals a LaTeX command or is used as an escape character.
-To enter a backslash, escape it's meaning by entering it twice: `\\\\`.
-
-A dollar-sign is entered as `\\$`, which escapes the meaning of "formula-start".
-
-### The preview does not update
+To enter a backslash, escape its meaning by entering it twice: `\\\\`.
+
+A dollar sign is entered as `\\$`, which escapes the meaning of "formula-start".
+
+### What to do if the preview does not update

 Possible reasons:

 1. Are there any errors in the "Issues" tab? LaTeX only compiles well if there are zero reported errors.
 2. Long documents could take an extended period of time to complete. In the "Preview" tab, disable the preview and only enable it once to avoid piling up too much work on the back-end.
-3. Similarly, computational-heavy "SageTeX" computations could lead to too long compilation times.
+3. Similarly, computational-heavy "SageTeX" computations could lead to excessive compilation times.
    You can pre-compute results or split the document into smaller parts.

 ### How to deal with large documents across multiple source files?


Groups: forgotten queue.next() is added for killing process

--- workers/productimport/main.coffee
+++ workers/productimport/main.coffee
@@ -118,7 +118,8 @@
         queue.next()
       -> importPacks ->
         console.log 'All Packs are added'
-      -> process.kill(1)
+        queue.next()
+      -> process.kill()
     ]

     daisy queue


add credit for suggestions

add credit for suggestions

--- scripts/dgshow.coffee
+++ scripts/dgshow.coffee
@@ -56,6 +56,7 @@
   robot.respond /dgshow suggest (.*) (http.*)/, (msg) ->
       cardName = msg.match[1]
       cardUrl = msg.match[2]
+      suggester = msg.message.user.name
       if not cardName.length
         msg.send "You must provide a name for the link."
         return
@@ -67,7 +68,7 @@
         msg.send "Error: Trello list ID is not specified"
       if not (process.env.HUBOT_TRELLO_KEY and process.env.HUBOT_TRELLO_TOKEN and process.env.HUBOT_TRELLO_LIST)
          return
-      createCard msg, cardName, cardUrl
+      createCard msg, cardName, cardUrl, suggester

   robot.respond /dgshow suggestions/i, (msg) ->
     Trello = require("node-trello")
@@ -79,10 +80,10 @@
       msg.send "Suggestions in " + data.name + ":"
       msg.send "- " + card.name + " "+card.desc for card in data.cards

-createCard = (msg, cardName, cardUrl) ->
+createCard = (msg, cardName, cardUrl, suggester) ->
   Trello = require("node-trello")
   t = new Trello(process.env.HUBOT_TRELLO_KEY, process.env.HUBOT_TRELLO_TOKEN)
-  t.post "/1/cards", {name: cardName, desc: cardUrl, idList: process.env.HUBOT_TRELLO_LIST}, (err, data) ->
+  t.post "/1/cards", {name: cardName+" (h/t "+suggester+")", desc: cardUrl, idList: process.env.HUBOT_TRELLO_LIST}, (err, data) ->
     if err
       msg.send "There was an error creating the card"
       return


Exclusion using 'isnt'.

Exclusion using 'isnt'.

--- scripts/points.coffee
+++ scripts/points.coffee
@@ -103,17 +103,14 @@
             chat = JSON.parse(body)
             people = flatten([chat.chatters.moderators, chat.chatters.staff, chat.chatters.admins, chat.chatters.global_mods, chat.chatters.viewers])

-            if robot.auth.hasRole('awebot', ['bot'])
-                # No points for awebot
-            else
-                for username in people
-                    points[username] ?= 0
-                    points[username] += 5
-                    save(robot)
+            for username in people isnt 'awebot'
+                points[username] ?= 0
+                points[username] += 5
+                save(robot)

-                # Winners (and then recall) is equal to all users
-                # with points, and their points respectively.
-                robot.brain.set 'winners', points
+            # Winners (and then recall) is equal to all users
+            # with points, and their points respectively.
+            robot.brain.set 'winners', points
     ), 60000

     # Get a list of stored people and points


auth: middleware shouldnt error

auth: middleware shouldnt error

--- services/auth.coffee
+++ services/auth.coffee
@@ -29,7 +29,7 @@
         Promise.resolve null
     ).then (user) ->
       if not user?
-        next new router.Error status: 401, detail: 'Unauthorized'
+        next()
       else
         # Authentication successful
         req.user = user


Removing debugging log statements from station dots

--- telostats/static/coffee/app.coffee
+++ telostats/static/coffee/app.coffee
@@ -99,9 +99,6 @@
     drawStationDots = () ->
         dots = stationDotsGroup.selectAll('circle').data(stationCoords)

-        console.log("Drawing station dots with zoom ", map.zoom())
-        console.log("Dots should be ", stationDotSize(map.zoom()),  "px big")
-
         # Position the dots
         dots
             .attr('r', stationDotSize(map.zoom()))


Ace: Put back save as feature.

Ace: Put back save as feature.

--- client/Ace/ace.coffee
+++ client/Ace/ace.coffee
@@ -100,10 +100,11 @@

     if enableShortcuts
       @addKeyCombo 'save',       'Ctrl-S',           @bound 'requestSave'
+      @addKeyCombo "saveAs",     "Ctrl-Shift-S",     @bound 'requestSaveAs'
+      @addKeyCombo 'saveAll',    'Ctrl-Alt-S',       @bound 'saveAllFiles'
       @addKeyCombo 'fullscreen', 'Ctrl-Enter', =>    @getDelegate().toggleFullscreen()
       @addKeyCombo 'gotoLine',   'Ctrl-G',           @bound 'showGotoLine'
       @addKeyCombo 'gotoLineL',  'Ctrl-L',           @bound 'showGotoLine'
-      @addKeyCombo 'saveAll',    'Ctrl-Alt-S',       @bound 'saveAllFiles'
       @addKeyCombo 'settings',   'Ctrl-,',           noop # override default ace settings view

       if createFindAndReplaceView
@@ -114,7 +115,6 @@
         @addKeyCombo 'replace', 'Ctrl-Shift-F', =>  @emit 'FindAndReplaceViewRequested', yes

       # these features are broken with IDE, should reimplement again
-      # @addKeyCombo "saveAs",     "Ctrl-Shift-S",     @bound "requestSaveAs"
       # @addKeyCombo "preview",    "Ctrl-Shift-P", =>  @getDelegate().preview()
       # @addKeyCombo "closeTab",   "Ctrl-W", "Ctrl-W", @bound "closeTab"

@@ -178,7 +178,7 @@
     localSync.on 'LocalContentCouldntSynced', (file) =>
       @notify 'File coudn\'t be synced to remote please try again...', null, null, 5000

-  requestSaveAs: (options) ->
+  requestSaveAs: ->
     contents = @getContents()
     @emit 'ace.requests.saveAs', contents


jenkins-notifier: added notification-stratgey-feature

--- src/scripts/jenkins-notifier.coffee
+++ src/scripts/jenkins-notifier.coffee
@@ -12,13 +12,41 @@
 #   None
 #
 # URLS:
-#   POST /hubot/jenkins-notify?room=<room>[&type=<type>]
+#   POST /hubot/jenkins-notify?room=<room>[&type=<type>][notstrat=<notificationSTrategy>]
 #
+# Notification Strategy is [Ff][Ss] which stands for "Failure" and "Success"
+# Capitalized letter means: notify always
+# small letter means: notify only if buildstatus has changed
+# "Fs" is the default
+#
 # Authors:
 #   spajus
+#   k9ert (notification strategy feature)

 url = require('url')
 querystring = require('querystring')
+
+buildStatusChanged = (data, @failing) ->
+  if data.build.status == 'FAILURE' and data.name in @failing
+    return false
+  if data.build.status == 'FAILURE' and not (data.name in @failing)
+    return true
+  if data.build.status == 'SUCCESS' and data.name in @failing
+    return true
+  if data.build.status == 'SUCCESS' and not (data.name in @failing)
+    return false
+  console.log "this should not happen"
+
+shouldNotify = (notstrat, data, @failing) ->
+  if data.build.status == 'FAILURE'
+    if /F/.test(notstrat)
+      return true
+    return buildStatusChanged(data, @failing)
+  if data.build.status == 'SUCCESS'
+    if /S/.test(notstrat)
+      return true
+    return buildStatusChanged(data, @failing)
+

 module.exports = (robot) ->

@@ -29,28 +57,33 @@

     res.end('')

-    envelope = {}
+    envelope = {notstrat:"Fs"}
     envelope.user = {}
     envelope.room = query.room if query.room
     envelope.user.type = query.type if query.type
-
+    envelope.notstrat = query.notstrat if query.notstrat
     try
       for key of req.body
         data = JSON.parse key

       if data.build.phase == 'FINISHED'
+        robot.send envelope, data.name
         if data.build.status == 'FAILURE'
           if data.name in @failing
             build = "is still"
           else
             build = "started"
-          robot.send envelope, "#{data.name} build ##{data.build.number} #{build} failing (#{encodeURI(data.build.full_url)})"
+          robot.send envelope, "#{data.name} build ##{data.build.number} #{build} failing (#{encodeURI(data.build.full_url)})" if shouldNotify(envelope.notstrat, data, @failing)
           @failing.push data.name unless data.name in @failing
         if data.build.status == 'SUCCESS'
           if data.name in @failing
-            index = @failing.indexOf data.name
-            @failing.splice index, 1 if index isnt -1
-            robot.send envelope, "#{data.name} build was restored ##{data.build.number} (#{encodeURI(data.build.full_url)})"
+            build = "was restored"
+            robot.send envelope, "woop2"
+          else
+            build = "suceeded"
+          robot.send envelope, "#{data.name} build ##{data.build.number} #{build} (#{encodeURI(data.build.full_url)})"  if shouldNotify(envelope.notstrat, data, @failing)
+          index = @failing.indexOf data.name
+          @failing.splice index, 1 if index isnt -1

     catch error
       console.log "jenkins-notify error: #{error}. Data: #{req.body}"


Build notification changes (death star)

Build notification changes (death star)

--- src/scripts/jenkins-notifier.coffee
+++ src/scripts/jenkins-notifier.coffee
@@ -63,50 +63,42 @@
             robot.messageRoom room, "http://i.imgur.com/CoqJxBx.gif"
         if data.build.status == 'SUCCESS'
           console.log "Success"
-          if data.name in @failing
-            index = @failing.indexOf data.name
-            @failing.splice index, 1 if index isnt -1
-            robot.messageRoom room, "#{data.name} build is fixed! ##{data.build.number} (#{encodeURI(data.build.full_url)})"
-          else
-            console.log "Sending success"
-#            robot.messageRoom "#dibsy-dev", "#{data.name} build succeeded! ##{data.build.number} (#{encodeURI(data.build.full_url)})"
-            robot.messageRoom room, "#{data.name} build succeeded! ##{data.build.number} (#{encodeURI(data.build.full_url)})"
+          #if data.name in @failing
+          #  index = @failing.indexOf data.name
+          #  @failing.splice index, 1 if index isnt -1
+          #  robot.messageRoom room, "#{data.name} build is fixed! ##{data.build.number} (#{encodeURI(data.build.full_url)})"
+          #else
+          #  console.log "Sending success"
+          #  robot.messageRoom room, "#{data.name} build succeeded! ##{data.build.number} (#{encodeURI(data.build.full_url)})"
           if data.name == '1stdibs.com Deploy Production PROD PROD PROD PROD'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
             http.get 'http://xserve:5051/shipit', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
               console.log res.statusCode
+            robot.messageRoom "#release", "1stdibs.com hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
           if data.name == 'Admin-v2 Deploy (PROD)'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
             http.get 'http://xserve:5051/shipit-adminv2', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
               console.log res.statusCode
+            robot.messageRoom "#release", "Admin v2 hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
           if data.name == 'Admin-v1 Deploy (PROD) (RACKSPACE)'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
             http.get 'http://xserve:5051/shipit-adminv1', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
               console.log res.statusCode
+            robot.messageRoom "#release", "Admin v1 hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
           if data.name == 'JAVA-InventoryService (Prod)'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
             http.get 'http://xserve:5051/shipit-inventory', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
               console.log res.statusCode
-            robot.messageRoom "#release", "I hope you know what you're doing..."
-          if data.name == 'JAVA-InventoryService-Logistics (PROD)'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
-            http.get 'http://xserve:5051/shipit-inventory', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
-              console.log res.statusCode
+            robot.messageRoom "#release", "Inventory service hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
           if data.name == 'JAVA-IdentityService (Prod)'
-            console.log "LEEEEEEEEEEEROOOOOOOOOOOOOY"
             http.get 'http://xserve:5051/shipit-identity', (res) ->
-              console.log "JEEEEEEEEEEEEEENKIIIIIIIIINS"
               console.log res.statusCode
+            robot.messageRoom "#release", "Identity service hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
+          if data.build.parameters.SERVER_HOSTNAME == 'deathstar.1stdibs.com'
+            http.get 'http://xserve:5051/deathstar', (res) ->
+              console.log res.statusCode
+            robot.messageRoom "#general", "The Death Star is now fully armed and operational"

     catch error
       console.log "jenkins-notify error: #{error}. Data: #{req.body}"


4.3.4

--- src/scripts/jenkins-notifier.coffee
+++ src/scripts/jenkins-notifier.coffee
@@ -40,10 +40,10 @@

       if data.build.phase == 'STARTED'
         console.log "jenkins-notify: A build has started! Oooh, the excitement!!"
-          if data.name == 'Mothra (QA)'
-            http.get 'http://xserve:5051/mothra-qa', (res) ->
-              console.log "MOTHRA!!"
-              console.log res.statusCode
+        if data.name == 'Mothra (QA)'
+          http.get 'http://xserve:5051/mothra-qa', (res) ->
+            console.log "MOTHRA!!"
+            console.log res.statusCode
       if data.build.phase == 'COMPLETED'
         console.log "jenkins-notify: A build has finished! Oooh, the excitement!!"
         if data.build.status == 'FAILURE'


Remove unnecessary console.log statement

This clutters the browser console. It looks like it's been left in there by accident anyway :)

--- client/helpers.coffee
+++ client/helpers.coffee
@@ -9,7 +9,6 @@
 # return path
 pathFor = (path, view) ->
   throw new Error('no path defined') unless path
-  console.log path,view
   if path.hash?.route?
     view = path
     path = view.hash.route


fix the English in https://github.com/sagemathinc/cocalc/pull/3768

--- src/smc-webapp/redux_account.coffee
+++ src/smc-webapp/redux_account.coffee
@@ -59,11 +59,11 @@
             is_logged_in : user_type == 'signed_in'

     sign_in: (email, password) =>
-        doc_conn = '[connectivity issues](https://doc.cocalc.com/howto/connectivity-issues.html)'
+        doc_conn = '[connectivity debugging tips](https://doc.cocalc.com/howto/connectivity-issues.html)'
         err_help = """
                    Please reload this browser tab and try again.

-                   If that doesn't work after a few minutes, consult #{doc_conn} or email #{help()}.
+                   If that doesn't work after a few minutes, try these #{doc_conn} or email #{help()}.
                    """

         @setState(signing_in: true)


fix https://github.com/sagemathinc/smc/issues/1112 -- "don't autosave all files if not connected"

--- src/smc-webapp/redux_account.coffee
+++ src/smc-webapp/redux_account.coffee
@@ -242,7 +242,11 @@
     # Use the most recent autosave value.
     if autosave
         save_all_files = () ->
-            redux.getActions('projects').save_all_files()
+            if salvus_client.is_connected()
+                console.log 'saving all files'
+                redux.getActions('projects').save_all_files()
+            else
+                console.log 'not saving'
         _autosave_interval = setInterval(save_all_files, autosave * 1000)

 account_store = redux.getStore('account')


Remove console.dir

Remove console.dir

--- server/lib/git.coffee
+++ server/lib/git.coffee
@@ -9,7 +9,6 @@
   )
   branchName = ''

-  console.dir getBranchCommand
   getBranchCommand.stdout.on('data', (str) ->
     branchName = str
   )


add console log

add console log

--- scripts/bungie-data-helper.coffee
+++ scripts/bungie-data-helper.coffee
@@ -17,6 +17,7 @@
       damageTypeName = response.definitions.damageTypes[item.damageTypeHash].damageTypeName
     else
       damageTypeName = 'Kinetic'
+      console.log("damageType empty for #{itemDefs.itemName}")

     prefix = 'http://www.bungie.net'
     iconSuffix = itemDefs.icon


move to builder.notAllowed

move to builder.notAllowed

--- src/textorum/relaxng/objects.coffee
+++ src/textorum/relaxng/objects.coffee
@@ -30,6 +30,8 @@
   DEBUG = false

   uniqueIndex = 0
+  indexCount = {}
+
   patternIntern = {
     internSuccess: 0,
     internCheck: 0,
@@ -65,14 +67,14 @@
     if node instanceof Pattern
       return node
     if not node
-      return new NotAllowed("trying to load empty pattern")
+      return builder.notAllowed("trying to load empty pattern")

     children = node.childNodes

     pattern = switch h.getLocalName(node)
       when 'element' then new Element children[0], children[1]
       when 'define' then new Define h.getNodeAttr(node, "name"), children[0]
-      when 'notAllowed' then new NotAllowed("not allowed by pattern", node)
+      when 'notAllowed' then builder.notAllowed("not allowed by pattern", node)
       when 'empty' then builder.empty(undefined, node)
       when 'text' then new Text()
       when 'data' then new Data h.getNodeAttr(node, "datatypeLibrary"), h.getNodeAttr(node, "type"), children
@@ -103,7 +105,9 @@
       @choiceMap = {}
       patternIntern['empty'] = new Empty()
       patternIntern['notallowed'] = new NotAllowed()
-    notAllowed: ->
+    notAllowed: (message, pattern, childnode, priority) ->
+      if message isnt undefined
+        return new NotAllowed(message, pattern, childnode, priority)
       return patternIntern['notallowed']
     empty: (message, node) ->
       return patternIntern['empty']
@@ -134,7 +138,7 @@
         return @internChoice(pattern1, pattern2)
       else
         if @choiceMap[pattern.uniqueIndex] isnt undefined
-          return new NotAllowed()
+          return @notAllowed()
       return pattern

     choice: (pattern1, pattern2) ->
@@ -300,6 +304,8 @@
         @uniqueIndex = "empty"
       else
         @uniqueIndex = uniqueIndex++
+        indexCount[@constructor.name] ||= 0
+        indexCount[@constructor.name]++

     choiceLeaves: ->
       [@uniqueIndex]
@@ -317,7 +323,7 @@
       return node._memoizedStartTagOpenDeriv[this.uniqueIndex]

     _startTagOpenDeriv: (node) ->
-      return new NotAllowed("expected #{this}", this, node)
+      return builder.notAllowed("expected #{this}", this, node)

     startTagCloseDeriv: (node) ->
       if node._memoizedstartTagCloseDeriv is undefined
@@ -339,12 +345,12 @@
     _endTagDeriv: (node) ->
       if this instanceof NotAllowed
         return this
-      return new NotAllowed("invalid pattern: #{this}", this, node)
+      return builder.notAllowed("invalid pattern: #{this}", this, node)

     attDeriv: (attribute) ->
       if h.getNamespacePrefix(attribute.name) is "xml"
         return this
-      return new NotAllowed("unknown attribute #{attribute.name} (value #{attribute.value}", this, attribute)
+      return builder.notAllowed("unknown attribute #{attribute.name} (value #{attribute.value}", this, attribute)

     childDeriv: (node, descend = false) ->
       _nodelog(node, "starting childDeriv", node, this)
@@ -365,7 +371,7 @@
           descend = descend - 1
         patt = patt.childrenDeriv(node.childNodes, descend)
       else
-        return new After(builder.empty("skipping 1"), builder.empty("skipping descent"))
+        return builder.after(builder.empty("skipping 1"), builder.empty("skipping descent"))
       if patt instanceof NotAllowed
         return patt
       return patt.endTagDeriv(node)
@@ -393,7 +399,7 @@
       return patt

     textDeriv: (node) ->
-      return new NotAllowed("#{this}", this, node)
+      return builder.notAllowed("#{this}", this, node)

     toString: ->
       if @_toStringCache is undefined
@@ -751,7 +757,7 @@
       @dataType = dataType
       @type = type
       @params = []
-      @except = new NotAllowed()
+      @except = builder.notAllowed()
       for param in paramList
         if param.local is "param"
           @params.push getPattern param
@@ -804,7 +810,7 @@
     _startTagCloseDeriv: (node) ->
       patternIntern['attributeShutDown'] += 1
       return globalNotAllowed
-      return new NotAllowed("attr StartTagCloseDeriv #{this}", this, node)
+      return builder.notAllowed("attr StartTagCloseDeriv #{this}", this, node)
     matchAttrName: (attribute) ->

     attDeriv: (attribute) ->
@@ -850,7 +856,7 @@
       if nameCheck
         builder.after @pattern, builder.empty()
       else
-        new NotAllowed("expecting #{@name}", @name, node, 5 + h.depth(node))
+        builder.notAllowed("expecting #{@name}", @name, node, 5 + h.depth(node))

     _toString: ->
       "element #{@name} { #{@pattern} }"
@@ -868,17 +874,17 @@
       @dereference()
       if @pattern?
         return @pattern.startTagOpenDeriv(node)
-      return new NotAllowed("cannot find reference '#{@refname}'", this, node)
+      return builder.notAllowed("cannot find reference '#{@refname}'", this, node)
     _endTagDeriv: (node) ->
       @dereference()
       if @pattern?
         return @pattern.endTagDeriv(node)
-      return new NotAllowed("cannot find reference '#{@refname}'", this, node)
+      return builder.notAllowed("cannot find reference '#{@refname}'", this, node)
     attDeriv: (attribute) ->
       @dereference()
       if @pattern?
         return @pattern.attDeriv(attribute)
-      return new NotAllowed("cannot find reference '#{@refname}'", this, node)
+      return builder.notAllowed("cannot find reference '#{@refname}'", this, node)

     _toString: ->
       @refname
@@ -928,5 +934,5 @@
     Ref,
     Text,
     Value,
-    patternIntern, uniqueIndex
+    patternIntern, uniqueIndex, indexCount
   }


Have unsubscribeEmailFromMarketingEmails handle existing ZP contacts

--- server/commons/unsubscribe.coffee
+++ server/commons/unsubscribe.coffee
@@ -29,11 +29,21 @@

   # unsubscribe user from ZP
   searchUrl = "https://www.zenprospect.com/api/v1/contacts/search?api_key=#{config.zenProspect.apiKey}&q_keywords=#{email}"
+  contactUrl = "https://www.zenprospect.com/api/v1/contacts?api_key=#{config.zenProspect.apiKey}"
+  DO_NOT_CONTACT = '57290b9c7ff0bb3b3ef2bebb'
   [res] = yield request.getAsync({ url:searchUrl, json: true })
-  if res.statusCode is 200 and res.body.contacts.length is 0
-    postContactUrl = "https://www.zenprospect.com/api/v1/contacts?api_key=#{config.zenProspect.apiKey}"
-    json = { email, contact_stage_id: '57290b9c7ff0bb3b3ef2bebb' } # contact stage: do not contact
-    [res] = yield request.postAsync({ url:postContactUrl, json })
+  if res.statusCode is 200
+    if res.body.contacts.length is 0
+      # post a contact with status "do not contact" to prevent reaching out
+      json = { email, contact_stage_id: DO_NOT_CONTACT } # contact stage: do not contact
+      [res] = yield request.postAsync({ url:contactUrl, json })
+    else
+      # update any existing contacts "to do not contact"
+      for contact in res.body.contacts
+        if contact.contact_stage_id isnt DO_NOT_CONTACT
+          url = "https://www.zenprospect.com/api/v1/contacts/#{contact.id}?api_key=#{config.zenProspect.apiKey}"
+          json = {contact_stage_id: DO_NOT_CONTACT}
+          [res] = yield request.putAsync({ url, json })

   # unsubscribe user from Intercom
   tries = 0


Added integration test for model formatters

--- test/integration/bound.spec.coffee
+++ test/integration/bound.spec.coffee
@@ -87,3 +87,11 @@
     @render 'div[data-foo=number] @number', model
     expect(@body.find('div').attr('data-foo')).to.eql("0")
     expect(@body.find('div').text()).to.eql("0")
+
+  it 'uses model formatter', ->
+    model = Serenade({ name: "Jonas" })
+    model.property("name", format: (val) -> val.toUpperCase())
+    @render 'div[data-name=@name style:color=@name] @name', model
+    expect(@body.find('div').attr('data-name')).to.eql("JONAS")
+    expect(@body.find('div').css("color")).to.eql("JONAS")
+    expect(@body.find('div').text()).to.eql("JONAS")


remove

remove

--- commands/truth.coffee
+++ commands/truth.coffee
@@ -1,7 +0,0 @@
-###
-ipad2 with iOS 5
-###
-
-brain.addPattern 'ipad2',
-    match: /ipad\s?2\s.*\siOS(\s?)5/i
-    fn: (user, m, cb) -> cb "http://i.imgur.com/VYyQk.gif"


add random string to smoke tests to avoid collision

--- test/smoke/coffee/SmokeTests.coffee
+++ test/smoke/coffee/SmokeTests.coffee
@@ -6,10 +6,14 @@

 buildUrl = (path) -> "http://#{Settings.internal.clsi.host}:#{Settings.internal.clsi.port}/#{path}"

+random = require("crypto").randomBytes(4).toString("hex")
+
+url = buildUrl("project/smoketest-#{random}/compile")
+
 describe "Running a compile", ->
 	before (done) ->
 		request.post {
-			url: buildUrl("project/smoketest/compile")
+			url: url
 			json:
 				compile:
 					resources: [


Move passport to $httpInitializer

Move passport to $httpInitializer

--- server/packages/user/index.coffee
+++ server/packages/user/index.coffee
@@ -6,8 +6,8 @@

 	user: req.user

-exports.$httpMiddleware = (http) ->
-
+exports.$httpInitializer = (req, res, next) ->
+
 	{models: User: User} = require 'server/jugglingdb'

 	LocalStrategy = require("passport-local").Strategy
@@ -46,6 +46,10 @@

 				done null, user

+	next()
+
+exports.$httpMiddleware = (http) ->
+
 	label: 'Load user using passport'
 	middleware: [


IMPROVED - image-load failures get automatic, exponential fall-off retrys as long as they are requested

--- source/Art/Engine/Elements/Shapes/BitmapElement.coffee
+++ source/Art/Engine/Elements/Shapes/BitmapElement.coffee
@@ -22,9 +22,24 @@
     get: (url, initializerPromise) ->
       return Bitmap.get url unless isString url # non-string sources are not cached
       @_referenceCounts[url] = (@_referenceCounts[url] || 0) + 1
-      out = @_cache[url] ||= initializerPromise || Bitmap.get url
-      out.then (bitmap) => @_loaded[url] = bitmap
-      out
+      @_cache[url] ||= initializerPromise || @_get url
+      .tap (bitmap) => @_loaded[url] = bitmap
+
+    _get: (url, tryCount = 0) ->
+      Bitmap.get url
+      # .tap =>
+      #   if tryCount > 0
+      #     log sourceToBitmapCacheSuccess: {url, tryCount, refs: @_referenceCounts[url]}
+      .catch (error) =>
+        if @_referenceCounts[url] > 0
+          retryInSeconds = min(30, (2 ** tryCount)) * .9 + .2 * Math.random()
+          # log sourceToBitmapCache1: {retryInSeconds, url, tryCount, refs: @_referenceCounts[url], message: error?.message}
+          timeout 1000 * retryInSeconds, =>
+            # log sourceToBitmapCache2: {retryInSeconds, url, tryCount, refs: @_referenceCounts[url]}
+            if @_referenceCounts[url] > 0
+              @_get url, tryCount + 1
+            else throw error
+        else throw error

     loaded: (url) -> @_loaded[url]


Update Atom config

Update Atom config

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -1,15 +1,15 @@
 'exception-reporting':
   'userId': '70a0032d-3fb2-4bcb-e887-64623e256e19'
 'release-notes':
-  'viewedVersion': '0.69.0'
+  'viewedVersion': '0.71.0'
 'welcome':
   'showOnStartup': false
 'metrics':
   'userId': 'ba44e3beb28ecd4cac067ffa00fb25caece41ae8'
 'editor':
   'tabLength': 4
+  'showIndentGuide': true
   'fontSize': 12
-  'showIndentGuide': true
 'core':
   'themes': [
     'atom-dark-ui'
@@ -31,7 +31,6 @@
     'language-ruby-on-rails'
     'language-toml'
     'vim-mode'
-    'editor-stats'
     'symbols-view'
     'command-logger'
     'archive-view'
@@ -63,3 +62,6 @@
     'text.plain'
     'text.plain.null-grammar'
   ]
+'autoclose-html':
+  'closeOnEndOfOpeningTag': true
+  'forceInline': 'div, span, title, h1, h2, h3, h4, h5, h6'


Fixed toggle thumbnails settings

Fixed toggle thumbnails settings

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -178,14 +178,19 @@

     containers = ['leftside', 'rightside', 'overlay', 'thumbnailsToggle']

-    if show is '1' or hasClass @thumbnails, choco_hide
-      method = 'remove'
-      show = true
+    if show?
+      if show is '1'
+        method = 'remove'
+      else
+        method = 'add'
     else
-      method = 'add'
-      show = false
-
-    session.set show
+      if hasClass @thumbnails, choco_hide
+        method = 'remove'
+        show = true
+      else
+        method = 'add'
+        show = false
+      session.set show

     classList @thumbnails, choco_hide, null, method


Added aliases as discussed on pekim/tedious#179

--- src/data-type.coffee
+++ src/data-type.coffee
@@ -10,11 +10,13 @@
   0x1F:
     type: 'NULL'
     name: 'Null'
+    aliases: []

   # Fixed-length types
   0x30:
     type: 'INT1'
     name: 'TinyInt'
+    aliases: []
     declaration: (parameter) ->
       'tinyint'
     writeTypeInfo: (buffer) ->
@@ -31,6 +33,7 @@
   0x32:
     type: 'BIT'
     name: 'Bit'
+    aliases: []
     declaration: (parameter) ->
       'bit'
     writeTypeInfo: (buffer) ->
@@ -47,6 +50,7 @@
   0x34:
     type: 'INT2'
     name: 'SmallInt'
+    aliases: []
     declaration: (parameter) ->
       'smallint'
     writeTypeInfo: (buffer) ->
@@ -63,6 +67,7 @@
   0x38:
     type: 'INT4'
     name: 'Int'
+    aliases: []
     declaration: (parameter) ->
       'int'
     writeTypeInfo: (buffer) ->
@@ -79,6 +84,7 @@
   0x3A:
     type: 'DATETIM4'
     name: 'SmallDateTime'
+    aliases: []
     declaration: (parameter) ->
       'smalldatetime'
     writeTypeInfo: (buffer) ->
@@ -103,6 +109,7 @@
   0x3B:
     type: 'FLT4'
     name: 'Real'
+    aliases: []
     declaration: (parameter) ->
       'real'
     writeTypeInfo: (buffer) ->
@@ -119,6 +126,7 @@
   0x3C:
     type: 'MONEY'
     name: 'Money'
+    aliases: []
     declaration: (parameter) ->
       "money"
     writeTypeInfo: (buffer, parameter) ->
@@ -135,6 +143,7 @@
   0x3D:
     type: 'DATETIME'
     name: 'DateTime'
+    aliases: []
     declaration: (parameter) ->
       'datetime'
     writeTypeInfo: (buffer) ->
@@ -168,6 +177,7 @@
   0x3E:
     type: 'FLT8'
     name: 'Float'
+    aliases: []
     declaration: (parameter) ->
       'float'
     writeTypeInfo: (buffer) ->
@@ -184,6 +194,7 @@
   0x37:
     type: 'DECIMAL'
     name: 'Decimal'
+    aliases: []
     hasPrecision: true
     hasScale: true
     declaration: (parameter) ->
@@ -246,6 +257,7 @@
   0x3F:
     type: 'NUMERIC'
     name: 'Numeric'
+    aliases: []
     hasPrecision: true
     hasScale: true
     declaration: (parameter) ->
@@ -307,6 +319,7 @@
   0x7A:
     type: 'MONEY4'
     name: 'SmallMoney'
+    aliases: []
     declaration: (parameter) ->
       "smallmoney"
     writeTypeInfo: (buffer, parameter) ->
@@ -323,6 +336,7 @@
   0x7F:
     type: 'INT8'
     name: 'BigInt'
+    aliases: []
     declaration: (parameter) ->
       'bigint'
     writeTypeInfo: (buffer) ->
@@ -342,6 +356,7 @@
   0x22:
     type: 'IMAGE'
     name: 'Image'
+    aliases: []
     hasTableName: true
     hasTextPointerAndTimestamp: true
     dataLengthLength: 4
@@ -367,6 +382,7 @@
   0x23:
     type: 'TEXT'
     name: 'Text'
+    aliases: []
     hasCollation: true
     hasTableName: true
     hasTextPointerAndTimestamp: true
@@ -395,6 +411,7 @@
   0x24:
     type: 'GUIDN'
     name: 'UniqueIdentifierN'
+    aliases: ['UniqueIdentifier']
     dataLengthLength: 1
     declaration: (parameter) ->
       'uniqueidentifier'
@@ -414,10 +431,12 @@
   0x26:
     type: 'INTN'
     name: 'IntN'
+    aliases: []
     dataLengthLength: 1
   0x63:
     type: 'NTEXT'
     name: 'NText'
+    aliases: []
     hasCollation: true
     hasTableName: true
     hasTextPointerAndTimestamp: true
@@ -425,34 +444,41 @@
   0x68:
     type: 'BITN'
     name: 'BitN'
+    aliases: []
     dataLengthLength: 1
   0x6A:
     type: 'DECIMALN'
     name: 'DecimalN'
+    aliases: []
     dataLengthLength: 1
     hasPrecision: true
     hasScale: true
   0x6C:
     type: 'NUMERICN'
     name: 'NumericN'
+    aliases: []
     dataLengthLength: 1
     hasPrecision: true
     hasScale: true
   0x6D:
     type: 'FLTN'
     name: 'FloatN'
+    aliases: []
     dataLengthLength: 1
   0x6E:
     type: 'MONEYN'
     name: 'MoneyN'
+    aliases: []
     dataLengthLength: 1
   0x6F:
     type: 'DATETIMN'
     name: 'DateTimeN'
+    aliases: []
     dataLengthLength: 1
   0xA5:
     type: 'BIGVARBIN'
     name: 'VarBinary'
+    aliases: []
     dataLengthLength: 2
     maximumLength: 8000
     declaration: (parameter) ->
@@ -503,6 +529,7 @@
   0xA7:
     type: 'BIGVARCHR'
     name: 'VarChar'
+    aliases: []
     hasCollation: true
     dataLengthLength: 2
     maximumLength: 8000
@@ -556,6 +583,7 @@
   0xAD:
     type: 'BIGBinary'
     name: 'Binary'
+    aliases: []
     dataLengthLength: 2
     maximumLength: 8000
     declaration: (parameter) ->
@@ -580,11 +608,13 @@
   0xAF:
     type: 'BIGCHAR'
     name: 'Char'
+    aliases: []
     hasCollation: true
     dataLengthLength: 2
   0xE7:
     type: 'NVARCHAR'
     name: 'NVarChar'
+    aliases: []
     hasCollation: true
     dataLengthLength: 2
     maximumLength: 4000
@@ -638,15 +668,18 @@
   0xEF:
     type: 'NCHAR'
     name: 'NChar'
+    aliases: []
     hasCollation: true
     dataLengthLength: 2
   0xF1:
     type: 'XML'
     name: 'Xml'
+    aliases: []
     hasSchemaPresent: true
   0x29:
     type: 'TIMEN'
     name: 'TimeN'
+    aliases: ['Time']
     hasScale: true
     dataLengthLength: 0
     dataLengthFromScale: (scale) ->
@@ -693,6 +726,7 @@
   0x28:
     type: 'DATEN'
     name: 'DateN'
+    aliases: ['Date']
     dataLengthLength: 0
     declaration: (parameter) ->
       "date"
@@ -710,6 +744,7 @@
   0x2A:
     type: 'DATETIME2N'
     name: 'DateTime2N'
+    aliases: ['DateTime2']
     hasScale: true
     dataLengthLength: 0
     dataLengthFromScale: (scale) ->
@@ -758,6 +793,7 @@
   0x2B:
     type: 'DATETIMEOFFSETN'
     name: 'DateTimeOffsetN'
+    aliases: ['DateTimeOffset']
     hasScale: true
     dataLengthLength: 0
     dataLengthFromScale: (scale) ->
@@ -811,10 +847,12 @@
   0xF0:
     type: 'UDTTYPE'
     name: 'UDT'
+    aliases: []
     hasUDTInfo: true
   0xF3:
     type: 'TVPTYPE'
     name: 'TVP'
+    aliases: []
     declaration: (parameter) ->
       "#{parameter.value.name} readonly"
     writeTypeInfo: (buffer, parameter) ->
@@ -877,6 +915,8 @@
 for id, type of TYPE
   type.id = parseInt(id, 10)
   typeByName[type.name] = type
+  for alias in type.aliases
+    typeByName[alias] = type

 exports.TYPE = TYPE


draggable & resizable update

draggable & resizable update

--- JSKit/02_JSView.coffee
+++ JSKit/02_JSView.coffee
@@ -22,6 +22,7 @@
 		@_hidden = false
 		@_shadow = false
 		@_userInteractionEnabled = true
+		@_axis = false

 	addSubview: (object) ->
 		if (!object?)
@@ -32,8 +33,8 @@

 		if ($(@_viewSelector).length)
 			$(@_viewSelector).append(object._div)
-			object.setDraggable(object._draggable)
-			object.setResizable(object._resizable)
+			object.setDraggable(object._draggable, object._axis, object._dragopacity)
+			object.setResizable(object._resizable, object._resizeAction, object._resizeopacity)
 			object.viewDidAppear()

 	setFrame: (@_frame) ->
@@ -91,7 +92,8 @@
 			$(@_viewSelector).unbind("click")
 			$(@_viewSelector).unbind("dblclick")

-	setDraggable: (@_draggable) ->
+	setDraggable: (@_draggable, @_axis = false, @_dragopacity = 0.5) ->
+		JSLog(@_dragopacity)
 		if (@_parent?)
 			containment = @_parent._containment
 		else
@@ -105,7 +107,8 @@
 			if (containment == true)
 				$(@_viewSelector).draggable
 					containment:"parent"
-					opacity:0.5
+					axis: @_axis
+					opacity:@_dragopacity
 					disabled: false
 					drag: (event, ui) =>
 						frame = @_self._frame
@@ -113,10 +116,11 @@
 						frame.origin.y = $(@_viewSelector).css("top")
 						@_self.setFrame(frame)
 			else
-				$(@_viewSelector).draggable({opacity:0.5, disabled: false})
+				$(@_viewSelector).draggable({opacity:@_dragopacity, disabled: false})
 				$(@_viewSelector).draggable("destroy")
 				$(@_viewSelector).draggable
-					opacity:0.5
+					opacity:@_dragopacity
+					axis: @_axis
 					disabled: false
 					drag: (event, ui) =>
 						frame = @_self._frame
@@ -127,7 +131,7 @@
 			$(@_viewSelector).css("cursor", "auto")
 			$(@_viewSelector).draggable({disabled: true})

-	setResizable: (@_resizable, @_resizeAction = null, minWidth = 0, minHeight = 0, maxWidth = 16777216, maxHeight = 16777216) ->
+	setResizable: (@_resizable, @_resizeAction = null, @_resizeopacity = 0.5, minWidth = 0, minHeight = 0, maxWidth = 16777216, maxHeight = 16777216) ->
 		if (@_parent?)
 			containment = @_parent._containment
 		else
@@ -152,7 +156,7 @@
 						@_resizeAction()
 			else
 				$(@_viewSelector).resizable
-					opacity:0.5
+					opacity:@_resizeopacity
 					disabled: false
 				$(@_viewSelector).resizable("destroy")
 				$(@_viewSelector).resizable
@@ -160,7 +164,7 @@
 					minHeight:minHeight
 					maxWidth:maxWidth
 					maxHeight:maxHeight
-					opacity:0.5
+					opacity:@_resizeopacity
 					disabled: false
 					resize: (event, ui) =>
 						frame = @_self._frame
@@ -178,7 +182,7 @@

 	setContainment:(@_containment) ->
 		for obj in @_objlist
-			obj.setDraggable(obj._draggable)
+			obj.setDraggable(obj._draggable, obj._axis, obj._dragopacity)

 	bringSubviewToFront:(obj)->
 		id = obj._objectID
@@ -296,7 +300,8 @@
 		@setBorderWidth(@_borderWidth)
 		@setShadow(@_shadow)
 		@setClipToBounds(@_clipToBounds)
-		@setDraggable(@_draggable)
+		@setDraggable(@_draggable, @_axis, @_dragopacity)
+		@setResizable(@_resizable, @_resizeAction, @_resizeopacity)
 		@removeTapGesture(1)
 		@removeTapGesture(2)
 		if (@_tapAction?)


prefer single quotes

prefer single quotes

--- app/templates/gulp/tasks/watch.coffee
+++ app/templates/gulp/tasks/watch.coffee
@@ -1,12 +1,11 @@
-gulp         = require "gulp"
-watch        = require "gulp-watch"
+gulp         = require 'gulp'
+watch        = require 'gulp-watch'

 conf = require '../gulpconfig'

-gulp.task "watch", ["css", "scripts", "browser-sync"], () ->
+gulp.task 'watch', ['css', 'scripts', 'browser-sync'], () ->
   global.isWatching = true

-  gulp.watch "#{conf.path.dev.scss}/**/*.scss", ["css"]
-  gulp.watch ["#{conf.path.dev.js}/**/!(*.bundle).js", "#{conf.path.dev.js}/**/*.jsx"], ["scripts:lint", "scripts"]
-  gulp.watch "#{conf.path.dev.views}/**/*.html.php", ["bs-reload"]
-
+  gulp.watch "#{conf.path.dev.scss}/**/*.scss", ['css']
+  gulp.watch ["#{conf.path.dev.js}/**/!(*.bundle).js", "#{conf.path.dev.js}/**/*.jsx"], ['scripts:lint', 'scripts']
+  gulp.watch "#{conf.path.dev.views}/**/*.html.php", ['bs-reload']


include label map in artist template tests

--- apps/artist_new/test/templates.coffee
+++ apps/artist_new/test/templates.coffee
@@ -43,6 +43,7 @@
         counts: @filterArtworks.counts
         activeText: ''
         params: new Backbone.Model
+        filterLabelMap: require '../../../components/filter2/dropdown/label_map.coffee'
         _s: _s
       }, done

@@ -82,6 +83,7 @@
         counts: @filterArtworks.counts
         activeText: ''
         params: new Backbone.Model
+        filterLabelMap: require '../../../components/filter2/dropdown/label_map.coffee'
         _s: _s
       }, done

@@ -120,6 +122,7 @@
         counts: @filterArtworks.counts
         activeText: ''
         params: new Backbone.Model
+        filterLabelMap: require '../../../components/filter2/dropdown/label_map.coffee'
         _s: _s
       }, done


Rebuild native modules when atom-shell is upgraded

Spawn an apm rebuild when the atom shell version changes
after running the update-atom-shell script.

Closes #618

--- tasks/update-atom-shell-task.coffee
+++ tasks/update-atom-shell-task.coffee
@@ -1,6 +1,26 @@
+path = require 'path'
+
 module.exports = (grunt) ->
   {spawn} = require('./task-helpers')(grunt)

+  getAtomShellVersion = ->
+    versionPath = path.join('atom-shell', 'version')
+    if grunt.file.isFile(versionPath)
+      grunt.file.read(versionPath).trim()
+    else
+      null
+
   grunt.registerTask 'update-atom-shell', 'Update atom-shell', ->
     done = @async()
-    spawn cmd: 'script/update-atom-shell', (error) -> done(error)
+    currentVersion = getAtomShellVersion()
+    spawn cmd: 'script/update-atom-shell', (error) ->
+      if error?
+        done(error)
+      else
+        newVersion = getAtomShellVersion()
+        if newVersion and currentVersion isnt newVersion
+          grunt.log.writeln("Rebuilding native modules for new atom-shell version #{newVersion.cyan}.")
+          cmd = path.join('node_modules', '.bin', 'apm')
+          spawn {cmd, args: ['rebuild']}, (error) -> done(error)
+        else
+          done()


Arruma passagem de conta

Arruma passagem de conta

--- Agencia/server/operador.coffee
+++ Agencia/server/operador.coffee
@@ -27,7 +27,7 @@
 	if Match.test data, Object
 		data.agencia = Meteor.user().agencia
 		data.operador = Meteor.user()
-		if Meteor.user().role is 'conta'
+		if Meteor.user().profile.role is 'conta'
 			data.conta = Meteor.user()._id

 	return chamarOperador operador, nome, data


fix(macAutocomplete): Fixed dropdown not hiding when no item is returned

Fixes #182

--- src/directives/autocomplete.coffee
+++ src/directives/autocomplete.coffee
@@ -241,8 +241,8 @@
       Update list of items getting passed to menu
       @param {Array} data Array of data
       ###
-      updateItem = (data = []) ->
-        if data.length > 0
+      updateItem = (data) ->
+        if data?.length > 0
           currentAutocomplete = data

           $menuScope.items = data.map (item) ->
@@ -255,6 +255,9 @@
               {label: item, value: item}

           appendMenu positionMenu
+
+        else
+         reset()

       ###
       @function


JSView update

JSView update

--- JSKit/02_JSView.coffee
+++ JSKit/02_JSView.coffee
@@ -145,7 +145,9 @@
 					maxWidth:maxWidth
 					maxHeight:maxHeight
 					resize: (event, ui) =>
-						frame = @_self._frame
+						frame = @_frame
+						frame.origin.x = $(@_viewSelector).css("left")
+						frame.origin.y = $(@_viewSelector).css("top")
 						frame.size.width = $(@_viewSelector).width()
 						frame.size.height = $(@_viewSelector).height()
 						@_self.setFrame(frame)