fix error in ZipManager writesEnabled setting

--- services/document-updater/app/coffee/ZipManager.coffee
+++ services/document-updater/app/coffee/ZipManager.coffee
@@ -3,7 +3,7 @@
 metrics = require('./Metrics')
 zlib = require('zlib')

-ZIP_WRITES_ENABLED = Settings.redis.zip?.writesEnabled?
+ZIP_WRITES_ENABLED = Settings.redis.zip?.writesEnabled
 ZIP_MINSIZE = Settings.redis.zip?.minSize || 64*1024

 module.exports = ZipManager =


Add invalid rows of tokenized buffer to error metadata

This will tell us if we’re in the middle of async tokenization, which
could be interesting

Signed-off-by: Antonio Scandurra <0e17b4d558b07b12cd221e35c438be378ba118cf@github.com>

--- src/display-layer.coffee
+++ src/display-layer.coffee
@@ -899,7 +899,8 @@
             foldCount: @foldsMarkerLayer.getMarkerCount(),
             atomicSoftTabs: @atomicSoftTabs,
             tokenizedBufferEventId: @textDecorationLayer.lastBufferChangeEventId,
-            displayLayerEventId: @lastBufferChangeEventId
+            displayLayerEventId: @lastBufferChangeEventId,
+            tokenizedBufferInvalidRows: @textDecorationLayer.invalidRows
           }
           throw error


Hide map from tabindex hierarchy

Hide map from tabindex hierarchy

--- src/map-view.coffee
+++ src/map-view.coffee
@@ -497,6 +497,7 @@

             @previousZoomlevel = @map.getZoom()
             @drawInitialState()
+            @$el.attr('tabindex', '-1') # Remove from tabindex hierarchy

         _removeBboxMarkers: (zoom, zoomLimit) ->
             unless @markers?


:fire: Remove keymaps

:fire: Remove keymaps

--- keymaps/linter.cson
+++ keymaps/linter.cson
@@ -1,2 +0,0 @@
-'atom-text-editor:not(.mini)':
-  'alt->': 'linter:next-error'


Safety

Safety

--- src/projects.coffee
+++ src/projects.coffee
@@ -30,6 +30,8 @@
     return
   # Open main graph, or the first graph
   main = project.main or project.graphs[0].properties.id
+  unless main
+    return callback new Error "Unable find a main graph for project #{project.id}"
   callback null, [
     'project'
     project.id


Because contexts have scale, we can use that property for clarity


Renamed "float" and "boolean" Model attribute types to "real" and "bool" to avoid conflicts.

--- lib/ST/Model.coffee
+++ lib/ST/Model.coffee
@@ -313,10 +313,12 @@
       newValue = switch details.type
         when 'string'
           String rawValue
-        when 'float'
+        when 'real'
           Number rawValue
         when 'integer'
           Math.round Number(rawValue)
+        when 'bool'
+          !!rawValue
         when 'datetime'
           date = new Date(rawValue)
           if isNaN(date.getTime()) then null else date
@@ -356,8 +358,8 @@
   # In the following methods, “def” stands for “default”
   @classMethod 'string', (name, def) -> @attribute name, 'string', def
   @classMethod 'integer', (name, def) -> @attribute name, 'integer', def
-  @classMethod 'float', (name, def) -> @attribute name, 'float', def
-  @classMethod 'boolean', (name, def) -> @attribute name, 'boolean', def
+  @classMethod 'real', (name, def) -> @attribute name, 'real', def
+  @classMethod 'bool', (name, def) -> @attribute name, 'bool', def
   @classMethod 'datetime', (name, def) -> @attribute name, 'datetime', def
   @classMethod 'enum', (name, def, values) ->
     @attribute name, 'enum', def


List the questions and the default values.

--- src/reporter.coffee
+++ src/reporter.coffee
@@ -6,6 +6,21 @@

 module.exports = Reports = (@options = { directory: DEFAULT_FOLDER }) ->
 (->
+  # Public: The list of questions and their default values.
+  #
+  # Returns an array containing the questions and eventually the default values.
+  @questions = ->
+    return @_questions if @_questions?
+
+    @_questions = null
+    files = fs.readdirSync @options.directory
+    if files.length
+      file = path.join(@options.directory, files[0])
+      @_questions = JSON.parse(fs.readFileSync(file)).questions
+
+    @_questions
+
+
   # Public: Retrieve reports
   #
   # options - The Hash options to filter the results by (default: {}):


fixes #2830 - dsiallow registration of users on a decativated organization

--- server/entry.coffee
+++ server/entry.coffee
@@ -44,7 +44,7 @@
       check email, String
       domain = email.split("@")[1]
       org = Organizations.findOne({domain: domain})
-      unless org
+      unless org and org.deactivated != true
         return false
       return true


Added :x command

Added :x command

--- lib/commands.coffee
+++ lib/commands.coffee
@@ -15,6 +15,10 @@
   atom.workspace.closeActivePaneItemOrEmptyPaneOrWindow()

 wq = ->
+  w()
+  q()
+
+x = ->
   w()
   q()

@@ -71,6 +75,7 @@
   normalCommands: {
     w
     wq
+    x
     wall
     wqall
     q


Fixes #655

Fixes #655

--- lib/git-plus.coffee
+++ lib/git-plus.coffee
@@ -90,12 +90,12 @@
   gp.activate?()
   gp.consumeStatusBar?(gp.statusBar) if gp.statusBar

+getWorkspaceNode = -> document.querySelector('atom-workspace')
+
 module.exports =
   config: configurations

   subscriptions: null
-
-  workspace: document.querySelector('atom-workspace')

   provideService: -> require './service'

@@ -193,7 +193,7 @@
   autoFetch: (interval) ->
     clearInterval @autoFetchInterval
     if fetchIntervalMs = (interval * 60) * 1000
-      fetch = => atom.commands.dispatch(@workspace, 'git-plus:fetch-all')
+      fetch = => atom.commands.dispatch(getWorkspaceNode(), 'git-plus:fetch-all')
       @autoFetchInterval = setInterval(fetch, fetchIntervalMs)

   consumeAutosave: ({dontSaveIf}) ->
@@ -218,13 +218,13 @@
     @statusBarTile = statusBar.addRightTile item: div, priority: 0

   setupBranchesMenuToggle: (statusBar) ->
-    statusBar.getRightTiles().some ({item}) =>
+    statusBar.getRightTiles().some ({item}) ->
       if item?.classList?.contains? 'git-view'
-        $(item).find('.git-branch').on 'click', (e) =>
+        $(item).find('.git-branch').on 'click', (e) ->
           {newBranchKey} = atom.config.get('git-plus.general')
           pressed = (key) -> e["#{key}Key"]
           if pressed newBranchKey
-            atom.commands.dispatch(@workspace, 'git-plus:new-branch')
+            atom.commands.dispatch(getWorkspaceNode(), 'git-plus:new-branch')
           else
-            atom.commands.dispatch(@workspace, 'git-plus:checkout')
+            atom.commands.dispatch(getWorkspaceNode(), 'git-plus:checkout')
         return true


Fixes

Fixes

--- src/sys/ajax.coffee
+++ src/sys/ajax.coffee
@@ -8,16 +8,19 @@
     catch
   throw Error 'AJAX not supported!'

-ajax.get = (url)->
+ajax.get = (url, asBody)->
   z = do ajax
   z.open 'GET', url, false
   z.send null
   if 200 != z.status
     throw Error "HTTP error #{z.status}: #{z.statusText}"
-  z.responseText
+  if asBody
+    z.responseBody
+  else
+    z.responseText

 ajax.dl = (url, path)->
-  data = get url
+  data = ajax.get url, true
   stream = new ActiveXObject "adodb.stream"
   stream.Type = 1           # adTypeBinary
   stream.Open()


use generic userdata instead of view

use generic userdata instead of view

--- src/template.coffee
+++ src/template.coffee
@@ -31,8 +31,8 @@
     constructor: (opts = {}, template) ->
         # options
         [template, opts] = [opts, {}] if typeof opts is 'function'
-        view = opts.view
-        opts.view = null # prevent infinite recursion
+        userdata = opts.userdata
+        opts.userdata = null # prevent infinite recursion
         # defaults
         opts.encoding ?= 'utf-8'
         opts.doctype ?= off
@@ -55,7 +55,7 @@
         # instantiate
         @xml = new ExtendedBuilder opts
         @xml.template = this
-        @xml.view     = view
+        @xml.userdata = userdata
         # override query
         old_query = @xml.query
         @xml.query = (type, tag, key) ->


Typo fix. reset receivers

Typo fix. reset receivers

--- lib/messages.coffee
+++ lib/messages.coffee
@@ -50,6 +50,8 @@

   constructor: (receiver, content) ->
     @id = uuid()
+    @recipients = []
+
     if receiver
       @addRecipient receiver
     if content
@@ -81,7 +83,7 @@
     @recipients.push receiver unless @hasRecipient receiver

   hasRecipient: (receiver) ->
-    true if receiver in @recipients
+    return true if receiver in @recipients
     false

   setSender: (sender) ->
@@ -152,7 +154,7 @@
   @MAX_HEADER_LENGTH = 140

   contructor: (receiver, content) ->
-    super reciever, content
+    super receiver, content

   setHeader: (header) ->
     if header and header <= SMSMessage.MAX_HEADER_LENGTH


minor fix

minor fix

--- src/Create-Book-Txt.coffee
+++ src/Create-Book-Txt.coffee
@@ -16,8 +16,7 @@
   create: ()=>
     @.leanpub_Api.folder_Manuscript.folder_Create()
     book_Txt_Contents = @.build()
-    book_Txt_Contents.save_As @.leanpub_Api.file_Book
-    console.log @.leanpub_Api.file_Book.file_Exists()
+    book_Txt_Contents.save_As @.leanpub_Api.file_Book

   get_Parts: ->
     @.folder_Content.folders().file_Names()


- Proxy mode must be even more direct!

- Proxy mode must be even more direct!

--- server_setup.coffee
+++ server_setup.coffee
@@ -419,7 +419,7 @@
   return unless config.proxy
   httpProxy = require 'http-proxy'
   proxy = httpProxy.createProxyServer({
-    target: 'https://direct.codecombat.com'
+    target: 'https://very.direct.codecombat.com'
     secure: false
   })
   log.info 'Using dev proxy server'


Return the data series config list.

Return the data series config list.

--- app/javascripts/chart.coffee
+++ app/javascripts/chart.coffee
@@ -70,13 +70,12 @@

       # @param data the input resource objects
       # @param dataSpec the dataSpec described in configureChart
-      # @returns the [{key: label, values: coordinates}, ...]
-      #   nvd3 configuration
+      # @returns the [{key, values, color}] nvd3 configuration
       configureAllDataSeries = (data, dataSpec) ->
         # @param data the input resource objects
         # @param x the x-xaxis {accessor: function} object
         # @param y the y-axis  {accessor: function} object
-        # @returns the {key, values} pair
+        # @returns the {key, values, color} object
         configureADataSeries = (data, x, y) ->
           # @returns the graph [x, y] coordinates
           coordinates = (data, xAccessor, yAccessor) ->
@@ -86,8 +85,7 @@
           values: coordinates(data, x.accessor, y.accessor)
           color: y.color

-        for y in dataSpec.y.data
-         configureADataSeries(data, dataSpec.x, y)
+        (configureADataSeries(data, dataSpec.x, y) for y in dataSpec.y.data)

       # Adds padding to the give value range as follows:
       # * the the chart max is the next higher significant


Project cards are now owned cards

Project cards are now owned cards

--- app/partials/owned-card.cjsx
+++ app/partials/owned-card.cjsx
@@ -14,8 +14,8 @@
     linkTo: React.PropTypes.string.isRequired
     translationObjectName: React.PropTypes.string.isRequired

-  projectOwner: ->
-    apiClient.type(@props.project.links.owner.type).get(@props.project.links.owner.id)
+  resourceOwner: ->
+    apiClient.type(@props.resource.links.owner.type).get(@props.resource.links.owner.id)

   componentDidMount: ->
     card = @refs.ownedCard.getDOMNode()
@@ -29,7 +29,7 @@

   render: ->
     <div className="card" ref="ownedCard">
-      <PromiseRenderer promise={@projectOwner()} pending={null}>{(owner) =>
+      <PromiseRenderer promise={@resourceOwner()} pending={null}>{(owner) =>
         linkProps =
           to: @props.linkTo
           params:


Fix invalid byte

Fix invalid byte

--- app/src/dongle/dongle.coffee
+++ app/src/dongle/dongle.coffee
@@ -589,9 +589,9 @@
       ###

       PkScript = (address) =>
-        hash160WithNetwork = ledger.bitcoin.addressToHash160WithNetwork(address)
-        hash160 = hash160.bytes(1, hash160.length - 1)
-        return P2shScript(hash160) if hash160WithNetwork.byte(0) is ledger.config.network.version.P2SH
+        #hash160WithNetwork = ledger.bitcoin.addressToHash160WithNetwork(address)
+        hash160 = ledger.bitcoin.addressToHash160(address)
+        #return P2shScript(hash160) if hash160WithNetwork.byteAt(0) is ledger.config.network.version.P2SH
         script =
           OP_DUP
           .concat(OP_HASH160)


Remove useless inputs file

Remove useless inputs file

--- app/src/wallet/inputs.coffee
+++ app/src/wallet/inputs.coffee
@@ -1,8 +0,0 @@
-ledger.wallet ?= {}
-
-class ledger.wallet.Input
-
-  @inputsFromUnspentsOutputs: (unspentOutputs, callback) ->
-    addresses = (address for address in unspentOutput.addresses for unspentOutput in unspentOutputs)
-    l addresses
-


disable smoothscrolling on mac

disable smoothscrolling on mac

--- app/views/application.coffee
+++ app/views/application.coffee
@@ -4,13 +4,18 @@

   # Init smooth scroll effect on scroll
   initSimplrSmoothScroll: ( ->
-    $.srSmoothscroll({
-      step: 100,
-      speed: 100,
-      ease: 'swing',
-      target: $('body'),
-      container: $(window)
-      })
+    platform = navigator.platform.toLowerCase()
+    userAgent = navigator.userAgent.toLowerCase()
+
+    # Only enable simplr-smoothscroll for webkit browsers on windows and linux
+    if (platform.indexOf('win') == 0 || platform.indexOf('linux') == 0) && (userAgent.indexOf('webkit') != -1)
+      $.srSmoothscroll(
+        step: 100,
+        speed: 100,
+        ease: 'swing',
+        target: $('body'),
+        container: $(window)
+      )
   ).on('didInsertElement')

 `export default ApplicationView;`


Fix borders in Chrome

Fix borders in Chrome

Fixes https://github.com/motif/company/issues/4927


disable modulation of colors for the time being

--- framer/Utils.coffee
+++ framer/Utils.coffee
@@ -369,10 +369,10 @@
 	[toLow, toHigh] = rangeB

 	# if rangeB consists of Colors we return a color tween
-	if Color.isColor(toLow) || _.isString(toLow) && Color.isColorString(toLow)
-		ratio = Utils.modulate(value, rangeA, [0, 1])
-		result = Color.mix(toLow, toHigh, ratio)
-		return result
+	# if Color.isColor(toLow) || _.isString(toLow) && Color.isColorString(toLow)
+	# 	ratio = Utils.modulate(value, rangeA, [0, 1])
+	# 	result = Color.mix(toLow, toHigh, ratio)
+	# 	return result

 	result = toLow + (((value - fromLow) / (fromHigh - fromLow)) * (toHigh - toLow))


improved naming of parents to ancestors

improved naming of parents to ancestors

--- framer/Utils.coffee
+++ framer/Utils.coffee
@@ -754,25 +754,25 @@
 # convert a point from a layer to the context level, with limit you can make it continue to the root context
 Utils.convertPointToContext = (point = {}, layer, limit=false) ->
 	point = _.defaults(point, {x:0, y:0, z:0})
-	parents = layer.ancestors(limit)
-	parents.unshift(layer)
-
-	for parent in parents
-		point.z = 0 if parent.flat
-		point = parent.matrix3d.point(point)
-		point.z = 0 unless parent.parent
+	ancestors = layer.ancestors(limit)
+	ancestors.unshift(layer)
+
+	for ancestor in ancestors
+		point.z = 0 if ancestor.flat
+		point = ancestor.matrix3d.point(point)
+		point.z = 0 unless ancestor.parent

 	return point

 # convert a point from the context level to a layer, with limit you can make it start from the root context
 Utils.convertPointFromContext = (point = {}, layer, limit=false, includeLayer = true) ->
 	point = _.defaults(point, {x:0, y:0, z:0})
-	parents = layer.ancestors(limit)
-	point = parents.pop().matrix3d.inverse().point(point) if parents.length
-	parents.reverse()
-	parents.push(layer) if includeLayer
-	for parent in parents
-		point = parent.matrix3d.inverse().point(point)
+	ancestors = layer.ancestors(limit)
+	point = ancestors.pop().matrix3d.inverse().point(point) if ancestors.length
+	ancestors.reverse()
+	ancestors.push(layer) if includeLayer
+	for ancestor in ancestors
+		point = ancestor.matrix3d.inverse().point(point)
 	return point

 # convert a frame from the context level to a layer, with limit you can make it start from the root context


update parsing method for Styles

update parsing method for Styles

--- src/client/style/sandbox.coffee
+++ src/client/style/sandbox.coffee
@@ -5,9 +5,12 @@

 StyleMap = [];
 MergedStyles   = null;
-BufferedStyles = null;
+Buffer = "";

-rewriteCSSURLs = require('css-url-rewriter')
+# replaceRule = (sheet, selector, cssText, index)->
+#     if sheet.removeRule then sheet.removeRule(index) else sheet.deleteRule(index);
+#     rule = if selector then selector + '{' + cssText + '}' else cssText
+#     if sheet.addRule then sheet.addRule(selector, cssText, index) else sheet.insertRule(rule, index);

 createStyleSheet = (content="", disabled=false)->
   style = document.createElement('style')
@@ -17,10 +20,10 @@
   document.head.appendChild(style)
   style

-removeStyleSheet = (style)->
-  style.parentNode?.removeChild(style)
+removeStyleSheet = (style)-> style.parentNode?.removeChild(style)

 getRules = (sheet)->
+  return unless sheet?
   sheet.cssRules || sheet.rules

 empty = (sheet)->
@@ -33,15 +36,33 @@
   new Promise (resolve, reject)->
     superagent.get(href).end (err, res)-> resolve(res.text)

-replaceRule = (sheet, selector, cssText, index)->
-    if sheet.removeRule then sheet.removeRule(index) else sheet.deleteRule(index);
-    rule = if selector then selector + '{' + cssText + '}' else cssText
-    if sheet.addRule then sheet.addRule(selector, cssText, index) else sheet.insertRule(rule, index);
+appendStyle = (prefix, node, uri=window.location.href)->
+  rules = getRules(node.sheet)
+  if rules
+    appendRules(prefix, rules) if rules
+  else if !!node.href
+    # Loading External stylesheets (out of current domain)
+    # Only Chrome will use this, since we have tweaked the Polyfill to avoid 2 requests.
+    href = node.href
+    uri = getUriFromHref(node.href || uri)
+    node.parentNode.removeChild(node)
+    fetch(href).then (text)->
+      style = createStyleSheet(replaceLinkTagUrls(uri, text), true)
+      rules = getRules(style.sheet)
+      appendRules(prefix, rules)
+      removeStyleSheet(style)
+      true

-urlMatcher = /url\(\s*['"]?([^)'"]+)['"]?\s*\)/g;
+replaceLinkTagUrls = (uri, text)->
+  re = new RegExp "url\\(['\"]?([^)]*?)['\"]?\\)", "g"
+  text.replace(re, "url('#{uri}$1')")

-prefixRule = (prefix, sheet, rule, index)->
-  return unless rule and sheet
+appendRules = (prefix, rules)->
+  _.map rules, (rule)-> Buffer += prefixRule(prefix, rule);
+  true
+
+prefixRule = (prefix, rule)->
+  return unless rule
   if rule.selectorText
     # Manipulate insert Prefix here.
     selectorText = rule.selectorText?.split(',').map (r)->
@@ -49,38 +70,13 @@
       r = r.replace(':host', prefix)
       if r.indexOf(prefix)>-1 then r else "#{prefix} #{r}"
     .join(', ')
-    "#{selectorText} {#{rule.style.cssText}}"
+    return "#{selectorText} {#{rule.style.cssText}} "
   else
     subSheet = rule.cssRules || rule.rules
-    if subSheet
-      prefixRule(prefix, rule, subRule, j) for subRule, j in subSheet
-    rule.cssText
-
-appendStyle = (prefix, sheet, uri=window.location.href)->
-  uri = getUriFromHref(sheet.href || uri)
-  if !!sheet.href and !(sheet.cssRules || sheet.rules)
-    # Loading External stylesheets (out of current domain)
-    href = sheet.href
-    sheet.ownerNode.parentNode.removeChild(sheet.ownerNode)
-    fetch(href).then (text)->
-      console.log "Loaded", href
-      style = createStyleSheet(replaceLinkTagUrls(uri, text), true)
-      appendRules sheet.cssRules, uri
-      removeStyleSheet(style)
-      true
-  else
-    rules = sheet.cssRules || sheet.rules
-    appendRules(rules, uri)
-
-replaceLinkTagUrls = (uri, text)->
-  re = new RegExp "url\\(['\"]?([^)]*?)['\"]?\\)", "g"
-  text.replace(re, "url('#{uri}$1')")
-
-appendRules = (rules, uri)->
-  _.map _.toArray(rules).reverse(), (rule)->
-    cssText = rule.cssText
-    BufferedStyles.sheet.insertRule(rule.cssText, 0)
-  true
+    return rule.cssText unless subSheet
+    content = (prefixRule(prefix, subRule) for subRule, j in subSheet)
+    query = rule.cssText.split('{');
+    return "#{query[0]} {#{content.join(' ')}} "

 getUriFromHref = (href)->
   uri = href.split('/')
@@ -88,7 +84,9 @@
   uri.join('/')+'/'

 addLink = (prefix, node)->
-  appendStyle(prefix, node.sheet, getUriFromHref(node.href))
+  appendStyle(prefix, node, getUriFromHref(node.href))
+
+promise = new Promise (resolve, reject)-> resolve()

 ###*
  * Processes a complete document and writes a merged, prefixed stylesheet into the Main Document's HEAD.
@@ -98,45 +96,35 @@
 processDocument = (prefix, doc)->
   # Create and initialize a new global stylesheet that will receive merged styles in the right order
   MergedStyles = createStyleSheet("") unless MergedStyles
-  BufferedStyles = createStyleSheet("") unless BufferedStyles
-  BufferedStyles.disabled=true
-
   # Under Firefox, you can't change css Rules or the containing
   # style tag or those will be reset when touching anything else.
   # Resort to building an entirely new stylesheet without copying cssRules

-  # Clear the Merged Styles
-  empty(BufferedStyles.sheet)
-
   # Promise manipulation ensures stylesheets are loaded in the correct order even if they are async.
-  promise = new Promise (resolve, reject)-> resolve()
-
+  styles = doc.querySelectorAll('style,link')
   # IE doens't support inserting at any position.
   # Reverse stylesheets and insert from the end first.
-  _.map doc.styleSheets, (sheet)->
-    unless sheet.disabled
-      sheet.disabled=true
-      t = promise.then ()->
-        o = appendStyle(prefix, sheet)
-        console.log o
-        o
-      , (err)-> console.log err
-      console.log t
-      promise = t
+  _.map styles, (style)->
+    unless style.disabled
+      style.disabled=true
+      promise = promise.then ()->
+        appendStyle(prefix, style)
+      , (err)-> console.log err.message, err.stack

-  promise.then ()->
-    for rule, i in BufferedStyles.sheet.cssRules
-      cssText = prefixRule(prefix, BufferedStyles.sheet, rule, i);
-      MergedStyles.sheet.insertRule(cssText, MergedStyles.sheet.cssRules.length)
+  promise.then ()->
+    MergedStyles.textContent = "#{MergedStyles.textContent} #{Buffer}"
+    Buffer=""
     true
+  , (err)->
+    console.log 'Something failed', err, err.stack

-processStyle = (prefix, node)->
-  Array.prototype.slice.call(node.querySelectorAll('style:not([data-scoped])')).forEach (node)->
-    node.setAttribute('data-scoped',true);
-    new ScopedCss(prefix, null, node).process()
+addStyle = (prefix, node)->
+  # Array.prototype.slice.call(node.querySelectorAll('style:not([data-scoped])')).forEach (node)->
+  node.setAttribute('data-scoped',true);
+  new ScopedCss(prefix, null, node).process()

 module.exports = {
   processDocument: processDocument
-  processStyle: processStyle,
+  addStyle: addStyle,
   addLink: addLink,
 }


simplify

simplify

--- features/step_definitions/events.coffee
+++ features/step_definitions/events.coffee
@@ -29,8 +29,7 @@

   Then 'Blur event is fired', () ->
     condition = new WebElementCondition '', (driver) ->
-      driver.findElements css: '.focus'
-      .then (elements) -> elements[0]
+      driver.findElement css: '.focus'
       .then (element) -> element.isDisplayed().then (v) -> if v then null else element
     @driver.wait(condition)


Only log events when new ones are encountered

--- gitcommander.coffee
+++ gitcommander.coffee
@@ -83,7 +83,8 @@
       for channel in CHANNELS
         eventTeller[event.type] channel, event

-  console.log "* Seen #{nofEvents} new events (#{events.length} total)."
+  if nofEvents
+    console.log "* Seen #{nofEvents} new events (#{events.length} total)."

 timerCallback = ->
   for orgEntry in GIT_OPTS.orgs


Correct snippets for math environments

Correct snippets for math environments

Prefixes taken from Sublime Text Latextools.

Closes Issue 60 (https://github.com/msiniscalchi/atom-latextools/issues/60)

--- snippets/latex.cson
+++ snippets/latex.cson
@@ -29,35 +29,35 @@
   'numbered eqn':
     'prefix': 'beqn'
     'body': '\\\\begin{equation}\n$0\n\\\\end{equation}\n'
-  'gathern':
+  'gather':
     'prefix': 'bga'
     'body': '\\\\begin{gather*}\n$0\n\\\\end{gather*}\n'
-  'gather':
+  'gathern':
     'prefix': 'bgan'
     'body': '\\\\begin{gather}\n$0\n\\\\end{gather}\n'
+  'align':
+    'prefix': 'bal'
+    'body': '\\\\begin{align*}\n$0\n\\\\end{align*}\n'
   'alignn':
-    'prefix': 'bga'
-    'body': '\\\\begin{align*}\n$0\n\\\\end{align*}\n'
-  'align':
-    'prefix': 'bgan'
+    'prefix': 'baln'
     'body': '\\\\begin{align}\n$0\n\\\\end{align}\n'
+  'alignat':
+    'prefix': 'baa'
+    'body': '\\\\begin{alignat*}\n$0\n\\\\end{alignat*}\n'
   'alignatn':
-    'prefix': 'bga'
-    'body': '\\\\begin{alignat*}\n$0\n\\\\end{alignat*}\n'
-  'alignat':
-    'prefix': 'bgan'
+    'prefix': 'baan'
     'body': '\\\\begin{alignat}\n$0\n\\\\end{alignat}\n'
+  'flalign':
+    'prefix': 'bfl'
+    'body': '\\\\begin{flalign*}\n$0\n\\\\end{flalign*}\n'
   'flalignn':
-    'prefix': 'bga'
-    'body': '\\\\begin{flalign*}\n$0\n\\\\end{flalign*}\n'
-  'flalign':
-    'prefix': 'bgan'
+    'prefix': 'bfln'
     'body': '\\\\begin{flalign}\n$0\n\\\\end{flalign}\n'
+  'multiline':
+    'prefix': 'bml'
+    'body': '\\\\begin{multiline*}\n$0\n\\\\end{multiline*}\n'
   'multilinen':
-    'prefix': 'bga'
-    'body': '\\\\begin{multiline*}\n$0\n\\\\end{multiline*}\n'
-  'multiline':
-    'prefix': 'bgan'
+    'prefix': 'bmln'
     'body': '\\\\begin{multiline}\n$0\n\\\\end{multiline}\n'

   'itemize':


Accents and better brackets

Accents and better brackets

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -55,6 +55,9 @@
                 include: '#escapedCharacter'
             }
             {
+                include: '#accents'
+            }
+            {
                 include: '#documentclass'
             }
             {
@@ -142,7 +145,7 @@
                 include: '#lineComment'
             }
             {
-                include: '#openCurlyBracketMeta'
+                include: '$base'
             }
         ]
     }
@@ -224,6 +227,11 @@
         comment: 'Finds escaped characters like \$ and \%. Uses this regex so unique capture groups can be used.'
         name: 'constant.character.latex'
         match: '(\\\\)(\\&|\\%|\\$|\\#|\\_|\\{|\\}|(textascii(tilde|circum)|textbackslash)(?=[^a-zA-Z@]))'
+    }
+    accents: {
+        comment: 'For standard latex accent macros such as \^ or \`'
+        name: 'constant.character.accent.latex'
+        match: '''(\\\\)([\\`\\'\\^\\"\\~\\=\\.](\\w|\\{\\w?\\})|[Hcklbdruv]\\{\\w?\\})'''
     }
     hypersetup: {
         comment: 'Recongnises hypersetup environment. Can be extended to be a general key-option scoper, but this (potentially) allows custom colours for known keys.'
@@ -763,3 +771,7 @@
             }
         ]
     }
+    verbatim: {
+        comment: 'Finds an inline verbatim string of the format \verb+...+'
+        name: 'string.function.verbatim'
+    }


Fixed for else/else-if

Fixed for else/else-if

--- grammars/marko.cson
+++ grammars/marko.cson
@@ -254,7 +254,7 @@
     ]
   }
   {
-    'begin': '(</?)((?i:for|if|else|else-if|var|require|def|invoke|include|with)\\b)'
+    'begin': '(</?)((?i:for|if|else-if|else|var|require|def|invoke|include|with)\\b)'
     'captures':
       '1':
         'name': 'punctuation.definition.tag.html'
@@ -470,8 +470,12 @@
     'match': '(?<=[^=])\\b([a-zA-Z0-9:-]+)'
     'name': 'entity.other.attribute-name.html'
   'tag-marko-attribute':
-    'match': '(?<=[^=])\\b(if|for|else|else-if|attrs|w-bind|w-el-id|w-id)'
-    'name': 'support.function.marko_attribute'
+    'match': '(?<=[^=])\\b((if|for|else-if|attrs|w-bind|w-el-id|w-id)\\s*=|(else)\\b)'
+    'captures':
+      '2':
+        'name': 'support.function.marko_attribute'
+      '3':
+        'name': 'support.function.marko_attribute'
   'tag-id-attribute':
     'begin': '\\b(id)\\b\\s*(=)'
     'captures':


Permit # symbols in function names

Permit # symbols in function names

--- grammars/viml.cson
+++ grammars/viml.cson
@@ -160,7 +160,7 @@
 			match: "\\b(fu(n|nction)?|end(f|fu|fun|function)?)\\b"
 		},{
 			name: "entity.name.function.viml"
-			match: "(?:([sSgGbBwWtTlL]?(:))?\\w+)(?=\\()"
+			match: "(?:([sSgGbBwWtTlL]?(:))?[\\w#]+)(?=\\()"
 			captures:
 				1: name: "storage.modifier.scope.viml"
 				2: name: "punctuation.definition.scope.key-value.viml"
@@ -169,7 +169,7 @@
 	augGroup:
 		patterns: [
 			name: "meta.define-$1.viml"
-			begin: "\\b(aug|augroup)\\b\\s*(\\w+)"
+			begin: "\\b(aug|augroup)\\b\\s*([\\w#]+)"
 			end:   "\\b(\\1)\\s+(END)\\b"
 			patterns: [include: "$self"]
 			beginCaptures:


:memo: Add missing initialization in code example

Fix atom/atom#5353

--- src/composite-disposable.coffee
+++ src/composite-disposable.coffee
@@ -10,6 +10,7 @@
 #
 # class Something
 #   constructor: ->
+#     @disposables = new CompositeDisposable
 #     editor = atom.workspace.getActiveTextEditor()
 #     @disposables.add editor.onDidChange ->
 #     @disposables.add editor.onDidChangePath ->


reasonable page limits

reasonable page limits

--- src/controllers/torrents.coffee
+++ src/controllers/torrents.coffee
@@ -27,7 +27,7 @@
   Torrent.count query, (err, count) ->
     q = Torrent.find query, ['title', 'size', 'dateUploaded', 'category', 'permalink']
     q.sort 'dateUploaded', 1
-    resperpage = 2 #2 per page
+    resperpage = 50 #50 per page
     q.limit(resperpage)
     page = parseInt(req.query.page)
     if !isNaN(page)


Reworked the indentation logic a little

Reworked the indentation logic a little

Previously the logic lacked handling of multiple matches of the
increase/decrease regexs, so things like the following javascript
would not be handled correctly (the last line would be indented).

if (test) {
  foo({a:1
  })};
var t = "this should be at indentation 0";

Fixed that.

Also revisited the logic regarding decreaseIndent and
decreaseNextIndent. It did not seem very logical that decreaseIndent
did *not* correspond to increaseIndent: decreaseIndent regarded the
current line whereas increaseIndent regarded the next line (just like
decreaseNextIndent). For that reason I renamed decreaseIndent to
decreaseThisIndent and decreaseNextIndent to decreaseIndent. This way
we also avoid a whole lot of issues related to the concept of
decreaseNextIndent, because most of the language packages I looked at
have not yet adopted it but the semantics of decreaseIndent had
changed. So now the semantics of decreaseIndent is back to what it was
and decreaseThisIndent is the new concept.

--- src/language-mode.coffee
+++ src/language-mode.coffee
@@ -243,13 +243,14 @@
     @suggestedIndentForTokenizedLineAtBufferRow(bufferRow, line, tokenizedLine, options)

   suggestedIndentForTokenizedLineAtBufferRow: (bufferRow, line, tokenizedLine, options) ->
+    # console.log tokenizedLine
     iterator = tokenizedLine.getTokenIterator()
     iterator.next()
     scopeDescriptor = new ScopeDescriptor(scopes: iterator.getScopes())

     increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor)
+    decreaseThisIndentRegex = @decreaseThisIndentRegexForScopeDescriptor(scopeDescriptor)
     decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor)
-    decreaseNextIndentRegex = @decreaseNextIndentRegexForScopeDescriptor(scopeDescriptor)

     if options?.skipBlankLines ? true
       precedingRow = @buffer.previousNonBlankRow(bufferRow)
@@ -263,12 +264,29 @@

     unless @editor.isBufferRowCommented(precedingRow)
       precedingLine = @buffer.lineForRow(precedingRow)
-      desiredIndentLevel += 1 if increaseIndentRegex?.testSync(precedingLine)
-      desiredIndentLevel -= 1 if decreaseNextIndentRegex?.testSync(precedingLine)
+      tokenizedPrecedingLine =
+        @editor.displayBuffer.tokenizedBuffer
+        .buildTokenizedLineForRowWithText(precedingRow, precedingLine)
+
+      # console.log "preceding", tokenizedPrecedingLine
+
+      # desiredIndentLevel += 1 if increaseIndentRegex?.testSync(precedingLine)
+      if increaseIndentRegex
+        desiredIndentLevel += @countRegex(increaseIndentRegex, precedingLine, tokenizedPrecedingLine)
+      # desiredIndentLevel -= 1 if decreaseIndentRegex?.testSync(precedingLine)
+      if decreaseIndentRegex
+        desiredIndentLevel -= @countRegex(decreaseIndentRegex, precedingLine, tokenizedPrecedingLine)
+      # we need to add back one if we already closed one scope on the previous line itself
+      if decreaseThisIndentRegex and @countRegex(decreaseThisIndentRegex, precedingLine, tokenizedPrecedingLine)
+        desiredIndentLevel += 1

     unless @buffer.isRowBlank(precedingRow)
-      desiredIndentLevel -= 1 if decreaseIndentRegex?.testSync(line)
-
+      # desiredIndentLevel -= 1 if decreaseThisIndentRegex?.testSync(line)
+      if decreaseThisIndentRegex and @countRegex(decreaseThisIndentRegex, line, tokenizedLine)
+        desiredIndentLevel -= 1
+      # desiredIndentLevel -= @countRegex(decreaseThisIndentRegex, line) if decreaseThisIndentRegex
+
+    # console.log("suggestedIndentForTokenizedLineAtBufferRow: rtv", desiredIndentLevel)
     Math.max(desiredIndentLevel, 0)

   # Calculate a minimum indent level for a range of lines excluding empty lines.
@@ -298,15 +316,30 @@
     indentLevel = @suggestedIndentForBufferRow(bufferRow, options)
     @editor.setIndentationForBufferRow(bufferRow, indentLevel, options)

+
+  # Count the number of occurence of regex in string, given its tokenized
+  # version, and ignoring any occurence that start inside a quoted string
+  countRegex: (regex, string, tokenized) ->
+    count = 0
+    m = regex.searchSync(string)
+    while (m)
+      quoted = false
+      if scopes = tokenized.tokenAtBufferColumn(m[0].start)?.scopes
+        quoted = scope for scope in scopes when scope.match '^string.quoted'
+      # console.log quoted
+      count += 1 unless quoted
+      m = regex.searchSync(string, m[0].start + 1)
+    count
+
   # Given a buffer row, this decreases the indentation.
   #
   # bufferRow - The row {Number}
   autoDecreaseIndentForBufferRow: (bufferRow) ->
     scopeDescriptor = @editor.scopeDescriptorForBufferPosition([bufferRow, 0])
-    return unless decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor)
+    return unless decreaseThisIndentRegex = @decreaseThisIndentRegexForScopeDescriptor(scopeDescriptor)

     line = @buffer.lineForRow(bufferRow)
-    return unless decreaseIndentRegex.testSync(line)
+    return unless decreaseThisIndentRegex.testSync(line)

     currentIndentLevel = @editor.indentationForBufferRow(bufferRow)
     return if currentIndentLevel is 0
@@ -320,9 +353,11 @@
     if increaseIndentRegex = @increaseIndentRegexForScopeDescriptor(scopeDescriptor)
       desiredIndentLevel -= 1 unless increaseIndentRegex.testSync(precedingLine)

-    if decreaseNextIndentRegex = @decreaseNextIndentRegexForScopeDescriptor(scopeDescriptor)
-      desiredIndentLevel -= 1 if decreaseNextIndentRegex.testSync(precedingLine)
-
+    if decreaseIndentRegex = @decreaseIndentRegexForScopeDescriptor(scopeDescriptor)
+      desiredIndentLevel -= 1 if decreaseIndentRegex.testSync(precedingLine)
+      # desiredIndentLevel -= @countRegex(decreaseIndentRegex, precedingLine)
+
+    # console.log("autoDecreaseThisIndentForBufferRow: desiredIndentLevel", desiredIndentLevel)
     if desiredIndentLevel >= 0 and desiredIndentLevel < currentIndentLevel
       @editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)

@@ -330,14 +365,21 @@
     if pattern = @config.get(property, scope: scopeDescriptor)
       new OnigRegExp(pattern)

+  # when the previous line matches this pattern than increase indentation of the
+  # current line
   increaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
     @getRegexForProperty(scopeDescriptor, 'editor.increaseIndentPattern')

+  # when the *current* line matches this pattern than decrease indentation of
+  # the current line (this, e.g., puts closing brackets with nothing before them
+  # at the level of the opening statement, as in the KR style for C)
+  decreaseThisIndentRegexForScopeDescriptor: (scopeDescriptor) ->
+    @getRegexForProperty(scopeDescriptor, 'editor.decreaseThisIndentPattern')
+
+  # when the previous line matches this pattern than decrease indentation of the
+  # current line
   decreaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
     @getRegexForProperty(scopeDescriptor, 'editor.decreaseIndentPattern')
-
-  decreaseNextIndentRegexForScopeDescriptor: (scopeDescriptor) ->
-    @getRegexForProperty(scopeDescriptor, 'editor.decreaseNextIndentPattern')

   foldEndRegexForScopeDescriptor: (scopeDescriptor) ->
     @getRegexForProperty(scopeDescriptor, 'editor.foldEndPattern')


View: Documentation fixes.

View: Documentation fixes.

--- src/lib/core/View.coffee
+++ src/lib/core/View.coffee
@@ -4,12 +4,14 @@
 goog.require 'spark.utils'

-###*
-  Main View class of Spark Framework.
-###
 class spark.core.View extends spark.core.Object

   ###*
+    Main View class of Spark Framework. It is basically a div element. But it's
+    configurable to be any kind of element. It's event driven. This means you
+    can attach and listen custom events with your data. It also supports native
+    DOM events.
+
     @constructor
     @export
     @param   {Object=} options Class options.
@@ -51,6 +53,7 @@

   ###*
     Sets DOM id.
+
     @export
     @param {!string} domId Id of the element.
   ###
@@ -59,7 +62,8 @@

   ###*
-    Returns the DOM id if exists, otherwise it will return null
+    Returns the DOM id if exists, otherwise it will return null.
+
     @export
     @return {string|null}
   ###
@@ -70,6 +74,7 @@
   ###*
     Sets the class name of element. This will override existing class names.
     Use `@addClass` if you want to add new class name to the element.
+
     @export
     @param {!string} cssClass Class name.
   ###
@@ -79,6 +84,7 @@

   ###*
     Returns class name of the element.
+
     @export
     @return {string} Class name.
   ###
@@ -88,6 +94,7 @@

   ###*
     Returns class list of the element.
+
     @export
     @return {Array} List of class names.
   ###
@@ -97,6 +104,7 @@

   ###*
     Adds new class name to element.
+
     @export
     @param {!string} cssClass New class name for the element.
   ###
@@ -106,6 +114,7 @@

   ###*
     Remove a class name from the element.
+
     @export
     @param {!string} cssClass Name of the class which will be removed.
   ###
@@ -115,6 +124,7 @@

   ###*
     Returns true if element has that class name.
+
     @export
     @param {!string} cssClass Name of the class which will be tested.
     @return {boolean} Whether element has a class name or not.
@@ -125,6 +135,7 @@

   ###*
     Returns the DOM element.
+
     @export
     @return {Element} DOM element of this view.
   ###
@@ -135,6 +146,7 @@
   ###*
     Very basic support of templating. Spark Framework will provide much more
     powerful templating solution but that's better than nothing for now.
+
     @export
     @param {!string} template HTML markup of the element.
   ###
@@ -143,8 +155,9 @@

   ###*
-    @export
     Appends view into document's body.
+
+    @export
   ###
   appendToDocumentBody: ->
     document.body.appendChild @getElement()
@@ -153,6 +166,7 @@

   ###*
     Removes element from DOM if it is in DOM.
+
     @export
     @return {boolean} Whether element removed from document or not.
   ###
@@ -168,6 +182,7 @@

   ###*
     Appends a new view into this view's element as a child.
+
     @export
     @param {!spark.core.View} view A spark.View instance to append.
   ###
@@ -186,6 +201,7 @@

   ###*
     Native setAttribute wrapper.
+
     @export
     @param {!string} name  Atrribute name.
     @param {!string} value Attribute value.
@@ -196,6 +212,7 @@

   ###*
     Native getAttribute wrapper.
+
     @export
     @param {!string} name  Atrribute name.
   ###
@@ -205,6 +222,7 @@

   ###*
     Native removeAttribute wrapper.
+
     @export
     @param {!string} name  Atrribute name.
   ###
@@ -213,8 +231,9 @@

   ###*
-    @export
     Disable view.
+
+    @export
   ###
   disable: ->
     disabled = 'disabled'
@@ -224,8 +243,9 @@

   ###*
-    @export
     Enable view.
+
+    @export
   ###
   enable: ->
     disabled = 'disabled'
@@ -235,16 +255,18 @@

   ###*
-    @export
     Toggle view state. Disable if enabled, enable if disabled.
+
+    @export
   ###
   toggle: ->
     if @isDisabled() then @enable() else @disable()

   ###*
-    @export
     Returns the current disabled state of the button.
+
+    @export
   ###
   isDisabled: ->
     return @disabled or no
@@ -263,9 +285,10 @@

   ###*
+    Override Object::once to support two way binding for DOM events.
+
     @export
     @override
-    Override Object::once to support two way binding for DOM events.
   ###
   once: (eventName, callback) ->
     if spark.core.View.EventTypes[eventName]
@@ -275,9 +298,10 @@

   ###*
+    Override Object::off to remove events binded to DOM element.
+
     @export
     @override
-    Override Object::off to remove events binded to DOM element.
   ###
   off: (eventName, callback) ->
     goog.events.unlisten @getElement(), eventName, callback
@@ -301,6 +325,7 @@

   ###*
     Helper method to set css class to options set.
+
     @param {Object}  options  Class options.
     @param {string=} optionalClass Optinal CSS class which will added to default.
   ###


refactor the routing file to use a lodash `each` function instead of a native "for" loop.  The reason this is important is that the scoping makes a lot more sense, e.g. we have unique variables for each iteration of the loop, instead of one variable.

--- guts/routing.coffee
+++ guts/routing.coffee
@@ -10,13 +10,13 @@
                 configuredRoutes = require '../config/routes'

                 # Let's loop through the routes file and do the appropriate mapping.
-                for route of configuredRoutes
+                # NOTE: I really hate that the value comes before the key.
+                _.each configuredRoutes, (actionString, route) ->

                         # This is just a handle on the string object so as to avoid square-bracket-hell
-                        actionString = configuredRoutes[route]

                         # routes are stored like METHOD /route, so we'll split on spaces.
-                        routeComponent = route.split(' ')
+                        routeComponent = route.split ' '

                         # THe first item should be the method, so we'll grab that.  The toLowerCase
                         # function is there to make the routing a bit more dev friendly in case
@@ -27,11 +27,12 @@
                         # helper-variable.
                         endpoint = routeComponent[1]

+
+                        allRoutes = actionString.split ' '
                         # I was having a bit of trouble with scopign and not-copying, and since
                         # we're already utilizing lodash, I might as well take advantage of the
                         # deep-copy function they have so as to guarantee it won't be a problem
                         # in the future
-                        allRoutes = _.cloneDeep(actionString.split ' ')

                         # This is a thunk'd funciton.  I was having some issues with the "allRoutes"
                         # variable not being the one I needed, and it turns out that it was shallow
@@ -40,8 +41,7 @@
                         # Thus, I thunk'd it: I passit it into the function as an argument, so as to
                         # guarantee that I'm getting a personalized "allroutes" variable.  The thunk
                         # then returns a function that we can use.
-                        wrapper = (allRoutes) ->
-                                (req, res) ->
+                        wrapper = (req, res) ->
                                         # A quick holder for all the promises yet to come.
                                         promiseArray = []

@@ -64,17 +64,16 @@
                                                 return controllerObject[myController][myAction]

                                         # Once we've gotten all the handles on the functions we need
-                                        # to call, we can concat it to all previous promises.
-                                        endPromiseArray = promiseArray.concat actionHandles
-
-                                        # We need to guarantee these functions will run sequentially,
-                                        # piping the output from the previous one to the next one.
-                                        #
-                                        # It turns out that _.reduce is sort of designed for *exactly that*
-                                        #
-                                        # This should converge on one final promise.
-                                        finalPromise = _.reduce endPromiseArray, (cur, next) ->
-                                                cur.then(next)
+                                        # to call, we can concat it to all previous promises. Afterwards
+                                        # we want these to run sequentially, so we use the reduce function
+                                        # to run them, then converge into a single, final promise.
+                                        finalPromise =
+                                                do
+                                                        _.chain promiseArray
+                                                        .concat actionHandles
+                                                        .reduce (cur, next) ->
+                                                                cur.then next
+                                                        .value

                                         # Everything should be done.  We can finally render a template
                                         # or return back JSON depending on what they did on that last function
@@ -102,4 +101,4 @@

                         # As stated above, wrapper will return a new function based on what
                         # we send in for "allRoutes"
-                        app[method](endpoint, wrapper(allRoutes))
+                        app[method](endpoint, wrapper)


Add cb parameters

Add cb parameters

--- src/octonode/gist.coffee
+++ src/octonode/gist.coffee
@@ -133,7 +133,7 @@

   # Delete a comment
   # '/gists/comments/1' DELETE
-  deleteComment: (id) ->
+  deleteComment: (id, cb) ->
     @client.del "/gists/comments/#{id}", {}, (err, s, b, h) ->
       return cb(err) if err
       if s isnt 204 then cb(new Error("Gist deleteComment error")) else cb null


added error output in player tracer

added error output in player tracer

--- src/plugins/trace.coffee
+++ src/plugins/trace.coffee
@@ -18,6 +18,10 @@
             $gte: Date.now() - 30 * 24 * 60 * 60 * 1000
     ).sort({time: -1}).limit(500).toArray (err, logs) ->

+        if err
+            logger.error '[Trace] %s', err.message
+            return callback()
+
         for item in logs
             console.log '[%s]\t%s', moment(item.time).format('LLL'), item.text


httpd.coffee - register routes with robot.name

--- src/scripts/httpd.coffee
+++ src/scripts/httpd.coffee
@@ -21,22 +21,22 @@

 module.exports = (robot) ->

-  robot.router.get "/hubot/version", (req, res) ->
+  robot.router.get "/#{robot.name}/version", (req, res) ->
     res.end robot.version

-  robot.router.post "/hubot/ping", (req, res) ->
+  robot.router.post "/#{robot.name}/ping", (req, res) ->
     res.end "PONG"

-  robot.router.get "/hubot/time", (req, res) ->
+  robot.router.get "/#{robot.name}/time", (req, res) ->
     res.end "Server time is: #{new Date()}"

-  robot.router.get "/hubot/info", (req, res) ->
+  robot.router.get "/#{robot.name}/info", (req, res) ->
     child = spawn('/bin/sh', ['-c', "echo I\\'m $LOGNAME@$(hostname):$(pwd) \\($(git rev-parse HEAD)\\)"])

     child.stdout.on 'data', (data) ->
       res.end "#{data.toString().trim()} running node #{process.version} [pid: #{process.pid}]"
       child.stdin.end()

-  robot.router.get "/hubot/ip", (req, res) ->
+  robot.router.get "/#{robot.name}/ip", (req, res) ->
     robot.http('http://ifconfig.me/ip').get() (err, r, body) ->
       res.end body


Added comments

Added comments

--- src/scripts/index.coffee
+++ src/scripts/index.coffee
@@ -18,22 +18,25 @@
   avr = new AVR.Context(document.getElementById 'display')
   avr.loadPrograms {

+    # Basic functions
     fill      : "shaders/fill.glsl"
     zero      : "shaders/zero.glsl"
     display   : "shaders/display.glsl"
-    velocity  : "shaders/velocity.glsl"
-    position  : "shaders/position.glsl"
-
+
+    # Neighbour search
     genGridCells: "shaders/gen_grid_cells.glsl"
-    bitonic     : "shaders/bitonic.glsl"
-
+    genAccessor : "shaders/gen_accessor.glsl"
+    bitonicSort : "shaders/bitonic.glsl"
+
+    # SPH
     gridDensities : "shaders/grid_densities.glsl"
     gridPressures : "shaders/grid_pressures.glsl"
     densities : "shaders/densities.glsl"
     gpressure : "shaders/gpressure.glsl"
-
-    genAccessor: "shaders/gen_accessor.glsl"
-
+    velocity  : "shaders/velocity.glsl"
+    position  : "shaders/position.glsl"
+
+    # Rendering
     particles : {
       vertexUrl   : "shaders/particles.vertex.glsl"
       fragmentUrl : "shaders/particles.fragment.glsl"
@@ -41,14 +44,19 @@

   }, {

-    max_count : 32
+    # Constants
     pi        : 3.14.toFixed(8)
+
+    # World dimensions
     factor    : factor.toFixed(8)
     lobound   : 0.toFixed(8)
     hibound   : factor.toFixed(8)
     sizex     : size[0].toFixed(8)
     sizey     : size[1].toFixed(8)
     count     : count.toFixed(8)
+    grid_size : (factor / h).toFixed(8)
+
+    # SPH parameters
     h         : h.toFixed(8)
     m         : m.toFixed(8)
     h2        : Math.pow(h, 2).toFixed(8)
@@ -56,7 +64,6 @@
     h9        : Math.pow(h, 9).toFixed(8)
     k         : 0.1.toFixed(8)
     r0        : 10.toFixed(8)
-    grid_size : (factor / h).toFixed(8)

   }, (p) ->

@@ -80,9 +87,7 @@
     c.doubleFramebuffer('grid', size: size)
     c.doubleFramebuffer('particles', size: size)
     c.doubleFramebuffer('velocities', size: size)
-
-    eachCell (i, j, k) ->
-      c.framebuffer("accessor_#{i}_#{j}_#{k}", size: size)
+    eachCell (i, j, k) -> c.framebuffer("accessor_#{i}_#{j}_#{k}", size: size)

     # Bootstrap
     c.pass(p.fill, 'back particles')
@@ -100,7 +105,7 @@
       # Sorting
       sortSpread = 2
       while sortSpread <= count
-        c.pass(p.bitonic, 'switch grid', {
+        c.pass(p.bitonicSort, 'switch grid', {
           target: 'auto grid'
         }, ({prog}) ->
           prog.sendFloat 'spread', sortSpread
@@ -109,7 +114,7 @@
         mergeSpread = sortSpread / 2
         sortSpread *= 2
         while mergeSpread >= 2
-          c.pass(p.bitonic, 'switch grid', {
+          c.pass(p.bitonicSort, 'switch grid', {
             target: 'auto grid'
           }, ({prog}) ->
             prog.sendFloat 'spread', mergeSpread
@@ -117,8 +122,6 @@
           )
           mergeSpread /= 2

-      c.pass(p.zero, 'auto densities')
-      c.pass(p.zero, 'auto pressures')

       eachCell (i, j, k) ->
         c.pass(p.genAccessor, "accessor_#{i}_#{j}_#{k}", {
@@ -128,6 +131,7 @@
           prog.sendFloat3 'cmpCell', [i, j, k]
         )

+      c.pass(p.zero, 'auto densities')
       eachCell (i, j, k) ->
         c.pass(p.gridDensities, 'switch densities', {
           particles: 'back particles'
@@ -136,6 +140,7 @@
           densities: 'auto densities'
         })

+      c.pass(p.zero, 'auto pressures')
       eachCell (i, j, k) ->
         c.pass(p.gridPressures, 'switch pressures', {
           particles: 'back particles'


Executing `optmize_for_development` only if the Tree has it defined.

--- src/toaster/core/tree.coffee
+++ src/toaster/core/tree.coffee
@@ -67,7 +67,7 @@
     for file in @files
       file.compile_to_disk @config

-    do @optimizer.optimize_for_development
+    @optimizer.optimize_for_development?()

   watch:()->
     # initialize watchers array


Trix.Helpers.trace for debug logging of the arguments and return value of a method call

--- src/trix/core/helpers.coffee
+++ src/trix/core/helpers.coffee
@@ -9,6 +9,12 @@
     ->
       @memos ?= {}
       @memos[memo] ?= fn.apply(this, arguments)
+
+  trace: (name, fn) -> ->
+    result = fn.apply(this, arguments)
+    args = (formatValue(arg) for arg in arguments)
+    Trix.Logger.log("methodTraces", name, "(", args..., ") =", result)
+    result

   capitalize: (string) ->
     string.charAt(0).toUpperCase() + string.substring(1)
@@ -24,3 +30,6 @@
     for name, value of methods when name not in reservedNames and typeof value is "function"
       do (name, value) =>
         destination[name] = -> value.apply(@[toProperty], arguments) if @[toProperty]?
+
+formatValue = (value) ->
+  value?.inspect?() ? (try JSON.stringify(value)) ? value


Remove scatterplot limit

Remove scatterplot limit

--- src/ubret/scatterplot.coffee
+++ src/ubret/scatterplot.coffee
@@ -9,9 +9,7 @@
   graphData: =>
     data = @preparedData()
     return if _.isEmpty(data) or !@opts.axis1 or !@opts.axis2
-    _.chain(data).shuffle().take(300)
-      .map((d) => _(d).pick(@opts.axis1, @opts.axis2, 'uid'))
-      .value()
+    _.map(data, (d) => _(d).pick(@opts.axis1, @opts.axis2, 'uid'))

   drawData: =>
     data = @graphData()


Added unit test for Timespan.segmentByInterval.

--- test/01-time.coffee
+++ test/01-time.coffee
@@ -52,4 +52,18 @@
       fps = 30
       ts = new fk.Timespan.str "1s + 1f .. 1s * 2", fps
       ts.from.value.should.equal 1000 + 1000 / fps
-      ts.to.value.should.equal 2000+      ts.to.value.should.equal 2000
+
+  describe '#segmentByInterval()', ->
+    it 'should work with an even interval', ->
+      r = fk.Timespan.s(1).segmentByInterval fk.Time.ms(250)
+      r.length.should.equal 4
+
+    it 'should work with an uneven interval', ->
+      r = fk.Timespan.s(1).segmentByInterval fk.Time.ms(255)
+      r.length.should.equal 4
+
+    it 'should work with an uneven interval and snapping', ->
+      r = fk.Timespan.s(1).segmentByInterval fk.Time.ms(255), true
+      r.length.should.equal 4
+      r[3].to.value.should.equal 1000


PUBDEV-825 Hyperlink frame and model keys.

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -533,11 +533,11 @@
           else if isObject v
             if meta = v.__meta
               if meta.schema_type is 'Key<Frame>'
-                record[k] = v.name
+                record[k] = "#{escape v.name}"
               else if meta.schema_type is 'Key<Model>'
-                record[k] = v.name
+                record[k] = "#{escape v.name}"
               else if meta.schema_type is 'Frame'
-                record[k] = v.key.name
+                record[k] = "#{escape v.key.name}"
               else
                 inspectObject inspections, "#{name} - #{k}", origin, v
             else


Add todo and remarks onto mongo.

Add todo and remarks onto mongo.

--- express/index.coffee
+++ express/index.coffee
@@ -10,6 +10,8 @@
 app = express()
 server = http.createServer(app)
 app.set('port', process.env.PORT || 4000)
+
+mongo = require('./models/connection')
 ###
     Require routes.
 ###
@@ -44,7 +46,7 @@
     else
         user_id = parseInt(req.query.user_id)
         api_key = req.query.api_key.toString()
-
+        # Mongo request should be in a model.
         mongo.db.collection('homeagain_users').findOne(
             {
                 user_id: user_id,
@@ -61,6 +63,7 @@
                     res.send 401
             )
 ### Default 404 middleware ###
+# Seems to be buggy on my computer.
 #app.use routes.error('Page not found :(', 404)

 #Application name.
@@ -68,7 +71,7 @@

 # Init mongo connection only once
-require('./models/connection').initiate (db) ->
+mongo.initiate (db) ->
     console.log('Connection is now established with mongoDB on homeAgain.')


model_postgres: must quote "user" column for Postgres

--- src/local/model_postgres.coffee
+++ src/local/model_postgres.coffee
@@ -308,7 +308,7 @@
     getPending: (node, cb) ->
         db = @db
         async.waterfall [(cb2) ->
-            db.query "SELECT user FROM subscriptions WHERE subscription = 'pending' AND node = $1 ORDER BY updated DESC", [ node ], cb2
+            db.query "SELECT \"user\" FROM subscriptions WHERE subscription = 'pending' AND node = $1 ORDER BY updated DESC", [ node ], cb2
         , (res, cb2) ->
             cb2 null, res.rows.map((row) ->
                 row.user
@@ -438,7 +438,7 @@
     getOutcast: (node, cb) ->
         db = @db
         async.waterfall [(cb2) ->
-            db.query "SELECT user FROM affiliations WHERE affiliation = 'outcast' AND node = $1 ORDER BY updated DESC", [ node ], cb2
+            db.query "SELECT \"user\" FROM affiliations WHERE affiliation = 'outcast' AND node = $1 ORDER BY updated DESC", [ node ], cb2
         , (res, cb2) ->
             cb2 null, res.rows.map((row) ->
                 row.user


Refactoring SQL query for most recent posts.

--- src/local/model_postgres.coffee
+++ src/local/model_postgres.coffee
@@ -583,24 +583,28 @@
                         AND    node LIKE '%/posts'
                         AND    subscription='subscribed'""", [ subscriber ], cb2
         , (res, cb2) ->
-            async.map res?.rows, (row, cb3) ->
+            ph = 1
+            prepArgs = []
+            q = ""
+            for row in res?.rows
                 node = row.node
-                q = """SELECT id, node, xml, updated FROM items
-                       WHERE node=$1
-                       AND   updated >= $2::timestamp
-                       ORDER BY updated DESC
-                       LIMIT $3"""
-                db.query q, [ node, timeStart, maxItems ], cb3
-            , cb2
-        , (res, cb2) ->
-            items = []
-            for r in res
-                items = items.concat r?.rows.map (row) ->
-                    node: row.node
-                    id: row.id
-                    globalId: "#{row.node};#{row.id}"
-                    updated: row.updated
-                    el: parseEl(row.xml)
+                q = (q + " UNION ALL ") if ph > 1
+                q = q + """(SELECT id, node, xml, updated FROM items
+                           WHERE node=$#{ph++}
+                           AND   updated >= $#{ph++}::timestamp
+                           ORDER BY updated DESC
+                           LIMIT $#{ph++})"""
+                prepArgs.push node
+                prepArgs.push timeStart
+                prepArgs.push maxItems
+            db.query q, prepArgs, cb2
+        , (res, cb2) ->
+            items = res?.rows.map (row) ->
+                node: row.node
+                id: row.id
+                globalId: "#{row.node};#{row.id}"
+                updated: row.updated
+                el: parseEl(row.xml)
             cb2 null, items
         ], cb


webapp/misc: dereference the actual event for ReactJS.SyntheticMouseEvent (otherwise .which is empty and other params are null due to garbage collection)

--- src/smc-util/misc.coffee
+++ src/smc-util/misc.coffee
@@ -1480,9 +1480,12 @@
             new_map[k] = if typeof(v) == 'object' then map_without_undefined(v) else v
     return new_map

-
 # foreground; otherwise, return false.
 exports.should_open_in_foreground = (e) ->
+    # for react.js synthetic mouse events, where e.which is undefined!
+    if e.constructor.name == 'SyntheticMouseEvent'
+        e = e.nativeEvent
+    #console.log("e: #{e}, e.which: #{e.which}", e)
     return not (e.which == 2 or e.metaKey or e.altKey or e.ctrlKey)

 # Like Python's enumerate
@@ -1496,7 +1499,7 @@

 # escape everything in a regex
 exports.escapeRegExp = escapeRegExp = (str) ->
-  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
+    return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")

 # smiley-fication of an arbitrary string
 smileys_definition = [


misc/seconds2hms: tuning longform and fractoins of seconds

--- src/smc-util/misc.coffee
+++ src/smc-util/misc.coffee
@@ -1461,7 +1461,12 @@

 exports.seconds2hms = seconds2hms = (secs, longform) ->
     longform ?= false
-    s = round2(secs % 60)
+    if secs < 10
+        s = round2(secs % 60)
+    else if secs < 60
+        s = round1(secs % 60)
+    else
+        s = Math.round(secs % 60)
     m = Math.floor(secs / 60) % 60
     h = Math.floor(secs / 60 / 60)
     if h == 0 and m == 0
@@ -1471,7 +1476,7 @@
             return "#{s}s"
     if h > 0
         if longform
-            return "#{h} #{exports.plural(s, 'hour')} #{m} #{exports.plural(m, 'minute')}  #{s} #{exports.plural(s, 'second')}"
+            return "#{h} #{exports.plural(h, 'hour')} #{m} #{exports.plural(m, 'minute')}"
         else
             return "#{h}h#{m}m#{s}s"
     if m > 0


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/animated.coffee
+++ src/animated.coffee
@@ -37,7 +37,6 @@
         }
         frames: [0]
       }]
-    spriteLookup: {}
     activeAnimation:
       name: ""
       complete: ""
@@ -63,19 +62,22 @@

     return I.data

-  I.data.tileset.each (spriteData, i) ->
-    I.spriteLookup[i] = Sprite.fromURL(spriteData.src)
+  window["#{I.animationName}SpriteLookup"] ||= []
+
+  unless window["#{I.animationName}SpriteLookup"].length
+    I.data.tileset.each (spriteData, i) ->
+      window["#{I.animationName}SpriteLookup"][i] = Sprite.fromURL(spriteData.src)
+
+  I.spriteLookup = window["#{I.animationName}SpriteLookup"]

   if I.data.animations.first().name != ""
     I.activeAnimation = I.data.animations.first()
-    I.currentFrameIndex = I.activeAnimation.frames.first()

     I.data.tileset.each (spriteData, i) ->
       I.spriteLookup[i] = Sprite.fromURL(spriteData.src)
   else if I.animationName
     loadByName I.animationName, ->
       I.activeAnimation = I.data.animations.first()
-      I.currentFrameIndex = I.activeAnimation.frames.first()

       I.data.tileset.each (spriteData, i) ->
         I.spriteLookup[i] = Sprite.fromURL(spriteData.src)
@@ -85,20 +87,22 @@
   advanceFrame = ->
     frames = I.activeAnimation.frames

-    if I.currentFrameIndex == frames.last()
+    if I.currentFrameIndex == frames.indexOf(frames.last())
       self.trigger("Complete")

       nextState = I.activeAnimation.complete

       if nextState
         I.activeAnimation = find(nextState) || I.activeAnimation
-        sprite = I.spriteLookup[I.activeAnimation.frames.first()]
+        I.currentFrameIndex = 0
+    else
+      I.currentFrameIndex = (I.currentFrameIndex + 1) % frames.length

-        I.width = sprite.width
-        I.height = sprite.height
+    sprite = I.spriteLookup[frames[I.currentFrameIndex]]

-    I.currentFrameIndex = I.activeAnimation.frames[(frames.indexOf(I.currentFrameIndex) + 1) % frames.length]
-    I.sprite = I.spriteLookup[I.currentFrameIndex]
+    I.sprite = sprite
+    I.width = sprite.width
+    I.height = sprite.height

   find = (name) ->
     result = null
@@ -129,7 +133,8 @@
       firstFrame = I.activeAnimation.frames.first()
       firstSprite = I.spriteLookup[firstFrame]

-      I.currentFrameIndex = firstFrame
+      I.currentFrameIndex = 0
+      I.sprite = firstSprite
       I.width = firstSprite.width
       I.height = firstSprite.height
     else
@@ -144,13 +149,13 @@

         if updateFrame = (time - I.lastUpdate) >= I.activeAnimation.speed
           I.lastUpdate = time
-          if triggers = I.activeAnimation.triggers?[I.activeAnimation.frames.indexOf(I.currentFrameIndex)]
+          if triggers = I.activeAnimation.triggers?[I.currentFrameIndex]
             triggers.each (event) ->
               self.trigger(event)

           advanceFrame()
       else
-        if triggers = I.activeAnimation.triggers?[I.activeAnimation.frames.indexOf(I.currentFrameIndex)]
+        if triggers = I.activeAnimation.triggers?[I.currentFrameIndex]
           triggers.each (event) ->
             self.trigger(event)


Removing maxmind ip attribution since we're not using it

--- static/js/maproulette.coffee
+++ static/js/maproulette.coffee
@@ -28,8 +28,6 @@

     thing by Martijn van Exel

-  This website uses GeoIP Javascript from MaxMind.
-

 """

 # Misc variables
@@ -473,6 +471,7 @@

   # Determine the user's preferences
+  challenge = $(document).getUrlParam("challenge")
   if
   difficulty = "beginner" if not difficulty?
   if not location?


First attempt at initialTask code

First attempt at initialTask code

--- static/js/maproulette.coffee
+++ static/js/maproulette.coffee
@@ -1,4 +1,4 @@
-1###
+11###
 # This file contains all the MapRoulette client/javascript code
 ###
 root = exports ? this
@@ -11,8 +11,6 @@
 currentChallenge = null
 currentTask = null
 selectedFeature = null
-selectedFeatureType = null
-selectedFeatureId = null

 # User variables
 editor = ""
@@ -28,7 +26,6 @@
 # Statically stored strings
 msgMovingOnToTheNextChallenge = 'OK, moving right along...'
 msgZoomInForEdit = """Please zoom in a little so we don't have to load a huge area from the API."""
-enablekeyboardhooks = true
 mr_attrib = """
 <small>
   <p>
@@ -90,6 +87,15 @@
     else
       returnVal

+clearTask = ->
+  ###
+  # Clear all the task-related variables in between tasks
+  ###
+  currentTask = null
+  selectedFeature = null
+  # Remove and re-add the geojson layer (since we can't clear it)
+  map.removeLayer(geojsonLayer)
+  addGeoJSONLayer()

 getExtent = (feature) ->
   ###
@@ -184,13 +190,15 @@
     else
       "Somewhere on Earth"

-revGeocodeOSMObj = (type, id) ->
-  ###
-  # Reverse geocodes an OSM object
+revGeocodeOSMObj = (feature) ->
+  ###
+  # Reverse geocodes an OSM object as a geoJSON feature
   ###
   # The Nominatim documents say reverse geocoding an object is
   # preferable to a location, so this function should be used instead
   # of revGeocode
+  type = feature.properties.type
+  id = feature.properties.id
   mqurl = "http://open.mapquestapi.com/nominatim/v1/reverse?format=json&osm_type=#{type}@osm_id=#{id}"
   msgClose()
   $.getJSON mqurl, (data) ->
@@ -211,7 +219,7 @@
     # display a message saying where we are in the world
     msg locstr

-@getInitialTask = (difficulty, near) ->
+@getInitialTask = (difficulty = "easy", near) ->
   ###
   # Gets a new task and challenge and displays it
   ###
@@ -224,21 +232,13 @@
       args = "#{args}&near=#{near}"
   $.getJSON "/task#{args}", (data) ->
     currentTask = data
-    # Enter in the time we got the task
     currentTask.startTime = new Date.getTime()
-    features = data.features.features
-    drawFeatures(features) if features? and features.length
-    updateStats()
-    # If we have a selected object, then use it to geocode (for
-    # efficiency)
-    if selectedFeatureType? and selectedFeatureId?
-      revCodeCodeOSMObj selectedFeatureType, selectedFeatureId
-      setDelay 3, msgClose
-    else
-      # Otherwise, fall back on the old method
-      revGeocode()
-      setDelay 3, msgClose
-    msgTaskText()
+    # Since this is out first task, we'll need to grab the metadata
+    # from the task and use that to populate the page
+    challenge = currentTask.challenge
+    updateChallenge(challenge)
+    updateStats(challenge)
+    showTask(data)

 drawFeatures = (features) ->
   ###
@@ -248,37 +248,34 @@
   for feature in features
     if feature.properties.selected is true
         selectedFeature = feature
-        selectedFeatureId = feature.properties.id
-        selectedFeatureType = feature.properties.type
       geojsonLayer.addData feature
     extent = getExtent(selectedFeature)
     map.fitBounds(extent)

+showTask = (task) ->
+  ###
+  # Displays a task to the display and waits for the user prompt
+  ###
+  ######## NOT USED YET ########
+  # Draw the features and move the map to the right extent
+  drawFeaures(task.features)
+  # Update the stats on the side. We can rely on the ordering here
+  revGeocode()
+  setDelay 3, msgClose()
+  msgTaskText()
+
 @getTask = (challenge = currentChallenge.slug, near = null) ->
   ###
   # Gets another task from the current challenge, close to the
   # location (if supplied)
   ###
   if not currentChallenge? or currentChallenge.slug != challenge
-    updateChallengeDetails(challenge)
-    # In the meantime, we can grab our task,  feature.properties.selected is true
-        selectedFeatureId = feature.properties.id
-        selectedFeatureType = feature.properties.type
-      geojsonLayer.addData feature
-      extent = getExtent(features[0])
-      map.fitBounds(extent)
-
-    updateStats(currentChallenge.slug)
-    # If we have a selected object, then use it to geocode (for
-    # efficiency)
-    if selectedFeatureType? and selectedFeatureId?
-      revCodeCodeOSMObj selectedFeatureType, selectedFeatureId
-      setDelay 3, msgClose
-    else
-      # Otherwise, fall back on the old method
-      revGeocode()
-      setDelay 3, msgClose
-      msgTaskText()
+    updateChallengechallenge)
+  $.getJSON "c/#{challenge}/task", (data) ->
+    currentTask = data
+    currentTask.startTime = new Date.getTime()
+    showTask(data)
+  updateStats(challenge)

 changeMapLayer = (layerUrl, layerAttrib = tileAttrib) ->
   ###
@@ -309,8 +306,7 @@
   ###
   # Clear out some variables
   currentTask = null
-  selectedFeatureId = null
-  selectedFeatureType = null
+  selectedFeature = null

   # Now display the message and move on to the next task
   msg msgMovingOnToTheNextChallenge, 1
@@ -319,7 +315,11 @@
       "editor": editor,
       "startTime": currentTask.startTime,
       "endTime": new Date.getTime() }
-  $.post "/c/#{currentTask.challenge}/task/#{currentTask.id}", payload, -> setTimeout getTask, 1000
+  # Find the map centroid for our next near
+  center = map.getCenter()
+  near = "#{center.lat},#{center.lon}"
+  challenge = currentChallenge.slug
+  $.post "/c/#{currentTask.challenge}/task/#{currentTask.id}", payload, -> setTimeout getTask(challenge, near), 1000

 @openIn = (e) ->
   ###
@@ -332,8 +332,10 @@
   bounds = map.getBounds()
   sw = bounds.getSouthWest()
   ne = bounds.getNorthEast()
+  selectedFeatureId = selectedFeature.properties.id
+  selectedFeatureType = selectedFeature.properties.type
   if editor is "josm"
-    JOSMurl =  "http://127.0.0.1:8111/load_and_zoom?left=#{sw.lng}&right=#{ne.lng}&top=#{ne.lat}&bottom=#{sw.lat}&new_layer=0&select=#{selectedFeatureType}#{selectedFeatureId}"
+    JOSMurl =  "http://127.0.0.1:8111/load_and_zoom?left=#{sw.lng}&right=#{ne.lng}&top=#{ne.lat}&bottom=#{sw.lat}&new_layer=0&select=#{selectedFeaturetype}#{selectedFeatureId}"
     # Use the .ajax JQ method to load the JOSM link unobtrusively and
     # alert when the JOSM plugin is not running.
     $.ajax
@@ -427,7 +429,7 @@
     remaining = data.total - data.done
     $("#counter").text remaining

-updateChallengeDetails = (challenge) ->
+updateChallenge = (challenge) ->
   ###
   # Use the current challenge metadata to fill in the web page
   ###
@@ -456,28 +458,21 @@
   ###
   # Find a challenge and set the map up
   ###
-
   # First create the map
   map = new L.Map "map"
   tileLayer = new L.TileLayer(tileUrl, attribution: tileAttrib)
   map.setView new L.LatLng(40.0, -90.0), 17
   map.addLayer tileLayer
   addGeoJSONLayer()
-
-  # add keyboard hooks
-  if enablekeyboardhooks
-    enableKeyboardShortcuts()
+  enableKeyboardShortcuts()

   # Try to grab parameters from the url
   challenge = $(document).getUrlParam("challenge")
   difficulty = $(document).getUrlParam("difficulty")
   near = $(document).getUrlParam("near")
-  difficulty = "easy" if not difficulty?
   if challenge?
-    updateChallengeDetails(challenge)
+    updateChallenge(challenge)
     updateStats(challenge)
     getTask(challenge, near)
   else
-    # We'll need to grab a task and then use the information from that
-    # task to populate the page
-
+    getInitialTask(difficulty, near)


STL/dnd the 'drop' event handling implementation

--- stl/dnd/src/droppable.coffee
+++ stl/dnd/src/droppable.coffee
@@ -75,13 +75,9 @@
     overlap.emit 'dragenter', draggable: Draggable.current, droppable: Droppable.current

   else if !overlap and Droppable.current isnt null
-    overlap = Droppable.current
-    options = overlap.__droppable
+    droppable_revert()

-    overlap.removeClass options.allowClass
-    overlap.removeClass options.denyClass
-
-    overlap.emit 'dragleave', draggable: Draggable.current, droppable: Droppable.current
+    Droppable.current.emit 'dragleave', draggable: Draggable.current, droppable: Droppable.current
     Droppable.current = null

@@ -140,6 +136,10 @@
 #
 # Checks if the draggable is acceptable by the drooppable
 #
+# @param {dom.Element} draggable
+# @param {dom.Element} droppable
+# @return {Boolean} check result
+#
 droppable_acceptable = (draggable, droppable)->
   options = droppable.__droppable

@@ -158,5 +158,29 @@

   return false

+#
+# Reverts a droppable state, when something was dropped
+# or draggable just left the target
+#
+droppable_revert = ->
+  overlap = Droppable.current
+  options = overlap.__droppable

+  overlap.removeClass options.allowClass
+  overlap.removeClass options.denyClass
+
+#
+# Checks if the droppable was dropped over a target and fires the events
+#
+# @param {dom.Event} the original mouseup event
+# @param {dom.Element} the draggable element
+#
 droppable_check_drop = (event, draggable)->
+  if Droppable.current isnt null
+    droppable_revert()
+
+    if droppable_acceptable(draggable, Droppable.current)
+      Droppable.current.emit 'drop', draggable: draggable, droppable: Droppable.current
+
+  return # nothing
+


bind => on

bind => on

--- src/bindable.coffee
+++ src/bindable.coffee
@@ -23,7 +23,7 @@
   eventCallbacks = {}

   bind: ->
-    self.on()
+    self.on.apply(a)

   ###*
   Adds a function as an event listener.


able to print detailed help for subcommands

--- src/cli/help.coffee
+++ src/cli/help.coffee
@@ -4,13 +4,21 @@
   summary: "Show detailed help for a command"

   run: (args) ->
-    @help()
+    cli = require("./cli")
+    @commands = cli.commands
+
+    commandName = args[0]
+    if command = @commands[commandName]
+      command.help()
+    else
+      @help()

   help: ->
     console.log "Fork2 Version #{version}"
-    cli = require("./cli")
     console.log "The available commands are:\n"
-    for name, command of cli.commands
+    for name, command of @commands
       console.log "  #{name} - #{command.summary}"

+    console.log "\n`fork2 help <command>` to show detailed help for a subcommand."
+
 module.exports = new Help()


Dont intercept htmlFrag responses.

Dont intercept htmlFrag responses.

--- src/code/app.coffee
+++ src/code/app.coffee
@@ -144,7 +144,6 @@
         message: "authInfo"
         data: "knowuh@gmail.com"
       "extendedSupport": false
-      "htmlFragResponse": false
       "interactiveStateGlobal":
         handler: (data) =>
           @globalState = _.extend(@globalState,data)


update url for om interface

update url for om interface

--- hubot/fleet.coffee
+++ hubot/fleet.coffee
@@ -18,7 +18,7 @@
   done: 0

   constructor: (@scenario, @client) ->
-    history = (process.env.HUBOT_FLEET_SHOW_URL or process.env.HUBOT_FLEET_URL) + '#/history/' + @scenario
+    history = (process.env.HUBOT_FLEET_SHOW_URL or process.env.HUBOT_FLEET_URL) + '#/scenarios/' + @scenario
     @client.send "executing " + scenario + ", waiting 2 seconds for acks, reporting to: " + history

   process: (msg) ->


refactor2

--- src/coverage.coffee
+++ src/coverage.coffee
@@ -61,6 +61,19 @@
   'static'
 ]

+# Check if these are treated as keywords as well...
+#
+# abstract  implements  protected
+# boolean instanceOf  public
+# byte  int short
+# char  interface static
+# double  long  synchronized
+# false native  throws
+# final null  transient
+# float package true
+# goto  private
+
+

 isValidIdentifier = (name) ->
   name? && !(name in reservedWords) && (name.toString().match(/^[_a-zA-Z][_a-zA-Z0-9]*$/) || name.toString().match(/^[1-9][0-9]*$/))
@@ -97,6 +110,26 @@
   else
     "nope"

+
+numberProperty = (property) ->
+  type: 'MemberExpression'
+  computed: false
+  object: { type: 'Identifier', name: 'Number' }
+  property: { type: 'Identifier', name: property }
+
+
+replaceNegativeInfinities = (ast) ->
+  escodegen.traverse ast,
+    enter: (node) ->
+      if node.type == 'UnaryExpression' && node.operator == '-' && node.argument.type == 'Literal' && node.argument.value == Infinity
+        replaceNode(node, numberProperty('NEGATIVE_INFINITY'))
+
+
+replacePositiveInfinities = (ast) ->
+  escodegen.traverse ast,
+    enter: (node) ->
+      if node.type == 'Literal' && node.value == Infinity
+        replaceNode(node, numberProperty('POSITIVE_INFINITY'))

 formatTree = (ast) ->
@@ -143,27 +176,8 @@
         else if node.type == 'WhileStatement' && node.test.type == 'Literal'
           node.test.value = !!node.test.value

-  # step 2: replace negative infinities
-  escodegen.traverse ast,
-    enter: (node) ->
-      if node.type == 'UnaryExpression' && node.argument.type == 'Literal' && node.argument.value == Infinity
-        replaceNode(node, {
-          type: 'MemberExpression'
-          computed: false
-          object: { type: 'Identifier', name: 'Number' }
-          property: { type: 'Identifier', name: 'NEGATIVE_INFINITY' }
-        })
-
-  # step 3: replace positive infinities
-  escodegen.traverse ast,
-    enter: (node) ->
-      if node.type == 'Literal' && typeof node.value == 'number' && node.value == Infinity
-        replaceNode(node, {
-          type: 'MemberExpression'
-          computed: false
-          object: { type: 'Identifier', name: 'Number' }
-          property: { type: 'Identifier', name: 'POSITIVE_INFINITY' }
-        })
+  replaceNegativeInfinities(ast)
+  replacePositiveInfinities(ast)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/bounded.coffee
+++ test/bounded.coffee
@@ -12,7 +12,7 @@
   equals obj.bounds().width, 50
   equals obj.bounds().height, 100

-test "Bounds returns correct centered x, y, width, height", ->
+test "Bounds returns correct centered x, y, xw, yx", ->
   obj = GameObject
     x: -5
     y: 20


Adding new test

Adding new test

--- test/general.coffee
+++ test/general.coffee
@@ -47,4 +47,25 @@
   it 'should get undefined when reading an unexistent key', ->

     tmp = new Sample
-    should.not.exist tmp.store.get 'name'+    should.not.exist tmp.store.get 'name'
+
+  it 'should unbind property properly', ->
+
+    called = 0
+    tmp = new Sample
+    names = ['bender', 'lecter']
+
+    tmp.store.on 'name', on_name_change = ( name )->
+      called++
+      name.should.equal names.shift()
+
+    tmp.store.set 'name', 'bender'
+    tmp.store.set 'name', 'lecter'
+    tmp.store.get('name').should.equal 'lecter'
+
+    tmp.store.off 'name', on_name_change
+    tmp.store.set 'name', 'peter'
+    tmp.store.set 'name', 'rob'
+    tmp.store.set 'name', 'charles'
+
+    called.should.equal 2


Save new models

Save new models

--- scripts/collections/content.coffee
+++ scripts/collections/content.coffee
@@ -67,7 +67,7 @@
         .done () -> saveNextItem(queue)

       # Save all the models that have changes
-      changedModels = @filter (model) -> model.hasChanged()
+      changedModels = @filter (model) -> model.hasChanged() or model.isNew()
       saveNextItem(changedModels)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/array_extensions.coffee
+++ test/array_extensions.coffee
@@ -1,7 +1,7 @@
 module "Array"

 test "#average", ->
-  [1, 3, 5, 7].
+  [1, 3, 5, 7].average

 test "#compact", ->
   a = [0, 1, undefined, 2, null, 3, '', 4]


remove the f on the describe

remove the f on the describe

--- spec/app/language-mode-spec.coffee
+++ spec/app/language-mode-spec.coffee
@@ -2,7 +2,7 @@
 Buffer = require 'text-buffer'
 EditSession = require 'edit-session'

-fdescribe "LanguageMode", ->
+describe "LanguageMode", ->
   [editSession, buffer, languageMode] = []

   afterEach ->


Also merge spec for #116

Also merge spec for #116

merge setPosition spec code from https://github.com/atom/autocomplete

--- spec/autocomplete-view-spec.coffee
+++ spec/autocomplete-view-spec.coffee
@@ -304,7 +304,8 @@

         # Check position
         cursorPixelPosition = editorView.getModel().pixelPositionForScreenPosition editor.getCursorScreenPosition()
-        expect(parseInt autocompleteView.css("top")).toBe cursorPixelPosition.top
+        autocompleteBottom = autocompleteView.position().top + autocompleteView.outerHeight()
+        expect(autocompleteBottom).toBe cursorPixelPosition.top
         expect(autocompleteView.position().left).toBe cursorPixelPosition.left

   describe "when auto-activation is disabled", ->


Add spec for project replace tooltip disposable

--- spec/project-find-view-spec.coffee
+++ spec/project-find-view-spec.coffee
@@ -1065,6 +1065,7 @@
             expect(fileContent).toBe("\\t\nb\n\\t")

     describe "replace all button enablement", ->
+      disposable = null
       it "is disabled initially", ->
         expect(projectFindView.replaceAllButton).toHaveClass 'disabled'

@@ -1072,10 +1073,14 @@
         projectFindView.findEditor.setText('items')
         atom.commands.dispatch(projectFindView[0], 'project-find:confirm')

-        waitsForPromise ->
-          searchPromise
-
-        runs ->
+
+        waitsForPromise ->
+          searchPromise
+
+        runs ->
+          disposable = projectFindView.replaceTooltipSubscriptions
+          spyOn(disposable, 'dispose')
+
           expect(projectFindView.replaceAllButton).not.toHaveClass 'disabled'

           projectFindView.findEditor.setText('nopenotinthefile')
@@ -1083,7 +1088,10 @@

           projectFindView.findEditor.setText('itemss')
           expect(projectFindView.replaceAllButton).toHaveClass 'disabled'
-
+          expect(disposable.dispose).toHaveBeenCalled()
+
+          disposable = projectFindView.replaceTooltipSubscriptions
+          spyOn(disposable, 'dispose')
           projectFindView.findEditor.setText('items')
           expect(projectFindView.replaceAllButton).not.toHaveClass 'disabled'

@@ -1092,6 +1100,7 @@

         runs ->
           expect(projectFindView.replaceAllButton).toHaveClass 'disabled'
+          expect(disposable.dispose).toHaveBeenCalled()

           projectFindView.findEditor.setText('')
           atom.commands.dispatch(projectFindView[0], 'project-find:confirm')


Resolve CSON file using require

Resolve CSON file using require

--- spec/text-mate-grammar-spec.coffee
+++ spec/text-mate-grammar-spec.coffee
@@ -23,7 +23,7 @@
       expect(tokens[0]).toEqual value: "this text is so plain. i love it.", scopes: ["text.plain", "meta.paragraph.text"]

     it "loads grammars from cson files", ->
-      grammar = TextMateGrammar.loadSync(fs.resolveOnLoadPath('spec/fixtures/packages/package-with-grammars/grammars/alot.cson'))
+      grammar = TextMateGrammar.loadSync(require.resolve('./fixtures/packages/package-with-grammars/grammars/alot.cson'))
       expect(grammar.scopeName).toBe "source.alot"
       {tokens} = grammar.tokenizeLine("this is alot of code")
       expect(tokens[1]).toEqual value: "alot", scopes: ["source.alot", "keyword.alot"]


Stopped songs from overplaying each other

--- client/main/gamestate.coffee
+++ client/main/gamestate.coffee
@@ -36,20 +36,21 @@
     SC.initialize({
       client_id: "fd1dc47d643674b46399ab11ec8089bf"
     });
-
-    currently_play = false;

     $('#play button').click () ->
       track_url = $('#urlForm').val()

       SC.get '/resolve', url: track_url, (data) ->
+        console.log '/tracks/' + data.id
         SC.stream '/tracks/' + data.id, {onfinish: ()->
           $('#play button').show()
+          console.log '/tracks/' + data.id
         },
         (sound)->
           sound.play()
           $('#play button').hide()
           $('#play p').text(data.title)
+

     # Game stuff


Add newline

Add newline

--- lib/load-paths-task.coffee
+++ lib/load-paths-task.coffee
@@ -34,4 +34,5 @@
     deferred

   abort: ->
-    @aborted = true+    @aborted = true
+


read error message from state, trigger action when user has read the error.

--- imports/ui/App.cjsx
+++ imports/ui/App.cjsx
@@ -16,9 +16,6 @@

   switchSideBar: ->
     @setState priority: (if @state.priority is 'right' then 'left' else 'right')
-
-  onErrorToastClose: -> @props.route.App.emit 'clear error message'
-  onInfoToastClose: -> @props.route.App.emit 'clear info message'

   render: ->
     <G.App centered=false>
@@ -48,7 +45,7 @@
         {@props.children}
       </G.Split>
       {if errorMessage = @props.errorMessage
-        <G.Toast status='critical' onClose={@onErrorToastClose}>
+        <G.Toast status='critical' onClose={@props.onErrorToastClose}>
           {errorMessage}
         </G.Toast>
       }
@@ -59,12 +56,17 @@
       }
     </G.App>

+{userErrorAcknowledged} = require '/imports/redux/actions/errors.coffee'
+
 mapStateToProps = (state) ->
-  errorMessage: null
+  errorMessage: state.error?.message
   infoMessage: null
   isLoggedIn: state.user?

-module.exports = connect(mapStateToProps) App
+mapDispatchToProps = (dispatch) ->
+  onErrorToastClose: -> dispatch userErrorAcknowledged()
+
+module.exports = connect(mapStateToProps, mapDispatchToProps) App

 # module.exports = createContainer (props) ->
 #   errorMessage: props..globalErrorMessage()


New function waitForExecution

New function waitForExecution

--- actions/nc.coffee
+++ actions/nc.coffee
@@ -8,84 +8,109 @@
 ###
 nc
 ===
-
-`waitForConnection(host, port, [timeout], callback)`
-`waitForConnection(hosts, port, [timeout], callback)`
-`waitForConnection(hosts_ports, [timeout], callback)`
-
 arbitrary TCP and UDP connections and listens.
 ###

 module.exports.push module.exports.configure = (ctx) ->
-  ctx.waitForConnection = (host, port, timeout, callback) ->
-    if typeof host is 'string'
-      options = [host: host, port: port]
-    else if Array.isArray(host) and typeof port is 'number'
-      options = for h in host then host: h, port: port
+  inc = 0
+  ctx.waitForExecution = () ->
+    if typeof arguments[0] is 'string'
+      ###
+      Argument "cmd" is a string:
+      `waitForConnection(cmd, [options], callback)`
+      ###
+      cmd = arugments[0]
+      options = arguments[1]
+      callback = arguments[2]
+    else if typeof arguments[0] is 'object'
+      ###
+      Argument "cmd" is a string:
+      `waitForConnection(options, callback)`
+      ###
+      options = arguments[0]
+      callback = arguments[1]
+      cmd = options.cmd
+    if typeof options is 'function'
+      callback = options
+      options = {}
+    options.interval = 2000
+    ctx.log "Wait for command to execute"
+    ctx.run.emit 'wait', ctx
+    running = false
+    run = ->
+      return if running
+      running = true
+      ctx.execute
+        cmd: cmd
+        code: options.code or 0
+        code_skipped: options.code_skipped
+      , (err, ready, stdout, stderr) ->
+        running = false
+        return if not err and not ready
+        clearInterval clear if clear
+        ctx.run.emit 'waited', ctx
+        callback err, stdout, stderr
+    clear = setInterval ->
+      run()
+    , options.interval
+    run()
+  ###
+  Options include:
+  *   `timeout`
+  ###
+  ctx.waitForConnection = () ->
+    if typeof arguments[0] is 'string'
+      ###
+      Argument "host" is a string and argument "port" is a number:
+      `waitForConnection(host, port, [options], callback)`
+      ###
+      servers = [host: arguments[0], port: arguments[1]]
+      options = arguments[2]
+      callback = arguments[3]
+    else if Array.isArray(arguments[0]) and typeof arguments[1] is 'number'
+      ###
+      Argument "hosts" is an array of string and argument "port" is a number:
+      `waitForConnection(hosts, port, [options], callback)`
+      ###
+      servers = for h in arguments[0] then host: h, port: arguments[1]
+      options = arguments[2]
+      callback = arguments[3]
     else
-      options = host
-      callback = timeout
-      timeout = port
-    if typeof timeout is 'function'
-      callback = timeout
-      timeout = null
-
-    each(options)
+      ###
+      Argument "servers" is an array of object with the host and port properties:
+      `waitForConnection(servers, [options], callback)`
+      ###
+      servers = arguments[0]
+      options = arguments[1]
+      callback = arguments[2]
+    if typeof options is 'function'
+      callback = options
+      options = {}
+    each(servers)
     .parallel(true)
-    .on 'item', (option, next) ->
-      if timeout
-        rand = Date.now()
+    .on 'item', (server, next) ->
+      if options.timeout
+        rand = Date.now() + inc++
         timedout = false
         clear = setTimeout ->
           timedout = true
           ctx.touch
             destination: "/tmp/#{rand}"
           , (err) -> # nothing to do
-        , timeout
-        cmd = "while [[ ! `nc -z -w5 #{option.host} #{option.port}` ]] && [[ ! -f /tmp/#{rand} ]]; do sleep 2; done;"
+        , options.timeout
+        cmd = "while [[ ! `nc -z -w5 #{server.host} #{server.port}` ]] && [[ ! -f /tmp/#{rand} ]]; do sleep 2; done;"
       else
-        cmd = "while ! nc -z -w5 #{option.host} #{option.port}; do sleep 2; done;"
-      ctx.log "Wait for #{option.host} #{option.port}"
-      ctx.run.emit 'wait', ctx, option.host, option.port
+        cmd = "while ! nc -z -w5 #{server.host} #{server.port}; do sleep 2; done;"
+      ctx.log "Wait for #{server.host} #{server.port}"
+      ctx.run.emit 'wait', ctx, server.host, server.port
       ctx.execute
         cmd: cmd
       , (err, executed) ->
         clearTimeout clear if clear
-        err = new Error "Reached timeout #{timeout}" if not err and timedout
-        next err, ->
-          ctx.run.emit 'waited', ctx, option.host, option.port
+        err = new Error "Reached timeout #{options.timeout}" if not err and timedout
+        ctx.run.emit 'waited', ctx, server.host, server.port
+        next err
     .on 'both', callback
-    # if timeout
-    #   each(options)
-    #   .parallel(true)
-    #   .on 'item', (option, next) ->
-    #     rand = Date.now()
-    #     timedout = false
-    #     clear = setTimeout ->
-    #       timedout = true
-    #       ctx.touch
-    #         destination: "/tmp/#{rand}"
-    #       , (err) -> # nothing to do
-    #     , timeout
-    #     ctx.log "Wait for #{option.host} #{option.port}"
-    #     ctx.execute
-    #       cmd: "while [[ ! `nc -z -w5 #{option.host} #{option.port}` ]] && [[ ! -f /tmp/#{rand} ]]; do sleep 2; done;"
-    #     , (err, executed) ->
-    #       clearTimeout clear
-    #       err = new Error "Reached timeout #{timeout}" if not err and timedout
-    #       next err
-    #   .on 'both', callback
-    # else
-    #   each(options)
-    #   .parallel(true)
-    #   .on 'item', (option, next) ->
-    #     ctx.log "Wait for #{option.host} #{option.port}"
-    #     ctx.execute
-    #       cmd: "while ! nc -z -w5 #{option.host} #{option.port}; do sleep 2; done;"
-    #     , (err, executed) ->
-    #       next err
-    #   .on 'both', (err) ->
-    #     callback err

 module.exports.push name: 'NC # Install', timeout: -1, callback: (ctx, next) ->


fix imports in test

fix imports in test

--- test/context.test.coffee
+++ test/context.test.coffee
@@ -60,9 +60,9 @@
       complete_callback = ->
       ctx = null
       result = null
-      base_context = Context.create_base_context(imports: ['builtins', 'compat'])
+      base_context = Context.create_base_context(imports: ['builtins.*'])
       base_context.modules.test_module = test_module
-      base_context.imports.push 'test_module'
+      base_context.imports.push 'test_module.*'
       ctx = Context.create_context base_context

     it 'can run javascript strings', ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -9,6 +9,6 @@

   player.include(Controllable)

-  e
+  keydown.le

 module()


fixing weird test stuff

fixing weird test stuff

git-svn-id: 00f01ee4f729ccc52c3e336777c3e81b5adc88db@122017 ef392f78-ee14-0410-84e5-9db46baae5bb

--- test/e2e/spec/map.coffee
+++ test/e2e/spec/map.coffee
@@ -1,7 +1,4 @@
 describe "map", () ->
-
-    beforeEach () ->
-        browser.get "http://localhost:9001"

     it "should show the correct markers", () ->
         browser.get "http://localhost:9001/#?lang=sv&cqp=%5B%5D&corpus=suc2&page=0&show_map&search=lemgram%7Cskog..nn.1&result_tab=1"


Modification to unit test for Node versions 0.8 and 0.10

--- test/request.spec.coffee
+++ test/request.spec.coffee
@@ -267,6 +267,9 @@
       server = require('http').createServer (req, resp) ->
         app(req, resp)

+      if server.setTimeout
+        server.setTimeout(1)
+
       beforeEach (done) ->
         data = ''; error = null

@@ -320,6 +323,9 @@
           done()

       it 'emits error when stream length is less than content-length header', (done) ->
+        if server.setTimeout == undefined
+          return done()
+
         AWS.HttpClient.streamsApiVersion = 1

         app = (req, resp) ->


Moved the version to Dropzone.version.

Moved the version to Dropzone.version.

But every instance copies it to a member variable.

--- src/dropzone.coffee
+++ src/dropzone.coffee
@@ -31,8 +31,6 @@
 noop = ->

 class Dropzone extends Em
-
-  version: "2.0.3-dev"

   ###
   This is a list of all available events you can register on a dropzone object.
@@ -235,6 +233,9 @@
                       """

   constructor: (@element, options) ->
+    # For backwards compatibility since the version was in the prototype previously
+    @version = Dropzone.version
+
     @defaultOptions.previewTemplate = @defaultOptions.previewTemplate.replace /\n*/g, ""

@@ -611,6 +612,9 @@

+Dropzone.version = "2.0.3-dev"
+
+
 # This is a map of options for your different dropzones. Add configurations
 # to this object for your different dropzone elemens.
 #


default to http

default to http

--- src/modules/link-tooltip.coffee
+++ src/modules/link-tooltip.coffee
@@ -2,7 +2,7 @@

 enterEditMode = (url) ->
-  url = 'https://' + url unless /^http[s]?:\/\//.test(url)
+  url = 'http://' + url unless /^http[s]?:\/\//.test(url)
   @tooltipInput.value = url
   Scribe.DOM.addClass(@tooltip, 'editing')


Added OOP usage test

Added OOP usage test

--- test/io_spec.coffee
+++ test/io_spec.coffee
@@ -20,3 +20,21 @@

     it "factorial function", ->
       expect(ioEval("""fact := method(n, if (n == 0, 1, n * fact (n - 1))); fact(5)""")).toBe(120)
+
+  describe "Usage", ->
+    it "moveRight, say", ->
+      history = []
+      log = (s) ->
+        expect(s).toEqual "hello"
+        history.push s
+      thisValue = {say: log}
+      thisValue.moveDown = () ->
+        expect(this).toEqual thisValue
+        history.push 'moveDown'
+
+      aether = new Aether language: 'io'
+      code = """moveDown;say("hello")"""
+      aether.transpile code
+      method = aether.createMethod thisValue
+      aether.run method
+      expect(history).toEqual(['moveDown', 'hello'])


movable velocity and acceleration getters

--- test/movable.coffee
+++ test/movable.coffee
@@ -37,6 +37,7 @@
     velocity: Point(7, 4)
     acceleration: Point(1, -0.3)

+
   particle.update(4)

   equals particle.I.velocity.x, 11


Fix coverage test

Fix coverage test

--- src/pipe/transpile/index.coffee
+++ src/pipe/transpile/index.coffee
@@ -32,7 +32,7 @@
     .pipe -> lib.pipe.if(
       options.coffeeScript,
       lib.pipe.if(
-        options.coffeeCoverage?
+        options.coffeeCoverage
         coffeeCoverage(options.coffeeCoverage)
         lib.transform.transpile.coffeeScript(config.transform.transpile.coffeeScript)
       )


Fix access to undefined root property

Fix access to undefined root property

The ::filterDefined transform unfortunately doesn't prevent an undefined
initial value when applied to behaviors.

--- src/pane-container-model.coffee
+++ src/pane-container-model.coffee
@@ -14,9 +14,10 @@

   constructor: ->
     super
-    @subscribe @$root.filterDefined(), (root) =>
-      root.parent = this
-      root.focusContext = @focusContext
+    @subscribe @$root, (root) =>
+      if root?
+        root.parent = this
+        root.focusContext = @focusContext

   deserializeParams: (params) ->
     params.root = atom.deserializers.deserialize(params.root)


fix issues will testAllExamples script loading

--- testExamples.coffee
+++ testExamples.coffee
@@ -25,26 +25,42 @@
 ###
 module.exports = class TestExamples

+  constructor: (options={}) ->
+    @options = _.defaults options,
+      # specify additional scripts to load relative to your project root. Note that
+      # if a package named dist/#{package.json:name}.js exists, that is added automatically
+      addScripts: []
+
+
+
   # this is a suboptimal way of doing this.  I also tried and failed when using:
   #  - a script tag with a src,  no way to load it synchrously or detect it's load
   #  - wrapping this in another jsDom.env  - i think it ignores if already in a jsDom.env
   #
-  # It dumps the whole contents of the reactDatum lib and the compiled example into
-  # two static script tags in the dom and that makes the code instantly load and run
-  # and at this point we can be assured that we are...
-  @loadExample: (exampleScriptFile, done) ->
+  # It dumps the whole contents of the scrips and the compiled example into
+  # static script tags in the dom and that makes the code instantly load and run
+  # and at this point we can be assured that we are fully loaded
+  loadExample: (exampleScriptFile, done) ->
     # example files all expect to find an element with the id='demo' where they do
     # their rendering
-    $('body').html """
+    html = """

-
+

-
     """
+    # console.log "WTF", html
+
+    $('body').html(html)
+
+    #console.log "woohoo"

     done()

-  @testExample: (exampleFile) ->
+
+  testExample: (exampleFile) ->
     describe "Example: #{exampleFile}", =>
       it 'should render something', (done) =>
         @loadExample exampleFile, ->
@@ -53,12 +69,24 @@
           done()

-  @testAllExamples: (exampleDir='docs/examples') ->
+  testAllExamples: (exampleDir='docs/examples') ->
     for demo in configFile.examples.demos
       # all coffee and jsx get compiled to .js
       path = demo.path.replace(/(\.jsx|\.coffee|\.cjsx)/, '.js')
       @testExample(Path.join(exampleDir, path))

+  _renderScriptTags: () ->
+    scripts = @options.addScripts.concat([])
+    npmPackage = JSON.parse(fs.readFileSync('package.json'))
+    userDist = "dist/#{npmPackage.name}.js"
+    scripts.push(userDist) if fs.existsSync(userDist)
+
+    scriptTags = for script in scripts
+      ""
+
+    return scriptTags.join('\n')
+
+