Update mini-course-content.coffee

Update mini-course-content.coffee

--- app/lib/mini-course-content.coffee
+++ app/lib/mini-course-content.coffee
@@ -8,7 +8,7 @@

The 2nd phase of the mission (K2) began in 2014. During this phase the telescope will be looking at new patches of sky every 75 days, providing a fresh set of data for you to search through on Planet Hunters.

       """
       figure: "./images/mini-course/01-KeplerHR_sm.jpg"
-      figure_credits: "Image courtesy of NASA"
+      figure_credits: "Image credit: NASA"
   }
   {
     course_number: 2
@@ -39,7 +39,7 @@
   {
     course_number: 4
     material:
-      title: "What can we learn from a lightcurve? (Part 2)"
+      title: "What can we learn from a lightcurve?"
       text: """

           If we observe multiple transits at equally spaced intervals then we know they are caused by a single planet and we have a measurement of its orbital period, as it is just the time interval between each transit. Astronomer Johannes Kepler showed that orbital period,P, is proportional to orbital separation, a:
@@ -89,7 +89,7 @@

Also, if one of the background stars is actually an eclipsing binary it may appear like there are smaller transits occurring on the target star, when in fact there is nothing there at all. The right-hand panel of the diagram below shows an example of this scenario.

         """
       figure: "./images/mini-course/slide-7.jpg"
-      figure_credits: ""
+      figure_credits: "Image credit: NASA/Wendy Stenzel"

   }

@@ -113,7 +113,7 @@
         The idea of planets orbiting other stars in our galaxy has been around for hundreds of years (in fact 16th century Italian astronomer Giordano Bruno was burnt at the stake at least in part for his beliefs on the matter!). However, it was not until 1992 that the first exoplanet was confirmed. It was found orbiting a pulsar, the rapidly-spinning, dense core of a dead star. The first confirmed planet orbiting a Sun-like star, 51 Pegesi b, was announced in 1995. Since then over one thousand exoplanets have been confirmed and many more candidates identified. The graph below shows the distribution of planet candidates discovered by the Kepler mission as of November 2013.
         """
       figure: "./images/mini-course/8-size-candidates.jpg"
-      figure_credits: "NASA"
+      figure_credits: ""

   }

@@ -125,7 +125,7 @@
         The first confirmed planet discovered by volunteers, like you, on Planet Hunters was PH1b (also known as Kepler-64b). It is a Neptune-sized giant planet with a radius 6 times greater than that of the Earth. The really interesting thing about PH1b is that it’s a circumbinary planet, meaning it orbits around two stars! Those two stars are also in orbit around another binary star system, which makes PH1b the first planet ever discovered in a quadruple star system. Below is an artist’s impression of the system.
         """
       figure: "./images/mini-course/9-FirstPlanet.png"
-      figure_credits: "NASA"
+      figure_credits: "Image Credit: H. Giguere, M. Giguere"

   }

@@ -137,7 +137,7 @@
         PH2b is the second planet discovered by volunteers on Planet Hunters. It is a Jupiter-sized, gas giant planet in orbit around a star very similar to our Sun. It’s orbit is only 17% smaller than that of the Earth, putting it in a region known as the habitable zone, the distance from a star where the conditions may be right for life. You will learn more about the habitable zone later. Below is an artist’s impression of the view from a hypothetical habitable moon in orbit around PH2b.
         """
       figure: "./images/mini-course/10-2b.png"
-      figure_credits: "NASA"
+      figure_credits: "Image Credit: H. Giguere, M. Giguere"

   }

@@ -161,7 +161,7 @@
         Stars are mostly made of hydrogen, which is also true for some gas giant planets such as Jupiter. The difference is that stars are massive enough to ignite nuclear fusion of hydrogen into helium in their cores. The smallest stars are roughly 75 times more massive than Jupiter, and the largest planets are about 13 times more massive than Jupiter.
         """
       figure: "./images/mini-course/12-star-v-planet.jpg"
-      figure_credits: "NASA"
+      figure_credits: ""

   }

@@ -173,7 +173,7 @@
         A star spends the majority of its active life burning the hydrogen in its core. Stars that are in this phase are known as main sequence stars. Main sequence stars are split into 7 main groups named O, B, A, F, G, K and M in order from hottest to coolest. Our Sun is a G-type star but the vast majority of stars in our galaxy are smaller, cooler M-type stars.
         """
       figure: "./images/mini-course/13-spectral-chart.jpg"
-      figure_credits: "NASA"
+      figure_credits: ""

   }

@@ -185,7 +185,7 @@
         There exists a region around a star inside which a planet may be considered habitable by life as we understand it. Habitability can depend on many factors but the main one is the potential for liquid water to exist on the surface of an Earth-sized, rocky planet. This therefore depends primarily on the distance of the planet from its host star. Too close and the water will boil, too far and it will freeze. Stars that are smaller and cooler than our Sun (such as M-dwarfs) will have habitable zones that are much closer in, which means potentially habitable planets around them will have shorter orbital periods than a year.
         """
       figure: "./images/mini-course/14-HabitableZone.png"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: NASA"

   }

@@ -196,10 +196,10 @@
       text: """

The transit method is a very simple and effective method for discovering planets, but it is not the only one used by astronomers. Let’s have a look at some of the other methods:

         THE RADIAL VELOCITY METHOD
-
As a planet orbits a star its gravitational pull moves the star around. Therefore at some points the star is moving towards us (the observer) and at other points it is moving away from us. We can measure the speed of this movement by looking at the spectrum of light from the star. When moving towards us the star’s light becomes more blue, and when moving away its light becomes more red. The faster the star is moving, the more massive the planet. For example, Jupiter moves the Sun at 12.7 m/s (slightly faster than Usain Bolt can run), whereas the effect from Earth is over 100 times smaller, making it much easier to detect larger planets.

+
As a planet orbits a star its gravitational pull moves the star around. Therefore at some points the star is moving towards us and at other points it is moving away from us. We can measure the speed of this movement by examining the light from the star. When moving towards us the star’s light becomes more blue, and when moving away, more red. The faster the star is moving, the more massive the planet. For example, Jupiter moves the Sun at 12.7 m/s (slightly faster than Usain Bolt can run), whereas the effect of the Earth is 100 times smaller, making it much easier to detect larger planets.

         """
       figure: "./images/mini-course/slide-16.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: NASA"

   }

@@ -211,7 +211,7 @@
         The radial velocity method has been used to discover hundreds of exoplanets to date, however it has one major disadvantage; it cannot be used to determine the angle of the planetary system to our line-of-sight, so perhaps we are only seeing a small fraction of the star’s movement? This means that only a minimum measurement of the star’s speed can be calculated, leading to only a minimum possible value for the mass of the exoplanet.
         """
       figure: "./images/mini-course/16-radial-velocity.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: UCAR Center for Science Education"

   }

@@ -223,7 +223,7 @@
         The gravitational field of a star is strong enough to noticeably bend light. When one star passes directly in front of a more distant star as seen from Earth it can bend and focus the light of the distant star causing it to appear brighter for a short period of time. This is known as gravitational microlensing and the closer star is called the lens. If there is a planet orbiting the lens it will sometimes add a noticeable component to the lens effect allowing us to confirm its existence.
         """
       figure: "./images/mini-course/17-micro-lensing.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: Maggy Wassilieff"

   }

@@ -235,7 +235,7 @@
         The first ever confirmed exoplanet was not actually discovered orbiting a Sun-like star. It was found around an object known as a pulsar. Pulsars are the extremely dense, rapidly spinning cores of dead stars which have beams of radiation that sweep out like an interstellar lighthouse. The rotation-rate of pulsars is extremely reliable and can be measured to very high accuracy. However, if a planet in in orbit its gravitational pull on the pulsar will manipulate the rotation-rate in a way that allows its existence to be inferred.
         """
       figure: "./images/mini-course/slide-19.gif"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: Cambridge Physics"

   }

@@ -249,7 +249,7 @@
       video: '<video class="nativeEmbedPlayerPid" id="pid_mwe_player_1" src="//upload.wikimedia.org/wikipedia/commons/transcoded/9/96/201008-2a_PlanetOrbits_16x9-_Transit_timing_of_1-planet_vs_2-planet_systems.ogv/201008-2a_PlanetOrbits_16x9-_Transit_timing_of_1-planet_vs_2-planet_systems.ogv.480p.ogv" autoplay="autoplay" style="width: 350px; margin-left:155px; z-index: 1; "></video>'

       figure: "missing"
-      figure_credits: "NASA"
+      figure_credits: "Credit: NASA/Kepler Mission"

   }

@@ -261,7 +261,7 @@
         As described before for the radial velocity method, stars are pulled around by the gravitation force from their orbiting planets (see animation below). Therefore, if the position of a star can be measured accurately, this movement can be observed and the existence of the planet can be confirmed. These movements are extremely small and to-date very few exoplanet candidates have been discovered in this way, however the recently launch Gaia spacecraft plans to utilise this method as part of its mission.
         """
       figure: "./images/mini-course/slide-21.gif"
-      figure_credits: "NASA"
+      figure_credits: ""

   }

@@ -274,7 +274,7 @@

Below is an image showing the directly imaged exoplanet candidate orbiting in the debris disk around the star Formalhaut.

         """
       figure: "./images/mini-course/slide-22.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: NASA"

   }

@@ -286,7 +286,7 @@
         The first planets discovered using the transit method were very strange. They were gas giant planets the same size as Jupiter but so close to their star that they only take a few days to complete one orbit! There is nothing like this in our Solar System, and theories suggest it is impossible for a Jupiter-sized planet to form in the high temperature environment that close to a star.
         """
       figure: "./images/mini-course/slide-23.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: ESA"

   }

@@ -298,7 +298,7 @@
         For the Hot Jupiters to have gotten so close to their host stars they would have to have first formed much farther out where it was colder and then migrated inwards through the system. Multiple theories on how this migration occurs have been proposed, including interactions with other material orbiting the star in the early stages of the system and gravitational scattering involving other large bodies.
         """
       figure: "./images/mini-course/slide-24.jpg"
-      figure_credits: "NASA"
+      figure_credits: "Image credit: NASA / JPL-Caltech"

   }


optimize performance

optimize performance

--- src/egen.coffee
+++ src/egen.coffee
@@ -2,7 +2,7 @@

   document = window.document

-  $.egen = $.eGen = (queryTokens, attrs, innerContents) ->
+  $.egen = $.eGen = (queryTokens, attrs, innerContents, raw) ->
     tagName = id = null

     # generate element
@@ -12,14 +12,17 @@
     else
       if typeof queryTokens is 'string'
         queryTokens = queryTokens.split /(?![\w\-]+|$)/
-      else
+      else if not raw
         queryTokens = queryTokens.concat() # duplicate
       if queryTokens[0] and /^\w/.test queryTokens[0]
         tagName = queryTokens.shift()
       else
         tagName = 'div'
     element = document.createElement tagName
-    $element = $(element)
+    $element = $(element) unless raw
+
+    # set attributes
+    $element.attr attrs if not raw and attrs

     # setup id, class
     while queryTokens.length
@@ -27,8 +30,9 @@
       if tokenStr == ' '
         if queryTokens[0].indexOf(' ') < 0
           # nested element without tag-name
-          innerContents = $.egen(queryTokens, null, innerContents)
-          queryTokens = []
+          element.appendChild $.egen(queryTokens, null, innerContents, 1)
+          innerContents = 0
+          break
         continue
       token = tokenStr.match(/([^\w\-])([\w\-]+)/)
       unless token and token.length == 3
@@ -41,24 +45,24 @@
         when ' '
           # nested element with tag-name
           queryTokens.unshift token[2]
-          innerContents = $.egen(queryTokens, null, innerContents)
-          queryTokens = []
-          continue
+          element.appendChild $.egen(queryTokens, null, innerContents, 1)
+          innerContents = 0
         else
           throw "The query token provided ('#{tokenStr}') is not a valid token type."
-
-    # set attributes
-    $element.attr attrs if attrs

     # set inner contents
     if innerContents
       if typeof innerContents is 'string'
         # disable html code
-        $element.text(innerContents)
+        element.appendChild document.createTextNode(innerContents)
       else
+        $element = $(element) if raw
         $element.append(innerContents)

-    $element
+    if raw
+      element
+    else
+      $element

   $.fn.egen = $.fn.eGen = (queryTokens, attrs, innerContents) ->
     @append $.egen(queryTokens, attrs, innerContents)


Update server example to work with latest Express

--- examples/hello-server/app.coffee
+++ examples/hello-server/app.coffee
@@ -6,7 +6,7 @@
 # Register transparency as a plugin for the given jQuery instance
 transparency.register $

-app = express.createServer()
+app = express()

 app.configure ->
   app.use app.router
@@ -62,4 +62,4 @@
   res.send template[0].outerHTML

 app.listen 3000
-console.log "Express server listening on port %d in %s mode", app.address().port, app.settings.env+console.log "Express server listening on port 3000 in %s mode", app.settings.env


Add snippet for ES6 arrow function

Add snippet for ES6 arrow function

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -189,6 +189,10 @@
     'prefix': 'fe'
     'body': 'function ($1) {\n\t$2\n}$3'

+  'arrow function':
+    'prefix': 'af'
+    'body': '($1) => {\n\t$2\n}$3'
+
   'immediately-invoked function expression':
     'prefix': 'iife'
     'body': '(function($1) {\n$2\n}($3));'


Post: fix style issues

Post: fix style issues

--- workers/social/lib/social/models/messages/post.coffee
+++ workers/social/lib/social/models/messages/post.coffee
@@ -32,7 +32,8 @@
   schema = extend {}, jraphical.Message.schema, {
     isLowQuality  : Boolean
     slug          : String
-    slug_         : String # this is necessary, because $exists operator won't work with a sparse index.
+    slug_         : String # this is necessary, because $exists
+                           #operator won't work with a sparse index.
     group         : String
     counts        :
       followers   :
@@ -171,19 +172,19 @@
               else
                 queue.next()
           ->
-            status.fetchTeaser (err, teaser_)=>
+            status.fetchTeaser (err, teaser_)->
               if err
                 callback createKodingError err
               else
                 teaser = teaser_
                 queue.next()
-          =>
+          ->
             activity.update
               $set:
                 snapshot: JSON.stringify(teaser)
               $addToSet:
                 snapshotIds: status.getId()
-            , =>
+            , ->
               callback null, teaser
               return queue.next()  if status.isLowQuality
               status.fetchTags (err, tags)->
@@ -221,7 +222,7 @@
       daisy queue = [
         =>
           tags or= []
-          @addTags client, tags, (err)=>
+          @addTags client, tags, (err)->
             return callback err  if err
           queue.next()
         =>
@@ -296,7 +297,7 @@
           activityId = activityId_
           queue.next()
       =>
-        @fetchTeaser (err, teaser_)=>
+        @fetchTeaser (err, teaser_)->
           if err
             callback createKodingError err
           else
@@ -373,13 +374,13 @@
             queue.docs = docs
             queue.next()
         =>
-          Relationship.count {sourceId: @getId(),as:'reply'}, (err, count)=>
+          Relationship.count {sourceId: @getId(),as:'reply'}, (err, count)->
             queue.relationshipCount = count
             return callback err if err
             queue.next()
         =>
           return queue.next() if exempt
-          @update $set: repliesCount: queue.relationshipCount, (err)=>
+          @update $set: repliesCount: queue.relationshipCount, (err)->
             return callback err if err
             queue.next()
         =>


Add pattern-matching for concealed newlines in Pic

--- grammars/pic.cson
+++ grammars/pic.cson
@@ -26,6 +26,7 @@
 			{include: "#keywords"}
 			{include: "#string"}
 			{include: "#number"}
+			{include: "#escaped-newline"}
 			{include: "#punctuation"}
 			{include: "#shapes"}
 			{include: "#attributes"}
@@ -59,6 +60,15 @@
 		end:   "$"
 		beginCaptures:
 			0: name: "punctuation.definition.comment.pic"
+
+
+	# Concealed newline
+	"escaped-newline":
+		name: "constant.character.escape.newline.pic"
+		begin: "\\\\$\\n?"
+		end:   "^(?:[.'])?"
+		beginCaptures:
+			0: name: "punctuation.definition.escape.pic"

 	# Function call


adding favicon snippet

adding favicon snippet

--- atom.symlink/snippets.cson
+++ atom.symlink/snippets.cson
@@ -23,3 +23,8 @@
   'Use Strict':
     'prefix': 'us'
     'body': '\'use strict\';'
+
+'.text.html':
+  'Empty favicon':
+    'prefix': 'favicon'
+    'body': '<link rel="icon" href="data:;base64,iVBORw0KGgo=">'


Minor debug update.

Minor debug update.

--- src/main.coffee
+++ src/main.coffee
@@ -138,7 +138,7 @@

   # Handle a WebSocket connection
   wsServer.on 'connection', (socket) ->
-    $debug 'WebSocket connection'
+    $debug '+ WebSocket connection'

     # Forward declaration due to cyclic dependency connection <-> jsonRpc.
     connection = null
@@ -167,7 +167,9 @@
     }

     # Close the connection with the socket.
-    socket.on 'close', $bind connection.close, connection
+    socket.on 'close', ->
+      $debug '- WebSocket connection'
+      $bind connection.close, connection

     # Handles each request in a separate fiber.
     socket.on 'message', $bind jsonRpc.exec, jsonRpc


chore(cleanup): Fix the bad brackets

chore(cleanup): Fix the bad brackets

--- src/main.coffee
+++ src/main.coffee
@@ -145,13 +145,11 @@
 				maxdate = scope.restrictions.maxdate
 				(mindate? and currentDate < mindate) or (maxdate? and currentDate > maxdate)
 			isPrevMonthButtonHidden: () ->
-                date = scope.restrictions["mindate"]
-                date? and @_month <= date.getMonth() and @_year <= date.getFullYear()
-            },
-            isNextMonthButtonHidden: () ->
-                date = scope.restrictions["maxdate"]
-                date? and @_month >= date.getMonth() and @_year >= date.getFullYear()
-            },
+				date = scope.restrictions["mindate"]
+				date? and @_month <= date.getMonth() and @_year <= date.getFullYear()
+			isNextMonthButtonHidden: () ->
+				date = scope.restrictions["maxdate"]
+				date? and @_month >= date.getMonth() and @_year >= date.getFullYear()
 			class: (d) ->
 				classString = ''
 				# coffeelint: disable=max_line_length


Allow conversion between vectors and points.

--- src/math.coffee
+++ src/math.coffee
@@ -47,6 +47,10 @@
     # Return true if the point is the origin, otherwise false.
     isOrigin : () ->
         return @x == 0 and @y == 0
+
+    # Return a vector from the origin to this point.
+    toVector : () ->
+        return new wolf.Vector(@x, @y)

     # Return a string representation of the point.
     toString : () ->
@@ -128,6 +132,10 @@
         sinr = Math.sin(r)
         return new wolf.Vector(@x*cosr - @y*sinr, @x*sinr + @y*cosr)

+    # Return the vector's endpoint.
+    getEndPoint : () ->
+        return new wolf.Point(@x, @y)
+
     # Return a string representation of the vector.
     toString : () ->
         return "wolf.Vector(#{@x}, #{@y})"


Added condition if name is a function in moloDefine

--- src/molo.coffee
+++ src/molo.coffee
@@ -47,6 +47,9 @@
       firstScriptElem.parentNode.insertBefore scriptElem, firstScriptElem

   moloDefine = (name, body) ->
+    # If name is a function, then just call the function
+    if typeof name is 'function' then return name.apply @
+
     # If body is a function, add it to the cache directly, else queue it
     if typeof body is 'function' then return cache[name] = body


mqtt: Debug on error/reconnect/offline

mqtt: Debug on error/reconnect/offline

--- src/mqtt.coffee
+++ src/mqtt.coffee
@@ -19,6 +19,12 @@
       return callback mqtt

     @client = mqtt.connect @address
+    @client.on 'error', (err) =>
+      debug 'error', err
+    @client.on 'reconnect', () =>
+      debug 'reconnect'
+    @client.on 'offline', () =>
+      debug 'offline'
     onConnected = (err) =>
       debug 'connected'
       @client.on 'message', (topic, message) =>
@@ -29,6 +35,9 @@
   disconnect: (callback) ->
     @client.removeAllListeners 'message'
     @client.removeAllListeners 'connect'
+    @client.removeAllListeners 'reconnect'
+    @client.removeAllListeners 'offline'
+    @client.removeAllListeners 'error'
     @subscribers = {}
     @client.end (err) =>
       debug 'disconnected'


debug heroku

debug heroku

--- application/config/config.coffee
+++ application/config/config.coffee
@@ -236,7 +236,7 @@
 exports['sess_expiration']		= 7200
 exports['sess_expire_on_close']	= false
 exports['sess_encrypt_cookie']	= false
-exports['sess_use_database']	= process.env.REDISTOGO_URL ? 'redis://localhost:6379'
+exports['sess_use_database']	= false # process.env.REDISTOGO_URL ? 'redis://localhost:6379'
 exports['sess_table_name']		= 'ci_sessions'
 exports['sess_match_ip']		= false
 exports['sess_match_useragent']	= true


Fix test

Fix test

--- apps/articles/test/routes.coffee
+++ apps/articles/test/routes.coffee
@@ -19,6 +19,7 @@
     @next = sinon.stub()
     sinon.stub Backbone, 'sync'
     routes.__set__ 'sailthru', apiGet: sinon.stub().yields('error')
+    routes.__set__ 'EOY_2016_SLUGS', '/article/'

   afterEach ->
     Backbone.sync.restore()


Client-side support only

Client-side support only

Implement proper server-side support later.

--- lib/activeroute.coffee
+++ lib/activeroute.coffee
@@ -43,18 +43,22 @@
     @configure.apply this, arguments

   configure: (options) ->
+    return if Meteor.isServer
+
     share.config.set options
     return

   name: (routeName) ->
     checkRouterPackages()

+    return if Meteor.isServer
+
     checkArgument routeName

     if ir
       currentRouteName = ir.Router.current()?.route?.getName?()

-    if fr and Meteor.isClient
+    if fr
       currentRouteName ?= fr.FlowRouter.getRouteName()

     test currentRouteName, routeName
@@ -62,12 +66,14 @@
   path: (path) ->
     checkRouterPackages()

+    return if Meteor.isServer
+
     checkArgument path

     if ir
       currentPath = ir.Router.current()?.location.get().path

-    if fr and Meteor.isClient
+    if fr
       currentPath ?= fr.FlowRouter.reactiveCurrent()?.path

     test currentPath, path


if not a string -> false

if not a string -> false

--- src/coffee/validators/email.coffee
+++ src/coffee/validators/email.coffee
@@ -10,8 +10,9 @@
   factory('validatorEmail', ->

     validator = (name, values, rule) ->
+      if !values[name]? or typeof values[name] != "string" then return false
       p = /^([\w.-]+)@([\w.-]+)\.([a-zA-Z.]{2,6})$/i;
-      if values[name] and values[name].match p then true else false
+      if values[name]? and values[name].match p then true else false

     return {
       validator: validator


Remove break statements.

Remove break statements.

--- lib/auto-indent.coffee
+++ lib/auto-indent.coffee
@@ -217,7 +217,6 @@

             stackOfTokensStillOpen.push idxOfToken
             idxOfToken++
-            break

           # tags ending </tag>
           when JSXTAG_CLOSE
@@ -243,7 +242,6 @@
               parentTokenIdx: parentTokenIdx         # ptr to <tag
             if parentTokenIdx >=0 then tokenStack[parentTokenIdx].termsThisTagIdx = idxOfToken
             idxOfToken++
-            break

           # tags ending />
           when JSXTAG_SELFCLOSE_END
@@ -278,7 +276,6 @@
               tokenStack[parentTokenIdx].type = JSXTAG_SELFCLOSE_START
               tokenStack[parentTokenIdx].termsThisTagIdx = idxOfToken
             idxOfToken++
-            break

           # tags ending >
           when JSXTAG_CLOSE_ATTRS
@@ -310,7 +307,6 @@
               parentTokenIdx: parentTokenIdx            # ptr to <tag
             if parentTokenIdx >= 0 then tokenStack[parentTokenIdx].termsThisTagsAttributesIdx = idxOfToken
             idxOfToken++
-            break

           # embeded expression start {
           when JSXBRACE_OPEN
@@ -343,7 +339,6 @@

             stackOfTokensStillOpen.push idxOfToken
             idxOfToken++
-            break

           # embeded expression end }
           when JSXBRACE_CLOSE
@@ -370,7 +365,6 @@
               parentTokenIdx: parentTokenIdx         # ptr to <tag
             if parentTokenIdx >=0 then tokenStack[parentTokenIdx].termsThisTagIdx = idxOfToken
             idxOfToken++
-            break

           # Javascript brace Start {
           when BRACE_OPEN
@@ -411,7 +405,6 @@

             stackOfTokensStillOpen.push idxOfToken
             idxOfToken++
-            break

           # Javascript brace End }
           when BRACE_CLOSE
@@ -439,7 +432,6 @@
                 parentTokenIdx: parentTokenIdx         # ptr to <tag
               if parentTokenIdx >=0 then tokenStack[parentTokenIdx].termsThisTagIdx = idxOfToken
               idxOfToken++
-            break

       # handle lines with no token on them
       if idxOfToken and not tokenOnThisLine and row isnt range.end.row
@@ -453,19 +445,15 @@
       when JSXTAG_SELFCLOSE_START, JSXTAG_OPEN, JSXBRACE_OPEN
         @indentRow({row: row,allowAdditionalIndents: false}
           ,token.firstCharIndentation,0,1)
-        break
       when BRACE_OPEN
         @indentRow({row: row, allowAdditionalIndents: false}
           ,token.firstCharIndentation + @getEslintIndent())
-        break
       when JSXTAG_SELFCLOSE_END, JSXBRACE_CLOSE, JSXTAG_CLOSE_ATTRS
         @indentRow({row: row,allowAdditionalIndents: false}
           ,tokenStack[token.parentTokenIdx].firstCharIndentation,0,1)
-        break
       when BRACE_CLOSE
         @indentRow({row: row, allowAdditionalIndents: false}
           ,tokenStack[token.parentTokenIdx].firstCharIndentation + @getEslintIndent())
-        break

   # get the token at the given match position or return truthy false
   getToken: (bufferRow, match) ->


Adjusted format a bit, uglifying code. Code is no longer pasted to the editor.

--- lib/bookmarklet.coffee
+++ lib/bookmarklet.coffee
@@ -1,3 +1,5 @@
+uglify = require 'uglify-js'
+
 module.exports =
   activate: ->
     atom.workspaceView.command "bookmarklet:create", => @create()
@@ -5,8 +7,9 @@
   create: ->
     editor = atom.workspace.activePaneItem
     content = editor.getText()
-    header = 'javascript:function(){';
-    footer = '}();';
-    out = header + encodeURIComponent(content) + footer;
-    editor.insertText(out)
+    header = 'javascript:(function(){';
+    footer = '})();';
+    ug = uglify.minify(content, { fromString: true })
+    out = header + ug.code + footer;
+    # editor.insertText(out)
     atom.clipboard.write(out)


set ids and keys of waypoints of use stepIndex

--- src/components/exercise/index.cjsx
+++ src/components/exercise/index.cjsx
@@ -120,10 +120,12 @@
     onPartEnter = _.partial(onPartEnter, part.stepIndex) if onPartEnter and _.isFunction(onPartEnter)
     onPartLeave = _.partial(onPartLeave, part.stepIndex) if onPartLeave and _.isFunction(onPartLeave)

-    marker =
<Waypoint
-      key="exercise-part-with-scroll-#{index}"
-      onEnter={onPartEnter}
-      onLeave={onPartLeave}/>

+    marker =

+      <Waypoint
+        key="exercise-part-with-scroll-#{part.stepIndex}"
+        onEnter={onPartEnter}
+        onLeave={onPartLeave}/>
+

     [
       marker,


made `until` less parenful as well

made `until` less parenful as well

--- nodes.coffee
+++ nodes.coffee
@@ -128,9 +128,10 @@
   traverseChildren: (crossScope, func) ->
     @eachChild (child) ->
       return false if func(child) is false
-      if child instanceof Base and
-         (crossScope or child not instanceof Code)
+      if crossScope or child not instanceof Code
         child.traverseChildren crossScope, func
+
+  invert: -> new Op '!', this

   # Default implementations of the common node properties and methods. Nodes
   # will override these with custom logic, if needed.
@@ -1103,10 +1104,7 @@

   constructor: (condition, opts) ->
     super()
-    if opts?.invert
-      condition = new Parens condition if condition instanceof Op
-      condition = new Op('!', condition)
-    @condition  = condition
+    @condition  = if opts?.invert then condition.invert() else condition
     @guard = opts?.guard

   addBody: (body) ->
@@ -1184,9 +1182,6 @@
   isUnary: ->
     not @second

-  isInvertible: ->
-    @operator in ['===', '!==']
-
   isComplex: -> @operator isnt '!' or @first.isComplex()

   isMutator: ->
@@ -1196,7 +1191,13 @@
     include(@CHAINABLE, @operator)

   invert: ->
-    @operator = @INVERSIONS[@operator]
+    if @operator in ['===', '!==']
+      @operator = @INVERSIONS[@operator]
+      this
+    else if @second
+      new Parens(this).invert()
+    else
+      super()

   toString: (idt) ->
     super(idt, @constructor.name + ' ' + @operator)
@@ -1517,14 +1518,7 @@

   constructor: (condition, @body, @tags) ->
     @tags or= {}
-    if @tags.invert
-      op = condition instanceof Op
-      if op and condition.isInvertible()
-        condition.invert()
-      else
-        condition = new Parens condition if op and not condition.isUnary()
-        condition = new Op '!', condition
-    @condition = condition
+    @condition = if @tags.invert then condition.invert() else condition
     @elseBody  = null
     @isChain   = false


CoffeeScript 0.9.0

CoffeeScript 0.9.0

--- nodes.coffee
+++ nodes.coffee
@@ -1153,7 +1153,7 @@
     [@arr1, @arr2] = @array.compileReference o, precompile: yes
     [i, l] = [o.scope.freeVariable(), o.scope.freeVariable()]
     prefix = if @obj1 isnt @obj2 then @obj1 + '; ' else ''
-    "!!(function(){ #{prefix}for (var #i=0, #l=#{@arr1}.length; #i<#l; #i++) if (#{@arr2}[#i] === #@obj2) return true; }).call(this)"
+    "(function(){ #{prefix}for (var #i=0, #l=#{@arr1}.length; #i<#l; #i++) { if (#{@arr2}[#i] === #@obj2) return true; } return false; }).call(this)"

 #### TryNode


assigning to bizarre things like `[a()] = b` now causes syntax error

--- nodes.coffee
+++ nodes.coffee
@@ -140,12 +140,14 @@
   # will override these with custom logic, if needed.
   children: []

-  unwrap          : THIS
   isStatement     : NO
   isPureStatement : NO
   isComplex       : YES
   isChainable     : NO
-  unfoldSoak      : NO
+  isAssignable    : NO
+
+  unwrap     : THIS
+  unfoldSoak : NO

   # Is this node used to assign a certain variable?
   assigns: NO
@@ -259,6 +261,8 @@
   # meaning when wrapped in a closure.
   isPureStatement: -> @value in ['break', 'continue', 'debugger']

+  isAssignable: -> IDENTIFIER.test @value
+
   isComplex: NO

   assigns: (name) -> name is @value
@@ -327,6 +331,9 @@
     for node in @properties.concat @base
       return no if node.soakNode or node instanceof Call
     yes
+
+  isAssignable: ->
+    @hasProperties() or @base.isAssignable()

   assigns: (name) ->
     not @properties.length and @base.assigns name
@@ -770,8 +777,8 @@
       @value.klass = match[1]
     val = @value.compile o, LEVEL_LIST
     return "#{name}: #{val}" if @context is 'object'
-    unless @variable.isComplex() or IDENTIFIER.test assignee = @variable.unwrap().value
-      throw SyntaxError "#{assignee} cannot be assigned."
+    unless @variable.isAssignable()
+      throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
     o.scope.find name unless isValue and (@variable.hasProperties() or @variable.namespaced)
     val = name + " #{ @context or '=' } " + val
     if o.level <= LEVEL_LIST then val else "(#{val})"
@@ -821,9 +828,6 @@
             [obj, idx] = @matchParens o, obj
           else
             idx = if obj.tags.this then obj.properties[0].name else obj
-      unless obj instanceof Value or obj instanceof Splat
-        throw SyntaxError \
-          'destructuring assignment must use only identifiers on the left-hand side.'
       if not splat and obj instanceof Splat
         val   = new Literal obj.compileValue o, valVar, i, olength - i - 1
         splat = true
@@ -848,8 +852,6 @@

   matchParens: (o, obj) ->
     continue until obj is obj = obj.unwrap()
-    unless obj instanceof Literal or obj instanceof Value
-      throw SyntaxError 'nonreference in destructuring assignment shorthand.'
     Value.wrap(obj).cacheReference o

 #### Code
@@ -963,6 +965,8 @@

   children: ['name']

+  isAssignable: YES
+
   constructor: (name) ->
     super()
     @name = if name.compile then name else new Literal name


Reversing evaluation order of __inArray to reflect the ordering of the in operator.

--- nodes.coffee
+++ nodes.coffee
@@ -1269,7 +1269,7 @@
     "(#{tests.join(' || ')})"

   compileLoopTest: (o) ->
-    "#{utility 'inArray'}(#{@array.compile o}, #{@object.compile o})"
+    "#{utility 'inArray'}(#{@object.compile o}, #{@array.compile o})"

 #### Try

@@ -1678,7 +1678,7 @@
         var i = this.length; while (i--) if (this[i] === item) return i;
         return -1;
       };
-      return function(array, item) { return indexOf.call(array, item) > -1; };
+      return function(item, array) { return indexOf.call(array, item) > -1; };
     })();
   '''


set last_edit_time and last_edit_userId fields on document edits

--- model.coffee
+++ model.coffee
@@ -73,7 +73,10 @@
   # ----------------------------------------

   insert_hook = (userId, doc) ->
-    doc.edits = [{'time':Date.now(),'userId':userId}]
+    now = Date.now()
+    doc.edits = [{'time':now,'userId':userId}]
+    doc.last_edit_time = now
+    doc.last_edit_userId = userId
     return

   DriverLines.before.insert insert_hook
@@ -90,6 +93,11 @@

     modifier.$push = modifier.$push or {}
     modifier.$push.edits = {'time':now,'userId':userId}
+
+    modifier.$set = modifier.$set or {}
+    modifier.$set.last_edit_time = now
+    modifier.$set.last_edit_userId = userId
+
     return

   DriverLines.before.update update_hook


kill previous bindings

kill previous bindings

--- keymaps/compatible.cson
+++ keymaps/compatible.cson
@@ -7,6 +7,18 @@

 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
+
+# unset previous bindings
+".platform-win32 atom-workspace atom-text-editor:not([mini])":
+  "ctrl-alt-[": "unset!" # kill "editor:fold-current-row"
+
 '.platform-win32 atom-text-editor':
+  'ctrl-alt-q': 'unset!' # kill "autoflow:reflow-selection"
+
+# set new bindings
+'.platform-win32 atom-workspace atom-text-editor':
+  # at-sign
   'ctrl-alt-q': 'compatible:at'
+
+  # backslash
   'ctrl-alt-[': 'compatible:backslash'


clean.coffee update

clean.coffee update

--- gulp/clean.coffee
+++ gulp/clean.coffee
@@ -4,12 +4,4 @@
 del  = require 'del'

 gulp.task 'clean', ->
-	# clean image output
-	del 'dist/images/*.*'
-	# clean css / stylus output
-    del 'dist/css/*.css'
-    # clean jade output
-    del 'dist/*.html'
-    # clean javascript output
-    del 'dist/js/*.js'
-    del 'dist/js/*.js.map'+	del config.all_destination_files


Added before_save handler

Added before_save handler

--- lib/minimongoid.coffee
+++ lib/minimongoid.coffee
@@ -196,6 +196,12 @@

     for k,v of attr
       @[k] = v
+
+    if @constructor.before_save
+      for k,v of @constructor.before_save(@)
+        attr[k] = v
+        @[k] = v
+
     return @ if not @isValid()

     # attr['_type'] = @constructor._type if @constructor._type?


Fix number escape

Fix number escape

--- index.coffee
+++ index.coffee
@@ -30,7 +30,7 @@
         else if definition.range and _.isString(value) and '~' in value
           [from, to] = value.split('~').map (value) ->
             if _.isFinite parseInt value
-              return parseInt value
+              return escape parseInt value

           if from and to
             whereAnd "#{escaped_field} BETWEEN #{from} AND #{to}"


Try to make header visible

Try to make header visible

--- src/layout/inspect_behavior.coffee
+++ src/layout/inspect_behavior.coffee
@@ -15,7 +15,13 @@

 program_row = (name, program) ->
   make.columns "program-#{name}", [
-    name # action: select this behavior/ edit name
+    {
+      _LABEL: 'name'
+      name: name
+      background: 'white'
+      height: my.button.size
+      width: my.button.size
+    }
     make.buttons(
       name,
       program


Fix heightOfString with autoFirstPage: false

--- lib/mixins/text.coffee
+++ lib/mixins/text.coffee
@@ -145,8 +145,7 @@

     # wrap to margins if no x or y position passed
     unless options.lineBreak is false
-      margins = @page.margins
-      options.width ?= @page.width - @x - margins.right
+      options.width ?= @page.width - @x - @page.margins.right

     options.columns ||= 0
     options.columnGap ?= 18 # 1/4 inch


Clean up front end logic: ./index.coffee. v 0.10.19

--- index.coffee
+++ index.coffee
@@ -53,6 +53,11 @@
     core.export global

     #
+    # set the environment
+    #
+    define 'ENVIRONMENT', process.env.ENVIRONMENT ? process.env.NODE_ENV ? 'development'
+
+    #
     #  The coffee-script file extension
     #
     define 'EXT', '.coffee'
@@ -63,32 +68,14 @@
     define 'FCPATH', realpath(__dirname) + '/'

     #
-    # set the environment
-    #
-    define 'ENVIRONMENT', process.env.ENVIRONMENT ? process.env.NODE_ENV ? 'development'
-
-    #
-    # discover the system path
-    #
-    $system_folder = if realpath('system') then 'system' else FCPATH + 'system'
-    unless is_dir($system_folder)
-      exit "Your system folder path is not set correctly."
-
-    #
-    # discover the application path
-    #
-    $app_folder = if realpath($apppath) then $apppath else FCPATH + $apppath
-    unless is_dir($app_folder)
-      exit "Your application folder path not set correctly."
-
     #  Path to the system folder
     #
-    define 'SYSPATH', realpath($system_folder) + '/'
+    define 'SYSPATH', FCPATH + 'system/'

     #
     # The path to the "application" folder
     #
-    define 'APPPATH', realpath($app_folder) + '/'
+    define 'APPPATH', if is_dir($apppath) then realpath($apppath) + '/' else FCPATH + 'application/'

     #
     # The path to the "assets" folder (optional)
@@ -101,12 +88,20 @@
     define 'MODPATH', if is_dir($modpath) then realpath($modpath) + '/' else false

     #
-    #   Initialize the API
+    # Verify the embedding application path
+    #
+    unless is_dir($apppath)
+      console.log "WARN Your application folder path not set correctly"
+      console.log "WARN --> #{$apppath} <--"
+      console.log "WARN Booting default exspresso application"
+
+    #
+    # Initialize the API
     #
     core()

     #
-    #   Create the top level system controller
+    # Create the top level system controller
     #
     define 'exspresso', new system.core.Exspresso


Correcting for PR comments

Correcting for PR comments

--- src/chaplin/views/view.coffee
+++ src/chaplin/views/view.coffee
@@ -194,7 +194,7 @@
   #   e.g.
   #   @delegate('click', 'button.confirm', @confirm)
   delegate: (eventName, second, third) ->
-    if Backbone.utils
+    if Backbone.utilsBackbone.utils?.delegate
       return Backbone.utils.delegate(this, eventName, second, third)
     if typeof eventName isnt 'string'
       throw new TypeError 'View#delegate: first argument must be a string'
@@ -251,7 +251,7 @@

   # Remove all handlers registered with @delegate.
   undelegate: (eventName, second, third) ->
-    if Backbone.utils
+    if Backbone.utilsBackbone.utils?.undelegate
       return Backbone.utils.undelegate(this, eventName, second, third)
     if eventName
       if typeof eventName isnt 'string'


Add link, underline, and strike options to text method. #183

Should make it way easier to do these common things.

--- lib/mixins/text.coffee
+++ lib/mixins/text.coffee
@@ -173,6 +173,28 @@
                     textWidth = @widthOfString(text.replace(/\s+/g, ''), options)
                     spaceWidth = @widthOfString(' ') + characterSpacing
                     wordSpacing = Math.max 0, (options.lineWidth - textWidth) / Math.max(1, options.wordCount - 1) - spaceWidth
+
+        # calculate the actual rendered width of the string after word and character spacing
+        renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1))
+
+        # create link annotations if the link option is given
+        if options.link
+            @link x, y, renderedWidth, @currentLineHeight(), options.link
+
+        # create underline or strikethrough line
+        if options.underline or options.strike
+            @save()
+            @strokeColor @_fillColor... unless options.stroke
+            @lineWidth 2
+
+            d = if options.underline then 1 else 2
+            lineY = y + @currentLineHeight() / d
+            lineY -= 2 if options.underline
+
+            @moveTo x, lineY
+            @lineTo x + renderedWidth, lineY
+            @stroke()
+            @restore()

         # flip coordinate system
         @save()


logging

logging

--- index.coffee
+++ index.coffee
@@ -101,17 +101,18 @@
 		console.log error

 handleClefLogout = (req, res) ->
-	urlParts = url.parse req.url, true
+	urlParts = url.parse req.url, true

 	form = new formidable.IncomingForm

 	form.parse req, (err, fields, files) ->
-		data =
+		return console.log err if err
+		data =
 	 		app_id: configs.clef.app_id
 	 		app_secret: configs.clef.app_secret
 	 		logout_token: fields.logout_token

-	 	request.post
+	 	request.post
 	 		url: 'https://clef.io/api/v1/logout'
 	 		form: data
 	 		(err, resp, body) ->
@@ -127,11 +128,12 @@
 		 				Users.getByIdentifier userInfo.clef_id, (err, existingUser) ->
 		 					try
 			 					if err or !existingUser.length
+			 						console.log "Error finding user with Clef ID #{userInfo.clef_id}", err
 			 						v0.responses.internalError res, "Error finding your user.  This probably isn't your fault.  Try again."
 			 					else
 			 						user = existingUser[0]
 			 						user.logged_out_at = Date.now()
-
+
 			 						user.save () ->
 			 							pubnub.publish
 						                   channel: user.identifier


send compose output to teardownlog event endpoint

--- index.coffee
+++ index.coffee
@@ -52,9 +52,20 @@
   start.on 'pulling', (event) ->
     event.instance = instanceName
     mqtt.publish '/agent/docker/pulling', event
+  start.on 'startup-log', (logData) ->
+    event =
+      instance: instanceName
+      data: logData
+    mqtt.publish '/agent/docker/log/startup', event
+

 agent.on 'stop', (data) ->
   instanceName = data.instance.name
-  compose.stop instanceName, data
+  stop = compose.stop instanceName, data
+  stop.on 'teardown-log', (logData) ->
+    event =
+      instance: instanceName
+      data: logData
+    mqtt.publish '/agent/docker/log/teardown', event

 require('./src/coffee/storage') agent, mqtt, config


update the index

update the index

--- index.coffee
+++ index.coffee
@@ -33,7 +33,8 @@

 # This construction loads up the framework loader module and extends
 # the current `this` object with the methods found in the loader for
-# convenient access by the implementation further below. Refer to it.
+# convenient access by the implementation further below. Refer to the
+# implementation of the loader for more information on how it works.
 _.merge this, require "./library/nucleus/loader"

 # Build up the entire module hierarchy of the framework. Please do
@@ -48,8 +49,14 @@
 # Do some aliasing after asserting that the basic components of the
 # framework is indeed loaded and are not missing. This is precaution
 # to make sure that the framework is in usable state, once is loaded.
+# You can refer to this definitions from the outside of the framework.
 assert nucleus = module.exports.nucleus
 assert membrane = module.exports.membrane
 assert exposure = module.exports.exposure
 assert semantic = module.exports.semantic
+
+# Alias the cakefile routine for the easy access to the primary way
+# of referencing the built in Cakefile library, which is standard.
+# You should generally prefer the cakefile module facilities over
+# any other build too, including rolling out the tools of your own.
 module.exports.cakefile = nucleus.cakefile


fin put small file

fin put small file

--- index.coffee
+++ index.coffee
@@ -3,6 +3,7 @@
 program = require 'commander'
 fs      = require 'fs'
 wfall   = require 'water-fall'
+mime    = require 'mime-types'
 log4js  = require 'log4js'

 logger  = log4js.getLogger()
@@ -27,17 +28,6 @@
     json: yes
   request par, (err, resp, body) ->
     fin? err, body
-
-dirve = (access_token, fin) ->
-  par =
-    uri: 'https://graph.microsoft.com/v1.0/me/drive/root/children'
-    headers:
-      Authorization: 'bearer ' + access_token
-    method: 'GET'
-    json: yes
-  request par, (err, resp, body) ->
-    console.log '%j', body
-    fin? err

 getInput = (callback) ->
@@ -100,10 +90,35 @@
     logger.trace '%j', par
     request par, (err, resp, body) ->
       logger.error err if err
-      logger.debug body if body.err
+      logger.debug body if body.error
       _.each body.value, (e) ->
         logger.info '%j', _.omit e, ['createdBy', 'lastModifiedBy', 'parentReference']
       callback()
+  wf.exec (err) ->
+
+
+cmdPut = (options) ->
+  logger.debug options
+  wf = wfall.create
+    stream: fs.createReadStream options.localpath
+  wf.push (hooks, callback) ->
+    readToken options, (err, auth) ->
+      hooks.auth = auth
+      callback()
+  wf.push (hooks, callback) ->
+    p = if v = options.path then ':/' + v + ':' else ''
+    par =
+      uri: [options.ROOT, options.user, options.dirve, '/root', encodeURIComponent(p), '/content'].join ''
+      headers:
+        Authorization: 'bearer ' + hooks.auth.access_token
+        'Content-Type': mime.lookup options.localpath
+      method: 'PUT'
+      body: hooks.stream
+    logger.trace '%j', _.omit par, 'body'
+    request par, (err, resp, body) ->
+      logger.error err if err
+      logger.debug body if body.error
+      logger.debug body
   wf.exec (err) ->

@@ -131,6 +146,14 @@
       par = _.extend {}, defaultOptions, _.pick options, ['path'].concat _.keys defaultOptions
       cmdShowList par if name is 'list'

+  program.command 'put <localpath>'
+    .description 'show list/drive'
+    .option '-p --path [name]', 'item id/name'
+    .action (name, options) ->
+      par = _.extend {}, defaultOptions, _.pick options, ['path'].concat _.keys defaultOptions
+      par.localpath = name
+      cmdPut par
+
   program.parse process.argv


file read operation is handled async

file read operation is handled async

--- index.coffee
+++ index.coffee
@@ -10,10 +10,17 @@
   pathToWalk  = folder
   walker      = walk.walk pathToWalk, {}

+
+  readfile = (path) ->
+    fs.readFile path, 'utf8', (err, code)->
+      unless err
+        varsAndPath = analyzeCode code, path, skipParseError
+        processResult varsAndPath.stats, varsAndPath.path
+
+
   work = (path) ->
-    code = fs.readFileSync path, 'utf8'
-    varsAndPath = analyzeCode code, path, skipParseError
-    processResult varsAndPath.stats, varsAndPath.path
+    code = readfile path
+

   q = async.queue(((path, work) ->
     work(path)


add x-auth-token to locals

add x-auth-token to locals

--- index.coffee
+++ index.coffee
@@ -10,10 +10,7 @@
 crypto = require 'crypto'
 { parse } = require 'url'

-# Hoist the XAPP token out of a request and store it at the module level for
-# the passport callbacks to access. (Seems like there should be a better way to access
-# request-level data in the passport callbacks.)
-artsyXappToken = null
+arenaXappToken = null

 # Default options
 opts =
@@ -81,8 +78,11 @@

 addLocals = (req, res, next) ->
   if req.user
+    console.log 'req.user', req.user
     res.locals.user = req.user
     res.locals.sd?.CURRENT_USER = req.user.toJSON()
+    res.locals.sd?.XAuthToken = req.user.get('authentication_token')
+    console.log 'res.locals.sd', res.locals.sd
   next()

 headerLogin = (req, res, next) ->


added search form

added search form

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -52,9 +52,39 @@
                         <button id=\"#{@options.uuid}-#{widget.widgetName}-addimage\">Add Image</button>

-
SEARCH

+

+                    <form action=\"app_dev.php/liip/vie/assets/search/?page=1&length=4\" tpye=\"post\" id=\"search_form\">
+                        <input type=\"text\" class=\"searchInput\" /><input type=\"submit\" class=\"searchButton\" value=\"OK\"/>
+                    </form>
+

+                        Search results come here!
+

+

+
+

+

UPLOAD

"
+
+            jQuery(@options.dialog).contents().find('#search_form').submit (event) ->
+                that = @
+                jQuery.ajax({
+                    type: "GET",
+                    url: "/app_dev.php/liip/vie/assets/search/",
+                    data: "page=1&length=4&searchString=2",
+                    success: (response) ->
+                        items = Array()
+                        $.each response.assets, (key, val) ->
+                            items.push("");
+                        jQuery(that).parents().contents().find('.searchResults').html(items.join(''))
+
+                        # Add action to image thumbnails
+                        jQuery(".#{widget.widgetName}-imageThumbnail").live "click", (event) ->
+                            jQuery(".#{widget.widgetName}-imageThumbnail").removeClass "#{widget.widgetName}-imageThumbnailActive"
+                            jQuery(this).addClass "#{widget.widgetName}-imageThumbnailActive"
+                            jQuery("##{widget.options.uuid}-#{widget.widgetName}-activeImage_search").attr "src", jQuery(this).attr "src"
+                })
+                event.preventDefault()

             insertImage = () ->
                 #This may need to insert an image that does not have the same URL as the preview image, since it may be a different size


Fixed: wrong test label

Fixed: wrong test label

--- tests/main.coffee
+++ tests/main.coffee
@@ -125,7 +125,7 @@
                     designsToRemove: ['alarm']
                     callback: done

-            it "There should be two design documents, doctypes and contact", (done) ->
+            it "There should be two 4 documents, doctypes, device, tags and contact", (done) ->
                 url = 'cozy/_all_docs?startkey="_design/"&endkey="_design0"' + \
                       '&include_docs=true'
                 couch.get url, (err, res, body) ->


fix hole digging

fix hole digging

--- lib/text-buffer.coffee
+++ lib/text-buffer.coffee
@@ -14,8 +14,9 @@
     constructor: (@core) ->

     # compare goals with indices
-    changed: (indices) -> _.isEqual _.pluck(@goals, 'index'), indices
-
+    indicesChanged: (indices) -> ! _.isEqual _.pluck(@goals, 'index'), indices
+    # compare content with text buffer
+    textBufferChanged: (content) -> content isnt @core.editor.getText()

     #########################
     #   Cursor Management   #
@@ -159,13 +160,15 @@
     ########################

     goalsAction: (indices) -> @protectCursor =>
-        unless @changed indices
+
+        textRaw     = @core.editor.getText()            # get raw text
+        textBracket = convertToHoles textRaw            #   ?  => {!!}
+        text        = resizeHoles textBracket, indices  # {!!} => {!  !}
+
+        if @indicesChanged(indices) or @textBufferChanged(text)
             log 'Text Buffer', "setting goals #{indices}"
             @removeGoals()
-
-            textRaw     = @core.editor.getText()            # get raw text
-            textBracket = convertToHoles textRaw            #   ?  => {!!}
-            text        = resizeHoles textBracket, indices  # {!!} => {!  !}
+
             @core.editor.setText text

             positions   = findHoles text


:fire: unnecessary property

:fire: unnecessary property

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -794,7 +794,6 @@

 class RangeMarker extends TextObject
   @extend()
-  backward: true

   select: ->
     ranges = @vimState.getRangeMarkers().map((m) -> m.getBufferRange())


Fixing content type ajax test

Fixing content type ajax test

--- test/ajax.spec.coffee
+++ test/ajax.spec.coffee
@@ -51,8 +51,8 @@
             assert.equal data, 'content type undefined'
             countdown.fire()

-        ajax.request url: '/content', contentType: 'xxx', (data, settings) ->
-            assert.equal data, 'content type xxx'
+        ajax.request url: '/content', contentType: 'text/plain', (data, settings) ->
+            assert.equal data, 'content type text/plain'
             countdown.fire()

     test 'requested with', (done) ->


removed unused variable

removed unused variable

--- src/sloc.coffee
+++ src/sloc.coffee
@@ -173,7 +173,6 @@
     else
       throw new TypeError "File extension '#{lang}' is not supported"

-  commentLineNumbers  = []
   nullLineNumbers     = []

   lines = code.split '\n'
@@ -195,12 +194,10 @@
     else if start is true and stopMultiLineComment.test l
       start = false
       x = i - startLine + 1
-      commentLineNumbers.push nr for nr in [startLine..i]
       bCounter += x

     else if start is false and comment.test l
       cCounter++
-      commentLineNumbers.push i

   sloc      = loc - cCounter - bCounter - nloc
   totalC    = cCounter + bCounter


clampable

clampable

--- test/clampable.coffee
+++ test/clampable.coffee
@@ -6,7 +6,7 @@
   o.clamp
     x:
       min: 0
-      max: 100
+      max: max

   o.update()


add VIF in specs

add VIF in specs

--- src/spec.coffee
+++ src/spec.coffee
@@ -403,6 +403,19 @@
             }
           }

+          $VIFs: @dynamic [], {
+            VIF: {
+              update: (VIF, UUID) ->
+                remove @field, UUID
+
+                # Adds this VBD to this VM if it belongs to it..
+                @field.push UUID if do =>
+                  for ref in @generator.VIFs
+                    return true if refsToUUIDs[ref] is UUID
+                  false
+            }
+          }
+
           # The reference is necessary for operations with the XAPI.
           $ref: -> @generatorKey

@@ -539,6 +552,34 @@

           VM: get('VM')

+      VIF:
+
+        test: (value) ->
+          return false if value.$type isnt @rule.name
+
+          # TODO: Sometimes a network does not have an associated VIF,
+          # find out why.
+          refsToUUIDs[value.VIF] isnt null
+
+        value:
+
+          type: -> @rule.name
+
+          UUID: -> @key
+
+          attached: get('currently_attached')
+
+          device: get('device')
+
+          mac: get('MAC')
+
+          mtu: get('MTU')
+
+          # TODO: networks
+          network: get('network')
+
+          VM: get('VM')
+
       console:

         test: test


make people bigger

make people bigger

--- client/tawk.coffee
+++ client/tawk.coffee
@@ -96,8 +96,8 @@
       person_width = person_height * 4 / 3

     _:
-      person_height: Math.round(person_height)
-      person_width: Math.round(person_width)
+      person_height: Math.round(person_height * 1.5)
+      person_width: Math.round(person_width * 1.5)

   bus('tawk/window').to_fetch = (key) ->
     _:


S64847: updated test to not use flaky rank definitions

--- test/spec/iterationplanningboard/IterationPlanningBoardAppSpec.coffee
+++ test/spec/iterationplanningboard/IterationPlanningBoardAppSpec.coffee
@@ -338,12 +338,12 @@
         expect(editorOpenedStub).toHaveBeenCalledOnce()

   it 'should display a newly created story ranked at the bottom of the column', ->
-    storyRank = 1000
+    storyRank = 'aaaa'
     firstStoryName = 'Story 1'
     userStory1 =
       Iteration: @getIteration1(),
       Name: firstStoryName
-      Rank: storyRank
+      DragAndDropRank: storyRank

     @ajax.whenQuerying('artifact').respondWith(userStory1)

@@ -353,7 +353,7 @@
         Iteration: @getIteration1(),
         Name: secondStoryName
         ObjectID: 2,
-        Rank: storyRank + 1
+        DragAndDropRank: 'bbbb'

       @ajax.whenQuerying('artifact').respondWith [userStory2]
       Rally.environment.getMessageBus().publish Rally.Message.objectCreate, @createUserStoryRecord userStory2


Can't get the personal store to work

Can't get the personal store to work

--- client.coffee
+++ client.coffee
@@ -31,20 +31,20 @@
 renderRound = (round_no) ->
 	round = Db.shared.ref 'rounds', round_no

+	Dom.div ->
+		Dom.style fontSize: '150%', fontWeight: 'bold', textShadow: '0 1px 0 #fff', textAlign: 'center', padding: '4px 10px 10px 10px'
+		Dom.text Util.stringToQuestion(round.get('question'))
+
 	if round.get('finished')
-		Dom.div ->
-			Dom.style fontSize: '150%', fontWeight: 'bold', textShadow: '0 1px 0 #fff', textAlign: 'center', padding: '4px 10px 10px 10px'
-			Dom.text Util.stringToQuestion(round.get('question'))
-
+		Ui.bigButton 'Go to advanced...', -> Page.nav ['advanced']
+	else
+		ranking = Db.personal.ref('rounds', round_no) || Obs.create()
+
 		Ui.bigButton 'I have!', ->
-			{}.noSuchMethod()
+			ranking.set(true)

 		Ui.bigButton 'I have not!', ->
-			{}.noSuchMethod()
-
-		Ui.bigButton 'Go to advanced...', -> Page.nav ['advanced']
-	else
-		Dom.h2 "Patat"
+			ranking.set(false)

 renderRoundList = ->
 	renderRoundItem = (round) ->


Minor adjustment to scrolling preview to cursor

--- coffee/main.coffee
+++ coffee/main.coffee
@@ -117,8 +117,8 @@
         viewHeight = viewWrapEl.offsetHeight
         cursorSpan = document.getElementById 'cursor'
         cursorTop = offset(cursorSpan).top
-        #cursorHeight = cursorSpan.offsetHeight
-        if cursorTop < scrollTop or cursorTop > scrollTop + viewHeight #- cursorHeight
+        cursorHeight = cursorSpan.offsetHeight
+        if cursorTop < scrollTop or cursorTop > scrollTop + viewHeight - cursorHeight
           viewWrapEl.scrollTop = cursorTop - viewHeight/2
       setViewHtml marked editor.getValue()


bump react-native version to 0.13.0-rc

bump react-native version to 0.13.0-rc

--- natal.coffee
+++ natal.coffee
@@ -18,7 +18,7 @@
 projNameRx      = /\$PROJECT_NAME\$/g
 projNameHyphRx  = /\$PROJECT_NAME_HYPHENATED\$/g
 projNameUnderRx = /\$PROJECT_NAME_UNDERSCORED\$/g
-rnVersion       = '0.12.0'
+rnVersion       = '0.13.0-rc'
 podMinVersion   = '0.38.2'
 process.title   = 'natal'


fixing network healthcheck, making it more generic to accommodate different ifconfig outputs

--- index.coffee
+++ index.coffee
@@ -23,7 +23,7 @@
     scriptBaseDir: env.assert 'SCRIPT_BASE_DIR'
   net_container:
     healthcheck:
-      test: env.get 'NETWORK_HEALTHCHECK_TEST', "ifconfig #{NETWORK_HEALTHCHECK_TEST_INTERFACE} | grep 'inet addr:#{NETWORK_HEALTHCHECK_TEST_IP_PREFIX}'"
+      test: env.get 'NETWORK_HEALTHCHECK_TEST', "ifconfig #{NETWORK_HEALTHCHECK_TEST_INTERFACE} | grep inet | grep #{NETWORK_HEALTHCHECK_TEST_IP_PREFIX}"
       interval:  env.get 'NETWORK_HEALTHCHECK_INTERVAL', '30s'
       timeout: env.get 'NETWORK_HEALTHCHECK_TIMEOUT', '5s'
       retries: parseInt(env.get 'NETWORK_HEALTHCHECK_RETRIES', 4)


Register git as an impromptu repository.

--- index.coffee
+++ index.coffee
@@ -161,3 +161,8 @@
       update: (done) ->
         git["_#{type}"] (err, statuses) ->
           done err, statuses.toString()
+
+  # Register the git repository.
+  @repository.register 'git',
+    root: git.root
+    branch: git.branch


parse payload

parse payload

--- index.coffee
+++ index.coffee
@@ -40,8 +40,8 @@

     return unless payload

-    @servos.left?.pwMicroSeconds  payload.left  if payload.left?
-    @servos.right?.pwMicroSeconds payload.right if payload.right?
+    @servos.left?.pwMicroSeconds  parseInt payload.left  if payload.left?
+    @servos.right?.pwMicroSeconds parseInt payload.right if payload.right?

   onConfig: (device) =>
     debug 'onConfig', device


daily marks can be set in db

daily marks can be set in db

--- index.coffee
+++ index.coffee
@@ -38,5 +38,9 @@
     router.get '/quest/:quest_id', (request, response) ->
         response.send request.quest

+    router.post '/mark/:quest_id', (request, response) ->
+        client.query 'insert into daily_mark (quest,date) values ($1,localtimestamp)', [request.quest_id]
+        response.send "ok"
+
     app.listen (app.get 'port'), () ->
         console.log "started; port = " + app.get('port')


remove useless ;

remove useless ;

--- index.coffee
+++ index.coffee
@@ -7,7 +7,7 @@
 menu = require 'menu'
 tray = require 'tray'

-mainWindow = null;
+mainWindow = null

 app.on 'ready', ->
     mainWindow = new browserWindow


Input db and utils as global variables added

--- input.coffee
+++ input.coffee
@@ -22,7 +22,6 @@
 	CONSTANT_VARS = @CONSTANT_VARS = ['undefined', 'false', 'true', 'null', 'this', 'JSON']

 	cache = {}
-
 	GLOBAL =
 		Math: Math
 		Array: Array
@@ -30,6 +29,8 @@
 		Number: Number
 		RegExp: RegExp
 		String: String
+		db: require 'db'
+		utils: require 'utils'

 	@getVal = do ->
 		getFromElement = (elem, prop) ->


Used encoder to decode html that will be evalled.

--- client/landing/app/CommonViews/introductiontooltip.coffee
+++ client/landing/app/CommonViews/introductiontooltip.coffee
@@ -16,7 +16,7 @@
     return unless parentView # view not appended to dom yet, probably came from db query

     view       = null
-    try view   = eval @getData().snippet?.split(""").join("\"") # trying to eval snippet, sanity check
+    try view   = eval Encoder.htmlDecode @getData().snippet.split("@").join("this.") # trying to eval snippet
     return unless view instanceof KDView # we will add this as a subview, should be a KDView instance

     view.addSubView @closeButton = new KDCustomHTMLView


fix global suppress refresh bug

fix global suppress refresh bug

the global refresh check was only looking if the suppressRefresh key
existed, not its value

--- SingularityUI/app/application.coffee
+++ SingularityUI/app/application.coffee
@@ -66,7 +66,7 @@
         setInterval @globalRefresh, @globalRefreshTime

     globalRefresh: =>
-        return if localStorage.getItem 'suppressRefresh'
+        return if localStorage.getItem('suppressRefresh') is 'true'
         if @blurred
             clearInterval @globalRefreshInterval
             return


Just catch alls for inner scoping now.

Just catch alls for inner scoping now.

--- nodes.coffee
+++ nodes.coffee
@@ -994,7 +994,7 @@
           params.push param
     o.scope.startLevel()
     params = (param.compile(o) for param in params)
-    @body.makeReturn() unless empty
+    @body.makeReturn() unless empty or @noReturn
     (o.scope.parameter(param)) for param in params
     comm  = if @comment then @comment.compile(o) + '\n' else ''
     o.indent = @idt 2 if @className
@@ -1456,16 +1456,20 @@
       body.unshift  new Literal "var #{name} = #{ivar}" if range
       body.unshift  new Literal "var #{namePart}" if namePart
       body.unshift  new Literal "var #{index} = #{ivar}" if index
+      lastLine    = body.expressions.pop()
       body.push     new Assign new Literal(ivar), new Literal index if index
       body.push     new Assign new Literal(nvar), new Literal name if nvar
-      body        = Closure.wrap(body, true)
+      body.push     lastLine
+      # o.indent    = @idt 1
+      # comp        = new Literal body.compile o
+      body        = Closure.wrap(body, yes, yes)
       body.push     new Assign new Literal(index), new Literal ivar if index
       body.push     new Assign new Literal(name), new Literal nvar or ivar if name
     else
       varPart     = "#{idt1}#{namePart};\n" if namePart
     if @object
       forPart     = "#{ivar} in #{sourcePart}"
-      guardPart   = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
+      guardPart   = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
     body          = body.compile merge o, indent: idt1, top: true
     vars          = if range then name else "#{name}, #{ivar}"
     """
@@ -1624,7 +1628,7 @@
   # Wrap the expressions body, unless it contains a pure statement,
   # in which case, no dice. If the body mentions `this` or `arguments`,
   # then make sure that the closure wrapper preserves the original values.
-  wrap: (expressions, statement) ->
+  wrap: (expressions, statement, noReturn) ->
     return expressions if expressions.containsPureStatement()
     func = new Parens new Code [], Expressions.wrap [expressions]
     args = []
@@ -1634,6 +1638,7 @@
       args = [new Literal 'this']
       args.push new Literal 'arguments' if mentionsArgs
       func = new Value func, [new Accessor meth]
+      func.noReturn = noReturn
     call = new Call func, args
     if statement then Expressions.wrap [call] else call


CUI.Form

CUI.Form

- "renderAsBlock" when Form has a Checkbox ("ng" only).

--- src/elements/Form/Form.coffee
+++ src/elements/Form/Form.coffee
@@ -453,6 +453,9 @@
 		@table

 	renderAsBlock: ->
+		if @getCheckbox()
+			return true
+
 		fields = @getFields()
 		for f in fields
 			if f.form?.label


Fixed issue where LRSView.withdraw function returned has the wrong scope

--- src/view.coffee
+++ src/view.coffee
@@ -281,7 +281,7 @@
 		nextSibling = @el.nextSibling
 		@el.parentNode.removeChild(@el)

-		return ->
+		return =>
 			if nextSibling
 				parentNode.insertBefore(@el, nextSibling)
 			else


Mustache rendering of views is such that View's parent is automatically in scope.

--- src/view.coffee
+++ src/view.coffee
@@ -46,14 +46,12 @@
     call += "()" unless call[call.length - 1] == ')'
     call = "function(){ this.#{call}; }"
     call = "$.wCall('#{this.wQid()}/..', #{call});"
-    console.log "Rendering |#{call}|"
     call

   mustacheRender: =>
 	  tpl = this.template()
-	  data = this.renderData()
-	  callRenderer = this.wCallRenderer
-	  data.wCall = -> callRenderer
+	  callRenderer = this.wCallRenderer
+	  data = $.extend({}, this.wParent(), {wCall: -> callRenderer}, this.renderData())
 	  Mustache.to_html(tpl, data)

   ############################################################## Private API


new app.songs.Song from json.

new app.songs.Song from json.

--- app/client/js/songs/song.coffee
+++ app/client/js/songs/song.coffee
@@ -6,10 +6,12 @@
 class app.songs.Song

   ###*
+    @param {Object=} json
     @constructor
   ###
-  constructor: ->
+  constructor: (json) ->
     @id = goog.string.getRandomString()
+    goog.mixin @, json if json

   @MSG_MISSING_LYRICS: goog.getMsg 'missing lyrics'
   @MSG_NOT_PUBLISHED: goog.getMsg 'Song must be published.'


Ask db for data

Ask db for data

--- app/frontend.coffee
+++ app/frontend.coffee
@@ -8,6 +8,7 @@
 fs = require 'fs'
 url = require 'url'
 jade = require 'jade'
+db = require './db.coffee'

 respond404 = (req, res) ->
 	fs.readFile(path.join(process.cwd(), '/public/404.html'), (err, file) ->
@@ -25,6 +26,7 @@
 	uri = url.parse(request.url).pathname
 	filename = path.join(process.cwd(), '/public/' + uri)
 	console.log "filename: #{filename}"
+
 	fs.exists(filename, (exists) ->

 		# We have a file that doesn't exist, respond with 404
@@ -42,130 +44,133 @@
 				return

 		if filename.indexOf('.jade') isnt -1
-			try
-				html = jade.renderFile filename,
-					pretty: true
-					compileDebug: true
-					getHourMinutes: (timestamp) ->
-						date = new Date(timestamp)
-						return "#{('0'+date.getHours()).slice(-2)}:#{('0' + date.getMinutes()).slice(-2)}"
-					events: [
-						{
-							dateHeader: 'Søndag, 19.03.2015'
-							events: [
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+			try
+				onSuccess = (data) ->
+					html = jade.renderFile filename,
+						pretty: true
+						compileDebug: true
+						getHourMinutes: (timestamp) ->
+							date = new Date(timestamp)
+							return "#{('0'+date.getHours()).slice(-2)}:#{('0' + date.getMinutes()).slice(-2)}"
+						events: [
+							{
+								dateHeader: 'Søndag, 19.03.2015'
+								events: [
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-							]
-						}
-						{
-							dateHeader: 'Søndag, 19.03.2015'
-							events: [
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+								]
+							}
+							{
+								dateHeader: 'Søndag, 19.03.2015'
+								events: [
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-								{
-									title: 'Hello world'
-									source: 'http://test.test'
-									date: new Date().getTime()
-									organiser: 'Some group'
-									location:
-										name: 'Det Akademiske Kvarter'
-										address: 'Strømgaten 6, Bergen, Norge'
+									}
+									{
+										title: 'Hello world'
+										source: 'http://test.test'
+										date: new Date().getTime()
+										organiser: 'Some group'
+										location:
+											name: 'Det Akademiske Kvarter'
+											address: 'Strømgaten 6, Bergen, Norge'

-								}
-							]
-						}
-					]
+									}
+								]
+							}
+						]

-				response.writeHead(200)
-				response.write(html, "binary")
-				response.end()
+					response.writeHead(200)
+					response.write(html, "binary")
+					response.end()

+
+				db.get({ onSuccess: onSuccess, onError: (error) -> console.log 'fuck!', error})

 			catch e
 				# console.log e


Fix: TableView rows duplicated when column shown or hidden.

--- lib/ST/TableView.coffee
+++ lib/ST/TableView.coffee
@@ -107,15 +107,11 @@
     @renderColumnsButton() if @_canCustomizeColumns

   @method 'renderTable', ->
-    self = this
     @_tableElement = @helper().tag('table').addClass('tableView')
     @_tableElement.addClass @_tableClass if @_tableClass
     html = []
     @generateTableHTML html
     @_tableElement.html html.join('')
-    @_tbody = $ 'tbody', @_tableElement
-    $('tr', @_tbody).each (index) ->
-      self._rowsByUid[self._ordered[index]._uid] = this
     @activateBody()

   @method 'renderColumnsButton', ->
@@ -164,6 +160,10 @@
       self.generateRowHTML item, html, media

   @method 'activateBody', ->
+    self = this
+    @_tbody = $ 'tbody', @_tableElement
+    $('tr', @_tbody).each (index) ->
+      self._rowsByUid[self._ordered[index]._uid] = this
     @_list.each @method('activateRow')

   @method 'generateRowHTML', (item, html, media='screen') ->


fix template list output

fix template list output

--- lib/api/template.coffee
+++ lib/api/template.coffee
@@ -39,7 +39,7 @@

 exports.list = (args) ->
   __track('api', { name: 'template-list' })
-  _.keys(sprout.templates)
+  "\n- #{_.keys(sprout.templates).join('\n- ')}\n"

 ###*


Remove deprecated API

Remove deprecated API

--- lib/autoprefixer.coffee
+++ lib/autoprefixer.coffee
@@ -37,12 +37,6 @@

   plugin.options = options

-  plugin.process = (str, options = { }) ->
-    console?.warn?('Autoprefixer\'s process() method is deprecated ' +
-                   'and will removed in next major release. ' +
-                   'Use postcss([autoprefixer]).process() instead')
-    postcss(plugin).process(str, options)
-
   plugin.info = (opts) ->
     require('./info')(loadPrefixes(opts))

@@ -56,10 +50,6 @@
 # Autoprefixer default browsers
 module.exports.defaults = browserslist.defaults

-# Deprecated shortcut
-module.exports.process = (css, options) ->
-  module.exports().process(css, options)
-
 # Inspect with default Autoprefixer
 module.exports.info = ->
   module.exports().info()


Update -> method to use _.find.

Update -> method to use _.find.

--- lib/common-utils.coffee
+++ lib/common-utils.coffee
@@ -16,10 +16,6 @@

   isObjectPresentInArray: (array, object) ->
-    present = false
-    _.each array, (element) ->
-      if _.isEqual(object, element)
-        present = true
-    present
+    _.find array, (element) -> _.isEqual(element, object)

 module.exports = CommonUtils


2 is not so lonely anymore, day after day

--- models/team.coffee
+++ models/team.coffee
@@ -43,7 +43,7 @@
 TeamSchema.static 'canRegister', (next) ->
   Team.count {}, (err, count) ->
     return next err if err
-    max = 317 + 1 # +1 because team fortnight labs doesn't count
+    max = 319 + 1 # +1 because team fortnight labs doesn't count
     next null, count < max, max - count

 TeamSchema.static 'uniqueName', (name, next) ->


xo.watchTask(uuid)

xo.watchTask(uuid)

--- src/xo.coffee
+++ src/xo.coffee
@@ -125,6 +125,28 @@
     $spec.call @_xobjs

     @_proxyRequests = Object.create null
+
+    taskWatchers = @_taskWatchers = Object.create null
+    @_xobjs.on 'rule=task', (event, task) ->
+      return unless event is 'enter'
+
+      task = task.val
+      {UUID} = task
+
+      watcher = taskWatchers[UUID]
+      return unless watcher?
+
+      {status} = task
+      if status is 'success'
+        watcher.resolve task.result
+      else if status is 'failure'
+        watcher.reject task.error_info
+      else
+        return
+
+      delete taskWatchers[UUID]
+
+      return

   start: (config) ->
     # Connects to Redis.
@@ -468,6 +490,22 @@

     return

+  watchTask: (uuid) ->
+    watcher = @_taskWatchers[uuid]
+    unless watcher?
+      resolve = reject = null
+      promise = new $Bluebird (resove_, reject_) ->
+        resolve = resolve_
+        reject = reject_
+        return
+      watcher = @_taskWatchers[uuid] = {
+        promise
+        reject
+        resolve
+      }
+
+    return watcher.promise
+
 #=====================================================================

 module.exports = $XO


Clean up logging

Clean up logging

--- gulp-tasks.coffee
+++ gulp-tasks.coffee
@@ -34,9 +34,6 @@
       fileExt = path.extname file.path
       if fileExt is options?.from or not options?.from?
         transformation file, (error, result) ->
-          # TODO: Gulp has a nice util for logging.
-          console.log error.toString() if error?
-
           if options?.to?
             file.path = file.path.slice(0, file.path.lastIndexOf fileExt) + options.to

@@ -63,11 +60,11 @@
         else
           tagsToGo = tags.length
           tags.each ->
-            manipulation $(this), ->
+            manipulation $(this), (error) ->
               tagsToGo -= 1
               if tagsToGo is 0
                 file.contents = new Buffer $.html()
-                callback null, file
+                callback error, file

 compileInlineTags = ->
   CoffeeScript = require 'coffee-script'
@@ -92,6 +89,10 @@
           tag.html content
           callback error

+loggingErrors = (emitter) ->
+  emitter.on 'error', console.error
+  emitter
+
 gulp.task 'html', ->
   ect = require 'gulp-ect'
   htmlFileToDirectory = require 'gulp-html-file-to-directory'
@@ -111,7 +112,7 @@

     gulp.src files.html
       .pipe filelog()
-      .pipe ect({data}).on 'error', console.error
+      .pipe loggingErrors ect {data}
       .pipe compileInlineTags()
       .pipe htmlFileToDirectory()
       .pipe gulp.dest localBuildDir ? buildDir


Cosmetics.

Cosmetics.

Lose a few commas.
Rename `grunt build` to `grunt dist`, to not confuse this with `grunt build:index`.
Extract `test` task from `dist` and `server`.
Add description to tasks.

--- app/templates/_Gruntfile.coffee
+++ app/templates/_Gruntfile.coffee
@@ -9,15 +9,15 @@
                 options:
                     livereload: true
                 files: [
-                    'index.html',
-                    'slides/*.md',
-                    'slides/*.html',
+                    'index.html'
+                    'slides/*.md'
+                    'slides/*.html'
                     'js/*.js'
                 ]

             index:
                 files: [
-                    'index.tpl',
+                    'index.tpl'
                     'slides/list.json'
                 ]
                 tasks: ['build:index']
@@ -48,29 +48,30 @@
                 indentation:
                     value: 4

-            files: ['Gruntfile.coffee']
+            all: ['Gruntfile.coffee']

         jshint:

             options:
                 jshintrc: '.jshintrc'

-            files: ['js/*.js']
+            all: ['js/*.js']

         copy:
-            main:
+
+            dist:
                 files: [{
-                    expand: true,
+                    expand: true
                     src: [
-                        'slides/**',
-                        'bower_components/**',
+                        'slides/**'
+                        'bower_components/**'
                         'js/**'
-                    ],
+                    ]
                     dest: 'dist/'
                 },{
-                    expand: true,
-                    src: ['index.html'],
-                    dest: 'dist/',
+                    expand: true
+                    src: ['index.html']
+                    dest: 'dist/'
                     filter: 'isFile'
                 }]

@@ -88,27 +89,28 @@
                     slides
             grunt.file.write 'index.html', html

+    grunt.registerTask 'test',
+        '*Lint* javascript and coffee files.', [
+            'coffeelint'
+            'jshint'
+        ]
+
     grunt.registerTask 'server',
         'Run presentation locally and start watch process (living document).', [
-            'build:index',
-            'connect:livereload',
+            'build:index'
+            'connect:livereload'
             'watch'
         ]

-    grunt.registerTask 'build', [
-
-        'coffeelint',
-        'jshint',
-        'build:index',
-        'copy'
-    ]
+    grunt.registerTask 'dist',
+        'Save presentation files to *dist* directory.', [
+            'test'
+            'build:index'
+            'copy'
+        ]

     # Define default task.
     grunt.registerTask 'default', [
-        'coffeelint',
-        'jshint',
-        'build:index',
-        'connect:livereload',
-        'watch'
+        'test'
+        'server'
     ]
-


Fix speed bug

Fix speed bug

--- app/views/home-page-view.coffee
+++ app/views/home-page-view.coffee
@@ -34,6 +34,7 @@
     level = 'level1'
     @loadLevel level, =>
       @setup level
+      window.requestAnimationFrame @doTheWork

   loadLevel: (level, rest...) =>
@@ -66,7 +67,7 @@
     lvl.setup() unless lvl.setupped
     @soundManager.startAll() if mediator.playWithSounds

-    window.requestAnimationFrame @doTheWork
+    # window.requestAnimationFrame @doTheWork
     @loadNextLevels()


no commit when no changes

no commit when no changes

--- index.coffee
+++ index.coffee
@@ -118,7 +118,7 @@
       return next()  unless config.git?.enable
       execFile '/bin/sh', ['-c', "git add -f #{filename}"], {cwd: config.tastesDir}, (err) ->
         return next err  if err?
-        execFile '/bin/sh', ['-c', "git commit --allow-empty -m 'updated #{filename}'"], {cwd: config.tastesDir}, (err) ->
+        execFile '/bin/sh', ['-c', "git diff-index --quiet HEAD || git commit -m 'updated #{filename}'"], {cwd: config.tastesDir}, (err) ->
           return next err  if err?
           return next()  unless config.git.remoteUrl?
           execFile '/bin/sh', ['-c', "git push -f origin HEAD:#{config.git.upstream}"], {cwd: config.tastesDir}, next


pass instance data to compose.config

pass instance data to compose.config

--- index.coffee
+++ index.coffee
@@ -51,7 +51,7 @@
   instanceName = data.instance.name
   options = data.instance.options

-  compose.config instanceName, data.app.definition, (err, composev2) ->
+  compose.config instanceName, data.app.definition, data, (err, composev2) ->
     if err
       mqtt.publish '/agent/docker/log/startup/error',
         instance: instanceName


removed cljs

removed cljs

--- index.coffee
+++ index.coffee
@@ -1,8 +1,3 @@
-require("./target/goog/bootstrap/nodejs");
-require("./target/cljs/core")
-require('./target/compose/compose')
-goog.require("compose.compose")
-
 fs            = require 'fs-extra'
 path          = require 'path'
 server        = require 'docker-dashboard-agent-api'


require ink 0.12.3

require ink 0.12.3

--- lib/julia-client.coffee
+++ lib/julia-client.coffee
@@ -8,7 +8,7 @@
 semver = require 'semver'

 # TODO: Update me when tagging a new relase:
-INK_VERSION_COMPAT  = "^0.12.2"
+INK_VERSION_COMPAT  = "^0.12.3"

 INK_LINK            = '[`ink`](https://github.com/JunoLab/atom-ink)'
 LANGUAGE_JULIA_LINK = '[`language-julia`](https://github.com/JuliaEditorSupport/atom-language-julia)'


Fixed #1 now ready for early testing

Fixed #1 now ready for early testing

--- lib/linter-julia.coffee
+++ lib/linter-julia.coffee
@@ -6,6 +6,37 @@
   socket.write "#{fname}\n"
   socket.write "#{siz}\n"
   socket.write str + "\n"
+
+doSomeMagic = (data,textEditor) ->
+  filePath = textEditor.getPath()
+  linteroutput = [ ]
+
+  lines = data.split("\n")
+  for line in lines
+    try
+      splittedline = line.split(":")
+      numbers = splittedline[1].split(" ")
+      row_number = parseInt(numbers[0],10)
+      severity = (numbers[1])[0]
+      if severity.match("I")
+        type = "Info"
+      else if severity.match("W")
+        type = "Warning"
+      else
+        type = "Error"
+      text = splittedline[1] + ":" + splittedline[2]
+      range = [[row_number - 1, 0], [row_number - 1,1]]
+      fullmsg = {
+        type
+        text
+        range
+        filePath
+      }
+      linteroutput.push(fullmsg)
+
+    catch TypeError
+  linteroutput
+

 module.exports =
   config:
@@ -30,53 +61,24 @@
       name: 'linter-julia'
       grammarScopes: ['source.julia']
       scope: 'file'
-      lintsOnChange: true
+      lintOnFly: true
       lint: (textEditor)->
-        filePath = textEditor.getPath()
-        inptext = textEditor.getText()
-
-        console.log("I am alive")
         port = parseInt(atom.config.get('linter-julia.linterjuliaport'),10)
         domain = atom.config.get('linter-julia.linterjuliadomain')
         connection = net.createConnection(port, domain)

-        connection.on 'connect', () ->
-          console.log "Opened connection to #{domain}:#{port}."
-          lintfromserver(connection, inptext, filePath)
-          connection.end()
-
-        linteroutput = [ ]
-
-        connection.on 'data', (data) ->
-          textChunk = data.toString('utf8')
-          lines = textChunk.split("\n")
-
-          for line in lines
-            try
-              splittedline = line.split(":")
-              numbers = splittedline[1].split(" ")
-              row_number = parseInt(numbers[0],10)
-              severity = (numbers[1])[0]
-              if severity.match("I")
-                type = "Info"
-              else if severity.match("W")
-                type = "Warning"
-              else
-                type = "Error"
-              text = splittedline[1] + ":" + splittedline[2]
-              range = [[row_number - 1, 0], [row_number - 1,1]]
-              fullmsg = {
-                type
-                text
-                range
-                filePath
-              }
-              linteroutput.push(fullmsg)
-
-            catch TypeError
-          rout = []
-          linteroutput.forEach (rr) ->
-            rout.push rr
-          console.log rout
-          connection.end()
-          rout
+        return new Promise (resolve, reject) ->
+          data = []
+          connection.on 'connect', () ->
+            inptext = textEditor.getText()
+            filePath = textEditor.getPath()
+            lintfromserver(connection, inptext, filePath)
+            connection.end()
+          connection.on('error',reject)
+          connection.on 'data', (chunk) ->
+            data.push(chunk)
+            if chunk.asciiSlice().match("\n\n")
+              connection.destroy()
+          connection.on 'close', () ->
+            allOfData = data.join('')
+            resolve(doSomeMagic(allOfData,textEditor))


Recognize 'yes' as boolean true whem matching variable types

--- common.coffee
+++ common.coffee
@@ -54,7 +54,7 @@
       Number(dst)
     when BOOLEAN_TYPE
       v = String(dst).trim().toLowerCase()
-      v == 'true' or v == 'on' or v == '1'
+      v == 'true' or v == 'on' or v == 'yes' or v == '1'
     else
       dst


App: RouteHandler: ignore collab request for session owner

--- client/app/lib/routehandler.coffee
+++ client/app/lib/routehandler.coffee
@@ -7,6 +7,7 @@
 lazyrouter     = require './lazyrouter'
 isKoding       = require './util/isKoding'
 whoami         = require './util/whoami'
+nick           = require './util/nick'

 EnvironmentsModal       = require 'app/environment/environmentsmodal'
 MachineSettingsModal    = require 'app/providers/machinesettingsmodal'
@@ -140,6 +141,8 @@
   kd.singletons.mainController.ready ->

     whoami().pushNotification
+    if nickname is nick()
+      return kd.singletons.router.back()
       receiver: nickname
       channelId: channelId
       action: 'COLLABORATION_REQUEST'


rewrite mathjax-config in javascript

rewrite mathjax-config in javascript

--- src/smc-util/mathjax-config.coffee
+++ src/smc-util/mathjax-config.coffee
@@ -1,67 +0,0 @@
-# mathjax configuration: this could be cleaned up further or even parameterized with some code during startup
-# ATTN: do not use "xypic.js", frequently causes crash!
-
-exports.MathJaxConfig =
-    skipStartupTypeset: true
-    extensions: ["tex2jax.js","asciimath2jax.js","Safe.js"]  # "static/mathjax_extensions/xypic.js"
-    # NOTE: "output/CommonHTML" is the output default: http://docs.mathjax.org/en/latest/output.html
-    # However, **DO NOT** use "output/CommonHTML" for the output JAX; it completely breaks
-    # Sage worksheet output right now.  Maybe when/if worksheets are rewritten
-    # using React, we can change, but not now.  Using "output/SVG" works just fine.
-    #   https://github.com/sagemathinc/cocalc/issues/1962
-    jax: ["input/TeX","input/AsciiMath", "output/SVG"]
-    # http://docs.mathjax.org/en/latest/options/tex2jax.html
-    tex2jax:
-        inlineMath     : [ ['$','$'], ["\\(","\\)"] ]
-        displayMath    : [ ['$$','$$'], ["\\[","\\]"] ]
-        processEscapes : true
-        ignoreClass    : "tex2jax_ignore"
-        skipTags       : ["script","noscript","style","textarea","pre","code"]
-
-    TeX:
-        MAXBUFFER  : 100000  # see https://github.com/mathjax/MathJax/issues/910
-        extensions : ["autoload-all.js", "noUndefined.js", "noErrors.js"]
-        Macros     : # get these from sage/misc/latex.py; also in cocalc/src/smc-webapp/math_katex.coffee
-            Bold  : ["\\mathbb{#1}",1]
-            ZZ    : ["\\Bold{Z}",0]
-            NN    : ["\\Bold{N}",0]
-            RR    : ["\\Bold{R}",0]
-            CC    : ["\\Bold{C}",0]
-            FF    : ["\\Bold{F}",0]
-            QQ    : ["\\Bold{Q}",0]
-            QQbar : ["\\overline{\\QQ}",0]
-            CDF   : ["\\Bold{C}",0]
-            CIF   : ["\\Bold{C}",0]
-            CLF   : ["\\Bold{C}",0]
-            RDF   : ["\\Bold{R}",0]
-            RIF   : ["\\Bold{I} \\Bold{R}",0]
-            RLF   : ["\\Bold{R}",0]
-            CFF   : ["\\Bold{CFF}",0]
-            GF    : ["\\Bold{F}_{#1}",1]
-            Zp    : ["\\ZZ_{#1}",1]
-            Qp    : ["\\QQ_{#1}",1]
-            Zmod  : ["\\ZZ/#1\\ZZ",1]
-        noErrors:  # http://docs.mathjax.org/en/latest/tex.html#noerrors
-            inlineDelimiters : ["$","$"]
-            multiLine        : true
-            style:
-                "font-size"  : "85%"
-                "text-align" : "left"
-                "color"      : "red"
-                "padding"    : "1px 3px"
-                "background" : "#FFEEEE"
-                "border"     : "none"
-        noUndefined:  # http://docs.mathjax.org/en/latest/tex.html#noundefined
-            attributes:
-                mathcolor      : "red"
-                mathbackground : "#FFEEEE"
-                mathsize       : "90%"
-
-    # do not use "xypic.js", frequently causes crash!
-    "HTML-CSS":
-        linebreaks:
-            automatic: true
-    SVG:
-        linebreaks:
-            automatic: true
-    showProcessingMessages: false


Do not cache fetch results for collections

IE refuses to cooperate and work like other browsers. Despite the data
changing on the server, IE will use cached results of earlier fetch
calls when updating a collection. To avoid this, this commit completely
blocks all caching on fetch calls for collections.

--- coffee/cilantro/models/base.coffee
+++ coffee/cilantro/models/base.coffee
@@ -28,6 +28,11 @@
             @links = {}
             super(attrs, options)

+        fetch: (options) ->
+            options = options or {}
+            options.cache = false
+            return c.Backbone.Collection.prototype.fetch.call(this, options)
+
         parse: (attrs, options) ->
             if attrs? and attrs._links?
                 @links = {}


Updating the precision of the calculate_age method.  The old version of the method made rough assumtions of the length of a year or month which when combined with aggreate leap years caused inprecise calculations.

--- Src/coffeescript/cql-execution/src/elm/clinical.coffee
+++ Src/coffeescript/cql-execution/src/elm/clinical.coffee
@@ -49,17 +49,40 @@
     @

 calculateAge = (date1, date2, precision) ->
-  ageInMS = date2.getTime() - date1.getTime()
-  # Not quite precise (leap years, months, etc) but close enough for now
-  divisor = switch (precision)
-    when 'Year' then 1000 * 60 * 60 * 24 * 365
-    when 'Month' then (1000 * 60 * 60 * 24 * 365) / 12
-    when 'Day' then 1000 * 60 * 60 * 24
-    when 'Hour' then 1000 * 60 * 60
-    when 'Minute' then 1000 * 60
-    when 'Second' then 1000
-    else 1
-  Math.floor(ageInMS / divisor)
+  value = if precision is "Year"
+    monthsDiff(date1,date2) / 12
+  else if  precision is "Month"
+    monthsDiff(date1,date2)
+  else
+    ageInMS = date2.getTime() - date1.getTime()
+    divisor = switch (precision)
+      when 'Day' then 1000 * 60 * 60 * 24
+      when 'Hour' then 1000 * 60 * 60
+      when 'Minute' then 1000 * 60
+      when 'Second' then 1000
+      else 1
+    ageInMS / divisor
+  Math.floor(value)
+
+monthsDiff = (date1, date2) ->
+  [high,low] = if date1.getTime() > date2.getTime() then [date1,date2] else [date2,date1]
+  #Rough approximation not taking day into account yet.  This may be +1 month
+  months = ((high.getFullYear() - low.getFullYear()) * 12) + (high.getMonth() - low.getMonth())
+  return 0 if months is 0
+
+  date3 = new Date(low.getTime())
+  #add the number of months to the low date clone to bring it up to the current month and year
+  # note however that this may push the date into the next month.  If the low date was in a month
+  # with 31 days and the high date is in a month with less then 31 days this will cause the date to
+  #be pushed forward into the next month.
+  date3.setMonth(low.getMonth() + months)
+  # If the months are equal and the adjusted dated is greater than the high date we havn't
+  # reached the actual turn over day so remove a month from the count
+  if date3.getMonth() == high.getMonth() && (date3.getDate() - high.getDate() > 0)
+    months--
+
+  months
+

 module.exports.CalculateAge = class CalculateAge extends Expression
   constructor: (json) ->


Clean up code

Clean up code

--- src/views/loading-indicator.coffee
+++ src/views/loading-indicator.coffee
@@ -19,10 +19,8 @@
         onCancel: (ev) ->
             ev.preventDefault()
             @model.cancel()
-        isDone: () =>
-            @model.get('complete') or @model.get('canceled')
         onDomRefresh: ->
-            if @isDone()
+            if @model.get('complete') or @model.get('canceled')
                 @$el.removeClass 'active'
             else
                 @$el.addClass 'active'