Expose replacePaths

Expose replacePaths

--- src/scandal.coffee
+++ src/scandal.coffee
@@ -6,7 +6,7 @@
 path = require "path"

 SingleProcess = require('./single-process-search')
-{search} = SingleProcess
+{search, replace, replacePaths} = SingleProcess
 singleProcessScanMain = SingleProcess.scanMain
 singleProcessSearchMain = SingleProcess.searchMain
 singleProcessReplaceMain = SingleProcess.replaceMain
@@ -42,4 +42,4 @@
   else
     singleProcessScanMain(options)

-module.exports = {main, search, PathSearcher, PathScanner, PathReplacer}
+module.exports = {main, search, replace, replacePaths, PathSearcher, PathScanner, PathReplacer}


Wait until files are closed

Wait until files are closed

--- src/sitemap.coffee
+++ src/sitemap.coffee
@@ -1,6 +1,7 @@
 config = require './config'
 fs = require 'fs'
 Stream = require 'stream'
+async = require 'async'

 escapeXmlValue = (str) ->
   str.replace(/&/g, '&')
@@ -34,7 +35,7 @@

     @gzipper.on 'end', =>
       sitemapThis.flushed = true
-    @file.on 'end', =>
+    @file.on 'close', =>
       sitemapThis.fileFlushed = true
     @stream.pipe(@gzipper).pipe(@file)
     @stream.emit 'data', config.sitemapHeader
@@ -42,14 +43,14 @@
   notifyWhenDone: (cb) ->
     sitemapThis = this
     process.nextTick =>
-      if sitemapThis.flushed && sitemapThis.fileFlushed
-        console.log "!! sitemap done #{sitemapThis.fileName}, #{sitemapThis.urlCount} urls"
-        cb(null, true)
-      else
-        sitemapThis.gzipper.on 'end', =>
-          sitemapThis.file.on 'end', =>
-            console.log "!! sitemap done #{sitemapThis.fileName}, #{sitemapThis.urlCount} urls"
-            cb(null, true)
+      async.until(
+        -> sitemapThis.flushed && sitemapThis.fileFlushed
+        (untilCb) ->
+          setTimeout(untilCb, 1000)
+        (err) ->
+          console.log "!! sitemap done #{sitemapThis.fileName}, #{sitemapThis.urlCount} urls, err: #{err}"
+          cb(err, true)
+      )

   close: ->
     return if @closed


:lipstick:

:lipstick:

--- src/app/display-buffer.coffee
+++ src/app/display-buffer.coffee
@@ -112,8 +112,7 @@
   #
   # bufferRow - The buffer row {Number} to check against
   destroyFoldsContainingBufferRow: (bufferRow) ->
-    for marker in @findMarkers(class: 'fold', containsBufferRow: bufferRow)
-      marker.destroy()
+    fold.destroy() for fold in @foldsContainingBufferRow(bufferRow)

   # Largest is defined as the fold whose difference between its start and end rows
   # is the greatest.
@@ -146,21 +145,23 @@

   # Public: Given a buffer row, this returns the largest fold that includes it.
   #
-  # Largest is defined as the fold whose difference between its start and end points
-  # are the greatest.
+  # Largest is defined as the fold whose difference between its start and end rows
+  # is the greatest.
   #
   # bufferRow - A {Number} indicating the buffer row
   #
   # Returns a {Fold}.
   largestFoldContainingBufferRow: (bufferRow) ->
-    largestFold = null
-    for currentBufferRow in [bufferRow..0]
-      if fold = @largestFoldStartingAtBufferRow(currentBufferRow)
-        largestFold = fold if fold.getEndRow() >= bufferRow
-    largestFold
-
-  largestFoldStartingAtBufferRange: (bufferRange) ->
-    if marker = @findMarker(class: 'fold', containingBufferRange: bufferRange)
+    @foldsContainingBufferRow(bufferRow)[0]
+
+  # Public: Given a buffer row, this returns folds that include it.
+  #
+  #
+  # bufferRow - A {Number} indicating the buffer row
+  #
+  # Returns an {Array} of {Fold}s.
+  foldsContainingBufferRow: (bufferRow) ->
+    for marker in @findMarkers(class: 'fold', containsBufferRow: bufferRow)
       @foldForMarker(marker)

   # Public: Given a buffer range, this converts it into a screen range.


Always wrap marker screen positions at soft newlines

--- src/app/display-buffer.coffee
+++ src/app/display-buffer.coffee
@@ -316,7 +316,7 @@
     delete @markerScreenPositions[id]

   getMarkerScreenRange: (id) ->
-    @screenRangeForBufferRange(@getMarkerBufferRange(id))
+    @screenRangeForBufferRange(@getMarkerBufferRange(id), wrapAtSoftNewlines: true)

   setMarkerScreenRange: (id, screenRange, options) ->
     @setMarkerBufferRange(id, @bufferRangeForScreenRange(screenRange), options)
@@ -334,7 +334,7 @@
     @getMarkerHeadBufferPosition(id)

   getMarkerHeadScreenPosition: (id) ->
-    @screenPositionForBufferPosition(@getMarkerHeadBufferPosition(id))
+    @screenPositionForBufferPosition(@getMarkerHeadBufferPosition(id), wrapAtSoftNewlines: true)

   setMarkerHeadScreenPosition: (id, screenPosition, options) ->
     screenPosition = @clipScreenPosition(screenPosition, options)
@@ -347,7 +347,7 @@
     @buffer.setMarkerHeadPosition(id, bufferPosition)

   getMarkerTailScreenPosition: (id) ->
-    @screenPositionForBufferPosition(@getMarkerTailBufferPosition(id))
+    @screenPositionForBufferPosition(@getMarkerTailBufferPosition(id), wrapAtSoftNewlines: true)

   setMarkerTailScreenPosition: (id, screenPosition, options) ->
     screenPosition = @clipScreenPosition(screenPosition, options)
@@ -374,7 +374,7 @@
     @markerScreenPositionObservers[id].head.push(callback)
     subscription = @buffer.observeMarkerHeadPosition id, (bufferPosition) =>
       @cacheMarkerScreenPositions(id)
-      callback(@screenPositionForBufferPosition(bufferPosition))
+      callback(@getMarkerHeadScreenPosition(id))

     cancel: =>
       subscription.cancel()


Fix IE11 bug. Closes gh-863.

Fix IE11 bug. Closes gh-863.

--- src/chaplin/views/view.coffee
+++ src/chaplin/views/view.coffee
@@ -18,7 +18,10 @@

 setHTML = do ->
   if $
-    (elem, html) -> elem.html html
+    (elem, html) ->
+      elem.empty()
+      elem.append html
+      html
   else
     (elem, html) -> elem.innerHTML = html


Replacing async.map with async.mapLimit to adress #641

--- src/upgrade.coffee
+++ src/upgrade.coffee
@@ -129,7 +129,7 @@
         @getLatestVersion pack, (err, latestVersion) ->
           done(err, {pack, latestVersion})

-    async.map packages, getLatestVersionOrSha, (error, updates) ->
+    async.mapLimit packages, 10, getLatestVersionOrSha, (error, updates) ->
       return callback(error) if error?

       updates = _.filter updates, (update) -> update.latestVersion? or update.sha?


Prevent showing error notification when navigating to external pages

Fix #422

--- src/coffee/cilantro/ui.coffee
+++ src/coffee/cilantro/ui.coffee
@@ -19,9 +19,11 @@
     './ui/notify'
 ], ($, _, Backbone, c, mods...) ->

+    externalLink = false
+
     $(document).ajaxError (event, xhr, settings, exception) ->
         # Unknown error which usually means the server is unavailable
-        if not exception
+        if not exception and not externalLink
             c.notify
                 timeout: null
                 dismissable: false
@@ -51,8 +53,11 @@
         # otherwise let the event process normally to load the new
         # location.
         if c.router.hasRoute(pathname)
+            externalLink = false
             event.preventDefault()
             c.router.navigate(pathname, trigger: true)
+        else
+            externalLink = true

         return


Refactor.

Refactor.

--- main.coffee
+++ main.coffee
@@ -102,7 +102,6 @@
             .attr("height", height)

         @bar = {domainDir:"y", domainAttr:"height", rangeDir:"x", rangeAttr:"width"}
-        #@bar = {domainDir:"x", domainAttr:"width", rangeDir:"y", rangeAttr:"height"}

         @plotArea.selectAll("rect")
            .data(@data)
@@ -119,7 +118,6 @@
             .attr(@bar.rangeDir, (d,i) => (1-d.count/cmax)*width)
             .attr(@bar.rangeAttr, (d, i) => d.count/cmax*width)

-
 class Canvas

     @width = 360
@@ -156,34 +154,33 @@
         @y = m*Math.sin(a)
         this

-#==== Particles ====
-

 class Sunlight

-    colors: ["#ff0", "#00f"]
-    sizes: [2, 3]
+    colors: ["#ff0", "#ff0"]
+    sizes: [2, 5]
     w: Canvas.width
     h: Canvas.height
     O: -> new Vector 0, 0

-    constructor: (@pos=@O(), @vel0=@O()) ->
-        @init()
-        @limit = 0
-        @velocity = []  # Set of velocities indexed by state
-        @setVelocities()  # Configured in subclass
+    constructor: (@pos=@O(), g, q) ->
+
+        # sim units -> screen units
+        @xScale = d3.scale.linear()
+            .domain([-1, 1])
+            .range([0, @w])
+        @yScale = d3.scale.linear()
+            .domain([-1, 1])
+            .range([@h, 0])
+
+        # dynamics
         @d = 0
+        @velocity = []
+        @velocity[0] = new Vector 0, 2
+        @velocity[1] = @O()
+        @setCollision(g, q)
         @setState 0
-
-    init: ->
-        @xScale = d3.scale.linear() # sim units -> screen units
-            .domain([-1, 1])
-            .range([0, @w])
-
-        @yScale = d3.scale.linear() # sim units -> screen units
-            .domain([-1, 1])
-            .range([@h, 0])
-
+
     setState: (@state) ->
         return if @state<0
         @vel = @velocity[@state]
@@ -200,74 +197,44 @@
         if @collision() and @state is 0
             @setState(1)
             count[@bin] += 1
-            console.log "count", count
-
         @d += @vel.mag()
         @pos.add @vel

-
-    setVelocities: ->
-
-        @velocity[0] = new Vector @vel0.x, @vel0.y
-        @velocity[1] = (new Vector).polar(10, pi/2)
-
-        g = (u) -> ((u<0)*1.5 + (u>0)/2)*u + 0.375
-        h = (u) -> Math.floor(20*(u+0.5))
-
+    setCollision: (g, quant) ->
         @limit =  @yScale(g(@xScale.invert(@pos.x)))
-        #console.log "???", h(@xScale.invert(@pos.x))
-        @bin = Math.floor((@yScale.invert(@limit)+0.875)/2*20)
+        @bin = quant(@yScale.invert(@limit))

     collision: -> @pos.y > @limit

-
-#==== Emitters ====
-
-class Emitter
-
+class Sun
+
+    l: 180
     maxPhotons: 4000
-    rate: 0
-
-    cy: Canvas.height/2  # Canvas center
-    cx: Canvas.width/2  # Canvas center
-
-    constructor: ->
+    rate: 10
+    cx: Canvas.width/2
+
+    constructor: (@g, @q)->
         @photons = []

     emit: () ->
         unless @photons.length > @maxPhotons
-            # emitPhoton defined in subclass
-            # console.log "photons", @photons
             @photons.push(@emitPhoton()) for [0...@rate]
         @photons = @photons.filter (photon) => photon.visible()
         for photon in @photons
             photon.move()
             photon.draw()

-class Sun extends Emitter
-
-    x: 1
-    l: 180
-
+    emitPhoton: ->
+        pos = new Vector @cx + @l*(Math.random()-0.5), 1
+        new Sunlight(pos, @g, @q)
+
+class Simulation
+
     constructor: ->
-        #@velocity = new Vector 2, 0
-        @velocity = new Vector  0, 2
-        super()
-
-    emitPhoton: ->
-        #pos = new Vector @x, @cy + @l*(Math.random()-0.5)
-        pos = new Vector @cx + @l*(Math.random()-0.5), 1
-        new Sunlight(pos, @velocity)
-
-
-#==== Simulation ====
-
-class Simulation
-
-    constructor: ->
-        @sun = new Sun
-        @sun.rate = 10
+        g = (u) -> ((u<0)*1.5 + (u>0)/2)*u + 0.375
+        q = (y) -> Math.floor((y+0.875)/2*20)
+        @sun = new Sun g, q
         @h = new Histo

     start: () ->


Fixed _addDoc + improved feedback

Fixed _addDoc + improved feedback

--- main.coffee
+++ main.coffee
@@ -60,10 +60,14 @@

 _addDoc = (doc, callback) -> (callback) ->
     client.post 'data/', doc, (err, res, body) ->
-    if err?
-        callback("#{res.statusCode} - #{err}", null)
-    else
-        callback(null, 'OK')
+        if err?
+            if res?
+                statusCode = "#{statusCode} - "
+            else
+                statusCode = ""
+            callback("#{statusCode}#{err}", null)
+        else
+            callback(null, 'OK')

 _processFactory = (doctypeName, docs, callback) -> (callback) ->

@@ -85,8 +89,8 @@
         console.log "\t* Deleting documents from the Data System..."
         _removeDocs doctypeName, (err) ->
             if err?
-                msg = "\t\tx Couldn't delete documents from the data " + \
-                           "system --- #{err}"
+                msg = "\t\tx Couldn't delete documents from the Data " + \
+                           "System --- #{err}"
                 console.log msg.red
             else
                 msg = "\t\t-> Documents have been deleted from the Data System."
@@ -103,7 +107,8 @@
                     msg = "\t\tx One or more documents have not been added " + \
                           "to the Data System -- #{err}"
                     console.log msg.red
-                console.log "\t\t-> #{results.length} docs added!".green
+                else
+                    console.log "\t\t-> #{results.length} docs added!".green

                 # starts next doctype importation
                 callback null, null


Query database version on boot.

Query database version on boot.

--- main.coffee
+++ main.coffee
@@ -16,10 +16,16 @@

 'use strict'

-config = require './config.js'
+config = require "#{__dirname}/config.js"

 anyDB = require 'any-db'
+
 dbConnection = anyDB.createPool config.DATABASE_URL, min: 2, max: 20
+dbConnection.query 'SELECT version()', [], (error, result) ->
+	if error?
+		console.log "Problem with database: #{error.stack}"
+	else
+		console.log "Database: #{result.rows[0].version}"

 # Attach profiler?
 if process.env.SQLPROF is 'true'
@@ -59,7 +65,7 @@
 			#tx.__commit a
 		return tx

-lib = require './lib.coffee'
+lib = require "#{__dirname}/lib.coffee"
 async = require 'async'
 express = require 'express'
 sync = require 'sync'


Display a notification when downloading

Display a notification when downloading

--- src/components/library.coffee
+++ src/components/library.coffee
@@ -37,6 +37,7 @@
   downloadUpload: (upload) ->
     =>
       I.current_user().download_upload(@props.game.key.id, upload.id).then (res) =>
+        new Notification(JSON.stringify(res))
         console.log res
       , (errors) =>
         console.error "failed to download upload"


examples: make quadtree example executable


Better pattern for creating actions on arbitrary controller

This has the exact same functionality, except it's cleaner: calling
`endCommandBatch()` is now directly calling the action, instead
of the awkward `internalEndCommandBatchAction` pattern previously
used.

We still gave to explicitly listen to the actions, because we don't
have the simple "listenables" magic property that Reflux stores have.

--- src/code/utils/undo-redo.coffee
+++ src/code/utils/undo-redo.coffee
@@ -3,7 +3,9 @@

 DEFAULT_CONTEXT_NAME = 'building-models'

-internalEndCommandBatchAction = Reflux.createAction()
+# Note: We use several actions, because they hook into Reflux's dispatching system
+# which puts actions in a stack before calling them. We frequently want to ensure
+# that all other actions have completed before, e.g., we end a commandBatch.

 class Manager
   constructor: (options = {}) ->
@@ -13,17 +15,16 @@
     @savePosition = -1
     @changeListeners = []
     @currentBatch = null
-    internalEndCommandBatchAction.listen @_finalizeEndComandBatch, @
+
+    # listen to all our actions
+    @endCommandBatch.listen @_endComandBatch, @

   startCommandBatch: ->
     @currentBatch = new CommandBatch() unless @currentBatch

-  endCommandBatch: ->
-    # calling this via an action pushes it to the end of the
-    # command stack, allowing any other commands to execute first
-    internalEndCommandBatchAction()
+  endCommandBatch: Reflux.createAction()

-  _finalizeEndComandBatch: ->
+  _endComandBatch: ->
     if @currentBatch
       @commands.push @currentBatch
       @stackPosition++


removing bad URL and adding a white space before success to help prevent grabbing the word 'success' in URLs, image names, and emoticon names

--- src/victory.coffee
+++ src/victory.coffee
@@ -47,7 +47,6 @@
   "http://media.giphy.com/media/2vA33ikUb0Qz6/giphy.gif",
   "http://bestanimations.com/Sports/Baseball/funny-baseball-fans-animated-gif-2.gif,"
   "https://bigtennetworks.files.wordpress.com/2015/09/1-northwestern.gif",
-  "http://funnyasduck.net/wp-content/uploads/2013/04/funny-fan-dunk-phone-basketball-animated-gif-pics.gif,"
   "https://metrouk2.files.wordpress.com/2015/09/serena.gif"
 ]

@@ -55,5 +54,5 @@
   robot.hear /victory\b/i, (msg) ->
     msg.send msg.random victory

-  robot.hear /success\b/i, (msg) ->
+  robot.hear / success\b/i, (msg) ->
     msg.send msg.random victory


vmController: Fixed a regression with fetchVMs.

--- client/app/MainApp/VirtualizationController.coffee
+++ client/app/MainApp/VirtualizationController.coffee
@@ -202,8 +202,7 @@
       if @vms.length
         return @utils.defer => callback null, @vms

-      if not force and (waiting.push callback) > 1
-        return  callback null, []
+      return if not force and (waiting.push callback) > 1

       KD.remote.api.JVM.fetchVms (err, vms)=>
         @vms = vms  unless err


started componentifying and implementing wrapper api

--- dechat.cjsx
+++ dechat.cjsx
@@ -1,170 +1,105 @@
 React = require('react')
-
-# var comm = new Icecomm('4Mt09Xq/gyUee2TyDE.qC1.Lg2cXec.ZWBq3AGy32ZnDpsnP0.');
-
-
+ChatAPI = require('./icecomm_wrapper.coffee')

 DeChat = React.createClass
+  componentWillMount: () ->
+    ChatAPI.createName("Joe")
+    ChatAPI.createChatRoom()
   render: () ->
     return

-

-

-

-
Chatrooms

-
FB

-
AP

-
AB

-
SP

-
FB

-
AP

-
AB

-
SP

-

-

-
Users

-

-

-

-
Shuo

-

-

-

-

-

-
Ilan

-

-

-

-

-

-
Anton

-

-

-

-

-

-
Feifan

-

-

-

-

-
Video

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-
<video></video>

-

-

-

-

-

+

+

+

+
Chatrooms

+
FB

+
AP

+
AB

+
SP

+
FB

+
AP

+
AB

+
SP

+

+

+
Users

+

+

+

+
Shuo

-

-

-
Conversation

-                  <button className="camera">Video</button>
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-
Ilan

-

-                      Today this is a great day and I had so much fun coding
-

-

-

-

-                    <input className="newMessage" placeholder="chat here"></input>
-                    <button type="submit" className="send btn btn-primary">Send</button>
-

-

+

+

+

+
Ilan

+

+

+

+

+

+
Anton

+

+

+

+

+

+
Feifan

+

+

+

+

+
Video

+            <VideoContainer users={ChatAPI.rooms[ChatAPI.currentRoomID].users} />
+

+

+

+

+

+
Conversation

+          <button className="camera">Video</button>
+

+        <MessageContainer messages={ChatAPI.rooms[ChatAPI.currentRoomID].channels[@state.currentChannel].messages} />
+        <MessageSender currentChannel={@state.currentChannel} />
+

+

+
+VideoContainer = React.createClass
+  videos = @props.users.map (elem) ->
+    return

+

+
<video src={elem.stream}></video>

+

+

+  render: () ->
+    return

+      {videos}
+

+
+MessageContainer = React.createClass
+  render: () ->
+    messages = @props.messages.map (elem) ->
+      name = ChatAPI.rooms[ChatAPI.currentRoomID].users[elem.callerID]
+      isme = "isme" if elem.callerID == ChatAPI.userID else ""
+      return

+
{name}

+

+          {elem.text}
+

+

+    return

+      {messages}
+

+
+MessageSender = React.createClass
+  sendMessage: () ->
+    ChatAPI.createMessage(@state.value, @props.currentChannel)
+    @setState({value: ''})
+  handleChange: (ev) ->
+    @setState({value: ev.target.value})
+  render: () ->
+    return

+      <input className="newMessage" placeholder="chat here" value={@state.value} onChange={@handleChange}></input>
+      <button type="submit" className="send btn btn-primary" onClick={@sendMessage}>Send</button>
+

 module.exports = DeChat


Function to stop force layout

Function to stop force layout

--- graphedit-coffee/coffee/graphedit.coffee
+++ graphedit-coffee/coffee/graphedit.coffee
@@ -6,7 +6,6 @@
 colors = d3.scale.category10()

 redraw = () ->
-	console.log "in redraw"
 	svg.attr "transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")"

@@ -49,6 +48,18 @@
 		.attr "class", "node"
 		.attr "r", 5
 		.style "fill", (d) -> colors(d.id)
-		.call force.drag
+
+		# override to turn off force layout
+		.call force.drag().on "drag.force", () ->
+			d3.select(this).attr "transform", "translate(" + d3.event.x + "," + d3.event.y + ")"
+
+		.call force.drag().origin () ->
+			t = d3.transform(d3.select(this).attr("transform")).translate
+			{x:t[0], y:t[1]}
+
+stop = () ->
+	console.log("stopped")
+	force.stop()
+setTimeout stop, 1000

 console.log nodes


Remove verify_html as it isn't supported in TinyMCE 4

--- common/lib/xmodule/xmodule/js/src/html/edit.coffee
+++ common/lib/xmodule/xmodule/js/src/html/edit.coffee
@@ -53,7 +53,6 @@
       valid_children : "+body[style]",

       # Allow any elements to be used, e.g. link, script, math
-      verify_html: false,
       valid_elements: "*[*]",
       extended_valid_elements: "*[*]",
       invalid_elements: "",


Tabs

Tabs

- Allow "header_right". Still appends overflow button.
- Set "cui-button-size-mini" on Tab button when appearance is "mini".

--- src/elements/Tabs/Tabs.coffee
+++ src/elements/Tabs/Tabs.coffee
@@ -2,7 +2,7 @@

 	initOpts: ->
 		super()
-		@removeOpt("header_right")
+		# @removeOpt("header_right")
 		@removeOpt("header_center")
 		@removeOpt("content")

@@ -138,11 +138,13 @@
 			if not tab
 				continue
 			if tab instanceof Tab
-				@addTab(tab)
+				_tab = @addTab(tab)
 			else if CUI.isPlainObject(tab)
-				@addTab(new Tab(tab))
+				_tab = @addTab(new Tab(tab))
 			else
 				assert(false, "new #{@__cls}", "opts.tabs[#{idx}] must be PlainObject or Tab but is #{getObjectClass(tab)}", opts: @opts)
+			if @_appearance == "mini"
+				_tab.getButton().addClass("cui-button-size-mini")

 		@__tabs[@_active_idx or 0].activate()


Fix global requires

Fix global requires

--- src/wrapper.coffee
+++ src/wrapper.coffee
@@ -49,7 +49,7 @@
           @body.push node

       if @globalRequire
-        for node in (parse 'global.require = req').body
+        for node in (parse 'global.require = rqzt').body
           @body.push node


intel-corei7-64.coffee: Define attribute for the yocto flasher image

Signed-off-by: Florin Sarbu <3a837a37a2ac9072a088641ec330e0e5d5b86f4e@resin.io>

--- intel-corei7-64.coffee
+++ intel-corei7-64.coffee
@@ -91,7 +91,8 @@
 		image: 'resin-image-flasher'
 		fstype: 'resinos-img'
 		version: 'yocto-morty'
-		deployArtifact: 'resin-image-flasher-intel-corei7-64.resinos-img'
+		deployArtifact: 'resin-image-intel-corei7-64.resinos-img'
+		deployFlasherArtifact: 'resin-image-flasher-intel-corei7-64.resinos-img'
 		compressed: true

 	configuration:


add expectRelation helper function

add expectRelation helper function

--- workers/social/testhelper/index.coffee
+++ workers/social/testhelper/index.coffee
@@ -5,6 +5,7 @@
 JSession                = require '../lib/social/models/session'
 Bongo                   = require 'bongo'

+{ Relationship }        = require 'jraphical'
 { expect }              = require 'chai'
 { daisy, ObjectId }     = Bongo
 { argv }                = require 'optimist'
@@ -169,11 +170,34 @@
     else  caller[callee] client, kallback

+fetchRelation = (options, callback) ->
+
+  Relationship.one options, (err, relationship) ->
+    expect(err).to.not.exist
+    callback relationship
+
+
+expectRelation = {
+
+  toExist : (options, callback) ->
+    fetchRelation options, (relationship) ->
+      expect(relationship).to.exist
+      callback relationship
+
+  toNotExist : (options, callback) ->
+    fetchRelation options, (relationship) ->
+      expect(relationship).to.not.exist
+      callback relationship
+
+}
+
+
 module.exports = {
   _
   daisy
   expect
   ObjectId
+  expectRelation
   withDummyClient
   generateUserInfo
   withConvertedUser


API change to Client to support templatized urls

Resources instantiated using the URLs in api.directory are now
stored in client.directory, rather than client.resources.

client.resources is now an dictionary of functions for instantiating
resources when templatized URLs are required.

--- client.coffee
+++ client.coffee
@@ -74,17 +74,31 @@
     @authorizer = options.authorizer

     @resource_constructors = @create_resource_constructors(options.resources)
-    @resources = @create_resources(options.directory, @resource_constructors)
+    @resources = @create_resources(options.url_templates, @resource_constructors)
+    @directory = @create_directory(options.directory, @resource_constructors)
+
+
+  create_resources: (templates, constructors) ->
+    out = {}
+    for name, fn of templates
+      out[name] = @create_resource(name, fn)
+    out
+
+  create_resource: (name, fn) ->
+    (options) =>
+      constructor = @resource_constructors[name]
+      url = fn(options)
+      return new constructor(url: url)

   # Create resource instances using the URLs supplied in the service
   # description's directory.
-  create_resources: (directory, constructors) ->
-    resources = {}
-    for key, value of directory
+  create_directory: (urls, constructors) ->
+    out = {}
+    for key, url of urls
       if constructors[key]
-        resources[key] = new constructors[key](url: value)
-    return resources
+        out[key] = new constructors[key](url: url)
+    return out

   create_resource_constructors: (definitions) ->
     resource_constructors = {}


Chef rating fix (ignore guests)

Chef rating fix (ignore guests)

--- client.coffee
+++ client.coffee
@@ -132,7 +132,6 @@

 offset = (new Date).getTimezoneOffset()
 today = 0|((Plugin.time()-offset*60)/86400)
-log 'today', today

 renderDayItem = (day) !->
 	if typeof day=='object'
@@ -327,7 +326,6 @@
 									centField.value(0)
 								if v and inputField and centField
 									result = +(inputField.value()+"."+centField.value())
-									log result
 					Dom.on 'keydown', (evt) !->
 						if evt.getKeyCode() in [188,190] # comma and dot
 							centField.focus()
@@ -416,9 +414,10 @@
 		if info.cost?
 			for k,v of info.eat when v%1000
 				delta["#{k}/eat"] = v%1000
+				delta["#{k}/guests"] = (v-1)%1000
 				delta["#{k}/consumed"] = info.cost*(v%1000)/eaters
 			delta["#{cook}/cook"] = 1
-			delta["#{cook}/cookGuest"] = info.eat[cook]-1 if info.eat[cook]>1
+			# delta["#{cook}/cookGuest"] = info.eat[cook]-1 if info.eat[cook]>1
 			delta["#{cook}/fed"] = eaters
 			delta["#{cook}/spent"] = info.cost
 		else
@@ -448,7 +447,7 @@
 					renderFlex()
 					renderStat tr("chef"), !->
 						cook = stat.get('cook') || 0
-						cmpEat = (stat.get('eat')||0)%1000 - (stat.get('cookGuest')||0)
+						cmpEat = (stat.get('eat')||0)%1000 - (stat.get('guests')||0)
 						perc = Math.round(100*cook/(cmpEat||cook))
 						perc = (if isNaN(perc) then '-' else perc+'%')
 						Dom.text perc
@@ -472,7 +471,6 @@

 renderPersonalBalance = (id) !->
-	log "renderPersonalBalance", id
 	data = Obs.create()
 	merge = (delta, minus, month) ->
 		for k,v of delta
@@ -500,7 +498,6 @@
 			delta["#{cook}/spent"] = info.cost
 		else
 			delta["#{cook}/noCost"] = 1
-		log day, Util.getUTCMonth(day)
 		merge delta, false, Util.getUTCMonth(day)
 		Obs.onClean !-> merge delta, true


Corrected embed addition

Corrected embed addition

--- app/assets/javascripts/backoffice/backoffice.js.coffee
+++ app/assets/javascripts/backoffice/backoffice.js.coffee
@@ -9,7 +9,7 @@
 @add_fields = (link, association, content) ->
   new_id = new Date().getTime();
   regexp = new RegExp("new_" + association, "g");
-  $(link).prepend(content.replace(regexp, new_id))
+  $(link).prev().append(content.replace(regexp, new_id))

 $ ->
   try


OX-766 Bug fix

OX-766 Bug fix

--- app/assets/javascripts/oxalis/model/celltracing.coffee
+++ app/assets/javascripts/oxalis/model/celltracing.coffee
@@ -65,7 +65,7 @@
         @createNewTree()

     tracingType = tracing.typ
-    if (tracingType == "Task" or tracingType == "Training") and nodeList.length == 0
+    if (tracingType == "Task" or tracingType == "Training") and @getNodeListOfAllTrees().length == 0
       @addNode(tracing.content.editPosition)

     @branchPointsAllowed = tracing.content.settings.branchPointsAllowed


character limit

character limit

--- app/assets/javascripts/rails_admin/custom/ui.js.coffee
+++ app/assets/javascripts/rails_admin/custom/ui.js.coffee
@@ -25,7 +25,8 @@

   tag_input = $(".js-tag-suggestions__trigger input")
   if tag_input.length
-    elem = $("

")
+    elem = $(
+      "

")
     $(".js-tag-suggestions .controls .help-block").before elem

     tag_input.on 'blur', (e) ->
@@ -33,7 +34,8 @@

       $.get "/tags/#{name}.json", (tag_array) ->
         if tag_array.length
-          display = "Ähnliche Angebote verwenden folgende Tags:
#{tag_array.join(', ')}"
+          display = "Ähnliche Angebote verwenden folgende Tags:

+                    #{tag_array.join(', ')}"
         else
           display = "Es gibt keine Tags für Angebote mit genau diesem Namen."


Move roundToZero to a free function

Move roundToZero to a free function

And using parentheses when calling it

--- framer/LayerStyle.coffee
+++ framer/LayerStyle.coffee
@@ -1,6 +1,12 @@
 filterFormat = (value, unit) ->
 	"#{Utils.round value, 2}#{unit}"
 	# "#{value}#{unit}"
+
+roundToZero = (num) ->
+	if (-1e-6 < num && num < 1e-6)
+		return 0
+	return num
+

 # TODO: Ideally these should be read out from the layer defined properties
 _WebkitProperties = [
@@ -23,6 +29,7 @@
 	"skewY": 0
 	"rotationX": 0
 	"rotationY": 0
+

 exports.LayerStyle =

@@ -90,14 +97,7 @@

 		return css.join(" ")

-	_roundToZero: (num) ->
-		if (-1e-6 < num && num < 1e-6)
-			return 0
-		return num
-
 	webkitTransform: (layer) ->
-
-
 		# We have a special rendering path for layers that prefer 2d rendering.
 		# This definitely decreases performance, but is handy in complex drawing
 		# scenarios with rounded corners and shadows where gpu drawing gets weird
@@ -107,21 +107,21 @@
 			return exports.LayerStyle.webkitTransformForce2d(layer)
 		"
 		translate3d(
-			#{@_roundToZero layer._properties.x}px,
-			#{@_roundToZero layer._properties.y}px,
-			#{@_roundToZero layer._properties.z}px)
+			#{roundToZero(layer._properties.x)}px,
+			#{roundToZero(layer._properties.y)}px,
+			#{roundToZero(layer._properties.z)}px)
 		scale3d(
-			#{@_roundToZero(layer._properties.scaleX * layer._properties.scale)},
-			#{@_roundToZero(layer._properties.scaleY * layer._properties.scale)},
-			#{@_roundToZero layer._properties.scaleZ})
-		skew(#{@_roundToZero layer._properties.skew}deg,#{@_roundToZero layer._properties.skew}deg)
-		skewX(#{@_roundToZero layer._properties.skewX}deg)
-		skewY(#{@_roundToZero layer._properties.skewY}deg)
-		translateZ(#{@_roundToZero layer._properties.originZ}px)
-		rotateX(#{@_roundToZero layer._properties.rotationX}deg)
-		rotateY(#{@_roundToZero layer._properties.rotationY}deg)
-		rotateZ(#{@_roundToZero layer._properties.rotationZ}deg)
-		translateZ(#{@_roundToZero -layer._properties.originZ}px)
+			#{roundToZero(layer._properties.scaleX * layer._properties.scale)},
+			#{roundToZero(layer._properties.scaleY * layer._properties.scale)},
+			#{roundToZero(layer._properties.scaleZ)})
+		skew(#{roundToZero(layer._properties.skew)}deg,#{roundToZero(layer._properties.skew)}deg)
+		skewX(#{roundToZero(layer._properties.skewX)}deg)
+		skewY(#{roundToZero(layer._properties.skewY)}deg)
+		translateZ(#{roundToZero(layer._properties.originZ)}px)
+		rotateX(#{roundToZero(layer._properties.rotationX)}deg)
+		rotateY(#{roundToZero(layer._properties.rotationY)}deg)
+		rotateZ(#{roundToZero(layer._properties.rotationZ)}deg)
+		translateZ(#{roundToZero(-layer._properties.originZ)}px)
 		"

 	webkitTransformForce2d: (layer) ->
@@ -135,10 +135,10 @@
 			if layer._properties[p] isnt v
 				console.warn "Layer property '#{p}'' will be ignored with force2d enabled"

-		css.push "translate(#{@_roundToZero layer._properties.x}px,#{@_roundToZero layer._properties.y}px)"
-		css.push "scale(#{@_roundToZero layer._properties.scale})"
-		css.push "skew(#{@_roundToZero layer._properties.skew}deg,#{@_roundToZero layer._properties.skew}deg)"
-		css.push "rotate(#{@_roundToZero layer._properties.rotationZ}deg)"
+		css.push "translate(#{roundToZero(layer._properties.x)}px,#{roundToZero(layer._properties.y)}px)"
+		css.push "scale(#{roundToZero(layer._properties.scale)})"
+		css.push "skew(#{roundToZero(layer._properties.skew)}deg,#{roundToZero(layer._properties.skew)}deg)"
+		css.push "rotate(#{roundToZero(layer._properties.rotationZ)}deg)"

 		return css.join(" ")


Auth checking to middleware

Auth checking to middleware

--- main.coffee
+++ main.coffee
@@ -82,6 +82,13 @@
 app.set 'views', __dirname + '/views'

+mustBeAuthed = (request, response, next) ->
+	if request.uonline.basicOpts.loggedIn is true
+		next()
+	else
+		response.redirect '/login/'
+
+
 app.use ((request, response) ->
 	# Read basic stuff
 	request.uonline = {}
@@ -190,19 +197,16 @@
 		response.render 'login', options

-app.get '/profile/', (request, response) -> sync ->
-	if request.uonline.basicOpts.loggedIn is true
-		options = request.uonline.basicOpts
-		options.instance = 'profile'
-		options.username = request.uonline.basicOpts.login
-		options.profileIsMine = true
-		options.id = request.uonline.basicOpts.userid
-		chars = lib.game.getUserCharacters.sync null, dbConnection, request.uonline.basicOpts.userid
-		for i of chars
-			options[i] = chars[i]
-		response.render 'profile', options
-	else
-		response.redirect '/login/'
+app.get '/profile/', mustBeAuthed, (request, response) -> sync ->
+	options = request.uonline.basicOpts
+	options.instance = 'profile'
+	options.username = request.uonline.basicOpts.login
+	options.profileIsMine = true
+	options.id = request.uonline.basicOpts.userid
+	chars = lib.game.getUserCharacters.sync null, dbConnection, request.uonline.basicOpts.userid
+	for i of chars
+		options[i] = chars[i]
+	response.render 'profile', options

 app.get '/profile/:username/', (request, response) ->
@@ -228,81 +232,66 @@
 			response.redirect '/'

-app.get '/game/', (request, response) -> sync ->
-	if request.uonline.basicOpts.loggedIn is true
-		userid = request.uonline.basicOpts.userid
-		options = request.uonline.basicOpts
-		options.instance = 'game'
-
-		try
-			location = lib.game.getUserLocation.sync null, dbConnection, userid
-		catch e
-			console.log e.stack
-			location = lib.game.getDefaultLocation.sync null, dbConnection
-			lib.game.changeLocation.sync null, dbConnection, userid, location.id, true
-
-		area = lib.game.getUserArea.sync null, dbConnection, userid
-		options.location_name = location.title
-		options.area_name = area.title
-		options.pic = options.picture  if options.picture?
-		options.description = location.description
-		options.ways = location.goto
-		options.ways.forEach (i) -> # Facepalm. #273
-			i.name = i.text
-			i.to = i.id
-		tmpUsers = lib.game.getNearbyUsers.sync null,
-			dbConnection, userid, location.id
-		tmpUsers.forEach (i) -> # Facepalm. Refs #273 too.
-			i.name = i.user
-		options.players_list = tmpUsers
-		tmpMonsters = lib.game.getNearbyMonsters.sync null, dbConnection, location.id
-		options.monsters_list = tmpMonsters
-		options.fight_mode = lib.game.isInFight.sync null, dbConnection, userid
-		options.autoinvolved_fm = lib.game.isAutoinvolved.sync null, dbConnection, userid
-
-		chars = lib.game.getUserCharacters.sync null, dbConnection, request.uonline.basicOpts.userid
-		for i of chars
-			options[i] = chars[i]
-
-		response.header 'X-PJAX-URL', '/game/'
-		response.render 'game', options
-	else
-		response.redirect '/login/'
-
-
-app.get '/inventory/', (request, response) ->
-	if request.uonline.basicOpts.loggedIn is true
-		userid = request.uonline.basicOpts.userid
-		options = request.uonline.basicOpts
-		options.instance = 'inventory'
-		options.fight_mode = lib.game.isInFight.sync null, dbConnection, userid
-		response.render 'inventory', options
-	else
-		response.redirect '/login/'
-
-
-app.get '/action/go/:to', (request, response) ->
-	unless request.uonline.basicOpts.loggedIn
-		response.redirect '/login/'
-	else
-		lib.game.changeLocation.sync null, dbConnection, request.uonline.basicOpts.userid, request.param('to')
-		response.redirect '/game/'
-
-
-app.get '/action/attack', (request, response) ->
-	unless request.uonline.basicOpts.loggedIn
-		response.redirect '/login/'
-	else
-		lib.game.goAttack.sync null, dbConnection, request.uonline.basicOpts.userid
-		response.redirect '/game/'
-
-
-app.get '/action/escape', (request, response) ->
-	unless request.uonline.basicOpts.loggedIn
-		response.redirect '/login/'
-	else
-		lib.game.goEscape.sync null, dbConnection, request.uonline.basicOpts.userid
-		response.redirect '/game/'
+app.get '/game/', mustBeAuthed, (request, response) -> sync ->
+	userid = request.uonline.basicOpts.userid
+	options = request.uonline.basicOpts
+	options.instance = 'game'
+
+	try
+		location = lib.game.getUserLocation.sync null, dbConnection, userid
+	catch e
+		console.log e.stack
+		location = lib.game.getDefaultLocation.sync null, dbConnection
+		lib.game.changeLocation.sync null, dbConnection, userid, location.id, true
+
+	area = lib.game.getUserArea.sync null, dbConnection, userid
+	options.location_name = location.title
+	options.area_name = area.title
+	options.pic = options.picture  if options.picture?
+	options.description = location.description
+	options.ways = location.goto
+	options.ways.forEach (i) -> # Facepalm. #273
+		i.name = i.text
+		i.to = i.id
+	tmpUsers = lib.game.getNearbyUsers.sync null,
+		dbConnection, userid, location.id
+	tmpUsers.forEach (i) -> # Facepalm. Refs #273 too.
+		i.name = i.user
+	options.players_list = tmpUsers
+	tmpMonsters = lib.game.getNearbyMonsters.sync null, dbConnection, location.id
+	options.monsters_list = tmpMonsters
+	options.fight_mode = lib.game.isInFight.sync null, dbConnection, userid
+	options.autoinvolved_fm = lib.game.isAutoinvolved.sync null, dbConnection, userid
+
+	chars = lib.game.getUserCharacters.sync null, dbConnection, request.uonline.basicOpts.userid
+	for i of chars
+		options[i] = chars[i]
+
+	response.header 'X-PJAX-URL', '/game/'
+	response.render 'game', options
+
+
+app.get '/inventory/', mustBeAuthed, (request, response) ->
+	userid = request.uonline.basicOpts.userid
+	options = request.uonline.basicOpts
+	options.instance = 'inventory'
+	options.fight_mode = lib.game.isInFight.sync null, dbConnection, userid
+	response.render 'inventory', options
+
+
+app.get '/action/go/:to', mustBeAuthed, (request, response) ->
+	lib.game.changeLocation.sync null, dbConnection, request.uonline.basicOpts.userid, request.param('to')
+	response.redirect '/game/'
+
+
+app.get '/action/attack', mustBeAuthed, (request, response) ->
+	lib.game.goAttack.sync null, dbConnection, request.uonline.basicOpts.userid
+	response.redirect '/game/'
+
+
+app.get '/action/escape', mustBeAuthed, (request, response) ->
+	lib.game.goEscape.sync null, dbConnection, request.uonline.basicOpts.userid
+	response.redirect '/game/'

 app.get '/ajax/isNickBusy/:nick', (request, response) ->


Fix slider. Add stringify. Tidy.

Fix slider. Add stringify. Tidy.

--- main.coffee
+++ main.coffee
@@ -1,26 +1,14 @@
-
-# A Sheet is an array of data augmented with row and column names
-# (i.e., how spreadsheets look. Better name?). If row/col names aren't
-# given, defaults are applied. Data can be extracted by various
-# methods: for instance, JSON data with the row headings as keys
-# (rowJson). The data provided by the methods is suitable for
-# digestion by other table/plotting classes.

 class Sheet

-    constructor: (@spec) ->
-
-        @data = @spec.data
-
-        if @spec.colHeaders?
-            @colHeaders = @spec.colHeaders
-        else
-            @colHeaders = ('c'+k for k in [0...@data[0].length])
-
-        if @spec.rowHeaders?
-            @rowHeaders = @spec.rowHeaders
-        else
-            @rowHeaders = ('r'+k for k in [0...@data.length])
+    constructor: (@spec, @data, @colHeaders, @rowHeaders) ->
+
+        @data ?= [[0]]
+        numCols = @data[0].length
+        numRows = @data.length
+
+        @colHeaders ?= ("c#{k}" for k in [0...numCols])
+        @rowHeaders ?= ("r#{k}" for k in [0...numRows])

     rowJson: ->
         x = {}
@@ -28,89 +16,117 @@
         return x

     toLocal: ->
-        eval(@spec.id + " = $blab.sheet['" + @spec.id + "'].data")
-
-    fromLocal: ->
-        console.log "???", "$blab.sheet['" + @spec.id + "'].data = " + @spec.id
-        eval("$blab.sheet['" + @spec.id + "'].data = " + @spec.id)
-
-
-class Plot
+        eval("#{@spec.id} = $blab.sheet['#{@spec.id}'].data")
+
+    fromLocal: (u)->
+        $blab.sheet[@spec.id].data = u
+
+    stringify: ->
+        s = JSON.stringify(@spec)
+        d = JSON.stringify(@data)
+        r = JSON.stringify(@rowHeaders)
+        c = JSON.stringify(@colHeaders)
+        "{spec:#{s}, data:#{d}, rowHeaders:#{r}, colHeaders:#{c}}"
+
+class Figure

     constructor: (@spec) ->

         @sheet = $blab.sheet[@spec.id]
-
+        container = $("[data-sym=#{@spec.id}][data-type='figure']")[0]
+
         @chart = c3.generate(
-          bindto: $("[data-sym=#{@spec.id}][data-type='figure']")[0]
-          data: json: @sheet.rowJson()
+            bindto: container
+            data: json: @sheet.rowJson()
         )

     update: ->
         @chart.load(json: @sheet.rowJson())

+    stringify: ->
+        JSON.stringify($blab.figure[@spec.id]["spec"])
+

 class Table
-
+
     constructor: (@spec) ->

-        @sheet = $blab.sheet[@spec.id]
-        @data = @sheet.data
-
-        @table = new Handsontable $("[data-sym=#{@spec.id}][data-type='table']")[0],
-            data: @data
-            startRows: @data.length
-            startCols: @data[0].length
-            rowHeaders: @sheet.rowHeaders
-            colHeaders: @sheet.colHeaders
+        sheet = $blab.sheet[@spec.id]
+
+        data = sheet.data
+        numRows = data.length
+        numCols = data[0].length
+        container = $("[data-sym=#{@spec.id}][data-type='table']")[0]
+
+        @table = new Handsontable container,
+            data: data
+            startRows: numRows
+            startCols: numCols
+            rowHeaders: sheet.rowHeaders
+            colHeaders: sheet.colHeaders
             contextMenu: true
-            columns: ({type: 'numeric'} for k in [1..@data[0].length])
-            afterChange: (change, source) ->
-                compute() if source is "edit"
+            columns: ({type: 'numeric'} for k in [1..numCols])
+            afterChange: (change, source) =>
+                compute() if source is "edit" and @spec.compute

     update: ->
-        @data = @sheet.data
-        @table.loadData @data
+        @table.loadData $blab.sheet[@spec.id].data
         @table.render()

+    stringify: ->
+        JSON.stringify($blab.table[@spec.id]["spec"])
+

 class Slider

-    constructor: (@sheet, @spec) ->
-
-        @container = $("[data-sym=#{@spec.id}][data-type='slider']")
-        @container.css("width", @spec.width)
-
-        @container.append("

")
-        @slider = @container.find('.slider')
-
-        @container.append("

")
-        @label = @container.find('.label')
-        @label.html(@sheet.rowHeaders[0])
-
-        @container.append("<input type='text' readonly class='report'>")
-        @report = @container.find('.report')
-
+    constructor: (@spec) ->
+
+        @spec.width ?= 500
+        @spec.value ?= 1
+        @spec.min ?= 0
+        @spec.max ?= 10
+        @spec.step ?= 1
+
+        sheet = $blab.sheet[@spec.id]
+
+        container = $("[data-sym=#{@spec.id}][data-type='slider']")
+        container.css("width", @spec.width)
+        container.append("

")
+        container.append("

")
+        container.append("<input type='text' readonly class='report'>")
+
+        label = container.find('.label')
+        label.html(sheet.rowHeaders[0])
+
+        report = container.find('.report')
+
+        @slider = container.find('.slider')
         @slider.slider
-            value: 1
-            min: 0
-            max: 10
-            step: 1
-            slide: (event, ui) =>
-                @report.val ui.value
-                compute()
+            value: @spec.value
+            min: @spec.min
+            max: @spec.max
+            step: @spec.step
+            change: (event, ui) =>
+                report.val ui.value
+                compute() if @spec.compute

-        @report.val @slider.slider('value')
+        report.val @slider.slider("value")

     update: ->
-        $blab.sheet[@spec.id].data[0][0] = @slider.slider('value')
-
+        $blab.sheet[@spec.id].data[0][0] =  @slider.slider("value")
+
+    stringify: ->
+        JSON.stringify($blab.slider[@spec.id]["spec"])

 ## From GUI

 # sheets

-sh = (id, data) -> new Sheet {id:id, data:data}
+$blab.sheet = []
+sh = (id, data) -> new Sheet {id:id}, data #{id:id, data:data}
+
+$blab.sheet["A"] = sh "A", [[1,2],[3,4]]
+
 $blab.sheet =
     A: sh "A", [[1,2],[3,4]]
     x: sh "x", [[5],[6]]
@@ -118,19 +134,30 @@
     y: sh "y", [[30, 200, 100, 400, 150, 250],[50,  20,  10,  40,  15,  25]]
     z: sh "z", [[50]]
     q: sh "q", [[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]]
+    u: sh "u"

 $blab.sheet['y'].rowHeaders = ['dA','dB']
 $blab.sheet['y'].colHeaders = ['i','ii','iii','iv','v','vi']

+#console.log "!!!", $blab.sheet
+
 # slider

-slid = (id) -> new Slider $blab.sheet[id], {id:id , width: 500}
+slid = (id) -> new Slider
+    id:id
+    width: 500
+    value: 1
+    min: 0
+    max: 10
+    step: 1
+    compute: true
+
 $blab.slider =
     z: slid "z"

 # tables

-tab = (id) -> new Table {id:id}
+tab = (id) -> new Table {id:id, compute:true}
 $blab.table =
     A: tab "A"
     x: tab "x"
@@ -139,10 +166,15 @@

 # figures

-fig = (id) -> new Plot {id:id}
+fig = (id) -> new Figure {id:id}

 $blab.figure =
     q: fig "q"
+
+
+
+console.log "??stringify??", $blab.sheet["A"].stringify()
+

 # user code

@@ -154,8 +186,11 @@
     for sl of $blab.slider
         $blab.slider[sl].update()

+    console.log "z???", $blab.sheet["z"].data
+
     # local copy of vars
     for sh of $blab.sheet
+        #console.log "sh", sh
         $blab.sheet[sh].toLocal()

     ## user code
@@ -172,8 +207,7 @@
     # update stuff
     #
     for s of $blab.sheet
-        eval("$blab.sheet['" + s + "'].data = " + s)
-        #$blab.sheet[s].fromLocal()
+        $blab.sheet[s].fromLocal(eval(s))

     for t of $blab.table
         $blab.table[t].update()


Imported basic animation now class.

Imported basic animation now class.

--- main.coffee
+++ main.coffee
@@ -5,7 +5,7 @@

 # Set up grid
 N = 256
-dt = 0.8/N.pow(2)  # 0.4 in Trefethen
+dt = 0.4/N.pow(2)  # 0.4 in Trefethen
 x = 2*pi/N * linspace(-N/2, N/2-1, N)

 # Integrating factor
@@ -41,7 +41,6 @@
 soliton = (A, x1) ->
     3*A.pow(2) * (sech(.5*A*(x+x1))).pow(2)

-# Soliton graph (LineChart imported from another blab - see "Ext" section)
 lineChart = new $blab.LineChart
     id: "solitons"
     xLabel: "x"
@@ -52,13 +51,22 @@
     yTicks: 5
     click: (x, y) -> initSoliton(x, y)

-# Initial soliton plot
-count = 0
-u0 = null
+@kdv = new $blab.BasicAnimation
+    numSnapshots: 2000
+    delay: 10
+    strobeInterval: 10000
+    snapshotFunction: ->
+    strobeFunction: ->
+
+# Plot control
+count = 0 # number of solitons in plot
+u0 = null # initial condition
 initSoliton = (xS, yS) ->
-    $blab.stopAnimation()
+    @kdv.stopAnimation()
     count++
-    u0 = zeros(x) if count is 1
+    if count is 1
+        u0 = zeros(x)
+        @kdv.n = 0
     x1 = -xS
     A = sqrt(yS/3)
     u0 += soliton(A, x1)
@@ -69,17 +77,12 @@

 # Animated soliton plot
 animateSolitons = (u) ->
-    # Solve PDE and plot results.
-    # u: initial conditions
     v = fft u
-    snapshot = ->
+    @kdv.snapshotFunction = ->
         {u, v} = computeUV(v)
         lineChart.plot(x, u)
-    $blab.animate snapshot, 1000, 10
+    @kdv.animate()

 # Run: two solitons
 initSoliton(-1, 800)
-initSoliton(0, 200)  #;
-
-#!end (coffee)
-
+initSoliton(0, 200)


added prism showing instance startup logs

--- imports/ui/pages/InstanceDetailPage.cjsx
+++ imports/ui/pages/InstanceDetailPage.cjsx
@@ -3,6 +3,8 @@
 _             = require 'lodash'
 DetailPage    = require '../DetailPage.cjsx'
 Helpers       = require '../Helpers.coffee'
+{PrismCode}   = require 'react-prism'
+ansi_up       = require('ansi_up')

 { Header, Split, Sidebar, Notification, Section, List, ListItem, Heading, Menu, Button, Icons } = require 'grommet'

@@ -39,6 +41,17 @@
           </List>

+

+

+          <PrismCode className="language-bash">
+            {x = @props.instance.logs?.startup?.join('')
+            console.log x
+            x
+            }
+          </PrismCode>
+

+

+
         {_.map @props.instance.services, (service, name) ->

             <Heading tag='h2'>{name}</Heading>


Required libs in Downloader

Required libs in Downloader

--- source/Downloader.coffee
+++ source/Downloader.coffee
@@ -2,3 +2,9 @@
   Downloader module for MP3 Downloader.
   Written by Jense5.
 ###
+
+# Require external libs
+fs = require('fs')
+request = require('request')
+cheerio = require('cheerio')
+inquirer = require('requirer')


undo button, just make play work like live edit

--- obot.coffee
+++ obot.coffee
@@ -235,6 +235,27 @@

   return

+renderUndoButton = (ctx) ->
+  ics = inner_control_size
+  ctx.beginPath()
+  ctx.arc(0,0,ics*.3, -Math.PI/8, Math.PI/8, true)
+
+  arrowEnd =
+    x: Math.cos(-Math.PI/8)*ics*.3
+    y:-Math.sin(-Math.PI/8)*ics*.3
+  innerArrow =
+    x: arrowEnd.x + Math.cos(Math.PI*(1-1/8+.125))*ics*.3*.5
+    y: arrowEnd.y - Math.sin(Math.PI*(1-1/8+.125))*ics*.3*.5
+  outerArrow =
+    x: arrowEnd.x + Math.cos(Math.PI*(-1/8-.3))*ics*.3*.5
+    y: arrowEnd.y - Math.sin(Math.PI*(-1/8-.3))*ics*.3*.5
+
+  ctx.lineTo(innerArrow.x, innerArrow.y)
+  ctx.moveTo(arrowEnd.x, arrowEnd.y)
+  ctx.lineTo(outerArrow.x, outerArrow.y)
+
+  ctx.stroke()
+  return

 # TODO: these should handle the passage of time? or maybe that is up to
 # stepLevelSimulation?
@@ -277,7 +298,7 @@
     when levelMode.STOPPED
       level.commands[level.current_command] = @cmd
       level.advanceCurrentCommand()
-    when levelMode.LIVE_EDIT, levelMode.PLAYING
+    when levelMode.PLAYING
       level.commands[level.commands.length] = @cmd

   return
@@ -285,6 +306,18 @@
 playButtonAction = (level) ->
   level.resetAndRun()
   return
+
+undoButtonAction = (level) ->
+  if level.commands.length == 0
+    return false
+
+  level.commands = level.commands[...-1]
+
+  if level.current_command >= level.commands.length
+    level.resetAndRun()
+    while level.step()
+      true
+

 arrowButtonRender = (ctx) ->
   renderArrow(ctx, @dir.theta, inner_control_size)
@@ -312,13 +345,15 @@
 play_button =
   render: renderPlayButton
   action: playButtonAction
+undo_button =
+  render: renderUndoButton
+  action: undoButtonAction

 # level

 levelMode =
-  STOPPED: 0
-  PLAYING: 1
-  LIVE_EDIT: 2
+  STOPPED: 1
+  PLAYING: 2

 levelAnimMode =
   READY: 1  # ready to run the next command
@@ -331,7 +366,6 @@
   @bot.showyi = @bot.yi = @initial_bot_location.yi
   @bot.showdir = @bot.dir = @initial_bot_location.dir

-
   @current_command = 0

   return
@@ -341,6 +375,7 @@
   @mode = levelMode.PLAYING
   @last_t = Date.now()/1000
   @animation_mode = levelAnimMode.READY
+  delete @move_control

   return

@@ -353,33 +388,26 @@

 animateLevel = (t) ->

-  if @mode == levelMode.STOPPED
+  if @mode == levelMode.STOPPED or
+     (@mode == levelMode.PLAYING and @animation_mode == levelAnimMode.READY)
     @show_current_command = @current_command
     @bot.showxi = @bot.xi
     @bot.showyi = @bot.yi
     @bot.showdir = @bot.dir

+  if @mode == levelMode.STOPPED
     return

   dt = t - @last_t

-  # PLAYING or LIVE_EDIT
+  # PLAYING

   if @animation_mode == levelAnimMode.READY
     @show_current_command = @current_command
     next_move_control =
       start: (t: t, x: @bot.xi, y: @bot.yi, dir: @bot.dir)
       duration: 1/bot_speed
-    if not @step()
-
-      switch @mode
-        when levelMode.PLAYING
-          @mode = levelMode.LIVE_EDIT
-          @animation_mode = levelAnimMode.READY
-
-        #when levelMode.LIVE_EDIT keep waiting
-
-    else
+    if @step()
       @move_control = next_move_control
       @animation_mode = levelAnimMode.MOVING

@@ -419,7 +447,7 @@
     animate: animateLevel
     step: stepLevelSimulation

-    mode: levelMode.LIVE_EDIT
+    mode: levelMode.PLAYING
     animation_mode: levelAnimMode.READY

     advanceCurrentCommand: -> @current_command++
@@ -430,7 +458,7 @@

 # control panel
 setupControlPanel = ->
-  buttons: [ play_button,
+  buttons: [ play_button, undo_button,
             go_up_button, go_down_button, go_left_button, go_right_button ]
   selected_button: null
   render: renderControlPanel
@@ -449,6 +477,8 @@

   level_state.animate(t)
   level_state.render(level_ctx, prog_ctx)
+
+  #stop = true

   if !stop
     requestAnimationFrame(render)


[➦] Merged changes.

[➦] Merged changes.

--- vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/shadify/shady.js.coffee
@@ -1,36 +1,5 @@
 class @Shady
   # === Constants ==
-
-  @MESH:
-    width: 1.2
-    height: 1.2
-    depth: 10
-    segments: 20
-    slices: 16
-    xRange: 0.8
-    yRange: 0.1
-    zRange: 1.0
-    ambient: '#555555'
-    diffuse: '#FFFFFF'
-    speed: 0.002
-
-  @LIGHT:
-    count: 2
-    xyScalar: 1
-    zOffset: 100
-    ambient: '#880066'
-    diffuse: '#FF8800'
-    speed: 0.001
-    gravity: 1200
-    dampening: 0.95
-    minLimit: 10
-    maxLimit: null
-    minDistance: 20
-    maxDistance: 400
-    autopilot: true
-    draw: true
-    bounds: do FSS.Vector3.create
-    step: FSS.Vector3.create Math.randomInRange(0.2, 1.0), Math.randomInRange(0.2, 1.0), Math.randomInRange(0.2, 1.0)

   @WEBGL: 'webgl'
   @CANVAS: 'canvas'
@@ -44,6 +13,37 @@
   rendering:
     renderer: @WEBGL

+    mesh:
+      width: 1.0
+      height: 1.0
+      depth: 5
+      segments: 16
+      slices: 8
+      xRange: 1.6
+      yRange: 0.1
+      zRange: 1.0
+      ambient: '#555555'
+      diffuse: '#FFFFFF'
+      speed: 0.002
+
+    light:
+      count: 2
+      xyScalar: 1
+      zOffset: 100
+      ambient: '#880066'
+      diffuse: '#FF8800'
+      speed: 0.001
+      gravity: 1200
+      dampening: 0.95
+      minLimit: 10
+      maxLimit: null
+      minDistance: 20
+      maxDistance: 400
+      autopilot: true
+      draw: true
+      bounds: do FSS.Vector3.create
+      step: FSS.Vector3.create Math.randomInRange(0.2, 1.0), Math.randomInRange(0.2, 1.0), Math.randomInRange(0.2, 1.0)
+
   # === Public ===

   constructor: (element, options) ->
@@ -66,36 +66,40 @@
     return

   update: ->
-    offset = Shady.MESH.depth / 2
+    offset = @rendering.mesh.depth / 2

     # Update bounds
-    FSS.Vector3.copy Shady.LIGHT.bounds, @center
-    FSS.Vector3.multiplyScalar Shady.LIGHT.bounds, Shady.LIGHT.xyScalar
+    FSS.Vector3.copy @rendering.light.bounds, @center
+    FSS.Vector3.multiplyScalar @rendering.light.bounds, @rendering.light.xyScalar

     # Update attractor
-    FSS.Vector3.setZ @attractor, Shady.LIGHT.zOffset
+    FSS.Vector3.setZ @attractor, @rendering.light.zOffset

     # Overwrite the attractor position
-    if Shady.LIGHT.autopilot
-      ox = Math.sin Shady.LIGHT.step[0] * @now * Shady.LIGHT.speed
-      oy = Math.cos Shady.LIGHT.step[1] * @now * Shady.LIGHT.speed
+    if @rendering.light.autopilot
+      ox = Math.sin @rendering.light.step[0] * @now * @rendering.light.speed
+      oy = Math.cos @rendering.light.step[1] * @now * @rendering.light.speed

       FSS.Vector3.set(
         @attractor
-        Shady.LIGHT.bounds[0] * ox
-        Shady.LIGHT.bounds[1] * oy
-        Shady.LIGHT.zOffset
+        @rendering.light.bounds[0] * ox
+        @rendering.light.bounds[1] * oy
+        @rendering.light.zOffset
       )

     # Animate lights
-    for light in @scene.lights
+    l = @scene.lights.length - 1
+
+    while l >= 0
+      light = @scene.lights[l]
+
       # Reset the z-position of the light
-      FSS.Vector3.setZ light.position, Shady.LIGHT.zOffset
+      FSS.Vector3.setZ light.position, @rendering.light.zOffset

       # Calculate the force Luke!
-      d = Math.clamp FSS.Vector3.distanceSquared(light.position, @attractor), Shady.LIGHT.minDistance, Shady.LIGHT.maxDistance
-
-      f = Shady.LIGHT.gravity * light.mass / d
+      d = Math.clamp FSS.Vector3.distanceSquared(light.position, @attractor), @rendering.light.minDistance, @rendering.light.maxDistance
+
+      f = @rendering.light.gravity * light.mass / d

       FSS.Vector3.subtractVectors light.force, @attractor, light.position
       FSS.Vector3.normalise light.force
@@ -105,27 +109,35 @@
       FSS.Vector3.set light.acceleration
       FSS.Vector3.add light.acceleration, light.force
       FSS.Vector3.add light.velocity, light.acceleration
-      FSS.Vector3.multiplyScalar light.velocity, Shady.LIGHT.dampening
-      FSS.Vector3.limit light.velocity, Shady.LIGHT.minLimit, Shady.LIGHT.maxLimit
+      FSS.Vector3.multiplyScalar light.velocity, @rendering.light.dampening
+      FSS.Vector3.limit light.velocity, @rendering.light.minLimit, @rendering.light.maxLimit
       FSS.Vector3.add light.position, light.velocity

-    # Animate vertices
-    for vertex in @geometry.vertices
-      ox = Math.sin vertex.time + vertex.step[0] * @now * Shady.MESH.speed
-      oy = Math.cos vertex.time + vertex.step[1] * @now * Shady.MESH.speed
-      oz = Math.sin vertex.time + vertex.step[2] * @now * Shady.MESH.speed
-
-      FSS.Vector3.set (
+      l--
+
+    # Animate Vertices
+    v = @geometry.vertices.length - 1
+
+    while v >= 0
+      vertex = @geometry.vertices[v]
+
+      ox = Math.sin(vertex.time + vertex.step[0] * @now * @rendering.mesh.speed)
+      oy = Math.cos(vertex.time + vertex.step[1] * @now * @rendering.mesh.speed)
+      oz = Math.sin(vertex.time + vertex.step[2] * @now * @rendering.mesh.speed)
+
+      FSS.Vector3.set(
         vertex.position
-        Shady.MESH.xRange * @geometry.segmentWidth * ox
-        Shady.MESH.yRange * @geometry.sliceHeight * oy
-        Shady.MESH.zRange * offset * oz - offset
+        @rendering.mesh.xRange * @geometry.segmentWidth * ox
+        @rendering.mesh.yRange * @geometry.sliceHeight * oy
+        @rendering.mesh.zRange * offset * oz - offset
       )

       FSS.Vector3.add vertex.position, vertex.anchor

+      v--
+
     # Set the geometry to dirty
-    # @geometry.dirty = true
+    @geometry.dirty = true

     return

@@ -133,8 +145,12 @@
     @renderer.render @scene

     # Draw Lights
-    if Shady.LIGHT.draw
-      for light in @scene.lights
+    if @rendering.light.draw
+      l = @scene.lights.length - 1
+
+      while l >= 0
+        light = @scene.lights[l]
+
         lx = light.position[0]
         ly = light.position[1]

@@ -169,6 +185,8 @@
             light.ring.setAttributeNS null, 'cy', ly

             @renderer.element.appendChild light.ring
+
+        l--

     return

@@ -215,10 +233,6 @@

     return

-  onMouseClick: (event) =>
-    FSS.Vector3.set @attractor, event.x, @renderer.height - event.y
-    FSS.Vector3.subtract @attractor, @center
-
   # === Private ===

   initialize = ->
@@ -269,15 +283,15 @@
     # add the mesh to the scene

     @geometry = new FSS.Plane(
-      Shady.MESH.width * @renderer.width
-      Shady.MESH.height * @renderer.height
-      Shady.MESH.segments
-      Shady.MESH.slices
+      @rendering.mesh.width * @renderer.width
+      @rendering.mesh.height * @renderer.height
+      @rendering.mesh.segments
+      @rendering.mesh.slices
     )

     @material = new FSS.Material(
-      Shady.MESH.ambient
-      Shady.MESH.diffuse
+      @rendering.mesh.ambient
+      @rendering.mesh.diffuse
     )

     @mesh = new FSS.Mesh(
@@ -288,7 +302,11 @@
     @scene.add @mesh

     # Augment vertices for animation
-    for vertex in @geometry.vertices
+    v = @geometry.vertices.length - 1
+
+    while v >= 0
+      vertex = @geometry.vertices[v]
+
       vertex.anchor = FSS.Vector3.clone vertex.position

       vertex.step = FSS.Vector3.create(
@@ -299,16 +317,26 @@

       vertex.time = Math.randomInRange 0, Math.PIM2

+      v--
+
     return

   createLights = ->
-    for light in @scene.lights
+    l = @scene.lights.length - 1
+
+    while l >= 0
+      light = @scene.lights[l]
+
       @scene.remove light

+      l--
+
     do @renderer.clear

-    for i in [0...Shady.LIGHT.count]
-      light = new FSS.Light Shady.LIGHT.ambient, Shady.LIGHT.diffuse
+    l = 0
+
+    while l < @rendering.light.count
+      light = new FSS.Light @rendering.light.ambient, @rendering.light.diffuse

       light.ambientHex = do light.ambient.format
       light.diffuseHex = do light.diffuse.format
@@ -335,12 +363,13 @@
       light.core.setAttributeNS null, 'fill', light.diffuseHex
       light.core.setAttributeNS null, 'r', '4'

+      l++
+
     return

   addEventListeners = ->
     window.addEventListener 'resize', @onWindowResize

-    @container.addEventListener 'click', @onMouseClick
-    @container.addEventListener 'mousemove', @onMouseMove
+    window.addEventListener 'mousemove', @onMouseMove

     return


fixed coffeelint errors on workers/social/lib/social/models/computeproviders/machine.coffee

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -3,7 +3,7 @@
 { revive }  = require './computeutils'
 KodingError = require '../../error'

-{argv}      = require 'optimist'
+{ argv }    = require 'optimist'
 KONFIG      = require('koding-config-manager').load("main.#{argv.c}")

 module.exports = class JMachine extends Module
@@ -12,8 +12,8 @@

   @trait __dirname, '../../traits/protected'

-  {slugify} = require '../../traits/slugifiable'
-  {permit}  = require '../group/permissionset'
+  { slugify } = require '../../traits/slugifiable'
+  { permit }  = require '../group/permissionset'

   @share()

@@ -89,7 +89,7 @@

       label             :
         type            : String
-        default         : -> ""
+        default         : -> ''

       slug              : String

@@ -109,26 +109,26 @@

         state           :
           type          : String
-          enum          : ["Wrong type specified!", [
+          enum          : ['Wrong type specified!', [

             # States which description ending with '...' means its an ongoing
             # proccess which you may get progress info about it
             #
-            "NotInitialized"  # Initial state, machine instance does not exists
-            "Building"        # Build started machine instance creating...
-            "Starting"        # Machine is booting...
-            "Running"         # Machine is physically running
-            "Stopping"        # Machine is turning off...
-            "Stopped"         # Machine is turned off
-            "Rebooting"       # Machine is rebooting...
-            "Terminating"     # Machine is getting destroyed...
-            "Terminated"      # Machine is destroyed, not exists anymore
-            "Unknown"         # Machine is in an unknown state
+            'NotInitialized'  # Initial state, machine instance does not exists
+            'Building'        # Build started machine instance creating...
+            'Starting'        # Machine is booting...
+            'Running'         # Machine is physically running
+            'Stopping'        # Machine is turning off...
+            'Stopped'         # Machine is turned off
+            'Rebooting'       # Machine is rebooting...
+            'Terminating'     # Machine is getting destroyed...
+            'Terminated'      # Machine is destroyed, not exists anymore
+            'Unknown'         # Machine is in an unknown state
                               # needs to solved manually

           ]]

-          default       : -> "NotInitialized"
+          default       : -> 'NotInitialized'

       meta              : Object

@@ -144,25 +144,29 @@
   # Helpers
   # -------

-  generateSlugFromLabel = ({user, group, label, index}, callback)->
+  generateSlugFromLabel = ({ user, group, label, index }, callback) ->

     slug = _label = if index? then "#{label}-#{index}" else label
     slug = slugify slug

     JMachine.count {
-      users : $elemMatch: id: user.getId()
-      groups: $elemMatch: id: group.getId()
+      users        :
+        $elemMatch :
+          id       : user.getId()
+      groups       :
+        $elemMatch :
+          id       : group.getId()
       slug
-    }, (err, count)->
+    }, (err, count) ->

       return callback err  if err?

       if count is 0
-        callback null, {slug, label: _label}
+        callback null, { slug, label: _label }
       else
         index ?= 0
         index += 1
-        generateSlugFromLabel {user, group, label, index}, callback
+        generateSlugFromLabel { user, group, label, index }, callback

   isOwner  = (user, machine) ->
@@ -175,7 +179,7 @@
     return owner

-  excludeUser = (options)->
+  excludeUser = (options) ->

     { users, user, permanent } = options

@@ -191,11 +195,11 @@
     return newUsers

-  addUser = (users, options)->
+  addUser = (users, options) ->

     # asOwner option is disabled for now ~ GG
     # passing False for owner
-    {user, asOwner, permanent} = options
+    { user, asOwner, permanent } = options

     newUsers = excludeUser { users, user, permanent }

@@ -216,10 +220,10 @@

   informAccounts = (users, machineUId, action) ->

-    users.forEach (user)->
-      user.fetchOwnAccount (err, account)->
+    users.forEach (user) ->
+      user.fetchOwnAccount (err, account) ->
         return if err or not account
-        account.sendNotification 'MachineListUpdated', {machineUId, action}
+        account.sendNotification 'MachineListUpdated', { machineUId, action }

   # Private Methods
@@ -227,7 +231,7 @@

   # Static Methods

-  @create = (data, callback)->
+  @create = (data, callback) ->

     # JMachine.uid is a unique id which is generated from:
     #
@@ -237,7 +241,7 @@
     # 3     first letter of `provider`
     # 4..12 32-bit random hex string

-    {user, group, provider} = data
+    { user, group, provider } = data

     data.user  = username  = user.username
     data.group = groupSlug = group.slug
@@ -262,10 +266,10 @@
       assignedAt   : data.createdAt

     data.status    =
-      state        : "NotInitialized"
+      state        : 'NotInitialized'
       modifiedAt   : data.createdAt

-    if provider is "koding"
+    if provider is 'koding'
       { userSitesDomain } = KONFIG
       data.domain = "#{data.uid}.#{username}.#{userSitesDomain}"
     else
@@ -273,9 +277,9 @@

     data.provisioners  ?= [ ]

-    {label} = data
-
-    generateSlugFromLabel {user, group, label}, (err, {slug, label})->
+    { label } = data
+
+    generateSlugFromLabel { user, group, label }, (err, { slug, label }) ->

       return callback err  if err?

@@ -283,20 +287,20 @@
       data.slug  = slug

       machine = new JMachine data
-      machine.save (err)->
+      machine.save (err) ->

         if err
           callback err
-          console.warn "Failed to create Machine for ", {username, groupSlug}
+          console.warn 'Failed to create Machine for ', { username, groupSlug }
         else
           callback null, machine

-  @getSelectorFor = (client, {machineId, owner})->
+  @getSelectorFor = (client, { machineId, owner }) ->

     { r: { group, user } } = client

-    userObj    = if owner then {sudo: yes, owner: yes} else {}
+    userObj    = if owner then { sudo: yes, owner: yes } else {}
     userObj.id = user.getId()

     selector  =
@@ -304,15 +308,19 @@
         { _id : ObjectId machineId }
         { uid : machineId }
       ]
-      users   : $elemMatch: userObj
-      groups  : $elemMatch: id: group.getId()
+      users        :
+        $elemMatch : userObj
+      groups       :
+        $elemMatch :
+          id       : group.getId()

     return selector

-
+  # due to a bug in coffeelint 1.10.1
+  # coffeelint: disable=no_implicit_braces
   # Instance Methods

-  destroy: (client, callback)->
+  destroy: (client, callback) ->

     { r: { user } } = client

@@ -322,27 +330,27 @@
     @remove callback

-  addUsers: (options, callback)->
-
-    {targets, asOwner, permanent} = options
+  addUsers: (options, callback) ->
+
+    { targets, asOwner, permanent } = options

     users = @users.splice 0

     for user in targets
-      users = addUser users, {user, asOwner, permanent}
+      users = addUser users, { user, asOwner, permanent }

     if users.length > 10
       callback new KodingError \
-        "Machine sharing is limited up to 10 users."
+        'Machine sharing is limited up to 10 users.'
     else
       @update $set: { users }, (err) =>
         informAccounts targets, @getAt('uid'), 'added'
         callback err

-  removeUsers: (options, callback)->
-
-    {targets, permanent, inform} = options
+  removeUsers: (options, callback) ->
+
+    { targets, permanent, inform } = options

     users = @users.splice 0

@@ -354,7 +362,7 @@
       callback err

-  shareWith: (options, callback)->
+  shareWith: (options, callback) ->

     { target, asUser, asOwner, permanent, inform } = options

@@ -363,15 +371,15 @@
     inform  ?= yes

     unless target?
-      return callback new KodingError "Target required."
+      return callback new KodingError 'Target required.'

     JUser = require '../user'
     JName = require '../name'

-    JName.fetchModels target, (err, result)=>
+    JName.fetchModels target, (err, result) =>

       if err or not result?
-        return callback new KodingError "Target not found."
+        return callback new KodingError 'Target not found.'

       targets = (target.models[0]  for target in result)

@@ -380,16 +388,16 @@
       if target instanceof JUser

         if asUser
-        then @addUsers {targets, asOwner, permanent}, callback
-        else @removeUsers {targets, permanent, inform}, callback
+        then @addUsers { targets, asOwner, permanent }, callback
+        else @removeUsers { targets, permanent, inform }, callback

       else
-        callback new KodingError "Target does not support machines."
+        callback new KodingError 'Target does not support machines.'

   fetchOwner: (callback) ->

-    owner = user for user in @users when user.owner and user.sudo
+    owner = (user for user in @users when user.owner and user.sudo)
     errCb = -> callback new KodingError 'Owner user not found'
     return errCb()  unless owner

@@ -411,11 +419,11 @@
       shouldReviveClient   : yes
       shouldReviveProvider : no

-    , (client, machineId, callback)->
-
-      selector = @getSelectorFor client, {machineId}
-
-      JMachine.one selector, (err, machine)->
+    , (client, machineId, callback) ->
+
+      selector = @getSelectorFor client, { machineId }
+
+      JMachine.one selector, (err, machine) ->
         callback err, machine

@@ -426,7 +434,7 @@
       shouldReviveClient   : yes
       shouldReviveProvider : no

-    , (client, selector, callback)->
+    , (client, selector, callback) ->

       { r: { group, user } } = client

@@ -434,24 +442,24 @@
       selector['users.id']  = user.getId()
       selector['groups.id'] = group.getId()

-      JMachine.some selector, limit: 30, (err, machines)->
+      JMachine.some selector, limit: 30, (err, machines) ->
         callback err, machines

-  @fetchByUsername = (username, callback)->
+  @fetchByUsername = (username, callback) ->

     JUser = require '../user'
-    JUser.one {username}, (err, user)->
+    JUser.one { username }, (err, user) ->

       return callback err  if err
-      return callback new KodingError "User not found."  unless user
+      return callback new KodingError 'User not found.'  unless user

       selector        =
         'users.id'    : user.getId()
         'users.sudo'  : yes
         'users.owner' : yes

-      JMachine.some selector, limit: 30, (err, machines)->
+      JMachine.some selector, limit: 30, (err, machines) ->
         callback err, machines

@@ -464,7 +472,7 @@
       shouldReviveClient   : yes
       shouldReviveProvider : no

-    , (client, provisioner, callback)->
+    , (client, provisioner, callback) ->

       { r: { user } } = client

@@ -472,7 +480,7 @@
         return callback new KodingError 'Access denied'

       JProvisioner = require './provisioner'
-      JProvisioner.one$ client, slug: provisioner, (err, provision)=>
+      JProvisioner.one$ client, { slug: provisioner }, (err, provision) =>
         if err or not provision?
           callback new KodingError 'Provisioner not found'
         else
@@ -486,10 +494,10 @@
       shouldReviveClient   : yes
       shouldReviveProvider : no

-    , (client, options, callback)->
+    , (client, options, callback) ->

       { r: { user } } = client
-      {permanentOnly} = options
+      { permanentOnly } = options

       unless isOwner user, this
         return callback new KodingError 'Access denied'
@@ -499,13 +507,13 @@
       accounts = []
       queue    = []

-      (@users ? []).forEach (_user)->
+      (@users ? []).forEach (_user) ->

         return  if permanentOnly and not _user.permanent

-        queue.push -> JUser.one _id: _user.id, (err, user)->
+        queue.push -> JUser.one { _id: _user.id }, (err, user) ->
           if not err? and user
-            user.fetchOwnAccount (err, account)->
+            user.fetchOwnAccount (err, account) ->
               if not err? and account?
                 accounts.push account
               queue.next()
@@ -525,29 +533,29 @@
       shouldReviveClient   : yes
       shouldReviveProvider : no

-    , (client, label, callback)->
+    , (client, label, callback) ->

       { r: { user, group } } = client

       unless isOwner user, this
         return callback new KodingError 'Access denied'

-      kallback = (err, slug)->
+      kallback = (err, slug) ->
         if err?
         then callback err
         else callback null, slug

       slug = slugify label

-      if slug is ""
-        return callback new KodingError "Nickname cannot be empty"
+      if slug is ''
+        return callback new KodingError 'Nickname cannot be empty'

       if slug isnt @slug
-        generateSlugFromLabel { user, group, label }, (err, {slug, label})=>
+        generateSlugFromLabel { user, group, label }, (err, { slug, label }) =>
           return callback err  if err?
-          @update $set: { slug, label }, (err)-> kallback err, slug
+          @update $set: { slug, label }, (err) -> kallback err, slug
       else
-        @update $set: { label }, (err)-> kallback err, slug
+        @update $set: { label }, (err) -> kallback err, slug

   # .shareWith can be used like this:
@@ -568,36 +576,36 @@
       shouldReviveProvider : no
       shouldLockProcess    : yes

-    , (client, options, callback)->
+    , (client, options, callback) ->

       { r: { user } } = client

       # Only an owner of this machine can modify it
       unless isOwner user, this
-        return callback new KodingError "Access denied"
+        return callback new KodingError 'Access denied'

       { target, permanent, asUser } = options

       # At least one target is required
       if not target or target.length is 0
-        return callback new KodingError "A target required."
+        return callback new KodingError 'A target required.'

       # Max 9 target can be passed
       if target.length > 9
         return callback new KodingError \
-          "It is not allowed to change more than 9 state at once."
+          'It is not allowed to change more than 9 state at once.'

       # Owners cannot unassign them from a machine
       # Only another owner can unassign any other owner
       if user.username in target
         return callback \
-          new KodingError "You are not allowed to change your own state!"
+          new KodingError 'You are not allowed to change your own state!'

       # For Koding provider credential field is username
       # and we don't allow them to be removed from users
       if @provider is 'koding' and @credential in target
         return callback \
-          new KodingError "It is not allowed to change owner state!"
+          new KodingError 'It is not allowed to change owner state!'

       # If it's a call for unshare then no need to check
       # any other state for it
@@ -613,7 +621,7 @@
                    # TODO: we can limit this for koding provider only ~ GG

         Payment = require '../payment'
-        Payment.subscriptions client, {}, (err, subscription)=>
+        Payment.subscriptions client, {}, (err, subscription) =>

           if err? or not subscription? or subscription.planTitle is 'free'
             return callback \
@@ -632,12 +640,12 @@
     @shareWith$ client, options, callback

-  unshare: secure (client, users, callback)->
+  unshare: secure (client, users, callback) ->

     options = target: users, asUser: no

-    {connection:{delegate}} = client
-    {profile:{nickname}}    = delegate
+    { connection:{ delegate } } = client
+    { profile:{ nickname } }    = delegate

     if users.length is 1 and users[0] is nickname
     then @shareWith options, callback
@@ -662,7 +670,7 @@
     shouldReviveProvider : no
     hasOptions           : no

-  , (client, callback)->
+  , (client, callback) ->

     { r: { user } } = client

@@ -671,9 +679,9 @@
       return callback null

     JMachine.update
-      "_id"      : @getId()
-      "users.id" : user._id
-    , $set       : "users.$.approved" : yes
+      '_id'      : @getId()
+      'users.id' : user._id
+    , $set       : 'users.$.approved' : yes
     , (err) =>
       options = { action: 'approve', @uid }
       client.connection.delegate.sendNotification 'MachineShareActionTaken', options
@@ -687,7 +695,7 @@
     shouldReviveProvider : no
     hasOptions           : no

-  , (client, callback)->
+  , (client, callback) ->

     { r: { user } } = client

@@ -709,7 +717,7 @@

   @shareByUId = secure (client, uid, options, callback) ->

-    JMachine.one {uid}, (err, machine) ->
+    JMachine.one { uid }, (err, machine) ->

       return callback err  if err
       return callback 'Machine is not found'  unless machine
@@ -717,3 +725,5 @@
       machine.shareWith$ client, options, (err) ->

         callback err, machine
+
+


JMachine::shareWith: add support for permanent option

Permanent option is only valid for paid accounts, if its passed we are checking
for a valid subscription from Payment. If everything is ok, shared user will be
added as permanent: true into the users list of subject JMachine document.

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -175,10 +175,12 @@
     return newUsers

-  addUser = (users, user, asOwner)->
+  addUser = (users, options)->
+
+    {user, asOwner, permanent} = options

     newUsers = excludeUser users, user
-    newUsers.push { id: user.getId(), owner: asOwner }
+    newUsers.push { id: user.getId(), owner: asOwner, approved: no, permanent }

     return newUsers

@@ -247,12 +249,14 @@

   # Instance Methods

-  addUsers: (usersToAdd, asOwner, callback)->
+  addUsers: (options, callback)->
+
+    {targets, asOwner, permanent} = options

     users = @users.splice 0

-    for user in usersToAdd
-      users = addUser users, user, asOwner
+    for user in targets
+      users = addUser users, {user, asOwner, permanent}

     if users.length > 10
       callback new KodingError \
@@ -273,9 +277,11 @@

   shareWith: (options, callback)->

-    { target, asUser, asOwner } = options
-    asUser  ?= yes
-    asOwner ?= no
+    { target, asUser, asOwner, permanent } = options
+
+    asUser    ?= yes
+    asOwner   ?= no
+    permanent ?= no

     unless target?
       return callback new KodingError "Target required."
@@ -295,7 +301,7 @@
       if target instanceof JUser

         if asUser
-        then @addUsers targets, asOwner, callback
+        then @addUsers {targets, asOwner, permanent}, callback
         else @removeUsers targets, callback

       else
@@ -443,9 +449,12 @@
   # .shareWith can be used like this:
   #
   # JMachineInstance.shareWith {
-  #   asUser: yes, asOwner: no, target: ["gokmen", "dicle"]}, cb
+  #   asUser: yes, asOwner: no, target: ["gokmen", "dicle"], permanent: no}, cb
   # }
   #                        user slugs ->  ^^^^^^ ,  ^^^^^
+  #
+  # ps. permanent option requires a valid paid subscription
+  #

   shareWith$: permit 'populate users',

@@ -461,7 +470,7 @@
       unless isOwner user, this
         return callback new KodingError "Access denied"

-      { target } = options
+      { target, permanent } = options

       if target.length > 9
         return callback new KodingError \
@@ -477,8 +486,24 @@
         return callback \
           new KodingError "It is not allowed to change owner state!"

-      JMachine::shareWith.call this, options, callback
-
+      # Permanent option is only valid for paid accounts
+      # if its passed then we need to check payment
+      #
+      if permanent # and @provider is 'koding'
+                   # TODO: we can limit this for koding provider only ~ GG
+
+        Payment = require '../payment'
+        Payment.subscriptions client, {}, (err, subscription)=>
+
+          if err? or not subscription? or subscription.planTitle is 'free'
+            return callback \
+              new KodingError "You don't have a paid subscription!"
+
+          JMachine::shareWith.call this, options, callback
+
+      else
+
+        JMachine::shareWith.call this, options, callback

   share: secure (client, users, callback) ->


JMachine: add more data to model, update state field based on klient

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -58,26 +58,34 @@
       users             : Array
       groups            : Array

-      state             :
-        type            : String
-        enum            : ["Wrong type specified!", [
+      createdAt         : Date

-          # States which description ending with '...' means its an ongoing
-          # proccess which you may get progress info about it
-          #
-          "NotInitialized"  # Initial state, machine instance does not exists
-          "Building"        # Build started machine instance creating...
-          "Starting"        # Machine is booting...
-          "Running"         # Machine is physically running
-          "Stopping"        # Machine is turning off...
-          "Stopped"         # Machine is turned off
-          "Rebooting"       # Machine is rebooting...
-          "Terminating"     # Machine is getting destroyed...
-          "Terminated"      # Machine is destroyed, not exists anymore
+      status            :

-        ]]
+        modifiedAt      : Date

-        default         : "NotInitialized"
+        state           :
+          type          : String
+          enum          : ["Wrong type specified!", [
+
+            # States which description ending with '...' means its an ongoing
+            # proccess which you may get progress info about it
+            #
+            "NotInitialized"  # Initial state, machine instance does not exists
+            "Building"        # Build started machine instance creating...
+            "Starting"        # Machine is booting...
+            "Running"         # Machine is physically running
+            "Stopping"        # Machine is turning off...
+            "Stopped"         # Machine is turned off
+            "Rebooting"       # Machine is rebooting...
+            "Terminating"     # Machine is getting destroyed...
+            "Terminated"      # Machine is destroyed, not exists anymore
+            "Unknown"         # Machine is in an unknown state
+                              # needs to solved manually
+
+          ]]
+
+          default       : -> "NotInitialized"

       meta              : Object

@@ -93,7 +101,13 @@
     # 4..12 32-bit random hex string

     {user, group, provider} = data
+
     data.uid = "u#{user[0]}#{group[0]}#{provider[0]}#{(require 'hat')(32)}"
+    data.createdAt = new Date()
+    data.status  =
+      state      : "NotInitialized"
+      modifiedAt : data.createdAt
+
     return new JMachine data


[PUBDEV-4497] Use info log as default

[PUBDEV-4497] Use info log as default

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -1738,7 +1738,7 @@
           else
             go null, extendLogFile cloud, nodeIpPort, fileType, logFile

-  getLogFile = (nodeIpPort="self", fileType='warn') ->
+  getLogFile = (nodeIpPort="self", fileType='info') ->
     _fork requestLogFile, nodeIpPort, fileType

   requestNetworkTest = (go) ->


fix user creation bug

fix user creation bug

--- common.coffee
+++ common.coffee
@@ -17,8 +17,12 @@
     type: Boolean
   createdAt:
     type: Date
+  services:
+    type: Object
+    optional: true
+    blackbox: true

-#Meteor.users.attachSchema Schemas.User
+Meteor.users.attachSchema Schemas.User

 share.Dishes = new Meteor.Collection "dishes"
 Schemas.Dish = new SimpleSchema


Removed a few hubot scripts (especially the try one)

--- packages/rocketchat-hubot/hubot.coffee
+++ packages/rocketchat-hubot/hubot.coffee
@@ -167,12 +167,8 @@
 		scriptsToLoad = [
 			'alot.coffee'
 			'applause.coffee'
-			'bang-bang.coffee'
-			'base58.coffee'
-			'base64.coffee'
 			'beerme.coffee'
 			'botsnack.coffee'
-			'brewerydb.coffee'
 			'calm-down.coffee'
 			'carlton.coffee'
 			'chuck-norris.coffee'
@@ -194,7 +190,6 @@
 			'hangout.coffee'
 			'hashing.coffee'
 			'hello.coffee'
-			'homer.coffee'
 			'httpcat.coffee'
 			'karma.coffee'
 			'megusta.coffee'


Some additional styling of organization/email warnings.

--- picoCTF-web/web/coffee/front-page.coffee
+++ picoCTF-web/web/coffee/front-page.coffee
@@ -38,7 +38,7 @@
     else
       showGroupMessage = (->
         <Alert bsStyle="info">
-          You are registering as part of the {@props.groupName} organization.
+          You are registering as a member of {@props.groupName}.
         </Alert>
       ).bind this

@@ -51,8 +51,10 @@
       registrationForm = if @props.status == "Register" then \

           <Row>
-            {if @props.groupName.length > 0 then showGroupMessage() else }
-            {if @props.emailFilter.length > 0 then showEmailFilter() else }
+

+              {if @props.groupName.length > 0 then showGroupMessage() else }
+              {if @props.emailFilter.length > 0 then showEmailFilter() else }
+

             <Col md={6}>
               <Input type="text" id="first-name" valueLink={@props.firstname} label="First Name"/>
             </Col>


enforce hashtable key to be a string

enforce hashtable key to be a string

--- tds.coffee
+++ tds.coffee
@@ -718,6 +718,7 @@
     s = key
     s.retain()
    else
+    key = "#{key}"
     s = new StringClass key
    hash = s.hash()
    #console.log "hash: #{hash}"
@@ -761,6 +762,7 @@
     s = key
     s.retain()
    else
+    key = "#{key}"
     s = new StringClass key
    hash = s.hash()
    pos = hash % size


Update ZeroChat.coffee

Update ZeroChat.coffee

--- js/ZeroChat.coffee
+++ js/ZeroChat.coffee
@@ -85,7 +85,7 @@
         replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim
         replacePattern4 = /0net:\/\/([-a-zA-Z0-9+&.,:+_\/=?]*)/g
         replacePattern5 = /(([a-zA-Z0-9\-\_\.])+)\/\/0mail/gim;
-
+
         # // url rewriting 127.0.0.1:43110 to 0net:// so other replacements don't break
         replacedText = body.replace(replacePattern0, '0net://')
         replacedText = replacedText.replace('@zeroid.bit', '//0mail')
@@ -147,13 +147,15 @@

                 # // STYLE OUR MESSAGES AND MENTIONS
                 prestyle=""
-                poststyle = ''
+                poststyle=""
                 # our messages
                 if userid == Page.site_info.cert_user_id
                     prestyle = ''
+                    poststyle = ''
                 # our mentions
                 if Page.site_info.cert_user_id and body.indexOf(Page.site_info.cert_user_id.replace('@zeroid.bit', '')) > -1
                     prestyle = ''
+                    poststyle = ''
                 body = prestyle + body + poststyle

                 message_lines.push "
#{time} #{username}#{msgseparator} #{body}
"
@@ -170,7 +172,7 @@
     onOpenWebsocket: (e) =>
         @cmd "siteInfo", {}, (site_info) =>
             document.getElementById("bigTitle").innerHTML = site_info.content.title + ' - ' + site_info.content.description
-            document.getElementById("peerCount").innerHTML = site_info.peers + ' Visitors'
+            document.getElementById("peerCount").innerHTML = site_info.peers + ' Peers'

             # Update currently selected username
             if site_info.cert_user_id


Bugfix: starting cells needs to count as visited.

This was creating cycles sometimes.

--- maze.coffee
+++ maze.coffee
@@ -37,7 +37,8 @@
     @passages = {}
     starting_cell = (randrange(0, d) for d in @dimensions)
     active_cells = [starting_cell]
-    visited_cells = {} # using joined tuples for keys
+    visited_cells = {}
+    visited_cells[starting_cell] = true
     until active_cells.length == 0
       cell = choice(active_cells)
       unvisited_neighbors =


using UTC for time calc

using UTC for time calc

--- time.coffee
+++ time.coffee
@@ -1,7 +1,7 @@
 ms_in_a_day = 1000 * 60 * 60 * 24

 calculate_year = (now) ->
-  origin = new Date(2009, 2, 28)
+  origin = new Date(Date.UTC(2009, 2, 28))
   ms = now.getTime() - origin.getTime()
   real_life_days = Math.ceil(ms / ms_in_a_day)
   real_life_days / 12 # 3 days for each of 4 seasons


put the image uploaded for group cover photo

--- client/Social/Activity/views/feedcoverphotoview.coffee
+++ client/Social/Activity/views/feedcoverphotoview.coffee
@@ -23,9 +23,16 @@
     admin = role for role in KD.config.roles when role is "admin"
     if admin
       new KDButtonView
-        style  : "solid green small account-header-button"
-        type   : "submit"
-        title  : "update cover photo"
+        style     : "solid green small"
+        type      : "submit"
+        title     : "update cover photo"
+        callback  : =>
+          new UploadImageModalView
+            title         : "Change Cover Photo"
+            imageSize     :
+              width       : 914
+              height      : 315
+            imageType     : "coverPhoto"
     else
       new KDCustomHTMLView


--- client/app/MainApp/maintabs/maintabhandleholder.coffee
+++ client/app/MainApp/maintabs/maintabhandleholder.coffee
@@ -73,7 +73,9 @@
             contextMenu.destroy()
           separator            : yes
         'Search the App Store' :
-          callback             : (source, event)=> appManager.open "Apps"
+          callback             : (source, event)=>
+            appManager.open "Apps"
+            contextMenu.destroy()
         'Make your own app...' :
           callback             : (source, event)=> appsController.makeNewApp()


KodingKontrol: disable autoReconnect for kloud kite since we are forcing XHR for it

--- client/app/lib/kite/kodingkontrol.coffee
+++ client/app/lib/kite/kodingkontrol.coffee
@@ -143,6 +143,8 @@
     # allow to use websockets by emptying the protocols_whitelist
     if kiteName is 'klient'
       options.transportOptions = protocols_whitelist: []
+    else if kiteName is 'kloud'
+      options.autoReconnect = no

     kite = KontrolJS::createKite.call this, options


More formatting.

More formatting.

--- main.coffee
+++ main.coffee
@@ -300,10 +300,12 @@
 	setInstance('monster'), render('monster')

-app.get '/action/logout', mustBeAuthed, (request, response) ->
-	lib.user.closeSession.sync null,
-		dbConnection, request.uonline.sessid
-	response.redirect '/'
+app.get '/action/logout',
+	mustBeAuthed,
+	(request, response) ->
+		lib.user.closeSession.sync null,
+			dbConnection, request.uonline.sessid
+		response.redirect '/'

 app.get '/game/',


Set a max-height for body when inside a modal

--- client/lanes/components/modal/Modal.cjsx
+++ client/lanes/components/modal/Modal.cjsx
@@ -65,7 +65,7 @@
                 <BS.Modal.Title>{@state.title}</BS.Modal.Title>
             </BS.Modal.Header>

-            <BS.Modal.Body>
+            <BS.Modal.Body style={maxHeight: @context.viewport.height - 250}>
                 <Body modal={@} />
             </BS.Modal.Body>


Added include and require highlighting

Added include and require highlighting

--- grammars/sstemplate.cson
+++ grammars/sstemplate.cson
@@ -2,6 +2,11 @@
 'foldingStartMarker': '<%\\s[^end].*\\s%>'
 'foldingStopMarker': '<%\\send.*\\s%>'
 'patterns': [
+  {
+    'begin': '<% (include|require)'
+    'end': '-? %>'
+    'name': 'keyword.control.import.include.ss'
+  }
   {
     'begin': '<% +(?!>)[-=]?'
     'captures':
@@ -16,9 +21,6 @@
             'name': 'punctuation.definition.comment.ruby'
         'match': '(#).*?(?=-? %>)'
         'name': 'comment.line.number-sign.ruby'
-      }
-      {
-        'include': 'source.ruby.rails'
       }
     ]
   }
@@ -36,9 +38,6 @@
             'name': 'punctuation.definition.comment.html'
         'match': '(#).*?(?=-?--%>)'
         'name': 'invalid.illegal.bad-comments-or-CDATA.html'
-      }
-      {
-        'include': '#embedded-code'
       }
     ]
   }
@@ -72,7 +71,6 @@
   'ss-variable-open':
     'match': '\\$(.*[\w\d]*(\([\w\d\'\,\s]*\))*)*'
     'name': 'variable.ss'
-    # 'match': '\\$[a-zA-Z0-9\\.\(\)\,]*'
   'ss-variable-closed':
     'begin': '\{\\$'
     'end': '\}'


Edit grunt/tasks/watch.coffee

Edit grunt/tasks/watch.coffee

--- grunt/tasks/watch.coffee
+++ grunt/tasks/watch.coffee
@@ -16,8 +16,10 @@
           enabled: true
           port: process.env['GILM_LIVERELOAD_PORT'] || process.env['LIVERELOAD_PORT']
           extensions: ['js', 'css']
+
       'scss': (path) =>
         ["compass:build"]
+
       'coffee': (path) =>
         if path.match(/^spec\/src\/coffee\//)
           ['test']


Changed policy on restarting the same controller.  Before it just let a controller continue running, but now it explicitly stops it and restarts it, just in case there is any progressive enhancement that must be performed on start.

--- src/controller.js.coffee
+++ src/controller.js.coffee
@@ -11,18 +11,17 @@
       if jQuery(contr.selector).length > 0
         newActive = contr

-    if @active? and @active isnt newActive
+    if @active?
       # We need to start a new controller, so make sure we stop the current one if
       # this is one
       @active.stop()
       window.onbeforeunload = null

     if newActive?
-      if @active isnt newActive
-        @active = newActive
-        @active.start()
-        window.onbeforeunload = =>
-          @active.stop()
+      @active = newActive
+      @active.start()
+      window.onbeforeunload = =>
+        @active.stop()
     else
       @active = null


Explicitly test for error

Explicitly test for error

--- test/errors.coffee
+++ test/errors.coffee
@@ -131,13 +131,14 @@
         done()

   class ErrorStream extends Readable
-    contructor: (@query) ->
+    contructor: (_) ->

     _read: ->
      @emit 'error', new Error("Error")
      return @push null

   it 'should only get one callback if stream errors then ends', (done) ->
-    new Understream(new ErrorStream()).run ->
+    new Understream(new ErrorStream()).run (err) ->
+      assert err
       # If done is called multiple times then mocha will complain
       done()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/follow.coffee
+++ test/follow.coffee
@@ -18,18 +18,6 @@

   ok enemy.I.direction.equal(Point(1, 0)), 'enemy should head toward player with velocity Point(1, 0)'

-  fastEnemy = GameObject
-    x: 50
-    y: 100
-    width: 10
-    height: 10
-    followSpeed: 5
-
-  fastEnemy.include(Follow)
-  fastEnemy.follow(player)
-
-  ok fastEnemy.I.velocity.equal(Point(0, -5)), 'fastEnemy should head toward player with velocity Point(0, 5)'
-
   rightEnemy = GameObject
     x: 100
     y: 50


Make the redraw method global and remove the duplicated code from the domain method

Signed-off-by: Marko Locher <9efe9a5a1da5f41a4eb7599f2715dc24abf5bbc8@locher.at>

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -179,7 +179,7 @@
         for dataset in @options.datasets
             do (dataset) => @drawDataset(dataset)

-        redraw = =>
+        @redraw = =>
             # update brush
             @brush.x(@scales.x).extent(@brush.extent())

@@ -198,13 +198,13 @@
             @options.width = if @useBBox then svg.getBBox().width else svg.clientWidth
             @scales.x.range([0, @options.width])

-            redraw()
+            @redraw()

         d3.select(window).on('resize', resize)

         # zooming & dragging
         zoom = =>
-            redraw()
+            @redraw()

         @options.zoom = d3.behavior.zoom()
             .x(@scales.x)
@@ -235,18 +235,9 @@
         @options.domain.end = end

         @scales.x.domain([ @options.domain.start, @options.domain.end ])
-
-        # TODO: duplication of code in the redraw() function
-        # update brush
-        @brush.x(@scales.x).extent(@brush.extent())
-
-        # repaint the axis and the brush
-        d3.select(@element).select('g.axis').call(@axis.x)
-        d3.select(@element).select('g.brush').call(@brush)
-
-        # repaint the datasets
-        for dataset of @data
-            @updateDataset(dataset)
+        @redraw()
+
+        true

     select: (params...) ->
         start = new Date(params[0])


Turned off splashscreen for webadmin.

Turned off splashscreen for webadmin.

--- community/server/src/main/coffeescript/webadmin.coffee
+++ community/server/src/main/coffeescript/webadmin.coffee
@@ -69,7 +69,7 @@
     $("body").append(baseView.el)
     Backbone.history.start()

-    if not splashScreen.hasBeenShownForThisSession()
-      splashScreen.show()
+    #if not splashScreen.hasBeenShownForThisSession()
+    #  splashScreen.show()

 )