added some null checks and more persistance

--- migrations/1422460849371-doc-lines.coffee
+++ migrations/1422460849371-doc-lines.coffee
@@ -8,7 +8,7 @@
 exec = require("child_process").exec

 finished_projects_path = "/tmp/finished-projects"
-
+all_projects_path = "/tmp/all-projects"

 printProgress = ->
 	exec "wc #{finished_projects_path}", (error, results) ->
@@ -18,15 +18,32 @@
 checkIfFileHasBeenProccessed = (project_id, callback)->
 	exec "grep #{project_id} #{finished_projects_path}", (error, results) ->
 		hasBeenProcessed = _.include(results, project_id)
-		console.log hasBeenProcessed, project_id
+		#console.log hasBeenProcessed, project_id
 		callback(null, hasBeenProcessed)

+loadProjectIds = (callback)->
+	fs.readFile all_projects_path, "utf-8", (err, data)->
+		console.log data.length
+		ids = data.split("\n")
+		console.log ids.length
+		callback err, ids
+
+getAndWriteProjectids = (callback)->
+	console.log "finding all project id's - #{new Date().toString()}"
+	db.projects.find {}, {_id:1}, (err, ids)->
+		console.log "total found projects in mongo #{ids.length} - #{new Date().toString()}"
+		ids = _.pluck ids, '_id'
+		ids = _.filter ids, (id)-> id?
+		fileData = ids.join("\n")
+		fs.writeFile all_projects_path, fileData, ->
+			callback(err, ids)
+
 getProjectIds = (callback)->
-	console.log "finding all project id's - #{new Date().toString()}"
-	db.projects.find {}, {_id:1}, (err,ids)->
-		console.log "total found projects in mongo #{ids.length} - #{new Date().toString()}"
-		ids = _.map ids, (id)-> return id._id.toString()
-		callback(err, ids)
+	exists = fs.existsSync all_projects_path
+	if exists
+		loadProjectIds callback
+	else
+		getAndWriteProjectids callback

 markProjectAsProcessed = (project_id, callback)->
 	fs.appendFile finished_projects_path, "#{project_id}\n", callback
@@ -34,7 +51,9 @@
 getAllDocs = (project_id, callback = (error, docs) ->) ->
 	db.projects.findOne _id:ObjectId(project_id), (error, project) ->
 		return callback(error) if error?
-		return callback new Errors.NotFoundError("No such project: #{project_id}") if !project?
+		if !project?
+			console.error("No such project: #{project_id}")
+			return callback("no such project #{project_id}")
 		findAllDocsInProject project, (error, docs) ->
 			return callback(error) if error?
 			return callback null, docs
@@ -78,9 +97,9 @@

 processNext = (project_id, callback)->
-	#console.log("starting to process #{project_id} - #{new Date().toString()}")
 	checkIfFileHasBeenProccessed project_id, (err, hasBeenProcessed)->
 		if hasBeenProcessed
+			console.log "#{project_id} already procssed, skipping"
 			return callback()
 		getAllDocs project_id, (err, docs)->
 			if err?


First attempt at loading the content-by-url from cloud files

--- lib/content._coffee
+++ lib/content._coffee
@@ -6,20 +6,17 @@
 URL = require 'url'
 Worker = require './worker'

+pkgcloud = require('pkgcloud')
+cloudClient = pkgcloud.storage.createClient
+    provider: 'rackspace'
+    username: config.RACKSPACE_USERNAME
+    apiKey: config.RACKSPACE_API_KEY
+    region: config.CONTENT_REGION

 ## HELPERS

 DIR_BY_ID_PATH = Path.join config.DATA_DIR, 'content-by-id'
 DIR_BY_URL_PATH = Path.join config.DATA_DIR, 'content-by-url'
-
-# TODO: this is a short term fix to support the content by url code-path
-# we should remove this when we move to a proper database
-try
-    DATABASE = require Path.join DIR_BY_URL_PATH, 'data.json'
-catch e
-    DATABASE = {}
-
-DIR_PATH_FROM_URL_TO_ID = Path.relative DIR_BY_URL_PATH, DIR_BY_ID_PATH

 # TODO: We should be generating random IDs instead of incrementing them.
 NEXT_ID_KEY = 'content:next.id'
@@ -47,11 +44,14 @@
     id = id.replace /([A-Z])/g, '_$1'
     Path.join DIR_BY_ID_PATH, "#{id}.json"

-getFilePathForURL = (url) ->
-    if idFile = DATABASE["#{hashURL url}.json"]
-        Path.join DIR_BY_ID_PATH, idFile.replace '../content-by-id', ''
-    else
-        ''
+readFileForURL = (url, _) ->
+    cloudClient.download
+        container: 'content/content-by-url'
+        remote: "#{hashURL url}.txt"
+
+    # Somehow after the download we get the ID and then ...
+    path = Path.join DIR_BY_ID_PATH, "#{id}.json"
+    readFile path, _

 getRedisKeyForId = (id) ->
     "content:id:#{id}"
@@ -254,7 +254,7 @@
         else
             # note that our URL files are symlinks to the ID files, and
             # node's FS.readFile() follows symlinks natively. sweet!
-            if json = readFile (getFilePathForURL url), _
+            if json = readFileForURL url, _
                 enqueueIfNeeded _, new Content JSON.parse json
             else
                 null
@@ -276,12 +276,8 @@

         else
             idPath = getFilePathForId id
-            urlPath = getFilePathForURL url
-            urlToIdPath =
-                Path.join DIR_PATH_FROM_URL_TO_ID, Path.basename idPath
-
             FS.writeFile idPath, content._stringifyData(), _
-            FS.symlink urlToIdPath, urlPath, _
+            # TODO: Update content-by-url in Cloud Files

         # Either way now:
         enqueueForConversion content, _


Clicking to progress limited to bottom UI part. Fix $12w

--- packages/landsofillusions/interface/text/text.coffee
+++ packages/landsofillusions/interface/text/text.coffee
@@ -235,7 +235,7 @@
       'wheel .scrollable': @onWheelScrollable
       'mouseenter .command': @onMouseEnterCommand
       'mouseleave .command': @onMouseLeaveCommand
-      'click': @onClick
+      'click .ui-area': @onClickUIArea
       'click .command': @onClickCommand
       'click .location': @onClickLocation
       'mouseenter .exits .exit .name': @onMouseEnterExit
@@ -253,8 +253,8 @@
   onMouseLeaveCommand: (event) ->
     @hoveredCommand null

-  onClick: (event) ->
-    # When we're waiting for user interaction, clicking doubles for pressing enter.
+  onClickUIArea: (event) ->
+    # When we're waiting for user interaction, clicking on the bottom UI part doubles for pressing enter.
     if @waitingKeypress()
       @onCommandInputEnter()


Harden Player spec fakes given recent changes.

--- tests/fakes.coffee
+++ tests/fakes.coffee
@@ -1,9 +1,14 @@
 define [
   'phaser'
   'underscore'
-], (Phaser, _) ->
+  'app/helpers'
+], (Phaser, _, Helpers) ->

   {Point} = Phaser
+
+  {PointMixin} = Helpers
+
+  _.extend Point::, PointMixin

   # Phaser is written with interwoven dependencies, but does not provide test
   # helpers or fake classes. This custom faking isn't ideal, but a last resort.
@@ -49,9 +54,9 @@
   createPlayerProps: (player) ->
     sprite:
       body:
-        onFloor: -> no
         drag: new Point(), setSize: jasmine.createSpy 'setSize'
         velocity: new Point(), acceleration: new Point()
+        position: new Point(), offset: new Point(), onFloor: -> no
       game:
         time: { create: -> new FakeTimer() }
       scale: new Point()
@@ -61,7 +66,8 @@
         { isFinished: no, isPlaying: yes, loop: name is 'run', name: name }
       frame: 17 # Initial.

-    cameraFocus: {}
+    cameraFocus:
+      position: new Point()

     cursors:
       _.mapObject { left: {}, right: {}, up: {}, down: {} }, (key) ->


add more howe

add more howe

--- app/index.coffee
+++ app/index.coffee
@@ -34,7 +34,7 @@

 modeGetter = () ->
   # order = [ "intro", "chain", "lines", "colocation", "howe", "howe", "howe", "howe", "howe" ]
-  order = [ "intro", "chain", "lines", "colocation", "howe", "howe" ]
+  order = [ "intro", "chain", "lines", "colocation", "howe", "howe", "howe", "howe" ]
   index = -1
   ->
     if ++index is order.length then index = 0


Revert "Merge pull request #1107 from andyrichardson/java-package"

This reverts commit 0886816c274d85e0b896c2b2f28348d427ea5881, reversing
changes made to aac36114d45029c6a3ccbced3dbbce39c71f6e14.

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -341,14 +341,12 @@
     "File Based":
       command: if GrammarUtils.OperatingSystem.isWindows() then "cmd" else "bash"
       args: (context) ->
-        tmpFolder = GrammarUtils.Java.tempFilesDir
-        className = GrammarUtils.Java.getClassName context
-        classPackage = GrammarUtils.Java.getClassPackage context
-
+        className = context.filename.replace /\.java$/, ""
+        args = []
         if GrammarUtils.OperatingSystem.isWindows()
           args = ["/c javac -Xlint #{context.filename} && java #{className}"]
         else
-          args = ["-c", "javac -cp . -d '#{tmpFolder}' '#{context.filepath}' && java -cp /tmp #{classPackage}.#{className}"]
+          args = ['-c', "javac -d /tmp '#{context.filepath}' && java -cp /tmp #{className}"]
         return args

   JavaScript:
@@ -697,7 +695,7 @@
         else
           args = ['-c', "rebuild '#{progname}.native' && '#{progname}.native'"]
         return args
-
+
   "Ren'Py":
     "File Based":
       command: "renpy"


Add some ? to check availability of file

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -128,7 +128,7 @@
     "File Based":
       command: "gnuplot"
       args: (context) -> ['-p', context.filepath]
-      workingDirectory: atom.workspace.getActivePaneItem()?.buffer.file?.getParent().getPath()
+      workingDirectory: atom.workspace.getActivePaneItem()?.buffer?.file?.getParent?().getPath?()

   Go:
     "File Based":


Animate data points moving between JD/phase.

--- assets/js/lightcurve.coffee
+++ assets/js/lightcurve.coffee
@@ -70,6 +70,8 @@
             @svg.select('.x.axis')
                 .call(@xAxis)
             @svg.selectAll('circle')
+                .transition()
+                .duration(1000)
                 .attr
                     cx: (d) => @xScale if isPhaseChart then d.phase else d.jd


Cleanup spec

Cleanup spec

--- spec/aggregate_entity_spec.coffee
+++ spec/aggregate_entity_spec.coffee
@@ -6,9 +6,6 @@
   Entity            = eventric 'AggregateEntity'
   EntityCollection  = eventric 'AggregateEntityCollection'

-  it 'should implement backbone events', ->
-    entity = new Entity
-    expect(entity._events).not.to.be 'undefined'

   describe '#prop', ->


Fixed a typo

Fixed a typo

--- src/map-view.coffee
+++ src/map-view.coffee
@@ -398,7 +398,7 @@

         clearPublicTransitStopsLayer: ->
             @publicTransitStopsLayer.clearLayers()
-            @publicTransitStops = []
+            @publicTransitStopsCache = []

         handleMapBackgroundLayerChange: ->
             oldLayer = @map._baseLayer


Module spec

Module spec

--- spec/language-haskell-spec.coffee
+++ spec/language-haskell-spec.coffee
@@ -70,9 +70,9 @@
   describe "backtick function call", ->
     it "finds backtick function names", ->
       {tokens} = grammar.tokenizeLine("\`func\`")
-      expect(tokens[0]).toEqual value: '`', scopes: ['source.haskell', 'keyword.operator.function.infix.haskell','punctuation.definition.entity.haskell']
+      expect(tokens[0]).toEqual value: '`', scopes: ['source.haskell', 'keyword.operator.function.infix.haskell', 'punctuation.definition.entity.haskell']
       expect(tokens[1]).toEqual value: 'func', scopes: ['source.haskell', 'keyword.operator.function.infix.haskell']
-      expect(tokens[2]).toEqual value: '`', scopes: ['source.haskell', 'keyword.operator.function.infix.haskell','punctuation.definition.entity.haskell']
+      expect(tokens[2]).toEqual value: '`', scopes: ['source.haskell', 'keyword.operator.function.infix.haskell', 'punctuation.definition.entity.haskell']

   describe "keywords", ->
     controlKeywords = ['case', 'of', 'in', 'where', 'if', 'then', 'else']
@@ -441,3 +441,30 @@
                               [5, ['meta.preprocessor.haskell']]
                               [6, ['meta.preprocessor.haskell']]
                               ]]
+  describe "module", ->
+    it "understands module declarations", ->
+      g = grammarExpect grammar, 'module Module where'
+      g.toHaveTokens [['module', ' ', 'Module', ' ', 'where']]
+      g.toHaveScopes [['source.haskell', 'meta.declaration.module.haskell']]
+      g.tokenToHaveScopes [[[2, ['support.other.module.haskell']]]]
+    it "understands module declarations with exports", ->
+      g = grammarExpect grammar, 'module Module (export1, export2) where'
+      g.toHaveTokens [['module', ' ', 'Module', ' ', '(', 'export1', ',', ' ', 'export2', ')', ' ', 'where']]
+      g.toHaveScopes [['source.haskell', 'meta.declaration.module.haskell']]
+      g.tokenToHaveScopes [[[2, ['support.other.module.haskell']]
+                            [5, ['meta.declaration.exports.haskell', 'entity.name.function.haskell']]
+                            [8, ['meta.declaration.exports.haskell', 'entity.name.function.haskell']]
+                            ]]
+    it "understands module declarations with export lists", ->
+      g = grammarExpect grammar, 'module Module (export1 (..), export2 (Something)) where'
+      g.toHaveTokens [['module', ' ', 'Module', ' ', '(', 'export1', ' ', '(' , '..', ')',
+                       ',', ' ', 'export2', ' ', '(', 'Something', ')', ')', ' ', 'where']]
+      g.toHaveScopes [['source.haskell', 'meta.declaration.module.haskell']]
+      g.tokenToHaveScopes [[[2, ['support.other.module.haskell']]
+                            [5, ['meta.declaration.exports.haskell', 'entity.name.function.haskell']]
+                            [8, ['meta.declaration.exports.haskell', 'meta.other.constructor-list.haskell',
+                                 'keyword.operator.wildcard.haskell']]
+                            [12, ['meta.declaration.exports.haskell', 'entity.name.function.haskell']]
+                            [15, ['meta.declaration.exports.haskell', 'meta.other.constructor-list.haskell',
+                                  'entity.name.tag.haskell']]
+                            ]]


fix conflict

fix conflict

--- server/app/bongo/models/bucket.coffee
+++ server/app/bongo/models/bucket.coffee
@@ -206,7 +206,6 @@

   @share()

-<<<<<<< HEAD
   @set
     schema          : CBucket.schema

@@ -221,8 +220,6 @@

   @share()

-=======
->>>>>>> d34ab7c62cda6fb11dfdbb6000eb7c8a21587315
   @set
     schema          : CBucket.schema


Reverse last

Reverse last

--- app/pages/home.cjsx
+++ app/pages/home.cjsx
@@ -79,6 +79,26 @@
     else
       './assets/simple-avatar.jpg'
     Promise.resolve src
+
+  render: ->
+

+      <PromiseRenderer promise={apiClient.type('projects').get(id: FEATURED_PRODUCT_IDS, cards: true)}>{(projects) =>
+        if projects?
+

+          {for project in projects
+            [owner, name] = project.slug.split('/')
+            <OwnedCard
+              key={project.id}
+              resource={project}
+              linkTo="/projects/#{owner}/#{name}"
+              translationObjectName="projectsPage"
+              imagePromise={@imagePromise(project)}
+              skipOwner={true} />
+          }
+

+      }</PromiseRenderer>
+      <Link to="/projects" className="call-to-action standard-button x-large"><Translate content="home.featuredProjects.button" /></Link>
+

 module.exports = React.createClass
   displayName: 'HomePage'


Renamed vendor to "virgin mobile" and set bill type to lowercase

--- server/konnectors/virginmobile.coffee
+++ server/konnectors/virginmobile.coffee
@@ -44,7 +44,7 @@
             .use(logIn)
             .use(parsePage)
             .use(filterExisting log, Bill)
-            .use(saveDataAndFile(log, Bill, 'virginmobile', ['bill']))
+            .use(saveDataAndFile(log, Bill, 'virgin mobile', ['bill']))
             .use(linkBankOperation
                 log: log
                 model: Bill
@@ -113,7 +113,7 @@
                 date: moment inv.invoiceDate, 'DD/MM/YYYY'
                 amount: parseFloat(inv.amount.unite + '.' + inv.amount.centimes)
                 pdfurl: baseURL + inv.invoiceNumber
-                type: "Phone"
+                type: "phone"

             if bill.date? and bill.amount? and bill.pdfurl?
                 bills.fetched.push bill


close clients

close clients

--- lib/live-redis.iced
+++ lib/live-redis.iced
@@ -85,10 +85,12 @@
     options.max_socket_commands ?= 10

     io = eio.attach server
-    process.on 'SIGINT', ->
+    close = ->
         for _, socket of io.clients
             socket.close()
         io.close()
+    server.on 'close', close
+    process.on 'SIGINT', close

     await connect options, defer err, db
     return if err?


Change mind, don't skip commented row. it' not necessarily good solution for all case. #279

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -335,27 +335,16 @@
   @description: "Compact multiple spaces to single space"
   displayName: 'Compact space'
   mutateSelection: (selection) ->
-    # Special care for commented row on linewise target.
-    # When selection is linewise range, skip mutation for commented row.
-    if swrap(selection).isLinewise()
-      text = ''
-      for row in swrap(selection).getRows()
-        lineText = @editor.getTextInBufferRange(@editor.bufferRangeForBufferRow(row, includeNewline: true))
-        if @editor.languageMode.isLineCommentedAtBufferRow(row)
-          text += lineText
-        else
-          text += @getNewText(lineText)
-    else
-      text = @getNewText(selection.getText(), selection)
+    text = @getNewText(selection.getText(), selection)
     selection.insertText(text, {@autoIndent})
     @restorePoint(selection) if @setPoint

   getNewText: (text) ->
-    if text.match(/^[ ]+$/gm)
+    if text.match(/^[ ]+$/)
       ' '
     else
       text.replace /^(\s*)(.*?)(\s*)$/gm, (m, leading, middle, trailing) ->
-        leading + middle.split(/\s+/).join(' ') + trailing
+        leading + middle.split(/[ \t]+/).join(' ') + trailing

 # -------------------------
 class TransformStringByExternalCommand extends TransformString


Changed uppercase "Q" with lowercase "q"

If the OS in case-sensitive, this prevents a successful build, even if everything else is fine.

--- compilation/script-package.coffee
+++ compilation/script-package.coffee
@@ -8,7 +8,7 @@
 path            = require 'path'
 join            = path.join
 resolve         = path.resolve
-Q = require 'Q'
+Q = require 'q'

 keygen = (dir) ->
   dir = resolve dir
@@ -37,4 +37,4 @@
       defer.resolve()
       crx.destroy()
       return
-  defer.promise+  defer.promise


fix authors spec

fix authors spec

--- app/assets/javascripts/controllers/paper_edit.js.coffee
+++ app/assets/javascripts/controllers/paper_edit.js.coffee
@@ -14,4 +14,4 @@
     authors = @get('authors').map (author) ->
       [author.first_name, author.last_name].join(' ')
     authors.join(', ')
-  ).property('authors')
+  ).property('authors.@each')


Fix flexibility ordering for IE9

Fix flexibility ordering for IE9

--- app/assets/javascripts/lib/views/base_chart_view.coffee
+++ app/assets/javascripts/lib/views/base_chart_view.coffee
@@ -107,8 +107,7 @@
     sortable_el = document.querySelectorAll("ul.sortable")[0]

     if sortable_el
-      api_session_id = App.settings.get("api_session_id")
-      base_url = "#{ globals.api_url }/api/v3/scenarios/#{ api_session_id }/flexibility_order/"
+      base_url = "#{ App.scenario.url_path() }/flexibility_order/"

       $.ajax
         url: "#{ base_url}get",


Stop exporting to folders, just export strait to html files

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -20,7 +20,7 @@

   renderDocs: (sourcePaths, outPath, options={}) ->
     sourcePaths ?= atom.project.getPaths()
-    outPath ?= '/Users/jessegrosjean/Desktop/gitbooktest'
+    outPath ?= '/Users/jessegrosjean/Desktop/birchapi'
     if sourcePaths
       unless fs.existsSync(outPath)
         fs.mkdirSync(outPath)
@@ -33,11 +33,11 @@
   renderClasses: (outPath, options) ->
     for name, clazz of @metadata.classes
       renderedClazz = @renderClass clazz, options
-      classDir = path.join(outPath, name)
-      unless fs.existsSync(classDir)
-        fs.mkdirSync(classDir)
-      fs.writeFileSync(path.join(classDir, 'index.md'), renderedClazz)
-
+      #classDir = path.join(outPath, name)
+      #unless fs.existsSync(classDir)
+      #  fs.mkdirSync(classDir)
+      #fs.writeFileSync(path.join(classDir, 'index.md'), renderedClazz)
+      fs.writeFileSync(path.join(outPath, "#{name}.md"), renderedClazz)
   renderClassList: (outPath) ->
     classes = []
     for name, clazz of @metadata.classes
@@ -318,19 +318,19 @@
   resolveStaticReference: (klass, item, text) ->
     switch
       when klass is '' then { name: text, url: "#static-#{item}" }
-      when @metadata.classes[klass] then { name: text, url: "../#{klass}#static-#{item}" }
+      when @metadata.classes[klass] then { name: text, url: "#{klass}.html#static-#{item}" }
       when @referenceMap[klass] then { name: text, url: "#{mozillaJavascriptBaseUrl}/#{klass}/#{item}" }

   resolveInstanceReference: (klass, item, text) ->
     switch
       when klass is '' then { name: text, url: "#instance-#{item}" }
-      when @metadata.classes[klass] then { name: text, url: "../#{klass}#instance-#{item}" }
+      when @metadata.classes[klass] then { name: text, url: "#{klass}.html#instance-#{item}" }
       when @referenceMap[klass] then { name: text, url: "#{mozillaJavascriptBaseUrl}/#{klass}/#{item}" }

   resolveClassReference: (klass, text) ->
     switch
       when @metadata?.classes?[klass]
-        { name: klass, url: '../' + klass}
+        { name: klass, url: klass + '.html'}
       when @referenceMap[klass]
         { name: klass, url: @referenceMap[klass] }
       else text


style nested code blocks

style nested code blocks

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -74,7 +74,7 @@
   if fontFamily = atom.config.get('editor.fontFamily')
     $(html).find('code').css('font-family', fontFamily)

-  for preElement in html.filter("pre")
+  for preElement in $.merge(html.filter("pre"), html.find("pre"))
     $(preElement).addClass("editor-colors")
     codeBlock = $(preElement.firstChild)


Add console helpers to editor, to turn on token-access-ui

--- services/web/public/coffee/ide.coffee
+++ services/web/public/coffee/ide.coffee
@@ -82,6 +82,11 @@
 		}
 		$scope.user = window.user
 		$scope.__enableTokenAccessUI = window.enableTokenAccessUI == true
+		# TODO: remove after rollout and testing
+		window.turnOnTokenAccessUI = () ->
+			$scope.__enableTokenAccessUI = true
+		window.turnOffTokenAccessUI = () ->
+			$scope.__enableTokenAccessUI = false

 		$scope.$watch "project.features.trackChangesVisible", (visible) ->
 			return if !visible?


Fix remove taxon js code

Fix remove taxon js code

[Fixes #3136][Fixes #3140]

--- backend/app/assets/javascripts/admin/taxonomy.js.coffee
+++ backend/app/assets/javascripts/admin/taxonomy.js.coffee
@@ -51,8 +51,8 @@
     error: handle_ajax_error

 handle_delete = (e, data) ->
-  last_rollback = data.rlb
-  node = data.rslt.ob
+  last_rollback = data.rlbk
+  node = data.rslt.obj
   delete_url = base_url.clone()
   delete_url.setPath delete_url.path() + '/' + node.attr("id")
   jConfirm Spree.translations.are_you_sure_delete, Spree.translations.confirm_delete, (r) ->


Allow SVG in sanitizer, as needed for new KaTeX

--- lib/sanitize.coffee
+++ lib/sanitize.coffee
@@ -28,6 +28,43 @@
 ## Additional HTML features
 sanitizeHtml.defaults.allowedTags.push 's', 'u', 'tt'
 sanitizeHtml.defaults.allowedAttributes.ol = ['start']
+
+## SVG, based on
+## https://github.com/alnorris/SVG-Sanitizer/blob/master/SvgSanitizer.php
+sanitizeHtml.defaults.allowedTags.push 'circle', 'clipPath', 'defs',
+  'desc', 'ellipse', 'feGaussianBlur', 'filter', 'foreignObject', 'g',
+  'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
+  'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'svg',
+  'switch', 'text', 'textPath', 'title', 'tspan', 'use'
+#sanitizeHtml.defaults.allowedAttributes.a = ["clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "id", "mask", "opacity", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform", "href", "xlink:href", "xlink:title"]
+sanitizeHtml.defaults.allowedAttributes.circle = ["clip-path", "clip-rule", "cx", "cy", "fill", "fill-opacity", "fill-rule", "filter", "id", "mask", "opacity", "r", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform"]
+sanitizeHtml.defaults.allowedAttributes.clippath = ["clippathunits", "id"]
+#sanitizeHtml.defaults.allowedAttributes.style  = ["type"]
+sanitizeHtml.defaults.allowedAttributes.ellipse = ["clip-path", "clip-rule", "cx", "cy", "fill", "fill-opacity", "fill-rule", "filter", "id", "mask", "opacity", "requiredfeatures", "rx", "ry", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform"]
+sanitizeHtml.defaults.allowedAttributes.fegaussianblur = ["color-interpolation-filters", "id", "requiredfeatures", "stddeviation"]
+sanitizeHtml.defaults.allowedAttributes.filter = ["color-interpolation-filters", "filterres", "filterunits", "height", "id", "primitiveunits", "requiredfeatures", "width", "x", "xlink:href", "y"]
+sanitizeHtml.defaults.allowedAttributes.foreignobject = ["font-size", "height", "id", "opacity", "requiredfeatures", "transform", "width", "x", "y"]
+sanitizeHtml.defaults.allowedAttributes.g = ["clip-path", "clip-rule", "id", "display", "fill", "fill-opacity", "fill-rule", "filter", "mask", "opacity", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform", "font-family", "font-size", "font-style", "font-weight", "text-anchor"]
+sanitizeHtml.defaults.allowedAttributes.image = ["clip-path", "clip-rule", "filter", "height", "id", "mask", "opacity", "requiredfeatures", "systemlanguage", "transform", "width", "x", "xlink:href", "xlink:title", "y"]
+sanitizeHtml.defaults.allowedAttributes.line = ["clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform", "x1", "x2", "y1", "y2"]
+sanitizeHtml.defaults.allowedAttributes.lineargradient = ["id", "gradienttransform", "gradientunits", "requiredfeatures", "spreadmethod", "systemlanguage", "x1", "x2", "xlink:href", "y1", "y2"]
+sanitizeHtml.defaults.allowedAttributes.marker = ["id", "markerheight", "markerunits", "markerwidth", "orient", "preserveaspectratio", "refx", "refy", "systemlanguage", "viewbox"]
+sanitizeHtml.defaults.allowedAttributes.mask = ["height", "id", "maskcontentunits", "maskunits", "width", "x", "y"]
+sanitizeHtml.defaults.allowedAttributes.metadata = ["id"]
+sanitizeHtml.defaults.allowedAttributes.path = ["clip-path", "clip-rule", "d", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform"]
+sanitizeHtml.defaults.allowedAttributes.pattern = ["height", "id", "patterncontentunits", "patterntransform", "patternunits", "requiredfeatures", "systemlanguage", "viewbox", "width", "x", "xlink:href", "y"]
+sanitizeHtml.defaults.allowedAttributes.polygon = ["clip-path", "clip-rule", "id", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "points", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform"]
+sanitizeHtml.defaults.allowedAttributes.polyline = ["clip-path", "clip-rule", "id", "fill", "fill-opacity", "fill-rule", "filter", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "points", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform"]
+sanitizeHtml.defaults.allowedAttributes.radialgradient = ["cx", "cy", "fx", "fy", "gradienttransform", "gradientunits", "id", "r", "requiredfeatures", "spreadmethod", "systemlanguage", "xlink:href"]
+sanitizeHtml.defaults.allowedAttributes.rect = ["clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "height", "id", "mask", "opacity", "requiredfeatures", "rx", "ry", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform", "width", "x", "y"]
+sanitizeHtml.defaults.allowedAttributes.stop = ["id", "offset", "requiredfeatures", "stop-color", "stop-opacity", "systemlanguage"]
+sanitizeHtml.defaults.allowedAttributes.svg = ["clip-path", "clip-rule", "filter", "id", "height", "mask", "preserveaspectratio", "requiredfeatures", "systemlanguage", "viewbox", "width", "x", "xmlns", "xmlns:se", "xmlns:xlink", "y"]
+sanitizeHtml.defaults.allowedAttributes.switch = ["id", "requiredfeatures", "systemlanguage"]
+sanitizeHtml.defaults.allowedAttributes.symbol = ["fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "opacity", "preserveaspectratio", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "transform", "viewbox"]
+sanitizeHtml.defaults.allowedAttributes.text = ["clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "mask", "opacity", "requiredfeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "text-anchor", "transform", "x", "xml:space", "y"]
+sanitizeHtml.defaults.allowedAttributes.textpath = ["id", "method", "requiredfeatures", "spacing", "startoffset", "systemlanguage", "transform", "xlink:href"]
+sanitizeHtml.defaults.allowedAttributes.tspan = ["clip-path", "clip-rule", "dx", "dy", "fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "mask", "opacity", "requiredfeatures", "rotate", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "systemlanguage", "text-anchor", "textlength", "transform", "x", "xml:space", "y"]
+sanitizeHtml.defaults.allowedAttributes.use = ["clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "height", "id", "mask", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "transform", "width", "x", "xlink:href", "y"]

 ## KaTeX/MathML
 ## (tag list from https://developer.mozilla.org/en-US/docs/Web/MathML/Element)


supid Amazon sealing inheritance...

supid Amazon sealing inheritance...

curse you old school programming models, in javascript making a black
box you can't inherit from only causes a big headache for the consumers
of it. And I Hath Defeated It Anyway with __proto__!

--- lib/coaws.coffee
+++ lib/coaws.coffee
@@ -1,14 +1,13 @@
 Aws = require 'aws-sdk'
 thunkify = require 'thunkify'
-
 # Coaws go moo
 module.exports = class Coaws extends Aws
-  for own key, service of Aws
-    if service instanceof Function
-      do (service) ->
-        Coaws[key] = class Service extends service
-          constructor: ->
-            super arguments...
-            for key, method of @
-              if method instanceof Function
-                @[key] = thunkify method.bind service
+  for serviceName, service of Aws when service?.serviceIdentifier
+    Coaws[serviceName] = do (service) ->
+      class Service
+        constructor: (options) ->
+          @service = new service options
+          for key, method of @service
+            if method instanceof Function
+              @[key] = thunkify method.bind service
+          @__proto__ = @service


:bomb: very opinionated default value for revealOnStartCondition

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -72,10 +72,10 @@
     autoPreviewOnQueryChange: true
     closeOnConfirm: true
     revealOnStartCondition:
-      default: 'never'
+      default: 'always'
       enum: ['never', 'always', 'on-input']

-  _.extend(properties, otherProperties) if otherProperties?
+  _.deepExtend(properties, otherProperties) if otherProperties?

   return {
     type: 'object'
@@ -101,11 +101,19 @@
   # Per providers settings
   # -------------------------
   GitDiffAll: newProviderConfig()
-  Fold: newProviderConfig()
-  Symbols: newProviderConfig()
+  Fold: newProviderConfig(
+    revealOnStartCondition:
+      default: "on-input"
+  )
+  Symbols: newProviderConfig(
+    revealOnStartCondition:
+      default: "on-input"
+  )
   Linter: newProviderConfig()
   Bookmarks: newProviderConfig()
   Scan: newProviderConfig(
+    revealOnStartCondition:
+      default: "on-input"
     searchWholeWord:
       default: false
       description: """
@@ -151,5 +159,8 @@
       enum: ['smartcase', 'sensitive', 'insensitive']
     searchWholeWord: false
   )
-  Lines: newProviderConfig()
+  Lines: newProviderConfig(
+    revealOnStartCondition:
+      default: "on-input"
+  )
   GitDiff: newProviderConfig()


removed unnecessary commenting

removed unnecessary commenting

--- psiturk/static_dashboard/js/views/SidebarView.coffee
+++ psiturk/static_dashboard/js/views/SidebarView.coffee
@@ -242,13 +242,13 @@
                     num_counters: @options.config.get("Task Parameters").num_counters)

                 # Have content area respond to sidebar link clicks
+                # TODO(Jay): Obvious pattern here. Refactor
                 validator = new Validators
                 saveConfig = _.bind(@save, @)
                 $('#overview').off('click').on 'click', =>
                   $('li').removeClass 'selected'
                   $('#overview').addClass 'selected'
                   @loadOverview()
-                    # @options.chart.refresh())
                 $('#aws-info').on 'click', ->
                   $('#content').html(awsInfo)
                   validator.loadValidators()
@@ -260,11 +260,8 @@
                   $('#content').html(hitConfig)
                   validator.loadValidators()
                   $('#myform').submit(false)
-                  #$(document).on "click", '.save', (event) ->
-                  $('.save').on "click", (event) ->
-                    # event.preventDefault()
-                    saveConfig(event)
-                    # @save(event)
+                  $('.save').on "click", (event) ->
+                    saveConfig(event)
                 $('#database').on 'click', ->
                   $('#content').html(database)
                   validator.loadValidators()


Add Arnie emoji to the end of every quote. Update description.

--- scripts/arnie-quotes.coffee
+++ scripts/arnie-quotes.coffee
@@ -1,5 +1,5 @@
 # Description:
-#   Listens for words and sometimes replies with an Arnie quote
+#   Listens for mentions of Arnie and replies with an Arnie quote
 #
 # Dependencies:
 #   None
@@ -27,4 +27,6 @@

 module.exports = (robot) ->
     robot.hear /(^|\s)(arnold|arnie)(\s|$|[\W])/ig, (msg) ->
-        msg.send msg.random arnie_quotes
+        quote = msg.random arnie_quotes
+        quote += ' <:arnold:298646907658436609>'
+        msg.send quote


Refactored addFile logic. Added async lookupFile.

--- lib/files.coffee
+++ lib/files.coffee
@@ -23,16 +23,17 @@
   constructor: (@source, @target) ->
     @files = []

-  lookup: (path) ->
-    @files[path]
+  addFile: (path, stats) ->
+    ctr = getFileConstructor path
+    file = new ctr(path, stats)
+    files[path] = file
+    utils.log "debug", "Found #{file.constructor.name} at #{path}"
+    return file

   scan: (cb) ->
-    files = @files
+    self = this
     processFile = (path, stats, cb) ->
-      ctr = getFileConstructor path
-      file = new ctr(path, stats)
-      files[path] = file
-      utils.log "debug", "Found #{file.constructor.name} at #{path}"
+      self.addFile(path, stats)
       cb()

     utils.iterateFolder @source, proignore, processFile, =>
@@ -50,6 +51,14 @@
         processFile(i+1)

     processFile(0)
+
+  lookupFile: (path, cb) ->
+    if @files[path]
+      return cb(null, @files[path])
+    else
+      fs.stat pathUtils.join(@source, path), (err, stats) ->
+        return cb(err) if err
+        cb(null, addFile(path, stats))

   buildOutdated: (cb) ->
     self = this


:art: improve emoji size calculation and don't show hover with limit by emoji.

--- lib/hover.coffee
+++ lib/hover.coffee
@@ -3,15 +3,23 @@

 class Hover
   constructor: (@vimState) ->
-    @text = ''
+    @text = []
     @view = atom.views.getView(this)

   add: (text) ->
-    @text += text
+    @text.push text
     @view.show()

+  getText: ->
+    limit = switch
+              when ':clipboard:' in @text then 3
+              when ':scissors:' in @text then 3
+              else  2
+    return if @text.length < limit
+    @text.join('')
+
   reset: ->
-    @text = ''
+    @text = []
     @view.reset()

   destroy: ->
@@ -26,16 +34,19 @@
   initialize: (@model) ->
     this

-  emojify: (text) ->
-    emoji(String(text), emojiFolder, 20)
+  emojify: (text, size=20) ->
+    emoji(String(text), emojiFolder, size)

   show: ->
-    @innerHTML = @emojify(@model.text)
     {editor} = @model.vimState
+    lineHeightInPixels = editor.getLineHeightInPixels()
+    unless text = @model.getText()
+      return
+    @innerHTML = @emojify(text, lineHeightInPixels * 0.9 + 'px')
     @style.paddingLeft  = '0.2em'
     @style.paddingRight = '0.2em'
     @style.marginLeft   = '-0.2em'
-    @style.marginTop = (editor.getLineHeightInPixels() * -2) + 'px'
+    @style.marginTop = (lineHeightInPixels * -2) + 'px'

     point = editor.getCursorBufferPosition()
     @marker = editor.markBufferPosition point,


fixed my stupidness

fixed my stupidness

--- lib/index.coffee
+++ lib/index.coffee
@@ -107,7 +107,7 @@

     filename = filename.toString()

-    headers['Accept-Encoding:'] = gzip
+    headers['Accept-Encoding:'] = 'gzip'

     @getFile filename, headers, (err, res) ->
       return cb err if err


Additional checkStale run after deltas are calculated

--- lib/surveyor.coffee
+++ lib/surveyor.coffee
@@ -113,7 +113,7 @@
           for pid, procData of slaveData.processes
             running++ if procData.repo is repo and procData.status is 'running' and procData.commit is repoData.opts.commit
         repoData.delta = repoData.instances - running
-    cb()
+    @checkStale model.manifest, cb
   @markHealthy = (cb) ->
     return cb null if Object.keys(model.manifest).length is 0
     counter = 0
@@ -292,6 +292,7 @@
     for slave, data of model.slaves
       for pid, proc of data.processes
         repo = manifest[proc.repo]
+        continue if !repo
         kill slave, pid, proc if (proc.commit isnt repo.opts.commit) and repo.killable
         if repo.prunable and repo.delta < 0
           kill slave, pid, proc, 100


:bug: Fix problems with symlinks (atom/tabs #182)

It also replaces the use of atom.project.getRepositories (which will be removed in version 2.0) for atom.project.repositoryForDirectory

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -190,9 +190,12 @@

   setupVcsStatus: ->
     return unless @path?
-    repo = @repoForPath(@path)
-    @subscribeToRepo(repo)
-    @updateVcsStatus(repo)
+    @repoForPath(@path).then (repo) =>
+      @subscribeToRepo(repo)
+      @updateVcsStatus(repo)
+    .catch (err) ->
+      # We can only get here if repository is destroyed
+      # by the time the promise is resolved

   # Subscribe to the project's repo for changes to the VCS status of the file.
   subscribeToRepo: (repo) ->
@@ -207,11 +210,10 @@
     @repoSubscriptions.add repo.onDidChangeStatuses =>
       @updateVcsStatus(repo)

-  repoForPath: (goalPath) ->
-    for projectPath, i in atom.project.getPaths()
-      if goalPath is projectPath or goalPath.indexOf(projectPath + path.sep) is 0
-        return atom.project.getRepositories()[i]
-    null
+  repoForPath: ->
+    for dir in atom.project.getDirectories()
+      return atom.project.repositoryForDirectory(dir) if dir.contains @path
+    Promise.resolve(null)

   # Update the VCS status property of this tab using the repo.
   updateVcsStatus: (repo, status) ->


Fix some values not being closed over properly

--- src/property.coffee
+++ src/property.coffee
@@ -71,7 +71,8 @@
   registerGlobal: ->
     return if @_isRegistered
     @_isRegistered = true
-    for { name, type, subname } in @definition.globalDependencies
+    @definition.globalDependencies.forEach (dep) =>
+      { name, type, subname } = dep
       switch type
         when "singular"
           if @object[name]
@@ -102,12 +103,12 @@
   trigger: =>
     @clearCache()
     if @hasChanged()
-      value = @get()
+      newValue = @get()

       changes = {}
       changes[name] = @object[name] for name in @dependents when name isnt @name

-      @event.trigger(@_oldValue, value)
+      @event.trigger(@_oldValue, newValue)
       for own name, value of changes
         prop = @object[name + "_property"]
         prop.clearCache()
@@ -115,9 +116,9 @@
           prop.event.trigger(prop._oldValue, value)
           prop._oldValue = value

-      changes[@name] = value
+      changes[@name] = newValue
       @object.changed?.trigger?(changes)
-      @_oldValue = value
+      @_oldValue = newValue

   ["bind", "rebind", "unbind", "one", "resolve"].forEach (fn) =>
     this::[fn] = -> @event[fn](arguments...)


:new: Validate linter.scope properly

:new: Validate linter.scope properly

--- lib/validate.coffee
+++ lib/validate.coffee
@@ -16,6 +16,9 @@
       throw new Error('Linter.name must be a string') if typeof linter.name isnt 'string'
     else
       linter.name = null
+    if linter.scope and typeof linter.scope is 'string'
+      linter.scope = linter.scope.toLowerCase()
+    throw new Error('Linter.scope must be either `file` or `project`') if linter.scope isnt 'file' and linter.scope isnt 'project'
     return true

   messages: (messages, linter) ->


Notification: prepareData is changed as viewAppended

--- client/Main/CommonViews/notificationlistitemview.coffee
+++ client/Main/CommonViews/notificationlistitemview.coffee
@@ -43,7 +43,6 @@

     @activityPlot = new KDCustomHTMLView tagName: "span"
     @timeAgoView  = new KDTimeAgoView null, @getLatestTimeStamp @getData().dummy
-    @prepareData()

   fetchActors: ->
@@ -69,7 +68,7 @@
       warn err.description

-  prepareData: ->
+  viewAppended: ->
     promises = []
     promises.push @fetchActors()
     promises.push @getActivityPlot()


SidebarMachineBox: Rename method.

SidebarMachineBox: Rename method.

--- client/Social/Activity/sidebar/sidebarmachinebox.coffee
+++ client/Social/Activity/sidebar/sidebarmachinebox.coffee
@@ -37,10 +37,10 @@
       partial  : 'Workspaces'
       click    : =>
         modal = new MoreWorkspacesModal {}, @getData().workspaces
-        modal.once 'NewWorkspaceRequested', @bound 'showAddWorkspaceInput'
+        modal.once 'NewWorkspaceRequested', @bound 'createAddWorkspaceInput'

-  showAddWorkspaceInput: ->
+  createAddWorkspaceInput: ->

     if @addWorkspaceView
       @addWorkspaceView.input.setFocus()


activity: fix for search highlight markers

--- client/activity/lib/flux/actions/searchconstants.coffee
+++ client/activity/lib/flux/actions/searchconstants.coffee
@@ -1,4 +1,4 @@
 module.exports =
-  HIGHLIGHT_PRE_MARKER  : '!em='
-  HIGHLIGHT_POST_MARKER : '=em!'
+  HIGHLIGHT_PRE_MARKER  : 'hPRE='
+  HIGHLIGHT_POST_MARKER : '=hPOST'


Login:doRegister: pass referrer or use in-memory one [completes #91625346]

--- client/landing/site.landing/coffee/login/AppView.coffee
+++ client/landing/site.landing/coffee/login/AppView.coffee
@@ -484,6 +484,11 @@

     formData.agree    = 'on'

+    unless formData.referrer
+      {mainController}  = KD.singletons
+      referrer          = KD.utils.getReferrer() or mainController._referrer
+      formData.referrer = referrer  if referrer
+
     form or= @registerForm
     form.notificationsDisabled = yes
     form.notification?.destroy()


use clone of query for dialog

use clone of query for dialog

--- client/lanes/components/record-finder/RecordFinder.cjsx
+++ client/lanes/components/record-finder/RecordFinder.cjsx
@@ -21,13 +21,14 @@
             @props.model

     showFinder: ->
-        @props.query.reset()
+        query = @props.query.clone()
+        query.autoRetrieve = true
         @context.viewport.displayModal(
             title: "Find #{@props.query.title}"
             buttons: [{title: 'Cancel'}]
             autoHide: true
             body: =>
-                <LC.RecordFinder.Dialog query={@props.query} onRecordSelect={@setModel} />
+                <LC.RecordFinder.Dialog query={query} onRecordSelect={@setModel} />
         )

     setModel: (model) ->


Remove debugging

Remove debugging

--- src/reactive.coffee
+++ src/reactive.coffee
@@ -918,11 +918,11 @@
               else
                 (elt.childNodes[index].insertBefore node) for node in toAdd
           else if contents instanceof ObsCell
-            console.log('!! rxt.svg_mktag ObsCell')
-            console.log("#{elt}")
+            #console.log('!! rxt.svg_mktag ObsCell')
+            #console.log("#{elt}")
             first = contents.x[0]
-            console.log(first instanceof SVGElement)
-            console.log(contents.x[0].toString())
+            #console.log(first instanceof SVGElement)
+            #console.log(contents.x[0].toString())
 #            rx.autoSub contents.onSet, ([old, val]) -> updateContents(elt, val)
             contents.onSet.sub(([old, val]) -> updateSVGContents(elt, val))
           else


Fix indentation error. Callback was being called twice.

--- src/renderer.coffee
+++ src/renderer.coffee
@@ -1,4 +1,3 @@
-
 fs = require 'fs'
 util = require 'util'
 async = require 'async'
@@ -33,7 +32,7 @@
         else
           writeStream.write result
           writeStream.end()
-        callback null, true
+          callback null, true
       else
         logger.verbose "skipping #{ content.url }"
         callback null, false


Catch failing scenario

Catch failing scenario

--- src/selector.coffee
+++ src/selector.coffee
@@ -53,7 +53,7 @@
         return no if sel.id?  and sel.id  isnt tag.attr('id')
         # classes
         tagclass = tag.attr('class') ? ""
-        return no for cls in sel.classList ? [] when tagclass.indexOf(cls) is -1
+        return no for cls in sel.classList ? [] when (typeof(tagclass.indexOf) is 'undefined' || tagclass.indexOf(cls) is -1)
         # attributes
         for a in sel.attributes ? []
             unless a.operator


modified

modified

--- src/sortsina.coffee
+++ src/sortsina.coffee
@@ -21,6 +21,11 @@
   c = param.category ? 'sh_b'
   s = param.sort ? 'amount'
   n = param.topn ? '40'
+
+  #針對 etf_hq_fund 的特殊處理,濾除貨幣基金:
+  if c is 'etf_hq_fund'
+    n += 10
+    isetf = true

   options =
     url: "#{host}/Market_Center.getHQNodeDataSimple?page=1&num=#{n}&sort=#{s}&asc=0&node=#{c}&symbol=&_s_r_a=sort"
@@ -46,13 +51,18 @@
         console.error 'sortsina.coffee >> qsort', error
         return

-      callback err, arr
+      if isetf
+        resp = (each for each in arr when (not /^(1590|511)/.test each.code))
+      else
+        resp = arr
+
+      callback err, resp

 module.exports = qsort

-### 在這行前面加或去一個#就可以測試,測試完記得加回去
-qsort {category:'sh_b'},(err, arr)->
+### 在這行前面加或去一個#就可以測試,測試完記得加回去###
+qsort {category:'etf_hq_fund'},(err, arr)->
   console.log arr
 ###


Fixed issue in which the _handleErrors function was not returning the status code and message returned by the vault server.

--- node-vault.coffee
+++ node-vault.coffee
@@ -95,13 +95,20 @@
     @_request 'DELETE', '/'+path, null, @_handleErrors(done)

   _handleErrors: (done)->
+    extend = exports.extend = (object, properties) ->
+      for key, val of properties
+        object[key] = val
+      object
     return (err, res, body)->
       debug err if err
       return done err if err
       err = new Error(body.errors[0]) if body?.errors?
+      if err
+        if res.statusCode
+          extend err, statusCode: res.statusCode
+          extend err, statusMessage: res.statusMessage
       return done err if err
       done null, body
-

   _generate: (name, opts)->
     @[name] = ->


default-config is no longer used

default-config is no longer used

--- benchmark/benchmark-suite.coffee
+++ benchmark/benchmark-suite.coffee
@@ -14,7 +14,6 @@

     rootView.width(1024)
     rootView.height(768)
-    require fs.join(config.configDirPath, "default-config")
     rootView.open() # open blank editor
     editor = rootView.getActiveEditor()


might as well change to route while we're here

--- resources/assets/coffee/store-username-change.coffee
+++ resources/assets/coffee/store-username-change.coffee
@@ -24,7 +24,7 @@
   $status = $('#username-check-status')
   requestedUsername = $('#username.form-control').val()

-  $.post '/users/check-username-availability', username: requestedUsername
+  $.post laroute.route('users.check-username-availability'), username: requestedUsername
   .done (data) ->
     return unless data.username == $('#username.form-control').val()


fix #12 Polish S

fix #12 Polish S

https://medium.com/medium-eng/the-curious-case-of-disappearing-polish-s-fa398313d4df#.2drl4f91m

--- static/index.coffee
+++ static/index.coffee
@@ -26,6 +26,7 @@
       contentSrc = $editor[0].innerHTML = he.encode content

   wantsToEdit = (evt) ->
+    return false  if evt.altKey
     metaKey = evt.ctrlKey
     metaKey = evt.metaKey  if /^Mac/.test navigator.platform
     return false  unless metaKey
@@ -57,6 +58,7 @@
     $editor.focus()

   wantsToSave = (evt) ->
+    return false  if evt.altKey
     metaKey = evt.ctrlKey
     metaKey = evt.metaKey  if /^Mac/.test navigator.platform
     return false  unless metaKey


Scroll to the top of the page when navigating to profile page

--- core/app/backbone/controllers/profile_controller.coffee
+++ core/app/backbone/controllers/profile_controller.coffee
@@ -43,6 +43,8 @@
       main_region.show(new NotificationSettingsView model: user)

   showPage: (username, options) ->
+    $(window).scrollTop(0)
+
     FactlinkApp.leftBottomRegion.close()
     @main = new TabbedMainRegionLayout();
     FactlinkApp.mainRegion.show(@main)


Don't store previous fact relation opinion, that feels too unnatural

--- core/app/backbone/views/fact_relations/vote_view.coffee
+++ core/app/backbone/views/fact_relations/vote_view.coffee
@@ -39,17 +39,12 @@
   set_fact_relation_opinion: (opinion) ->
     return if @model.current_opinion() == opinion

-    @_originalFactRelationOpinion = @model.current_opinion()
     @model.setOpinion opinion

   unset_fact_relation_opinion: (opinion) ->
     return unless @model.current_opinion() == opinion

-    if @_originalFactRelationOpinion?
-      @model.setOpinion @_originalFactRelationOpinion
-      @_originalFactRelationOpinion = null
-    else
-      @model.removeOpinion()
+    @model.removeOpinion()

   set_fact_opinion: (opinion) ->
     return if @model.getFact().getFactWheel().isUserOpinion opinion


Remove typeOf

Remove typeOf

--- lib/solid.coffee
+++ lib/solid.coffee
@@ -1,5 +1,3 @@
-typeOf = (obj) ->
-  Object.prototype.toString.call(obj).slice 8, -1

 routes =
   cache : {}
@@ -15,16 +13,16 @@

   build_recurse : (prefix, paths...) ->
     for path in paths
-      switch typeOf(path)
-        when "Object" # Hash
+      switch typeof(path)
+        when "object" # Hash
           for pathName, value of path
-            type = typeOf(value)
-            if type is "Object" # Hash again
+            type = typeof(value)
+            if type is "object" # Hash again
               routes.build_recurse "#{prefix}/#{pathName}/", value
             else
-              value = routes.normalizePath value  if type is "String"
+              value = routes.normalizePath value  if type is "string"
               routes.bind prefix + pathName, value
-        when "String"
+        when "string"
           path = routes.normalizePath prefix + path
           routes.bind path, path
         else


added stack traces to evaled expressions

--- platform/src/gamEvolve.coffee
+++ platform/src/gamEvolve.coffee
@@ -243,7 +243,7 @@
     try
       evaluatedParams[paramName] = evaluationContext.evaluateExpression(paramValue)
     catch error
-      throw new Error("Error evaluating the input parameter expression '#{paramValue}' for node '#{node.action}': #{error}")
+      throw new Error("Error evaluating the input parameter expression '#{paramValue}' for node '#{node.action}':\n#{error.stack}")

   locals =
     params: evaluatedParams
@@ -267,7 +267,7 @@
     try
       outputValue = evaluationContext.evaluateExpression(paramValue, outParams)
     catch error
-      throw new Error("Error evaluating the output parameter value expression '#{paramValue}' for node '#{node.action}': #{error}. Output params were #{JSON.stringify(outputParams)}.")
+      throw new Error("Error evaluating the output parameter value expression '#{paramValue}' for node '#{node.action}':\n#{error.stack}\nOutput params were #{JSON.stringify(outputParams)}.")

     [parent, key] = GE.getParentAndKey(evaluationContext, paramName.split("."))
     parent[key] = outputValue
@@ -295,7 +295,7 @@
           # If the where clause evaluates to false, don't add it
           if evaluationContext.evaluateExpression(node.foreach.where) then bindingSet.push(newBindings)
         catch error
-          throw new Error("Error evaluating the where expression '#{node.foreach.where}' for foreach node '#{node}': #{error}")
+          throw new Error("Error evaluating the where expression '#{node.foreach.where}' for foreach node '#{node}':\n#{error.stack}")
       else
         bindingSet.push(newBindings)
   else if _.isString(node.foreach.from)
@@ -319,7 +319,7 @@
           # If the where clause evaluates to false, don't add it
           if evaluationContext.evaluateExpression(node.foreach.where) then bindingSet.push(newBindings)
         catch error
-          throw new Error("Error evaluating the where expression '#{node.foreach.where}' for foreach node '#{node}': #{error}")
+          throw new Error("Error evaluating the where expression '#{node.foreach.where}' for foreach node '#{node}':\n#{error.stack}")
       else
         bindingSet.push(newBindings)
   else
@@ -378,7 +378,7 @@
     try
       outputValue = evaluationContext.evaluateExpression(src)
     catch error
-      throw new Error("Error evaluating the output parameter value expression '#{src}' for send node: #{error}")
+      throw new Error("Error evaluating the output parameter value expression '#{src}' for send node:\n#{error.stack}")

     [parent, key] = GE.getParentAndKey(evaluationContext, dest.split("."))
     parent[key] = outputValue


added http message to RetsServerError

added http message to RetsServerError

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -19,9 +19,9 @@

 class RetsServerError extends Error
-  constructor: (@retsMethod, @httpStatus) ->
+  constructor: (@retsMethod, @httpStatus, @httpStatusMessage) ->
     @name = 'RetsServerError'
-    @message = "Error while attempting #{@retsMethod} - HTTP Status #{@httpStatus} returned"
+    @message = "Error while attempting #{@retsMethod} - HTTP Status #{@httpStatus} returned (#{httpStatusMessage})"
     Error.captureStackTrace(this, RetsServerError)

@@ -68,7 +68,7 @@
     Promise.reject(error)
   .spread (response, body) ->
     if response.statusCode != 200
-      error = new RetsServerError(methodName, response.statusCode)
+      error = new RetsServerError(methodName, response.statusCode, response.statusMessage)
       logger.debug "RETS #{methodName} error:\n" + error.message
       return Promise.reject(error)
     response: response


OPCE3: Added documentation

OPCE3: Added documentation

--- lib/y-rte.coffee
+++ lib/y-rte.coffee
@@ -30,6 +30,34 @@

 class Selection
+  # Construct a new selection
+  #
+  # @overload constructor(startAtN, startAtPosition, endAtN, endAtPosition, [style])
+  #   Construct a new selection using the position in a word for start and end
+  #   positions
+  #   @param [Integer] startAtN position of the first word of selection
+  #   @param [Integer] startAtPosition position in this first word
+  #   @param [Integer] endAtN position of the last word of selection
+  #   @param [Integer] endAtPosition position in this last word
+  #   @option options [Object] style the style of the selection
+  #
+  # @overload constructor(start, end, rte, [style])
+  #   Construct a new selection using the index of the first and last character.
+  #   Retrieves the position in (word, position) using an instance of rte
+  #   @param [Integer] start index of the first character
+  #   @param [Integer] end index of the last character
+  #   @param [Rte] rte a rich-text editor (Rte) instance
+  #   @option options [Object] style the style of the selection
+  #
+  # @overload constructor(startPos, endPos, [style])
+  #   Construct a new selection using two position objects
+  #   @param [Object] startPos the position of the start
+  #   @option startPos [Integer] word first word of selection
+  #   @option startPos [Integer] pos position in first word of selection
+  #   @param [Object] endPos the position of the end
+  #   @option endPos [Integer] word last word of selection
+  #   @option endPos [Integer] pos position in last word of selection
+  #   @option options [Object] style the style of the selection
   constructor: (a, b, c, d, e)->
     if a? and b? and c? and d?
       if !( typeof a is "number" and
@@ -49,7 +77,7 @@
       c.constructor is "Rte"

       [@startPos, @endPos] = @_relativeFromAbsolute(a, b, c)
-      style = d
+      attr = d

     else if a? and b? and a.pos? and a.word? and b.pos? and b.word?
       @startPos = a
@@ -68,7 +96,13 @@
     @startPos.gt = @endPos.gt = (s) ->
       @word > s.word or (@word == s.word and @pos >= s.pos)

-  relativeFromAbsolute: (untilStart, untilEnd, rte)->
+  # Convert indexes from beginning of text to coordinates expressed in word and
+  # position within word
+  #
+  # @param [Integer] untilStart index from first character
+  # @param [Integer] untilEnd index from first character
+  # @param [Rte] rte a rich text editor instance
+  _relativeFromAbsolute: (untilStart, untilEnd, rte)->
     # Convert absolute coordinates to relatives
     spw = spp = epw = epp = 0

@@ -94,7 +128,7 @@

     [{word: spw, pos: spp}, {word: epw, pos: epp}]

-  # Compares *the bounds* of two selections
+  # Compares the bounds of two selections
   #
   # @param [Selection] s the selection to compare to this
   #
@@ -104,13 +138,6 @@
     @endPos.word == s.endPos.word and
     @endPos.pos == s.endPos.pos

-  # Compares *the bounds* of two selections
-  #
-  # @param [Selection] s the selection to compare to this
-  #
-  notEquals: (s) ->
-    not equals(s)
-
   # Returns true if the given selection is in the current selection
   #
   # @param [Selection] s the selection to compare to this
@@ -118,44 +145,50 @@
   in: (s) ->
     @startPos.lt(s) and @endPos.gt(s)

+  # Returns true if the current selection is in the given selection
+  #
+  # @param [Selection] s the selection to compare to this
+  #
   contains: (s) ->
     s.in(@)

+  # Returns true if the given selection overlaps the current selection
+  #
+  # @param [Selection] s the selection to compare to this
+  #
   overlaps: (s) ->
     @startPos.lt(s.endPos) or @endPos.gt(s.startPos)

   #TODO
-  setStyle: (@style) ->
-
+  setAttr: (@attr) ->
+
+  # Create a copy of the selection
+  #
   clone: ->
-    new Selection(@startPos, @endPos)
-
+    new Selection(@startPos, @endPos, @style)
+
+  # Validate a selection if the start is before the end of the selection
+  #
   isValid: ->
     @startPos.lt(@endPos)

-  # Try to merge this selection with the one given in argument
-  #
-  merge: (s, rte) ->
-    # Check if they're contiguous
-    if s.endPos.word == @startPos.word or
-       (s.endPos.word == @startPos.word -1 and
-        s.endPos.loc == rte.getWord(s.endPos.word).length() and
-        @startPos.loc == 0)
-      # boundaries of new selection
-      start = s.startPos
-      end = @endPos
-      # remove link of middle words to selection
-      rte.getWord(s.endPos.word).removeSel(s)
-      rte.getWord(@startPos.word).removeSel(@)
-    else if @endPos.word == s.startPos.word or
-       (@endPos.word == s.startPos.word -1 and
-        @endPos.loc == rte.getWord(@endPos.word).length() and
-        s.startPos.loc == 0)
-      start = @startPos
-      end = s.endPos
-      rte.getWord(@endPos.word).removeSel(@)
-      rte.getWord(s.endPos.word).removeSel(s)
+# Class describing the Rich Text Editor type
+#
+class Rte
+  # @property [Options] _rte the RTE object
+  # @param [String] content the initial content to set
+  # @option _rte [Array<Selection>] selections array containing all the current selections
+  # @option _rte [Array<String>] words array containing all the words of the text
+  #
+  constructor: (content = '')->
+    if content.constructor is String
+      @_rte = {}
+      @_rte.styles = []
+      @_rte.selections = []
+      @_rte.cursorInformation = {}
+      @_rte.words = []
+      @push(content)
     else
       return

@@ -183,12 +216,24 @@

   _name: "Rich Text Editor"

+  # _getModel:
+  # _setModel:
+  # observe:
+  # unobserve:
+
+  # @overload val()
+  #   Return a string representation of the object
+  #
+  # @overload val(content)
+  #   Set the value of the object to content
+  #   @param [String] content the initial content to set
+  #
   val: (content)->
     if content?
       # reset styles when replacing content
       @_rte.words = []
       @_rte.style = []
-      @push(content)
+      @_push(content)
     else
       # TODO: support breaks (br, new paragraph, …)
       (e.word for e in @_rte.words).join('')
@@ -225,11 +270,17 @@
       throw new Error "Index out of bounds"
     @_rte.words[index].word = content

-  push: (content) ->
-    wObj = buildWord content
-    @_rte.words = @_rte.words.concat(wObj)
-
-
+  # Split the content around ' ' and append all the words created to the object
+  #
+  _push: (content) ->
+    for w in content.split(' ')
+      @_rte.words.push(w)
+
+  # Insert words at position
+  #
+  # @param [Integer] position the position where to insert words
+  # @param [Array<String>] words the words to insert at position
+  #
   insertWords: (position, words)->
     # TODO: update selections
     if typeof position isnt "number"
@@ -241,17 +292,29 @@
       before = @getWords(0, Math.max(position-1, 0)).append(new Word ' ')
       if position == 0
         before = []
-      if position == @_rte.words.length - 1
-        after = []
-
-      wordsObj = (new Word w for w in words)
-
-      @_rte.words = before.concat(wordsObj).concat(after)
-
+      else
+        before = @_rte.words[..position-1]
+      after = @_rte.words[position..]
+      @_rte.words = before.concat(words).concat(after)
+      # @updateInsertWords(position, words.length)
     else
       throw new Error 'Index #{position} out of bound in word list'

-
+  # insert l words at pos wNum
+  #
+  updateInsertWords: (wNum, n)->
+    # TODO
+
+  # insert n caracters in word wNum at position pos
+  #
+  updateInsert: (wNum, pos, n)->
+    # TODO
+
+
+  # Delete all the words between start and end
+  #
+  # @param [Integer] start position of first word to delete
+  # @param [Integer] end position of last word to delete
   deleteWords: (start, end) ->
     if not end?
       end = start+1
@@ -265,6 +328,10 @@
       @_rte.words = before.concat(@getWords(end))
     @_rte.words

+  # Merge two words at position
+  #
+  # @param [Integer] n position of word where to perform merge. The merge will be done with the word at right (if any)
+  #
   merge: (n) ->
     if 0 <= n < @_rte.words.length
       w = @getWord(n).trimRight()
@@ -273,6 +340,10 @@
     else
       throw new Error "Impossible to merge"

+  # Delete a selection
+  #
+  # @param [Selection] sel the selection to delete
+  #
   deleteSel: (sel) ->
     if not sel.isValid()
       throw new Error "Invalid selection"
@@ -301,8 +372,11 @@
       # merge
       @merge(s)

-
-
+  # Insert text at position
+  #
+  # @param [Option] position The position where to insert text
+  # @param [String] content the content to insert
+  #
   insert: (sel, content)->
     if not sel.startPos?
       throw new Error "Expected a location object as first argument"
@@ -314,7 +388,8 @@
     word = @getWord(n)
     @setWord(n, word.substring(0, pos) + content + word.substring(pos))

-  # relative jump from position
+  # Relative jump from position
+  #
   _jump: (position, relJump) ->
     word = position.word
     pos = position.pos
@@ -348,25 +423,36 @@
       pos = pos
     {word: word, pos: pos}

-  # Set the style of the selection and try to extend as much
+  # get all selections with right (or left end) at location
+  _getSel: (location, rightOrLeft) ->
+    ret = []
+    if rightOrLeft == 'right'
+      selList = @_rte.words[location.word].refRight
+      for sel in selList
+        if sel.endPos.pos == location.pos
+          ret.push(sel)
+
+    else if rightOrLeft == 'left'
+      selList = @_rte.words[location.word].refLeft
+      for sel in selList
+        if sel.startPos.pos == location.pos
+          ret.push(sel)
+
+    else
+      throw new Error "Error in second argument of _getSel"
+
+    ret
+
+  # Set the attribute to the selection and try to extend as much
   # as possible existing ones
   #
-  setStyle: (selection, style)->
+  setAttr: (thisSel)->
     if not thisSel.isValid()
       throw new Error "Invalid selection"

-    # Try to merge with previous / next contiguous selection
-    {prevWord, position} = @_jump(s.startPos, -1)
-    {nextWord, position} = @_jump(s.endPos,   +1)
-    for s in prevWord.selections when selection.style == s.style
-      s.merge selection, @
-    for s in nextWord.selections when selection.style == s.style
-      s.merge selection, @
-
   # Apply a delta to the object
   # @see http://quilljs.com/docs/deltas/
   #
-  delta: (deltas) ->
     position = 0
     for delta in deltas.ops
       if delta.retain?


updated httpbind

updated httpbind

--- core/core_modules/httpbind.coffee
+++ core/core_modules/httpbind.coffee
@@ -4,17 +4,7 @@
 express = require 'express'
 os      = require 'os'

-getLocalIP = ->
-    ifaces = os.networkInterfaces()
-    addresses = []
-    for dev of ifaces
-        ifaces[dev].forEach (details)->
-            if details.family is 'IPv4' and details.internal is false
-                addresses.push(details.address)
-    if addresses.length is 0
-        return "127.0.0.1"
-    else
-        return addresses[0]
+

 findTargetPath = (folder,filename,index,callback)->
@@ -32,6 +22,18 @@
 class HttpBind
     constructor : (@mew)->
         @staticPathDefinitionPool = {}
+
+    getLocalIP : ->
+        ifaces = os.networkInterfaces()
+        addresses = []
+        for dev of ifaces
+            ifaces[dev].forEach (details)->
+                if details.family is 'IPv4' and details.internal is false
+                    addresses.push(details.address)
+        if addresses.length is 0
+            return "127.0.0.1"
+        else
+            return addresses[0]

     handleHttpAuth : (req,res,possibleAuthPool,next) ->
@@ -80,7 +82,7 @@
         else if process.env.MEWBOT_HOST
             return "#{process.env.MEWBOT_HOST}:#{@mew.port}"
         else
-            return "http://#{getLocalIP()}:#{@mew.port}"
+            return "http://#{@getLocalIP()}:#{@mew.port}"

     bindMiddleware : (path,callback)->
         do(path)=>


Add a listener to monitor for changes to our base directory

--- lifeguard.coffee
+++ lifeguard.coffee
@@ -75,10 +75,24 @@
   #----------

   _startUp: ->
+    # there are two things we need to be watching for:
+    # 1) a change event on tmp/restart.txt
+    # 2) a change to the symlinked current that is @dir
+
     # set up a watcher on tmp/restart.txt
-    @watcher = fs.watch path.resolve(@dir,"tmp/restart.txt"), (type,filename) =>
+    @r_watcher = fs.watch path.resolve(@dir,"tmp/restart.txt"), (type,filename) =>
       # only restart on a touch, not on a deletion (such as when current/ is unlinked)
       @_restartInstance() if fs.existsSync("#{@dir}/tmp/restart.txt")
+
+    # watch for our directory to change out from under us
+    d_base = path.basename(@dir)
+    @d_watcher = fs.watch path.resolve(@dir,".."), (type,filename) =>
+      if filename == d_base
+        # we need to start over.  the directory is changing.
+        @r_watcher.close()
+        @d_watcher.close()
+
+        @_watchForDir path.resolve(@dir,"tmp/restart.txt"), => @_startUp()

     @_restartInstance()


Kick docs threshold down again because I removed public methods

--- spec/app/atom-spec.coffee
+++ spec/app/atom-spec.coffee
@@ -355,7 +355,7 @@
           throw new Error("There were errors compiling documentation. See console for details.")

         coverage = parseFloat results.pop().match(/.+?%/)
-        expect(coverage).toBeGreaterThan 79
+        expect(coverage).toBeGreaterThan 78

         # stderr
         expect(docRunner.argsForCall[0][2]).toBe ''


Default entry

Default entry

--- _mdwriter.cson
+++ _mdwriter.cson
@@ -2,7 +2,7 @@
 siteEngine: "jekyll"

 # absolute path to the root directory of your blog
-siteLocalDir: "/home/msurbey/workspace/github.com/ecwpz91/ecwpz91.github.io"
+siteLocalDir: "/your/path/here"

 # directory to drafts from the root of siteLocalDir
 siteDraftsDir: "_drafts/"


Remove Anchor and AnchorRange. They're fully replaced by markers.

We're still leaking markers for selections and cursors. We need to
clean that up before merging.

--- spec/snippets-spec.coffee
+++ spec/snippets-spec.coffee
@@ -86,7 +86,7 @@

       describe "when the snippet contains tab stops", ->
         it "places the cursor at the first tab-stop, and moves the cursor in response to 'next-tab-stop' events", ->
-          anchorCountBefore = editor.activeEditSession.getAnchors().length
+          markerCountBefore = editor.activeEditSession.getMarkerCount()
           editor.setCursorScreenPosition([2, 0])
           editor.insertText('t2')
           editor.trigger keydownEvent('tab', target: editor[0])
@@ -118,7 +118,7 @@
           editor.trigger keydownEvent('tab', target: editor[0])
           editor.trigger keydownEvent('tab', target: editor[0])
           expect(buffer.lineForRow(2)).toBe "go here next:(abc) and finally go here:(  )"
-          expect(editor.activeEditSession.getAnchors().length).toBe anchorCountBefore
+          expect(editor.activeEditSession.getMarkerCount()).toBe markerCountBefore

         describe "when tab stops are nested", ->
           it "destroys the inner tab stop if the outer tab stop is modified", ->


:lipstick:

:lipstick:

--- spec/template-spec.coffee
+++ spec/template-spec.coffee
@@ -57,8 +57,18 @@
     it 'converts markdown', ->
       expect(template.render({test: '*test*'}, markdown: ['test'])).toEqual '
test
\n'

+    # coffeelint: disable=max_line_length
+
     it 'resolves references', ->
-      expect(template.render({test: '{String}'}, resolve: ['test'])).toEqual "String"
+      actual = template.render({test: '{String}'}, resolve: ['test'])
+      mozilla = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String"
+      expected = "String"
+
+      expect(actual).toEqual expected
+
+    # coffeelint: enable=max_line_length

     it 'does not resolve references without braces', ->
-      expect(template.render({test: '`undefined`'}, resolve: ['test'], markdown: ['test'])).toEqual '
undefined
\n'
+      actual = template.render({test: '`undefined`'}, resolve: ['test'], markdown: ['test'])
+
+      expect(actual).toEqual '
undefined
\n'


include transposing into template

include transposing into template

--- src/opensong.coffee
+++ src/opensong.coffee
@@ -30,7 +30,7 @@

           {{#chords}}
-          {{this}}
+          {{transpose this}}
           {{/chords}}

           {{#lyrics}}
@@ -45,6 +45,12 @@
       {{/this}}
     """
     @template = Handlebars.compile templateSrc
+
+  transpose: (amount) ->
+    Handlebars.registerHelper 'transpose', (chord) ->
+      transposeChord chord, amount || 0
+
+    this.renderLyrics() # rerender

   renderLyrics: ->
     # clear Html Element and add opensong class
@@ -201,3 +207,6 @@
       else
         abbr

+  Handlebars.registerHelper 'transpose', (chord) ->
+    chord
+


Don't override component name

Don't override component name

--- src/protocol.coffee
+++ src/protocol.coffee
@@ -80,7 +80,6 @@
     debug 'sent components', components.length

   else if sub == 'component' and cmd == 'getsource'
-
     sendMainGraphSource = () ->
       graph = proto.coordinator.serializeGraph 'main'
       resp =
@@ -101,7 +100,6 @@
             language: 'javascript'
             code: ""
           proto.transport.send 'component', 'error', { name: payload.name, error: err.message }, ctx
-        source.name = payload.name
         proto.transport.send 'component', 'source', source, ctx

   else if sub == 'component' and cmd == 'source'


inline examples are pure

inline examples are pure

--- app/markdown.coffee
+++ app/markdown.coffee
@@ -1,5 +1,5 @@
 Marked = require 'marked'
-React = require 'react'
+React = require 'react/addons'
 Components = require './components'
 Context = require './context'
 ContextComponents = require './contextComponents'
@@ -31,7 +31,7 @@

 InlineExampleComponent = React.createClass
   displayName: 'InlineExampleComponent'
-  mixins: [ContextComponents.ContextAwareMixin]
+  mixins: [ContextComponents.ContextAwareMixin, React.addons.PureRenderMixin]
   render: ->
     exampleComponent = Components.SourceComponent displayValue: @props.displayValue, value: @props.value, language: 'coffeescript'


Support arbitrary offset in AABB overlap test

--- app/js/utils.coffee
+++ app/js/utils.coffee
@@ -90,7 +90,15 @@
     values = (Vec.dotProduct point, axis for point in points)
     [Math.min(values...), Math.max(values...)]

-  aabbOverlap: ([[ax1, ay1], [ax2, ay2]], [[bx1, by1], [bx2, by2]]) ->
+  aabbOverlap: (aAABB, bAABB, offset=[0,0]) ->
+    [[ax1, ay1], [ax2, ay2]] = aAABB
+    [[bx1, by1], [bx2, by2]] = bAABB
+    [xOffset, yOffset] = offset
+    ax1 += xOffset
+    ax2 += xOffset
+    ay1 += yOffset
+    ay2 += yOffset
+
     @intervalOverlap([ax1, ax2], [bx1, bx2]) > 0 and
       @intervalOverlap([ay1, ay2], [by1, by2]) > 0


Added encodeURIComponent in ajax.serializeParameters to fix the upload of some characters like (+, &, ? ...)

--- src/quo.ajax.coffee
+++ src/quo.ajax.coffee
@@ -106,7 +106,7 @@
         for parameter of parameters
             if parameters.hasOwnProperty(parameter)
                 serialize += "&" if serialize isnt character
-                serialize += parameter + "=" + parameters[parameter]
+                serialize += "#{encodeURIComponent parameter}=#{encodeURIComponent parameters[parameter]}"
         (if (serialize is character) then "" else serialize)

     _xhrStatus = (xhr, settings) ->


Use runtime value of require() in relation. Helps compatibility with browserify

--- src/relation.coffee
+++ src/relation.coffee
@@ -1,6 +1,5 @@
 Spine   = @Spine or require('spine')
 isArray = Spine.isArray
-require = @require or ((value) -> eval(value))

 class Collection extends Spine.Module
   constructor: (options = {}) ->
@@ -111,8 +110,12 @@
      .replace(/-/g, '_')
      .toLowerCase()

+requireModel = (model) ->
+  requireFn = @require or ((value) -> eval(value))
+  requireFn(model)
+
 association = (name, model, record, fkey, Ctor) ->
-  model = require(model) if typeof model is 'string'
+  model = requireModel(model) if typeof model is 'string'
   new Ctor(name: name, model: model, record: record, fkey: fkey)

 Spine.Model.extend


atom: update config.cson

atom: update config.cson

--- init/config.cson
+++ init/config.cson
@@ -3,32 +3,26 @@
     createFileInstantly: true
     suggestCurrentFilePath: true
   "atom-material-ui":
-    compactTreeView: true
     depth: true
     fonts: {}
     panelContrast: true
-    panels: {}
-    rippleAccentColor: true
-    slimScrollbar: true
     tabs:
       compactTabs: true
     treeView:
       compactList: true
     ui:
       panelContrast: true
-      slimScrollbar: true
   "circle-ci":
     apiToken: "CIRCLE-CI-API-TOKEN"
   core:
-    closeEmptyWindows: false
     disabledPackages: [
       "svg-preview"
       "relative-numbers"
     ]
-    excludeVcsIgnoredPaths: false
+    openEmptyEditorOnStart: false
     themes: [
-      "atom-material-ui"
-      "atom-material-syntax"
+      "dracula-ui"
+      "dracula-theme"
     ]
   docblockr: {}
   editor:
@@ -39,6 +33,8 @@
     showInvisibles: true
     useShadowDOM: true
   emmet: {}
+  "exception-reporting":
+    userId: "user_id"
   "file-watcher":
     promptWhenFileHasChangedOnDisk: false
   "fuzzy-finder":
@@ -54,6 +50,8 @@
     showErrorPanel: false
   "linter-jshint":
     disableWhenNoJshintrcFileInPath: true
+  "linter-scss-lint":
+    executablePath: "path_to_linter"
   pigments:
     groupPaletteColors: "by file"
     markerType: "dot"
@@ -63,6 +61,8 @@
   "travis-ci-status": {}
   "tree-view":
     hideIgnoredNames: true
+    showOnRightSide: true
+    squashDirectoryNames: true
   "vim-mode": {}
   welcome:
     showOnStartup: false
@@ -83,6 +83,12 @@
 ".hamlc.text":
   editor:
     preferredLineLength: 1000
+".html.mustache.text":
+  editor:
+    preferredLineLength: 1000
 ".ini.source":
   editor:
     preferredLineLength: 1000
+".mustache.source.sql":
+  editor:
+    preferredLineLength: 1000


Add hexadecimal offset column to charmap snippet


Increase timer delay

Increase timer delay

--- src/streamer.coffee
+++ src/streamer.coffee
@@ -56,10 +56,9 @@
     if @url.indexOf('microphone') != -1
       me.ctr_buffering = spawn 'arecord', ["-f","dat",me.buffer_path + 'stream.wav']
       me.ctr_buffering.stdout.on 'data', ->
-        console.log 'ICICIC'
       me.prototype.initSample()
       me.prototype.setState('ready')
-      setTimeout me.prototype.play, 1000
+      setTimeout me.prototype.play, 1500
     else
       @startBuffering @url, (code, data) ->
         if !code || 0


silent mode テストok

silent mode テストok

--- test/spec/KazitoriSpec.coffee
+++ test/spec/KazitoriSpec.coffee
@@ -520,6 +520,17 @@
       # expect(notFoundHandler).toHaveBeenCalled()
       # expect(notFoundHandler.calls.length).toEqual(1)

+  describe "silent", ->
+    it 'shuold call show and not change location', ->
+      spyOn(controller, 'show')
+      router.silent = true
+      expect(window.location.pathname).toEqual "/"
+      router.change('/posts/1')
+      expect(controller.show).toHaveBeenCalled()
+      expect(window.location.pathname).toEqual "/"
+      router.silent = false
+      router.change('/posts/2')
+      expect(window.location.pathname).toEqual "/posts/2"


Rename Tile's makeXML -> makeDOM and xml -> dom

--- src/svgtiler.coffee
+++ src/svgtiler.coffee
@@ -243,9 +243,9 @@
     else
       viewBox

-isAuto = (xml, prop) ->
-  xml.documentElement.hasAttribute(prop) and
-  /^\s*auto\s*$/i.test xml.documentElement.getAttribute prop
+isAuto = (dom, prop) ->
+  dom.documentElement.hasAttribute(prop) and
+  /^\s*auto\s*$/i.test dom.documentElement.getAttribute prop

 attributeOrStyle = (node, attr, styleKey = attr) ->
   if value = node.getAttribute attr
@@ -431,9 +431,9 @@
     @svg = removeSVGComments @svg

   setId: (@id) ->
-    @xml.documentElement.setAttribute 'id', @id if @xml?
-  makeXML: ->
-    return @xml if @xml?
+    @dom.documentElement.setAttribute 'id', @id if @dom?
+  makeDOM: ->
+    return @dom if @dom?
     @makeSVG()
     ## Force SVG namespace when parsing, so nodes have correct namespaceURI.
     ## (This is especially important on the browser, so the results can be
@@ -444,7 +444,7 @@
           match = match[...match.length-end.length] +
             " xmlns='#{SVGNS}'" + match[match.length-end.length..]
         match
-    @xml = new DOMParser
+    @dom = new DOMParser
       locator:  ## needed when specifying errorHandler
         line: 1
         col: 1
@@ -461,30 +461,30 @@
     ## Remove from the symbol any top-level xmlns=SVGNS or xmlns:xlink,
     ## in the original parsed content or possibly added above,
     ## to avoid conflict with these attributes in the top-level <svg>.
-    @xml.documentElement.removeAttribute 'xmlns'
+    @dom.documentElement.removeAttribute 'xmlns'
     unless @getSetting 'useHref'
-      @xml.documentElement.removeAttribute 'xmlns:xlink'
+      @dom.documentElement.removeAttribute 'xmlns:xlink'

     ## Wrap XML in <symbol> if not already.
-    symbol = @xml.createElementNS SVGNS, 'symbol'
+    symbol = @dom.createElementNS SVGNS, 'symbol'
     ## Force `id` to be first attribute.
     symbol.setAttribute 'id', @id if @id?
     # Avoid a layer of indirection for <symbol>/<svg> at top level
-    if @xml.documentElement.nodeName in ['symbol', 'svg'] and
-       not @xml.documentElement.nextSibling?
-      for attribute in @xml.documentElement.attributes
+    if @dom.documentElement.nodeName in ['symbol', 'svg'] and
+       not @dom.documentElement.nextSibling?
+      for attribute in @dom.documentElement.attributes
         unless attribute.name in ['version', 'id'] or attribute.name.startsWith 'xmlns'
           symbol.setAttribute attribute.name, attribute.value
-      doc = @xml.documentElement
-      @xml.removeChild @xml.documentElement
+      doc = @dom.documentElement
+      @dom.removeChild @dom.documentElement
     else
-      doc = @xml
+      doc = @dom
     for child in (node for node in doc.childNodes)
       symbol.appendChild child
-    @xml.appendChild symbol
+    @dom.appendChild symbol

     ## <image> processing
-    domRecurse @xml.documentElement, (node) =>
+    domRecurse @dom.documentElement, (node) =>
       if node.nodeName == 'image'
         ###
         Fix image-rendering: if unspecified, or if specified as "optimizeSpeed"
@@ -549,12 +549,12 @@
         true

     ## Compute viewBox attribute if absent.
-    @viewBox = svgBBox @xml
+    @viewBox = svgBBox @dom

     ## Overflow behavior
-    overflow = attributeOrStyle @xml.documentElement, 'overflow'
+    overflow = attributeOrStyle @dom.documentElement, 'overflow'
     if not overflow? and (overflowDefault = @getSetting 'overflowDefault')?
-      @xml.documentElement.setAttribute 'overflow',
+      @dom.documentElement.setAttribute 'overflow',
         overflow = overflowDefault
     @overflowVisible = (overflow? and /^\s*(visible|scroll)\b/.test overflow)
     @width = @height = null
@@ -573,8 +573,8 @@
           @viewBox[3] = zeroSizeReplacement
       ## Reset viewBox attribute in case either absent (and computed via
       ## svgBBox) or changed to avoid zeroes.
-      @xml.documentElement.setAttribute 'viewBox', @viewBox.join ' '
-    @overflowBox = extractOverflowBox @xml
+      @dom.documentElement.setAttribute 'viewBox', @viewBox.join ' '
+    @overflowBox = extractOverflowBox @dom
     @width = forceWidth if (forceWidth = @getSetting 'forceWidth')?
     @height = forceHeight if (forceHeight = @getSetting 'forceHeight')?
     warnings = []
@@ -588,22 +588,22 @@
       console.warn "Failed to detect #{warnings.join ' and '} of SVG for tile '#{@key}'"
     ## Detect special `width="auto"` and/or `height="auto"` fields for future
     ## processing, and remove them to ensure valid SVG.
-    @autoWidth = isAuto @xml, 'width'
-    @autoHeight = isAuto @xml, 'height'
-    @xml.documentElement.removeAttribute 'width' if @autoWidth
-    @xml.documentElement.removeAttribute 'height' if @autoHeight
-    @zIndex = extractZIndex @xml.documentElement
+    @autoWidth = isAuto @dom, 'width'
+    @autoHeight = isAuto @dom, 'height'
+    @dom.documentElement.removeAttribute 'width' if @autoWidth
+    @dom.documentElement.removeAttribute 'height' if @autoHeight
+    @zIndex = extractZIndex @dom.documentElement
     ## Optionally extract <text> nodes for LaTeX output
     if @getSetting 'texText'
       @text = []
-      domRecurse @xml.documentElement, (node, parent) =>
+      domRecurse @dom.documentElement, (node, parent) =>
         if node.nodeName == 'text'
           @text.push node
           parent.removeChild node
           false # don't recurse into <text>'s children
         else
           true
-    @xml
+    @dom

 ## Tile to fall back to when encountering an unrecognized key.
 ## Path from https://commons.wikimedia.org/wiki/File:Replacement_character.svg
@@ -1116,7 +1116,7 @@
           ## Include new <symbol> in SVG
           unless found?
             tile.setId @id key unless tile.id?  # unrecognizedTile has id
-            svg.appendChild tile.makeXML().documentElement
+            svg.appendChild tile.makeDOM().documentElement
             if symbolIds.has tile.id
               console.warn "Multiple symbols with id '#{tile.id}': This shouldn't happen, and SVG likely won't load correctly."
             else


Skipped Html5 Parser

Skipped Html5 Parser

--- test/test-html5-parser.coffee
+++ test/test-html5-parser.coffee
@@ -5,7 +5,7 @@

 fs = require 'fs'

-describe 'Html5 Parser', ->
+describe.skip 'Html5 Parser', ->

   it 'Work in progress', ->


tasks/concat.coffee removed

tasks/concat.coffee removed

--- tasks/concat.coffee
+++ tasks/concat.coffee
@@ -1,24 +0,0 @@
-_ = require "underscore"
-
-module.exports = (grunt) ->
-
-    grunt.registerMultiTask "concatFiles", "files concatination", ->
-
-        content = ""
-        errors = []
-
-        for file in @.data.src
-            try
-                fileContent = grunt.file.read file
-                content += fileContent
-            catch err
-                errors.push err
-                if err.origError.code == "ENOENT"
-                    console.warn "NO FILE FOUND:::", file
-                else
-                    console.warn "Error in concatFiles task"
-
-        if !errors.length
-            grunt.file.write @.data.dest, content
-
-        grunt.log.ok "OK"


removed now useless options (set those in css)

--- plugins/overlay.coffee
+++ plugins/overlay.coffee
@@ -22,8 +22,6 @@
             editable: null
             toolbar: null
             uuid: ""
-            opacity: 0.5
-            backgroundColor: '#000000'

             # The pieces of the overlay are re-positioned when the editable is modified. This value defines
             # the minimal interval between two repositioning to avoid performance issues


Update on user change

Update on user change

--- app/pages/admin/user-settings.cjsx
+++ app/pages/admin/user-settings.cjsx
@@ -16,8 +16,15 @@
   getDefaultProps: ->
     editUser: null

+  componentDidMount: ->
+    @_boundForceUpdate ?= @forceUpdate.bind this
+    @props.editUser?.listen 'change', @_boundForceUpdate
+
+  componentWillReceiveProps: (nextProps) ->
+    @props.editUser?.stopListening 'change', @_boundForceUpdate
+    nextProps.editUser.listen 'change', @_boundForceUpdate
   render: ->
-    if @props.editUser
+    if @props.editUser?

Settings for { @props.editUser.login }


Fix for latexindent v3

Fix for latexindent v3

--- src/beautifiers/latex-beautify.coffee
+++ src/beautifiers/latex-beautify.coffee
@@ -59,11 +59,11 @@
     .then((dirPath)=>
       @setUpDir(dirPath, text, @buildConfigFile(options))
       run = @run "latexindent", [
-        "-o"            #Output to the same location as file, -w creates a backup file, whereas this does not
         "-s"            #Silent mode
         "-l"            #Tell latexindent we have a local configuration file
         "-c=" + dirPath #Tell latexindent to place the log file in this directory
         @texFile
+        "-o"            #Output to the same location as file, -w creates a backup file, whereas this does not
         @texFile
       ], help: {
         link: "https://github.com/cmhughes/latexindent.pl"


added test

added test

--- test/unit/wd-sync-test.coffee
+++ test/unit/wd-sync-test.coffee
@@ -18,7 +18,8 @@
       @quit()
       done()

-describe "wd-async", ->
+describe "wd-sync", ->
+
   describe "passing browser", ->
     for browserName in [undefined,'firefox','chrome']
       testWithBrowser browserName
@@ -42,3 +43,22 @@
         @title().toLowerCase().should.include 'hello world'
         @quit()
         done()
+
+  describe 'wd.current()', ->
+    it "browsing", (done) ->
+      browser = wd.remote(mode:'sync')
+
+      myOwnTitle = ->
+        wd.current().title()
+
+      Wd with:browser, ->
+        if browserName? then @init browserName: "#{browserName}"
+        else @init()
+
+        @get "http://google.com"
+        myOwnTitle().toLowerCase().should.include 'google'
+
+        @quit()
+        done()
+
+


Seleciona dimensão em "combo" corretamente

--- src/coffee/portal-sku-selector.coffee
+++ src/coffee/portal-sku-selector.coffee
@@ -220,7 +220,7 @@

 	selectDimensionValue: (dimensionName, valueName) =>
 		@finditemDimensionValueInput(dimensionName, valueName).prop('checked', true).trigger('change')
-		@finditemDimensionOption(dimensionName).val(valueName).trigger('change')
+		@finditemDimensionSelect(dimensionName).val(valueName).trigger('change')

 	findSelectionStatus: (selection) =>
 		foundUnavailable = false
@@ -408,6 +408,7 @@
 	modalLayout: false
 	warnUnavailable: false
 	selectOnOpening: false
+	selectSingleDimensionsOnOpening: true
 	confirmBuy: false
 	showPriceRange: false
 	forceInputType: null


add delay to slices offset

add delay to slices offset

--- src/coffee/scenes/PizzaTunnel2.coffee
+++ src/coffee/scenes/PizzaTunnel2.coffee
@@ -24,13 +24,13 @@
 		for i in [0...@pizzas.length]
 			pizza = @pizzas[i]
 			pizza.position.z += 4
-			pizza.rotation.z -= .03
+			pizza.rotation.z += .03
 			if pizza.position.z > 300
 				pizza.position.z = -@pizzas.length * 100 + 300
 			for j in [0...8]
 				slice = pizza.slices[j]
 				angle = -j * (Math.PI / 4)
-				ratio = Math.pow(Math.max(pizza.position.z, 0) / 300, 4)
+				ratio = Math.pow(Math.max(pizza.position.z - j * 10, 0) / 300, 4)
 				slice.position.x = -Math.cos(angle) * (100 + 1000 * ratio)
 				slice.position.y = Math.sin(angle) * (100 + 1000 * ratio)


Need initiaize body

Need initiaize body

--- src/coffee/services/electronPF.coffee
+++ src/coffee/services/electronPF.coffee
@@ -124,6 +124,7 @@
     createNotification: (options) =>
       # options.icon = options.icon or options.iconUrl
       # options.icon = __dirname + "/.." + options.icon
+      options.body = ""
       for item in options.items
         options.body += "\n#{item.title}: #{item.message}"
       @_notification = new Notification(options.title, options)


Corrige bug quando tem dois totalizers

Corrige bug quando tem dois totalizers

--- src/coffee/portal-minicart.coffee
+++ src/coffee/portal-minicart.coffee
@@ -147,9 +147,13 @@
 # Plugin
 #
 $.fn.minicart = (options) ->
-	return this if @hasClass("plugin_minicart")
-	@addClass("plugin_minicart")
-	new Minicart(this, options)
+	for element in this
+		$element = $(element)
+		unless $element.hasClass("plugin_minicart")
+			$element.addClass("plugin_minicart")
+			new Minicart($element, options)
+
+	# Chaining
 	return this

 $.fn.minicart.defaults =


Update Atom telemetry setting

Update Atom telemetry setting

--- atom/config.cson
+++ atom/config.cson
@@ -12,6 +12,7 @@
     audioBeep: false
     destroyEmptyPanes: false
     projectHome: "/Users/randy/src"
+    telemetryConsent: "limited"
     themes: [
       "one-light-ui"
       "one-light-syntax"


random commit

random commit

--- atom/config.cson
+++ atom/config.cson
@@ -21,6 +21,7 @@
     ignoreErrorsAndWarnings: "D203,D212,D213,D404,D211,D100,D101"
   "linter-ui-default":
     hidePanelWhenEmpty: true
+    panelHeight: 69
     showPanel: true
   "markdown-writer":
     fileExtension: ".md"
@@ -30,6 +31,8 @@
     prettierOptions:
       singleQuote: true
     useEslint: true
+  "proto-repl":
+    enableCompletions: false
   "tree-view":
     hideIgnoredNames: true
     hideVcsIgnoredFiles: false


Autocomplete settings

Autocomplete settings

--- atom/config.cson
+++ atom/config.cson
@@ -16,3 +16,6 @@
   'showOnStartup': false
 'metrics':
   'userId': '8a91815e1f7f47cd08a90e7683fc5eb0f2799620'
+'scroll-past-end': {}
+'autocomplete-plus':
+  'autoActivationDelay': 0


Fix escape key in vim-mode

Fix escape key in vim-mode

Allow the Escape key to continue to dismiss autocomplete popups rather
than exiting vim insert-mode.

The previous “fix” (of using `unset!`) stopped the escape key from
closing the popups altogether.

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -31,4 +31,6 @@

 'atom-text-editor.vim-mode.insert-mode':
   'j k': 'vim-mode:activate-normal-mode'
-  'escape': 'unset!'
+
+'atom-text-editor.vim-mode.autocomplete-active':
+  'escape': 'autocomplete-plus:cancel'


fix(atom): custom keymap now overrides defaults properly

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -1,9 +1,6 @@
-# Keybindings for a Windows keyboard on Yosemite
-'body':
-  'cmd-up': 'core:move-up'
-  'cmd-down': 'core:move-down'
+# Keybindings for a Windows keyboard on Mac
+'atom-workspace atom-text-editor:not([mini])':
   'cmd-shift-up': 'editor:add-selection-above'
   'cmd-shift-down': 'editor:add-selection-below'
-  'cmd-alt-up': 'editor:move-line-up'
-  'cmd-alt-down': 'editor:move-line-down'
-
+  'cmd-ctrl-up': 'editor:move-line-up'
+  'cmd-ctrl-down': 'editor:move-line-down'


addhistory : scroll repaired

addhistory : scroll repaired

--- app/views/CNeditor/CNeditor.coffee
+++ app/views/CNeditor/CNeditor.coffee
@@ -2650,8 +2650,8 @@
         @_history.historySelect.push savedSel
         # save scrollbar position
         savedScroll =
-            xcoord: @editorBody$.scrollTop()
-            ycoord: @editorBody$.scrollLeft()
+            xcoord: @linesDiv.scrollTop
+            ycoord: @linesDiv.scrollLeft
         @_history.historyScroll.push savedScroll
         # save newPosition flag
         @_history.historyPos.push @newPosition
@@ -2700,10 +2700,9 @@
             savedSel = @_history.historySelect[@_history.index]
             rangy.deserializeSelection savedSel, @linesDiv
             # 2 - restore scrollbar position
-            xcoord = @_history.historyScroll[@_history.index].xcoord
-            ycoord = @_history.historyScroll[@_history.index].ycoord
-            @editorBody$.scrollTop(xcoord)
-            @editorBody$.scrollLeft(ycoord)
+            savedScroll = @_history.historyScroll[@_history.index]
+            @linesDiv.scrollTop = savedScroll.xcoord
+            @linesDiv.scrollLeft = savedScroll.ycoord
             # 3 - restore the lines structure
             @_readHtml()
             # 4 - update the index
@@ -2729,8 +2728,8 @@
             # 3 - restore scrollbar position
             xcoord = @_history.historyScroll[@_history.index+1].xcoord
             ycoord = @_history.historyScroll[@_history.index+1].ycoord
-            @editorBody$.scrollTop(xcoord)
-            @editorBody$.scrollLeft(ycoord)
+            @linesDiv.scrollTop = xcoord
+            @linesDiv.scrollLeft = ycoord
             # 4 - restore lines structure
             @_readHtml()


Less turret quotes

Less turret quotes

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -36,9 +36,9 @@
   leaveReplies = ['Are you still there?', 'Target lost', 'Searching']

   robot.enter (msg) ->
-    msg.send msg.random enterReplies
+    msg.send msg.random enterReplies if Math.random <= 0.1
   robot.leave (msg) ->
-    msg.send msg.random leaveReplies
+    msg.send msg.random leaveReplies if Math.random <= 0.1
   #
   # answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
   #


Authentication packet now correctly exposes its opcode name

--- src/wrathnet/expansions/wotlk/net/auth-packet.coffee
+++ src/wrathnet/expansions/wotlk/net/auth-packet.coffee
@@ -12,8 +12,16 @@
 # Denotes an authentication packet
 class WrathNet.expansions.wotlk.net.AuthPacket extends WrathNet.net.Packet

+  # Imports
+  AuthOpcode = WrathNet.expansions.wotlk.enums.AuthOpcode
+  ObjectUtil = WrathNet.utils.ObjectUtil
+
   # Header size in bytes for both incoming and outgoing packets
   @HEADER_SIZE = 1
+
+  # Retrieves the name of the opcode for this packet (if available)
+  @getter 'opcodeName', ->
+    return ObjectUtil.keyByValue(AuthOpcode, @opcode)

   # Finalizes this packet
   finalize: ->


Update HoC tracking pixel identifier

Update HoC tracking pixel identifier

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -123,7 +123,7 @@
       me.patch()
       pixelCode = switch @terrain
         when 'game-dev-hoc' then 'code_combat_gamedev'
-        when 'game-dev-hoc-2' then 'code_combat_gamedev2'
+        when 'game-dev-hoc-2' then 'code_combat_build_arcade'
         else 'code_combat'
       $('body').append($("<img src='https://code.org/api/hour/begin_#{pixelCode}.png' style='visibility: hidden;'>"))
     else if me.isTeacher() and not utils.getQueryVariable('course-instance') and not application.getHocCampaign()


Changed tooltip initialiser class name to ".has-tooltip", so it doesn't conflict with Bootstrap's ".tooltip" class.

--- app/assets/javascripts/bootstrap.js.coffee
+++ app/assets/javascripts/bootstrap.js.coffee
@@ -1,4 +1,3 @@
 jQuery ->
   $("a[rel~=popover]").popover()
-  $(".tooltip").tooltip()
-  $("a[rel~=tooltip]").tooltip()
+  $("a[rel~=tooltip], .tip").tooltip()


Prevent Add Column and Add Record from adding more than 1.

--- app/assets/javascripts/databases.js.coffee
+++ app/assets/javascripts/databases.js.coffee
@@ -171,12 +171,14 @@
   enableTableOps()

 enableTableOps = () ->
+  $('form.add-record').off 'submit'
   $('form.add-record').on 'submit', (e) ->
     e.preventDefault()
     $.post '/records', {table_id: $('.database .tables .table').data('id')}, (data, textStatus, jqXHR) ->
       add_new_record_to_table(data['id'])
     , 'json'

+  $('form.add-column').off 'submit'
   $('form.add-column').on 'submit', (e) ->
     e.preventDefault()
     num_columns = $('table.data-table thead tr th:not(.actions)').length


Add hooks for conversions and derivations in addition to associations.

--- app/assets/javascripts/slickbone.js.coffee
+++ app/assets/javascripts/slickbone.js.coffee
@@ -59,6 +59,8 @@
     @derivations  = []

     @setupAssociations()
+    @setupConversions()
+    @setupDerivations()

     # we NEED this so that Backbone.js is happy.
     super
@@ -73,6 +75,8 @@
     @associations[name] = { model: model, associationType: type }

   setupAssociations: ->
+  setupConversions:  ->
+  setupDerivations:  ->

   # indicates that a given attribute is actually a Collection. Adds the correct settings to
   # the association hash.