Unused file

Unused file

Name is taken from package.json, not from file name

--- src/tools/name.coffee
+++ src/tools/name.coffee
@@ -1,3 +0,0 @@
-fs = require '../sys/fs'
-
-module.exports = fs.GetBaseName WScript.ScriptName


Make it work in IE11

Make it work in IE11

--- src/treeView.coffee
+++ src/treeView.coffee
@@ -8,7 +8,9 @@
     return false if event.target.tagName not in [ 'LI', 'OL' ] or (! event.target.classList.contains('item') and ! event.target.classList.contains('group'))

     # NOTE: Required for Firefox to start the actual dragging
-    event.dataTransfer.setData 'text/plain', null
+    # "try" is required for IE11 to not raise an exception
+    try
+      event.dataTransfer.setData 'text/plain', null

     dragged = event.target
     true


implemented get and create method options

--- src/typetalk.coffee
+++ src/typetalk.coffee
@@ -3,6 +3,7 @@
 {EventEmitter} = require 'events'
 Package        = require '../package'
 Hubot          = require 'hubot'
+Querystring    = require 'querystring'

 class Typetalk extends Hubot.Adapter
   # override
@@ -56,11 +57,13 @@

   Topic: (id) ->
     get: (opts, callback) =>
-      @get "/topics/#{id}", "", callback
+      params = Querystring.stringify opts
+      path = "/topics/#{id}?#{params}"
+      @get path, "", callback

     create: (message, opts, callback) =>
-      data =
-        message: message
+      data = opts
+      data.message = message
       @post "/topics/#{id}", data, callback

   get: (path, body, callback) ->


Add join as extracted method.

Add join as extracted method.

--- src/jnoid.coffee
+++ src/jnoid.coffee
@@ -22,6 +22,8 @@
 Jnoid.initial = (value) -> new Initial(value)
 Jnoid.next = (value) -> new Next(value)
 Jnoid.end = -> new End()
+
+Jnoid.join = (streamOfStreams)-> streamOfStreams.map(toEvent).flatMap(id)

 class Event
   isEnd: -> false
@@ -90,7 +92,7 @@
   map: (f)->
     @flatMap (x)-> Jnoid.unit(f(x))
   merge: (others...)->
-    Jnoid.fromList([@, others...]).map(toEvent).flatMap(id)
+    Jnoid.join Jnoid.fromList([@, others...])

 class Dispatcher
   constructor: (unfold, handleEvent) ->


mp4: Add doc

mp4: Add doc

--- mp4.coffee
+++ mp4.coffee
@@ -1206,7 +1206,7 @@
     obj.sampleNumbers = @sampleNumbers
     return obj

-# stsc: sample-to-chunk, partial data-offset information
+# stsc: number of samples for each chunk
 class SampleToChunkBox extends Box
   read: (buf) ->
     bits = new Bits buf
@@ -1330,7 +1330,7 @@
       obj.entrySizes = @entrySizes
     return obj

-# stco: index of each chunk
+# stco: chunk offsets relative to the beginning of the file
 class ChunkOffsetBox extends Box
   read: (buf) ->
     bits = new Bits buf
@@ -1342,6 +1342,7 @@
       @chunkOffsets.push bits.read_uint32()
     return

+  # Returns a position of the chunk relative to the beginning of the file
   getChunkOffset: (chunkNumber) ->
     if (chunkNumber <= 0) or (chunkNumber > @chunkOffsets.length)
       throw new Error "Chunk number of out of range: #{chunkNumber}"


Spacing.

Spacing.

--- src/lunch.coffee
+++ src/lunch.coffee
@@ -18,6 +18,6 @@

 module.exports = (robot) ->
   robot.hear /lunch/i, (msg) ->
-  	timezone = process.env.HUBOT_MOMENT_TIMEZONE || "Europe/London"
+    timezone = process.env.HUBOT_MOMENT_TIMEZONE || "Europe/London"
     isAppropriateLunchTime = moment().tz(timezone).getHours() < 12
     if isAppropriateLunchTime then msg.send "Hey #{msg.message.user.name}, isn't it a bit early to start talking about lunch?"


If one packet is requested, output it alone, otherwise output all in array

--- src/utils/dump.coffee
+++ src/utils/dump.coffee
@@ -15,17 +15,20 @@
     .option('--amount <number>', 'How many messages to dump', Number, 1)
     .parse(process.argv)

-  received = 0
   messaging = msgflo.transport.getClient program.broker,
     prefetch: 1
   messaging.connect (err) ->
     return onError err if err
+    packetsReceived = []

     onResult = (msg) ->
-      console.log JSON.stringify msg.data
-      received++
+      packetsReceived.push msg.data
       messaging.ackMessage msg
-      return unless received >= program.amount
+      return unless packetsReceived.length >= program.amount
+      if program.amount is 1
+        console.log JSON.stringify packetsReceived[0]
+      else
+        console.log JSON.stringify packetsReceived
       messaging.disconnect (disconnectErr) ->
         return onError disconnectErr if disconnectErr
         onComplete()


Catch case where player joined late and is unknown

--- src/Player.coffee
+++ src/Player.coffee
@@ -28,6 +28,9 @@
       true

   snap: (player) ->
+    # TODO: add players that join late so this doesn't happen
+    if not player?
+      return
     # draw a line from current player to other player
     line        = @two.makeLine(@pos.x, @pos.y, @pos.x, @pos.y)
     line.stroke = "rgba(0, 255, 0, 1)"


Added docs.

Added docs.

--- src/Setter.coffee
+++ src/Setter.coffee
@@ -31,10 +31,13 @@
     else
       lodash.cloneDeep(src)

-   # Deeply merges defaults, relying on _.merge(a,b) returning a if it isn't an object to prevent
-   # source property values overriding their defined destinations.
+  # @param {Object} object
+  # @param {Object} [defaults]
+  # @returns {Object} The object argument. If defaults is defined it is deeply merged.
+  # NOTE: Relying on _.merge(A,B) returning A if it isn't an object to prevent
+  # source property values overriding their defined destinations.
   defaults: lodash.partialRight(lodash.merge, deep)

-   # @param {*} value
-   # @returns Whether the given value is not an non-empty string, null, undefined or NaN.
+  # @param {*} value
+  # @returns Whether the given value is not an non-empty string, null, undefined or NaN.
   isDefined: (value) -> value != '' && value? && (!Types.isNumber(value) || !isNaN(value))


add request to authorizer

add request to authorizer

--- src/action.coffee
+++ src/action.coffee
@@ -53,7 +53,7 @@
       schemes = [schemes]

     if schemes? && context.authorizer?
-      result = context.authorizer(schemes, resource, @name)
+      result = context.authorizer(schemes, resource, @name, request)
       if result?
         {scheme, credential} = result
         request.headers["Authorization"] = "#{scheme} #{credential}"


Added a timestamp to the message

Added a timestamp to the message

If you leverage the ambush but jump in and out of the channel,
having a timestamp would make life easier :)

--- src/ambush.coffee
+++ src/ambush.coffee
@@ -15,9 +15,9 @@

 appendAmbush = (data, toUser, fromUser, message) ->
   data[toUser.name] or= []
-
+
   data[toUser.name].push [fromUser.name, message]
-
+
 module.exports = (robot) ->
   robot.brain.on 'loaded', =>
     robot.brain.data.ambushes ||= {}
@@ -26,13 +26,13 @@
     users = robot.brain.usersForFuzzyName(msg.match[1].trim())
     if users.length is 1
       user = users[0]
-      appendAmbush(robot.brain.data.ambushes, user, msg.message.user, msg.match[2])
+      appendAmbush(robot.brain.data.ambushes, user, msg.message.user, "#{msg.match[2]} sent at #{new Date()}")
       msg.send "Ambush prepared"
     else if users.length > 1
       msg.send "Too many users like that"
     else
       msg.send "#{msg.match[1]}? Never heard of 'em"
-
+
   robot.hear /./i, (msg) ->
     return unless robot.brain.data.ambushes?
     if (ambushes = robot.brain.data.ambushes[msg.message.user.name])


support x days, x weeks, default to 2 weeks for start date

--- src/retro.coffee
+++ src/retro.coffee
@@ -3,6 +3,7 @@
 #
 # Commands:
 #   [good|bad|park]: <comment> - store a comment
+#   hubot retro - show all comments in the last 2 weeks
 #   hubot retro <month>/<day>[/<year>] - show all comments since <month>/<day>[/<year>]
 #   hubot retro <month>/<day>[/<year>] <month>/<day>[/<year>] - show all comments between the given dates

@@ -16,20 +17,29 @@

   robot.respond /retro\s*([^\s]+)?\s?([^\s]+)?$/i, (msg) ->

-    start_date = date_from_string(msg.match[1])
-    unless start_date?
-      msg.send "Please specify a start date as <month>/<day> or <month>/<day>/<year>"
-      return
+    end_date = new Date()

-    end_date = new Date()
-    end_date_string = msg.match[2]
-    if end_date_string?
-      end_date = date_from_string(end_date_string)
-      unless end_date
-        msg.send "Please specify the end date as <month>/<day> or <month>/<day>/<year> or leave emtpy for the current date"
+    if (!msg.match[1]?)
+      start_date = weeks_ago(2)
+    else if msg.match[2]?.match(/weeks?/)
+      start_date = weeks_ago(parseInt(msg.match[1]))
+    else if msg.match[2]?.match(/days?/)
+      start_date = days_ago(parseInt(msg.match[1]))
+    else
+      start_date = date_from_string(msg.match[1])
+      unless start_date?
+        msg.send "Please specify a start date as <month>/<day>, <month>/<day>/<year>, <number> weeks, <number> days, or just leave blank for default 2 weeks"
         return

-    msg.send "Showing retro comments from #{start_date} to #{end_date}.\n"
+      end_date_string = msg.match[2]
+      if end_date_string?
+        end_date = date_from_string(end_date_string)
+        unless end_date
+          msg.send "Please specify the end date as <month>/<day> or <month>/<day>/<year> or leave emtpy for the current date"
+          return
+
+
+    msg.send "Showing retro comments from #{start_date.toLocaleDateString("en-US")} to #{end_date.toLocaleDateString("en-US")}.\n"

     items = {}
     items.good = []
@@ -63,6 +73,10 @@

 date_from_string = (string) ->
   return unless string?
+
+  weeks_arr = string.match(/(\d)\s*\weeks?/)
+  return weeks_ago(weeks_arr[1]) if weeks_arr?
+
   date_arr = string.split('/')
   month = parseInt(date_arr[0]) - 1
   day = parseInt(date_arr[1])
@@ -82,6 +96,13 @@
       year += (Math.floor(today.getFullYear() / 100) * 100)

   new Date(year, month, day)
+
+days_ago = (days) ->
+  milliseconds_per_day = 86400000
+  new Date(+new Date - milliseconds_per_day * (days - 1))
+
+weeks_ago = (weeks) ->
+  days_ago(weeks * 7)

 handle_comment = (msg) ->
   type = msg.match[0]


msgflo-setup: Add options for participant setup

--- src/setup.coffee
+++ src/setup.coffee
@@ -169,10 +169,15 @@
   program
     .arguments('<graph.fbp/.json>')
     .option('--broker <URL>', 'URL of broker to connect to', String, null)
+    .option('--participants', 'Also set up participants, not just bindings', Boolean, false)
+    .option('--only', 'Only set up these participants', String, '')
+    .option('--ignore', 'Do not set up these participants', String, '')
+    .option('--library <FILE.json>', 'Library definition to use', String, 'package.json')
     .action (gr, env) ->
       graph = gr
     .parse args

+  program.libraryfile = program.library
   program.graphfile = graph
   return program

@@ -200,8 +205,15 @@
     program.help()
     process.exit()

-  setupBindings options, (err, bindings) ->
+  maybeSetupParticipants = (options, callback) ->
+    return callback null, {}
+  maybeSetupParticipants = setupParticipants if options.participants
+
+  maybeSetupParticipants options, (err, p) ->
     throw err if err
-
-    console.log 'Set up bindings:\n', pretty bindings
-
+    console.log 'Set up participants', p
+
+    setupBindings options, (err, bindings) ->
+      throw err if err
+      console.log 'Set up bindings:\n', pretty bindings
+


Update slack.attachment to use @robot reference for name

--- src/slack.coffee
+++ src/slack.coffee
@@ -265,7 +265,7 @@

     msg.text = data.text

-    if data.username && data.username != robot.name
+    if data.username && data.username != @robot.name
       msg.as_user = false
       if data.icon_url?
         msg.icon_url = data.icon_url


add a single record to the collection when @refresh() is called with something other than an array

--- src/spine.coffee
+++ src/spine.coffee
@@ -115,8 +115,11 @@

   @refresh: (values, options = {}) ->
     @records = {} if options.clear
-
-    for record in @fromJSON(values)
+    records = @fromJSON(values)
+
+    records = [records] unless isArray(records)
+
+    for record in records
       record.newRecord    = false
       record.id           or= guid()
       @records[record.id] = record


restore the old behavior of set/merge where merge does a deep merge and set does a shallow merge.

--- src/store.coffee
+++ src/store.coffee
@@ -156,12 +156,12 @@
 			"""

 		if _.isString(name)
-			value = Immutable.fromJS val
-			@_properties = @_properties.set name, Immutable.fromJS(value)
+			obj = {}
+			obj[name] = Immutable.fromJS(val)
+			@_properties = @_properties.merge Immutable.Map obj

 		if _.isObject(name)
-			value = Immutable.fromJS name
-			@_properties = Immutable.fromJS(name)
+			@_properties = @_properties.merge Immutable.fromJS name

 		return @


use @

use @

--- src/token.coffee
+++ src/token.coffee
@@ -57,7 +57,7 @@

       outputTokens
     else
-      return [this] if this.isAtomic
+      return [this] if @isAtomic

       if breakOutLeadingWhitespace
         return [this] unless /^[ ]|\t/.test(@value)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -44,7 +44,8 @@
     properties = Object.extend({}, properties) # Make a local copy

     easing = properties.easing || "linear"
-    complete = properties.compl
+    complete = properties.complete
+
     delete properties.easing
     delete properties.complete


Fixed issue when comparison between two nodes fail

This happens when there's extra elements rendered on the page which are
informative but not tracked (contenteditable=false)

--- lib/ecrire/app/assets/javascripts/admin/editor/content.coffee
+++ lib/ecrire/app/assets/javascripts/admin/editor/content.coffee
@@ -260,8 +260,18 @@

   same: (node1, node2) =>
+    node1 = node1.cloneNode(true)
+    node2 = node2.cloneNode(true)
+
+    for el in node1.querySelectorAll('[contenteditable=false]')
+      el.remove()
+
+    for el in node2.querySelectorAll('[contenteditable=false]')
+      el.remove()
+
     node1.nodeName == node2.nodeName &&
     node1.innerHTML.trim() == node2.innerHTML.trim()
+


feat(vm copy): allow snapshot copy. Related to vatesfr/xo-web#1353

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -550,7 +550,7 @@
 }

 copy.resolve = {
-  vm: [ 'vm', 'VM', 'administrate' ]
+  vm: [ 'vm', ['VM', 'VM-snapshot'], 'administrate' ]
   sr: [ 'sr', 'SR', 'operate' ]
 }


Bigger markers for !IE8.

Bigger markers for !IE8.

--- src/views.coffee
+++ src/views.coffee
@@ -145,7 +145,7 @@
             unit_list.each (unit) =>
                 color = colors.unit_color(unit, @selected_services) or 'rgb(255, 255, 255)'
                 iconSize = 50
-                if get_ie_version() < 9
+                if get_ie_version() and get_ie_version() < 9
                     iconSize *= .8
                 icon = new widgets.CanvasIcon iconSize, color
                 location = unit.get('location')


Removed a log statement.

Removed a log statement.

--- src/watch.coffee
+++ src/watch.coffee
@@ -177,7 +177,6 @@
     _compile()

   _compile = ->
-    logging.info "processing #{source}"
     try
       switch sysPath.extname(source)
         when '.coffee'


remove a console.log

remove a console.log

--- server/app/bongo/models/account.coffee
+++ server/app/bongo/models/account.coffee
@@ -164,7 +164,7 @@
           prefs[granularity] = if prefs[granularity] then 'instant' else 'never'
         user.update {$set: emailFrequency: prefs}, callback

-  glanceMessages: secure (client, callback)-> console.log 'glancing messages'
+  glanceMessages: secure (client, callback)->

   glanceActivities: secure (client, callback)->
     @fetchActivities {'data.flags.glanced': $ne: yes}, (err, activities)->


Set watch to default task.

Set watch to default task.

--- build-config/gulpfile.coffee
+++ build-config/gulpfile.coffee
@@ -15,6 +15,8 @@
 overlayPath = [
   './overlay/**/*'
 ]
+
+gulp.task 'default',['watch']

 gulp.task 'watch',['watch:assets', 'webpack:watch']


code clean

code clean

--- server/processes/imap_scheduler.coffee
+++ server/processes/imap_scheduler.coffee
@@ -38,10 +38,8 @@
         if scheduler = @instances[accountID]
             return Promise.resolve scheduler

-        pAccount = if account then Promise.resolve account
-        else Account.findPromised accountID
-        pAccount.then (account) =>
-
+        Promise.resolve account or Account.findPromised accountID
+        .then (account) =>
             scheduler = if (not account?) or account.isTest() then new TestScheduler()
             else new ImapScheduler account.makeImapConfig()
             @instances[accountID] = scheduler
@@ -160,9 +158,6 @@
     # Returns a {Promise} for the return value of gen
     queueWithBox: (urgent, box, gen) ->
         @queue urgent, (imap) ->
-
-            uidvalidity = null
-
             imap.openBox box.path
             .then (imapbox) ->
                 unless imapbox.persistentUIDs


deprecate `staticGzip` (#45)

deprecate `staticGzip` (#45)

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -294,6 +294,11 @@
         delete options.path
         express.static(p,options)
       staticGzip: (options) ->
+        # Remove in June 2013.
+        console.error '''
+          staticGzip middleware is deprecated, please investigate using
+          standard `compress` and `staticCache` middleware instead
+        '''
         if typeof options is 'string'
           options = path: options
         options ?= {}


* let a handler can tell what event trigger it.  This is part of issue #3.

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -134,6 +134,7 @@
           socket.on name, (data) ->
             ctx = build_ctx(socket)
             ctx.data = data
+            ctx.event = name
             h = ws_handlers[name]
             h.apply(ctx, [ctx])
       ws_handlers[name] = h
@@ -298,6 +299,7 @@
           socket.on name, (data) ->
             ctx = build_ctx(socket)
             ctx.data = data
+            ctx.event = name
             h = ws_handlers[name]
             switch app.settings['databag']
               when 'this' then h.apply(data, [ctx])


remove ambiguity in ajax url

remove ambiguity in ajax url

--- app/assets/javascripts/more_items.js.coffee
+++ app/assets/javascripts/more_items.js.coffee
@@ -9,7 +9,7 @@

     $.ajax
       type: "GET"
-      url: $(this).attr("href")
+      url: $(this).attr("action")
       data: offset: nb_items
       dataType: "script"
       success: ->


Change search back to .search, needed on page.

--- web/site/search.coffee
+++ web/site/search.coffee
@@ -102,7 +102,7 @@

     # Def search: the function that is actually calling the search from Haskell.
     # Get the results from Solr and pass them into parseResults.
-    search = (query = "") ->
+    $scope.search = (query = "") ->
       # This is for if we want to pass an argument into this...
       if query.length > 0
         $scope.query = query


Generate unit tests with brunch g.

Generate unit tests with brunch g.

--- src/brunch.coffee
+++ src/brunch.coffee
@@ -121,7 +121,7 @@

   # We'll additionally generate tests for 'script' languages.
   initTests = (parentDir, callback) ->
-    return callback() unless languageType is 'script'
+    return callback() unless languageType is 'javascripts'
     parentDir ?= sysPath.join rootPath, 'test', 'unit', "#{type}s"
     fullPath = sysPath.join parentDir, "#{name}_test.#{extension}"
     if generate


vm.delete(): Fix `::` usage in CoffeeScript.

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -275,10 +275,10 @@
       return
     )

-    @releaseLimitsInResourceSet(
+    pCatch.call(@releaseLimitsInResourceSet(
       @computeVmResourcesUsage(vm),
       resourceSet
-    )::pCatch(noop)
+    ), noop)

   return xapi.deleteVm(vm._xapiId, deleteDisks)


Fixed tabs

Fixed tabs

--- src/lib/docpad.coffee
+++ src/lib/docpad.coffee
@@ -2547,7 +2547,7 @@

 		# Content Type
 		contentType = document.get('contentTypeRendered') or document.get('contentType')
-    res.setHeader('Content-Type', contentType);
+		res.setHeader('Content-Type', contentType);

 		# Send
 		dynamic = document.get('dynamic')


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/oscillator.coffee
+++ src/oscillator.coffee
@@ -3,7 +3,7 @@

 @name Oscillator
 @constructor
-@params {Number}
+@params {Number} amplitude
 ###
 Oscillator = (options={}) ->
   {amplitude, period, offset} = options


Clean up include/resolveAs checks.

Clean up include/resolveAs checks.

--- src/bundle.coffee
+++ src/bundle.coffee
@@ -24,15 +24,16 @@
   basePath      = opts.base ? opts.src
   sourceMapRoot = basePath ? ('/' + path.dirname opts.entry)

-  # Make sure we have a regular expression
+  # Make sure we have sane exclude, include, resolveAs to pass to modules
   exclude   = toRegex opts.exclude
-  include   = null
-  resolveAs = null
+  include   = opts.include   ? {}
+  resolveAs = opts.resolveAs ? opts.resolve ? {}

-  if (Object.keys opts.include ? {}).length
-    include   = opts.include
-  if (Object.keys (opts.resolveAs ? opts.resolve ? {})).length
-    resolveAs = opts.resolveAs
+  # Do not pass empty objects
+  unless (Object.keys include).length
+    include = null
+  unless (Object.keys resolveAs).length
+    resolveAs = null

   # Build module
   mod = new Module opts.entry,


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -7,7 +7,7 @@
       height: App.height
     screen: Rectangle
       x: App.width / 2
-      y: App.
+      y: App.height / 2
       width: App.width
       height: App.height
     deadzone: Point(0, 0)


:pisces::heavy_exclamation_mark: Updated at https://danielx.net/editor/

--- pixie.cson
+++ pixie.cson
@@ -16,3 +16,6 @@
   util: "distri/util:v0.1.0"
 width: 1280
 height: 720
+publish:
+  s3:
+    basePath: "public/danielx.net"


JGroup: create: share trial credentials with group and owner if needed

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -487,6 +487,15 @@
           console.log 'created socialApiId ids'
           queue.next()

+      ->
+        { shareCredentials } = require '../computeproviders/teamutils'
+        account = client.connection.delegate
+
+        shareCredentials { group, account }, (err) ->
+          console.error err  if err
+          console.log 'shared credentials'
+          queue.next()
+
     ]

     if 'private' is group.privacy


workers: check for err before destructuring

--- workers/social/lib/social/models/siftscience.coffee
+++ workers/social/lib/social/models/siftscience.coffee
@@ -63,8 +63,10 @@
   @send = (client, event, data, callback)->
     siftScience = require('yield-siftscience') KONFIG.siftScience

-    @fetchUserInfo client, (err, {username, email, sessionToken})->
+    @fetchUserInfo client, (err, userInfo)->
       return callback err   if err
+
+      {username, email, sessionToken} = userInfo

       data["$user_id"]    = username
       data["$user_email"] = email


Adds a test

Adds a test

--- desktop/components/article/test/templates.coffee
+++ desktop/components/article/test/templates.coffee
@@ -4,6 +4,7 @@
 jade = require 'jade'
 fs = require 'fs'
 moment = require 'moment'
+markdown = require '../../../components/util/markdown'
 Article = require '../../../models/article'
 Articles = require '../../../collections/articles'
 fixtures = require '../../../test/helpers/fixtures.coffee'
@@ -87,6 +88,29 @@
     html.should.containEql 'article-sa-sticky-header'
     html.should.containEql ''
     html.should.not.containEql 'visible no-transition'
+
+  it 'super articles have markdown-supported footers', ->
+    html = render('index')
+      article: new Article
+        title: 'hi'
+        sections: []
+        contributing_authors: []
+        is_super_article: true
+      footerArticles: new Articles
+      superArticle: new Article
+        super_article:
+          partner_logo: 'http://logo.jpg'
+          partner_logo_link: 'http://logo.com'
+          partner_fullscreen_header_logo: 'http://fullscreen-logo.jpg'
+          footer_blurb: 'Article Test [Link](http://artsy.net)'
+      superSubArticles: {models: []}
+      crop: (url) -> url
+      resize: (u) -> u
+      moment: moment
+      sd: {}
+      asset: ->
+      markdown: markdown
+    html.should.containEql 'Link'

   it 'renders a TOC', ->
     html = render('index')


auto add models when cloning collection

auto add models when cloning collection

--- lib/client/javascripts/nali/collection.js.coffee
+++ lib/client/javascripts/nali/collection.js.coffee
@@ -10,6 +10,7 @@
     @adaptations = apply: [], cancel: []
     @ordering    = {}
     @adaptCollection()
+    @model.each ( model ) => @add model if model.isCorrect @filters
     @

   new: ( model, filters ) ->


color2 ->

color2 ->

--- src/color2.coffee
+++ src/color2.coffee
@@ -2789,10 +2789,10 @@
   Color.random = ->
     Color(rand(256), rand(256), rand(256))

-  Color.mix = (color1, Color, amount) ->
+  Color.mix = (color1, color2, amount) ->
     amount ||= 0.5

-    new_colors = [color1.r, color1.g, color1.b, color1.a].zip([Color.r, Color.g, Color.b, Color.a]).map (array) ->
+    new_colors = [color1.r, color1.g, color1.b, color1.a].zip([color2.r, color2.g, color2.b, color2.a]).map (array) ->
       (array[0] * amount) + (array[1] * (1 - amount))

     return Color(new_colors)


Implement ::observeScopedKeyPath using ::onDidChangeScopedKeyPath

--- src/config.coffee
+++ src/config.coffee
@@ -972,16 +972,8 @@
     @scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath, options)

   observeScopedKeyPath: (scope, keyPath, callback) ->
-    oldValue = @get(keyPath, {scope})
-
-    callback(oldValue)
-
-    didChange = =>
-      newValue = @get(keyPath, {scope})
-      callback(newValue) unless _.isEqual(oldValue, newValue)
-      oldValue = newValue
-
-    @emitter.on 'did-change', didChange
+    callback(@get(keyPath, {scope}))
+    @onDidChangeScopedKeyPath scope, keyPath, (event) -> callback(event.newValue)

   onDidChangeScopedKeyPath: (scope, keyPath, callback) ->
     oldValue = @get(keyPath, {scope})


Refactor spec setup

Refactor spec setup

--- src/setup.spec.coffee
+++ src/setup.spec.coffee
@@ -3,7 +3,7 @@
 else
   root = global

-if !root._spec_setup
+if not root._spec_setup
   root.sinon    = require 'sinon'
   root.mockery  = require 'mockery'
   root.chai     = require 'chai'
@@ -12,25 +12,27 @@

   sinonChai = require 'sinon-chai'
   chai.use sinonChai
-
   root._spec_setup = true

-before ->
+root.before ->
   mockery.enable useCleanCache: true
   mockery.warnOnUnregistered false
   mockery.warnOnReplace false

-beforeEach ->
-  root.eventric = require './'
+root.beforeEach ->
+  root.eventric     = require './'
+  root.eventricStub = sinon.createStubInstance (require './eventric')
+  #eventric.log.setLogLevel 'debug'

-
-afterEach ->
+root.afterEach ->
+  delete root.eventric
+  delete root.eventricStub
   mockery.resetCache()
   mockery.deregisterAll()
   sandbox.restore()

-after ->
+root.after ->
   mockery.disable()


Fix deprecate reference

Fix deprecate reference

--- src/cursor.coffee
+++ src/cursor.coffee
@@ -220,7 +220,7 @@
   getScopeDescriptor: ->
     @editor.scopeDescriptorForBufferPosition(@getBufferPosition())
   getScopes: ->
-    deprecate 'Use Cursor::getScopeDescriptor() instead'
+    Grim.deprecate 'Use Cursor::getScopeDescriptor() instead'
     @getScopeDescriptor()

   # Public: Returns true if this cursor has no non-whitespace characters before


убрана окраска карт

убрана окраска карт

--- app/assets/javascripts/map.coffee
+++ app/assets/javascripts/map.coffee
@@ -1,7 +1,6 @@
 $ ->
   map.init()
   map.show_places()
-  map.color_countries()

 map =
   #параметры карты
@@ -30,34 +29,6 @@
         app.places.objects.forEach(places.render)

         #TODO: сделать так, чтобы места появлялись на карте даже в случае отсутствия текущей геолокации
-
-  color_countries: ->
-    #окрашивает страны
-
-    field_name = 'geometry'
-    table_id = '1uL8KJV0bMb7A8-SkrIe0ko2DMtSypHX52DatEE4'
-
-    layer = new google.maps.FusionTablesLayer({
-      suppressInfoWindows: true,
-      query: {
-        select: field_name,
-        from: table_id
-      },
-      styles: [{
-        polygonOptions: {
-          fillColor: '#00FF00',
-          fillOpacity: 0.3
-        }
-      }, {
-        where: "Name = 'Russia'",
-        polygonOptions: {
-          fillColor: '#B10909'
-        }
-      }]
-    })
-
-    layer.setMap app.google_map
-

   init: ->


fix supplemental tutorial split designations

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -90,7 +90,7 @@
     ifFaved: false

     # classification counts at which to display supplementary tutorial
-    @whenToDisplayTips = [1, 7] # TODO: don't forget to add 4 after beta version
+    @whenToDisplayTips = [1, 2, 3] # TODO: don't forget to add 4 after beta version
     @splitDesignation = null

     @known_transits = ''
@@ -333,7 +333,7 @@
       @course.setRate 10
       $('#course-interval-setter').remove() # destroy custom course interval setter

-    else if @splitDesignation in ['a', 'd']
+    else if @splitDesignation in ['a', 'd', 'g', 'j']
       # console.log 'Setting mini-course interval to 5'
       # console.log 'Allowing custom course interval.'
       @course.setRate 5 # set default
@@ -370,7 +370,6 @@
     # reset fav
     @el.find(".toggle-fav").removeClass("toggled")

-    $('#graph-container').addClass 'loading-lightcurve'

     if window.location.origin != "http://planethunters.org"
@@ -381,6 +380,7 @@
     # console.log 'jsonFile: ', jsonFile

     # handle ui elements
+    $('#graph-container').addClass 'loading-lightcurve'
     @el.find('#loading-screen').fadeIn()
     @el.find('.star-id').hide()
     @el.find('#ui-slider').attr('disabled',true)
@@ -634,7 +634,7 @@
         @supplementalTutorial.start()

         # prompt user to opt in/out of mini course
-        if @course.count is 7
+        if @course.count is 3
           newElement = document.createElement('div')
           newElement.setAttribute 'class', "supplemental-tutorial-option-container"
           newElement.setAttribute 'style', "padding: 20px;"
@@ -647,11 +647,9 @@

           if @allowCustomCourseInterval
             $('#course-opt-in-label').html """
-
-
Launch mini-course every

+
Launch mini-course every

                 <input type="number" id="course-interval-sup-tut" class="course-interval" name="course-interval-sup-tut" value="5"></input>
-
 classifications!

-
+
 classifications!

             """
           else
             $('#course-opt-in-label').html "Yes, I want to learn more!"


load training lightcurve onClickTutorial

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -188,13 +188,17 @@
     @loadSubjectData()
     @el.find('#loading-screen').hide() # TODO: uncomment

-  loadSubjectData: ->
+  loadSubjectData: (jsonFile) ->
+    unless jsonFile?
+      jsonFile = jsonFile = @subject.selected_light_curve.location
+
+
     console.log 'loadSubjectData()'
     @el.find('#ui-slider').attr('disabled',true)
     @el.find(".noUi-handle").fadeOut(150)

     # TODO: use Subject data to choose the right lightcurve
-    jsonFile = @subject.selected_light_curve.location
+    # jsonFile = @subject.selected_light_curve.location
     # jsonFile = 'https://s3.amazonaws.com/demo.zooniverse.org/planet_hunter/beta_subjects/2442084_13-2.json' # TRAINING FILE

     # jsonFile = 'test_data/test_light_curve.json'
@@ -374,6 +378,10 @@

   onClickTutorial: ->
     console.log 'onClickTutorial()'
+
+    # load training subject
+    @loadSubjectData(jsonFile='https://s3.amazonaws.com/demo.zooniverse.org/planet_hunter/beta_subjects/2442084_13-2.json')
+
     @notify('Loading tutorial...')
     @initialTutorial.start()


Make the tutorial more aware of what's going on

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -68,6 +68,8 @@
     @el.addClass 'loading'

   onSubjectSelect: (e, subject) =>
+    @tutorial.end() if @tutorial.started? and not subject.metadata.tutorial
+
     @classification = new Classification {subject}
     @surface.marks[0].destroy() until @surface.marks.length is 0
     @surface.image.attr src: subject.location.standard
@@ -94,7 +96,7 @@

   onClickRestartTutorial: ->
     return if @tutorial.started?
-    getTutorialSubject().select()
+    getTutorialSubject().select() unless @classification?.subject.metadata.tutorial
     @tutorial.start()

   onClickFinish: ->


disable keybindings while playing

disable keybindings while playing

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -48,6 +48,7 @@
     # 'click button[name="no-tags"]'        : 'onClickNoTags'

     'keydown': (e) ->
+      return if @el.hasClass 'playing'  # disable while playing
       switch e.which
         when KEYS.one
           @showFrame(0)
@@ -58,7 +59,7 @@
         when KEYS.four
           @showFrame(3)
         when KEYS.space
-          @play()
+          @onClickPlay()

   elements:
     '.subject'                      : 'subjectContainer'
@@ -154,6 +155,8 @@
   onClickFourUp: ->
     console.log "4-up"

+    @markingSurface.svg.slideDown 100
+
     # flicker.disable() # find way to disable flicker

   onClickFlicker: ->
@@ -167,8 +170,7 @@
         @showFrame(i)

   onClickPlay: ->
-    # play only once at a time
-    if @el.hasClass 'playing' then return
+    return if @el.hasClass 'playing'  # play only once at a time

     @el.addClass 'playing'
     @markingSurface.disable()   # no marking while playing


add method to create course opt-in view

add method to create course opt-in view

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -637,27 +637,30 @@

         # prompt user to opt in/out of mini course
         if @course.count is 3
-          newElement = document.createElement('div')
-          newElement.setAttribute 'class', "supplemental-tutorial-option-container"
-          newElement.setAttribute 'style', "padding: 20px;"
-          newElement.innerHTML = """
-            <input class=\"mini-course-option\" name=\"mini-course-option\" type=\"checkbox\"></input>
-

-          """
-          # inject custom element into zootorial
-          @supplementalTutorial.container.getElementsByClassName('zootorial-content')[0].appendChild(newElement)
-
-          if @allowCustomCourseInterval
-            $('#course-opt-in-label').html """
-
Launch mini-course every

-                <input type="number" id="course-interval-sup-tut" class="course-interval" name="course-interval-sup-tut" value="5"></input>
-
 classifications!

-            """
-          else
-            $('#course-opt-in-label').html "Yes, I want to learn more!"
-
-          # # check box only if mini-course enabled
-          # $('.mini-course-option').prop 'checked', @courseEnabled
+          @createMiniCoursePrompt()
+
+          # check box only if mini-course enabled
+          $('.mini-course-option').prop 'checked', @courseEnabled
+
+  createMiniCoursePrompt: ->
+    newElement = document.createElement('div')
+    newElement.setAttribute 'class', "supplemental-tutorial-option-container"
+    newElement.setAttribute 'style', "padding: 20px;"
+    newElement.innerHTML = """
+      <input class=\"mini-course-option\" name=\"mini-course-option\" type=\"checkbox\"></input>
+

+    """
+    # inject custom element into zootorial
+    @supplementalTutorial.container.getElementsByClassName('zootorial-content')[0].appendChild(newElement)
+
+    if @allowCustomCourseInterval
+      $('#course-opt-in-label').html """
+
Launch mini-course every

+          <input type="number" id="course-interval-sup-tut" class="course-interval" name="course-interval-sup-tut" value="5"></input>
+
 classifications!

+      """
+    else
+      $('#course-opt-in-label').html "Yes, I want to learn more!"

   sendClassification: ->
     if User.current?


triggering update before game objects

triggering update before game objects

--- src/engine.coffee
+++ src/engine.coffee
@@ -48,6 +48,8 @@
     queuedObjects = []

     update = ->
+      self.trigger "update"
+
       [I.objects, toRemove] = I.objects.partition (object) ->
         object.update()

@@ -55,8 +57,6 @@

       I.objects = I.objects.concat(queuedObjects)
       queuedObjects = []
-
-      self.trigger "update"

     draw = ->
       canvas.withTransform I.cameraTransform, (canvas) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine.coffee
+++ src/engine.coffee
@@ -259,7 +259,7 @@
     modules = modules.without([].concat(I.excludedModules))

     Engine.defaultModules.each (moduleName) ->
-
+      moduleName = ""
       throw "#Engine.#{moduleName} is not a valid engine module" unless Engine[moduleName]

       self.include Engine[moduleName]


Fix variable name _k to k

Fix variable name _k to k

--- src/filter.coffee
+++ src/filter.coffee
@@ -379,7 +379,7 @@

 						if toprocess.length > 0
 							for k in [0..toprocess.length-1]
-								content += "<input type='checkbox' name='groupable_check_group' id='groupable_check_" + check_count + "' checked='checked' />" + toprocess[_k] + "
"
+								content += "<input type='checkbox' name='groupable_check_group' id='groupable_check_" + check_count + "' checked='checked' />" + toprocess[k] + "
"
 								check_count++

 							$('#groupable_att').append("
" + content + "
")


follow docs

follow docs

--- src/follow.coffee
+++ src/follow.coffee
@@ -1,7 +1,7 @@
 ###*
 The Follow module provides a simple method to set an object's
 velocity so that it will approach another object. This method
-relies on the objects having `bounds` methods
+relies on the objects having `bounds` method.

 player = GameObject


fix #88: prompt for access token before loading github urls

--- src/github.coffee
+++ src/github.coffee
@@ -51,29 +51,31 @@
           site = settings.get 'githubs', github.default()
           path = path.substr 1 if path[0] == '/'
           [user, repo, segments...] = path.split '/'
-          url = "#{site.api_base_url}/repos/#{user}/#{repo}/contents/#{segments.join '/'}"
+          url = github.to_api_url site, "/repos/#{user}/#{repo}/contents/#{segments.join '/'}"
         else
           site = github.get_github path
           if path.indexOf(site.api_base_url) == 0
-            url = path
+            url = URI path
           else
             uri = URI path
             path = uri.pathname()
             path = path.substr 1 if path[0] == '/'
             [user, repo, x, ref, segments...] = path.split '/'
-            url = "#{site.api_base_url}/repos/#{user}/#{repo}/contents/#{segments.join '/'}?ref=#{ref}"
+            url = github.to_api_url site, "/repos/#{user}/#{repo}/contents/#{segments.join '/'}", {ref}

       save_gist: (gist, options={}) ->
         github_host = options.github ? github.default()
         gh = settings.get 'githubs', github_host
-        http.post "#{gh.api_base_url}/gists?access_token=#{gh.access_token}", gist
+        http.post github.to_api_url(gh, '/gists'), gist
+
+      to_api_url: (instance, path, params={}) ->
+        result = URI("#{instance.api_base_url}#{path}").setQuery(params)
+        result.setQuery('access_token', instance.access_token) if instance.access_token?
+        result

       to_gist_url: (gist) ->
         build_url = (site, id) ->
-          url = site.api_base_url + "/gists/#{id}"
-          if site.access_token
-            url += "?access_token=#{site.access_token}"
-          url
+          github.to_api_url site, "/gists/#{id}"
         gist = gist.toString()
         if gist.indexOf('http') != 0
           site = settings.get 'githubs', github.default()
@@ -85,37 +87,47 @@
             [id, rest...] = URI(gist).filename().split '.'
             build_url site, id
           else
-            gist
+            URI gist

     cmd 'load', 'Loads a file from GitHub', (path, options={}) ->
       url = github.to_repo_url path
-      ensure_access @, url
       @async ->
-        @text "Loading file #{path}"
-        promise = github.get_repo_contents(url)
-        .then (file) =>
-          notebook.handle_file @, file, options
-        promise.fail (response) =>
-          @error response.statusText
-        promise
+        authorized = ensure_access @, url
+        authorized.then (url) =>
+          @text "Loading file #{path}"
+          promise = github.get_repo_contents(url)
+          .then (file) =>
+            notebook.handle_file @, file, options
+          promise.fail (response) =>
+            @error response.statusText
+          promise

     ensure_access = (ctx, url) ->
       unless url?
-        instance = settings.get 'githubs', github.default()
+        domain = github.default()
+        instance = settings.get 'githubs', domain
       else
         instance = github.get_github url
+        domain = url.hostname()
       if instance? and instance.requires_access_token and not instance.access_token?
         result = Q.defer()
         ctx.text 'Please set a GitHub access token:'
         input = ctx.input.text_input()
         button = ctx.input.button('Save')
-        button.map(input).onValue (access_token) ->
-          domain = URI(url).hostname()
+        user_details = button.map(input).flatMapLatest (access_token) ->
+          Bacon.combineTemplate
+            user: Bacon.fromPromise http.get github.to_api_url(instance, '/user').setQuery {access_token}
+            access_token: access_token
+          .changes()
+        user_details.onValue ({user, access_token}) =>
           global_settings.user_settings.set 'github', 'githubs', domain, 'access_token', access_token
-          result.resolve()
+          ctx.text "Logged in as #{user.name}"
+          result.resolve url?.setQuery {access_token}
+        user_details.onError =>
+          ctx.text "That access token didn't work. Try again?"
         result.promise
       else
-        Q true
+        Q url

     cmd 'gist', 'Loads a script from a gist', (gist, options={}) ->
       if arguments.length is 0
@@ -124,7 +136,7 @@
         url = github.to_gist_url gist
         @async ->
           authorized = ensure_access @, url
-          authorized.then =>
+          authorized.then (url) =>
             @text "Loading gist #{gist}"
             promise = http.get url
             promise.done (response) =>
@@ -142,7 +154,7 @@
             content: JSON.stringify notebook, undefined, 2
       @async ->
         authorized = ensure_access @
-        authorized.then =>
+        authorized.then (url) =>
           promise = github.save_gist gist
           promise.done (result) =>
             @html "#{result.html_url}"


No change.

No change.

--- src/groups.coffee
+++ src/groups.coffee
@@ -94,6 +94,11 @@
     utils.toArray desensetizeGroups(rdb.table("Groups").getAll(user_id, {index: "pendingUsers"}))

   rejectInvitation: (user_id, group_id) ->
+    ###
+    rdb.table("Groups").get(group_id).update({
+      pendingUsers: rdb.table("Groups").get(group_id)("pendingUsers").setDifference([user_id])
+    }, nonAtomic: true ).run(con)
+    ###
     (rdb.table("Groups").get(group_id).replace (doc) ->
       doc.merge pendingUsers: doc("pendingUsers").setDifference([user_id])).run(con)


Pass payload directly in @emit

Pass payload directly in @emit

--- src/client.coffee
+++ src/client.coffee
@@ -72,7 +72,7 @@
             for user in data
               @users[user.id] = user
             @logger.info 'Found '+Object.keys(data).length+' profiles.'
-            @emit 'profilesLoaded', { profiles: data }
+            @emit 'profilesLoaded', data
         else
             @logger.error 'Failed to load profiles from server.'
             @emit 'error', { msg: 'failed to load profiles'}
@@ -82,7 +82,7 @@
             for channel in data
               @channels[channel.id] = channel
             @logger.info 'Found '+Object.keys(data).length+' subscribed channels.'
-            @emit 'channelsLoaded', { channels: data }
+            @emit 'channelsLoaded', data
         else
             @logger.error 'Failed to get subscribed channels list from server: ' + data.error
             @emit 'error', { msg: 'failed to get channel list'}
@@ -90,7 +90,7 @@
     _onPreferences: (data, headers) =>
         if data && not data.error
             @preferences = data
-            @emit 'preferencesLoaded', { preferences: @preferences }
+            @emit 'preferencesLoaded', data
             @logger.info 'Loaded Preferences...'
         else
             @logger.error 'Failed to load Preferences...' + data.error
@@ -99,7 +99,7 @@
     _onMe: (data, headers) =>
         if data && not data.error
             @me = data
-            @emit 'meLoaded', { me: @me }
+            @emit 'meLoaded', data
             @logger.info 'Loaded Me...'
         else
             @logger.error 'Failed to load Me...' + data.error
@@ -107,7 +107,7 @@
     _onTeams: (data, headers) =>
         if data && not data.error
             @teams = data
-            @emit 'teamsLoaded', { teams: @teams }
+            @emit 'teamsLoaded', data
             @logger.info 'Found '+Object.keys(@teams).length+' teams.'
             for t in @teams
                 @logger.debug "Testing #{t.name} == #{@group}"
@@ -246,7 +246,7 @@
                 # Deprecated
                 @logger.info 'ACK ping'
                 @_lastPong = Date.now()
-                @emit 'ping'
+                @emit 'ping', message
             when 'posted'
                 @emit 'message', m
             when 'hello', 'typing', 'post_edit', 'post_deleted', 'user_added', 'user_removed', 'status_change'


add cs, cg, ct to known function list.

add cs, cg, ct to known function list.

--- src/coffee.coffee
+++ src/coffee.coffee
@@ -35,6 +35,9 @@
     'pause'
     'st'
     'ht'
+    'cs'
+    'cg'
+    'ct'
     'pu'
     'pd'
     'pe'


add new cloudtrail resources

add new cloudtrail resources

--- src/coffin.coffee
+++ src/coffin.coffee
@@ -37,6 +37,8 @@
         Application: null
         DeploymentConfig: null
         DeploymentGroup: null
+      CloudTrail:
+        Trail: null
       DataPipeline:
         Pipeline: null
       DynamoDB:


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine.coffee
+++ src/engine.coffee
@@ -145,7 +145,7 @@
     step = ->
       if !I.paused || frameAdvance
         elapsedTime = (1 / I.FPS)
-        update(secondsPerFrame)
+        update(elapsedTime)
         I.age += 1

       draw()


Update branch text from subscribeToBuffer

--- src/app/status-bar.coffee
+++ src/app/status-bar.coffee
@@ -47,6 +47,8 @@
     @buffer.on 'after-save.status-bar', => _.defer =>
       @updateBranchText()
       @updateBufferModifiedText()
+    @updateBranchText()
+    @updateBufferModifiedText()

   updateBufferModifiedText: ->
     if @buffer.isModified()


Fixed bug in string's zfill. Was calling __len__ on a JS string

--- src/builtin/string.coffee
+++ src/builtin/string.coffee
@@ -247,7 +247,7 @@
     if width <= @__len__()
       return @value
     zeroStr = new Str('0')
-    if @value.__len__() == 0
+    if @value.length == 0
       return zeroStr.__mul__(width)
     zeroCount = width - @__len__()
     if @value[0] == '-'


Update modules.coffee

Update modules.coffee

--- www/modules.coffee
+++ www/modules.coffee
@@ -1,6 +1,6 @@
 window.randomColor = ->
 	hex = "0123456789abcdef"
-	r=50+(Math.round(Math.random()*1000))%206;
+	r=50+(Math.round(Math.random()*1000))%125;
 	g=r*0.618;
 	b=r-g;


Pass only necessary arguments to mapSetAttribute. Adjust TODO.

--- src/coffee/mapping.coffee
+++ src/coffee/mapping.coffee
@@ -140,14 +140,14 @@

   mapValue: (rawVariant, attribute, languageHeader2Index, rowIndex) ->
     switch attribute.type.name
-      when CONS.ATTRIBUTE_TYPE_SET then @mapSetAttribute rawVariant[@header.toIndex attribute.name], attribute, languageHeader2Index, rowIndex
+      when CONS.ATTRIBUTE_TYPE_SET then @mapSetAttribute rawVariant[@header.toIndex attribute.name]
       when CONS.ATTRIBUTE_TYPE_LTEXT then @mapLocalizedAttrib rawVariant, attribute.name, languageHeader2Index
       when CONS.ATTRIBUTE_TYPE_NUMBER then @mapNumber rawVariant[@header.toIndex attribute.name], attribute.name, rowIndex
       when CONS.ATTRIBUTE_TYPE_MONEY then @mapMoney rawVariant[@header.toIndex attribute.name], attribute.name
       else rawVariant[@header.toIndex attribute.name] # works for text, enum and lenum

-  # We currently only support Set of (l)enum
-  mapSetAttribute: (raw, attribute, rowIndex) ->
+  # TODO: support set of ltext attributes!
+  mapSetAttribute: (raw) ->
     return unless @isValidValue(raw)
     rawValues = raw.split CONS.DELIM_MULTI_VALUE
     values = []


Fix some message text

Fix some message text

--- app/uploaders/gcs-uploader.coffee
+++ app/uploaders/gcs-uploader.coffee
@@ -24,7 +24,7 @@
       processData: false
       xhrFields:
         withCredentials: false
-      beforeSend: (xhr)->
+      beforeSend: (xhr) ->
         for p of headers
           if headers.hasOwnProperty p
             xhr.setRequestHeader p, headers[p]
@@ -69,7 +69,13 @@
         self.ajax(url, data, "PUT", json.headers)
           .then (respData) ->
             self.didUpload respData
+            Notify.success "File Uploaded Successfully. Please wait while we process your file."
             respData
+          , (xhr)->
+            if xhr.status is 200
+              Notify.success "File Uploaded Successfully. Please wait while we process your file."
+
       , ->
+        Notify.error "Error While signing the file."
         debugger
 `export default GCSUploader;`


Cleanup

Cleanup

--- src/components/app.coffee
+++ src/components/app.coffee
@@ -1,5 +1,4 @@
 React = require 'react'
-{ connect } = require 'react-redux'

 PlayerOrderList = React.createFactory require('./player_order_list')
 ScoringTable = React.createFactory require('./scoring_table')
@@ -19,7 +18,4 @@
           ScoringTable {}
           Scoreboard {}

-mapStateToProps = (state) ->
-  players: state.player.get 'players'
-
-module.exports = connect(mapStateToProps)(DartsApp)
+module.exports = DartsApp


reproduce previous parent behaviour

reproduce previous parent behaviour

--- bokehjs/src/coffee/common/has_parent.coffee
+++ bokehjs/src/coffee/common/has_parent.coffee
@@ -49,9 +49,14 @@
     get: (attr) ->
       if attr == 'parent'
         return @_parent
+      val = super(attr)
+      if not _.isUndefined(val)
+        return val
       if parent and _.indexOf(parent.parent_properties, attr) >= 0
-        return parent.get(attr)
-      return @_display_defaults[attr] ? super(attr)
+        val = parent.get(attr)
+        if not _.isUndefined(val)
+          return val
+      return @_display_defaults[attr]

     display_defaults: {}


Configure overlay when adding tools to a plot

--- bokehjs/src/coffee/models/plots/plot.coffee
+++ bokehjs/src/coffee/models/plots/plot.coffee
@@ -747,6 +747,9 @@

   add_tools: (tools...) ->
     new_tools = for tool in tools
+      if tool.overlay?
+        @add_renderers(tool.overlay)
+
       if tool.plot?
         tool
       else


Blaze fix for batch admin page.

Blaze fix for batch admin page.

--- admin/experimentAdmin.coffee
+++ admin/experimentAdmin.coffee
@@ -100,7 +100,7 @@
       $pull: { treatmentIds: @_id }
   "click .-ts-add-batch-treatment": (e, tmpl) ->
     e.preventDefault()
-    treatment = Spark.getDataContext(tmpl.find(":selected"))
+    treatment = UI.getElementData(tmpl.find(":selected"))
     return unless treatment._id
     Batches.update @_id,
       $addToSet: { treatmentIds: treatment._id }


Don't trigger page change event when rendering discussion post

--- resources/assets/coffee/react/beatmap-discussions/post.coffee
+++ resources/assets/coffee/react/beatmap-discussions/post.coffee
@@ -36,16 +36,8 @@
       message: @props.post.message

-  componentDidMount: =>
-    osu.pageChange()
-
-
   componentWillUpdate: =>
     @cache = {}
-
-
-  componentDidUpdate: =>
-    osu.pageChange()

   componentWillUnmount: =>


Adjusts the atom packages.

Adjusts the atom packages.

--- .atom/packages.cson
+++ .atom/packages.cson
@@ -1,9 +1,7 @@
 packages: [
   "atom-beautify"
-  "atom-ctags"
   "atom-ide-ui"
   "atom-python-virtualenv"
-  "autocomplete-python"
   "autocomplete-robot-framework"
   "build-gradle"
   "busy-signal"
@@ -48,13 +46,10 @@
   "minimap-highlight-selected"
   "package-sync"
   "pigments"
-  "platformio-ide-terminal"
-  "python-tools"
   "refactor"
   "rst-preview"
   "script"
   "sort-lines"
-  "symbol-gen"
   "tree-view-git-status"
   "zenburn-syntax"
   "zenburn-ui"


Readd temporary variables for File-Icons debugging

--- .config/init.coffee
+++ .config/init.coffee
@@ -102,3 +102,5 @@

 global.__fileIconsDebugFilter = /Adding grammar/
+global.fip = atom.packages.loadedPackages["file-icons"].path + "/"
+global.icons = require(fip + "lib/service/icon-service")


another tweak to Structure.read

another tweak to Structure.read

--- src/packet.coffee
+++ src/packet.coffee
@@ -474,7 +474,7 @@
   sizeOf: (values...) -> 0

   read: (buffer, offset, callback) ->
-    callback = offset if typeof offset is "function" and not callback?
+    callback = offset if typeof offset is "function" and not callback
     @parser.reset()
     @parser.parse("structure", callback)
     @parser.read(buffer, offset, Number.MAX_VALUE)


:bug: Dispose correctly

:bug: Dispose correctly

--- src/panels.coffee
+++ src/panels.coffee
@@ -8,33 +8,31 @@
   constructor: ({searchElementProp, itemsElementProp, resizedBodyHeightProp, selectedItemProp, resetStream, openStream}) ->
     @disposables = new CompositeDisposable

-    sideEffects = [
+    @removeOnDispose(sideEffect) for sideEffect in [
       searchElementProp.onValue @createSearchPanel
       itemsElementProp.onValue @createItemsPanel
       resizedBodyHeightProp.debounce(500).onValue @saveResizedBodyHeight
       selectedItemProp.onValue @previewSelectedItem
       selectedItemProp.sampledBy(openStream).onValue @openSelectedItem

-      @quickDoubleStream(resetStream).onValue R.pipe(
-        @hideItemsPanel
-        @hideSearchPanel
-        -> atom.workspace.getActivePane()?.activate()
-      )
-      @quickDoubleStream(atoms.cancelCommand()).onValue R.pipe(
-        @showItemsPanel
-        @showSearchPanel
-        @getSearchInput
-        (input) -> input.select() and input.focus()
-      )
+      @quickDoubleStream(resetStream).onValue =>
+        @hideItemsPanel()
+        @hideSearchPanel()
+        atom.workspace.getActivePane()?.activate()
+
+      @quickDoubleStream(atoms.cancelCommand()).onValue =>
+        @showItemsPanel()
+        @showSearchPanel()
+        @selectAndFocus(@searchPanel.getItem())
     ]
-    @removeOnDispose(sideEffect) for sideEffect in sideEffects
+
+  selectAndFocus: (input) ->
+    input.select()
+    input.focus()

   # filter a given stream to only trigger if tow event are triggered within 300ms (e.g. double-ESC)
   quickDoubleStream: (stream) ->
     stream.bufferWithTimeOrCount(300, 2).filter R.propEq('length', 2)
-
-  getSearchInput: ->
-    @searchPanel.getItem()

   hideSearchPanel: ->
     @searchPanel.hide()
@@ -48,11 +46,11 @@
   showSearchPanel: ->
     @searchPanel.show()

-  createSearchPanel: (el) ->
-    unless @itemsPanel
+  createSearchPanel: (el) =>
+    unless @searchPanel
       @searchPanel = atom.workspace.addTopPanel(item: el)

-  createItemsPanel: (el) ->
+  createItemsPanel: (el) =>
     unless @itemsPanel
       @itemsPanel = atom.workspace.addTopPanel(item: el)

@@ -71,7 +69,7 @@
       atom.workspace.open Path.join(selectedItem.projectPath, selectedItem.relPath)

   removeOnDispose: (o) ->
-    unless typeof o.dispose is 'function'
+    unless Disposable.isDisposable(o)
       if typeof o is 'function'
         o = new Disposable(o)
       else
@@ -81,7 +79,7 @@
   dispose: ->
     @disposables.dispose()
     @disposables = null
+    @searchPanel?.destroy()
+    @searchPanel = null
     @itemsPanel?.destroy()
     @itemsPanel = null
-    @searchPanel?.destroy()
-    @searchPanel = null


- Rename rotation - Better inserting of elements - Code cleanup for setting matrix values

--- src/views/view.coffee
+++ src/views/view.coffee
@@ -33,6 +33,7 @@
 		# Set the view properties
 		@clip = args.clip or View.Properties.clip
 		@properties = args
+		@index = 0

 		# Overridable creation hook
 		@_postCreate?()
@@ -86,7 +87,6 @@
 	screenFrame: ->
 		# Get this views absolute frame on the screen
 		utils.convertPoint @frame, @, null
-

 	contentFrame: ->
 		# Get the total size of all subviews
@@ -122,115 +122,54 @@

 	@define "x",
 		get: -> @_matrix.x
-		set: (value) ->
-			@animateStop()
-			@_matrix.x = value
-			@_matrix = @_matrix
-			@emit "change:x"
-			@emit "change:frame"
+		set: (value) -> @_setMatrixValue "x", value

 	@define "y",
 		get: -> @_matrix.y
-		set: (value) ->
-			@animateStop()
-			@_matrix.y = value
-			@_matrix = @_matrix
-			@emit "change:y"
-			@emit "change:frame"
+		set: (value) -> @_setMatrixValue "y", value

 	@define "z",
 		get: -> @_matrix.z
-		set: (value) ->
-			@animateStop()
-			@_matrix.z = value
-			@_matrix = @_matrix
-			@emit "change:z"
-			@emit "change:frame"
+		set: (value) -> @_setMatrixValue "z", value

 	#############################################################################
 	## Scale

 	@define "scale",
 		get: -> @_matrix.scale
-		set: (value) ->
-			@animateStop()
-			@_matrix.scale = value
-			@_matrix = @_matrix
-
-			@emit "change:scale"
+		set: (value) -> @_setMatrixValue "scale", value

 	@define "scaleX",
 		get: -> @_matrix.scaleX
-		set: (value) ->
-			@animateStop()
-			@_matrix.scaleX = value
-			@_matrix = @_matrix
-
-			@emit "change:scaleX"
-			@emit "change:scale"
+		set: (value) -> @_setMatrixValue "scaleX", value

 	@define "scaleY",
 		get: -> @_matrix.scaleY
-		set: (value) ->
-			@animateStop()
-			@_matrix.scaleY = value
-			@_matrix = @_matrix
-
-			@emit "change:scaleY"
-			@emit "change:scale"
+		set: (value) -> @_setMatrixValue "scaleY", value

 	@define "scaleZ",
 		get: -> @_matrix.scaleZ
-		set: (value) ->
-			@animateStop()
-			@_matrix.scaleZ = value
-			@_matrix = @_matrix
-
-			@emit "change:scaleZ"
-			@emit "change:scale"
-
-
-	#############################################################################
-	## Rotate
-
-	@define "rotate",
-		get: -> @_matrix.rotate
-		set: (value) ->
-			@animateStop()
-			@_matrix.rotate = value
-			@_matrix = @_matrix
-
-			@emit "change:rotate"
-
-	@define "rotateX",
-		get: -> @_matrix.rotateX
-		set: (value) ->
-			@animateStop()
-			@_matrix.rotateX = value
-			@_matrix = @_matrix
-
-			@emit "change:rotateX"
-			@emit "change:rotate"
-
-	@define "rotateY",
-		get: -> @_matrix.rotateY
-		set: (value) ->
-			@animateStop()
-			@_matrix.rotateY = value
-			@_matrix = @_matrix
-
-			@emit "change:rotateX"
-			@emit "change:rotate"
-
-	@define "rotateZ",
-		get: -> @_matrix.rotateZ
-		set: (value) ->
-			@animateStop()
-			@_matrix.rotateZ = value
-			@_matrix = @_matrix
-
-			@emit "change:rotateZ"
-			@emit "change:rotate"
+		set: (value) -> @_setMatrixValue "scaleZ", value
+
+
+	#############################################################################
+	## Rotation
+
+	@define "rotation",
+		get: -> @_matrix.rotation
+		set: (value) ->  @_setMatrixValue "rotation", value
+
+	@define "rotationX",
+		get: -> @_matrix.rotationX
+		set: (value) -> @_setMatrixValue "rotationX", value
+
+	@define "rotationY",
+		get: -> @_matrix.rotationY
+		set: (value) -> @_setMatrixValue "rotationY", value
+
+	@define "rotationZ",
+		get: -> @_matrix.rotationZ
+		set: (value) -> @_setMatrixValue "rotationZ", value

 	#############################################################################
@@ -258,6 +197,19 @@
 			@__matrix = matrix
 			@style.webkitTransform = @__matrix.matrix().cssValues()

+	_setMatrixValue: (property, value) ->
+
+		@animateStop()
+
+		@_matrix[property] = value
+		@_matrix = @_matrix
+
+		@emit "change:#{property}"
+
+		# Make sure we also emit group changes like scaleX -> scale
+		if property[-1..] in ["X", "Y", "Z"]
+			@emit "change:#{property[..(property.length - 1)]}"
+
 	_computedMatrix: ->
 		new WebKitCSSMatrix @computedStyle.webkitTransform

@@ -302,7 +254,7 @@
 			return if value is @_superView

 			# Cancel previous pending insertions
-			# document.removeEventListener "DOMContentLoaded", @__insertElement
+			utils.domCompleteCancel @__insertElement

 			# Remove from previous superview subviews
 			if @_superView
@@ -316,13 +268,29 @@
 				value._subViews.push @
 				value.emit "change:subViews"
 			else
-				@__insertElement()
-
+				@_insertElement()
+
+			# Set the superview
 			@_superView = value
+
+			# Place this view on top of it's siblings
+			@bringToFront()
+
 			@emit "change:superView"

 	@define "subViews",
-		get: -> _.compact @_subViews
+		get: ->
+			# Make a shallow copy of the list
+			@_subViews.map (view) -> view
+
+	@define "siblingViews",
+		get: ->
+			if @superView is null
+				_.filter View.ViewList, (view) =>
+					view isnt @ and view.superView
+			else
+				_.filter @superView.subViews, (view) =>
+					view isnt @

 	addSubView: (view) ->
 		view.superView = @
@@ -338,7 +306,7 @@
 	## Ordering

 	@define "index",
-		get: -> @style['z-index'] or 0
+		get: -> parseInt @style['z-index'] or 0
 		set: (value) ->
 			@style['z-index'] = value
 			@emit "change:index"
@@ -354,6 +322,14 @@
 		indexB = view.index
 		view.index = indexA
 		@index = indexB
+
+	bringToFront: ->
+		siblingIndexes = _.pluck @siblingViews, "index"
+		@index = (utils.max(siblingIndexes) + 1) or 0
+
+	sendToBack: ->
+		siblingIndexes = _.pluck @siblingViews, "index"
+		@index = (utils.min(siblingIndexes) - 1) or 0

 	#############################################################################
 	## Animation
@@ -417,18 +393,13 @@
 		@classes = _.filter @classes, (item) -> item isnt className

 	_insertElement: ->
-
-		# Insert the element to the dom, wait for it if it's not loaded
-		# TODO: There might still be some bug here
-
-		if document.readyState in ["complete"]
-			@__insertElement()
-		else
-			document.addEventListener "DOMContentLoaded",
-				@__insertElement
+		utils.domComplete @__insertElement

 	__insertElement: =>
-		@_rootElement.appendChild @_element
+		document.body.appendChild @_element
+
+	destroy: ->
+		@_element.parentNode.removeChild @_element

 	#############################################################################
@@ -454,10 +425,10 @@
 	frame: null
 	clip: true
 	opacity: 1.0
-	rotateX: 0
-	rotateY: 0
-	rotateZ: 0
-	rotate: 0
+	rotationX: 0
+	rotationY: 0
+	rotationZ: 0
+	rotation: 0
 	scale: 1.0
 	scaleX: 1.0
 	scaleY: 1.0


Don't preload until all images are ready.

--- src/core/preloader.coffee
+++ src/core/preloader.coffee
@@ -31,7 +31,7 @@
   @imageLoaded: () =>
     Preloader.loadedCount++;
     console.log("Preloading loading finished: #{Preloader.loadedCount}/#{Preloader.addedCount} done.")
-    if (Preloader.loadedCount + 1 == Preloader.addedCount and Preloader.callback)
+    if (Preloader.loadedCount == Preloader.addedCount and Preloader.callback)
       console.log("Preloading calling back.")
       Preloader.callback()


Use the ::editorWidthInChars property directly

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -102,11 +102,10 @@
       @updateWrappedScreenLines()

   getSoftWrapColumn: ->
-    editorWidthInChars = @editorWidthInChars
     if atom.config.get('editor.softWrapAtPreferredLineLength')
-      Math.min(editorWidthInChars, atom.config.getPositiveInt('editor.preferredLineLength', editorWidthInChars))
+      Math.min(@editorWidthInChars, atom.config.getPositiveInt('editor.preferredLineLength', @editorWidthInChars))
     else
-      editorWidthInChars
+      @editorWidthInChars

   # Gets the screen line for the given screen row.
   #


move origin out from Sliding

move origin out from Sliding

--- src/puzzle.coffee
+++ src/puzzle.coffee
@@ -4,7 +4,11 @@

 toPos = (posid) ->
-    return if isArray(posid) then posid else @position[posid]
+    if isArray(posid) then posid else @position[posid]
+
+
+origin = (id, cols) ->
+    [Math.floor(id / cols), id % cols]

 class Sliding
@@ -127,9 +131,6 @@

         return @

-    origin = (id, cols) ->
-        return [Math.floor(id / cols), id % cols]
-
     swap: (p1, p2) ->
         [y1, x1] = toPos.call(@, p1)
         [y2, x2] = toPos.call(@, p2)


logger: fix level

logger: fix level

--- src/logger.coffee
+++ src/logger.coffee
@@ -5,7 +5,10 @@
 config = {}
 logFile = undefined
 exports.setConfig = (config_) ->
-    config = config_
+    config = Object.clone(config_)
+    # Translate user-passed string to level index
+    config.level = Math.max(0, CommonLogger.levels.indexOf config_.level)
+
     if config_.file
         logFile = fs.createWriteStream config_.file
     if config_.syslog?
@@ -22,8 +25,6 @@

 class Logger extends CommonLogger
     constructor: (@module) ->
-        # Translate user-passed string to level index
-        config.level = Math.max(0, CommonLogger.levels.indexOf config.level)
         super(config)

     # + @module output


Passed context to onBeforeAction call.

Passed context to onBeforeAction call.

--- src/routes.coffee
+++ src/routes.coffee
@@ -17,7 +17,7 @@

     onBeforeAction = ->
       Router.initLastPath()
-      (args.onBeforeAction ? this.next)()
+      (args.onBeforeAction ? @next).call(@)
     Router.onBeforeAction(onBeforeAction)

     reactiveCurrentName = new ReactiveVar(null)


Issues #156 #178 #179 - rerun, tcpreciever and polling server should run on locahost by default.

--- src/server.coffee
+++ src/server.coffee
@@ -117,7 +117,7 @@
 	defer = Q.defer()

 	tcpHttpReceiver = http.createServer app.callback()
-	tcpHttpReceiver.listen tcpHttpReceiverPort, ->
+	tcpHttpReceiver.listen tcpHttpReceiverPort, config.tcpAdapter.httpReceiver.host, ->
 		logger.info "HTTP receiver for Socket adapter listening on port #{tcpHttpReceiverPort}"
 		tcpAdapter.startupServers (err) ->
 			logger.error err if err
@@ -129,7 +129,7 @@
 	deferredHttp = Q.defer()

 	rerunServer = http.createServer app.callback()
-	rerunServer.listen httpPort, ->
+	rerunServer.listen httpPort, config.rerun.host, ->
 		logger.info "Transaction Rerun HTTP listening on port " + httpPort
 		deferredHttp.resolve()

@@ -139,7 +139,7 @@
 	defer = Q.defer()

 	pollingServer = http.createServer app.callback()
-	pollingServer.listen pollingPort, (err) ->
+	pollingServer.listen pollingPort, config.polling.host, (err) ->
 		logger.error err if err
 		logger.info 'Polling port listenting on port ' + pollingPort
 		defer.resolve()


Modify general test comment.

Modify general test comment.

--- test/2.general.coffee
+++ test/2.general.coffee
@@ -2,20 +2,22 @@

 The output should look something like this:

-2014-06-15T09:20:04.655Z OK: 13, Exception: 1, Pending: 4
-2014-06-15T09:20:05.594Z OK: 13, Exception: 1, Pending: 4
-2014-06-15T09:20:06.595Z OK: 16, Exception: 1, Pending: 1
-2014-06-15T09:20:07.596Z OK: 17, Exception: 1, Pending: 0
+2014-08-17T09:34:22.788Z OK: 13, Exception: 1, Pending: 4
+2014-08-17T09:34:23.757Z OK: 13, Exception: 1, Pending: 4
+2014-08-17T09:34:24.759Z OK: 16, Exception: 1, Pending: 1
+111
+null
+******************all ended!
+2014-08-17T09:34:25.760Z OK: 17, Exception: 1, Pending: 0

 ********** Exceptional Test **********
 Test:
 Function: function () {
-    return falseFunction(true);
-  }
+      return falseFunction(true);
+    }
 Error Name: ReferenceError
 Error Message: falseFunction is not defined
 Error Stack: ...
-

 ********** Broken Wish **********
     Test: root --> String.prototype test


Fixed unit test url

Fixed unit test url

--- test/call.coffee
+++ test/call.coffee
@@ -8,7 +8,7 @@
             xhr = new XHR( settings )

             xhr.call(
-                url:      "http://labs.marviq.net/xdm/example.json"
+                url:      "http://www.qwerios.nl/projects/xdm/example.json"
                 method:   "GET"
                 type:     "json"
             )


Add prefix for loading packages in spec/fixtures.

--- spec/app/text-mate-grammar-spec.coffee
+++ spec/app/text-mate-grammar-spec.coffee
@@ -24,7 +24,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(fsUtils.resolveOnLoadPath('package-with-grammars/grammars/alot.cson'))
+      grammar = TextMateGrammar.loadSync(fsUtils.resolveOnLoadPath('spec/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"]


Data-links tests improved

Data-links tests improved

--- spec/javascripts/data_link_spec.coffee
+++ spec/javascripts/data_link_spec.coffee
@@ -22,11 +22,29 @@
     expect(player.options.useSeekData).toBe true
     expect(FoundationPlayer.prototype.parseDataLinks).toHaveBeenCalledWith()

-  it 'elements have click handler', ->
-    $dataTimeLinks = $('[data-seek-to-time]')
-    expect($dataTimeLinks).not.toHandle 'click'
+  it 'for time have click handler if valid', ->
+    $dataTimeLinksValid = $('.valid[data-seek-to-time]')
+    expect($dataTimeLinksValid).not.toHandle 'click'
     $('.links').foundationPlayer useSeekData: true
-    expect($dataTimeLinks).toHandle 'click'
+    expect($dataTimeLinksValid).toHandle 'click'
+
+  it 'for time don\'t have click handler if invalid', ->
+    $dataTimeLinksInvalid = $('.invalid[data-seek-to-time]')
+    expect($dataTimeLinksInvalid).not.toHandle 'click'
+    $('.links').foundationPlayer useSeekData: true
+    expect($dataTimeLinksInvalid).not.toHandle 'click'
+
+  it 'for position have click handler if valid', ->
+    $dataPosLinksValid = $('.valid[data-seek-to-percentage]')
+    expect($dataPosLinksValid).not.toHandle 'click'
+    $('.links').foundationPlayer useSeekData: true
+    expect($dataPosLinksValid).toHandle 'click'
+
+  it 'for position don\'t have click handler if invalid', ->
+    $dataPosLinksInvalid = $('.invalid[data-seek-to-percentage]')
+    expect($dataPosLinksInvalid).not.toHandle 'click'
+    $('.links').foundationPlayer useSeekData: true
+    expect($dataPosLinksInvalid).not.toHandle 'click'

   it 'are stored in object property', ->
     # This test requires full control over player behaviour


Remove log

Remove log

--- src/markov.coffee
+++ src/markov.coffee
@@ -93,8 +93,7 @@
     # Chance to randomly respond un-prompted
     if pct > 0 and Math.random() < pct
       words = msg.message.text.match /\w+/g
-      console.log(words[0])
-      randword = Math.floor(Math.random() * words.length + 1)
+      randword = Math.floor(Math.random() * words.length)
       seed = words[randword]
       model.generate seed or '', max, (text) =>
         msg.send text


extracting point

extracting point

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -296,6 +296,7 @@
   Matrix.VERTICAL_FLIP = Matrix(1, 0, 0, -1)

   # Export to window
+  window["Point"] = $.noop #TODO: Figure out why things barf without this line
   window["Matrix"] = Matrix
 )()


Don't log every time we save.

Don't log every time we save.

--- src/dynamodb-brain.coffee
+++ src/dynamodb-brain.coffee
@@ -41,7 +41,6 @@
   doc = new AWS.DynamoDB.DocumentClient

   saveBrain = (data = {}) ->
-    console.log "Saving brain"
     brain = {TableName: params.TableName, Item: data}
     brain.Item.botname = params.Key.botname
     doc.put brain, (err, res) ->


check the validity of course period dates

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -211,10 +211,19 @@

     isValid: (id) ->
       plan = @_getPlan(id)
+
+      isValidDates = ->
+        flag = true
+        # TODO: check that all periods are filled in
+        _.each plan.tasking_plans, (tasking) ->
+          unless tasking.due_at and tasking.opens_at
+            flag = false
+        flag
+
       if (plan.type is 'reading')
-        return plan.title and plan.due_at and plan.settings?.page_ids?.length > 0
+        return plan.title and isValidDates() and plan.settings?.page_ids?.length > 0
       else if (plan.type is 'homework')
-        return plan.title and plan.due_at and plan.settings?.exercise_ids?.length > 0
+        return plan.title and isValidDates() and plan.settings?.exercise_ids?.length > 0

     isPublished: (id) ->
       plan = @_getPlan(id)


Don't require in bare modules.

Don't require in bare modules.

--- src/module.coffee
+++ src/module.coffee
@@ -280,7 +280,7 @@
     for node in @wrapped().body
       toplevel.body.push node

-    unless @async
+    unless @async or @bare
       if @export
         for node in (utils.parse "global.#{@export} = require('#{@requireAs}');").body
           toplevel.body.push node


Don’t take the shortest route when animating gradient angles

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


Username: do not show profile updated notification, it will show at the end of daisy queue

--- client/Account/views/username.coffee
+++ client/Account/views/username.coffee
@@ -87,7 +87,9 @@

           new VerifyPINModal 'Update E-Mail', (pin)=>
             KD.remote.api.JUser.changeEmail {email, pin}, (err)=>
-              notify if err then err.message else "E-mail changed!"
+              if err
+                notify err.message
+                profileUpdated = false
               queue.next()
       =>
         # on third turn update password


fix typo

fix typo

--- client/code/view/home_content.coffee
+++ client/code/view/home_content.coffee
@@ -15,7 +15,7 @@
   renderStuff: ->
     name = @model.get 'name'
     @$el.find('#tools .metro-tile').first().addClass(name).find('h3').text name
-    if @model.isInstalled
+    if @model.isInstalled()
       @$el.find('#datasets').append """

#{name} data

"""

   clickTile: (event_) ->


Simple fix.

Simple fix.

--- test/bone.io.coffee
+++ test/bone.io.coffee
@@ -1,7 +1,7 @@
 should = require('chai').should()
 express = require('express.io')
 rack = require('asset-rack')
-global.window = {}
+global.window = global
 global.$ = {}
 require('../bone.io')


+ keys, getOwnPropertyNames methods

+ keys, getOwnPropertyNames methods

--- src/object.coffee
+++ src/object.coffee
@@ -8,7 +8,7 @@
 isString        = require 'util-ex/lib/is/type/string'
 defineProperty  = require 'util-ex/lib/defineProperty'
 inheritsObject  = require 'inherits-ex/lib/inheritsObject'
-createObject    = require("inherits-ex/lib/createObject")
+createObject    = require 'inherits-ex/lib/createObject'
 ObjectValue     = require './value/object'
 attributes      = createObject require './attributes/object'
 module.exports  = Type = require './attribute'
@@ -40,8 +40,10 @@
       type: ...
   ###
   defineAttribute: (aName, aOptions)->
-    throw TypeError('defineAttribute has no attribute name') unless aName and aName.length
-    throw TypeError('the attribute "' + aName + '" has already defined.') if @attributes[aName]?
+    unless aName and aName.length
+      throw TypeError('defineAttribute has no attribute name')
+    if @attributes[aName]?
+      throw TypeError('the attribute "' + aName + '" has already defined.')
     if isString aOptions
       vType = Type(aOptions)
       throw TypeError("no such type registered:"+aOptions) unless vType
@@ -79,13 +81,12 @@
         continue if not k? or not v?
         @defineAttribute k, v
     return
-  _toObject:(aOptions)->
-    result = super(aOptions)
+  _toObject:(aOptions, aNameRequired)->
+    result = super
     result.attributes = vAttrs = {}
     for k,v of @attributes
-      vAttrs[k] = t = v.toObject(aOptions)
-      delete t[NAME]
-      delete t.fullName
+      vAttrs[k] = t = v.toObject(aOptions, false)
+      #delete t[NAME]
       vAttrs[k] = t[TYPE] if getObjectKeys(t).length is 1
     result
   _decodeValue: (aValue)->
@@ -136,3 +137,34 @@
       else
         defineProperty aObjectValue, '$type', @
     aObjectValue
+  attrKeys: ->
+    result = []
+    for k,v of @attributes
+      result.push v.name || k if v.enumerable isnt false
+    result
+  attrOwnPropertyNames: ->
+    result = []
+    for k,v of @attributes
+      result.push v.name
+    result
+  # Returns
+  #   all own, enumerable properties of an object
+  # Parameters
+  #   * aObject: The object whose enumerable own properties are to be returned.
+  keys: (aObject)->
+    result = getObjectKeys aObject
+    if @strict
+      vAttrKeys = @attrKeys()
+      result = result.filter (element)->element in vAttrKeys
+    result
+  # Returns
+  #   all own properties of an object, enumerable or not.
+  # Parameters
+  #   * aObject: The object whose enumerable and non-enumerable own properties
+  #     are to be returned.
+  getOwnPropertyNames: (aObject)->
+    result = getOwnPropertyNames aObject
+    if @strict
+      vAttrKeys = @attrOwnPropertyNames()
+      result = result.filter (element)->element in vAttrKeys
+    result


Add test case for defaultLanguage parameter.

--- test/compile.coffee
+++ test/compile.coffee
@@ -75,6 +75,26 @@
         context = vm.createContext(makeEnv('myApp', catalog))
         vm.runInContext(output, context)
         assert(catalog.called)
+
+    it 'Accepts a defaultLanguage parameter', ->
+        files = [
+            'test/fixtures/nl.po'
+        ]
+        output = testCompile(files, {
+            defaultLanguage: 'nl'
+        })
+
+        catalog = {
+            called: false
+            setStrings: (language, strings) ->
+                @called = true
+        }
+
+        context = vm.createContext(makeEnv('gettext', catalog))
+        vm.runInContext(output, context);
+        assert(catalog.called)
+        assert.notEqual(output.indexOf("gettextCatalog.currentLanguage = 'nl';"), -1)
+        assert.equal(catalog.currentLanguage, 'nl');

     it 'Accepts a requirejs and modulePath parameter', ->
         files = [


dash (-) is valid character

dash (-) is valid character

--- src/parser.coffee
+++ src/parser.coffee
@@ -35,7 +35,7 @@
     line = discard_comment_in_line line
     # file_path=/tmp/scribetest/bucket0
     # category=tps_report*
-    pattern = /^([a-z0-9_]+)\=([a-z0-9_\/]+)([\*]?)$/i
+    pattern = /^([a-z0-9_]+)\=([a-z0-9-_\/]+)([\*]?)$/i
     arr = pattern.exec line
     if arr is null then false else true


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/metered.coffee
+++ test/metered.coffee
@@ -24,5 +24,6 @@
   obj.include Metered

   obj.meter
+    name: 'turbo'

 module()


Fixup f8cad92, temporarily keep tests from failing.

--- src/player.coffee
+++ src/player.coffee
@@ -175,7 +175,7 @@
       @debug 'jump:start', @physics.position if @nextState is 'rising'

       if @nextState is 'falling'
-        @_fallingPoint ?= @sprite.position.clone()
+        @_fallingPoint ?= @physics.position?.clone()
       else if @nextState is 'still' and @_fallingPoint?
         @_fallingPoint = null


code refactoring

code refactoring

--- client/ace/lib/acefindandreplaceview.coffee
+++ client/ace/lib/acefindandreplaceview.coffee
@@ -94,17 +94,11 @@

     @$().css { height }
     @resizeEditor height
-    @toggleReplacePart(isReplaceMode)
+
+    for widget in [@replaceInput, @replaceButton, @replaceAllButton]
+      if isReplaceMode then widget.show() else widget.hide()
+
     @show()
-
-
-  toggleReplacePart: (visible) ->
-
-    toggle = (elem, visible) -> if visible then elem.show() else elem.hide()
-
-    toggle(@replaceInput, visible)
-    toggle(@replaceButton, visible)
-    toggle(@replaceAllButton, visible)

   resizeEditor: (height) ->


Hide user dropdown on side nav collapse

Hide user dropdown on side nav collapse

--- client/source/views/layouts/loggedin.coffee
+++ client/source/views/layouts/loggedin.coffee
@@ -64,6 +64,7 @@
     $view = $('.loggedInView')

     $menuBtn = @$('.btn-menu').css display: 'block'
+    @$('.usernav.open').trigger 'click.bs.dropdown'

     @killTweens()


StackEditor: handle stack sharing correctly

--- client/stack-editor/lib/editor/index.coffee
+++ client/stack-editor/lib/editor/index.coffee
@@ -320,13 +320,7 @@
       cssClass       : 'GenericButton hidden set-default'
       callback       : =>
         appManager.tell 'Stacks', 'exitFullscreen'  unless @getOption 'skipFullscreen'
-        createShareModal (needShare, modal) =>
-          @once 'Completed', =>
-            if needShare
-              @shareCredentials -> modal.destroy()
-            else
-              modal.destroy()
-          @handleSetDefaultTemplate()
+        @handleSetDefaultTemplate()

     @buttons.addSubView @generateStackButton = new kd.ButtonView
       title          : 'INITIALIZE'
@@ -469,15 +463,15 @@
         if canEditGroup
           # admin is editing a team stack
           if stackTemplate.isDefault
-            @handleSetDefaultTemplate completed = no
-            @outputView.addAndWarn '''
-              Your stack script has been successfully saved and all your new team
-              members now will see this stack by default. Existing users
-              of the previous default-stack will be notified that default-stack has
-              changed.
-
-              You can now close this window or continue working with your stack.
-            '''
+            @_handleSetDefaultTemplate =>
+              @outputView.add '''
+                Your stack script has been successfully saved and all your new team
+                members now will see this stack by default. Existing users
+                of the previous default-stack will be notified that default-stack has
+                changed.
+
+                You can now close this window or continue working with your stack.
+              '''
           # admin is editing a private stack
           else
             @afterProcessTemplate 'maketeamdefault'
@@ -495,15 +489,15 @@
             @afterProcessTemplate 'initialize'
             computeController.checkGroupStacks()
           else
-            @handleSetDefaultTemplate completed = no
-            @outputView.addAndWarn '''
-              Your stack script has been successfully saved and all your new team
-              members now will see this stack by default. Existing users
-              of the previous default-stack will be notified that default-stack has
-              changed.
-
-              You can now close this window or continue working with your stack.
-            '''
+            @handleSetDefaultTemplate =>
+              @outputView.add '''
+                Your stack script has been successfully saved and all your new team
+                members now will see this stack by default. Existing users
+                of the previous default-stack will be notified that default-stack has
+                changed.
+
+                You can now close this window or continue working with your stack.
+              '''
             computeController.checkGroupStacks()
         # member is creating a new stack
         else
@@ -803,7 +797,19 @@
       @emit 'Reload'

-  handleSetDefaultTemplate: (completed = yes) ->
+  handleSetDefaultTemplate: (callback = kd.noop) ->
+
+    createShareModal (needShare, modal) =>
+      @_handleSetDefaultTemplate (stackTemplate) =>
+
+        if needShare
+        then @shareCredentials -> modal.destroy()
+        else modal.destroy()
+
+        callback stackTemplate
+
+
+  _handleSetDefaultTemplate: (callback = kd.noop) ->

     { stackTemplate }    = @getData()
     { groupsController, reactor } = kd.singletons
@@ -831,7 +837,7 @@
       stackTemplate.isDefault = yes

       @emit 'Reload'
-      @emit 'Completed', stackTemplate  if completed
+      callback stackTemplate

   deleteStack: ->


Adds turbase-spec to test suite

Adds turbase-spec to test suite

--- test/suit.coffee
+++ test/suit.coffee
@@ -1,5 +1,8 @@
 describe 'database.coffee', ->
   require './database-spec'
+
+describe 'turbase.coffee', ->
+  require './turbase-spec'

 describe 'api.coffee', ->
   require './api-spec'


Fix french locale

Fix french locale

--- client/app/locales/fr.coffee
+++ client/app/locales/fr.coffee
@@ -1,11 +1,11 @@
 module.exports =

     'bad credentials': "Mauvais identifiants. Vérifiez les champs que vous avez renseignés."
-    'token not found': "Le jeton n'a pas pu être récupéré'
+    'token not found': "Le jeton n'a pas pu être récupéré"
     'key not found': 'Clé non trouvée'
-    'request error': 'Une requête au site web a échoué, veuillez lire les journaux de l'application.'
-    'parsing error': 'Le retour n'a pas pu être interprété.'
-    'file error': 'Le fichier n'a pas pu être créé/modifié/supprimé'
+    'request error': "Une requête au site web a échoué, veuillez lire les journaux de l'application."
+    'parsing error': "Le retour n'a pas pu être interprété."
+    'file error': "Le fichier n'a pas pu être créé/modifié/supprimé"
     'no bills retrieved': 'Pas de factures trouvées'
     'last import:': 'Dernière importation :'
     'save and import': 'Importer et sauvegarder'


Microfix

Microfix

--- test/test.coffee
+++ test/test.coffee
@@ -14,8 +14,8 @@
   style: fs.readFileSync stylePath, 'utf-8'
   answer: fs.readFileSync answerPath, 'utf-8'

-describe 'postcss-cson-cssvars', ->
-  it 'expect concat chain token', ->
+describe 'postcss-preref', ->
+  it 'expect replace global', ->
     {style, answer} = set 'global'

     result = postcss([preref]).process(style)


slow down tests for travil build results

--- test/test.coffee
+++ test/test.coffee
@@ -8,7 +8,7 @@
   awsSecret: process.env.AWS_SECRET

 beforeEach (done) ->
-  # pause between tests
+  # pause between tests, avoid getting yelled at by amazon
   setTimeout () ->
     done()
   , 500
@@ -135,6 +135,12 @@

 describe 'client.itemSearch(query, cb)', ->

+  beforeEach (done) ->
+    # pause between tests, avoid getting yelled at by amazon, avoid getting yelled at by amazon
+    setTimeout () ->
+      done()
+    , 500
+
   describe 'when credentials are valid', ->
     client = amazonAffiliateApi.createClient credentials

@@ -167,7 +173,6 @@
           results.Items.should.have.property 'TotalResults'
           results.Items.should.have.property 'TotalPages'

-
   describe 'when credentials are invalid', ->
     client = amazonAffiliateApi.createClient awsTag: 'sfsadf', awsId: 'sfadf', awsSecret: 'fsg'

@@ -195,6 +200,12 @@

 describe 'client.itemLookup(query, cb)', ->

+  beforeEach (done) ->
+    # pause between tests, avoid getting yelled at by amazon
+    setTimeout () ->
+      done()
+    , 500
+
   describe 'when credentials are valid', ->
     client = amazonAffiliateApi.createClient credentials

@@ -219,7 +230,6 @@
       it 'should return results from amazon', ->
         client.itemLookup {idType: 'UPC', itemId: '889030012227'}, (err, results) ->
           results.Items.Item.should.be.an.Array
-

   describe 'when credentials are invalid', ->
     client = amazonAffiliateApi.createClient awsTag: 'sfsadf', awsId: 'sfadf', awsSecret: 'fsg'
@@ -266,6 +276,12 @@

 describe 'client.browseNodeLookup(query, cb)', ->

+  beforeEach (done) ->
+    # pause between tests, avoid getting yelled at by amazon
+    setTimeout () ->
+      done()
+    , 500
+
   describe 'when credentials are valid', ->
     client = amazonAffiliateApi.createClient credentials

@@ -347,6 +363,12 @@

   describe 'when credentials are valid', ->
     client = amazonAffiliateApi.createClient credentials
+
+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500

     afterEach (done) ->
       client.cartClear
@@ -418,6 +440,12 @@
   describe 'when credentials are invalid', ->
     client = amazonAffiliateApi.createClient awsTag: 'sfsadf', awsId: 'sfadf', awsSecret: 'fsg'

+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500
+
     describe 'when no callback is passed', ->
       it 'should return an error', ->
         client.cartCreate
@@ -454,6 +482,12 @@
   describe 'when the request returns an error', ->
     client = amazonAffiliateApi.createClient credentials

+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500
+
     describe 'when no callback is passed', ->
       it 'should return the errors inside the request node', ->
         client.cartCreate({})
@@ -495,6 +529,12 @@
   describe 'when credentials are valid', ->
     client = amazonAffiliateApi.createClient credentials

+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500
+
     describe 'when no callback is passed', ->
       it 'should return results from amazon', ->
         client.cartClear
@@ -534,6 +574,12 @@
   describe 'when credentials are invalid', ->
     client = amazonAffiliateApi.createClient awsTag: 'sfsadf', awsId: 'sfadf', awsSecret: 'fsg'

+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500
+
     describe 'when no callback is passed', ->
       it 'should return an error', ->
         client.cartClear
@@ -544,7 +590,6 @@
           err.should.have.property 'Error'
           err.Error.should.have.property 'Code'
           err.Error.Code.should.equal 'InvalidClientTokenId'
-

     describe 'when callback is passed', ->
       it 'should return an error', (done) ->
@@ -561,6 +606,12 @@
   describe 'when the request returns an error', ->
     client = amazonAffiliateApi.createClient credentials

+    beforeEach (done) ->
+      # pause between tests, avoid getting yelled at by amazon
+      setTimeout () ->
+        done()
+      , 500
+
     describe 'when no callback is passed', ->
       it 'should return the errors inside the request node', ->
         client.cartClear({})


Do not erase data on unsuccessfull reload

--- client/redux/reducers.coffee
+++ client/redux/reducers.coffee
@@ -7,8 +7,6 @@
     switch action.type
         when "#{GET_ME}_#{FULFILLED}"
             return action.payload
-        when "#{GET_ME}_#{REJECTED}"
-            return null
         else
             return state

@@ -16,8 +14,6 @@
     switch action.type
         when "#{GET_TREE}_#{FULFILLED}"
             return action.payload
-        when "#{GET_TREE}_#{REJECTED}"
-            return null
         else
             return state

@@ -25,8 +21,6 @@
     switch action.type
         when "#{GET_NEWS}_#{FULFILLED}"
             return action.payload
-        when "#{GET_NEWS}_#{REJECTED}"
-            return null
         else
             return state

@@ -36,10 +30,6 @@
             return
                 data: action.payload
                 url: action.meta.url
-        when "#{GET_DATA}_#{REJECTED}"
-            return
-                data: null
-                url: null
         else
             return state


Set options for logged out users

Set options for logged out users

--- components/follow_button/view.coffee
+++ components/follow_button/view.coffee
@@ -9,9 +9,9 @@
     'touchstart': () -> @$el.removeClass "no-touch"

   initialize: (options) ->
-    return unless options.following
+    { @following, @notes, @modelName } = options

-    { @following, @notes, @modelName } = options
+    return unless @following

     throw new Error('Requires @modelName') unless @modelName


Update store comment.

Update store comment.

--- app/client/js/storage.coffee
+++ app/client/js/storage.coffee
@@ -62,10 +62,14 @@
     isUserStoreWithUser = store instanceof app.user.Store && store.user
     if isUserStoreWithUser
       console.log '@firebase.userRef.set json' if goog.DEBUG
-      # TODO: Firebase.ServerValue.TIMESTAMP replaces local time with server
-      # time. It's not used until I figure out how to inject my own time.
-      # Now it takes 3 localStorage updates for one change! Terrible.
-      # json.updated = Firebase.ServerValue.TIMESTAMP
+      # Firebase.ServerValue.TIMESTAMP replaces local time with server time. But
+      # it seems to be suboptimal for now. By own updated time, I can filter
+      # local changes that Firebase on 'value' unfortunatelly dispatches too.
+      # When json.updated = Firebase.ServerValue.TIMESTAMP is used, I can't
+      # filter and server updated time is also propagated back to client, so
+      # instead of one serialization, any local changes is synced three times.
+      # Because we are using throttling, it's really not an issue. Still, it's
+      # neither ideal.
       @firebase.userRef.set json

   ###*


only show waypoints when path is present

--- components/layout/header/view.coffee
+++ components/layout/header/view.coffee
@@ -32,8 +32,9 @@
     mediator.on 'search:loaded', @closeDropdown, @
     mediator.on 'notifications:synced', @maybeSetNotifications, @

-    new Waypoint.Sticky
-      element: $('.path__inner')
+    if $('.path__inner')[0]
+      new Waypoint.Sticky
+        element: $('.path__inner')

     if !sd.CURRENT_USER
       new AuthRouter pushState: false


clean up

clean up

--- app/lib/router/router.coffee
+++ app/lib/router/router.coffee
@@ -118,10 +118,9 @@

   @route 'downloadBid',
-    path: "cases/bid/pdf/:fileId"
-    #layoutTemplate: 'empty'
-    action: ->
-      console.log("Get download File", @params.fileId)
+    path: "cases/bid/download/:fileId"
+    onRun: ->
+      console.log("Get download BID File", @params.fileId)
       fileId = @params.fileId
       Meteor.call "getBid", @params.fileId, (error, result) =>
         if error
@@ -129,65 +128,45 @@
           CoffeeAlerts.error("Error geting BID: #{error.reason}")
         else if result?
           bidWindow = window.open("","_self")
-          #if not bidWindow?
-          #  # Try in same frame
-          #  bidWindow = window.open("","_self")
           if bidWindow?
             bidWindow.document.write(result)
-            #if false
             #  console.log("print BID")
             #  bidWindow.print()
           else
             CoffeeAlerts.error("Error geting BID, you need pop up windows enabled for this to work")
             Router.go 'viewCase',
               _id: @params.case
-          #file = result
-          #blob = new Blob [file],
-          #  type: "text/html"
-          #console.log("Sending download", fileId)
-          #saveAs(blob, fileId + ".html")
         else
           CoffeeAlerts.error("Error geting BID, could not find file")
-
           Router.go 'viewCase',
             _id: @params.case
-
+    action: ->
+      console.log("download BID Action")

   @route 'downloadMou',
-    path: "cases/mou/pdf/:fileId"
-    #layoutTemplate: 'empty'
+    path: "cases/mou/download/:fileId"
     onRun: ->
-      console.log("downloadMou:onRun", @params.fileId)
+      console.log("Get download MOU File", @params.fileId)
       fileId = @params.fileId
       Meteor.call "getMou", @params.fileId, (error, result) =>
         if error
           CoffeeAlerts.error("Error geting MOU: #{error.reason}")
         else if result?
-          console.log("mouWindow?", mouWindow)
           mouWindow = window.open("","_self")
-          #if not mouWindow?
-          #  # Try in same frame
-          #  mouWindow = window.open("","_self")
           if mouWindow?
             mouWindow.document.write(result)
-            #if false
             #  console.log("print MOU")
             #  mouWindow.print()
           else
             CoffeeAlerts.error("Error geting MOU, you need pop up windows enabled for this to work")
             Router.go 'viewCase',
               _id: @params.case
-          #file = result
-          #blob = new Blob [file],
-          #  type: "text/html"
-          #console.log("Sending download", fileId,  file.length)
-          #saveAs(blob, fileId + ".html")
         else
           CoffeeAlerts.error("Error geting MOU, could not find file")
           Router.go 'viewCase',
             _id: @params.case
     action: ->
-      console.log("downloadMou Action")
+      console.log("download MOU Action")

   @route 'mou',


Made name label font size twice as big.

Made name label font size twice as big.

--- app/lib/surface/Label.coffee
+++ app/lib/surface/Label.coffee
@@ -75,7 +75,7 @@
     o.fontWeight = {D: 'bold', S: 'bold', N: 'bold'}[st]
     o.shadow = {D: false, S: true, N: true}[st]
     o.shadowColor = {D: '#FFF', S: '#000', N: '#FFF'}[st]
-    o.fontSize = {D: 25, S: 12, N: 12}[st]
+    o.fontSize = {D: 25, S: 12, N: 24}[st]
     fontFamily = {D: 'Arial', S: 'Arial', N: 'Arial'}[st]
     o.fontDescriptor = "#{o.fontWeight} #{o.fontSize}px #{fontFamily}"
     o.fontColor = {D: '#000', S: '#FFF', N: '#00a'}[st]


If workflow request 404s, clear out from prefs and try again

--- app/pages/project/index.cjsx
+++ app/pages/project/index.cjsx
@@ -216,9 +216,13 @@
       query['active'] = true
     apiClient.type('workflows').get(query)
       .catch (error) =>
-        console.error error
         # TODO: Handle 404 once json-api-client error handling is fixed.
-        @setState({ error: error, loadingSelectedWorkflow: false })
+        if error.status is 404
+          @clearInactiveWorkflow(selectedWorkflowID)
+            .then(@getSelectedWorkflow(@state.project, @state.preferences))
+        else
+          console.error error
+          @setState({ error: error, loadingSelectedWorkflow: false })
       .then ([workflow]) =>
         if workflow
           @setState({ loadingSelectedWorkflow: false, workflow })