Treat nodes uniformly when traversing for hiding/unhiding

--- src/d3-flame-graph.coffee
+++ src/d3-flame-graph.coffee
@@ -36,45 +36,32 @@
       .nodes(data)

   hide: (nodes, unhide = false) ->
-    previouslyHidden = (node) -> node.hidden.reduce ((acc, val) -> acc + val), 0
+    sum = (arr) -> arr.reduce ((acc, val) -> acc + val), 0
     remove = (arr, val) ->
       # we need to remove precisely one occurrence of initial value
       pos = arr.indexOf(val)
       arr.splice(pos, 1) if pos >= 0
-    processChildren = (node, initialValue) ->
+    process = (node, val) ->
+      if unhide
+        remove(node.hidden, val)
+      else
+        node.hidden.push(val)
+      node.value = Math.max(node.originalValue - sum(node.hidden), 0)
+    processChildren = (node, val) ->
       return if not node.children
       node.children.forEach (child) ->
-        if unhide
-          remove(child.hidden, initialValue)
-          child.value = Math.max(child.originalValue - previouslyHidden(child), 0)
-        else
-          child.hidden.push(initialValue)
-          child.value = 0
-        processChildren(child)
-
-    processItself = (node) ->
-      if unhide
-        remove(node.hidden, node.originalValue)
-        node.value = node.originalValue - previouslyHidden(node)
-      else
-        node.hidden.push(node.originalValue)
-        node.value = 0
-
-    processParents = (node) ->
-      initialValue = node.originalValue
+        process(child, val)
+        processChildren(child, val)
+    processParents = (node, val) ->
       while node.parent
-        if unhide
-          remove(node.parent.hidden, initialValue)
-          node.parent.value += initialValue
-        else
-          node.parent.value = Math.max(node.parent.value - initialValue, 0)
-          node.parent.hidden.push(initialValue)
+        process(node.parent, val)
         node = node.parent

     nodes.forEach (node) ->
-      processParents(node)
-      processItself(node)
-      processChildren(node, node.originalValue)
+      val = node.originalValue
+      processParents(node, val)
+      process(node, val)
+      processChildren(node, val)

 d3.flameGraph = ->


iOS and IE fixes

iOS and IE fixes

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -510,9 +510,27 @@
 css.crossbrowserify = (props, as_str = false) ->

   prefixes = ['-webkit-', '-ms-', '-mox-', '-o-']
+
+
   if props.transform
     for prefix in prefixes
       props["#{prefix}transform"] = props.transform
+
+  if props.flex
+    for prefix in prefixes
+      props["#{prefix}flex"] = props.flex
+
+  if props.flexDirection
+    for prefix in prefixes
+      props["#{prefix}flex-direction"] = props.flexDirection
+
+  if props.justifyContent
+    for prefix in prefixes
+      props["#{prefix}justify-content"] = props.justifyContent
+
+
+  if props.display == 'flex'
+    props.display = 'display: table-cell; -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex'

   if props.transition
     for prefix in prefixes
@@ -523,6 +541,7 @@
       MozUserSelect: props.userSelect
       WebkitUserSelect: props.userSelect
       msUserSelect: props.userSelect
+

   if as_str then css_as_str(props) else props

@@ -619,6 +638,9 @@
   vertical-align: baseline;
   line-height: 1.4; }

+body, html {
+  height: 100%;
+}
 button {
   line-height: 1.4;
 }
@@ -740,7 +762,7 @@
   position: relative;
   font-size: 16px;
   color: black;
-  min-height: 500px; }
+  min-height: 100%; }

 .flipped {


Use consistent code style.

Use consistent code style.

--- src/master.coffee
+++ src/master.coffee
@@ -116,7 +116,7 @@
   # handle worker listening
   onListening: (worker, address) ->
     @emit 'worker:listening', worker, address
-    @reloadNext() if @reloading.length > 0
+    @reloadNext() if @reloading.length

   # reload worker
   reloadNext: ->


[artist] Change default for gate to always show the new page

--- src/desktop/config.coffee
+++ src/desktop/config.coffee
@@ -79,7 +79,7 @@
   METAPHYSICS_ENDPOINT: null
   MOBILE_MEDIA_QUERY: "only screen and (max-width: 640px)"
   MOBILE_URL: 'https://m.artsy.net'
-  NEW_ARTIST_PAGE_THRESHOLD: 0 # by default/not set no users will get the new page.
+  NEW_ARTIST_PAGE_THRESHOLD: 10 # all users will get the new page.
   NEW_AUTH_MODAL: false
   NODE_ENV: 'development'
   OPENREDIS_URL: null


modified example.cofee

modified example.cofee

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -9,8 +9,7 @@
 #   These are from the scripting documentation: https://github.com/github/hubot/blob/master/docs/scripting.md

 module.exports = (robot) ->
-  robot.respond /PING$/i, (msg) ->
-    msg.send "なんのようだなっしー！！！！"
+
   # robot.hear /badger/i, (msg) ->
   #   msg.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
   #


add_c2t_semisentence_freetalkdescription (#101)

--- snippets/language-coursescript.cson
+++ snippets/language-coursescript.cson
@@ -421,6 +421,14 @@
     name_language:
       zh-Hans: $4
     intro: $5
+    freetalk:
+     name: $6
+     vteacher_msg: $7
+      avatar: $8
+      nickname: $9
+      description:"$10"
+      cover: $11
+      title: $12
     \"""
     """
   'Assessment':
@@ -627,13 +635,13 @@
       [TYPE PreTextTeaching]
       \"""
       text_teaching:
-      - title: $2
-        paragraph: $3
-      - title: $4
+      - title: "$2"
+        paragraph: "$3"
+      - title: "$4"
         bullet_points:
-        - $5
-        - $6
-        - $7
+        - "$5"
+        - "$6"
+        - "$7"
       \"""
     """
   'SentenceQuiz':
@@ -932,17 +940,17 @@
       ID: $1
       Audio: $2
       Text: $3
-      QuestionPart:
+      QuestionPart:
       Audio: $4
       Text: $5
       Text: $6
       Text: $7
       Text: $8
-      QuestionPart:
+      QuestionPart:
       Audio: $9
       Text: $10
       Text: $11
-      QuestionPart:
+      QuestionPart:
       Audio: $12
       Text: $13
       Text: $14
@@ -954,7 +962,7 @@
       [TYPE T2A]
       ID: $1
       Text: $2
-      Opts:
+      Opts:
       Audio: $3
       Audio: $4
       Audio: $5
@@ -1112,3 +1120,42 @@
       Audio: $10
       Text: $11
     """
+  'C2E':
+    'prefix': 'c2e'
+    'body':"""
+      [TYPE C2E]
+      \"""
+      c2e:
+        text: $1
+        hint:
+        - "$2"
+        - "$3"
+        - "$4"
+        answers:
+        - "$5"
+        - "$6"
+        - "$7"
+        \"""
+      """
+    'SemiSentConstruct':
+      'prefix': 'semisentconstruct'
+      'body':"""
+        [TYPE SemiSentConstruct]
+        \"""
+        ssc:
+          vocabs:
+          - "$1"
+          - "$2"
+          - "$3"
+          - "$4"
+          - "$5"
+          - "$6"
+          knowledge_points:
+          - "$7"
+          - "$8"
+          - "$9"
+          - "$10"
+          - "$11"
+          - "$12"
+          \"""
+        """


made folders clickable in toc

made folders clickable in toc

--- lib/styles/default/behavior.coffee
+++ lib/styles/default/behavior.coffee
@@ -213,9 +213,15 @@
     when 'file'
       #} Single line to avoid extra whitespace
       node$.append """#{node.data.title}"""
+      clickLabel = ->
+        selectNode node$

     when 'folder'
-      node$.append """#{node.data.title}"""
+      node$.append """#{node.data.title}"""
+      clickLabel = (evt) ->
+        selectNode node$
+        node$.toggleClass 'expanded'
+        evt.preventDefault()

   if node.children?.length > 0
     children$ = $('
')
@@ -224,7 +230,7 @@
     node$.append children$

   label$ = node$.find('> .label')
-  label$.click -> selectNode node$
+  label$.click clickLabel

   discloser$ = $('').prependTo label$
   discloser$.addClass 'placeholder' unless node.children?.length > 0


Smooth shading for sprites.

Smooth shading for sprites.

--- packages/landsofillusions/engine/materials/spritematerial.coffee
+++ packages/landsofillusions/engine/materials/spritematerial.coffee
@@ -24,7 +24,7 @@

       SpriteMaterial.paletteTexture.needsUpdate = true

-  constructor: (@options = {}) ->
+  constructor: (options = {}) ->
     super
       transparent: true
       lights: true
@@ -40,6 +40,8 @@
           value: null
         normalMap:
           value: null
+        smoothShading:
+          value: options.smoothShading
       ,
         THREE.UniformsLib.lights

@@ -68,6 +70,7 @@

 uniform mat4 modelViewMatrix;
 uniform sampler2D palette;
+uniform bool smoothShading;

 void main()	{
   vec4 rampShadeDitherAlpha = texture2D(map, vUv);
@@ -87,47 +90,72 @@
   vec3 shadedColor = sourceColor * shadeFactor;

   // Find the nearest color from the palette to represent the shaded color.
-  vec2 shadeUv = rampShadeDitherAlpha.rg;
+  vec2 paletteColor = rampShadeDitherAlpha.rg;
   vec3 bestColor;
-  vec3 secondBestColor;
-  float bestColorDistance = 1000000.0;
-  float secondBestColorDistance = 1000000.0;
+  float bestColorDistance;
+
+  bool passedZero = false;
+  vec3 earlierColor;
+  vec3 laterColor;
+  float blendFactor = 0.0;
+
+  vec3 previousColor;
+  float previousSignedDistance;

   for (int shadeIndex = 0; shadeIndex < #{LOI.Engine.Materials.SpriteMaterial.shadesCount}; shadeIndex++) {
-    shadeUv.g = float(shadeIndex) / #{LOI.Engine.Materials.SpriteMaterial.shadesCount}.0;
-    vec3 shade = texture2D(palette, shadeUv).rgb;
+    paletteColor.g = float(shadeIndex) / #{LOI.Engine.Materials.SpriteMaterial.shadesCount}.0;
+    vec3 shade = texture2D(palette, paletteColor).rgb;

-    // Measure distance to color. We intentionally use squared distance.
-    float distance = distance(shade, shadedColor);
+    // Measure distance to color.
+    vec3 difference = shade - shadedColor;
+    float signedDistance = difference.x + difference.y + difference.z;
+    float distance = abs(difference.x) + abs(difference.y) + abs(difference.z);

-    if (distance < bestColorDistance) {
-      secondBestColor = bestColor;
-      secondBestColorDistance = bestColorDistance;
+    if (shadeIndex == 0) {
+      // Set initial values in first loop iteration.
       bestColor = shade;
       bestColorDistance = distance;
-    } else if (distance < secondBestColorDistance) {
-      secondBestColor = shade;
-      secondBestColorDistance = distance;
+      earlierColor = shade;
+      laterColor = shade;
+    } else {
+      // See if we've crossed zero distance, which means our target shaded color is between the previous and current shade.
+      if (previousSignedDistance < 0.0 && signedDistance >= 0.0 || previousSignedDistance >= 0.0 && signedDistance < 0.0) {
+        passedZero = true;
+        earlierColor = previousColor;
+        laterColor = shade;
+        blendFactor = abs(previousSignedDistance) / abs(signedDistance - previousSignedDistance);
+      }
+
+      if (distance < bestColorDistance) {
+        bestColor = shade;
+        bestColorDistance = distance;
+
+      // Note: We have to make sure the distance increased since there could be two of the same colors in the palette.
+      } else if (distance > bestColorDistance) {
+        // We have increased the distance, which means we're moving away from the best color and can safely quit.
+        break;
+      }
     }
+
+    previousSignedDistance = signedDistance;
+    previousColor = shade;
   }

   vec3 destinationColor = bestColor;

   // Apply dithering.
-  float ditherPercentage = 2.0 * bestColorDistance / (bestColorDistance + secondBestColorDistance);
-
   int x = int(mod(gl_FragCoord.x, 2.0));
   int y = int(mod(gl_FragCoord.y, 2.0));

-  if (ditherPercentage > 1.0 - rampShadeDitherAlpha.b) {
+  if (abs(0.5 - blendFactor) < rampShadeDitherAlpha.b / 2.0) {
     if (x==y) {
-      destinationColor = secondBestColor;
+      destinationColor = earlierColor;
+    } else {
+      destinationColor = laterColor;
     }
-  } //else {
-    // Apply smooth shading.
-    //float blendFactor = bestColorDistance / (bestColorDistance + secondBestColorDistance);
-    //destinationColor = mix(bestColor, secondBestColor, blendFactor);
-  //}
+  } else if (smoothShading && passedZero) {
+    destinationColor = mix(earlierColor, laterColor, blendFactor);
+  }

   // Color the pixel with the best match from the palette.
   gl_FragColor = vec4(destinationColor, rampShadeDitherAlpha.a);
@@ -135,3 +163,5 @@
   if (rampShadeDitherAlpha.a < 0.5) discard;
 }
 """
+
+    @options = options


renaming scrollbarwidth to getScrollBarWidth

--- scrollbar-width.coffee
+++ scrollbar-width.coffee
@@ -5,6 +5,8 @@
 # window.scrollbarWidth (standard browser environment)
 # Will cache the value, untill the function is called
 # with the recalculate parameter set to true.
+
+'use strict'

 factory = (doc) ->
   scrollbarWidth = null
@@ -40,4 +42,4 @@
   else if typeof exports isnt 'undefined'
     module.exports = factory root.document
   else
-    root.scrollbarWidth = factory root.document
+    root.getScrollbarWidth = factory root.document


Wait for both backends to return so that they are always in sync

--- app/coffee/RedisBackend.coffee
+++ app/coffee/RedisBackend.coffee
@@ -58,6 +58,8 @@
 	constructor: (@clients) ->

 	exec: (callback) ->
+		primaryError = null
+		primaryResult = null
 		jobs = @clients.map (client) ->
 			(cb) ->
 				timer = new Metrics.Timer("redis.#{client.driver}.exec")
@@ -80,15 +82,15 @@
 						result = filtered_result

 					if client.primary
-						# Return this result as the actual result
-						callback(error, result)
-					# Send the rest through for comparison
+						primaryError = error
+						primaryResult = result
 					cb(error, result)
 		async.parallel jobs, (error, results) ->
 			if error?
 				logger.error {err: error}, "error in redis backend"
 			else
 				compareResults(results)
+			callback(primaryError, primaryResult)

 COMMANDS = {
 	"get": 0,
@@ -108,6 +110,8 @@
 for command, key_pos of COMMANDS
 	do (command, key_pos) ->
 		Client.prototype[command] = (args..., callback) ->
+			primaryError = null
+			primaryResult = null
 			jobs = @clients.map (client) ->
 				(cb) ->
 					key_builder = args[key_pos]
@@ -118,15 +122,15 @@
 					client.rclient[command] args_with_key..., (error, result...) ->
 						timer.done()
 						if client.primary
-							# Return this result as the actual result
-							callback(error, result...)
-						# Send the rest through for comparison
+							primaryError = error
+							primaryResult = result
 						cb(error, result...)
 			async.parallel jobs, (error, results) ->
 				if error?
 					logger.error {err: error}, "error in redis backend"
 				else
 					compareResults(results)
+				callback(primaryError, primaryResult...)

 		MultiClient.prototype[command] = (args...) ->
 			for client in @clients
@@ -141,6 +145,7 @@
 	first = results[0]
 	for result in results.slice(1)
 		if not _.isEqual(first, result)
+			logger.error results: results, "redis backend conflict"
 			Metrics.inc "backend-conflict"
 		else
 			Metrics.inc "backend-match"


add reading default plan type

add reading default plan type

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -45,7 +45,9 @@
   events:
     settings: {}

-newTaskPlan = (attributes) ->
+newTaskPlan = (attributes = {}) ->
+  attributes.type ?= 'reading'
+
   if BASE_PLANS[attributes.type]?
     _.extend({}, attributes, cloneDeep(BASE_PLANS[attributes.type]))
   else


Removing code added during the migration. `freeVariable(..)` is called with a `type` at all times.

--- scope.coffee
+++ scope.coffee
@@ -20,8 +20,7 @@
   constructor: (parent, expressions, method) ->
     [@parent, @expressions, @method] = [parent, expressions, method]
     @variables = {}
-    @tempVars  =
-      general: '_a'
+    @tempVars  = {}
     if @parent
       (@tempVars[k] = val) for k, val of @parent.tempVars
     else
@@ -53,16 +52,10 @@
     !!(@parent and @parent.check(name))

   # If we need to store an intermediate result, find an available name for a
-  # compiler-generated variable. `_a`, `_b`, and so on...
+  # compiler-generated variable. `_var`, `_var2`, and so on...
   freeVariable: (type) ->
-    if type
-      next = (prev) ->
-        '_' + type + ((prev and Number(prev.match(/\d+$/) or 1) + 1) or '')
-    else
-      type = 'general'
-      next = (prev) ->
-        ordinal = 1 + parseInt prev.substr(1), 36
-        '_' + ordinal.toString(36).replace /\d/g, 'a'
+    next = (prev) ->
+      '_' + type + ((prev and Number(prev.match(/\d+$/) or 1) + 1) or '')
     while @check @tempVars[type] or= next()
       @tempVars[type] = next @tempVars[type]
     @variables[@tempVars[type]] = 'var'


Remove old non functioning TreeChildItemDemandView

--- app/coffeescripts/TreeChildItemDemandView.coffee
+++ app/coffeescripts/TreeChildItemDemandView.coffee
@@ -1,11 +0,0 @@
-class window.sirius.TreeChildItemDemandView extends window.sirius.TreeChildItemLinkView
-  initialize: (model, targets, name, element) ->
-    super(model, targets, name, element)
-    @model.set('contextMenu', $a.demand_context_menu)
-
-  setUpEvents: ->
-    window.sirius.broker.on("demand:show_dialog:#{@model.id}", @render, @)
-    super(@model.link)
-
-  render: (demandView) ->
-    console.log(demandView.model)


fix length error if no events on els

fix length error if no events on els

--- lib/generators/rails_script/install/templates/base.js.coffee
+++ lib/generators/rails_script/install/templates/base.js.coffee
@@ -32,6 +32,6 @@
   setClearEventHandlers: ->
     jQuery(document).on 'page:before-change', ->
       for element in [window, document]
-        for event, handlers in jQuery._data(element, 'events')
+        for event, handlers in (jQuery._data(element, 'events') || {})
           for handler in handlers
             if handler.namespace == '' then $(element).off event, handler.handler


Prevent double _cc classroom join

Prevent double _cc classroom join

--- app/views/courses/CoursesView.coffee
+++ app/views/courses/CoursesView.coffee
@@ -139,6 +139,7 @@
       classroomName: newClassroom.get('name')
       ownerID: newClassroom.get('ownerID')
     }
+    location.search = '' # Prevent another student from logging in later with the _cc query param in place
     @classrooms.add(newClassroom)
     @render()
     @classroomJustAdded = newClassroom.id


Fix error in toType and method and make compatible with module.exports

--- source/quo.coffee
+++ source/quo.coffee
@@ -73,9 +73,9 @@
       target[key] = source[key] for key of source
     target

-  $$.toType = (obj) -> $$.toType = (obj) ->
-    match = OBJECT_PROTOTYPE.toString.call(obj).match(/\s([a-z|A-Z])/)
-    if match then match[1].toLowerCase() else 'object'
+  $$.toType = (obj) ->
+    match = OBJECT_PROTOTYPE.toString.call(obj).match(/\s([a-z|A-Z]+)/)
+    if match.length > 1 then match[1].toLowerCase() else "object"

   $$.each = (elements, callback) ->
     i = undefined
@@ -184,8 +184,10 @@

   $$.fn.indexOf = EMPTY_ARRAY.indexOf

-  $$.version = "3.0.6"
+  $$.version = "3.0.7"

   $$

 @Quo = @$$ = Quo
+
+module?.exports = Quo


Elektron: Tray: mount/umount flow for new kd

--- elektron/src/trayicon.coffee
+++ elektron/src/trayicon.coffee
@@ -159,11 +159,11 @@
     return  unless selectedDir

     [ mountTo ] = selectedDir
-    remotePath  = "--remotepath /home/#{machine.hostname}"
+    remotePath  = ":/home/#{machine.username}"

     @setMenu 'Mount in progress...', yes

-    @kd "mount #{machine.vmName} #{mountTo} #{remotePath}", (err, res) =>
+    @kd "mount #{machine.alias}#{remotePath} #{mountTo}", (err, res) =>

       if err
         @setMenu 'Mount failed', yes
@@ -175,11 +175,11 @@
       console.log 'Mount:', err, res

-  handleUnmount: (machine) -> =>
+  handleUnmount: (mountId) -> =>

     @setMenu 'Unmount in progress...', yes

-    @kd "unmount #{machine.vmName}", (err, res) =>
+    @kd "umount #{mountId}", (err, res) =>

       if err
         @setMenu 'Unmount failed', yes
@@ -210,8 +210,16 @@
         callback null, stdout

+  # Mounts Fetcher
+  loadMounts: (callback) ->
+
+    @setMenu 'Fetching mounts...'
+
+    @kd 'mount list --json', callback
+
+
   # Machine Fetcher
-  loadMachineMenu: (show) ->
+  loadMachineMenu: (show) -> @loadMounts (err, mounts) =>

     @setMenu 'Fetching machines...'

@@ -253,18 +261,18 @@
           ]
         }

-        if machine.mountedPaths.length > 0
+        if machineMounts = mounts[machine.alias]
           # assuming that there is currently one mount point per machine
-          [ mount ] = machine.mountedPaths
+          [ mount ] = machineMounts
           actions   = [
             label : 'Open folder'
-            click : handleOpen "file:///#{mount}"
+            click : handleOpen "file:///#{mount.mount.path}"
           ,
             label : 'Unmount'
-            click : @handleUnmount machine
+            click : @handleUnmount mount.id
           ]
           item.submenu.push
-            label   : mount
+            label   : mount.mount.path
             submenu : actions
         else
           item.submenu.push


Removed dead line.

Removed dead line.

--- src/packet.coffee
+++ src/packet.coffee
@@ -175,7 +175,6 @@
     @fields.push [] if pattern.arrayed and pattern.endianness isnt "x"

   nextValue: ->
-    reading = not @outgoing
     pattern = @pattern[@patternIndex]

     if pattern.endianness is "x"


Correctly stub out cs/cs plugin.

Correctly stub out cs/cs plugin.

This removes the dynamic loading of the coffeescript compiler
which happened even in production applications.

--- grunt/config/requirejs.coffee
+++ grunt/config/requirejs.coffee
@@ -3,7 +3,7 @@
     options:
       baseUrl: '<%= build %>/js'
       exclude: ['coffee-script']
-      stubModules: ['cs']
+      stubModules: ['cs/cs']
       mainConfigFile: '<%= build %>/js/app/config.js'
       optimize: 'uglify2'
       generateSourceMaps: true


Fix docs for up.util.setTimer

Fix docs for up.util.setTimer

--- lib/assets/javascripts/unpoly/util.coffee
+++ lib/assets/javascripts/unpoly/util.coffee
@@ -778,7 +778,7 @@
   Waits for the given number of milliseconds, the nruns the given callback.

   If the number of milliseconds is zero, the callback is run in the current execution frame.
-  See [`up.util.nextFrame()`] for running a function in the next executation frame.
+  See [`up.util.nextFrame()`](/up.util.nextFrame) for running a function in the next executation frame.

   @function up.util.setTimer
   @param {Number} millis


Fix indenting

Fix indenting

--- src/parser.coffee
+++ src/parser.coffee
@@ -9,8 +9,8 @@
     URLTemplateFilters = []

     @addURLTemplateFilter: (func) ->
-      URLTemplateFilters.push(func) if typeof func is 'function'
-      return
+        URLTemplateFilters.push(func) if typeof func is 'function'
+        return

     @removeURLTemplateFilter: () -> URLTemplateFilters.pop()
     @countURLTemplateFilters: () -> URLTemplateFilters.length


Added msg so that it will reply to silly rabbot

--- src/rabbot.coffee
+++ src/rabbot.coffee
@@ -54,5 +54,5 @@
   robot.respond /teach me/i, (msg) ->
     msg.reply msg.random maxims

-  robot.hear /silly rabbot/, ->
+  robot.hear /silly rabbot/, (msg) ->
     msg.reply "Trix are for kids."


Added CSS generic margins & paddings

Added CSS generic margins & paddings

--- snippets/css.cson
+++ snippets/css.cson
@@ -4,6 +4,11 @@
     leftLabelHTML: "Ⓢ"
     rightLabelHTML: "LESS media calls"
     body:"@media (min-width: 768px) {\n$i\n}\n@media (min-width: 992px) {\n\n}\n@media (min-width: 1200px) {\n\n}"
+  "CSS Margings Paddings -variable":
+    prefix: "css:margins-paddings"
+    leftLabelHTML: "Ⓢ"
+    rightLabelHTML: "LESS Margins paddings"
+    body:".m-${1:t} { margin-${2:top}: 15px;}\n.m-${1:t}-10 { margin-${2:top}: 10px;}\n.m-${1:t}-20 { margin-${2:top}: 20px;}\n.m-${1:t}-30 { margin-${2:top}: 30px;}\n.m-${1:t}-40 { margin-${2:top}: 40px;}\n.m-${1:t}-50 { margin-${2:top}: 50px;}\n.p-${1:t} { padding-${2:top}: 15px;}\n.p-${1:t}-10 { padding-${2:top}: 10px;}\n.p-${1:t}-20 { padding-${2:top}: 20px;}\n.p-${1:t}-30 { padding-${2:top}: 30px;}\n.p-${1:t}-40 { padding-${2:top}: 40px;}\n.p-${1:t}-50 { padding-${2:top}: 50px;}"
   "Flexbox - align-content: flex-start;":
     leftLabelHTML: "Ⓢ"
     rightLabelHTML: "Flexbox align-content: flex-start"


fix missing translation

fix missing translation

--- client/app/en.coffee
+++ client/app/en.coffee
@@ -1,5 +1,5 @@
 en =
-    'cozy files configuration 1 on 1': 'Configure your device (1/2)'
+    'cozy files configuration 1 on 2': 'Configure your device (1/2)'
     'cozy files configuration 2 on 2': 'Register your device (2/2)'
     'directory to synchronize your data': 'Path of the folder where you will see your cozy files:'
     'your device name': 'The name used to sign up your device to your Cozy:'


Custom-only: remove now unnecessary optimisation.

This optimisation is now unnecessary, because we will *always* show at
least one completion suggestion in top spot.

--- background_scripts/completion.coffee
+++ background_scripts/completion.coffee
@@ -10,7 +10,7 @@
 #  - refresh(): (optional) refreshes the completer's data source (e.g. refetches the list of bookmarks).
 #  - cancel(): (optional) cancels any pending, cancelable action.
 class Suggestion
-  showRelevancy: true # Set this to true to render relevancy when debugging the ranking scores.
+  showRelevancy: false # Set this to true to render relevancy when debugging the ranking scores.

   constructor: (@options) ->
     # Required options.
@@ -539,20 +539,7 @@
       # continuation.
       onComplete suggestions,
         filter: filter
-        continuation: (suggestions, onComplete) =>
-
-          # We can skip querying the completion engine if any new suggestions we propose will not score highly
-          # enough to make the list anyway.  We construct a suggestion which perfectly matches the query, and
-          # ask the relevancy function what score it would get.  If that score is less than the score of the
-          # lowest-ranked suggestion from another completer (and there are already 10 suggestions), then
-          # there's no need to query the completion engine.
-          perfectRelevancyScore = @computeRelevancy new Suggestion
-            queryTerms: queryTerms, title: queryTerms.join " "
-
-          if 10 <= suggestions.length and perfectRelevancyScore < suggestions[suggestions.length-1].relevancy
-            console.log "skip (cannot make the grade):", suggestions.length, query if SearchEngineCompleter.debug
-            return onComplete []
-
+        continuation: (onComplete) =>
           CompletionSearch.complete searchUrl, queryTerms, (suggestions = []) =>
             console.log "fetched suggestions:", suggestions.length, query if SearchEngineCompleter.debug
             onComplete suggestions.map mkSuggestion
@@ -632,7 +619,7 @@
       if shouldRunContinuations
         jobs = new JobRunner continuations.map (continuation) ->
           (callback) ->
-            continuation suggestions, (newSuggestions) ->
+            continuation (newSuggestions) ->
               suggestions.push newSuggestions...
               callback()


Added ignore case

Added ignore case

--- client/events.coffee
+++ client/events.coffee
@@ -195,7 +195,8 @@
 Template.category.helpers
   'events': -> Events.find(categories: Session.get "category").fetch()

-Template.search.found_events = ->
-  q = Session.get("q")
-  re = new RegExp("#{q}.*")
-  Events.find(name: re).fetch()
+Template.search.helpers
+  'found_events': ->
+    q = Session.get("q")
+    re = new RegExp("#{q}.*", 'i')
+    Events.find(name: re).fetch()


fix(web): Fix manifest dependency

fix(web): Fix manifest dependency

--- apps/actor-web/gulpfile.coffee
+++ apps/actor-web/gulpfile.coffee
@@ -107,7 +107,7 @@
     .pipe gulp.dest './dist/'
     .pipe connect.reload()

-gulp.task 'manifest', ->
+gulp.task 'manifest-prod', ['assets', 'browserify', 'sass', 'html', 'usemin', 'push']
   gulp.src ['./dist/**/*']
     .pipe manifest {
       hash: true,
@@ -125,11 +125,11 @@
     root: ['./dist/', './']
     livereload: true

-gulp.task 'build', ['assets', 'browserify', 'sass', 'html', 'usemin', 'push', 'manifest']
+gulp.task 'build', ['manifest-prod']

-gulp.task 'build:dev', ['assets', 'browserify:watchify', 'sass', 'html', 'push', 'manifest']
+gulp.task 'build:dev', ['assets', 'browserify:watchify', 'sass', 'html', 'push']

-gulp.task 'build:gwt', ['assets', 'browserify', 'sass', 'usemin', 'push', 'manifest']
+gulp.task 'build:gwt', ['assets', 'browserify', 'sass', 'usemin', 'push']

 gulp.task 'dev', ['build:dev', 'server', 'watch']


fix date time demo

fix date time demo

--- bokehjs/demo/coffee/date_demo.coffee
+++ bokehjs/demo/coffee/date_demo.coffee
@@ -1,4 +1,7 @@
-require(['main'], (Bokeh) ->
+require([
+  'main'
+], (Bokeh) ->
+
   data_orig = [
     {"x": 1346630700000, "y": 3.558},
     {"x": 1346630760000, "y": 3.754},
@@ -99,26 +102,24 @@
     {"x": 1346664360000, "y": 14.82},
     {"x": 1346664420000, "y": 3.731},
     {"x": 1346664480000, "y": 1.469},
-    {"x": 1346664540000, "y": 3.535 }]
-
-  x = (obj.x for obj in data_orig)
-  y = (obj.y for obj in data_orig)
-  console.log(x);
+    {"x": 1346664540000, "y": 3.535},
+  ]
+
   data = {
-    x: x
-    y: y
+    x: (obj.x for obj in data_orig)
+    y: (obj.y for obj in data_orig)
   }
-
+
   scatter = {
     type: 'circle'
     x: 'x'
     y: 'y'
-    radius: 5
-
-    fill_alpha: 0.6
+    size: 10
+    fill_color: 'blue'
+    fill_alpha: 0.4
     line_color: null
   }
-
+
   options = {
     title: "Scatter Demo"
     dims: [600, 600]
@@ -127,6 +128,8 @@
     tools: true
     legend: false
   }
+
   plot = Bokeh.Plotting.make_plot(scatter, data, options)
+
   Bokeh.Plotting.show(plot))


one more fix for .length

one more fix for .length

--- SingularityUI/app/models/Request.coffee
+++ SingularityUI/app/models/Request.coffee
@@ -404,12 +404,15 @@
                 $('.remove-button').click @removeCmdLineArg

             callback: (data) =>
-                if typeof data.commandLineInput is 'string'
-                    if data.commandLineInput != ''
-                        data.commandLineInput = [data.commandLineInput.trim()]
-                    else
+                if data.commandLineInput
+                    if typeof data.commandLineInput is 'string'
+                        if data.commandLineInput != ''
+                            data.commandLineInput = [data.commandLineInput.trim()]
+                        else
+                            data.commandLineInput = []
+                    if data.commandLineInput.length == 1 and data.commandLineInput[0] == ''
                         data.commandLineInput = []
-                if data.commandLineInput.length == 1 and data.commandLineInput[0] == ''
+                else
                     data.commandLineInput = []
                 @data = data

@@ -468,11 +471,16 @@
                         $('.remove-button').click @removeCmdLineArg

                     callback: (data) =>
-                        if typeof data.commandLineInput is 'string'
-                            if data.commandLineInput != ''
-                                data.commandLineInput = [data.commandLineInput.trim()]
-                            else
+                        if data.commandLineInput
+                            if typeof data.commandLineInput is 'string'
+                                if data.commandLineInput != ''
+                                    data.commandLineInput = [data.commandLineInput.trim()]
+                                else
+                                    data.commandLineInput = []
+                            if data.commandLineInput.length == 1 and data.commandLineInput[0] == ''
                                 data.commandLineInput = []
+                        else
+                            data.commandLineInput = []
                         @data = data

     promptRemove: (callback) =>


deliver error

deliver error

--- src/liquid/helpers.coffee
+++ src/liquid/helpers.coffee
@@ -38,6 +38,7 @@
               singleFuture.deliver(arguments...)
           catch e
             console.log "Couldn't unfuture: %s\n%s", e, e.stack
+            singleFuture.deliver(e)

       _unfuture(future)
       singleFuture


Admin: Stacks: Refactor createOnboardingView to work with new parent view.

--- client/admin/lib/views/groupstacksettings.coffee
+++ client/admin/lib/views/groupstacksettings.coffee
@@ -3,7 +3,7 @@

 InitialView     = require './stacks/initialview'
 DefineStackView = require './stacks/definestackview'
-GetStartedView  = require './stacks/onboarding/getstartedview'
+OnboardingView  = require './stacks/onboarding/onboardingview'

 module.exports = class GroupStackSettings extends kd.View
@@ -18,7 +18,7 @@
   createOnboardingView: ->

     @scrollView = new kd.CustomScrollView
-    @scrollView.wrapper.addSubView new GetStartedView
+    @scrollView.wrapper.addSubView new OnboardingView

     @addSubView @scrollView


WebtermView: use WebTermMessagePane for showing connection messages on terminal

--- client/Terminal/webtermview.coffee
+++ client/Terminal/webtermview.coffee
@@ -76,6 +76,12 @@

     @setKeyView()

+    @addSubView @messagePane = new WebTermMessagePane
+      cssClass: 'hidden'
+
+    @messagePane.on 'RequestNewSession', @lazyBound 'webtermConnect', 'create'
+    @messagePane.on 'RequestReconnect',  @bound 'webtermConnect'
+

   generateOptions:->

@@ -99,6 +105,8 @@

   webtermConnect:(mode = 'create')->

+    @messagePane.busy()
+
     options = @generateOptions()
     options.mode = mode


changed way to accessing localstorage

changed way to accessing localstorage

--- client/app/lib/localstorage.coffee
+++ client/app/lib/localstorage.coffee
@@ -101,10 +101,5 @@
   @getStorage = -> storage

   @sanitize = ->
-
-    try
-      storage = global.localStorage
-
-      storage.removeItem k for k of storage when k in blacklist
-    catch e
-      kd.warn "#{e.name} occurred while getting localStorage:", e.message
+    storage = @getStorage()
+    storage.removeItem k for k of storage when k in blacklist


client: remove WelcomeModal

client: remove WelcomeModal

--- client/app/lib/welcomemodal.coffee
+++ client/app/lib/welcomemodal.coffee
@@ -1,57 +0,0 @@
-kd = require 'kd'
-KDCustomHTMLView = kd.CustomHTMLView
-KDHeaderView = kd.HeaderView
-KDModalView = kd.ModalView
-CustomLinkView = require './customlinkview'
-
-
-module.exports = class WelcomeModal extends KDModalView
-
-  constructor: (options = {}, data) ->
-
-    options.cssClass      = 'welcome-modal'
-    options.overlay       = yes
-    options.overlayClick  = no
-    options.width         = 766
-    options.height        = 519
-
-    super options, data
-
-    @addSubView new KDCustomHTMLView
-      cssClass    : 'decoration-image'
-      tagName     : 'figure'
-
-    @addSubView content = new KDCustomHTMLView
-      cssClass    : 'content'
-
-    content.addSubView new KDHeaderView
-      type        : 'big'
-      title       : 'Welcome Home'
-
-    content.addSubView new KDHeaderView
-      type        : 'medium'
-      title       : 'An all new Koding, all ready to go!'
-
-    content.addSubView new KDCustomHTMLView
-      tagName     : 'p'
-      partial     : "
-        Robust VMs, a new IDE/Terminal and awesome new social
-        features... all that is just a click away. You are about to
-        experience a whole new Koding and you will fall in love all
-        over again.
-      "
-
-    content.addSubView new CustomLinkView
-      cssClass    : 'welcome-btn'
-      title       : 'Read our blog post about this release'
-      click       : =>
-        global.open 'http://blog.koding.com/2014/09/new-release', '_blank'
-        @destroy()
-
-    content.addSubView new CustomLinkView
-      cssClass    : 'welcome-btn'
-      title       : 'Explore the new koding now'
-      click       : @bound 'cancel'
-
-
-


clone state array

clone state array

--- resources/assets/coffee/react/beatmap-discussions-history/main.coffee
+++ resources/assets/coffee/react/beatmap-discussions-history/main.coffee
@@ -40,9 +40,9 @@
     {beatmapset} = options
     return unless beatmapset?

-    discussions = @state.discussions
-    users = @state.users
-    relatedDiscussions = @state.relatedDiscussions
+    discussions = [@state.discussions...]
+    users = [@state.users...]
+    relatedDiscussions = [@state.relatedDiscussions...]

     discussionIds = _.map discussions, 'id'
     userIds = _.map users, 'id'
@@ -66,7 +66,7 @@

       users.push(newUser)

-    @cache.users = @cache.discussions = @cache.beatmaps = null
+    @cache.users = @cache.discussions = @cache.beatmaps = @state.relatedDiscussions = null
     @setState
       discussions: _.reverse(_.sortBy(discussions, (d) -> Date.parse(d.starting_post.created_at)))
       users: users


fix: remove useless lines before import

fix: remove useless lines before import

--- client/src/common/services/dynamic-fields.coffee
+++ client/src/common/services/dynamic-fields.coffee
@@ -1,4 +1,3 @@
-
 import DOMPurify from 'dompurify';

 angular.module 'Scrumble.common'


Exported Meta Model is now an Array (not an Object).

--- server/app/assets/metaModelEditor/ext/exportMetaModel/Exporter.coffee
+++ server/app/assets/metaModelEditor/ext/exportMetaModel/Exporter.coffee
@@ -45,7 +45,7 @@

   # Builds the metaModel JSON object and returns it.
   createMetaModel: () ->
-    metaModel = {}
+    metaModel = []

     @addClasses metaModel
     @addReferences metaModel
@@ -58,7 +58,7 @@
   addClasses: (metaModel) ->
     for element in @graph.getElements()

-      metaModel[@graph.getName element] =
+      metaModel.push
         mType: Constants.CLASS
         name: @graph.getName element
         abstract: @graph.isAbstract element
@@ -72,7 +72,7 @@
   addReferences: (metaModel) ->
     for reference in @graph.getReferences()

-      metaModel[@graph.getName reference] =
+      metaModel.push
         mType: Constants.REFERENCE
         name: @graph.getName reference
         sourceDeletionDeletesTarget: @graph.getSourceDeletionDeletesTarget reference
@@ -86,7 +86,7 @@
   addEnums: (metaModel) ->
     for thisMEnum in mEnum.getMEnums()

-      metaModel[thisMEnum.name] =
+      metaModel.push
         mType: Constants.ENUM
         name: thisMEnum.name
         type: thisMEnum.type


Klient: fetchTerminalSessions: make sure its not getting called more than once

--- client/Main/kite/kites/klient.coffee
+++ client/Main/kite/kites/klient.coffee
@@ -40,10 +40,9 @@

     @connect()  unless @_connectAttempted

-    unless @terminalSessions.length
-      @fetchTerminalSessions()
-
-    Promise.resolve()
+    if @terminalSessions.length is 0 and not @_fetchingSessions
+    then @fetchTerminalSessions()
+    else Promise.resolve()

   # setTransport is used to override the setTransport method in KodingKite
@@ -92,12 +91,19 @@

   fetchTerminalSessions: ->

+    @_fetchingSessions = yes
+
     @webtermGetSessions()

     .then (sessions)=>

       @terminalSessions = sessions
+      @_fetchingSessions = no
+
+    .timeout 10000

     .catch (err)=>
+
       # Reset current sessions if fails
       @terminalSessions = []
+      @_fetchingSessions = no


Activity: added default redirection to public

--- client/Social/Activity/routes.coffee
+++ client/Social/Activity/routes.coffee
@@ -43,3 +43,7 @@
       unless slug
       then router.openSection 'Activity', name, query
       else createContentDisplayHandler('Activity') arguments...
+
+    '/:name?/Activity' : ({params:{name, slug}, query}) ->
+      {router, appManager} = KD.singletons
+      router.handleRoute '/Activity/Public'


AdminAppView: Remove temp hack to style tabs.

--- client/admin/lib/adminappview.coffee
+++ client/admin/lib/adminappview.coffee
@@ -71,10 +71,6 @@

       @emit 'ready'

-      # borrow invitations tab styling
-      # should be implemented by refactoring stylus
-      @tabs.getPaneByName('Members').setClass 'invitations'
-

   search: (searchValue)->
     if @tabs.getActivePane().name is 'Invitations'


add metod tipo to use as app

add metod tipo to use as app

--- emt.coffee
+++ emt.coffee
@@ -21,16 +21,15 @@
       'Space'
     ]

-
-    apply:->
-      @text = @el.html()
-
+    tipo:(@text)->
       for rule in @rules
         rule.text = @text
         rule.apply()
         @text = rule.text
+      @text

-      @el.html @text
+    apply:->
+      @el.html @tipo @el.html()
       @


Fix signin redirect

Fix signin redirect

--- lib/assets/javascripts/routers/auth.js.coffee
+++ lib/assets/javascripts/routers/auth.js.coffee
@@ -5,7 +5,8 @@
   }

   signin: (params) =>
-    params.redirect = null if params.redirect && params.redirect.indexOf('://') != -1 && params.redirect.indexOf('://') < params.redirect.indexOf('/')
+    if params.redirect && params.redirect.indexOf('//') != -1 && params.redirect.indexOf('//') == params.redirect.indexOf('/')
+      params.redirect = null
     params.redirect ?= TentAdmin.config.PATH_PREFIX || '/'

     if TentAdmin.config.authenticated


Less suggestions for typeahead.

Less suggestions for typeahead.

--- src/search.coffee
+++ src/search.coffee
@@ -3,7 +3,7 @@
     engine = new Bloodhound
         name: 'suggestions'
         remote:
-            url: sm_settings.backend_url + "/search/?language=#{lang}&page_size=5&input=%QUERY"
+            url: sm_settings.backend_url + "/search/?language=#{lang}&page_size=4&input=%QUERY"
             ajax: settings.applyAjaxDefaults {}
             filter: (parsedResponse) ->
                 parsedResponse.results


Enable starting crash-reporter without parameters.

--- common/api/lib/crash-reporter.coffee
+++ common/api/lib/crash-reporter.coffee
@@ -1,7 +1,7 @@
 binding = process.atomBinding 'crash_reporter'

 class CrashReporter
-  start: (options) ->
+  start: (options={}) ->
     {productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler} = options

     productName ?= 'Atom-Shell'


No more need for restart().

No more need for restart().

--- src/server.coffee
+++ src/server.coffee
@@ -60,9 +60,6 @@
 # The Node.js app server
 class NodeAppServer

-  constructor: ->
-    @restart = _.debounce(@start, 1000, true)
-
   startAndWatch: ->
     # Start the server
     @start()
@@ -74,13 +71,13 @@
       {ignored: ignored, persistent: true, ignoreInitial: true, usePolling: true, interval: 200}
     watcher.on 'add', (path) =>
       logging.info "added #{path}"
-      @restart()
+      @start()
     watcher.on 'change', (path) =>
       logging.info "changed #{path}"
-      @restart()
+      @start()
     watcher.on 'unlink', (path) =>
       logging.info "removed #{path}"
-      @restart()
+      @start()
     watcher.on 'error', (error) ->
       logging.error "Error occurred while watching files: #{error}"

@@ -92,16 +89,17 @@
       logging.info 'Restarting the application server...'
     else
       # Start the server in a child process
-      child = exports.child = spawn 'node', ['server/server.js'], {stdio: 'inherit', cwd: process.cwd()}
+      child = exports.child = spawn 'node', ['server/server.js'], {cwd: process.cwd()}
       child.shouldRestart = false

-      # child.stdout.on 'data', (data) ->
-      #   console.log data.toString()
-      #   reloadBrowser() if /Quit the server with CONTROL-C/.test(data.toString())
+      child.stdout.on 'data', (data) ->
+        console.log data.toString()
+        if /Quit the server with CONTROL-C/.test(data.toString())
+          reloadBrowser()

-      # child.stderr.on 'data', (data) ->
-      #   if data.toString().length > 1
-      #     logging.error data
+      child.stderr.on 'data', (data) ->
+        if data.toString().length > 1
+          logging.error data

       child.on 'exit', (code) =>
         exports.child = null


Fix pub dir path.

Fix pub dir path.

--- src/server.coffee
+++ src/server.coffee
@@ -14,7 +14,7 @@
 PUBDIR = __dirname +
   if process.env.NODE_ENV is "development"
   then "/../front/public"
-  else "/public"
+  else "/../public"
 console.log PUBDIR

 MAX_ITEMS = 50


Create a new Page instance and Source instances each http requests

--- src/server.coffee
+++ src/server.coffee
@@ -148,18 +148,18 @@
       referer = req.headers.referer
       switch ext
         when ".html"
-          page = @pageList.filter((h) -> h.uri == uri)[0]
-          if !page?
-            page = new Page(uri, fileName, file.toString())
-            @pageList.push page
-          profile   = new Profile(page)
+          page    = new Page(uri, fileName, file.toString())
+          profile = new Profile(page)
+          @pageList.push page
           @profileList.push profile
           file = Instrumentor.instrumentFunctionTraceDefinition2Page(page,
                                                                      profile,
                                                                      @tracer)
         when ".js"
-          page    = @pageList.filter((h) -> h.uri == referer)[0]
-          profile = @profileList.filter((h) -> h.uri == referer)[0]
+          pages    = @pageList.filter((h) -> h.uri == referer)
+          profiles = @profileList.filter((h) -> h.uri == referer)
+          page     = pages[pages.length - 1]
+          profile  = profiles[profiles.length - 1]
           if page?
             source = new Source(uri, file.toString(), page)
             page.sources[uri] = source


tbg-forms remove error classes

tbg-forms remove error classes

--- vendor/assets/javascripts/styleguide/plugins/tbg-forms.js.coffee
+++ vendor/assets/javascripts/styleguide/plugins/tbg-forms.js.coffee
@@ -48,6 +48,7 @@

     showErrors :( errors )->
       @form.find('.form-msg.is-error').remove()
+      @form.find('.is-error').removeClass('is-error')

       for field, error of errors
         $this = @form.find("[id$=#{field}]").addClass('is-error')


Battle: Spectators can now see their own messages.

--- server/bw/battle_controller.coffee
+++ server/bw/battle_controller.coffee
@@ -53,7 +53,6 @@

   messageSpectators: (user, message) ->
     for spectator in @battle.spectators
-      continue  if spectator.id == user.id
       spectator.send('update battle chat', @battle.id, user.id, message)

   # Continue or begin a new turn if each player has made an action.


Properly check whether we know about a comment

--- server/cron/downloadSubmits.coffee
+++ server/cron/downloadSubmits.coffee
@@ -98,7 +98,7 @@
     mergeComments: (c1, c2) ->
         result = c1
         for c in c2
-            if not c in result
+            if not (c in result)
                 result.push(c)
         return result

@@ -146,6 +146,7 @@

         [source, comments, results] = await Promise.all([
             @getSource(runid), @getComments(newSubmit.problem, newSubmit.user, runid), @getResults(runid)])
+
         newSubmit.source = source
         newSubmit.results = results
         newSubmit.comments = @mergeComments(newSubmit.comments, comments)


Fix submitComment date

Fix submitComment date

--- server/cron/downloadSubmits.coffee
+++ server/cron/downloadSubmits.coffee
@@ -78,9 +78,8 @@
                     problemName: problem.name
                     userId: userId
                     text: c.comment
-                    time: new Date()
+                    time: new Date(moment(c.date + "+03"))
                     outcome: outcome
-                console.log newComment
                 await newComment.upsert()

             return (c.comment for c in comments)


So it works somehow, but Invalidation of cache required to realize it

--- server/helpers/cdnify/index.coffee
+++ server/helpers/cdnify/index.coffee
@@ -37,7 +37,11 @@
     _cdnKey = null

     request(url)
-      .then (content)->
+      .then (content) ->
+
+        CDNify.content(content)
+
+      .then (content) ->

         _cdnKey = url.replace('http://tilda.ws/', '')
         awsHelper.upload _cdnKey, content
@@ -99,11 +103,49 @@

     # Fix Tilda CDN URLs
     content =
-    content
+      content
       .replace /http:\/\/images\.tildacdn\.info\//gi, '//images.tildacdn.info/'

-    def.resolve content
+    # Get all URLs from content
+    urls = content.match urlRegex()
+    urls = [] if not urls?
+
+
+    urls = _.unique urls
+
+    urls = _.map urls, (url) ->
+      url
+        .replace /"/g, ''
+        .replace /\'/g, ''
+        .replace /\\'/g, ''
+        .replace /\(/g, ''
+        .replace /\)/g, ''
+
+
+    urls = _.filter urls, (url) ->
+      match = tildaImages.match url
+      match? and match.domain? and match.domain is 'tilda' and match.tld? and match.tld is 'ws'
+
+    promises = []
+
+    for url in urls
+      promises.push CDNify.exchange(url)
+
+    Promises
+      .all promises
+      .then (cdnUrls) ->
+
+        for url, i in urls
+          content = content.replace url, cdnUrls[i]
+          content = content.replace url, cdnUrls[i]
+
+        def.resolve content
+
+        return
+
+      .catch (err) ->
+        def.reject err

     def.promise


We've changed body of 404 message.

We've changed body of 404 message.

--- src/sockjs.coffee
+++ src/sockjs.coffee
@@ -23,6 +23,12 @@
         res.setHeader('content-type', 'text/plain; charset=UTF-8')
         res.writeHead(200)
         res.end("Welcome to SockJS!\n")
+        return true
+
+    handle_404: (req, res) ->
+        res.setHeader('content-type', 'text/plain; charset=UTF-8')
+        res.writeHead(404)
+        res.end('404 Error: Page not found\n')
         return true

     disabled_transport: (req, res, data) ->


Tests for asCallback with a graph, refs #582

--- spec/AsCallback.coffee
+++ spec/AsCallback.coffee
@@ -235,3 +235,35 @@
             'closeBracket 1'
           ]
           done()
+  describe 'with a graph instead of component name', ->
+    graph = null
+    wrapped = null
+    before (done) ->
+      noflo.graph.loadFBP """
+      INPORT=Async.IN:IN
+      OUTPORT=Stream.OUT:OUT
+      Async(process/Async) OUT -> IN Stream(process/Streamify)
+      """, (err, g) ->
+        return done err if err
+        graph = g
+        wrapped = noflo.asCallback graph,
+          loader: loader
+        done()
+    it 'should execute network with input map and provide output map with streams as arrays', (done) ->
+      wrapped
+        in: 'hello world'
+      , (err, out) ->
+        return done err if err
+        chai.expect(out.out).to.eql [
+          ['h','e','l','l','o']
+          ['w','o','r','l','d']
+        ]
+        done()
+    it 'should execute network with simple input and and provide simple output with streams as arrays', (done) ->
+      wrapped 'hello there', (err, out) ->
+        return done err if err
+        chai.expect(out).to.eql [
+          ['h','e','l','l','o']
+          ['t','h','e','r','e']
+        ]
+        done()


continue work on geometric collisions

continue work on geometric collisions

* refactor Sprite.collidesWith(other) to use new geometric classes
* remove Sprite.log()
* add experimental Sprite.highlight()
* modify Sprite 'draw' event, now 'draw:before' and 'draw:after'

--- src/sprite.coffee
+++ src/sprite.coffee
@@ -172,10 +172,10 @@
         #create default boundary if none was provided
         unless @_bnd?
             @_bnd = []
-            @_bnd.push new Point -@_dis.width / 2, @_dis.height /2, @_pos.x, @_pos.y
-            @_bnd.push new Point @_dis.width / 2, @_dis.height /2, @_pos.x, @_pos.y
-            @_bnd.push new Point @_dis.width / 2, -@_dis.height /2, @_pos.x, @_pos.y
-            @_bnd.push new Point -@_dis.width / 2, -@_dis.height /2, @_pos.x, @_pos.y
+            @_bnd.push new Point -@_dis.width / 2, @_dis.height / 2, @_pos.x, @_pos.y
+            @_bnd.push new Point @_dis.width / 2, @_dis.height / 2, @_pos.x, @_pos.y
+            @_bnd.push new Point @_dis.width / 2, -@_dis.height / 2, @_pos.x, @_pos.y
+            @_bnd.push new Point -@_dis.width / 2, -@_dis.height / 2, @_pos.x, @_pos.y

         #start updating if the engine is already running
         if Greenhorn.isRunning() then @_start()
@@ -217,6 +217,9 @@
         else if what.match /^left$/
             value = pt.x for pt in @_bnd
             value = Math.min value...
+        else if what.match /^radius$/
+            value = pt.get('dist') for pt in @_bnd
+            value = Math.max value...
         else if what.match /^distance$/
             value = Math.sqrt @_pos.x**2 + @_pos.y**2
         else if what.match /^speed$/
@@ -421,23 +424,38 @@
     #collision routines
     collidesWith: (other) ->
         if other is 'mouse'
-            collision = false
             if @_dis.visible
-                if @get('left', false) < Greenhorn.getMouseX() < @get('right', false) and
-                @get('bottom', false) < Greenhorn.getMouseY() < @get('top', false)
-                    collision = true
+                if @get('left', false) <= Greenhorn.getMouseX() <= @get('right', false) and
+                @get('bottom', false) <= Greenhorn.getMouseY() <= @get('top', false)
+                    return true
+            return false
         else
-            collision = true
-            if @_dis.visible and
-            other._dis.visible and
-            @_dis.level == other._dis.level
-                if @get('bottom', false) > other.get('top', false) or
-                @get('top', false) < other.get('bottom', false) or
-                @get('right', false) < other.get('left', false) or
-                @get('left', false) > other.get('right', false)
-                    collision = false
-            else collision = false
-        collision
+            if @_dis.visible
+                if other._dis.visible
+                    if @_dis.level == other._dis.level
+                        if @distanceTo(other) <= @get('radius', false) + other.get('radius', false)
+                            #declare arrays
+                            myLines = []
+                            otherLines = []
+
+                            #create lines representing boundaries
+                            for pt, i in @_bnd
+                                if i is @_bnd.length - 1
+                                    myLines.push new Line pt, @_bnds[0]
+                                else
+                                    myLines.push new Line pt, @_bnds[i+1]
+                            for pt, i in other._bnd
+                                if i is other._bnd.length - 1
+                                    otherLines.push new Line pt, other._bnd[0]
+                                else
+                                    otherLines.push new Line pt, other._bnd[i+1]
+
+                            #check for collisions
+                            for myLine in myLines
+                                for otherLine in otherLines
+                                    if myLine.collidesWith otherLine
+                                        return true
+            return false
     distanceTo: (other) ->
         otherX = otherY = 0
         if other is 'mouse'
@@ -460,11 +478,11 @@
     #update routines
     _draw: ->
         if @_dis.visible
-            #fire draw event
-            @emit 'draw'
-
             #save context
             @_dis.context.save()
+
+            #fire draw:before event
+            @emit 'draw:before'

             #translate and rotate
             @_dis.context.translate @_pos.x, -@_pos.y
@@ -477,9 +495,12 @@
                 -@_dis.height / 2, #top
                 @_dis.width, #width
                 @_dis.height) #height
-
+
             #restore context
             @_dis.context.restore()
+
+            #fire draw:after event
+            @emit 'draw:after'
     _update: =>
         #fire update event
         @emit 'update'
@@ -668,8 +689,18 @@
             right: #{@_bas.right.ba}
             left: #{@_bas.left.ba}
         """
-    log: ->
-        console.log @report()
+    highlight: ->
+        @on 'draw:after', ->
+            @_dis.context.save()
+            @_dis.context.lineWidth = 3
+            @_dis.context.strokeStyle = 'white'
+            @_dis.context.beginPath()
+            @_dis.context.moveTo(@_bnd[0].x, @_bnd[0].y)
+            for pt, i in @_bnd when i isnt 0
+                @dis.context.lineTo(pt.x, pt.y)
+            @_dis.context.closePath()
+            @_dis.context.stroke()
+            @_dis.context.restore()

 #add to namespace object
 gh.Sprite = Sprite


Prevent update specs from running

Prevent update specs from running

--- spec/about-spec.coffee
+++ spec/about-spec.coffee
@@ -44,7 +44,7 @@
         expect(atom.clipboard.read()).toBe atom.getVersion()

   # TODO: remove when this function is in beta / stable
-  return unless atom.autoUpdater?.getState?
+  return unless atom.autoUpdater?.onUpdateError?

   describe "updates", ->
     [aboutElement, updateManager] = []


Correct current timestamp calculation for out-of-office when moment.js is used

--- src/status.coffee
+++ src/status.coffee
@@ -535,7 +535,7 @@
     @updateToggle @humanData

   officeHoursTimeout: ->
-    now = utcDate().getTime()
+    now = @officeTimestamp()
     officeOpen = @officeOpenTimestamp() - now
     officeClose = @officeCloseTimestamp() - now
     nextChange = if officeOpen < officeClose then officeOpen else officeClose
@@ -547,7 +547,7 @@

   isOutOfOffice: ->
     return false if !@options["outOfOffice"]
-    now = utcDate().getTime()
+    now = @officeTimestamp()
     !(@officeOpenTimestamp() <= now && now <= @officeCloseTimestamp())

   officeOpenTimestamp: ->
@@ -571,6 +571,12 @@

   officeHoursOverlapDays: ->
     @outOfOffice["officeOpenHour"] < @outOfOffice["officeCloseHour"]
+
+  officeTimestamp: ->
+    if window.moment
+      moment().tz(@outOfOffice["timezone"]).valueOf()
+    else
+      utcDate().getTime()

   debounce: (func, threshold, execAsap) ->
     timeout = null


just a comment

just a comment

--- spec/redis_spec.coffee
+++ spec/redis_spec.coffee
@@ -25,6 +25,6 @@

   describe ".client in testmode" , ->
     it "should select the testdatabase if running in test enviroment", ->
-      #process.env.NODE_ENV = "test"
+      #process.env.NODE_ENV = "test" // because we are in test
       r = redis.client()
       expect(redis_client_spy.select).toHaveBeenCalledWith(15)


rmv trailing whitespace

rmv trailing whitespace

--- SingularityUI/app/views/tail.coffee
+++ SingularityUI/app/views/tail.coffee
@@ -180,6 +180,7 @@
     stopTailing: ->
         [..., task] = @model.get('taskUpdates')
         return if @isTailing isnt true and task.taskState in TERMINAL_TASK_STATES
+
         @isTailing = false
         clearInterval @tailInterval
         @$el.removeClass 'tailing'


only delegate mobile events if browser is mobile

--- components/layout/body/view.coffee
+++ components/layout/body/view.coffee
@@ -17,13 +17,12 @@
     'click #scroll-top'                           : 'scrollToTop'

   mobileEvents:
-    'tap'                                       : 'bodyClick'
-    'tap a[data-disabled]'                      : 'disable'
-    'tap a[data-client]:not([data-disabled])'   : 'intercept'
-    'tap span[data-client]:not([data-disabled])': 'intercept'
-    'tap a'                                     : 'maybeIntercept'
-    'tap #scroll-top'                           : 'scrollToTop'
-
+    'tap'                                         : 'bodyClick'
+    'tap a[data-disabled]'                        : 'disable'
+    'tap a[data-client]:not([data-disabled])'     : 'intercept'
+    'tap span[data-client]:not([data-disabled])'  : 'intercept'
+    'tap a'                                       : 'maybeIntercept'
+    'tap #scroll-top'                             : 'scrollToTop'

   initialize: (options) ->
     current_path = sd.CURRENT_PATH?.replace sd.CLIENT_PATH, ""


add file watching capability @ commandline

--- src/amdify.coffee
+++ src/amdify.coffee
@@ -12,6 +12,7 @@
 _ = require 'underscore'
 argv = require('optimist')
   .demand(['source','target'])
+  .boolean('w')
   .usage('Usage: amdify [-w] -source <source_module_dir> -target <target_output_dir>')
   .argv

@@ -59,16 +60,48 @@
 # we can build on top of EventEmitter.

 {parseFile} = require './parser'
+{EventEmitter} = require 'events'
+

 # we also want to have the ability to watch for the files to change...
-parseFile argv.source, (err, parsed) ->
-  if err
-    console.log 'ERROR\n', err
-  else
-    fs.writeFile argv.target, parsed.serialize(), (err) ->
-      if err
-        console.log 'ERROR\n', err
-      else
-        console.log 'done.'
+# because we have a list of the files that should be watched once we've done the parsing

+# should I pass in a callback? might be easier..
+class Watcher extends EventEmitter
+  constructor: () ->
+    @inner = {}
+  addFileMap: (fileMap, cb) ->
+    # the goal is to determine whether something exists...
+    # we also want to anything that
+    @removeOldWatchers fileMap
+    for file, val of fileMap
+      if not @inner[file]
+        @inner[file] = fs.watch file, (evt, fileName) =>
+          console.log "[#{evt}] #{file}"
+          @emit 'changed', event: evt, file: file
+          if cb
+            cb event: evt, file: file
+  removeOldWatchers: (fileMap) ->
+    for file, watcher of @inner
+      if not fileMap[file]
+        watcher.close()
+        delete @inner[file]

+watcher = new Watcher()
+
+entry = (source, target, watch) ->
+
+  parseFile source, (err, parsed) ->
+    if err
+      console.log 'ERROR\n', err
+    else
+      fs.writeFile target, parsed.serialize(), (err) ->
+        if err
+          console.log 'ERROR\n', err
+        else
+          console.log "Saved to #{target}"
+        if watch
+          watcher.addFileMap parsed.scripts, ({event, file}) ->
+            entry source, target, watch
+
+entry argv.source, argv.target, argv.w


length was not used

length was not used

--- src/ui/dem.coffee
+++ src/ui/dem.coffee
@@ -19,7 +19,6 @@

     for ring in contourLayer
       continue if ring.properties.elevation % 300
-      length = turf.lineDistance(ring, 'kilometers') * (map.s0 * map.sc) / app.PXKM
       contours.append('text')
           .attr('class', 'contour-label')
           .append('textPath')


Removed unnecessary call of setSize

Removed unnecessary call of setSize

--- src/Sprite.coffee
+++ src/Sprite.coffee
@@ -22,11 +22,8 @@
   setSize: (width, height) ->
     @_width = width
     @_height = height
-
     @style.width = "#{width.toFixed(DivSugar.NUM_OF_DIGITS)}px"
     @style.height = "#{height.toFixed(DivSugar.NUM_OF_DIGITS)}px"
-
-    @setImageClip @_imageClipU1, @_imageClipV1, @_imageClipU2, @_imageClipV2
     return @

   getPositionX: -> @_transform.trans.x


Refresh repo view when a new study is added.

--- frontend/coffeescript/app/dashboard/views.coffee
+++ frontend/coffeescript/app/dashboard/views.coffee
@@ -136,19 +136,30 @@
             @study_view.on( 'render', @_apply_draggable )
             @study_view.collection.reset( document.study_list )

+            @study_view.on( 'after:item:added', @refresh_repos_event )
+
             $( 'li', '#studies' ).droppable(
                 hoverClass: 'drop-hover'
                 drop: @_drop_on_study )
             @

-        refresh_repos_event: ( event ) ->
+        refresh_repos_event: ( event ) =>
+            if event.currentTarget?
+                study_el   = event.currentTarget
+                study_id   = $( study_el ).data( 'study' )
+                study_name = $( study_el ).html()
+            else
+                study_el   = event.el
+                study_id   = event.model.id
+                study_name = event.model.get( 'name' )
+
             # Update the "Study" name and highlight the one the user just clicked.
-            $( '#study_name' ).html( $( event.currentTarget ).html()  )
+            $( '#study_name' ).html( study_name  )
             $( '#studies .selected' ).removeClass( 'selected' )
-            $( event.currentTarget ).parent().addClass( 'selected' )
+            $( study_el ).parent().addClass( 'selected' )

             # Fetch the new set of repositories
-            @repo_view.refresh( $( event.currentTarget ).data( 'study' ) )
+            @repo_view.refresh( study_id )

             @


Fix headers

Fix headers

--- src/podroller/core.coffee
+++ src/podroller/core.coffee
@@ -166,22 +166,26 @@
             # Get the requested start and end
             if _u.isString rangeStr
                 rangeVals = rangeStr.match(/bytes=(.+)-(.+)?/)
-                requestStart = rangeVals[1]
-                requestEnd = rangeVals[2]
+
+                # Force into integers
+                requestStart = rangeVals[1] - 0
+                requestEnd = rangeVals[2] - 0

             console.log "requested start, end is", requestStart, requestEnd

             # If rangeVals has two numbers, then check if they
             # are valid and within the file size
-            if _u.isNumber requestStart and _u.isNumber requestEnd
+            if _u.isNumber(requestStart) and _u.isNumber(requestEnd)
                 rangeStart = if (requestStart >= fstart && requestStart < fend) then requestStart else fstart
                 rangeEnd = if (requestEnd > fstart && requestEnd <= fend) then requestEnd else fend

                 # Request is for a range
                 rangeRequest = true
-
+
+            console.log "rangeStart, rangeEnd, rangeRequest is", rangeStart, rangeEnd, rangeRequest
             # What is the actual length of content being sent back?
             length = if rangeRequest then (rangeEnd - rangeStart + 1) else fsize
+            console.log "actual length is", length

             # send out headers
             headers =
@@ -196,7 +200,6 @@
                 headers["Content-Range"] = "bytes #{rangeStart}-#{rangeEnd}/#{fsize}"

-            console.log "final size should be ", fsize
             console.log "request method is ", req.method
             console.log "headers are", headers


hide lines

hide lines

--- jarkle/client/skeleton.coffee
+++ jarkle/client/skeleton.coffee
@@ -69,6 +69,8 @@
         color: 0x00ff00
         linewidth: 1000
       line = new THREE.Line geometry, material
+      line.traverse (obj) ->
+        obj.visisble = false
       @scene.add line
       @lines.push line

@@ -76,6 +78,9 @@
     for bodyPartName, bodyPart of @bodyMap
       bodyPart.traverse (object) ->
         object.visible = false
+    for line in @lines
+      line.traverse (obj) ->
+        obj.visisble = false

   updateBodyPart: (bodyPart, points) ->
     unless bodyPart?
@@ -95,5 +100,7 @@
       bodyPart = @bodyMap[bodyPartName]
       @updateBodyPart(bodyPart, points)
     for line in @lines
+      line.traverse (obj) ->
+        obj.visisble = true
       line.geometry.verticesNeedUpdate = true


Removed uneeded directive

Removed uneeded directive

--- app/assets/javascripts/sprangular/directives/forms/counter.coffee
+++ app/assets/javascripts/sprangular/directives/forms/counter.coffee
@@ -1,12 +0,0 @@
-# Sprangular.directive 'dirFCounter', ->
-#   restrict: 'AE'
-#   scope:
-#     number: '=ngModel'
-#   link: (scope, counter, attrs) ->
-#     scope.update = (delta) ->
-#       # scope.number = if scope.number = 0 or is NaN or is undefined then 0
-#       console.log 'scope.number', scope.number
-#       # scope.number = 0 if scope.number <= 0 or scope.number is NaN or scope.number is undefined
-#       scope.number += delta unless (scope.number + delta) is 0
-#     scope.change = ->
-#       console.log 'change', scope.number


adjust amazon client to properly determine package status

--- src/amazon.coffee
+++ src/amazon.coffee
@@ -35,7 +35,7 @@

   presentStatus: (data) ->
     {$, response} = data
-    STATUS_MAP[response.toString().match('shortStatus=(.*?),')?[1]]
+    STATUS_MAP[response.toString().match('"shortStatus":"(.*?)"')?[1]]

   getActivitiesAndStatus: (data) ->
     activities = []


stash

stash

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -2631,18 +2631,20 @@

                 @index++
                 if rdb_query instanceof @TermBaseConstructor
+                    final_query = @index is @queries.length
                     @start_time = new Date()

-                    query_result = new QueryResult
-                        has_profile: @state.options.profiler
-                        current_query: @raw_query
-                        raw_query: @raw_queries[@index]
-                        driver_handler: @driver_handler
-                        events:
-                            error: (err) =>
-                                @results_view.render_error(@query, err)
-
-                    # ATN: pass the query_result object to the view
+                    if final_query
+                        query_result = new QueryResult
+                            has_profile: @state.options.profiler
+                            current_query: @raw_query
+                            raw_query: @raw_queries[@index]
+                            driver_handler: @driver_handler
+                            events:
+                                error: (err) =>
+                                    @results_view.render_error(@query, err)
+
+                        # ATN: pass the query_result object to the view

                     @driver_handler.run_with_new_connection rdq_query,
                         optargs:
@@ -2651,7 +2653,13 @@
                             profile: @state.options.profile
                         connection_error: (error) =>
                             @error_on_connect error
-                        callback: query_result.set
+                        callback: (error, result) =>
+                            if final_query
+                                query_result.set error, result
+                            else if error
+                                @result_view.render_error(@query, err)
+                            else
+                                @execute_portion()

                     return true
                 else
@@ -2664,50 +2672,6 @@
                         @save_query
                             query: @raw_query
                             broken_query: true
-
-
-        # ATN: move to child views, with special care for error handling
-        # ATN: this is no longer called
-        # Handle the result of a query
-        query_result_callback: (result) =>
-            if result.error?
-                if @queries.length > 1
-                    @results_view.render_error(@raw_queries[@index-1], result.error)
-                else
-                    @results_view.render_error(null, result.error)
-                @save_query
-                    query: @raw_query
-                    broken_query: true
-                return false
-
-            @ATN_profile = result.profile ? null
-            @state.ATN_profile = @ATN_profile
-
-            if @index is @queries.length # @index was incremented in execute_portion
-                @state.query_result = result
-                if result.cursor?
-
-                    result.shift @limit, @next_results_callback
-                else
-                    @ATN_current_results = result.value
-
-                    @state.ATN_results = @ATN_current_results
-                    @state.ATN_metadata =
-                        limit_value: if Object::toString.call(@results) is '[object Array]' then @ATN_current_results.length else 1
-                        skip_value: 0
-                        execution_time: new Date() - @start_time
-                        query: @query
-                        has_more_data: false
-
-                    @results_view.render_result
-                        query_result: @ATN_current_results
-
-                    # Successful query, let's save it in the history
-                    @save_query
-                        query: @raw_query
-                        broken_query: false
-            else
-                @execute_portion()

         # ATN: move to child views
         # Called when there is a new batch of results to display


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -25,7 +25,7 @@
   objectFilters = []
   transformFilters = []

-  focusOn = (object, d) ->
+  focusOn = (object, dt) ->
     dt = 1 / 30 # TODO: Use engine FPS
     dampingFactor = 2


Camera updates properly when loading save

--- src/camera.coffee
+++ src/camera.coffee
@@ -12,7 +12,7 @@
 	bounds: (rect) ->
 		@worldBounds =
 			_.defaults (_.pick rect, 'x', 'y', 'w', 'h'),
-				{ x: @x, y: @y, w: @viewport.w, h: @viewport.h }
+				{ x: 0, y: 0, w: @viewport.w, h: @viewport.h }

 	calculateOffset: (relPos, camSize, minBoundDist) ->
 		if minBoundDist > relPos then (relPos - minBoundDist)


feat(new-vm): shared VM in resource set (#518)

Fixes vatesfr/xo-web#1964.

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -158,7 +158,12 @@

   if resourceSet
     yield Promise.all([
-      @addAcl(user.id, vm.id, 'admin')
+      if params.share
+        $resourceSet = yield @getResourceSet(resourceSet)
+        Promise.all(map($resourceSet.subjects, (subjectId) => @addAcl(subjectId, vm.id, 'admin')))
+      else
+        @addAcl(user.id, vm.id, 'admin')
+
       xapi.xo.setData(xapiVm.$id, 'resourceSet', resourceSet)
     ])

@@ -214,6 +219,12 @@

   # PV Args
   pv_args: { type: 'string', optional: true }
+
+
+  share: {
+    type: 'boolean',
+    optional: true
+  }

   # TODO: add the install repository!
   # VBD.insert/eject


Add delete VM-template

Add delete VM-template

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -122,7 +122,7 @@
   }
 }
 delete_.resolve = {
-  vm: ['id', ['VM', 'VM-snapshot'], 'administrate']
+  vm: ['id', ['VM', 'VM-snapshot', 'VM-template'], 'administrate']
 }

 exports.delete = delete_


minor corrections

minor corrections

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -60,6 +60,7 @@
       @onPublish = options.publish || $.noop
       @onSave = options.save || $.noop
       @onPreview = options.preview || $.noop
+
       @expand_all_multioptions = null

       $(window).on "keydown", (evt)=>
@@ -141,17 +142,17 @@
         @$(".row-extras__add-to-question-library").hide()

-      if @expand_all_multioptions == null
+      if @expand_all_multioptions is null
         $expand_multioptions = @$(".js-expand-multioptions--all")
-        $expand_multioptions.click () ->
+        $expand_multioptions.click () =>
           if @expand_all_multioptions
             @expand_all_multioptions = false
             $(".card.card--selectquestion").removeClass("card--expandedchoices")
-            $expand_multioptions.html($expand_multioptions.html().replace("Colapse", "Expand"));
+            $expand_multioptions.html($expand_multioptions.html().replace("Collapse", "Expand"));
           else
             @expand_all_multioptions = true
             $(".card.card--selectquestion").addClass("card--expandedchoices")
-            $expand_multioptions.html($expand_multioptions.html().replace("Expand", "Colapse"));
+            $expand_multioptions.html($expand_multioptions.html().replace("Expand", "Collapse"));

       @


allowing metaKey in addition to ctrlKey for tp #1176

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -190,7 +190,8 @@
       _isIntendedTarget = $ect.closest('.survey__row').get(0) is $et.closest('.survey__row').get(0)
       if _isIntendedTarget
         $target = $et.closest('.survey__row')
-        if !evt.ctrlKey
+        meta_key_pressed = evt.ctrlKey or evt.metaKey
+        if !meta_key_pressed
           selected_rows = $target.siblings('.survey__row--selected')
           if !$target.hasClass('survey__row--selected') || selected_rows.length > 1
             @deselect_all_rows()


client: and we reach code generation.

client: and we reach code generation.

--- src/client.coffee
+++ src/client.coffee
@@ -78,8 +78,9 @@
                 return TYPES[type_]
             throw "Unknown value type: `#{ type_ }`."

-        set_choice_doc: (args...) ->
-            choice_doc = _.copy @model.get 'choice_doc'
+        set_choice_doc: (args...) =>
+            choice_doc = _.clone @model.get 'choice_doc'
+            choice_doc ?= {}
             for name, parameter of @model.get 'parameters'
                 value = @get_input_value name
                 # XXX dont need to deduce type *here* if we've rendered the


code clean

code clean

--- spec/underscore.string.spec.coffee
+++ spec/underscore.string.spec.coffee
@@ -1,7 +1,4 @@
 Handlebars = require 'handlebars'
-fs = require 'fs'
-vm = require 'vm'
-path = require 'path'

 require '../src/handlebars-helpers-underscore.string'


Add bounty hunter mechanics to coffeeconomy.

--- src/coffee.coffee
+++ src/coffee.coffee
@@ -71,6 +71,10 @@
     robot.brain.data.coffee ?= {brewing: {}}
     brewing = robot.brain.data.coffee.brewing ?= {}

+  bounty = {
+    price: 0
+  }
+
   coffeeconomy = new Coffeeconomy robot

   robot.respond /coffee balance(?:\s+@?([^ ]+)\s*)?$/i, (msg) ->
@@ -115,6 +119,25 @@

     createBrew msg

+  robot.respond /coffee bounty(?:\s+(\d+))?$/i, (msg) ->
+    if isBrewing()
+      msg.send "A brew is already underway by (@#{brewing.barista})!" +
+          "#{statusEmoji.randim('failure')}\n" + freeSpots()
+
+    hunter = robot.brain.usersForFuzzyName(msg.message.user['name'])[0].name
+    proposedPrice = parseInt msg.match[1]?.trim() || 0
+
+    if bounty.price > 0 and proposedPrice > bounty.price
+      msg.send "@team #{hunter} has increased the bounty from #{bounty.price} to #{proposedPrice}."
+    else if bounty.price > 0 and proposedPrice <= bounty.price
+      msg.send "A bounty of #{bounty.price} by #{bounty.hunter} has already been put out. #{statusEmoji.random('failure')}"
+      return
+    else
+      msg.send "@team #{hunter} has put out a bounty of #{proposedPrice}."
+
+    bounty.price = proposedPrice
+    bounty.hunter = hunter
+
   robot.respond /(fresh[ -]?pot|fp)\s*$/i, (msg) ->
     return handleNoBrew msg if not isBrewing()

@@ -124,7 +147,9 @@
     return handleNoBrew msg if not isBrewing()

     dibber = robot.brain.usersForFuzzyName(msg.message.user['name'])[0].name
-
+    dibs(dibber)
+
+  dibs = (dibber) ->
     if dibber in brewing.dibs
       msg.send "Nice try @#{dibber}, you already grabbed a spot! #{statusEmoji.random('failure')}"
       return
@@ -160,12 +185,24 @@
       barista: barista
       dibs: [barista],
       messageMetadata: msg.envelope.message?.metadata,
+      brewing.bounty = bountyAmount,

     robot.brain.save()

-    msg.send "@team Brew started by @#{brewing.barista}! #{statusEmoji.random('success')}\n" +
-        "To grab a spot use: #{robot.alias}dibs\n" +
-        "To end the brew use: #{robot.alias}fresh pot"
+    if bounty.amount > 0 and barista is not bounty.hunter
+      msg.send "@team A bountied Brew has been started by @#{brewing.barista}! #{statusEmoji.random('success')}\n" +
+          "@#{brewing.barista} will get an extra #{bounty.amount} coffeeconomy points for this brew."
+          "To grab a spot use: #{robot.alias}dibs\n" +
+          "To end the brew use: #{robot.alias}fresh pot"
+
+      dibs(bounty.hunter)
+    if bounty.amount > 0 and barista is bounty.hunter
+      msg.send "Hey @{bounty.hunter} can't collect your own bounty! Your bounty has been cancelled."
+      bounty.amount = 0
+    else
+      msg.send "@team Brew started by @#{brewing.barista}! #{statusEmoji.random('success')}\n" +
+          "To grab a spot use: #{robot.alias}dibs\n" +
+          "To end the brew use: #{robot.alias}fresh pot"

   endBrew = (msg) ->
     teamNotify = brewing.dibs.length < dibsLimit
@@ -181,6 +218,12 @@

         if dibber == brewing.barista
           coffeeconomy.deposit client, dibsLimit - 1
+
+          if bounty.price > 0
+            coffeeconomy.deposit client, bounty.price
+
+            bountyHunter = robot.brain.userForName bounty.hunter
+            coffeeconomy.withdraw bountyHunter, bounty.price
         else
           coffeeconomy.withdraw client, 1


add new resources from June 9 2016

add new resources from June 9 2016

--- src/coffin.coffee
+++ src/coffin.coffee
@@ -73,6 +73,7 @@
         DHCPOptions: null
         EIP: null
         EIPAssociation: null
+        FlowLog: null
         Host: null
         Instance: null
         InternetGateway: null
@@ -144,6 +145,8 @@
         UserToGroupAddition: null
       Kinesis:
         Stream: null
+      KinesisFirehose:
+        DeliveryStream: null
       KMS:
         Key: null
       Logs:


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -112,8 +112,11 @@

   Color2:: =
     complement: ->
+      @copy().complement$()
+
+    complement$: ->
       hsl = @toHsl()
-      @hue(180)
+      @hue$(180)

     copy: ->
       Color2(@r, @g, @b, @a)


Targets should act as an override for the GITLAB_CHANNEL, appending targets to GITLAB_CHANNEL seems odd.  Plus the default value of #gitlab mucks things up with HipChat.

--- src/scripts/gitlab.coffee
+++ src/scripts/gitlab.coffee
@@ -54,7 +54,7 @@
       console.log('hook', hook)

     user = {}
-    user.room = if query.targets then gitlabChannel + ',' + query.targets else gitlabChannel
+    user.room = if query.targets then query.targets else gitlabChannel
     user.type = query.type if query.type

     switch type


Listen for "haters gonna hate"

Listen for "haters gonna hate"

--- src/scripts/haters.coffee
+++ src/scripts/haters.coffee
@@ -11,6 +11,12 @@
 , "http://24.media.tumblr.com/tumblr_lltwmdVpoL1qekprfo1_500.gif"
 , "http://s3.amazonaws.com/kym-assets/photos/images/newsfeed/000/087/536/1292102239519.gif"
 ]
+
+hatin = (msg) ->
+  msg.send msg.random haters
+
 module.exports = (robot) ->
   robot.respond /haters/i, (msg) ->
-    msg.send msg.random haters
+    hatin msg
+  robot.hear /haters gonna hate/i, (msg) ->
+    hatin msg


Track team domain form actions

Track team domain form actions

--- client/landing/site.landing/coffee/team/tabs/teamdomaintab.coffee
+++ client/landing/site.landing/coffee/team/tabs/teamdomaintab.coffee
@@ -20,8 +20,11 @@
     @form = new TeamDomainTabForm
       callback: (formData) =>

+        track 'submitted domain form'
+
         KD.utils.verifySlug formData.slug,
           success : =>
+            track 'entered a valid domain'
             @form.input.parent.unsetClass 'validation-error'
             KD.utils.storeNewTeamData name, formData
             # removed these steps
@@ -36,6 +39,7 @@

   showError: (error) ->

+    track 'entered an invalid domain'
     @form.input.parent.setClass 'validation-error'
     new KDNotificationView { title : error }

@@ -50,3 +54,11 @@
       {{> @form}}
     </div>
     """
+
+
+track = (action) ->
+
+  category = 'TeamSignup'
+  label    = 'DomainTab'
+
+  KD.utils.analytics.track action, { category, label }


fixed bug in config writing

fixed bug in config writing

--- csi.coffee
+++ csi.coffee
@@ -403,7 +403,7 @@
           requirejs.optimize
             baseUrl: argv.staticpath
             paths: pathsConfig()
-            shim: config.shim
+            shim: extend(true, {}, config.shim) # r.js optimizer modifies shim
             name: module.name
             optimize: "none"
             keepBuildDir: true


Bug fix. Needed to declade a volume to use bind mounts

--- src/application.coffee
+++ src/application.coffee
@@ -65,6 +65,8 @@
 		docker.createContainerAsync(
 			Image: app
 			Cmd: ['/bin/bash', '-c', '/start web']
+			Volumes:
+				'/dev/snd': {}
 		)
 	).then((container) ->
 		container.startAsync(


renamed services

renamed services

--- api/controllers/lastFMController.coffee
+++ api/controllers/lastFMController.coffee
@@ -20,6 +20,6 @@
     delete params.action
     delete params.method

-    lastFMService.api method, action, params, (err, response) ->
+    LastFMService.api method, action, params, (err, response) ->
       return res.badRequest(err) if err
       res.ok(response)


Better comment loading

Better comment loading

--- app/assets/javascripts/artifacts.coffee
+++ app/assets/javascripts/artifacts.coffee
@@ -168,11 +168,17 @@
   $('#show-comments').click (e) ->

     $('#comments').load('/comments_script.html', ->
-      $('#comments-load').hide()
-      $('html, body').animate
-        scrollTop: $("#comments").offset().top - 100
-      , 2000
-    ).hide().fadeIn(500);
+      setTimeout ->
+
+        $('#comments-load').hide()
+        $('#comments').show()
+
+        $('html, body').animate
+          scrollTop: $("#comments").offset().top - 100
+        , 2000
+
+      , 500
+    ).hide()

     $('#comments-load').show()


Improve FullCalendar JS : check if calendar is editable before doing something

--- app/assets/javascripts/events.js.coffee
+++ app/assets/javascripts/events.js.coffee
@@ -26,14 +26,15 @@
         FullCalendar.Events.resize(event, delta, revertFunc)

       eventClick: (event, jsEvent, view) ->
-        FullCalendar.Events.show(event)
+        FullCalendar.Events.show(event, view)

       select: (start, end, jsEvent, view) ->
-        FullCalendar.Form.display
-          start_time:  start
-          end_time:    end
-          allDay:      !start.hasTime() && !end.hasTime()
-          newEventUrl: view.options.newEventUrl
+        if view.options.editable
+          FullCalendar.Form.display
+            start_time:  start
+            end_time:    end
+            allDay:      !start.hasTime() && !end.hasTime()
+            newEventUrl: view.options.newEventUrl
     options

   Events:
@@ -65,8 +66,11 @@
       data = FullCalendar.Events.prepare_data(event, delta)
       FullCalendar.Events.send_request(url, data, revertFunc)

-    show: (event) ->
-      url = event.path + '/edit'
+    show: (event, view) ->
+      if view.options.editable
+        url = event.path + '/edit'
+      else
+        url = event.path
       $.get url, (data) ->
         $('#modal-holder').html(data).find('.modal').modal()


fixing image upload

fixing image upload

--- app/assets/javascripts/images.js.coffee
+++ app/assets/javascripts/images.js.coffee
@@ -5,8 +5,7 @@
       maxFilesize: 500
       paramName: 'image[image]'
       addRemoveLinks: true
-      uploadMultiple: true
-      enqueueForUpload: true
+      uploadMultiple: false
       clickable: true)

 $(document).ready(ready)


Remove AAC stream format support

Remove AAC stream format support

--- app/assets/javascripts/player.js.coffee
+++ app/assets/javascripts/player.js.coffee
@@ -82,7 +82,7 @@
         DEBUG('jPlayer: unmute')
         $self.jPlayer('mute', false)

-    supplied: 'oga, mp3, m4a'
+    supplied: 'oga, mp3'
     solution: 'html'
     swfPath: '/'
     preload: 'none'
@@ -98,7 +98,6 @@
     listen_path =
       oga: "/listen.opus?_=#{$.now()}"
       mp3: "/listen.mp3?_=#{$.now()}"
-      m4a: "/listen.aac?_=#{$.now()}"
     is_playing = $this.data('playing')

     $this.jPlayer('clearMedia')


add scripts

add scripts

--- app/assets/javascripts/static.js.coffee
+++ app/assets/javascripts/static.js.coffee
@@ -1,3 +1,3 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
+$(".topbar-toggle").click ->
+  $(".topbar-nav").toggleClass "topbar-toggle-hide"
+  return


Fix typo

Fix typo

--- src/batman.coffee
+++ src/batman.coffee
@@ -2673,7 +2673,7 @@

   # ### Record API

-  # Add a universally accessible accessor for retrieving the primrary key, regardless of which key its stored under.
+  # Add a universally accessible accessor for retrieving the primary key, regardless of which key its stored under.
   @accessor 'id',
     get: ->
       pk = @constructor.primaryKey


hide "all" in legend

hide "all" in legend

--- app/assets/javascripts/zvg/point.coffee
+++ app/assets/javascripts/zvg/point.coffee
@@ -262,7 +262,9 @@
     @series_2.exit().remove()

   legend_data: ->
-    ({ key: x, text: "#{x}" } for x in @series_2_domain().slice(0).reverse())
+    s2d = @series_2_domain()
+    return [] if s2d.length is 1 and s2d[0] is "all"
+    ({ key: x, text: "#{x}" } for x in s2d.slice(0).reverse())

   apply_legend_elements: (selection) ->
     colors = @series_2_colors


Improved CLI argument descriptions

Improved CLI argument descriptions

--- src/binary.coffee
+++ src/binary.coffee
@@ -9,10 +9,10 @@
   { name: 'bucket',  desc: "S3 bucket used as target for the upload" }
   { name: 'key',     desc: "AWS access key" }
   { name: 'secret',  desc: "AWS access secret" }
-  { name: 'region',  desc: "Files/folders to include in the upload", defaultValue: 'us-east-1' }
-  { name: 'index',   desc: "File to use as index for the site", defaultValue: 'index.html' }
-  { name: 'error',   desc: "File to use for error on the site" }
-  { name: 'dns',     desc: "The name of a bucketful plugin for setting up a cname for your domain" }
+  { name: 'region',  desc: "AWS region to create the bucket in", defaultValue: 'us-east-1' }
+  { name: 'index',   desc: "File to use as index page", defaultValue: 'index.html' }
+  { name: 'error',   desc: "File to use as error page" }
+  { name: 'dns',     desc: "The name of a bucketful plugin for setting up a CNAME for your domain" }
   { name: 'configs', desc: "The files from which to read configs", defaultValue: 'package.json;config.json' }
 ]


Now handling both dropdown and regular button for invoice creation via reception index

--- app/assets/javascripts/backend/purchase_process/purchase_orders.coffee
+++ app/assets/javascripts/backend/purchase_process/purchase_orders.coffee
@@ -3,22 +3,22 @@

   listControlledBtn =
     toggleNewInvoiceButton: () ->
-      $btn = $('#generate-invoice-btn').find('a')
-      url = $btn.prop('href')
-      @_bindInputs('reception', 'sender', $btn, url)
+      $btn = if $('#generate-invoice-btn button').length then $('#generate-invoice-btn button') else $('#generate-invoice-btn a')
+      linksUrls = $('#generate-invoice-btn a').map -> { element: $(this), url: $(this).prop('href') }
+      @_bindInputs('reception', 'sender', $btn, linksUrls)

     toggleNewReceptionButton: () ->
       $btn = $('#generate-parcel-btn')
-      url = $btn.prop('href')
-      @_bindInputs('purchase_order', 'supplier', $btn, url)
+      linksUrls = [{ element: $btn, url: $btn.prop('href') }]
+      @_bindInputs('purchase_order', 'supplier', $btn, linksUrls)

-    _bindInputs: (model, third, $btn, url) ->
+    _bindInputs: (model, third, $btn, linksUrls) ->
       $(document).on 'change', 'input[data-list-selector]', =>
         $selectedItems = @_getSelectedItems()
         selectedItemsIds = @_getSelectedItemsIds($selectedItems)
         $reconciledItems = @_getReconciledItems($selectedItems)
         sameThird = @_checkThirdUniqueness($selectedItems, third)
-        @_setBtnUrl(selectedItemsIds, $btn, model, url)
+        @_setBtnUrl(selectedItemsIds, $btn, model, linksUrls)
         @_setDisabledProp(model, $btn, $selectedItems, $reconciledItems, sameThird)

     _getSelectedItems: () ->
@@ -41,11 +41,14 @@

       _.uniq(_.compact(selectedItemsThirdIds)).length == 1

-    _setBtnUrl: (selectedItemsIds, $btn, model, url) ->
-      if selectedItemsIds.length > 0
-        $btn.prop('href', "#{url}?mode=prefilled&#{model}_ids=#{selectedItemsIds}")
-      else
-        $btn.prop('href', url)
+    _setBtnUrl: (selectedItemsIds, $btn, model, linksUrls) ->
+      urlSeparator = if $btn.hasClass('dropdown-toggle') then '&' else '?'
+
+      for linkUrl in linksUrls
+        if selectedItemsIds.length > 0
+          $(linkUrl.element).prop('href', "#{linkUrl.url}#{urlSeparator}mode=prefilled&#{model}_ids=#{selectedItemsIds}")
+        else
+          $(linkUrl.element).prop('href', linkUrl.url)

     _setDisabledProp: (model, $btn, $selectedItems, $reconciledItems, sameThird) ->
       disabled = if model == 'reception'


DevTools: Keep track of opened files and reopen them after reload if they are exists

--- client/DevTools/AppView.coffee
+++ client/DevTools/AppView.coffee
@@ -200,8 +200,27 @@
 class DevToolsEditorPane extends CollaborativeEditorPane

   constructor:(options = {}, data)->
+
     options.cssClass = 'devtools-editor'
     super options, data
+
+    @_mode   = "coffeescript"
+    @storage = KD.singletons.localStorageController.storage "DevTools"
+
+  loadLastOpenFile:->
+
+    path = @storage.getAt "lastFileOn#{@_mode}"
+    return  unless path
+
+    lastOpenFile = FSHelper.createFileFromPath path
+    lastOpenFile.fetchContents (err, content)=>
+      if err
+        KD.showError err, "Failed to load last open file: #{path}"
+      else
+        # Override the path to keep VM Info
+        lastOpenFile.path = path
+
+        @openFile lastOpenFile, content

   createEditor: (callback)->

@@ -219,7 +238,7 @@
           scrollPastEnd   : yes
           cursorHeight    : 1
           tabSize         : 2
-          mode            : @_mode ? "coffeescript"
+          mode            : @_mode
           extraKeys       :
             "Cmd-S"       : @bound "handleSave"
             "Ctrl-S"      : @bound "handleSave"
@@ -232,7 +251,10 @@
         callback?()

         @emit 'ready'
+        @loadLastOpenFile()
+
   openFile: (file, content)->
+    @storage.setValue "lastFileOn#{@_mode}", file.path
     super

     path = (FSHelper.plainPath file.path).replace \


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -39,9 +39,9 @@
       I.scroll.x.clamp(centerRect.left, centerRect.right)
       I.scroll.y.clamp(centerRect.top, centerRect.bottom)
     )
-
+
     I.scroll.x = I.scroll.x.clamp(I.cameraBounds.left, I.cameraBounds.right - I.screen.width)
-    I.scroll.y = I.scr
+    I.scroll.y = I.scroll.y.clamp(I.cameraBounds.top, I.cameraBounds.bottom - I.screen.height)

   followTypes =
     centered: (object) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -131,3 +131,5 @@
   self.include(Camera.Fade)

   return self
+
+gine.defaultModules = [


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -41,7 +41,7 @@
     )

     I.scroll.x = I.scroll.x.clamp(I.cameraBounds.left, I.cameraBounds.right - I.screen.width)
-    I.
+    I.scroll

   followTypes =
     centered: (object) ->


Do not call openRoom on all route requests, only if chatsubscription is closed.

--- client/routes/roomRoute.coffee
+++ client/routes/roomRoute.coffee
@@ -17,7 +17,7 @@
 			if type is 'd'
 				delete query.name
 				query.usernames =
-					$all: [name, Meteor.user().username]
+					$all: [name, Meteor.user()?.username]

 			room = ChatRoom.findOne(query)
 			if not room?
@@ -49,7 +49,8 @@
 				, 100

 			# update user's room subscription
-			Meteor.call 'openRoom', room._id
+			if ChatSubscription.findOne({rid: room._id})?.open is false
+				Meteor.call 'openRoom', room._id

 roomExit = ->
 	mainNode = document.querySelector('.main-content')


Fix URL issue

Fix URL issue

--- client/scripts/narcissa.coffee
+++ client/scripts/narcissa.coffee
@@ -51,7 +51,7 @@
   addictiveTracks: sprintf '
     SELECT COUNT(fp.url) AS plays, fp.date_uts AS date_uts,
       fp.artist_text AS artist_text, fp.name AS name,
-      fp.album_text AS album_text
+      fp.album_text AS album_text, fp.url AS url
       FROM
         (SELECT * FROM lastfm_tracks GROUP BY url ORDER BY date_uts) fp
     INNER JOIN lastfm_tracks ap ON