Reduce and regroup remainder of tip docs. :hocho:

--- src/js/jquery.hlf.tip.coffee
+++ src/js/jquery.hlf.tip.coffee
@@ -20,7 +20,7 @@
 # axis. For example, snapping to the x-axis will only allow the tip to shift
 # along the y-axis. The x will remain constant.

-# __UMD__
+# § __UMD__
 # - When AMD, register the attacher as an anonymous module.
 # - When Node or Browserify, set module exports to the attach result.
 # - When browser globals (root is window), Just run the attach function.
@@ -85,7 +85,7 @@
   # - __triggerContent__ can be the name of the trigger element's attribute or a
   #   function that provides custom content when given the trigger element.
   #
-  # - NOTE: For these tip plugins, the majority of presentation state logic is
+  # - Note: for these tip plugins, the majority of presentation state logic is
   #   in the plugin stylesheet. We update the presentation state by using
   #   namespaced __classNames__ generated in a closure.
   #
@@ -235,7 +235,7 @@
       @_processTriggers()
       @_bindTriggers()

-    # __Accessors__
+    # § __Accessors__

     # ___defaultHtml__ provides a basic html structure for tip content. It can be
     # customized via the `tipTemplate` external option, or by subclasses using
@@ -351,21 +351,28 @@
         size
       return wrapped()

-    # ### Appearance
-
-    # ƒ `wakeByTrigger` is the main toggler and a `_state` updater. The toggling and
-    # main changes only happen if the delay is passed. It will return a promise that
-    # fails if waking gets skipped; it also may become done synchronously.
+    # § __Appearance__
+
+    # __wakeByTrigger__ is the main toggler and a `_state` updater. The toggling
+    # and main changes only happen if the delay is passed. It returns a promise
+    # that fails if waking gets skipped, but async execution isn't guaranteed.
+    # It will:
+    # 1. Go directly to the position updating if no toggling is needed.
+    # 2. Not toggle if awake or waking, or if event isn't `truemouseenter`.
+    # 3. Declare a `wake` subroutine running the timed-out logic, which includes
+    #    the fade transition, and ensures other tips disappear during it.
+    # 4. Wake up depending on current state. If we are in the middle of sleeping,
+    #    stop sleeping by updating `_sleepCountdown` and wake up sooner.
+    #    Otherwise start the normal wakeup and update `_wakeCountdown`.
     wakeByTrigger: ($trigger, event) ->
       deferred = $.Deferred()
       promise = deferred.promise()
       @_setCurrentTrigger $trigger
-      #- Abstract into subroutine.
-      updateBeforeWake = =>
+
+      updateBeforeWake = => # Abstract into subroutine.
         @_positionToTrigger $trigger, event
         @onShow event # Hook in custom logic.

-      # - Go directly to the position updating if no toggling is needed.
       if @_state is 'awake'
         @debugLog 'quick update'
         updateBeforeWake()
@@ -373,13 +380,11 @@
         return promise

       @debugLog event.type if event? # Log the event if we made it this far.
-      # - Don't toggle if awake or waking, or if event isn't `truemouseenter`.
+
       if @_state in ['awake', 'waking']
         deferred.reject()
         return promise

-      # - Our `wake` subroutine runs the timed-out logic, which includes the fade
-      #   transition. Ensure other tips disappear during the transition.
       wake = (duration) =>
         updateBeforeWake() # Hook in custom logic.
         options = _.defaults { duration }, @animations.show
@@ -392,29 +397,25 @@
           options = _.defaults { duration }, @animation.hide
           @animator.hide $el, options

-      # - Wake up depending on current state. If we are in the middle of
-      #   sleeping, stop sleeping by updating `_sleepCountdown` and wake up
-      #   sooner.
       if @_state is 'sleeping'
         @debugLog 'clear sleep'
         clearTimeout @_sleepCountdown
         wake(0)
-      # - Start the normal wakeup and update `_wakeCountdown`.
+
       else if event? and event.type is 'truemouseenter'
         @_setState 'waking', { event }
         @_wakeCountdown = setTimeout wake, @animations.show.delay

       promise

-    # ƒ `sleepByTrigger` is a much simpler toggler compared to its counterpart
+    # __sleepByTrigger__ is a much simpler toggler compared to its counterpart
     # `wakeByTrigger`. It also updates `_state` and returns a promise that
     # fails if waking gets skipped. As long as the tip isn't truly visible, or
-    # sleeping is redundant, it bails.
+    # sleeping is redundant, or event isn't `truemouseleave`, it bails.
     sleepByTrigger: ($trigger, event) ->
       deferred = $.Deferred()
       promise = deferred.promise()

-      # - Don't toggle if asleep or sleeping, or if event isn't `truemouseleave`.
       if @_state in ['asleep', 'sleeping']
         deferred.reject()
         return promise
@@ -432,7 +433,7 @@

       promise

-    # ƒ `_togglePositionTransition` adds a position css transition to the tip.
+    # __togglePositionTransition__ adds a position css transition to the tip.
     # This normally is very expensive considering we update position on mousemove.
     # But it's used together with a test to see if the cursor is likely currently
     # in a gap between triggers. See `_setState` for details.
@@ -443,9 +444,9 @@
       else ''
       @$tip.css 'transition', transition

-    # ### Content
-
-    # ƒ `_saveTriggerContent` comes with a very simple base implementation that
+    # § __Content__
+
+    # ___saveTriggerContent__ comes with a very simple base implementation that
     # supports the common `title` and `alt` meta content for an element. Support
     # is also provided for the `triggerContent` option. We take that content and
     # store it into a namespaced `content` jQuery data value on the trigger.
@@ -468,9 +469,9 @@
       if content?
         $trigger.data @attr('content'), content

-    # ### Events
-
-    # ƒ `_bind` adds event handlers to `$tip` mostly, so state can be updated such
+    # § __Events__
+
+    # ___bind__ adds event handlers to `$tip` mostly, so state can be updated such
     # that the handlers on `_$currentTrigger` make an exception. So that cursor
     # leaving the trigger for the tip doesn't cause the tip to dismiss.
     #
@@ -488,11 +489,12 @@
           if @_$currentTrigger?
             @_$currentTrigger.data @attr('is-active'), no
             @sleepByTrigger @_$currentTrigger, event
+
       if @autoDirection is on
         $(window).resize _.debounce @_setBounds, 300

-    # ƒ `_bindContext` uses MutationObserver. If `doLiveUpdate` is inferred to be
-    # true, process triggers added in the future. Make sure to ignore mutations
+    # ___bindContext__ uses `MutationObserver`. If `doLiveUpdate` is inferred to
+    # be true, process triggers added in the future. Make sure to ignore mutations
     # related to the tip.
     _bindContext: ->
       return false unless window.MutationObserver?
@@ -510,7 +512,7 @@
         childList: yes
         subtree: yes

-    # ƒ `_bindTriggers` links each trigger to the tip for:
+    # ___bindTriggers__ links each trigger to the tip for:
     # 1. Possible appearance changes during mouseenter, mouseleave (uses special
     #    events).
     # 2. Following on mousemove only if `doFollow` is on.
@@ -541,12 +543,12 @@
           onMouseMove = _.throttle @_onTriggerMouseMove, 16
         @$context.on 'mousemove', selector, onMouseMove

-    # ### Positioning
-
-    # ƒ `_onTriggerMouseMove` is actually the main tip toggling handler. To
-    # explain, first we take into account of child elements triggering the mouse
-    # event by deducing the event's actual `$trigger` element. Then we
-    # `wakeByTrigger` if needed.
+    # § __Positioning__
+
+    # ___onTriggerMouseMove__ is actually the main tip toggling handler. To
+    # explain, first account for the child elements triggering the mouse event
+    # by deducing the event's actual `$trigger` element. Then `wakeByTrigger`
+    # if needed.
     _onTriggerMouseMove: (event) ->
       return no if not event.pageX?

@@ -557,7 +559,7 @@

       @wakeByTrigger $trigger, event

-    # ƒ `_positionToTrigger` will properly update the tip offset per
+    # ___positionToTrigger__ will properly update the tip offset per
     # `offsetOnTriggerMouseMove` and `_isDirection`. Also note that `_stemSize`
     # gets factored in.
     _positionToTrigger: ($trigger, mouseEvent, cursorHeight=@cursorHeight) ->
@@ -584,7 +586,7 @@

       @$tip.css css

-    # ƒ `_setBounds` updates `_bounds` per `$viewport`'s inner bounds, and those
+    # ___setBounds__ updates `_bounds` per `$viewport`'s inner bounds, and those
     # measures get used by `_updateDirectionByTrigger`.
     _setBounds: ->
       $viewport = if @$viewport.is('body') then $(window) else @$viewport
@@ -594,17 +596,17 @@
         bottom: $viewport.innerHeight()
         right:  $viewport.innerWidth()

-    # ### Rendering
-
-    # ƒ `_inflateByTrigger` will reset and update `$tip` and its content element for the given trigger, so
-    # that it is ready to present, ie. it is 'inflated'. If the `resize` animation
-    # is desired, we need to also specify the content element's dimensions for
-    # respective transitions to take effect.
+    # § __Rendering__
+
+    # ___inflateByTrigger__ will reset and update `$tip` and its content element
+    # for the given trigger, so it is ready to present, ie. it is 'inflated'. If
+    # the `resize` animation is on, also specify the content element's dimension
+    # for respective transitions to take effect.
     _inflateByTrigger: ($trigger) ->
       $content = @selectByClass 'content'
       $content.text $trigger.data @attr('content')

-      #- NOTE: A transition style is in place, so this causes animation.
+      #- Note that a transition style is in place, so this causes animation.
       if @animations.resize.enabled
         contentSize = @_sizeForTrigger $trigger, (contentOnly = yes)
         $content
@@ -623,7 +625,7 @@
           , ''
         )

-    # ƒ `_render` comes with a base implementation that fills in and attaches
+    # ___render__ comes with a base implementation that fills in and attaches
     # `$tip` to the DOM, specifically at the beginning of `$viewport`. It uses
     # the result of `htmlOnRender` and falls back to that of `_defaultHtml`.
     # Render also sets up any animations per the `shouldAnimate` option.
@@ -643,9 +645,9 @@
       @selectByClass('content').css 'transition', transitionStyle.join(',')
       @$tip.prependTo @$viewport

-    # ### Subroutines
-
-    # ƒ `_processTriggers` does just that and sets up content, event, and
+    # § __Subroutines__
+
+    # ___processTriggers__ does just that and sets up content, event, and
     # positioning aspects.
     _processTriggers: ($triggers) ->
       $triggers ?= @$triggers
@@ -656,10 +658,10 @@
         @_saveTriggerContent $trigger
         @_updateDirectionByTrigger $trigger

-    # ƒ `_updateDirectionByTrigger` is the main provider of auto-direction
+    # ___updateDirectionByTrigger__ is the main provider of auto-direction
     # support. Given the `$viewport`'s `_bounds`, it changes to the best
-    # direction as needed. The current `direction` is stored as jQuery data with
-    # trigger.
+    # direction as needed. The current `direction` is stored as jQuery data on
+    # the trigger.
     _updateDirectionByTrigger: ($trigger) ->
       return no if @autoDirection is off
       triggerOffset   = @_offsetForTrigger $trigger
@@ -685,7 +687,7 @@
             when 'left'   then newDirection[1] = 'right'
           $trigger.data @attr('direction'), newDirection.join ' '

-    # ƒ `_wrapStealthRender` is a helper mostly for size detection on tips and
+    # ___wrapStealthRender__ is a helper mostly for size detection on tips and
     # triggers. Without stealth rendering the elements by temporarily un-hiding
     # and making invisible, we can't do `getComputedStyle` on them.
     _wrapStealthRender: (func) ->
@@ -696,7 +698,7 @@
         @$tip.css { display: 'none', visibility: 'visible' }
         return result

-    # ### Delegation to Subclass
+    # § __Delegation to Subclass__

     # These methods are hooks for custom functionality from subclasses. (Some are
     # set to no-ops becase they are given no arguments.)
@@ -707,26 +709,26 @@
     htmlOnRender: $.noop
     offsetOnTriggerMouseMove: (event, offset, $trigger) -> no

-  # SnapTip Implementation
-  # ----------------------
+  # SnapTip
+  # -------
   # With such a complete base API, extending it with an implementation with
   # snapping becomes almost trivial.
   class SnapTip extends Tip

-    # ƒ `init` continues setting up `$tip` and other properties.
+    # __init__ continues setting up `$tip` and other properties.
+    # 1. Infer `snap.toTrigger`.
+    # 2. `_offsetStart` stores the original offset, which is used for snapping.
+    # 3. Add snapping config as classes.
     init: ->
       super()
-      # - Infer `snap.toTrigger`.
       if @snap.toTrigger is off
         @snap.toTrigger = @snap.toXAxis is on or @snap.toYAxis is on
-      # - `_offsetStart` stores the original offset, which is used for snapping.
       @_offsetStart = null
-      # - Add snapping config as classes.
       @$tip.addClass(@classNames.snap[key]) for own key, active of @snap when active

-    # ### Events
-
-    # ƒ `_bindTriggers` extend its super to get initial position for snapping.
+    # § __Events__
+
+    # ___bindTriggers__ extend its super to get initial position for snapping.
     # This is only for snapping without snapping to the trigger, which is only
     # what's currently supported. See `afterShow` hook.
     _bindTriggers: ->
@@ -736,9 +738,9 @@
       @$context.on @evt('truemouseleave'), selector, { selector },
         (event) => @_offsetStart = null

-    # ### Positioning
-
-    # ƒ `_moveToTrigger` is the main positioner. The `baseOffset` given is
+    # § __Positioning__
+
+    # ___moveToTrigger__ is the main positioner. The `baseOffset` given is
     # expected to be the trigger offset.
     _moveToTrigger: ($trigger, baseOffset) -> # TODO: Still needs to support all the directions.
       #- @debugLog baseOffset
@@ -763,14 +765,14 @@
           offset.top += $trigger.outerHeight()
       offset

-    # ƒ `_positionToTrigger` extends its super to set `cursorHeight` to 0, since
+    # ___positionToTrigger__ extends its super to set `cursorHeight` to 0, since
     # it won't need to be factored in if we're snapping.
     _positionToTrigger: ($trigger, mouseEvent, cursorHeight=@cursorHeight) ->
       super $trigger, mouseEvent, 0

-    # ### Tip Delegation
-
-    # ƒ Implement `onShow` and `afterShow` delegate methods such that they make
+    # § __Tip Delegation__
+
+    # Implement __onShow__ and __afterShow__ delegate methods such that they make
     # the tip invisible while it's being positioned and then reveal it.
     onShow: (event) ->
       return unless @_triggerChanged is yes
@@ -781,17 +783,15 @@
       @$tip.css 'visibility', 'visible'
       @_offsetStart = { top: event.pageY, left: event.pageX }

-    # ƒ Implement `offsetOnTriggerMouseMove` delegate method as the main snapping
+    # Implement __offsetOnTriggerMouseMove__ delegate method as the main snapping
     # positioning handler. Instead of returning false, we return our custom,
     # snapping offset, so it gets used in lieu of the base `offset`.
     offsetOnTriggerMouseMove: (event, offset, $trigger) ->
       newOffset = @_moveToTrigger $trigger, _.clone(offset)

-  # §
-
-  # Export
-  # ------
-  # Both are exported with the `asSharedInstance` flag set to true.
+  # § __Attaching__
+
+  # Both plugins are created and attached with the `asSharedInstance` flag on.
   hlf.createPlugin
     name: 'tip'
     namespace: hlf.tip


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -3,10 +3,11 @@
     @accessor 'data'

     #constructor: ->
-    #ready: ->
-        #@oldPieData = ''
+    ready: ->
+        @testData = 123

     onData: (data) ->
+        console.log('testData',@testData)

         #$(@node).fadeOut().fadeIn()
         @container = $(@node).parent()


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -139,16 +139,16 @@
     update: (data) ->
         console.log("update pie", data);

-        var that = this;
+        that = this;

         this.piedata = this.pie(data);

         //create a marker element if it doesn't already exist
-        var defs = this.svg.select("defs");
+        defs = this.svg.select("defs");
         if (defs.empty() ) {
             defs = this.svg.append("defs");
         }
-        var marker = defs.select("marker#circ");
+        marker = defs.select("marker#circ");
         if (marker.empty() ) {
             defs.append("marker")
             .attr("id", "circ")
@@ -163,17 +163,17 @@
         }
         //Create/select <g> elements to hold the different types of graphics
         //and keep them in the correct drawing order
-        var pathGroup = this.svg.select("g.piePaths");
+        pathGroup = this.svg.select("g.piePaths");
         if (pathGroup.empty() ){
             pathGroup = this.svg.append("g")
                        .attr("class", "piePaths");
         }
-        var pointerGroup = this.svg.select("g.pointers")
+        pointerGroup = this.svg.select("g.pointers")
         if (pointerGroup.empty() ) {
             pointerGroup = this.svg.append("g")
                            .attr("class", "pointers");
         }
-        var labelGroup = this.svg.select("g.labels")
+        labelGroup = this.svg.select("g.labels")
         if (labelGroup.empty() ) {
             labelGroup = this.svg.append("g")
                          .attr("class", "labels");
@@ -198,7 +198,7 @@
 #            .attrTween("d", that.removePieTween)
 #            .remove();

-        var labels = labelGroup.selectAll("text")
+        labels = labelGroup.selectAll("text")
             .data(this.piedata
                 .sort((p1,p2) ->
                     return p1.startAngle - p2.startAngle;
@@ -211,38 +211,38 @@
             .remove();

-        var labelLayout = d3.geom.quadtree()
+        labelLayout = d3.geom.quadtree()
             .extent([[-that.width,-that.height], [that.width, that.height] ])
             .x((d) -> return d.x;)
             .y((d) -> return d.y;)
-            ([]); //create an empty quadtree to hold label positions
-        var maxLabelWidth = 0;
-        var maxLabelHeight = 0;
+            ([]); #create an empty quadtree to hold label positions
+        maxLabelWidth = 0;
+        maxLabelHeight = 0;

         labels.text((d) ->
-            // Set the text *first*, so we can query the size
-            // of the label with .getBBox()
+            # Set the text *first*, so we can query the size
+            # of the label with .getBBox()
             return d.value;
         )
         .each((d, i) ->
-            // Move all calculations into the each function.
-            // Position values are stored in the data object
-            // so can be accessed later when drawing the line
-
-            /* calculate the position of the center marker */
-            var a = (d.startAngle + d.endAngle) / 2 ;
-
-            //trig functions adjusted to use the angle relative
-            //to the "12 o'clock" vector:
+            # Move all calculations into the each function.
+            # Position values are stored in the data object
+            # so can be accessed later when drawing the line
+
+            # calculate the position of the center marker
+            a = (d.startAngle + d.endAngle) / 2 ;
+
+            #trig functions adjusted to use the angle relative
+            #to the "12 o'clock" vector:
             d.cx = Math.sin(a) * (that.radius - 75);
             d.cy = -Math.cos(a) * (that.radius - 75);

-            /* calculate the default position for the label,
-               so that the middle of the label is centered in the arc*/
-            var bbox = this.getBBox();
-            //bbox.width and bbox.height will
-            //describe the size of the label text
-            var labelRadius = that.radius - 20;
+            # calculate the default position for the label,
+            #   so that the middle of the label is centered in the arc
+            bbox = this.getBBox();
+            #bbox.width and bbox.height will
+            #describe the size of the label text
+            labelRadius = that.radius - 20;
             d.x =  Math.sin(a) * (labelRadius);
             d.l = d.x - bbox.width / 2 - 2;
             d.r = d.x + bbox.width / 2 + 2;
@@ -250,30 +250,30 @@
             d.b = d.oy = d.y + 5;
             d.t = d.y - bbox.height - 5 ;

-            /* check whether the default position
-               overlaps any other labels*/
-            var conflicts = [];
+            # check whether the default position
+            #   overlaps any other labels
+            conflicts = [];
             labelLayout.visit((node, x1, y1, x2, y2) ->
-                //recurse down the tree, adding any overlapping
-                //node is the node in the quadtree,
-                //node.point is the value that we added to the tree
-                //x1,y1,x2,y2 are the bounds of the rectangle that
-                //this node covers
+                #recurse down the tree, adding any overlapping
+                #node is the node in the quadtree,
+                #node.point is the value that we added to the tree
+                #x1,y1,x2,y2 are the bounds of the rectangle that
+                #this node covers

                 if (  (x1 > d.r + maxLabelWidth/2)
-                        //left edge of node is to the right of right edge of label
+                        #left edge of node is to the right of right edge of label
                     ||(x2 < d.l - maxLabelWidth/2)
-                        //right edge of node is to the left of left edge of label
+                        #right edge of node is to the left of left edge of label
                     ||(y1 > d.b + maxLabelHeight/2)
-                        //top (minY) edge of node is greater than the bottom of label
+                        #top (minY) edge of node is greater than the bottom of label
                     ||(y2 < d.t - maxLabelHeight/2 ) )
-                        //bottom (maxY) edge of node is less than the top of label
+                        #bottom (maxY) edge of node is less than the top of label

-                      return true; //don't bother visiting children or checking this node
+                      return true; #don't bother visiting children or checking this node

-                var p = node.point;
-                var v = false, h = false;
-                if ( p ) { //p is defined, i.e., there is a value stored in this node
+                p = node.point;
+                v = false, h = false;
+                if ( p ) { #p is defined, i.e., there is a value stored in this node
                     h =  ( ((p.l > d.l) && (p.l <= d.r))
                        || ((p.r > d.l) && (p.r <= d.r))
                        || ((p.l < d.l)&&(p.r >=d.r) ) ); //horizontal conflict
@@ -290,7 +290,7 @@

             if (conflicts.length) {
                 console.log(d, " conflicts with ", conflicts);
-                var rightEdge = d3.max(conflicts, (d2) ->
+                rightEdge = d3.max(conflicts, (d2) ->
                     return d2.r;
                 );

@@ -300,11 +300,11 @@
             }
             else console.log("no conflicts for ", d);

-            /* add this label to the quadtree, so it will show up as a conflict
-               for future labels.  */
+            # add this label to the quadtree, so it will show up as a conflict
+            #   for future labels.
             labelLayout.add( d );
-            var maxLabelWidth = Math.max(maxLabelWidth, bbox.width+10);
-            var maxLabelHeight = Math.max(maxLabelHeight, bbox.height+10);
+            maxLabelWidth = Math.max(maxLabelWidth, bbox.width+10);
+            maxLabelHeight = Math.max(maxLabelHeight, bbox.height+10);
         )
         #.transition()//we can use transitions now!
         .attr("x", (d) ->
@@ -315,7 +315,7 @@
                 );

-        var pointers = pointerGroup.selectAll("path.pointer")
+        pointers = pointerGroup.selectAll("path.pointer")
             .data(this.piedata);
         pointers.enter()
             .append("path")


Only show pp if score has weight attribute

--- resources/assets/coffee/react/_components/play-detail.coffee
+++ resources/assets/coffee/react/_components/play-detail.coffee
@@ -63,7 +63,7 @@
             className: 'detail-row__detail-row detail-row__detail-row--main'
             span
               className: 'detail-row__text-score detail-row__text-score--pp'
-              if score.pp
+              if score.weight
                 osu.trans('users.show.extra.top_ranks.pp', amount: Math.round(score.pp))
               else
                 score.score.toLocaleString()


don't increase rate limit when tasks are failing

--- services/document-updater/app/coffee/RateLimitManager.coffee
+++ services/document-updater/app/coffee/RateLimitManager.coffee
@@ -34,5 +34,6 @@
 				@_adjustLimitDown()
 		else
 			logger.log {active: @ActiveWorkerCount, currentLimit: Math.ceil(@CurrentWorkerLimit)}, "hit rate limit"
-			@_trackAndRun task, callback # only return after task completes
-			@_adjustLimitUp()
+			@_trackAndRun task, (err) =>
+				@_adjustLimitUp() if !err? # don't increment rate limit if there was an error
+				callback(err) # only return after task completes


Minor cleanup for pod controller

Minor cleanup for pod controller

--- static/coffee/controllers.coffee
+++ static/coffee/controllers.coffee
@@ -838,20 +838,21 @@
     PodApi.trigger($scope.podId, $scope.caseId, type, payload)
       .then((res) -> triggerDone(type, res))

-  $scope.onTriggerFailure = (payload) ->
-    # TODO show failure message
-
-  $scope.onTriggerSuccess = () ->
-    # TODO update notes
-    $scope.update()
-
   triggerDone = (type, {success, payload}) ->
     if success
-      $scope.onTriggerSuccess()
+      onTriggerSuccess()
     else
-      $scope.onTriggerFailure(payload)
+      onTriggerFailure(payload)

     $scope.podData.actions = updateAction(type, {isBusy: false})
+
+  onTriggerFailure = (payload) ->
+    $scope.$emit('podActionFailure', payload)
+    # TODO show failure message
+
+  onTriggerSuccess = () ->
+    $scope.$emit('podActionSuccess')
+    $scope.update()

   updateAction = (type, props) ->
     $scope.podData.actions
@@ -868,12 +869,11 @@

     d

-  parsePodAction = ({type, name, busy_text, payload}) ->
-    {
-      type,
-      name,
-      payload,
-      busyText: busy_text ? name,
-      isBusy: false
-    }
-])
+  parsePodAction = ({type, name, busy_text, payload}) -> {
+    type,
+    name,
+    payload,
+    busyText: busy_text ? name,
+    isBusy: false
+  }
+])


removing old phantom-bridge

removing old phantom-bridge

--- cli/src/crawler/phantom.coffee
+++ cli/src/crawler/phantom.coffee
@@ -1,12 +0,0 @@
-fs = require 'fs'
-page = require('webpage').create()
-url = phantom.args[ 0 ]
-
-page.open url, ->
-	setInterval ->
-		return unless (page.evaluate ->
-			return window && window.crawler && window.crawler.is_rendered
-		)
-		console.log page.content
-		phantom.exit()
-	, 30


code clean up

code clean up

--- client/app/views/market.coffee
+++ client/app/views/market.coffee
@@ -132,8 +132,11 @@

         slug = slugify(name)

-        out = git:(proto+domain+path+'.git'), name:name, slug:slug
-        out.branch = branch.substring(1) if branch?
+        git = proto + domain + path + '.git'
+        branch = branch.substring(1) if branch?
+
+        out = git:git, name:name, slug:slug
+        out.branch = branch if branch?
         return out

     # Display message inside info box.


working on fix for Plaza

working on fix for Plaza

--- gameState.coffee
+++ gameState.coffee
@@ -1232,8 +1232,7 @@
     while discarded.length < num
       # In `allowDiscard`, valid discards are the entire hand, plus `null`
       # to stop discarding.
-      validDiscards = ( card for card in player.hand when typeFunc(card) ).slice(0)
-      this.log("Valid: #{validDiscards}")
+      validDiscards = ( card for card in player.hand when typeFunc(card?) ).slice(0)
       validDiscards.push(null)
       choice = player.ai.chooseDiscard(this, validDiscards)
       return discarded if choice is null
@@ -1246,8 +1245,8 @@
   requireDiscard: (player, num, typeFunc = (card) -> true) ->
     discarded = []
     while discarded.length < num
-      this.log("#{player.hand}")
-      validDiscards = ( card for card in player.hand when typeFunc(card?) ).slice(0)
+      validDiscards = ( card for card in player.hand when typeFunc(card) ).slice(0)
+      this.log("Valid: #{validDiscards}")
       return discarded if validDiscards.length == 0
       choice = player.ai.chooseDiscard(this, validDiscards)
       discarded.push(choice)


Prevent room to finish render after change to another room

--- client/routes/roomRoute.coffee
+++ client/routes/roomRoute.coffee
@@ -1,12 +1,15 @@
+currentTracker = undefined
+
 openRoom = (type, name) ->
 	Session.set 'openedRoom', null

 	Meteor.defer ->
-		Tracker.autorun (c) ->
+		currentTracker = Tracker.autorun (c) ->
 			if RoomManager.open(type + name).ready() isnt true
 				BlazeLayout.render 'main', {center: 'loading'}
 				return

+			currentTracker = undefined
 			c.stop()

 			query =
@@ -61,6 +64,9 @@
 roomExit = ->
 	BlazeLayout.render 'main', {center: 'none'}

+	if currentTracker?
+		currentTracker.stop()
+
 	mainNode = document.querySelector('.main-content')
 	if mainNode?
 		for child in mainNode.children


Adds events to trashed.itemview

Adds events to trashed.itemview

--- app/assets/javascripts/backbone/apps/trashed/list/list_view.js.coffee
+++ app/assets/javascripts/backbone/apps/trashed/list/list_view.js.coffee
@@ -3,6 +3,20 @@
   class List.TrashedView extends Marionette.ItemView
     template: 'trashed/list/templates/_trashedmovie'
     tagName: 'tr'
+    events:
+      'click .remove-btn'  : 'untrash'
+      'mouseenter'         : 'showOverlay'
+      'mouseleave'         : 'hideOverlay'
+
+    untrash: ->
+      this.model.set(trashed: false).save()
+
+    showOverlay: ->
+      this.$el.find('.overlay').fadeIn(500)
+
+    hideOverlay: ->
+      this.$el.find('.overlay').fadeOut(500)
+

   class List.TrashedListCollection extends Marionette.CompositeView
     template: 'trashed/list/templates/_trashedmovies'


passing spec for eating items in continue-wrapped branches within all

--- spec/Thenable.coffee
+++ spec/Thenable.coffee
@@ -532,6 +532,20 @@
           done()

     describe "eating items in branches within all", ->
+
+      test = (brancher, done) ->
+        initialData =
+          items: [
+            { id: 1 }
+            { id: 2 }
+          ]
+        t = Root()
+        .deliver initialData
+        .all [brancher]
+        .finally (choice, data) ->
+          chai.expect(choice.availableItems()).to.not.be.empty
+          done()
+
       it 'should resolve', (done) ->
         brancher = (choice, data) ->
           choice.tree()
@@ -545,19 +559,29 @@
               item = choice.getItem -> true
               choice.eatItem item
               data
-
-        initialData =
-          items: [
-            { id: 1 }
-            { id: 2 }
-          ]
-
-        t = Root()
-        .deliver initialData
-        .all [brancher]
-        .finally (choice, data) ->
-          chai.expect(choice.availableItems()).to.not.be.empty
-          done()
+        test brancher, done
+
+      it 'with continue wraps should resolve', (done) ->
+        brancher = (choice, data) ->
+          choice.tree()
+          .deliver data
+          .then (c, data) ->
+            c.continue()
+            .deliver(data)
+            .then (c, data) ->
+              c.continue()
+              .deliver(data)
+              .then (choice, data) ->
+                choice.branch 'a', (choice, data) ->
+                  item = choice.getItem -> true
+                  choice.eatItem item
+                  data
+                choice.branch 'b', (choice, data) ->
+                  item = choice.getItem -> true
+                  choice.eatItem item
+                  data
+        test brancher, done
+

     describe 'with all & return values', ->


Add spec for MenuItem.click.

Add spec for MenuItem.click.

--- spec/api/menu.coffee
+++ spec/api/menu.coffee
@@ -23,3 +23,15 @@
       assert.equal menu.items[1].label, 'inserted'
       assert.equal menu.items[2].label, '2'
       assert.equal menu.items[3].label, '3'
+
+  describe 'MenuItem.click', ->
+    it 'should be called with the item object passed', (done) ->
+      menu = new Menu
+      menuItem = new MenuItem
+        label: 'text'
+        click: (item) ->
+          assert.equal item.constructor.name, 'MenuItem'
+          assert.equal item.label, 'text'
+          done()
+      menu.append menuItem
+      menu.delegate.executeCommand menuItem.commandId


Fixed KDBlockingModalView.

Fixed KDBlockingModalView.

--- components/modals/KDBlockingModalView.coffee
+++ components/modals/KDBlockingModalView.coffee
@@ -4,8 +4,7 @@
     $(window).off "keydown.modal"

   putOverlay:()->
-    @$overlay = $("<div/>")
-      class : "kdoverlay"
+    @$overlay = $("<div/>", class : "kdoverlay")
     @$overlay.hide()
     @$overlay.appendTo "body"
     @$overlay.fadeIn 200


Don't throw if JOIN parent couldn't be found

We shouldn't worry about that in _buildJoinPredicate() because we may be
called again for this same JOIN after more sources have been added.
However, we should do a check in deductJoinPredicates() before returning

--- src/dialects/sql-formatter.coffee
+++ src/dialects/sql-formatter.coffee
@@ -243,10 +243,12 @@

     _deductJoinPredicates: ->
         cnt = 1
-        while cnt == null || cnt > 0
+        while cnt > 0
             cnt = 0
             for j in @sources when j instanceof SqlJoin && j.predicate == null
                 cnt++ if @_buildJoinPredicate(j)
+
+        # SHOULD: throw if there are still unresolved JOINS
         return

     _buildJoinPredicate: (j) ->
@@ -263,9 +265,7 @@
                     s._model == fk.parentTable && (s instanceof SqlFrom || s.predicate?)

-        if (candidates.length == 0)
-            msg = "Can't find suitable parent to adopt #{j}"
-            throw new Error(msg)
+        return false if (candidates.length == 0)

         # SHOULD: get smarter about picking which PK to use
         pk = candidates[0]


When message is numerical, the call replace on message will cause a TypeError

--- vendor/assets/javascripts/twitter/bootstrap/rails/confirm.coffee
+++ vendor/assets/javascripts/twitter/bootstrap/rails/confirm.coffee
@@ -29,7 +29,7 @@
     .end()

     .find(".modal-body")
-      .html(message.replace(/\n/g, "
"))
+      .html(message.toString().replace(/\n/g, "
"))
     .end()

     .find(".modal-footer")


made sure selects have dropdownmenus with their min width, submenus can have any size. see #35157

--- src/elements/Button/Button.coffee
+++ src/elements/Button/Button.coffee
@@ -181,8 +181,7 @@
 			@__menu_opts.element = @

 			if not @__menu_opts.hasOwnProperty("use_element_width_as_min_width")
-				#submenus should always have the size of their parentmenus
-				if @_menu_parent
+				if not @_menu_parent
 					@__menu_opts.use_element_width_as_min_width = true

 			@__menu_opts.onHide = =>


update the package selection once a node data is fetched

Signed-off-by: Dominik Richter <b7323add517e187efe0283b76511b7ed762bfe13@gmail.com>

--- coffee/controllers/main.coffee
+++ coffee/controllers/main.coffee
@@ -62,6 +62,7 @@
           console.log 'fetch node '+id
           n.id = id
           $scope.node[id] = n
+          $scope.updatePackageSelection()
         , fetchError('node')

     $scope.fetchPackage = (id)->


slower graph to show some curvature

slower graph to show some curvature

--- web_modules/accumulator/view.cjsx
+++ web_modules/accumulator/view.cjsx
@@ -16,10 +16,10 @@
             accumulator: new Accumulator()
             value: 0
             chartData: {
-                labels: [0,0,0,0,0,0,0,0,0,0]
+                labels: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
                 datasets: [
                     label: "Value"
-                    data: [0,0,0,0,0,0,0,0,0,0]
+                    data: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
                 ]
             }
         }
@@ -43,10 +43,12 @@
             t = (t_1 - @accumulator.t_0) / @accumulator.scale
             value = Math.floor(@accumulator.evaluateAtTime(t_1))
             chartData = @state.chartData
-            chartData.datasets[0].data.shift()
-            chartData.datasets[0].data.push(value)
-            chartData.labels.shift()
-            chartData.labels.push(t_1)
+            @frame ?= 0
+            if @frame++ % 16 is 0
+                chartData.datasets[0].data.shift()
+                chartData.datasets[0].data.push(value)
+                chartData.labels.shift()
+                chartData.labels.push(t_1)
             @setState({
                 accumulator: @accumulator
                 t_1: t_1


inlined brain resets for lobby object changes

--- src/commands/admin.coffee
+++ src/commands/admin.coffee
@@ -104,7 +104,7 @@

       if type in ['cp', 'ctf', 'koth']
         random = msg.random(@brain.get("tflobby.maps.#{type}"))
-        lobby.set('map', random)
+        @brain.set('tflobby.lobby', lobby.set('map', random))
         return msg.reply(":: changed map to `#{random}`...")

       return msg.reply(":: invalid map type `#{type}`...")
@@ -112,9 +112,7 @@
     filtered = maps.filter (map) -> map.indexOf(msg.match[1]) isnt -1

     if filtered.length is 1
-
-      lobby.set('map', filtered[0])
-      @brain.set('tflobby.lobby', lobby)
+      @brain.set('tflobby.lobby', lobby.set('map', filtered[0]))
       return msg.reply(":: changing map to `#{filtered[0]}`...")

     return msg.reply(":: which map did you mean? #{filtered.join(', ')}...")
@@ -132,8 +130,10 @@
     server = msg.match[1].toLowerCase()

     if server in @brain.get('tflobby.servers.names')
-      lobby.set('server', @brain.get('tflobby.servers.all')[server])
-      robot.brain.set('tflobby.lobby', lobby)
+      robot.brain.set(
+        'tflobby.lobby',
+        lobby.set('server', @brain.get('tflobby.servers.all')[server])
+      )
       return msg.reply(":: server changed to `#{server}`...")

     return msg.reply(":: unknown server `#{server}`...")


fix(layout): don't render the menu content if the menu is closed

--- src/components/App.coffee
+++ src/components/App.coffee
@@ -194,26 +194,28 @@
               (if rightPanelIsOpen then "" else "Menu"),
                 i className: "fa fa-#{if rightPanelIsOpen then 'times' else 'bars'}"

-          div className: "logo"
-
-          div null,
-            React.createElement Menu,
-              info:
-                label   : " Info"
-                active  : view.right is V.INFO
-                onClick : ->
-                  dispatch Actions.showInfo()
-                  dispatch Actions.getServerInfo()
-              imprint:
-                label   : " Impressum"
-                active  : view.right is V.IMPRINT
-                onClick : -> dispatch Actions.showImprint()
-          div className: "content",
-            switch view.right
-              when V.INFO
-                React.createElement Info,
-                  clientVersion: pkg.version
-                  serverVersion: @props.server.version
-
-              when V.IMPRINT
-                React.createElement Imprint
+          if rightPanelIsOpen
+            div null,
+              div className: "logo"
+
+              div null,
+                React.createElement Menu,
+                  info:
+                    label   : " Info"
+                    active  : view.right is V.INFO
+                    onClick : ->
+                      dispatch Actions.showInfo()
+                      dispatch Actions.getServerInfo()
+                  imprint:
+                    label   : " Impressum"
+                    active  : view.right is V.IMPRINT
+                    onClick : -> dispatch Actions.showImprint()
+              div className: "content",
+                switch view.right
+                  when V.INFO
+                    React.createElement Info,
+                      clientVersion: pkg.version
+                      serverVersion: @props.server.version
+
+                  when V.IMPRINT
+                    React.createElement Imprint


change config for brunch

change config for brunch

--- brunch-config.coffee
+++ brunch-config.coffee
@@ -2,20 +2,23 @@
 exports.config =
   paths:
     'public': 'web'
-    'watched': [ 'app/Resources' ]
+    'watched': [ 'app/Resources','src/' ]
   files:
     javascripts: joinTo:
-      'js/app.js': /^app\/Resources\/(?!external)/
+      'js/app.js': [/^app\/Resources\/(?!external)/, /^src\//]
       'js/external.js': /^app\/Resources\/external.*.min.js/
       'js/vendor.js': /^vendor/

     stylesheets: joinTo:
-      'css/style.css': /^app\/Resources\/(?!external)/
+      'css/style.css': [/^app\/Resources\/(?!external)/,/^src\//]
       'css/vendor.css': /^(vendor)/
-      'css/external.css': /^app\/Resources\/external\/bootstrap-3.3.5-dist\/css.*.min.css/
-
+      'css/bootstrap.css': /^app\/Resources\/external\/bootstrap-3.3.5-dist\/css.*.min.css/
   conventions:
-    ignored: [ /\/_/ ]
+    ignored: [
+      /\/_/,
+      /bootstrap(-theme)?.css(.map)?/,
+      /(bootstrap|npm).js/
+    ]
     assets: /^app\/Resources\/assets/
   plugins:
     babel: pattern: /\.(js|jsx)$/


Use function instead of instance variable in helper methods

--- core/app/backbone/factlink/collection.coffee
+++ core/app/backbone/factlink/collection.coffee
@@ -9,7 +9,7 @@
   loading: -> @_loading

   waitForFetch: (callback) ->
-    if @_loading
+    if @loading()
       resetCallback = ->
         @off 'reset', resetCallback

@@ -21,7 +21,7 @@
       callback.call(this, this)

   fetchOnce: (options={}) ->
-    if @_loading
+    if @loading()
       @waitForFetch options.success if options.success?
     else
       @fetch options


teams: create private conversation copy fixes

--- client/activity/lib/components/createprivatechannelmodal/index.coffee
+++ client/activity/lib/components/createprivatechannelmodal/index.coffee
@@ -71,7 +71,7 @@

   getModalProps: ->
     isOpen             : yes
-    title              : 'Create a Private Group'
+    title              : 'Create a Private Conversation'
     className          : 'CreateChannel-Modal'
     buttonConfirmTitle : 'CREATE'
     onConfirm          : @bound 'createChannel'
@@ -320,8 +320,8 @@

-            A private group is only visible to its members,
-            and only members of a private group can read or search its contents.
+            A private conversation is only visible to its members,
+            and only those members can read or search its contents.

{@props.extraInformation}

@@ -336,7 +336,7 @@

           <input className='Reactivity-input' value={@state.name} maxlength='20' onChange={@bound 'setName'} onKeyDown={@bound 'onInputKeydown'}/>

-            This is how this thread is going to appear on your sidebar.
+            This is how this conversation is going to appear on your sidebar.

@@ -346,7 +346,7 @@

           <input className='Reactivity-input' value={@state.purpose} maxlength='200' onChange={@bound 'setPurpose'} onKeyDown={@bound 'onInputKeydown'}/>

-            Give your channel a purpose that describes what it will be used for.
+            Set a purpose to your conversation that describes what it will be used for.


app: Add dropper functionality to "drop" "items" onto the stage.

--- oghma/app.coffee
+++ oghma/app.coffee
@@ -59,6 +59,11 @@

   # Synonym for `kinetic_panel.stage`.
   stage: null
+
+  # Dropper
+  #
+  # Funcion to apply on next click to stage.
+  dropper: null

   # Constructor
   #
@@ -130,6 +135,11 @@
     )
     @viewport.add( @kinetic_panel )
     @stage = @kinetic_panel.stage
+    @kinetic_panel.getEl().on( 'click', ( e ) =>
+      pt = e.getPoint()
+      @apply_dropper( pt.x, pt.y, e )
+      null
+    )

     # Main toolbar.
     @toolbar_main = Ext.create( 'Ext.toolbar.Toolbar',
@@ -303,3 +313,31 @@
     else
       color = user.gets( 'primary' )
       @console?.message( from, msg, color, color )
+
+  # Load a function into the dropper.
+  #
+  # @param [function(x, y, event)] Event to load.
+  # @return [Oghma.App] this
+  load_dropper: ( f ) ->
+    @dropper = f
+    document.body.style.cursor = 'crosshair'
+    this
+
+  # Unload the dropper.
+  #
+  # @return [Oghma.App] this
+  unload_dropper: ->
+    @dropper = null
+    document.body.style.cursor = 'default'
+    this
+
+  # Apply the dropper.
+  #
+  # @param [numeric] x X stage location.
+  # @param [numeric] y Y stage location.
+  # @param [Object] e Event
+  # @return [Oghma.App] this
+  apply_dropper: ( x, y, e = null ) ->
+    @dropper?( x, y, e )
+    @unload_dropper()
+    this


chore(scripts): Remove unused folder from earlier version

--- scripts/index.coffee
+++ scripts/index.coffee
@@ -1,16 +0,0 @@
-# Description
-#   Just for running Hubot in dev-dependencies with this package, for tests
-#
-# Configuration:
-#   N/A
-#
-# Commands:
-#   N/A
-#
-# Notes:
-#   This file won't be used when Playbook is required as a module.
-#
-# Author:
-#   Tim Kinnane[@4thParty]
-Playbook = require '../index.coffee'
-module.exports = (robot, scripts) ->  Playbook robot, scripts


number_extensions

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -337,9 +337,7 @@

 @name approachByRatio
 @methodOf Number#
-
-@type Number
-@returns A number toward target by the ratio
+@returns {Number} A number toward target by the ratio
 ###
 Number::approachByRatio = (target, ratio) ->
   this.approach(target, this * ratio)


Fix for Android no move during swipe

Fix for Android no move during swipe

On some Android devices/versions a touchmove is never fired. This fix creates the _last delta from the touchend/cancel if it does not exist.

--- source/quo.gestures.swipe.coffee
+++ source/quo.gestures.swipe.coffee
@@ -39,6 +39,16 @@
         _last = null

     cancel = end = (target, data) ->
+      if not _last? or _last is `undefined`
+        if data.length >= 1
+          delta =
+            x: data[0].x - _start.x
+            y: data[0].y - _start.y
+
+          _last =
+            x: data[0].x
+            y: data[0].y
+            delta: delta
       if _last
         _check(false)
         _last = null


Add tests for indent_size

Add tests for indent_size

--- test/brave-mouse/validate.coffee
+++ test/brave-mouse/validate.coffee
@@ -73,3 +73,123 @@
 						results.should.be.true

 						done()
+
+			describe 'indent_size', ->
+				after ->
+					mockFs.restore()
+
+				it 'should validate if file uses tabs but 2 spaces are expected', (done) ->
+					prepareFs 'indent_size', 2, 'indent_size/tabs.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 2
+							is: 'tab'
+
+						done()
+
+				it 'should validate if file uses tabs but 4 spaces are expected', (done) ->
+					prepareFs 'indent_size', 4, 'indent_size/tabs.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 4
+							is: 'tab'
+
+						done()
+
+				it 'should validate if file uses tabs and tabs are expected', (done) ->
+					prepareFs 'indent_size', 'tab', 'indent_size/tabs.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should validate if file uses 2 spaces but tabs are expected', (done) ->
+					prepareFs 'indent_size', 'tab', 'indent_size/2-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 'tab'
+							is: 2
+
+						done()
+
+				it 'should validate if file uses 2 spaces and 2 spaces are expected', (done) ->
+					prepareFs 'indent_size', 2, 'indent_size/2-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should validate if file uses 2 spaces but 4 spaces are expected', (done) ->
+					prepareFs 'indent_size', 4, 'indent_size/2-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 4
+							is: 2
+
+						done()
+
+				it 'should validate if file uses 4 spaces but tabs are expected', (done) ->
+					prepareFs 'indent_size', 'tab', 'indent_size/4-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 'tab'
+							is: 4
+
+						done()
+
+				it 'should validate if file uses 4 spaces but 2 spaces are expected', (done) ->
+					prepareFs 'indent_size', 2, 'indent_size/4-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.indent_size.should.deep.equal
+							expected: 2
+							is: 4
+
+						done()
+
+				it 'should validate if file uses 4 spaces and 4 spaces are expected', (done) ->
+					prepareFs 'indent_size', 4, 'indent_size/4-spaces.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should validate if file uses no indentation and tabs are expected', (done) ->
+					prepareFs 'indent_size', 'tab', 'indent_size/none.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should validate if file uses no indentation and 2 spaces are expected', (done) ->
+					prepareFs 'indent_size', 2, 'indent_size/none.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should validate if file uses no indentation and 4 spaces are expected', (done) ->
+					prepareFs 'indent_size', 4, 'indent_size/none.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()
+
+				it 'should not validate if nothing is expected', (done) ->
+					prepareFs null, null, 'indent_size/none.txt'
+
+					bmValidate 'file.txt', (err, results) ->
+						results.should.be.true
+
+						done()


Fixed: the DB name conf wasn't fully used in production

--- server/lib/db.coffee
+++ server/lib/db.coffee
@@ -38,7 +38,7 @@
                 "names":[loginCouch[0], 'proxy']
                 "roles":[]
         couchClient.setBasicAuth(loginCouch[0],loginCouch[1])
-        couchClient.put 'cozy/_security', data, (err, res, body)->
+        couchClient.put "#{db.name}/_security", data, (err, res, body)->
             callback err

     addCozyUser = (callback) ->
@@ -83,7 +83,7 @@
                 if process.env.NODE_ENV is 'production'
                     loginCouch = initLoginCouch()
                     couchClient.setBasicAuth(loginCouch[0],loginCouch[1])
-                    couchClient.get 'cozy/_security', (err, res, body)=>
+                    couchClient.get "#{db.name}/_security", (err, res, body)=>
                         if not body.admins? or
                                 body.admins.names[0] isnt loginCouch[0] or
                                 body.readers?.names[0] isnt 'proxy'


try to put this back

try to put this back

--- server/server.coffee
+++ server/server.coffee
@@ -93,9 +93,9 @@
           kiteBroker.createQueue '', (dcQueue)->
             dcQueue.bind exchangeName, 'disconnected'
             dcQueue.subscribe ->
-              dcQueue.destroy()# -> dcQueue.close()
+              dcQueue.destroy -> dcQueue.close()
               setTimeout ->
-                kiteCmQueue.destroy()# -> kiteCmQueue.close()
+                kiteCmQueue.destroy -> kiteCmQueue.close()
               , kites?.disconnectTimeout ? 5000
           return res.send privName


style(gulpfile): use new CoffeeScript 1.7 chaining syntax

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -16,21 +16,23 @@
 template = require 'gulp-template'

 gulp.task 'changelog', ->
-	config =
+	options =
 		repository: pkg.repository.url
 		version: pkg.version

-	changelog config, (err, log) ->
+	changelog options, (err, log) ->
 		fs.writeFile './CHANGELOG.md', log

 gulp.task 'default', ['scripts', 'styles', 'views'], ->
-	gulp.src('./.temp/**')
-		.pipe(gulp.dest('./dist/'))
+	gulp
+		.src './.temp/**'
+		.pipe gulp.dest './dist/'

 gulp.task 'clean', ->
-	gulp.src(['./bower_components/', './components/', './.temp/', './dist/'])
-		.pipe(clean())
+	gulp
+		.src ['./bower_components/', './components/', './.temp/', './dist/']
+		.pipe clean()

 gulp.task 'bower', ['clean'], ->
 	trim = (file, prefix) ->
@@ -40,7 +42,7 @@
 	components = bower()

 	components
-		.pipe(filter (file) ->
+		.pipe filter (file) ->
 			switch file.path
 				when 'angular/angular.min.js'
 					trim file, 'angular/'
@@ -58,32 +60,30 @@
 					trim file, 'requirejs/'
 				else
 					return false
-		)
-		.pipe(gulp.dest('./components/scripts/libs/'))
+		.pipe gulp.dest './components/scripts/libs/'

 	components
-		.pipe(filter (file) ->
-			isLess = /bootstrap\/less\//.test(file.path)
+		.pipe filter (file) ->
+			isLess = /bootstrap\/less\//.test file.path

 			return if not isLess

 			trim file, 'bootstrap/less/'
-		)
-		.pipe(gulp.dest('./components/styles/'))
+		.pipe gulp.dest './components/styles/'

 	components
-		.pipe(filter (file) ->
-			isLess = /bootstrap\/dist\/fonts\//.test(file.path)
-
-			return if not isLess
+		.pipe filter (file) ->
+			isFont = /bootstrap\/dist\/fonts\//.test file.path
+
+			return if not isFont

 			trim file, 'bootstrap/dist/fonts/'
-		)
-		.pipe(gulp.dest('./components/fonts/'))
+		.pipe gulp.dest './components/fonts/'

 gulp.task 'copy:temp', ['clean', 'bower'], ->
-	gulp.src(['./src/**', './components/**'])
-		.pipe(gulp.dest('./.temp/'))
+	gulp
+		.src ['./src/**', './components/**']
+		.pipe gulp.dest './.temp/'

 gulp.task 'coffeelint', ->
 	options =
@@ -96,21 +96,27 @@
 		no_tabs:
 			level: 'ignore'

-	gulp.src('./src/**/*.coffee')
-		.pipe(coffeelint(options))
-		.pipe(coffeelint.reporter())
+	gulp
+		.src './src/**/*.coffee'
+		.pipe coffeelint options
+		.pipe coffeelint.reporter()

 gulp.task 'coffee', ['coffeelint', 'copy:temp'], ->
-	gulp.src('./.temp/**/*.coffee')
-		.pipe(coffee({sourceMap: true}))
-		.pipe(gulp.dest('./.temp/'))
+	options =
+		sourceMap: true
+
+	gulp
+		.src './.temp/**/*.coffee'
+		.pipe coffee options
+		.pipe gulp.dest './.temp/'

 gulp.task 'scripts', ['coffee']

 gulp.task 'less', ['copy:temp'], ->
-	gulp.src('./.temp/styles/styles.less')
-		.pipe(less())
-		.pipe(gulp.dest('./.temp/styles/'))
+	gulp
+		.src './.temp/styles/styles.less'
+		.pipe less()
+		.pipe gulp.dest './.temp/styles/'

 gulp.task 'styles', ['less']

@@ -119,19 +125,25 @@
 		scripts: '<script data-main="/scripts/main.js" src="/scripts/libs/require.js"></script>'
 		styles: '<!--[if lte IE 8]> <script src="/scripts/libs/json3.js"></script> <script src="/scripts/libs/html5shiv-printshiv.js"></script> <![endif]--><link rel="stylesheet" href="/styles/styles.css" />'

-	gulp.src('./.temp/**/*.{html,jade,md,markdown}')
-		.pipe(template(data))
-		.pipe(gulp.dest('./.temp/'))
+	gulp
+		.src './.temp/**/*.{html,jade,md,markdown}'
+		.pipe template data
+		.pipe gulp.dest './.temp/'

 gulp.task 'jade', ['template'], ->
-	gulp.src('./.temp/**/*.jade')
-		.pipe(jade(pretty: true))
-		.pipe(gulp.dest('./.temp/'))
+	options =
+		pretty: true
+
+	gulp
+		.src './.temp/**/*.jade'
+		.pipe jade options
+		.pipe gulp.dest './.temp/'

 gulp.task 'markdown', ['template'], ->
-	gulp.src('./.temp/**/*.{md,markdown}')
-		.pipe(markdown())
-		.pipe(gulp.dest('./.temp/'))
+	gulp
+		.src './.temp/**/*.{md,markdown}'
+		.pipe markdown()
+		.pipe gulp.dest './.temp/'

 gulp.task 'views', ['jade', 'markdown']

@@ -222,14 +234,7 @@
 	options =
 		quotes: true

-	gulp.src('./.temp/**/*.html')
-		.pipe(minifyHtml(options))
-		.pipe(gulp.dest('./.temp/'))
-
-
-
-
-
-
-
-
+	gulp
+		.src './.temp/**/*.html'
+		.pipe minifyHtml options
+		.pipe gulp.dest './.temp/'


build sequence changed

build sequence changed

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -47,8 +47,7 @@

 log "Build in #{ args.env } mode."
 log 'Debug is ' + (if args.debug then 'enabled' else 'disabled') + '.'
-log 'Paths are : '
-log paths
+log 'Paths are :\n', paths

 # preprocessing tasks

@@ -76,13 +75,21 @@

 # build tasks

-gulp.task 'build:statics-i18n', [], ->
-  from [paths.web + '/i18n/*.json']
+gulp.task 'build:statics-i18n', ->
+  from [
+    paths.web + '/i18n/*.json'
+  ]
   .pipe to paths.build + '/i18n/'

-gulp.task 'build:statics', ['build:statics-i18n'], ->
-  from [paths.web + '/*.html']
+gulp.task 'build:statics-root-files', ->
+  from [
+    paths.web + '/*.html'
+    paths.web + '/*.ico'
+  ]
   .pipe to paths.build
+
+gulp.task 'build:statics', (cb) ->
+  sequence ['build:statics-i18n', 'build:statics-root-files'], cb

 gulp.task 'build:vendors', [], ->
   vendorsFiles = do bowerFiles
@@ -117,6 +124,9 @@
   .pipe $.if args.compressed, $.obfuscate
   .pipe $.size title: 'ng-app'
   .pipe to paths.exploded
+
+gulp.task 'build:ng', (cb) ->
+  sequence ['build:ng-conf', 'build:ng-templates', 'build:ng-app'], cb

 # dev helpers tasks
@@ -181,8 +191,8 @@

 gulp.task 'build', [], (cb) ->
   sequence 'clean:before-build',
-    'compile:sass', ['hints:js', 'hints:html'], ['build:statics', 'build:vendors'],
-    ['build:ng-conf', 'build:ng-templates', 'build:ng-app'], 'package:ng',
+    'compile:sass', ['hints:js', 'hints:html'],
+    ['build:statics', 'build:vendors'], 'build:ng', 'package:ng',
     'clean:after-build', cb

 gulp.task 'default', ['build']


append entry to clean task.

append entry to clean task.


Add 'build' task to gulpfile

Add 'build' task to gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -14,6 +14,7 @@

 dir =
   tmp: './tmp/'
+  dist: './dist/'

 file =
   main: 'd3-meets-chart.js'
@@ -36,9 +37,12 @@
   stylusSrc: [
     './src/d3-meets-chart.styl'
   ]
-  main: dir.tmp + file.main
-  mainMin: dir.tmp + file.mainMin
-  specRunner: dir.tmp + file.specRunner
+  tmp:
+    main: dir.tmp + file.main
+    mainMin: dir.tmp + file.mainMin
+  dist:
+    main: dir.dist + file.main
+    mainMin: dir.dist + file.mainMin
   karmaFiles: [
     'bower_components/d3/d3.min.js',
     'tmp/d3-meets-chart.js',
@@ -47,41 +51,41 @@

 # Tasks

-gulp.task 'coffee-src', ->
-  gulp.src(src.coffeeSrc)
+taskCoffee = (srcPath, concatPath, destPath) ->
+  gulp.src(srcPath)
     .pipe(plumber())
     .pipe(coffee())
-    .pipe(concat(file.main))
-    .pipe(gulp.dest(dir.tmp))
+    .pipe(concat(concatPath))
+    .pipe(gulp.dest(destPath))

-gulp.task 'coffee-spec', ->
-  gulp.src(src.coffeeSpec)
-    .pipe(plumber())
-    .pipe(coffee())
-    .pipe(concat(file.specRunner))
-    .pipe(gulp.dest(dir.tmp))
+gulp.task('coffee:src:tmp', -> taskCoffee(src.coffeeSrc, file.main, dir.tmp))
+gulp.task('coffee:spec:tmp', -> taskCoffee(src.coffeeSpec, file.specRunner, dir.tmp))
+gulp.task('coffee:src:dist', -> taskCoffee(src.coffeeSrc, file.main, dir.dist))

-gulp.task 'stylus-src', ->
+gulp.task 'stylus:src', ->
   gulp.src(src.stylusSrc)
     .pipe(plumber())
     .pipe(stylus())
-    .pipe gulp.dest(dir.tmp)
+    .pipe(gulp.dest(dir.tmp))

-gulp.task 'uglify', ->
-  gulp.src(src.main)
-    .pipe(rename(src.mainMin))
+taskUglify = (srcPath, renamePath) ->
+  gulp.src(srcPath)
+    .pipe(rename(renamePath))
     .pipe(uglify())
     .pipe(gulp.dest('./'))

-gulp.task 'clean', ->
-  gulp.src(dir.tmp)
+gulp.task('uglify:tmp', -> taskUglify(src.tmp.main, src.tmp.mainMin))
+gulp.task('uglify:dist', -> taskUglify(src.dist.main, src.dist.mainMin))
+
+taskClean = (srcPath) ->
+  gulp.src(srcPath)
     .pipe(plumber())
     .pipe(rimraf())

-gulp.task 'licenses', ->
-  licenseFind().pipe(gulp.dest('./audit'))
+gulp.task('clean:tmp', -> taskClean(dir.tmp))
+gulp.task('clean:dist', -> taskClean(dir.dist))

-gulp.task 'karma-travis', ->
+gulp.task 'karma:travis', ->
   gulp.src(src.karmaFiles)
     .pipe(
       karma(
@@ -93,18 +97,12 @@
     )
     .on('error', (err) -> throw err)

+gulp.task('licenses', -> licenseFind().pipe(gulp.dest('./audit')))
+
 # Runners
-
-gulp.task 'compile', ->
-  runSequence('clean', 'coffee-src', 'coffee-spec', 'stylus-src', 'uglify')
-
-gulp.task 'travis', ->
-  runSequence('clean', 'coffee-src', 'coffee-spec', 'stylus-src', 'uglify', 'karma-travis')
-
-gulp.task('coffee', ['coffee-src', 'coffee-spec'])
-gulp.task('stylus', ['stylus-src'])
-
-gulp.task 'watch', ->
-  gulp.watch(['./src/*.coffee', './src/*.styl', './spec/*.coffee'], ['compile'])
-
-gulp.task('default', ['compile'])
+gulp.task('compile:tmp', -> runSequence('clean:tmp', 'coffee:src:tmp', 'coffee:spec:tmp', 'stylus:src', 'uglify:tmp'))
+gulp.task('compile:dist', -> runSequence('clean:dist', 'coffee:src:dist', 'uglify:dist'))
+gulp.task('travis', -> runSequence('clean:tmp', 'coffee:src:tmp', 'coffee:spec:tmp', 'stylus:src', 'uglify:tmp', 'karma:travis'))
+gulp.task('watch', -> gulp.watch(['./src/*.coffee', './src/*.styl', './spec/*.coffee'], ['compile:tmp']))
+gulp.task('build', ['compile:dist'])
+gulp.task('default', ['compile:tmp'])


Write package.json to dist

Write package.json to dist

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -23,6 +23,10 @@
 gulp.task 'ready', ->
   if !existsSync 'dist'
     mkdirSync 'dist'
+  p = cloneDeep pkg
+  p.dependencies = chokidar: pkg.dependencies.chokidar
+  delete p.devDependencies
+  writeFileSync 'dist/package.json', JSON.stringify p

 gulp.task 'copy', ->
   gulp
@@ -89,11 +93,6 @@
       output: './dist/main.js'

 gulp.task 'publish', ->
-  p = cloneDeep pkg
-  p.dependencies = chokidar: pkg.dependencies.chokidar
-  delete p.devDependencies
-  writeFileSync 'dist/package.json', JSON.stringify p
-
   github = new GitHub
     version: "3.0.0"
     debug: true


Update React.js externs path.

Update React.js externs path.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -35,7 +35,7 @@
   ]
   compiler: 'bower_components/closure-compiler/compiler.jar'
   externs: [
-    'bower_components/este-library/externs/react.js'
+    'bower_components/react-externs/externs.js'
   ]
   thirdParty:
     development: [


Move Styles and Scripts Subdirectories to Constants

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -16,6 +16,9 @@
 SRC = 'src'
 DEST = 'out'
 RELEASE_DEST = 'release'
+STYLES = 'styles'
+SCRIPTS = 'scripts'
+
 pathTo = (ext) -> "#{SRC}/#{ext}/**/*.#{ext}"
 JADE_PATH = pathTo 'jade'
 LESS_PATH = pathTo 'less'
@@ -46,9 +49,9 @@
     ]
     .pipe concat 'qbn.css'
     .pipe minifyCss()
-    .pipe gulp.dest "#{RELEASE_DEST}/styles"
+    .pipe gulp.dest "#{RELEASE_DEST}/#{STYLES}"
     .pipe sourcemaps.write()
-    .pipe gulp.dest "#{DEST}/styles"
+    .pipe gulp.dest "#{DEST}/#{STYLES}"

 gulp.task 'coffee', ->
   gulp.src COFFEE_PATH
@@ -57,9 +60,9 @@
     .pipe concat 'qbn.js'
     .pipe wrap '"use strict";{%= body %}'
     .pipe uglify mangle: false
-    .pipe gulp.dest "#{RELEASE_DEST}/scripts"
+    .pipe gulp.dest "#{RELEASE_DEST}/#{SCRIPTS}"
     .pipe sourcemaps.write()
-    .pipe gulp.dest "#{DEST}/scripts"
+    .pipe gulp.dest "#{DEST}/#{SCRIPTS}"

 gulp.task 'clean', (callback) ->
   del [DEST, RELEASE_DEST], callback


[DD&MC] Fix build script

[DD&MC] Fix build script

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -37,7 +37,7 @@

 gulp.task 'default', ['build']

-gulp.task 'bump', ['build'] ->
+gulp.task 'bump', ['build'], ->
   gulp.src paths.source.manifest
   .pipe bump { type: argv.bump }
   .pipe gulp.dest(paths.dest.root)


optimized gulpfile directories configuration

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -21,11 +21,10 @@
 conf =
   lib: ['src/main.coffee', 'theglow.js']
   tests: [['src/main.coffee'].concat(glob.sync('tests/**/*.coffee')), 'tests.js']
-  watch: ['src/**/*.coffee', 'src/**/*.js', 'tests/**/*.coffee']
+  watch: ['src/**/*.coffee', 'tests/**/*.coffee']
   workers: 'src/workers/*.coffee'
   dist_dir: 'dist/'
   build_dir: 'build/'
-  clean: ['dist/*.js', 'dist/*.map']

 # produce non-minified versions of theglow and tests + source maps
 gulp.task 'build', ['workers'], ->


rename e2e task

rename e2e task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -46,8 +46,8 @@
 gulp.task 'deploy', [].concat(if target is 's3' then ['s3Deploy'] else ['locationDeploy'])

 # Execute E2E tests
-gulp.task 'e2e', taskRequire './tasks/test/e2e'
-gulp.task 'e2e:watch', ['e2e'], taskRequire './tasks/test/e2eWatch'
+gulp.task 'protractor', taskRequire './tasks/test/e2e'
+gulp.task 'e2e', ['protractor'], taskRequire './tasks/test/e2eWatch'

 # Update E2E driver
 gulp.task 'e2e-driver-update', plugins.protractor.webdriver_update


added test for inserting as pack

added test for inserting as pack

--- services/track-changes/test/unit/coffee/UpdatesManager/UpdatesManagerTests.coffee
+++ services/track-changes/test/unit/coffee/UpdatesManager/UpdatesManagerTests.coffee
@@ -51,11 +51,10 @@
 					.calledWith(@doc_id)
 					.should.equal true

-			it "should save the compressed ops", ->
+			it "should save the compressed ops as a pack", ->
 				@PackManager.insertCompressedUpdates
 					.calledWith(@project_id, @doc_id, null, @compressedUpdates, @temporary)
 					.should.equal true
-

 			it "should call the callback", ->
 				@callback.called.should.equal true
@@ -93,6 +92,30 @@
 				it "should save the new compressed ops", ->
 					@MongoManager.insertCompressedUpdates
 						.calledWith(@project_id, @doc_id, @compressedUpdates[1..], @temporary)
+						.should.equal true
+
+				it "should call the callback", ->
+					@callback.called.should.equal true
+
+			describe "when the raw ops start where the existing history ends and the history is in a pack", ->
+				beforeEach ->
+					@lastCompressedUpdate = {pack: [{ v: 11, op: "compressed-op-11" }], v:11}
+					@rawUpdates = [{ v: 12, op: "mock-op-12" }, { v: 13, op: "mock-op-13" }]
+					@MongoManager.peekLastCompressedUpdate = sinon.stub().callsArgWith(1, null, @lastCompressedUpdate, @lastCompressedUpdate.v)
+					@UpdatesManager.compressAndSaveRawUpdates @project_id, @doc_id, @rawUpdates, @temporary, @callback
+
+				it "should look at the last compressed op", ->
+					@MongoManager.peekLastCompressedUpdate
+						.calledWith(@doc_id)
+						.should.equal true
+
+				it "should defer the compression of raw ops to PackManager", ->
+					@UpdateCompressor.compressRawUpdates
+						.should.not.be.called
+
+				it "should save the new compressed ops into a pack", ->
+					@PackManager.insertCompressedUpdates
+						.calledWith(@project_id, @doc_id, @lastCompressedUpdate, @compressedUpdates, @temporary)
 						.should.equal true

 				it "should call the callback", ->


Fix comments.

Fix comments.

--- src/ApiNodes/OVirtApiNode.coffee
+++ src/ApiNodes/OVirtApiNode.coffee
@@ -33,7 +33,6 @@
 #
 OVirtApiNode = class ApiNodes.OVirtApiNode extends CoffeeMix
   # Included mixins
-# Included Mixins
   @include Mixins.Fiberable, ['update']
   @include Mixins.PropertyDistributor


Close modal when saving integration

Close modal when saving integration

--- app/assets/javascripts/admin/views/home/add_integration.js.coffee
+++ app/assets/javascripts/admin/views/home/add_integration.js.coffee
@@ -192,7 +192,7 @@
             console.log 'missing'

       @model.signup parameters, @enabledMappings, error: @displayErrors
-      $.modal.close()
+      $('#new-integration-modal').dialog 'close'
     else
       @$el.find('.parsley-error:first').focus()


fix focus issue on decaying average input box

fixes OUT-2046

test plan:
- go to create an outcome using decaying average
- delete the rightmost number
- the cursor should stay where it is, instead of moving
  back to the start of the field

Change-Id: Iefd363b7544dc8f1735ff1e5e2374d24466f42bf
Reviewed-on: https://gerrit.instructure.com/145115
Tested-by: Jenkins
Reviewed-by: Augusto Callejas <7d9b9fd126d23d111f693e51511b33ea0e7192f6@instructure.com>
Reviewed-by: Michael Brewer-Davis <785693f4c81267e5b88c0f98d39b56a39a2b6910@instructure.com>
QA-Review: Leo Abner <6bfbfd5df67beb2a7b2543f9a05c72d17520f3f5@instructure.com>
Product-Review: Sidharth Oberoi <b9947257dd0ff1b6a5d899864f5ca846b60f0be3@instructure.com>

--- app/coffeescripts/views/outcomes/CalculationMethodFormView.coffee
+++ app/coffeescripts/views/outcomes/CalculationMethodFormView.coffee
@@ -37,6 +37,7 @@
     afterRender: ->
       if @hadFocus
         @$calculation_int.focus().val(@$calculation_int.val())
+        @$calculation_int[0].selectionStart = @selectionStart
       @hadFocus = undefined

     attach: ->
@@ -71,6 +72,8 @@
     render: ->
       @hadFocus = !_.isEmpty(@$calculation_int) and
         document.activeElement is @$calculation_int[0]
+      if @hadFocus
+        @selectionStart = document.activeElement.selectionStart
       @undelegateEvents()
       super
       @delegateEvents()


Bug fix on channels. Subscribers field can be omitted in topology

--- lib/actor/hchannel.coffee
+++ lib/actor/hchannel.coffee
@@ -41,6 +41,7 @@
     @type = "channel"
     @inboundAdapters.push adapters.adapter("socket_in", {url: topology.properties.listenOn, owner: @})
     @outboundAdapters.push adapters.adapter("channel_out", {url: topology.properties.broadcastOn, owner: @, targetActorAid: @actor})
+    @properties.subscribers = topology.properties.subscribers or []

   onMessage: (hMessage) ->
     # If hCommand, execute it


rename

rename

--- lib/atom-butterfly.coffee
+++ lib/atom-butterfly.coffee
@@ -58,7 +58,7 @@

   cmdCreateProject: ->

-    ProjectWizardView = require './scaffold/project-wizard-view'
+    ProjectWizardView = require './project/project-wizard-view'
     projectWizardView = new ProjectWizardView().attach()

     projectWizardView.on 'finish', (options) =>
@@ -80,7 +80,7 @@
         pv = new ProgressView("Create Project...")
         pv.attach()

-        {createProjectPromise} = require './scaffold'
+        {createProjectPromise} = require './project/scaffold'

         createProjectPromise(options)
         .progress (progress)->
@@ -102,7 +102,7 @@
     pv = new ProgressView("Install Butterfly.js...")
     pv.attach()

-    Scaffolder = require './scaffold'
+    Scaffolder = require './project/scaffold'
     Scaffolder.installFrameworkPromise()
     .progress (progress)->
       pv.setTitle(progress.message) if progress.message


Don't access navigator.userAgent at require time

--- lib/atom-io-client.coffee
+++ lib/atom-io-client.coffee
@@ -1,9 +1,9 @@
 fs = require 'fs-plus'
 path = require 'path'
+{remote} = require 'electron'

-glob = null    # defer until used
-request = null # defer until used
-DefaultRequestHeaders = {'User-Agent': navigator.userAgent}
+glob = require 'glob'
+request = require 'request'

 module.exports =
 class AtomIoClient
@@ -66,10 +66,9 @@
         callback(error, null)

   request: (path, callback) ->
-    request ?= require 'request'
     options = {
       url: "#{@baseURL}#{path}"
-      headers: DefaultRequestHeaders
+      headers: {'User-Agent': navigator.userAgent}
     }

     request options, (err, res, body) =>
@@ -122,7 +121,6 @@
     path.join @getCachePath(), "#{login}-#{Date.now()}"

   cachedAvatar: (login, callback) ->
-    glob ?= require 'glob'
     glob @avatarGlob(login), (err, files) =>
       return callback(err) if err
       files.sort().reverse()
@@ -141,10 +139,9 @@
       callback(null, null)
     else
       imagePath = @avatarPath login
-      request ?= require 'request'
       requestObject = {
         url: "https://avatars.githubusercontent.com/#{login}"
-        headers: DefaultRequestHeaders
+        headers: {'User-Agent': navigator.userAgent}
       }
       request.head requestObject, (error, response, body) ->
         if error? or response.statusCode isnt 200 or not response.headers['content-type'].startsWith('image/')
@@ -189,5 +186,4 @@
         children.forEach(deleteAvatar)

   getCachePath: ->
-    {remote} = require 'electron'
     @cachePath ?= path.join(remote.app.getPath('userData'), 'Cache', 'settings-view')


center images

center images

--- documentation/app/static/scripts/modules/process-documentation.coffee
+++ documentation/app/static/scripts/modules/process-documentation.coffee
@@ -65,6 +65,7 @@
       $('pre').addClass 'prettyprint'
       prettyPrint()

+      $(@elements.doc).find('img').parent().addClass('center')
       $(@elements.doc).find('table').wrap '<div class="definitions" />'

       title = $('h1').text()


Environments: Add domain data provider

Environments: Add domain data provider

--- client/Environments/views/scene/environmentdomaincontainer.coffee
+++ client/Environments/views/scene/environmentdomaincontainer.coffee
@@ -1,4 +1,16 @@
 class EnvironmentDomainContainer extends EnvironmentContainer
+
+  EnvironmentDataProvider.addProvider "domains", ->
+
+    new Promise (resolve, reject)->
+
+      KD.whoami().fetchDomains (err, domains)->
+
+        if err or not domains or domains.length is 0
+          warn "Failed to fetch domains", err  if err
+          return resolve []
+
+        resolve domains

   constructor:(options={}, data)->
     options.cssClass  = 'domains'
@@ -49,23 +61,6 @@
       aliases     : domain.hostnameAlias
       domain      : domain

-  loadItems:->
-
-    new Promise (resolve, reject)=>
-
-      {JDomain} = KD.remote.api
-      JDomain.fetchDomains (err, domains)=>
-
-        @removeAllItems()
-
-        if err or not domains or domains.length is 0
-          warn "Failed to fetch domains", err  if err
-          return resolve()
-
-        domains.forEach (domain, index)=>
-          @addDomain domain
-          if index is domains.length - 1 then resolve()
-
   getDomainCreateForm: ->

     domainCreateForm = new DomainCreateForm {}, {stack: @parent.stack}


use new TabView api.

use new TabView api.

--- client/app/Applications/Environments.kdapplication/AppView.coffee
+++ client/app/Applications/Environments.kdapplication/AppView.coffee
@@ -1,8 +1,15 @@
 class EnvironmentsMainView extends JView

   tabData = [
-    { name : 'VMs',              lazy : no,   itemClass : VMMainView }
-    { name : 'Domains',          lazy : yes,  itemClass : DomainMainView }
+    name        : 'VMS'
+    viewOptions :
+      lazy      : no
+      viewClass : VMMainView
+  ,
+    name        : 'Domains'
+    viewOptions :
+      lazy      : yes
+      viewClass : DomainMainView
   ]

   navData =
@@ -11,7 +18,6 @@

   constructor:(options={}, data)->

-    options.cssClass or= "content-page"
     data or= {}
     super options, data

@@ -43,12 +49,8 @@

     data = @getData()

-    for {name, lazy, itemClass} in tabData
-      @tabs.addPane new KDTabPaneView {
-        view : {itemClass, data}
-        name
-        lazy
-      }
+    for {name, viewOptions} in tabData
+      @tabs.addPane new KDTabPaneView {name, viewOptions}

   _windowDidResize:->
     contentHeight = @getHeight() - @header.getHeight()


fix ellisis always shown bug

fix ellisis always shown bug

--- client/controllers/incidentReports/suggestedIncidentsModal.coffee
+++ client/controllers/incidentReports/suggestedIncidentsModal.coffee
@@ -94,7 +94,7 @@
       incident.dateTerritory?.territoryEnd or countEnd)
     lastEnd = startingIndex
     html = ""
-    if incidentAnnotations[0].textOffsets[0] isnt 0
+    if incidentAnnotations[0]?.textOffsets[0][0] isnt 0
       html += "..."
     incidentAnnotations.map (annotation)->
       [start, end] = annotation.textOffsets[0]


fixing homepage

fixing homepage

--- client/landing/app/Applications/Home.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Home.kdapplication/AppView.coffee
@@ -279,6 +279,22 @@
       Websites  :
         count   : "00000"

+    @moreActivity = new KDCustomHTMLView
+      tagName : 'a'
+      partial : "Want to See More Activity"
+      click   : => @notify()
+    @moreTopics = new KDCustomHTMLView
+      tagName : 'a'
+      partial : "View More Topics?"
+      click   : => @notify()
+    @moreMembers = new KDCustomHTMLView
+      tagName : 'a'
+      partial : "View More Members"
+      click   : => @notify()
+
+  notify:->
+    new KDNotificationView
+      title : 'Please login/register!'

   showLoaders:->
     @membersLoader.show()
@@ -293,7 +309,7 @@
       {{> @membersLoader}}
       {{> @members}}

-        View More Members
+        {{> @moreMembers}}

@@ -304,7 +320,7 @@
       {{> @activityLoader}}
       {{> @activity}}

-        Want to See More Activity?
+        {{> @moreActivity}}

@@ -312,7 +328,7 @@
       {{> @topicsLoader}}
       {{> @topics}}

-        View More Topics?
+        {{> @moreTopics}}

     """
@@ -396,15 +412,15 @@

   followerText:(count)->
     if count < 2
-      "#{count} Follower"
+      "#{count} Post"
     else
-      "#{count} Followers"
+      "#{count} Posts"

   pistachio:->
     """
     {span.fl.ttag{ #(title)}}

-       {{ @followerText #(counts.followers)}}
+       {{ @followerText #(counts.tagged) or 0}}

     """

@@ -422,13 +438,27 @@
     options.type = "activity"
     super options,data

-    @user = new ProfileTextView
-      tagName           : "strong"
-      origin            :
-        id              : data.originId or data.anchor.id
-        constructorName : data.originType or data.anchor.constructorName
+
+    if data.anchor?.constructorName is "JTag"
+      @user = new ProfileTextView
+        tagName           : "strong"
+        origin            :
+          id              : data.group[0].id
+          constructorName : data.group[0].constructorName
+        click             : -> no
+    else
+      @user = new ProfileTextView
+        tagName           : "strong"
+        origin            :
+          id              : data.originId or data.anchor.id
+          constructorName : data.originType or data.anchor.constructorName
+

   getActivityPhrase:(constructorName)->
+    data = @getData()
+    if data.anchor?.constructorName is "JTag"
+      return "has followed a topic."
+
     switch constructorName
       when "JStatusUpdate"    then "posted a status update."
       when "JCodeSnip"        then "shared some code."


Removed function context variables

Removed function context variables

--- src/add-hooks.coffee
+++ src/add-hooks.coffee
@@ -9,15 +9,11 @@
 logger = require './logger'

 addHooks = (runner, transactions, emitter) ->
-  @emitter = emitter
-  @runner = runner
-  @transactions = transactions

-
-  for transaction in @transactions
+  for transaction in transactions
     hooks.transactions[transaction.name] = transaction

-  pattern = @runner?.configuration?.options?.hookfiles
+  pattern = runner?.configuration?.options?.hookfiles
   if pattern

     files = glob.sync pattern


Just moved some things around

Just moved some things around

--- client/escrow.coffee
+++ client/escrow.coffee
@@ -14,22 +14,24 @@
   query[k] = base64ToBytes query[k] for k in [ 'bob', 'alice', 'trent', 'priv', 'terms' ] when query[k]?
   { bob, alice, trent, terms, priv } = query

+  # Determine public key from private key
+  if priv? then bob = get_pub priv
+
+  # Generate a random private key
+  unless bob?
+    return document.location.hash = qs.stringify format { alice, trent, terms, priv: randomBytes 32 }
+
+  # TODO trim hash
   terms_hash = SHA256 terms, asBytes: true
   terms_pub = get_pub terms_hash
   terms_text = UTF8.bytesToString terms

-  # validate pub,agent,other are valid pubkeys
-
-  # Determine public key from private key
-  if priv? then bob = get_pub priv
-  # Generate a random private key
-  else if not bob?
-    priv = randomBytes 32
-    return document.location.hash = qs.stringify format { alice, trent, terms, priv }
-
+  # If we have the other party public key, create the multisig
   if alice?
     multisig_pubkeys = [ bob, alice, (derive_key trent, terms_hash).pub ]
     multisig = create_multisig 2, multisig_pubkeys
+    document.title = "Escrow for #{multisig} | Bitscrow"
+  else document.title = "Awaiting other party... | Bitscrow"

   render el = $ view {
     # Public keys, private key, and the terms


Update the html lang attribute when changing the locale

--- lib/utilities/i18n.coffee
+++ lib/utilities/i18n.coffee
@@ -1,3 +1,4 @@
+$       = require 'jquery'
 _       = require 'underscore'
 i18n    = require 'i18next-client'
 conf    = require('../config').get().locales
@@ -136,6 +137,7 @@
   ###
   App.channel.reply 'locale:set', (locale) ->
     i18n.setLng locale, ->
+      $('html').attr 'lang', locale
       App.channel.trigger 'locale:loaded', locale


:lipstick:

:lipstick:

--- src/app/text-mate-package.coffee
+++ src/app/text-mate-package.coffee
@@ -9,7 +9,7 @@
   @testName: (packageName) ->
     /(\.|_|-)tmbundle$/.test(packageName)

-  @cssSelectorForScopeSelector: (scopeSelector) ->
+  @cssSelectorFromScopeSelector: (scopeSelector) ->
     scopeSelector.split(', ').map((commaFragment) ->
       commaFragment.split(' ').map((spaceFragment) ->
         spaceFragment.split('.').map((dotFragment) ->
@@ -31,24 +31,30 @@
   getScopedProperties: ->
     scopedProperties = []

-    for grammar in @grammars when grammar.foldingStopMarker
-      scopedProperties.push
-        selector: TextMatePackage.cssSelectorForScopeSelector(grammar.scopeName)
-        properties: { editor: { foldEndPattern: grammar.foldingStopMarker } }
+    for grammar in @grammars
+      if properties = @propertiesFromTextMateSettings(grammar)
+        selector = @cssSelectorFromScopeSelector(grammar.scopeName)
+        scopedProperties.push({selector, properties})

+    for {scope, settings} in @getTextMatePreferenceObjects()
+      if properties = @propertiesFromTextMateSettings(settings)
+        selector = @cssSelectorFromScopeSelector(scope) if scope?
+        scopedProperties.push({selector, properties})
+
+    scopedProperties
+
+  getTextMatePreferenceObjects: ->
+    preferenceObjects = []
     if fs.exists(@preferencesPath)
       for preferencePath in fs.list(@preferencesPath)
         plist.parseString fs.read(preferencePath), (e, data) =>
           if e
             console.warn "Failed to parse preference at path '#{preferencePath}'", e.stack
           else
-            { scope, settings } = data[0]
-            if properties = @translateProperties(settings)
-              selector = TextMatePackage.cssSelectorForScopeSelector(scope) if scope?
-              scopedProperties.push({selector, properties})
-    scopedProperties
+            preferenceObjects.push(data[0])
+    preferenceObjects

-  translateProperties: (textMateSettings) ->
+  propertiesFromTextMateSettings: (textMateSettings) ->
     if textMateSettings.shellVariables
       shellVariables = {}
       for {name, value} in textMateSettings.shellVariables
@@ -63,3 +69,6 @@
       foldEndPattern: textMateSettings.foldingStopMarker
     )
     { editor: editorProperties } if _.size(editorProperties) > 0
+
+  cssSelectorFromScopeSelector: (scopeSelector) ->
+    @constructor.cssSelectorFromScopeSelector(scopeSelector)


ComputeProvider: updateGroupStackUsage: swallow decrement errors since min value is provided

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -354,7 +354,11 @@
       type      : 'member-stacks'
       max       : plan.member
       min       : 0
-    , callback
+    , (err) ->
+      # no worries about `decrement` errors
+      # since 0 is already defined as min ~ GG
+      callback if change is 'increment' then err else null
+

   @createGroupStack = (client, options, callback) ->


ComputeProvider::createGroupStack: carry the results to the callback

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -296,9 +296,7 @@

         queue.push ->

-          callback null, stack
-          # `results` keeps track of the all operation
-          # if needed return with callback.
+          callback null, stack, results

         daisy queue

@@ -316,11 +314,11 @@
           delegate : member
         context    : group : group.slug

-      ComputeProvider.createGroupStack client, (err, res)->
+      ComputeProvider.createGroupStack client, (err, stack, results)->

         if err?
           {nickname} = member.profile
-          console.log "Create group stack failed for #{nickname}:", err
+          console.log "Create group stack failed for #{nickname}:", err, results

     JAccount = require '../account'


Revert ComputeProvider change

Revert ComputeProvider change

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -34,7 +34,7 @@
     instances    : 'member_instances'

   @share()
-
+
   @set
     permissions           :
       'sudoer'            : []


Revert "CredentialStore: keep credentials only on sneaker if it's supported"

--- workers/social/lib/social/models/computeproviders/credentialstore.coffee
+++ workers/social/lib/social/models/computeproviders/credentialstore.coffee
@@ -45,7 +45,11 @@
     data = { meta, originId, identifier }

     if @SNEAKER_SUPPORTED
-      storeOnSneaker client, data, callback
+      storeOnSneaker client, data, (err) ->
+        # This part can be removed once kloud is ready
+        # to use sneaker by default ~ GG cc/ RJ
+        return callback err  if err
+        storeOnMongo data, callback
     else
       storeOnMongo data, callback

@@ -117,8 +121,14 @@
     { identifier, meta } = data

     if @SNEAKER_SUPPORTED
-      storeOnSneaker client, data, callback
+
+      storeOnSneaker client, data, (err) ->
+        return callback err  if err
+
+        updateOnMongo identifier, meta, callback
+
     else
+
       updateOnMongo identifier, meta, callback

   # UPDATE ENDS ---------------------------------------------------------------


GOV-335, add onLoginFailure hook to redirect rogue users from other vpcs to error page

--- shared/router.coffee
+++ shared/router.coffee
@@ -152,3 +152,10 @@
         console.log("set fromWhere", Iron.Location.get().path, Router.current()?.route?.getName?(), exclusions)
         Session.set('fromWhere', Iron.Location.get().path)
 ###
+
+
+if Meteor.isClient
+  #catch onlogin failures and redirect to static error page
+  Accounts.onLoginFailure (err) ->
+    console.log("on login error:" + JSON.stringify(err))
+    Router.go 'othervpc'


added Bandango.numberForCurrencyHelper

added Bandango.numberForCurrencyHelper

--- app/assets/javascripts/helpers/number_to_currency_helper.js.coffee
+++ app/assets/javascripts/helpers/number_to_currency_helper.js.coffee
@@ -1,3 +1,7 @@
+Bandango.numberForCurrencyHelper = (number) ->
+  # returns a float of two decimals (to use on currencies)
+  parseFloat number.toFixed(2), 10
+
 Bandango.numberToCurrencyHelper = (number) ->
   accounting.formatMoney number, "$ "


Don’t allow soft wrap to be enabled in large file mode

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -445,7 +445,10 @@
       @isSoftWrapped()

   isSoftWrapped: ->
-    @softWrapped ? @configSettings.softWrap ? false
+    if @largeFileMode
+      false
+    else
+      @softWrapped ? @configSettings.softWrap ? false

   # Set the number of characters that fit horizontally in the editor.
   #


:lipstick:

:lipstick:

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -722,7 +722,7 @@

   decorationsForBufferRow: (bufferRow, decorationType) ->
     decorations = @decorations[bufferRow] ? []
-    decorations = (dec for dec in decorations when dec.type == decorationType) if decorationType?
+    decorations = (dec for dec in decorations when dec.type is decorationType) if decorationType?
     decorations

   addDecorationToBufferRow: (bufferRow, decoration) ->


Components: SidebarMachinesListItem: Fix typo

--- client/app/lib/components/sidebarmachineslistitem/sidebarworkspaceslistitem.coffee
+++ client/app/lib/components/sidebarmachineslistitem/sidebarworkspaceslistitem.coffee
@@ -23,16 +23,16 @@
     activeWorkspace : EnvironmentFlux.getters.activeWorkspace

-  setCoordiantes: ->
+  setCoordinates: ->

     coordinates = getBoundingClientReact @refs.workspaceItem
     @setState { coordinates: coordinates }

-  componentWillReceiveProps: -> @setCoordiantes()
+  componentWillReceiveProps: -> @setCoordinates()

-  componentDidMount: -> @setCoordiantes()
+  componentDidMount: -> @setCoordinates()

   getWorkspaceLink: ->


No need all that stuff in fileTree we're already providing them in Env bar

--- client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
@@ -211,17 +211,13 @@
     fileData = fileView.getData()

     items =
-      customView                  : new NVMToggleButtonView {}, vmName: fileData.vmName
-      'Re-initialize VM'          :
-        action                    : 'resetVm'
+      Refresh                     :
+        action                    : 'refresh'
+        separator                 : yes
       'Unmount VM'                :
         action                    : 'unmountVm'
-        separator                 : yes
       'Open VM Terminal'          :
         action                    : 'openVmTerminal'
-        separator                 : yes
-      Refresh                     :
-        action                    : 'refresh'
         separator                 : yes
       Expand                      :
         action                    : 'expand'


update label on preset select

update label on preset select

--- views/components/main/parts/miniship-parts/minipanebody.cjsx
+++ views/components/main/parts/miniship-parts/minipanebody.cjsx
@@ -123,7 +123,7 @@
     {label} = @state
     updateflag = false
     switch path
-      when '/kcsapi/api_port/port', '/kcsapi/api_req_hensei/change', '/kcsapi/api_req_hokyu/charge', '/kcsapi/api_req_map/next', '/kcsapi/api_get_member/ship3', '/kcsapi/api_req_nyukyo/speedchange'
+      when '/kcsapi/api_port/port', '/kcsapi/api_req_hensei/change', '/kcsapi/api_req_hokyu/charge', '/kcsapi/api_req_map/next', '/kcsapi/api_get_member/ship3', '/kcsapi/api_req_nyukyo/speedchange', '/kcsapi/api_req_hensei/preset_select'
         updateflag = true
         label = @updateLabels()
       when '/kcsapi/api_req_nyukyo/start'


fixing issue with tinymce editors. fixes #492

--- app/assets/javascripts/comfortable_mexican_sofa/application.js.coffee
+++ app/assets/javascripts/comfortable_mexican_sofa/application.js.coffee
@@ -53,12 +53,12 @@

 window.CMS.wysiwyg = ->
   tinymce.init
-    selector:       'textarea[data-cms-rich-text]'
-    plugins:        ['link', 'image', 'code']
-    toolbar:        'undo redo | styleselect | bullist numlist | link unlink image | code'
-    menubar:        false
-    statusbar:      false
-    relative_urls:  false
+    selector:         'textarea[data-cms-rich-text]'
+    plugins:          ['link', 'image', 'code']
+    toolbar:          'undo redo | styleselect | bullist numlist | link unlink image | code'
+    menubar:          false
+    statusbar:        false
+    relative_urls:    false
     entity_encoding : 'raw'

 window.CMS.codemirror = ->
@@ -104,6 +104,8 @@
       url: $(this).data('url'),
       data:
         layout_id: $(this).val()
+      beforeSend: ->
+        tinymce.remove()
       complete: ->
         CMS.wysiwyg()
         CMS.timepicker()


Team Settings: Stacks: Providers: Delete EngineYard.coffee

--- workers/social/lib/social/models/computeproviders/engineyard.coffee
+++ workers/social/lib/social/models/computeproviders/engineyard.coffee
@@ -1,8 +0,0 @@
-ProviderInterface = require './providerinterface'
-
-module.exports = class Azure extends ProviderInterface
-
-  @ping = (client, callback) ->
-    callback null, "Azure is cool #{ client.connection.delegate.profile.nickname }!"
-
-


added gauge metrics for number of open socket.io http and https connections

--- services/web/app/coffee/Features/ServerAdmin/AdminController.coffee
+++ services/web/app/coffee/Features/ServerAdmin/AdminController.coffee
@@ -1,3 +1,4 @@
+metrics = require("metrics-sharelatex")
 logger = require('logger-sharelatex')
 _ = require('underscore')
 User = require('../../models/User').User
@@ -14,6 +15,18 @@
 projectEntityHandler = require('../Project/ProjectEntityHandler')
 TpdsPollingBackgroundTasks = require("../ThirdPartyDataStore/TpdsPollingBackgroundTasks")
 EditorRealTimeController = require("../Editor/EditorRealTimeController")
+
+oneMinInMs = 60 * 1000
+
+updateOpenConnetionsMetrics = ()->
+	metrics.gauge "open_connections.socketio", require("../../infrastructure/Server").io?.sockets?.clients()?.length
+	metrics.gauge "open_connections.http", _.size(require('http').globalAgent?.sockets)
+	metrics.gauge "open_connections.https", _.size(require('https').globalAgent?.sockets)
+	setTimeout updateOpenConnetionsMetrics, oneMinInMs
+
+setTimeout updateOpenConnetionsMetrics, oneMinInMs
+
+

 module.exports = AdminController =


allow autocompile without code check

allow autocompile without code check

--- services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
+++ services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
@@ -90,7 +90,9 @@
 				# to block auto compiles. It also causes problems where server-provided
 				# linting errors aren't cleared after typing
 				if (ide.$scope.settings.syntaxValidation and !ide.$scope.hasLintingError)
-					$scope.recompile(isAutoCompileOnChange: true)
+					$scope.recompile(isAutoCompileOnChange: true) # compile if no linting errors
+				else if !ide.$scope.settings.syntaxValidation
+					$scope.recompile(isAutoCompileOnChange: true) # always recompile
 			else
 				# Extend remainder of timeout
 				autoCompileTimeout = setTimeout () ->


change download links so they do not rely on build id

prefer the top level files, because the build directories are more
ephemeral.  In a shared project they can expire if there are multiple
compiles.

--- services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
+++ services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
@@ -117,10 +117,12 @@
 					qs.clsiserverid = response.clsiServerId
 					ide.clsiServerId = response.clsiServerId
 				# convert the qs hash into a query string and append it
-				qs_args = ("#{k}=#{v}" for k, v of qs)
-				$scope.pdf.qs = if qs_args.length then "?" + qs_args.join("&") else ""
+				$scope.pdf.qs = createQueryString qs
 				$scope.pdf.url += $scope.pdf.qs
-				$scope.pdf.downloadUrl = "/Project/#{$scope.project_id}/output/output.pdf" + $scope.pdf.qs
+				# special case for the download url
+				if perUserCompile
+					qs.isolated = true
+				$scope.pdf.downloadUrl = "/project/#{$scope.project_id}/output/output.pdf" + createQueryString(qs)

 				fetchLogs(fileByPath['output.log'], fileByPath['output.blg'])

@@ -136,10 +138,12 @@
 						file.name = "#{file.path.replace(/^output\./, "")} file"
 					else
 						file.name = file.path
-					if not file.url?
-						file.url = "/project/#{project_id}/output/#{file.path}"
+					qs = {}
+					if perUserCompile
+						qs.isolated = true
 					if response.clsiServerId?
-						file.url = file.url + "?clsiserverid=#{response.clsiServerId}"
+						qs.clsiserverid = response.clsiServerId
+					file.url = "/project/#{project_id}/output/#{file.path}" +	createQueryString qs
 					$scope.pdf.outputFiles.push file


Добавил изменение ширины и высоты при ресайзе

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -122,6 +122,10 @@

     @_hideLess() if @length is 1

+    $(window).bind 'resize', =>
+      image = @images[@current]
+      @updateDimensions image.width, image.height
+
     @open cid
     @

@@ -132,6 +136,8 @@
       if @options.thumbnails
         @thumbnails.html ''
         @overlay.find('.choco-thumbnails-toggle').unbind 'click'
+
+      $(window).unbind 'resize'

       @current = null
       @overlay.removeClass 'show'


"suspress" console methods :)

"suspress" console methods :)

--- core/KD.coffee
+++ core/KD.coffee
@@ -165,7 +165,13 @@
         KD.log 'success', inflated
         KD.log Date.now()-start

+  oldConsole = window.console
+  window.console = {}
+  for method in ['log','warn','error','trace']
+    console[method] = noop
+
   enableLogs:->
+    window.console = oldConsole
     KD.log   = log   = if console?.log   then console.log.bind(console)   else noop
     KD.warn  = warn  = if console?.warn  then console.warn.bind(console)  else noop
     KD.error = error = if console?.error then console.error.bind(console) else noop


KD: registerAppClass: add optional version

--- core/KD.coffee
+++ core/KD.coffee
@@ -142,7 +142,8 @@
     options.thirdParty    ?= no           # a Boolean
     options.menu         or= null         # <Array<Object{title: string, eventName: string, shortcut: string}>>
     options.navItem      or= {}           # <Object{title: string, eventName: string, shortcut: string}>
-    options.labels       or= []
+    options.labels       or= []           # <Array<string>> list of labels to use as app name
+    options.version       ?= "1.0"        # <string> version
     options.route        or= {}           # <string> or <Object{slug: string, handler: function}>

     registerRoute = (route)=>


more annotation as to what's signed, etc

--- src/openpgp/packet/signature.iced
+++ src/openpgp/packet/signature.iced
@@ -97,8 +97,6 @@
         s.primary = @primary
         s.key = subkey.key
         await s._verify data_packets, defer err
-        unless err?
-          subkey.got_primary_binding = true
       else
         err = new Error "unknown subpacket signature type: #{s.type}"
     cb err
@@ -141,6 +139,7 @@
     unless err?
       err = @_check_key_sig_expiration()

+    # Now mark the object that was vouched for
     unless err?
       switch @type
         when T.issuer, T.personal, T.casual, T.positive
@@ -149,7 +148,11 @@
           userid = data_packets[1]?.get_userid()
           @key.self_sign = { @type, options, userid }
         when T.subkey_binding
-          data_packets[0].got_subkey_binding = true
+          subkey.signed = {} unless subkey.signed?
+          subkey.signed.primary_of_subkey = true
+        when T.primary_binding
+          subkey.signed = {} unless subkey.signed?
+          subkey.signed.subkey_of_primary = true
     cb err

   #-----------------


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -221,7 +221,7 @@
           yw = target.height/2
           return Collision.rayRectangle source, direction,
             x: target.x + xw
-            y: target.y +
+            y: target.y + yw
             xw: xw
             yw: yw
         else


CoffeeScript 1.1.1

CoffeeScript 1.1.1

--- coffee-script.coffee
+++ coffee-script.coffee
@@ -21,7 +21,7 @@
   require.registerExtension '.coffee', (content) -> compile content

 # The current CoffeeScript version number.
-exports.VERSION = '1.1.0'
+exports.VERSION = '1.1.1'

 # Words that cannot be used as identifiers in CoffeeScript code
 exports.RESERVED = RESERVED