Added news

Added news

--- server/materials/data/news.coffee
+++ server/materials/data/news.coffee
@@ -3,6 +3,9 @@

 export default allNews = () ->
     return news([
+        newsItem("21 апреля занятия в лицее не будет", String.raw"""
+            21 апреля занятия в лицее 40 не будет. Занимайтесь из дома..
+        """),
         newsItem("Олимпиада им. В. Д. Лелюха", String.raw"""
             Добавлена информация про Нижегородскую олимпиаду школьников по информатике им. В. Д. Лелюха.
         """),


collision with regular bounds

collision with regular bounds

--- test/collision.coffee
+++ test/collision.coffee
@@ -49,6 +49,6 @@

 test "Collision.rayRectangle", ->
   rect = GameObject
-
+    x:
 module()


collision with regular bounds

collision with regular bounds

--- test/collision.coffee
+++ test/collision.coffee
@@ -61,4 +61,5 @@

   equals p1.y, 0

+
 module()


robots.txt: allow calculus tutorial project to be indexed

--- src/smc-hub/hub_http_server.coffee
+++ src/smc-hub/hub_http_server.coffee
@@ -105,6 +105,7 @@
         res.header('Cache-Control', 'private, no-cache, must-revalidate')
         res.write('''
                   User-agent: *
+                  Allow: /projects/487587b1-8b24-401a-92d9-a9b930edd53d/
                   Disallow: /projects/*
                   Disallow: /*/raw/
                   Disallow: /*/port/


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/expirable.coffee
+++ test/expirable.coffee
@@ -27,6 +27,6 @@
   5.times ->
     obj.update()

-  equals obj.I.alpha, 0.8 - ((obj.I.age / obj.I.duration) * 0.8)
+  equals obj.I.alpha, 0.8 *  - ((obj.I.age / obj.I.duration) * 0.8)

 module()


pass more function tests

pass more function tests

--- test/functions.coffee
+++ test/functions.coffee
@@ -39,36 +39,36 @@

   suite 'Bound Function Definition', ->

-    #test 'basic bound functions', ->
-    #  obj = {
-    #    bound: ->
-    #      (=> this)()
-    #    unbound: ->
-    #      (-> this)()
-    #    nested: ->
-    #      (=>
-    #        (=>
-    #          (=> this)()
-    #        )()
-    #      )()
-    #  }
-    #  eq obj, obj.bound()
-    #  ok obj isnt obj.unbound()
-    #  eq obj, obj.nested()
+    test 'basic bound functions', ->
+      obj = {
+        bound: ->
+          (=> this)()
+        unbound: ->
+          (-> this)()
+        nested: ->
+          (=>
+            (=>
+              (=> this)()
+            )()
+          )()
+      }
+      eq obj, obj.bound()
+      ok obj isnt obj.unbound()
+      eq obj, obj.nested()

-    #test "fancy bound functions", ->
-    #  obj = {
-    #    one: ->
-    #      do =>
-    #        return this.two()
-    #    two: ->
-    #      do =>
-    #        do =>
-    #          do =>
-    #            return this.three
-    #    three: 3
-    #  }
-    #  eq obj.one(), 3
+    test "fancy bound functions", ->
+      obj = {
+        one: ->
+          do =>
+            return this.two()
+        two: ->
+          do =>
+            do =>
+              do =>
+                return this.three
+        three: 3
+      }
+      eq obj.one(), 3

     test "#1844: bound functions in nested comprehensions causing empty var statements", ->
       a = ((=>) for a in [0] for b in [0])
@@ -77,50 +77,51 @@

   suite 'Parameter List Features', ->

-    #test "splats", ->
-    #  arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
-    #  arrayEq [2, 3], (((_, _1, splat...) -> splat) 0, 1, 2, 3)
-    #  arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3)
-    #  arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3)
+    test "splats", ->
+      arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
+      arrayEq [2, 3], (((_, _1, splat...) -> splat) 0, 1, 2, 3)
+      arrayEq [0, 1], (((splat..., _, _1) -> splat) 0, 1, 2, 3)
+      arrayEq [2], (((_, _1, splat..., _2) -> splat) 0, 1, 2, 3)

-    #test "destructured splatted parameters", ->
-    #  arr = [0,1,2]
-    #  splatArray = ([a...]) -> a
-    #  splatArrayRest = ([a...],b...) -> arrayEq(a,b); b
-    #  arrayEq splatArray(arr), arr
-    #  arrayEq splatArrayRest(arr,0,1,2), arr
+    test "destructured splatted parameters", ->
+      arr = [0,1,2]
+      splatArray = ([a...]) -> a
+      splatArrayRest = ([a...],b...) -> arrayEq(a,b); b
+      arrayEq splatArray(arr), arr
+      arrayEq splatArrayRest(arr,0,1,2), arr

+    # FAIL - PARTIAL
     test "@-parameters: automatically assign an argument's value to a property of the context", ->
       nonce = {}

       ((@prop) ->).call context = {}, nonce
       eq nonce, context.prop

-      #((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
-      #eq nonce, context.prop
+      ((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
+      eq nonce, context.prop

-      #((@prop...) ->).call context = {}, 0, nonce, 0
-      #eq nonce, context.prop[1]
+      ((@prop...) ->).call context = {}, 0, nonce, 0
+      eq nonce, context.prop[1]

       eq 0, ((@prop) -> @prop).call {}, 0
-      # FAIL - LS is as CS 1, but redux is different
+      # LS is as CS 1, but redux is different
       # eq 'undefined', ((@prop) -> typeof prop).call {}, 0

-    #test "@-parameters and splats with constructors", ->
-    #  a = {}
-    #  b = {}
-    #  class Klass
-    #    constructor: (@first, splat..., @last) ->
-    #
-    #  obj = new Klass a, 0, 0, b
-    #  eq a, obj.first
-    #  eq b, obj.last
+    test "@-parameters and splats with constructors", ->
+      a = {}
+      b = {}
+      class Klass
+        constructor: (@first, splat..., @last) ->

-    #test "destructuring splats", ->
-    #  (([{a: [b], c}]...) ->
-    #    eq 1, b
-    #    eq 2, c
-    #  ) {a: [1], c: 2}
+      obj = new Klass a, 0, 0, b
+      eq a, obj.first
+      eq b, obj.last
+
+    test "destructuring splats", ->
+      (([{a: [b], c}]...) ->
+        eq 1, b
+        eq 2, c
+      ) {a: [1], c: 2}

     test "default values", ->
       nonceA = {}
@@ -159,13 +160,13 @@
       eq nonceB, obj.f nonceB, nonceA
       eq nonceA, obj.p

-    #test "default values with splatted arguments", ->
-    #  withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
-    #  eq 30, withSplats()
-    #  eq 15, withSplats(1)
-    #  eq  5, withSplats(1,1)
-    #  eq  1, withSplats(1,1,1)
-    #  eq  2, withSplats(1,1,1,1)
+    test "default values with splatted arguments", ->
+      withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
+      eq 30, withSplats()
+      eq 15, withSplats(1)
+      eq  5, withSplats(1,1)
+      eq  1, withSplats(1,1,1)
+      eq  2, withSplats(1,1,1,1)

     test "default values with function calls", ->
       counter = 0


Minor: shorten a long line in the tests

Minor: shorten a long line in the tests

--- test/humanizer.coffee
+++ test/humanizer.coffee
@@ -56,7 +56,8 @@
     assert.equal h(540360012), "6 days, 6 hours"
     assert.equal h(540360012), "6 days, 6 hours"
     assert.equal h(540360012, largest: 3), "6 days, 6 hours, 6 minutes"
-    assert.equal h(540360012, largest: 100), "6 days, 6 hours, 6 minutes, 0.012 seconds"
+    assert.equal h(540360012, largest: 100),
+                 "6 days, 6 hours, 6 minutes, 0.012 seconds"

   it "has properties which can be modified", ->
     h = humanizer()


fixed simpleDriver

fixed simpleDriver

--- test/legacy/driver/simpleDriver.mocha.coffee
+++ test/legacy/driver/simpleDriver.mocha.coffee
@@ -21,7 +21,7 @@

 describe "simple driver", ->
   it "introspects", (testComplete) ->
-    wikiDriver.introspect null, (err, attributes) ->
+    wikiDriver.introspect(null).then((attributes) ->
       expect(attributes).to.deep.equal([
         {
           "name": "added",
@@ -90,19 +90,20 @@
         }
       ])
       testComplete()
+    ).done()

   it "computes the correct count", (testComplete) ->
     querySpec = [
       { operation: 'apply', name: 'Count', aggregate: 'count' }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         prop: {
           Count: 53940
         }
       })
       testComplete()
+    ).done()

   it "does a split", (testComplete) ->
     querySpec = [
@@ -110,8 +111,7 @@
       { operation: 'apply', name: 'Count', aggregate: 'count' }
       { operation: 'combine', method: 'slice', sort: { prop: 'Count', compare: 'natural', direction: 'descending' }, limit: 2 }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {},
         "splits": [
@@ -130,6 +130,7 @@
         ]
       })
       testComplete()
+    ).done()

   it "does a sort-by-delta after split", (testComplete) ->
     querySpec = [
@@ -196,8 +197,7 @@
         limit: 4
       }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {},
         "splits": [
@@ -228,6 +228,7 @@
         ]
       })
       testComplete()
+    ).done()

   it "does two splits with segment filter", (testComplete) ->
     querySpec = [
@@ -247,8 +248,7 @@
       { operation: 'apply', name: 'Count', aggregate: 'count' }
       { operation: 'combine', method: 'slice', sort: { compare: 'natural', prop: 'Count', direction: 'descending' }, limit: 2 }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {},
         "splits": [
@@ -281,31 +281,32 @@
         ]
       })
       testComplete()
+    ).done()

   it "does handles nothingness", (testComplete) ->
     querySpec = [
       { operation: 'filter', type: 'false' }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {}
       })
       testComplete()
+    ).done()

   it "does handles nothingness with apply", (testComplete) ->
     querySpec = [
       { operation: 'filter', type: 'false' }
       { operation: 'apply', name: 'Count', aggregate: 'count' }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {
           "Count": 0
         }
       })
       testComplete()
+    ).done()

   it "does handles nothingness with split", (testComplete) ->
     querySpec = [
@@ -316,8 +317,7 @@
       { operation: 'apply', name: 'Count', aggregate: 'count' }
       { operation: 'combine', method: 'slice', sort: { prop: 'Count', compare: 'natural', direction: 'descending' }, limit: 2 }
     ]
-    diamondsDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    diamondsDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {
           "Count": 0
@@ -325,46 +325,47 @@
         "splits": []
       })
       testComplete()
+    ).done()

   it "does a maxTime query", (testComplete) ->
     querySpec = [
       { operation: 'apply', name: 'Max', aggregate: 'max', attribute: 'time' }
     ]
-    wikiDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    wikiDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         prop: {
           Max: 1361919600000 # ToDo: make this a date
         }
       })
       testComplete()
+    ).done()

   it "does a minTime query", (testComplete) ->
     querySpec = [
       { operation: 'apply', name: 'Min', aggregate: 'min', attribute: 'time' }
     ]
-    wikiDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    wikiDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         prop: {
           Min: 1361836800000 # ToDo: make this a date
         }
       })
       testComplete()
+    ).done()

   it "filters on a numeric dimension", (testComplete) ->
     querySpec = [
       { operation: 'filter', type: 'contains', attribute: 'robot', value: '1' }
       { operation: 'apply', name: 'Count', aggregate: 'count' }
     ]
-    wikiDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    wikiDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {
           "Count": 19106
         }
       })
       testComplete()
+    ).done()

   it "splits on time correctly", (testComplete) ->
     timeData = [
@@ -384,8 +385,7 @@
       { operation: 'combine', method: 'slice', sort: { compare: 'natural', prop: 'Time', direction: 'ascending'} }
     ]

-    timeDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    timeDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {},
         "splits": [
@@ -464,6 +464,7 @@
         ]
       })
       testComplete()
+    ).done()

   it "splits identity correctly", (testComplete) ->
     querySpec = [
@@ -512,8 +513,7 @@
       }
     ]

-    wikiDriver { query: FacetQuery.fromJS(querySpec) }, (err, result) ->
-      expect(err).to.not.exist
+    wikiDriver({ query: FacetQuery.fromJS(querySpec) }).then((result) ->
       expect(result.toJS()).to.deep.equal({
         "prop": {},
         "splits": [
@@ -532,6 +532,7 @@
         ]
       })
       testComplete()
-
-
-
+    ).done()
+
+
+


Move replacing placeholder to a method

Move replacing placeholder to a method

--- src/trix/models/composition.coffee
+++ src/trix/models/composition.coffee
@@ -48,6 +48,14 @@
     @document.insertPlaceholderBlockAtLocationRange(range)
     @setLocationRange(index: range.end.index + 1, offset: 0)

+  replacePlaceholderBlock: ->
+    range = @getLocationRange()
+    return unless @document.getBlockAtIndex(range.end.index).isPlaceholder()
+    @selectionDelegate?.expandSelectionInDirectionWithGranularity("forward", "character")
+    range = @getLocationRange()
+    @document.insertPlaceholderBlockAtLocationRange(range)
+    @setLocationRange(range.start)
+
   insertDocument: (document) ->
     @notifyDelegateOfIntentionToSetLocationRange()
     range = @getLocationRange()
@@ -67,9 +75,7 @@
     switch
       when block.isPlaceholder()
         if block.hasAttributes()
-          @selectionDelegate?.expandSelectionInDirectionWithGranularity("forward", "character")
-          @document.insertPlaceholderBlockAtLocationRange(@getLocationRange())
-          @setLocationRange(range.end)
+          @replacePlaceholderBlock()
         else
           @insertPlaceholderBlock()
       when range.end.offset is block.getLength()


Fix issue with `placeDetails` being undefined

--- src/typeahead-addresspicker.coffee
+++ src/typeahead-addresspicker.coffee
@@ -98,7 +98,7 @@
     # to update marker position and map center/zoom for a specific Google Map place
     updateMap: (event, place) =>
       # Send place reference to place service to get geographic information
-      if @placeDetails
+      if @options.placeDetails
         @placeService.getDetails place, (response) =>
           @lastResult = new AddressPickerResult(response)
           if @marker


x axis ticks as frequent as need be

x axis ticks as frequent as need be

--- src/modules/graph.coffee
+++ src/modules/graph.coffee
@@ -90,12 +90,11 @@
         y = d3.scale.linear().range([ height, 0 ])

         xAxis = d3.svg.axis().scale(x)
+        .orient("bottom")
         # Show vertical lines...
         .tickSize(-height)
         # ...with day of the month...
         .tickFormat( (d) -> d.getDate() )
-        # ...once per day...
-        .ticks(d3.time.hours, 24)
         # ...and give us a spacer.
         .tickPadding(10)


Fixing handling of line datasets.

Fixing handling of line datasets.

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -67,7 +67,7 @@
             @options.height = @svg[0][0].clientHeight

         @options.brush ||= {}
-        @options.brush.start || = @options.start
+        @options.brush.start ||= @options.start
         @options.brush.end ||= new Date(new Date(@options.brush.start).setDate(@options.brush.start.getDate() + 3))
         @options.debounce ||= 50
         @options.ticksize ||= 3
@@ -424,7 +424,7 @@
             .datum(data)
             .attr("class", "line")
             .attr("d", line)
-            .attr('stroke', color)
+            .attr('stroke', dataset.color)
             .attr('stroke-width', "1.5px")
             .attr('fill', 'none')
             .attr('transform', "translate(0,"+ (-@options.height+29)+")")
@@ -492,38 +492,41 @@
             finalRecords = []
             finalPaths = []

-            for record in records
-
-                if record instanceof Date
-                    record = [ record, record ]
-
-                else if not (record[1] instanceof Date)
-                    record = [ record[0], record[0] ].concat(record[1..])
-
-                # TODO: implement other data conversions
-
-                finalRecords.push(record)
-
-                # if record[0] instanceof Date and record[1] instanceof Date
-                #     ranges.push(record)
-                # else
-                #     points.push(record)
-
-                # TODO: implement paths
-
-                # if Array.isArray(record)
-                #     if record.length == 3
-                #         paths.push(record)
-                #     else
-                #         ranges.push(record)
-                # else if record instanceof Date
-                #     points.push(record)
-
-                # # TODO: keep this?
-                # else if record.split("/").length > 1
-                #     elements = record.split("/")
-                #     elements.pop()
-                #     ranges.push(elements)
+            if !dataset.lineplot
+                for record in records
+                    if record instanceof Date
+                        record = [ record, record ]
+
+                    else if not (record[1] instanceof Date)
+                        record = [ record[0], record[0] ].concat(record[1..])
+
+                    # TODO: implement other data conversions
+
+                    finalRecords.push(record)
+
+                    # if record[0] instanceof Date and record[1] instanceof Date
+                    #     ranges.push(record)
+                    # else
+                    #     points.push(record)
+
+                    # TODO: implement paths
+
+                    # if Array.isArray(record)
+                    #     if record.length == 3
+                    #         paths.push(record)
+                    #     else
+                    #         ranges.push(record)
+                    # else if record instanceof Date
+                    #     points.push(record)
+
+                    # # TODO: keep this?
+                    # else if record.split("/").length > 1
+                    #     elements = record.split("/")
+                    #     elements.pop()
+                    #     ranges.push(elements)
+            else
+                # TODO: perform check of records
+                finalPaths = records

             dataset.setRecords(finalRecords)
             dataset.setPaths(finalPaths)
@@ -745,5 +748,6 @@
 class Source
     fetch: (start, end, params, callback) ->

+TimeSlider.Plugin = {}

 module.exports = TimeSlider


#46 ga event

#46 ga event

--- meteor/client/router.coffee
+++ meteor/client/router.coffee
@@ -1,15 +1,17 @@
 Router.route '/', ->
   if location.hash
     Router.go '/' + location.hash.slice(1)
-
   @render 'home'
   mtrPlayer.setChannel ''
+  _gaq.push ['_trackPageview']

 Router.route '/:channel', ->
   channel = @params.channel
   mtrPlayer.setChannel channel
   document.title = channel + ' | radio.meteor.com'
   @render 'channel'
+  _gaq.push ['_trackPageview']
+

 Router.configure
   layoutTemplate: 'AppLayout'


Implemented error proxy

Implemented error proxy

--HG--
branch : feature/error-proxy

--- spec/core/EventMessageSpec.coffee
+++ spec/core/EventMessageSpec.coffee
@@ -177,7 +177,7 @@

 			proxyFunc = msg.proxyErrors handler
 			msg.status = "error"
-			msg.error = new Error "Error"
+			msg.error = "Error"
 			msgNoReply.status = "error"
 			msgNoReply.error = "Error"
 			# No reply should throw the exception directly.
@@ -191,8 +191,7 @@
 				expect(replier.callCount).toBe 1
 				expect(handler.callCount).toBe 0
 				reply = replier.getCall(0).args[0]
-				expect(reply.status).toBe "error"
-				expect(reply.error).toBe "Error"
+				expect(reply).toBe msg

 		it "should propagate reply errors unless it has a reply handler", ->
 			# reply has an error
@@ -222,18 +221,20 @@
 			# msg.proxy (reply) =>
 			handler = sinon.spy -> throw new Error "Error"
 			# No reply should throw the exception directly.
-			testNoReply = -> msgNoReply.proxyErrors handler
+			proxyFuncNoReply = msgNoReply.proxyErrors handler
+			testNoReply = -> proxyFuncNoReply new EventMessage
 			expect(testNoReply).toThrow "Error"
 			expect(handler.callCount).toBe 1
 			# With reply handler should pass the error along.
-			msg.proxyErrors handler
+			proxyFunc = msg.proxyErrors handler
+			proxyFunc new EventMessage
 			waitsFor (-> replier.called), "Replier never called", 100
 			runs ->
 				expect(replier.callCount).toBe 1
-				expect(handler.callCount).toBe 1
+				expect(handler.callCount).toBe 2
 				reply = replier.getCall(0).args[0]
 				expect(reply.status).toBe "error"
-				expect(reply.error).toBe "Error"
+				expect(reply.error.split("\n")[0]).toBe "Error: Error :: Error: Error"

 	describe "callback proxy", ->
 		it "should propagate own errors unless it has a reply handler"


:lipstick: Wording

:lipstick: Wording

--- spec/editor-component-spec.coffee
+++ spec/editor-component-spec.coffee
@@ -447,7 +447,7 @@
         expect(lineNumberHasClass(3, 'cursor-line')).toBe true
         expect(lineNumberHasClass(4, 'cursor-line')).toBe false

-      it "does not render a curslor-line decoration for the last empty selected line in a multiline selection", ->
+      it "does not render a cursor-line decoration for the last line of a multi-line selection of the selection ends at column 0", ->
         cursor.setScreenPosition([1, 0])
         editor.selectDown(2)
         expect(lineNumberHasClass(0, 'cursor-line')).toBe false


KDTokenizedInputView: put a space right after token element

--- components/inputs/KDTokenizedInputView.coffee
+++ components/inputs/KDTokenizedInputView.coffee
@@ -119,13 +119,15 @@
   addToken: (item, tokenViewClass = @getOptions().tokenViewClass) ->
     {type, prefix, pistachio} = @activeRule
     tokenView = new tokenViewClass {type, prefix, pistachio}, item
+    tokenElement = tokenView.getElement()

     tokenKey              = "#{tokenView.getId()}-#{tokenView.getKey()}"
     @tokenViews[tokenKey] = tokenView

     tokenView.setAttributes "data-key": tokenKey
-    @tokenInput.parentElement.insertBefore tokenView.getElement(), @tokenInput
+    @tokenInput.parentElement.insertBefore tokenElement, @tokenInput
     tokenView.emit "viewAppended"
+    @tokenInput.nextSibling.textContent = "\u00a0"
     @utils.selectText @tokenInput.nextSibling, 1
     @tokenInput.remove()


Use Range literals

Use Range literals

--- spec/text-editor-view-spec.coffee
+++ spec/text-editor-view-spec.coffee
@@ -748,7 +748,7 @@
     describe "when a selection changes", ->
       describe "when the selection is within a single line", ->
         it "covers the selection's range with a single region", ->
-          selection.setBufferRange(new Range({row: 2, column: 7}, {row: 2, column: 25}))
+          selection.setBufferRange([[2, 7], [2, 25]])

           expect(selectionView.regions.length).toBe 1
           region = selectionView.regions[0]
@@ -759,7 +759,7 @@

       describe "when the selection spans 2 lines", ->
         it "covers the selection's range with 2 regions", ->
-          selection.setBufferRange(new Range({row: 2, column: 7}, {row: 3, column: 25}))
+          selection.setBufferRange([[2,7],[3,25]])

           expect(selectionView.regions.length).toBe 2

@@ -777,7 +777,7 @@

       describe "when the selection spans more than 2 lines", ->
         it "covers the selection's range with 3 regions", ->
-          selection.setBufferRange(new Range({row: 2, column: 7}, {row: 6, column: 25}))
+          selection.setBufferRange([[2,7],[6,25]])

           expect(selectionView.regions.length).toBe 3

@@ -808,7 +808,7 @@
           expect(region3.width()).toBeCloseTo(25 * charWidth)

       it "clears previously drawn regions before creating new ones", ->
-        selection.setBufferRange(new Range({row: 2, column: 7}, {row: 4, column: 25}))
+        selection.setBufferRange([[2,7],[4,25]])
         expect(selectionView.regions.length).toBe 3
         expect(selectionView.find('.region').length).toBe 3

@@ -1713,7 +1713,7 @@
       editor.setCursorBufferPosition([4, 0])
       expect(editor.find('.cursor').offset()).toEqual(editor.renderedLines.find('.line:eq(5)').offset())

-      editor.getSelection().setBufferRange(new Range([6, 30], [6, 55]))
+      editor.getSelection().setBufferRange([[6, 30], [6, 55]])
       [region1, region2] = editor.getSelectionView().regions
       expect(region1.offset().top).toBeCloseTo(editor.renderedLines.find('.line:eq(7)').offset().top)
       expect(region2.offset().top).toBeCloseTo(editor.renderedLines.find('.line:eq(8)').offset().top)
@@ -2030,17 +2030,17 @@
         editor.attachToDom(30)

       it "highlights the foreground of the gutter", ->
-        editor.getSelection().setBufferRange(new Range([0,0],[2,2]))
+        editor.getSelection().setBufferRange([[0,0],[2,2]])
         expect(editor.getSelection().isSingleScreenLine()).toBe false
         expect(editor.find('.line-number.cursor-line').length).toBe 3

       it "doesn't highlight the background of the gutter", ->
-        editor.getSelection().setBufferRange(new Range([0,0],[2,0]))
+        editor.getSelection().setBufferRange([[0,0],[2,0]])
         expect(editor.getSelection().isSingleScreenLine()).toBe false
         expect(editor.find('.line-number.cursor-line.cursor-line-no-selection').length).toBe 0

       it "doesn't highlight the last line if it ends at the beginning of a line", ->
-        editor.getSelection().setBufferRange(new Range([0,0],[1,0]))
+        editor.getSelection().setBufferRange([[0,0],[1,0]])
         expect(editor.getSelection().isSingleScreenLine()).toBe false
         expect(editor.find('.line-number.cursor-line').length).toBe 1
         expect(editor.find('.line-number.cursor-line').intValue()).toBe 1
@@ -2102,7 +2102,7 @@

     describe "when a fold-selection event is triggered", ->
       it "folds the lines covered by the selection into a single line with a fold class and marker", ->
-        editor.getSelection().setBufferRange(new Range([4, 29], [7, 4]))
+        editor.getSelection().setBufferRange([[4,29],[7,4]])
         editor.trigger 'editor:fold-selection'

         expect(editor.renderedLines.find('.line:eq(4)')).toHaveClass('fold')
@@ -2113,7 +2113,7 @@
         expect(editor.getCursorScreenPosition()).toEqual [5, 0]

       it "keeps the gutter line and the editor line the same heights (regression)", ->
-        editor.getSelection().setBufferRange(new Range([4, 29], [7, 4]))
+        editor.getSelection().setBufferRange([[4,29],[7,4]])
         editor.trigger 'editor:fold-selection'

         expect(editor.gutter.find('.line-number:eq(4)').height()).toBe editor.renderedLines.find('.line:eq(4)').height()


test: Add test for server-side emit-with-ack.

--- tests/sockets.coffee
+++ tests/sockets.coffee
@@ -70,6 +70,23 @@
       t.reached 'acked'
       t.equal 'data', data.foo, 'bar'

+  'client ack': (t) ->
+    t.expect 'got-foo', 'acked', 'data'
+    t.wait 10000
+
+    zapp = zappa port++, ->
+      @on connection: ->
+        @emit 'foo', bar:'foo', (data) ->
+          t.reached 'acked'
+          t.equal 'data', data.foo, 'bar'
+
+    c = t.client(zapp.server)
+    c.connect()
+
+    c.on 'foo', (data,ack) ->
+      t.reached 'got-foo'
+      ack foo:'bar'
+
   'server rooms': (t) ->
     t.expect 'joined1', 'room1', 'joined2', 'room2',
       'reached1', 'reached2', 'data1', 'data2'


Login: change object name to cookies

Login: change object name to cookies

--- client/Main/maincontroller/maincontroller.coffee
+++ client/Main/maincontroller/maincontroller.coffee
@@ -138,11 +138,11 @@
       cookie = $.cookie 'clientId'

       if cookieExists and not cookieMatches
-        KD.logToExternal "cookie changes", {cookies:cookieChanges, username:KD.nick()}
+        KD.logToExternal "cookie changes", {stackTraces:cookieChanges, username:KD.nick()}

         return @isLoggingIn off  if @isLoggingIn() is on

-        KD.logToExternal "cookie changes", {cookies:cookieChanges, username:KD.nick(), inlogin:true}
+        KD.logToExternal "cookie changes", {stackTraces:cookieChanges, username:KD.nick(), inlogin:true}

         window.removeEventListener 'beforeunload', wc.bound 'beforeUnload'
         @emit "clientIdChanged"


Onboarding: Added cancel button and its event.

--- client/Main/onboarding/onboardingitemview.coffee
+++ client/Main/onboarding/onboardingitemview.coffee
@@ -1,4 +1,4 @@
-class OnboardingItemView extends JView
+class OnboardingItemView extends KDView

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

@@ -32,7 +32,6 @@
       console.warn "Path parse error for onboarding item", { appName, itemName, e }

   createContextMenu: ->
-    delegate       = this
     @contextMenu   = new JContextMenu
       cssClass     : "onboarding-wrapper"
       sticky       : yes
@@ -52,11 +51,14 @@

   createContentView: ->
     {title, content} = @getData()
-    @overlay       = new KDOverlayView    { isRemovable : no                        }
-    title          = new KDCustomHTMLView { tagName     : "h3"  , partial : title   }
-    content        = new KDCustomHTMLView { tagName     : "p"   , partial : content }
-    buttonsWrapper = new KDCustomHTMLView { cssClass    : "buttons"                 }
-    view           = new KDCustomHTMLView { cssClass    : "onboarding-item"         }
+    @overlay       = new KDSpotlightView  { isRemovable : no,   delegate : @parentElement }
+    title          = new KDCustomHTMLView { tagName     : "h3", partial  : title          }
+    content        = new KDCustomHTMLView { tagName     : "p" , partial  : content        }
+    buttonsWrapper = new KDCustomHTMLView { cssClass    : "buttons"                       }
+    view           = new KDCustomHTMLView { cssClass    : "onboarding-item"               }
+    closeButton    = new KDCustomHTMLView
+      cssClass     : "close-icon"
+      click        : => @emit "OnboardingCancelled"

     if @hasPrev
       prevButton   = new KDButtonView
@@ -88,7 +90,7 @@
     for child in [ prevButton, nextButton, doneButton, stepsWrapper ] when child
       buttonsWrapper.addSubView child

-    for child in [ title, content, buttonsWrapper ] when child
+    for child in [ title, content, buttonsWrapper, closeButton ] when child
       view.addSubView child

     return view
@@ -105,10 +107,17 @@

   listenEvents: ->
     @on "NavigationRequested", (direction) =>
-      @overlay?.destroy()
-      @contextMenu.destroy()
+      @destroy()
       @getDelegate().emit "NavigationRequested", direction, @getData()

     @on "OnboardingCompleted", =>
-      @overlay?.destroy()
-      @contextMenu.destroy()
+      @destroy()
+
+    @on "OnboardingCancelled", =>
+      @destroy()
+
+
+  destroy: ->
+    super
+    @overlay?.destroy()
+    @contextMenu.destroy()


Onboarding: Disable scrolling and destroy views on ESC key pressed.

--- client/Main/onboarding/onboardingitemview.coffee
+++ client/Main/onboarding/onboardingitemview.coffee
@@ -45,9 +45,13 @@
     , customView       : @createContentView()

     @contextMenu.on "viewAppended", =>
+      @contextMenu.once "KDObjectWillBeDestroyed", =>
+        @destroy()
+
       KD.utils.defer =>
         left = @parentElement.getX() - @contextMenu.getX() + 10
         @contextMenu.arrow.setCss "left", left
+        $("body").addClass "noscroll"

   createContentView: ->
     {title, content} = @getData()
@@ -128,6 +132,7 @@
     super
     @overlay?.destroy()
     @contextMenu.destroy()
+    $("body").removeClass "noscroll"

 class OnboardingContextMenu extends JContextMenu


Tests: Fix failed test steps

Tests: Fix failed test steps

--- client/app/test/kodinglistcontroller.test.coffee
+++ client/app/test/kodinglistcontroller.test.coffee
@@ -17,7 +17,7 @@

       {
         useCustomScrollView, lazyLoadThreshold, limit,
-        sort, model, fetcherMethod, type
+        sort, model, fetcherMethod
       } = listController.getOptions()

       viewInstanceCheck = listController.getListView() instanceof KodingListView
@@ -27,19 +27,16 @@
       expect(lazyLoadThreshold).toBe 10
       expect(limit).toBe 10
       expect(model).toNotExist()
-      expect(type).toEqual ''
       expect(sort).toEqual { '_id' : -1 }

     it 'should create default no item found widget', ->

-      type = 'machine'
-
-      listController = new KodingListController { type, fetcherMethod : kd.noop }
+      listController = new KodingListController { fetcherMethod : kd.noop }

       { noItemFoundWidget, noItemFoundText } = listController.getOptions()

       expect(noItemFoundWidget).toExist()
-      expect(noItemFoundText).toEqual "You don't have any #{type}"
+      expect(noItemFoundText).toEqual "No item found!"

     it 'should create no item found widget with given text', ->


Clean

Clean

--- client/components/autocomplete_list/index.coffee
+++ client/components/autocomplete_list/index.coffee
@@ -37,7 +37,7 @@
     div { ref: 'container' },
       (
         for item in @state.items
-          div { className: 'autocomplete-select-selected  edit-admin-autocomplete-list-item' }, item.value,
+          div { className: 'autocomplete-select-selected' }, item.value,
             input { type: 'hidden', value: item.id, name: @props.name }
             button { className: 'autocomplete-select-remove', onClick: @removeItem(item) }
       )


implemented detached tabs feature

implemented detached tabs feature

--- gem/vendor/assets/javascripts/angular-tabs.js.coffee
+++ gem/vendor/assets/javascripts/angular-tabs.js.coffee
@@ -1,63 +1,92 @@
 angular.module "angular-tabs", []

 angular.module("angular-tabs").service "angularTabs", [() ->
-  angularTabInstances = {}
+  activeTabs = {}
   {
     getActiveTab: (id) ->
-      angularTabInstances[id]
+      activeTabs[id]
     setActiveTab: (id, title) ->
-      angularTabInstances[id] = title
+      activeTabs[id] = title
+
   }
 ]

-angular.module("angular-tabs").directive "angularTabs", ["angularTabs", (angularTabs) ->
+angular.module("angular-tabs").directive "angularTabs", ["$compile", "angularTabs", ($compile, angularTabs) ->
+
+  compileTabsBody = (divs) ->
+    titles = []
+
+    for div in divs
+      div = angular.element(div)
+      title = div.attr("title")
+      titles.push title
+      div.attr("ng-show", "isActive('#{title}')")
+
+    titles
+
+  createControl = (classes, titles) ->
+    tabs = angular.element("

")
+
+    if not classes
+      tabs.addClass("nav")
+      tabs.addClass("nav-tabs")
+    else
+      tabs.addClass classes
+
+    for title in titles
+      tabs.append createTab(title)
+
+    tabs
+
+  createTab = (title) ->
+    li = angular.element("

")
+    li.attr("ng-class", "{active: isActive('#{title}')}")
+
+    li.append a = angular.element("#{title}")
+    a.attr("href", "")
+    a.attr("ng-click", "setActive('#{title}')")
+
+    li
+
   {
     restrict: "E"
     scope: true
     compile: (element, attributes, transclude) ->

-      tabs = angular.element("

")
-      tabs.addClass("nav")
-      tabs.addClass("nav-tabs")
+      id = attributes.id
+      divs =  element.children("div")
+      titles = compileTabsBody(divs)
+      tabControls = angular.element("angular-tabs-control[for=#{id}]")

-      divs =  element.children("div")
-      for i in [0..divs.length - 1]
-        div = angular.element(divs[i])
-        title = div.attr("title")
-        if not title
-          title = i
-
-        div.attr("ng-show", "tabIsActive('#{title}')")
-
-        li = angular.element("

")
-        li.attr("ng-class", "{active: tabIsActive('#{title}')}")
-
-        a = angular.element("#{title}")
-        a.attr("href", "")
-
-        a.attr("ng-click", "setActiveTab('#{title}')")
-
-        li.append a
-
-        tabs.append li
-
-      element.prepend tabs
+      if tabControls.length <= 0
+        control = createControl attributes.class, titles
+        element.prepend control

       {
         post: ($scope, $element, $attributes) ->

-          id = $attributes.id
-          activeTab = $attributes.activeTab
+          # Create additional tab controls if required.
+          # The resulting element needs to be compiled.
+          # It is not compiled by the compile function because the control
+          # is not a child of element but located somewhere else in the DOM.
+          # We can't call the compile service in the compile function,
+          # because we don't have a scope there.
+          if tabControls.length > 0
+            for tabControl in tabControls
+              tabControl = angular.element(tabControl)
+              control = createControl tabControl.attr("class"), titles
+              $compile(control)($scope)
+              tabControl.append control

-          $scope.setActiveTab = (title) ->
-            $scope.activeTab = title
+          $scope.setActive = (title) ->
             angularTabs.setActiveTab id, title

-          $scope.tabIsActive = (title) ->
-            return ($scope.activeTab == title)
+          $scope.isActive = (title) ->
+            return (angularTabs.getActiveTab(id) == title)

-          $scope.setActiveTab(activeTab)
+          $scope.setActive($attributes.activeTab)

+          return
       }

   }


fix mail service config

fix mail service config

--- server/mail.coffee
+++ server/mail.coffee
@@ -58,7 +58,7 @@
   # also takes opts.attachments, but not required. Should be a list of objects as per
   # https://github.com/nodemailer/mailcomposer/blob/7c0422b2de2dc61a60ba27cfa3353472f662aeb5/README.md#add-attachments

-  ms = API.settings.service?[opts.service?]?.mail ? API.settings.mail
+  ms = if opts.service? and API.settings.service?[opts.service]?.mail? then API.settings.service[opts.service].mail else API.settings.mail
   delete opts.service
   opts.from ?= ms.from
   opts.to ?= ms.to


fixing tests

fixing tests

--- test/spec/util.coffee
+++ test/spec/util.coffee
@@ -48,10 +48,10 @@
         assert.isFalse util.isNode(comment), "Comment isnt node"

         fragment = document.createDocumentFragment('div')
-        assert.isFalse util.isNode(fragment), "Fragment is node"
+        assert.isTrue util.isNode(fragment), "Fragment is node"

-        text = document.createText('hi')
-        assert.isFalse util.isNode(text), "Text is node"
+        text = document.createTextNode('hi')
+        assert.isTrue util.isNode(text), "Text is node"

     test 'isNodeList', ->
         assert.isFalse util.isNodeList(false), "False isnt node list"


expose method to get chaptersection of exercise

--- src/flux/exercise.coffee
+++ src/flux/exercise.coffee
@@ -133,6 +133,9 @@
         @_unsavedExclusions[exerciseId]
       else
         @_exerciseCache[exerciseId]?.is_excluded
+
+    getChapterSectionOfExercise: (exercise) ->
+      getChapterSection(exercise)

     getGroupedIncludedExercises: (pageIds) ->
       exercises = @_exercises[pageIds.toString()]


fix(container): fixed _add fn for containers

--- src/lib/containable.coffee
+++ src/lib/containable.coffee
@@ -64,15 +64,17 @@

   ObservableArray self, name, items

-  self[name + '_add'] = (params = {}) =>
+  self[name + '_add'] = (params = {}, callback) =>
     c = container_fn(params)

     if c.after_create?
       c.after_create()
     if c.before_create?
       c.before_create()
+    if callback?
+      callback(c)

-    params = m.export(false, true)
+    params = c.export(false, true)

     self[name].push c
     c.__updated.subscribe =>


Use same branch name for pending or unpending greyhounds


nonhomepageheader for onchain

nonhomepageheader for onchain

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -2488,6 +2488,7 @@
     slider_pole_labels: interested

+
   HomepageHeader: ReactiveComponent
     displayName: 'HomepageHeader'

@@ -2500,6 +2501,7 @@
           backgroundColor: '#272727'
           overflow: 'hidden'
           paddingBottom: 60
+          height: if !homepage then 200
           # height: 63
           # borderBottom: '1px solid #ddd'
           # boxShadow: '0 1px 2px rgba(0,0,0,.1)'
@@ -2545,9 +2547,9 @@
               position: 'absolute'
               left: 0
               top: 0
-              height: '64%'
+              height: if homepage then '64%' else '100%'
               width: '100%'
-              background: 'linear-gradient(to bottom, rgba(0,0,0,.97) 0%,rgba(0,0,0,0.65) 70%,rgba(0,0,0,0) 100%)'
+              background: if homepage then 'linear-gradient(to bottom, rgba(0,0,0,.97) 0%,rgba(0,0,0,0.65) 70%,rgba(0,0,0,0) 100%)' else 'rgba(0,0,0,.7)'
               zIndex: 2

           IMG
@@ -2555,7 +2557,7 @@
               position: 'absolute'
               zIndex: 1
               width: '160%'
-              top: 45
+              top: 0 #45
               left: '-30%'
             src: asset('bitcoin/rays.png')

@@ -2566,6 +2568,7 @@
               paddingTop: 13
               position: 'absolute'
               zIndex: 3
+              top: 65

             SPAN
               style:


added comment

added comment

Former-commit-id: 674a84bae1fd403f58a32f7e8856050afae5d053 [formerly 17ad5c05f4cfd52100839f1eb055d88e6be155cd] [formerly 10f5807b1fb227c5dce1b2d94de9f026cea6703a [formerly e1a287a08091c182bb5d622953fffaff1073273f]] [formerly 417477f51f4cfd1eaa69baeeae4beb2293f43560 [formerly 7007578e8c4ad31bdbfb06100bf3cff4d6a56e48] [formerly cfc77fb59fb523d81cc3887295eb128cf797eccc [formerly cfc77fb59fb523d81cc3887295eb128cf797eccc [formerly 981487eb82df0890326131b44aa81e5d1b58427d]]]]
Former-commit-id: 7366a35571f369c6accace10d63c7bde8ed2c116 [formerly 9a4a230f895298fa706e8f9abf8bc4ebf0084b76] [formerly ae59d3c6051176fa1a4d332e30e2d2f8ef24de25 [formerly d668d12f6cd81effd57b92b27ecb58891b513daa]]
Former-commit-id: ee850cfdcad0d08cc96bebd1153f1af3b193c37c [formerly facf5d892412fcb1368f831dca8562135d79fd97]
Former-commit-id: dd20f7ab85d9ceb6aaee45e7fee8daa9fa95031c
Former-commit-id: 886c06b7926e46bcf817fbecaac46f272f97783e

--- @client/models/opinion.coffee
+++ @client/models/opinion.coffee
@@ -25,7 +25,11 @@

       # @proposal = ConsiderIt.all_proposals.get @attributes.proposal_id

-
+    # SUBSUME: if a user published a previous opinion on this before,
+    # but is submitting a new opinion (e.g. if they saved their
+    # opinion, logged out, came back after a couple days, created a
+    # new opinion, hit “save opinion”, then login), then merge the two
+    # opinions.
     subsume : (other_pos) ->
       params =
         stance : if other_pos.get('stance') != 0 then other_pos.get('stance') else @get('stance')


Very exciting discovery: the from value is different between public and private messages.

--- src/hubot/hipchat.coffee
+++ src/hubot/hipchat.coffee
@@ -43,7 +43,8 @@
     bot.onError (message, stanza)->
       console.log "Received error from HipChat:", message, stanza
     bot.onMessage /^\s*@hubot\s/i, (channel, from, message)->
-      author = self.userForId(from.match(/_(\d+)@/)[1])
+      console.log from
+      author = self.userForName(from)
       author.room = channel
       self.receive new Robot.Message(author, message.replace(/^\s*@hubot\s+/, "Hubot: "))
     bot.onPrivateMessage (from, message)=>


Grab user list on startup.

Grab user list on startup.

Properly map users based on HipChat user_id and JID.

--- src/hubot/hipchat.coffee
+++ src/hubot/hipchat.coffee
@@ -7,12 +7,12 @@
   send: (user, strings...) ->
     console.log "Sending"
     strings.forEach (str) =>
-      @bot.message user.room || user.id, str
+      @bot.message user.room || user.jid, str

   reply: (user, strings...) ->
     console.log "Replying"
     strings.forEach (str) =>
-      @send user, "#{user.name}: #{str}"
+      @send user, "@#{user.name} #{str}"

   run: ->
     self = @
@@ -29,16 +29,26 @@
     bot.onConnect =>
       console.log "Connected to HipChat"
       @get "/v1/rooms/list", (err, response)->
-        response.rooms.forEach (room)->
-          bot.join room.xmpp_jid
+        if response
+          response.rooms.forEach (room)->
+            bot.join room.xmpp_jid
+        else
+          console.log "Can't list rooms: #{err}"
+      @get "/v1/users/list", (err, response)->
+        if response
+          response.users.forEach (user)->
+            self.userForId user.user_id, user
+        else
+          console.log "Can't list rooms: #{err}"
     bot.onError (message, stanza)->
       console.log "Received error from HipChat:", message, stanza
     bot.onMessage /^\s*@hubot\s/i, (channel, from, message)->
-      author = self.userForId(from)
+      author = self.userForId(from.match(/_(\d+)@/)[1])
       author.room = channel
       self.receive new Robot.Message(author, message.replace(/^\s*@hubot\s+/, "Hubot: "))
     bot.onPrivateMessage (from, message)=>
-      author = self.userForId(from)
+      author = self.userForId(from.match(/_(\d+)@/)[1])
+      author.jid = from
       self.receive new Robot.Message(author, "Hubot: #{message}")
     bot.connect()


Set min.max width also

Set min.max width also

--- vendor/assets/javascripts/chosen/chosen.js.coffee
+++ vendor/assets/javascripts/chosen/chosen.js.coffee
@@ -58,9 +58,11 @@
     classes.push "rtl" if @is_rtl
     classes.push @target.className if @inherit_classes and @target.className

+    width = if @width? then @width else "#{@target.offsetWidth}px"
+
     container_props =
       class: classes.join ' '
-      style: "width: #{if @width? then @width else "#{@target.offsetWidth}px"};"
+      style: "width: #{width}; min-width: #{width}; max-width: #{width}"

     container_props.title = @target.title if @target.title.length
     container_props.id = @target.id.replace(/[^\w]/g, '-') + "-chosen" if @target.id.length


fix: `opts.polling` changed to `opts[watch-polling]`

--- command.coffee
+++ command.coffee
@@ -213,17 +213,17 @@
     #
     # This is useful while watching remote directory.
     # Such as the `fs.watch` won't catch the SMB server's file change event.
-    if opts.polling
-      fs.watchFile source, { interval: parseInt(opts.polling) }, compile
+    if opts['watch-polling']
+      fs.watchFile source, { interval: parseInt(opts['watch-polling']) }, compile
     else
       watcher = fs.watch source, compile
   catch e
     watchErr e

   rewatch = ->
-    if opts.polling
+    if opts['watch-polling']
       fs.unwatchFile source
-      fs.watchFile source, { interval: parseInt(opts.polling) }, compile
+      fs.watchFile source, { interval: parseInt(opts['watch-polling']) }, compile
     else
       watcher?.close()
       watcher = fs.watch source, compile
@@ -240,7 +240,7 @@
           if err
             throw err unless err.code is 'ENOENT'

-            if opts.polling
+            if opts['watch-polling']
               fs.unwatchFile source
             else
               watcher.close()
@@ -253,8 +253,8 @@
             sourceCode.push null
             compilePath file, no, base

-    if opts.polling
-      fs.watchFile source, { interval: parseInt(opts.polling) }, compile
+    if opts['watch-polling']
+      fs.watchFile source, { interval: parseInt(opts['watch-polling']) }, compile
     else
       watcher = fs.watch source, compile


Make callback optional

Make callback optional

--- node_modules_koding/bongo/lib/bongo.coffee
+++ node_modules_koding/bongo/lib/bongo.coffee
@@ -256,7 +256,7 @@
     delete @consumerTag
     delete @readyState = 0
     delete @queue
-    callback null
+    callback? null

   revive:(data)->
     {models} = this


bongo: race-condition work-around

bongo: race-condition work-around

wait to fire the "connect" callback until the mongo connection has also succeeded.

--- node_modules_koding/bongo/lib/bongo.coffee
+++ node_modules_koding/bongo/lib/bongo.coffee
@@ -17,12 +17,9 @@
   url = require 'url'
   fs = require 'fs'
   nodePath = require 'path'
-  # bongo = new EventEmitter
-  # client-side boilerplate
-  #@client = bongoClient = require 'bongo-client'
-  # dnode           = require 'koding-dnode'
-  # contrib
+
   require 'colors'
+
   @mongo          = require 'mongodb'
   {extend}        = require 'underscore'
   @JsPath = JsPath = require 'jspath'
@@ -83,15 +80,6 @@
     @mq?.ready => @mq.connection?.on 'error', Bongo.throwIt
     @setMaxListeners 0
     @emit 'newInstance', this
-
-  initBlacklist:do ->
-    blacklister = (k, v)->
-      return  if k in @blacklist
-      return v
-    (@blacklist=[])->
-      if blacklist.length
-        @blacklisting = yes
-        @replacer = blacklister.bind @

   defineModel:(name, model)->
     @models[name] = model
@@ -257,7 +245,9 @@
     @presence.on 'leave', callbacks.leave if callbacks.leave?

   connect:(callback=->)->
-    @once 'connected', callback
+    @once 'connected', =>
+      if @dbClientReady then callback()
+      else @once 'dbClientReady', callback
     @mq.ready =>
       @establishPresence()
       exchangeOptions = {type:'fanout', autoDelete: yes}
@@ -309,11 +299,6 @@
         @update model, yes
       else
         @update node
-
-  # handleAuth:(secretName, sessionToken)->
-  #   @fetchBrokerExchange (brokerExchange)->
-  #     brokerExchange.publish
-  #   # @emit 'auth', secretName, sessionToken

   handleRequest:(secretName, message)->
     console.log message.green  if @verbose
@@ -406,13 +391,7 @@
       @fetchBrokerExchange (brokerExchange)=>
         brokerExchange.publish secretName, JSON.stringify(message, @replacer)

-  getMethodDescription:(name, konstructor)->
-    description = konstructor.getSharedMethods()
-    # description.options =
-    #   broadcastable   : konstructor.getBroadcastable?()
-    #   slugTemplate    : konstructor.slugTemplate
-    #   schema          : konstructor.describeSchema?()
-    description
+  getMethodDescription:(name, konstructor)-> konstructor.getSharedMethods()

   describeApi:(callback)->
     api = {}
@@ -441,6 +420,10 @@

   getClient:-> Model.getClient()

-  setClient:(rest...)-> Model.setClient rest...
+  setClient:(rest...)->
+    Model.setClient rest...
+    Model.on 'dbClientReady', =>
+      @dbClientReady = yes
+      @emit 'dbClientReady'

   use:(fn...)-> @stack.push fn...


remove annoying log

remove annoying log

--- node_modules_koding/bongo/lib/bongo.coffee
+++ node_modules_koding/bongo/lib/bongo.coffee
@@ -145,7 +145,6 @@
   connect:(callback)->
     @once 'connected', callback
     @mq.ready =>
-      console.log 'adadadadda'
       @mq.connection.queue @queueName, {autoDelete:no}, (@queue)=>
         @emit 'connected'
         queue


Some tweaks to the player module

Some tweaks to the player module

--- modules/player/index.coffee
+++ modules/player/index.coffee
@@ -22,7 +22,9 @@
     )()
     moment.duration(info.duration).asSeconds()/60

-    if (duration > 1000 and not @permissions.isAdmin msg.author, msg.server) or duration <= 0
+    if (duration > 1000 and not @permissions.isAdmin msg.author, msg.server) or
+       duration > 3600 and not @permissions.isOwner msg.author or
+       duration <= 0
       return @bot.reply msg, 'The requested song is too long. (or too short?)'

     # Get filters
@@ -44,6 +46,9 @@
       # temp
       #filters = [filters[0]]

+    filterstr = " "
+      filterstr += filter for filter in filters
+    @bot.sendMessage msg.channel, "Loading `#{info.title}` #{filterstr} (#{info.duration})..."
     # Start download
     dl.download()
     .then =>
@@ -57,8 +62,6 @@
         filters: filters
         path: dl.path
       }
-      filterstr = " "
-      filterstr += filter for filter in qI.filters
       # Set events
       qI.on 'start', =>
         @bot.sendMessage msg.channel, """


misc: is_different_array handles undefined arrays as being equal and map_without_undefined should check if map is defined first

--- src/smc-util/misc.coffee
+++ src/smc-util/misc.coffee
@@ -273,7 +273,7 @@

 # convert object x to a JSON string, removing any keys that have "pass" in them and
-# any values that are potentially big -- this is meant to only be used for loging.
+# any values that are potentially big -- this is meant to only be used for logging.
 exports.to_safe_str = (x) ->
     obj = {}
     for key, value of x
@@ -1298,9 +1298,9 @@

 exports.is_different_array = (a, b) ->
     ad = a?; bd = b?
-    if not ad and bd
-        return true
-    if ad and not bd
+    if (not ad) and (not bd)
+        return false
+    if ad isnt bd
         return true
     if a.length != b.length
         return true
@@ -1677,10 +1677,10 @@
 # Doesn't modify map.  If map is an array, just returns it
 # with no change even if it has undefined values.
 exports.map_without_undefined = map_without_undefined = (map) ->
+    if not map?
+        return
     if is_array(map)
         return map
-    if not map?
-        return
     new_map = {}
     for k, v of map
         if not v?


more hardcore (& failing) asset registration specs

--- spec/Extensions.coffee
+++ spec/Extensions.coffee
@@ -210,109 +210,148 @@
         chai.expect(files).to.eql ['./didot.css','./georgia.css']
         done()

-
-    it 'multi-level asset registration w/ contest & aborts', (done) ->
+
+    describe 'multi-level asset registration w/ contest & aborts', ->
       ###
       assets registered by child should not be overwritten by parent
       ###
-
-      abortion = (parent) ->
-        parent.tree('abortion')
-        .deliver()
-        .then 'ignore-ugly', (c) ->
-          c.registerAsset
-            id: 'display-font-css'
-            type: 'css-file'
-            data: './ugly.css'
-        .then (c) ->
-          c.abort "too ugly"
-
-      abortionParent = (parent) ->
-        parent.tree('abortionParent')
-        .deliver()
-        .some [abortion,abortion]
-        .else ->
+
+      testAssetContest = (contestants, done) ->
+
+        abortion = (parent) ->
+          parent.tree('abortion')
+          .deliver()
+          .then 'ignore-ugly', (c) ->
+            c.registerAsset
+              id: 'display-font-css'
+              type: 'css-file'
+              data: './ugly.css'
+          .then (c) ->
+            c.abort "too ugly"
+
+        abortionParent = (parent) ->
+          parent.tree('abortionParent')
+          .deliver()
+          .some [abortion,abortion]
+          .else ->
+            true
+          .maybe [abortion]
+          .else ->
+            true
+          .then abortion
+          .else ->
+            true
+
+        winnergrandchild = (parent) ->
+          parent.tree('winnergrandchild')
+          .deliver()
+          .then abortionParent
+          .then 'display-font', (c) ->
+            c.registerAsset
+              id: 'display-font-css'
+              type: 'css-file'
+              data: './didot.css'
+
+        winnerchild = (parent) ->
+          parent.tree('winnerchild')
+          .deliver()
+          .then abortionParent
+          .then winnergrandchild
+
+        countdown = 5
+        Root 'asset-test', Choice:CustomChoice
+        .deliver {}
+        .then 'start', ->
           true
-        .maybe [abortion]
-        .else ->
-          true
-        .then abortion
-        .else ->
-          true
-
-      winnergrandchild = (parent) ->
-        parent.tree('winnergrandchild')
-        .deliver()
-        .then abortionParent
-        .then 'display-font', (c) ->
-          c.registerAsset
-            id: 'display-font-css'
-            type: 'css-file'
-            data: './didot.css'
-
-      winnerchild = (parent) ->
-        parent.tree('winnerchild')
-        .deliver()
-        .then abortionParent
-        .then winnergrandchild
-
-      winner = (parent) ->
-        parent.tree('winner')
-        .deliver()
-        .all [winnerchild]
-        .then abortionParent
-        .then 'ignore-comic-sans', (c) ->
-          c.registerAsset
-            id: 'display-font-css'
-            type: 'css-file'
-            data: './comic-sans.css'
-        .then 'body-font', (c) ->
-          c.registerAsset
-            id: 'body-font-css'
-            type: 'css-file'
-            data: './georgia.css'
-
-      loser = (parent) ->
-        parent.tree('loser')
-        .deliver()
-        .then 'ignore-marker', (c) ->
-          c.registerAsset
-            id: 'display-font-css'
-            type: 'css-file'
-            data: './marker.css'
-        .then 'ignored-zapfino', (c) ->
-          c.registerAsset
-            id: 'body-font-css'
-            type: 'css-file'
-            data: './zapfino.css'
-
-      countdown = 5
-      Root 'asset-test', Choice:CustomChoice
-      .deliver {}
-      .then 'start', ->
-        true
-      .contest [loser,winner]
-
-        , (n, results) -> # scoring
-          return results[1]
-
-        , (n, chosen) -> # until
-          countdown--
-          return false if countdown
-          true
-
-      .then 'ignore-arial', (c) ->
-        c.registerAsset
-          id: 'display-font-css'
-          type: 'css-file'
-          data: './arial.css'
-      .then 'build', (c) ->
-        c.getAssets (asset) ->
-          asset.type is 'css-file'
-        .map (asset) ->
-          asset.data
-      .finally (c, files) ->
-        chai.expect(files).to.eql ['./didot.css','./georgia.css']
-        done()
-
-
+        .contest contestants
+          , (n, results) -> # scoring
+            return results[1]
+          , (n, chosen) -> # until
+            countdown--
+            return false if countdown
+            true
+        .then 'ignore-arial', (c) ->
+          c.registerAsset
+            id: 'display-font-css'
+            type: 'css-file'
+            data: './arial.css'
+        .then 'build', (c) ->
+          c.getAssets (asset) ->
+            asset.type is 'css-file'
+          .map (asset) ->
+            asset.data
+        .finally (c, files) ->
+          chai.expect(files).to.eql ['./didot.css','./georgia.css']
+          done()
+
+
+      it 'via subtree', (done) ->
+
+        winner = (parent) ->
+          parent.tree('winner')
+          .deliver()
+          .all [winnerchild]
+          .then abortionParent
+          .then 'ignore-comic-sans', (c) ->
+            c.registerAsset
+              id: 'display-font-css'
+              type: 'css-file'
+              data: './comic-sans.css'
+          .then 'body-font', (c) ->
+            c.registerAsset
+              id: 'body-font-css'
+              type: 'css-file'
+              data: './georgia.css'
+
+        loser = (parent) ->
+          parent.tree('loser')
+          .deliver()
+          .then 'ignore-marker', (c) ->
+            c.registerAsset
+              id: 'display-font-css'
+              type: 'css-file'
+              data: './marker.css'
+          .then 'ignored-zapfino', (c) ->
+            c.registerAsset
+              id: 'body-font-css'
+              type: 'css-file'
+              data: './zapfino.css'
+
+        testAssetContest [winner,loser], done
+
+      it 'via branching', (done) ->
+
+        contestant = (parent) ->
+          parent.tree('contestant')
+          .deliver()
+          .then (n) ->
+
+            n.branch 'loser', (c) ->
+              c.tree()
+              .deliver()
+              .then 'ignore-marker', (c) ->
+                c.registerAsset
+                  id: 'display-font-css'
+                  type: 'css-file'
+                  data: './marker.css'
+              .then 'ignored-zapfino', (c) ->
+                c.registerAsset
+                  id: 'body-font-css'
+                  type: 'css-file'
+                  data: './zapfino.css'
+
+            # second is chosen...
+            n.branch 'winner', (c) ->
+              c.tree()
+              .deliver()
+              .all [winnerchild]
+              .then abortionParent
+              .then 'body-font', (c) ->
+                c.registerAsset
+                  id: 'body-font-css'
+                  type: 'css-file'
+                  data: './georgia.css'
+
+        testAssetContest [contestant], done
+
+


Fix atom plugin.

Fix atom plugin.

--- grammars/sifu.cson
+++ grammars/sifu.cson
@@ -86,13 +86,7 @@
             'include': '#customEndpoint'
           }
           {
-            'include': '#findEndpoint'
-          }
-          {
             'include': '#readEndpoint'
-          }
-          {
-            'include': '#pagedEndpoint'
           }
           {
             'include': '#createEndpoint'
@@ -394,7 +388,7 @@
     'name': 'clientTemplate'
     'patterns':[
       {
-        'begin': '\\('
+        'begin': '\\['
         'patterns': [
           {
             'include': '#comments'
@@ -407,7 +401,7 @@
             'name': 'invalid.illegal'
           }
         ]
-        'end': '\\)'
+        'end': '\\]'
       }
       {
         'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -811,12 +805,6 @@
             'include': '#requestDto'
           }
           {
-            'include': '#responseInlineDto'
-          }
-          {
-            'include': '#responseDto'
-          }
-          {
             'include': '#secured'
           }
           {
@@ -858,10 +846,10 @@
             'include': '#restSimple'
           }
           {
-            'include': '#endpointQueryFind'
-          }
-          {
             'include': '#modelSetting'
+          }
+          {
+            'include': '#endpointQuerySelect'
           }
           {
             'include': '#requestInlineDto'
@@ -1879,9 +1867,6 @@
             'include': '#responseDto'
           }
           {
-            'include': '#responseMapped'
-          }
-          {
             'include': '#secured'
           }
           {
@@ -1895,6 +1880,9 @@
           }
           {
             'include': '#version'
+          }
+          {
+            'include': '#paged'
           }
           {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -2101,22 +2089,10 @@
             'include': '#restSimple'
           }
           {
-            'include': '#endpointQueryFind'
-          }
-          {
-            'include': '#queryInlineFind'
-          }
-          {
-            'include': '#queryInlineCount'
-          }
-          {
-            'include': '#endpointQueryCount'
-          }
-          {
-            'include': '#queryInlineDelete'
-          }
-          {
-            'include': '#endpointQueryDelete'
+            'include': '#endpointQuerySelect'
+          }
+          {
+            'include': '#endpointQueryInlineSelect'
           }
           {
             'include': '#requestInlineDto'
@@ -3276,41 +3252,64 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

-  'endpointQueryDelete':
-    'begin': '([ \\t]*query)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'support.type'
-      '3':
-        'name': 'support.type'
-    'name': 'endpointQueryDelete'
-    'patterns':[
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
-  'endpointQueryFind':
-    'begin': '([ \\t]*query)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'support.type'
-      '3':
-        'name': 'support.type'
-    'name': 'endpointQueryFind'
-    'patterns':[
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
+  'endpointQueryInlineSelect':
+    'begin': '(?=[ \\t]*select)([ \\t]*\\n)?'
+    'beginCaptures':
+      '1':
+        'name': 'keyword'
+    'name': 'endpointQueryInlineSelect'
+    'patterns':[
+      {
+        'include': '#select'
+      }
+      {
+        'include': '#opt_from'
+      }
+      {
+        'include': '#opt_as'
+      }
+      {
+        'include': '#join'
+      }
+      {
+        'include': '#dropConstant'
+      }
+      {
+        'include': '#dropVariable'
+      }
+      {
+        'include': '#takeConstant'
+      }
+      {
+        'include': '#takeVariable'
+      }
+      {
+        'include': '#orderByOrderByProperty'
+      }
+      {
+        'include': '#orderBy'
+      }
+      {
+        'include': '#orderableByQueryProperty'
+      }
+      {
+        'include': '#orderableBy'
+      }
+      {
+        'include': '#groupByQueryProperty'
+      }
+      {
+        'include': '#groupBy'
+      }
+      {
+        'include': '#where'
+      }
+      {
+        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+        'name': 'invalid.illegal'
+      }
+    ]
+    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*group)(?![ \\t]*select)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'

   'endpointQuerySelect':
     'begin': '([ \\t]*query)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
@@ -3477,6 +3476,12 @@
             'include': '#dtoPropertyBytes'
           }
           {
+            'include': '#dtoPropertyInlineEnum'
+          }
+          {
+            'include': '#dtoPropertyDtoInline'
+          }
+          {
             'include': '#dtoPropertyUnidentified'
           }
           {
@@ -3547,71 +3552,6 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

-  'findEndpoint':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+find)'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'findEndpoint'
-    'patterns':[
-      {
-        'begin': '\\['
-        'patterns': [
-          {
-            'include': '#comments'
-          }
-          {
-            'include': '#restSimple'
-          }
-          {
-            'include': '#endpointQueryFind'
-          }
-          {
-            'include': '#queryInlineFind'
-          }
-          {
-            'include': '#requestInlineDto'
-          }
-          {
-            'include': '#requestDto'
-          }
-          {
-            'include': '#responseInlineDto'
-          }
-          {
-            'include': '#responseDto'
-          }
-          {
-            'include': '#responseMapped'
-          }
-          {
-            'include': '#secured'
-          }
-          {
-            'include': '#public'
-          }
-          {
-            'include': '#endpointErrors'
-          }
-          {
-            'include': '#version'
-          }
-          {
-            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-            'name': 'invalid.illegal'
-          }
-        ]
-        'end': '\\]'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
   'fireEvent':
     'begin': '([ \\t]*fire)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
     'beginCaptures':
@@ -3891,6 +3831,44 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

+  'groupBy':
+    'begin': '([ \\t]*group by)'
+    'beginCaptures':
+      '1':
+        'name': 'keyword'
+    'name': 'groupBy'
+    'patterns':[
+      {
+        'begin': '\\('
+        'patterns': [
+          {
+            'include': '#comments'
+          }
+          {
+            'include': '#queryProperty'
+          }
+          {
+            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+            'name': 'invalid.illegal'
+          }
+        ]
+        'end': '\\)'
+      }
+    ]
+    'end': '([ \\t]+(?=[a-zA-Z]))|([ \\t]*(\\n|(?=(,|#|\\]|\\)|\\}))))'
+
+  'groupByQueryProperty':
+    'begin': '([ \\t]*group by)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
+    'beginCaptures':
+      '1':
+        'name': 'keyword'
+      '2':
+        'name': 'support.type'
+      '3':
+        'name': 'support.type'
+    'name': 'groupByQueryProperty'
+    'end': '([ \\t]+(?=[a-zA-Z]))|([ \\t]*(\\n|(?=(,|#|\\]|\\)|\\}))))'
+
   'hidden':
     'begin': '([ \\t]*hidden)'
     'beginCaptures':
@@ -4601,6 +4579,9 @@
             'include': '#visible'
           }
           {
+            'include': '#sortable'
+          }
+          {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
             'name': 'invalid.illegal'
           }
@@ -4938,6 +4919,9 @@
             'include': '#visible'
           }
           {
+            'include': '#sortable'
+          }
+          {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
             'name': 'invalid.illegal'
           }
@@ -5103,6 +5087,9 @@
           }
           {
             'include': '#visible'
+          }
+          {
+            'include': '#sortable'
           }
           {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -5404,6 +5391,9 @@
             'include': '#visible'
           }
           {
+            'include': '#sortable'
+          }
+          {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
             'name': 'invalid.illegal'
           }
@@ -5830,6 +5820,12 @@
             'include': '#dtoPropertyBytes'
           }
           {
+            'include': '#dtoPropertyInlineEnum'
+          }
+          {
+            'include': '#dtoPropertyDtoInline'
+          }
+          {
             'include': '#dtoPropertyUnidentified'
           }
           {
@@ -5893,19 +5889,13 @@
             'include': '#comments'
           }
           {
-            'include': '#queryFind'
+            'include': '#querySelect'
           }
           {
             'include': '#queryCount'
           }
           {
-            'include': '#queryGet'
-          }
-          {
             'include': '#queryDelete'
-          }
-          {
-            'include': '#querySelect'
           }
           {
             'include': '#modelPropertyInt'
@@ -7788,7 +7778,7 @@
             'include': '#comments'
           }
           {
-            'include': '#orderableByProperty'
+            'include': '#queryProperty'
           }
           {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -7800,7 +7790,7 @@
     ]
     'end': '([ \\t]+(?=[a-zA-Z]))|([ \\t]*(\\n|(?=(,|#|\\]|\\)|\\}))))'

-  'orderableByOrderableByProperty':
+  'orderableByQueryProperty':
     'begin': '([ \\t]*orderable by)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
     'beginCaptures':
       '1':
@@ -7809,54 +7799,8 @@
         'name': 'support.type'
       '3':
         'name': 'support.type'
-    'name': 'orderableByOrderableByProperty'
+    'name': 'orderableByQueryProperty'
     'end': '([ \\t]+(?=[a-zA-Z]))|([ \\t]*(\\n|(?=(,|#|\\]|\\)|\\}))))'
-
-  'orderableByProperty':
-    'begin': '[ \\t]*([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
-    'beginCaptures':
-      '1':
-        'name': 'support.type'
-      '2':
-        'name': 'support.type'
-    'name': 'orderableByProperty'
-    'patterns':[
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
-  'orderable':
-    'begin': '([ \\t]*visible)'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-    'name': 'orderable'
-    'patterns':[
-      {
-        'begin': '\\('
-        'patterns': [
-          {
-            'include': '#comments'
-          }
-          {
-            'include': '#pathElement'
-          }
-          {
-            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-            'name': 'invalid.illegal'
-          }
-        ]
-        'end': '\\)'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

   'page':
     'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+page)'
@@ -8021,77 +7965,6 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

-  'pagedEndpoint':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+paged)'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'pagedEndpoint'
-    'patterns':[
-      {
-        'begin': '\\['
-        'patterns': [
-          {
-            'include': '#comments'
-          }
-          {
-            'include': '#restSimple'
-          }
-          {
-            'include': '#endpointQueryFind'
-          }
-          {
-            'include': '#queryInlineFind'
-          }
-          {
-            'include': '#queryInlineCount'
-          }
-          {
-            'include': '#endpointQueryCount'
-          }
-          {
-            'include': '#requestInlineDto'
-          }
-          {
-            'include': '#requestDto'
-          }
-          {
-            'include': '#responseInlineDto'
-          }
-          {
-            'include': '#responseDto'
-          }
-          {
-            'include': '#responseMapped'
-          }
-          {
-            'include': '#secured'
-          }
-          {
-            'include': '#public'
-          }
-          {
-            'include': '#endpointErrors'
-          }
-          {
-            'include': '#version'
-          }
-          {
-            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-            'name': 'invalid.illegal'
-          }
-        ]
-        'end': '\\]'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
   'paged':
     'begin': '([ \\t]*paged)'
     'beginCaptures':
@@ -8161,6 +8034,12 @@
           }
           {
             'include': '#dtoPropertyBytes'
+          }
+          {
+            'include': '#dtoPropertyInlineEnum'
+          }
+          {
+            'include': '#dtoPropertyDtoInline'
           }
           {
             'include': '#dtoPropertyUnidentified'
@@ -8722,7 +8601,7 @@
         'name': 'invalid.illegal'
       }
     ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
+    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*group)(?![ \\t]*select)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'

   'queryDelete':
     'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+delete)([ \\t]*\\n)?'
@@ -8750,90 +8629,10 @@
         'name': 'invalid.illegal'
       }
     ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryFind':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+find)([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'queryFind'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#dropConstant'
-      }
-      {
-        'include': '#dropVariable'
-      }
-      {
-        'include': '#takeConstant'
-      }
-      {
-        'include': '#takeVariable'
-      }
-      {
-        'include': '#orderByOrderByProperty'
-      }
-      {
-        'include': '#orderBy'
-      }
-      {
-        'include': '#orderableByOrderableByProperty'
-      }
-      {
-        'include': '#orderableBy'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryGet':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+get)([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'queryGet'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
+    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*group)(?![ \\t]*select)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'

   'queryInlineCount':
-    'begin': '([ \\t]*count)([ \\t]+from)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?([ \\t]*\\n)?'
+    'begin': '([ \\t]*count)[ \\t]+([ \\t]*from)[ \\t]+[ \\t]*([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?(?:[ \\t]+(?:[ \\t]*(#.*|\\n))?[ \\t]+([ \\t]*object))*([ \\t]*\\n)?'
     'beginCaptures':
       '1':
         'name': 'keyword'
@@ -8847,6 +8646,10 @@
         'name': 'keyword'
       '6':
         'name': 'punctuation.definition.identity'
+      '7':
+        'name': 'comment'
+      '8':
+        'name': 'object'
     'name': 'queryInlineCount'
     'patterns':[
       {
@@ -8866,24 +8669,32 @@
         'name': 'invalid.illegal'
       }
     ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryInlineDelete':
-    'begin': '([ \\t]*delete)([ \\t]+from)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'keyword'
-      '3':
+    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*group)(?![ \\t]*select)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
+
+  'queryProperty':
+    'begin': '[ \\t]*([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)'
+    'beginCaptures':
+      '1':
         'name': 'support.type'
-      '4':
+      '2':
         'name': 'support.type'
-      '5':
-        'name': 'keyword'
-      '6':
+    'name': 'queryProperty'
+    'patterns':[
+      {
+        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+        'name': 'invalid.illegal'
+      }
+    ]
+    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
+
+  'querySelect':
+    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)(?=[ \\t]+select)([ \\t]*\\n)?'
+    'beginCaptures':
+      '1':
         'name': 'punctuation.definition.identity'
-    'name': 'queryInlineDelete'
+      '2':
+        'name': 'keyword'
+    'name': 'querySelect'
     'patterns':[
       {
         'include': '#opt_from'
@@ -8892,9 +8703,42 @@
         'include': '#opt_as'
       }
       {
+        'include': '#select'
+      }
+      {
         'include': '#join'
       }
       {
+        'include': '#dropConstant'
+      }
+      {
+        'include': '#dropVariable'
+      }
+      {
+        'include': '#takeConstant'
+      }
+      {
+        'include': '#takeVariable'
+      }
+      {
+        'include': '#orderByOrderByProperty'
+      }
+      {
+        'include': '#orderBy'
+      }
+      {
+        'include': '#orderableByQueryProperty'
+      }
+      {
+        'include': '#orderableBy'
+      }
+      {
+        'include': '#groupByQueryProperty'
+      }
+      {
+        'include': '#groupBy'
+      }
+      {
         'include': '#where'
       }
       {
@@ -8902,217 +8746,7 @@
         'name': 'invalid.illegal'
       }
     ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryInlineFind':
-    'begin': '([ \\t]*from)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?(?:[ \\t]+(?:[ \\t]*(#.*|\\n))?[ \\t]+([ \\t]*object))*([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'support.type'
-      '3':
-        'name': 'support.type'
-      '4':
-        'name': 'keyword'
-      '5':
-        'name': 'punctuation.definition.identity'
-      '6':
-        'name': 'comment'
-      '7':
-        'name': 'object'
-    'name': 'queryInlineFind'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#dropConstant'
-      }
-      {
-        'include': '#dropVariable'
-      }
-      {
-        'include': '#takeConstant'
-      }
-      {
-        'include': '#takeVariable'
-      }
-      {
-        'include': '#orderByOrderByProperty'
-      }
-      {
-        'include': '#orderBy'
-      }
-      {
-        'include': '#orderableByOrderableByProperty'
-      }
-      {
-        'include': '#orderableBy'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryInlineGet':
-    'begin': '([ \\t]*get)([ \\t]+from)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'keyword'
-      '3':
-        'name': 'support.type'
-      '4':
-        'name': 'support.type'
-      '5':
-        'name': 'keyword'
-      '6':
-        'name': 'punctuation.definition.identity'
-    'name': 'queryInlineGet'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'queryInlineSelect':
-    'begin': '([ \\t]*select)([ \\t]+from)[ \\t]+([a-zA-Z][_a-zA-Z0-9]*(\\.[a-zA-Z][_a-zA-Z0-9]*)*)(?:[ \\t]+([ \\t]*as)[ \\t]+([ \\t]*[a-zA-Z][_a-zA-Z0-9]*))?([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-      '2':
-        'name': 'keyword'
-      '3':
-        'name': 'support.type'
-      '4':
-        'name': 'support.type'
-      '5':
-        'name': 'keyword'
-      '6':
-        'name': 'punctuation.definition.identity'
-    'name': 'queryInlineSelect'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#dropConstant'
-      }
-      {
-        'include': '#dropVariable'
-      }
-      {
-        'include': '#takeConstant'
-      }
-      {
-        'include': '#takeVariable'
-      }
-      {
-        'include': '#orderByOrderByProperty'
-      }
-      {
-        'include': '#orderBy'
-      }
-      {
-        'include': '#orderableByOrderableByProperty'
-      }
-      {
-        'include': '#orderableBy'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
-
-  'querySelect':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+select)([ \\t]*\\n)?'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'querySelect'
-    'patterns':[
-      {
-        'include': '#opt_from'
-      }
-      {
-        'include': '#opt_as'
-      }
-      {
-        'include': '#join'
-      }
-      {
-        'include': '#dropConstant'
-      }
-      {
-        'include': '#dropVariable'
-      }
-      {
-        'include': '#takeConstant'
-      }
-      {
-        'include': '#takeVariable'
-      }
-      {
-        'include': '#orderByOrderByProperty'
-      }
-      {
-        'include': '#orderBy'
-      }
-      {
-        'include': '#orderableByOrderableByProperty'
-      }
-      {
-        'include': '#orderableBy'
-      }
-      {
-        'include': '#where'
-      }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
+    'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*from)(?![ \\t]*as)(?![ \\t]*goto)(?![ \\t]*call)(?![ \\t]*close)(?![ \\t]*init)(?![ \\t]*open)(?![ \\t]*reload)(?![ \\t]*fire)(?![ \\t]*(left[ \\t]+)?*join)(?![ \\t]*where)(?![ \\t]*if )(?![ \\t]*drop)(?![ \\t]*take)(?![ \\t]*group)(?![ \\t]*select)(?![ \\t]*order)(?![ \\t]*orderable)|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'

   'readEndpoint':
     'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+read)'
@@ -9133,21 +8767,21 @@
             'include': '#restSimple'
           }
           {
-            'include': '#endpointQueryFind'
-          }
-          {
-            'include': '#queryInlineFind'
-          }
-          {
-            'include': '#queryInlineGet'
-          }
-          {
-            'include': '#queryInlineSelect'
+            'include': '#modelSetting'
           }
           {
             'include': '#endpointQuerySelect'
           }
           {
+            'include': '#endpointQueryInlineSelect'
+          }
+          {
+            'include': '#queryInlineCount'
+          }
+          {
+            'include': '#endpointQueryCount'
+          }
+          {
             'include': '#requestInlineDto'
           }
           {
@@ -9169,13 +8803,13 @@
             'include': '#public'
           }
           {
+            'include': '#endpointErrors'
+          }
+          {
+            'include': '#version'
+          }
+          {
             'include': '#paged'
-          }
-          {
-            'include': '#endpointErrors'
-          }
-          {
-            'include': '#version'
           }
           {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -9956,6 +9590,32 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

+  'select':
+    'begin': '([ \\t]*select)'
+    'beginCaptures':
+      '1':
+        'name': 'keyword'
+    'name': 'select'
+    'patterns':[
+      {
+        'begin': '\\('
+        'patterns': [
+          {
+            'include': '#comments'
+          }
+          {
+            'include': '#queryProperty'
+          }
+          {
+            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+            'name': 'invalid.illegal'
+          }
+        ]
+        'end': '\\)'
+      }
+    ]
+    'end': '([ \\t]+(?=[a-zA-Z]))|([ \\t]*(\\n|(?=(,|#|\\]|\\)|\\}))))'
+
   'sensitive':
     'begin': '([ \\t]*sensitive)'
     'beginCaptures':
@@ -10371,6 +10031,36 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

+  'sortable':
+    'begin': '([ \\t]*sortable)'
+    'beginCaptures':
+      '1':
+        'name': 'keyword'
+    'name': 'sortable'
+    'patterns':[
+      {
+        'begin': '\\('
+        'patterns': [
+          {
+            'include': '#comments'
+          }
+          {
+            'include': '#pathElement'
+          }
+          {
+            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+            'name': 'invalid.illegal'
+          }
+        ]
+        'end': '\\)'
+      }
+      {
+        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
+        'name': 'invalid.illegal'
+      }
+    ]
+    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
+
   'stub':
     'begin': '([ \\t]*stub)'
     'beginCaptures':
@@ -10449,7 +10139,7 @@
             'include': '#visible'
           }
           {
-            'include': '#orderable'
+            'include': '#sortable'
           }
           {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
@@ -11779,6 +11469,9 @@
             'include': '#visible'
           }
           {
+            'include': '#sortable'
+          }
+          {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
             'name': 'invalid.illegal'
           }
@@ -11941,25 +11634,13 @@
             'include': '#restSimple'
           }
           {
-            'include': '#endpointQueryFind'
-          }
-          {
             'include': '#modelSetting'
           }
           {
-            'include': '#queryInlineFind'
-          }
-          {
-            'include': '#queryInlineCount'
-          }
-          {
-            'include': '#endpointQueryCount'
-          }
-          {
-            'include': '#queryInlineSelect'
-          }
-          {
             'include': '#endpointQuerySelect'
+          }
+          {
+            'include': '#endpointQueryInlineSelect'
           }
           {
             'include': '#requestInlineDto'
@@ -12363,3 +12044,4 @@
     ]
     'name': 'if'
     'end': '(\\G(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))|((?![ \\t]*\\()(?![ \\t]*and )(?![ \\t]*or )(?!(?:([ \\t]*optional))?(?:([ \\t]+mandatory))?([ \\t]+[^(\\s\\{\\}\\[\\]\\(\\)#,)]+)(?:([ \\t]+==)|([ \\t]+!=)|([ \\t]+>=)|([ \\t]+>)|([ \\t]+<=)|([ \\t]+<)|([ \\t]+like)|([ \\t]+in))([ \\t]+[^(\\s\\{\\}\\[\\]\\(\\)#,)]+))(?!(?:([ \\t]*optional))?(?:([ \\t]+mandatory))?([ \\t]+[^(\\s\\{\\}\\[\\]\\(\\)#,)]+)(?:([ \\t]+is null)|([ \\t]+is not null)))|(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n)))'
+


Highlight internal folding commands

Highlight internal folding commands

--- grammars/viml.cson
+++ grammars/viml.cson
@@ -419,11 +419,12 @@
 	# Syntax highlighting definitions
 	syntax:
 		name: "meta.syntax-item.viml"
-		begin: "^\\s*(:)?\\s*(syntax|syn?)(?=\\s|$)"
+		begin: "^\\s*(:)?(?:(VimFold\\w)\\s+)?\\s*(syntax|syn?)(?=\\s|$)"
 		end: "$"
 		beginCaptures:
 			1: name: "punctuation.separator.key-value.colon.viml"
-			2: name: "support.function.syntax-item.viml"
+			2: name: "support.function.fold-command.viml"
+			3: name: "storage.type.syntax-item.viml"
 		patterns: [{

 			# Case-matching


populate the hidden input after deserialization

--- src/mentions-kinder.coffee
+++ src/mentions-kinder.coffee
@@ -66,6 +66,7 @@
   # Deserialize the original input into the editable
   deserializeFromInput: =>
     @$editable.html @_deserialize(@$originalInput.val())
+    @populateInput()

   # Helper method
   # un**** our editable after paste or other ****


remove debug

remove debug

--- src/mentions-kinder.coffee
+++ src/mentions-kinder.coffee
@@ -63,7 +63,6 @@
     @cleanChildNodes(@$editable[0])

   startAutocomplete: (triggerChar)->
-    console?.log "Start autocomplete for #{triggerChar}"
     @_current = {
       trigger: triggerChar,
       triggerOptions: @trigger[triggerChar],
@@ -102,8 +101,6 @@
     @isAutocompleting() && @_current.autocompleter.abort()

   handleAutocompleteDone: (data)=>
-    console?.log "Autocomplete done", data
-
     # add current trigger state to data to allow access from formatters and serializers
     data = $.extend({}, @_current, data)

@@ -122,8 +119,6 @@
     @_current = null

   handleAutocompleteFail: =>
-    console?.log "Autocomplete fail"
-
     # convert to text
     textNode = document.createTextNode(@_current.$tempMention.text())
     @_current.$tempMention.replaceWith(textNode)


fix #165

fix #165

--- grunt/build.coffee
+++ grunt/build.coffee
@@ -72,7 +72,7 @@
       modifier: 'modern'
       include: [
         'difference', 'flatten', 'intersection', 'last'
-        'all', 'each', 'map', 'pluck', 'reduce'
+        'all', 'each', 'invoke', 'map', 'pluck', 'reduce'
         'bind', 'defer', 'partial'
         'clone', 'defaults', 'has', 'keys', 'omit', 'values'
         'isArray', 'isElement', 'isEqual', 'isNumber', 'isObject', 'isString'


change name of deploy script

change name of deploy script

--- gruntConfig.coffee
+++ gruntConfig.coffee
@@ -2,8 +2,6 @@

   webpack setup and external grunt tasks borrowed from:
     https://github.com/felixhao28/using-coffee-react-for-frontend-dev-walkthrough
-
-  unusused tasks from zuKeeper.  TODO: remove them if not needed

 ###

@@ -61,7 +59,7 @@
         options:
           # should gracefully fail if it doesn't find zukeeper src.  see comment at top of the script
           failOnError: false
-        command: 'coffee ./scripts/deployToZukeeper.coffee'
+        command: 'coffee ./scripts/deploy.coffee'

       npmInstall:
         command: 'npm install'