trying to coffeeify

trying to coffeeify

Former-commit-id: 7ef41754e968032bd605d21c13802948a1a8221d [formerly abd63575727557886161d4ea0c7dd8cf103dc0b0] [formerly ef5997cd2e6632d08f689129e04c171eefcd0c9f [formerly ef5997cd2e6632d08f689129e04c171eefcd0c9f [formerly 00bd948f522fa6dcabbf06053244912b10880e3e]]]
Former-commit-id: ee6352a7fa707e3169b3ec8774d59769b0dd52c9 [formerly 27ca45c52c5aaa6ae89c4b84aaeff565d3e53b03]
Former-commit-id: 2ccfb313e30effa6b71744867f8d8dc8d306f340
Former-commit-id: 0caf915bc75f659dc8c8709794fff2c5f4792235

--- app/assets/themes/policyninja/javascripts/considerit.theme.js.coffee
+++ app/assets/themes/policyninja/javascripts/considerit.theme.js.coffee
@@ -1,15 +1 @@
-@ConsiderIt.module "Theme", (Theme, App, Backbone, Marionette, $, _) ->
-
-// $(document).ready(function(){
-
-//   per_request();
-//   $(document).ajaxComplete(function(e, xhr, settings) {
-//     per_request();
-//   });
-
-//   function per_request(){
-//     $('#points_on_board_pro .pro_header img').attr('src', '/assets/policyninja/images/pro_header.png');
-//     $('#points_on_board_con .con_header img').attr('src', '/assets/policyninja/images/con_header.png');
-
-//   }
-// });+@ConsiderIt.module "Theme", (Theme, App, Backbone, Marionette, $, _) ->


Never set closeTags/openTags to null

Never set closeTags/openTags to null

--- src/token-iterator.coffee
+++ src/token-iterator.coffee
@@ -28,8 +28,8 @@
     @endBufferPosition = null
     @endScreenPosition = null
     @text = null
-    @openTags = null
-    @closeTags = null
+    @openTags = EMPTY_ARRAY
+    @closeTags = EMPTY_ARRAY
     @containingTags = null
     @tagsToReopen = null

@@ -37,7 +37,7 @@
     @startScreenPosition = Point(screenRow, 0)
     @patchIterator.seekToOutputPosition(@startScreenPosition)
     @startBufferPosition = @patchIterator.translateOutputPosition(@startScreenPosition)
-    @openTags = null
+    @openTags = EMPTY_ARRAY

     if @decorationIterator?
       @containingTags = @decorationIterator.seek(@startBufferPosition) ? EMPTY_ARRAY
@@ -51,17 +51,14 @@
     @containingTags

   moveToSuccessor: ->
-    if @closeTags?
-      for tag in @closeTags
-        @containingTags.splice(@containingTags.lastIndexOf(tag), 1)
-
-    if @openTags?
-      @containingTags.push(@openTags...)
+    for tag in @closeTags
+      @containingTags.splice(@containingTags.lastIndexOf(tag), 1)
+    @containingTags.push(@openTags...)

     @startScreenPosition = @endScreenPosition
     @startBufferPosition = @endBufferPosition
-    @closeTags = null
-    @openTags = null
+    @closeTags = EMPTY_ARRAY
+    @openTags = EMPTY_ARRAY

     advanceToNextLine = true
     if @decorationIterator? and isEqualPoint(@startBufferPosition, @decorationIterator.getPosition())
@@ -73,7 +70,7 @@
       advanceToNextLine = false
       @patchIterator.moveToSuccessor()

-    return false unless @closeTags? or @openTags? or comparePoints(@startBufferPosition, @buffer.getEndPosition()) < 0
+    return false unless @closeTags.length > 0 or @openTags.length > 0 or comparePoints(@startBufferPosition, @buffer.getEndPosition()) < 0

     if advanceToNextLine
       @startScreenPosition = Point(@startScreenPosition.row + 1, 0)
@@ -87,19 +84,18 @@
         @patchIterator.moveToSuccessor()

     if @tagsToReopen?
-      if @closeTags?
-        for tag in @closeTags
-          @tagsToReopen.splice(@tagsToReopen.lastIndexOf(tag), 1)
-      @closeTags = null
-      @openTags = @tagsToReopen.concat(@openTags ? [])
+      for tag in @closeTags
+        @tagsToReopen.splice(@tagsToReopen.lastIndexOf(tag), 1)
+      @closeTags = EMPTY_ARRAY
+      @openTags = @tagsToReopen.concat(@openTags)
       @tagsToReopen = null

     @assignEndPositionsAndText()
     true

-  getOpenTags: -> @openTags ? EMPTY_ARRAY
+  getOpenTags: -> @openTags

-  getCloseTags: -> @closeTags ? EMPTY_ARRAY
+  getCloseTags: -> @closeTags

   assignEndPositionsAndText: ->
     if @patchIterator.getOutputEnd().row is @startScreenPosition.row
@@ -126,7 +122,7 @@
       if @isFold()
         @closeTags = @containingTags.slice()
         @containingTags.length = 0
-        @openTags = null
+        @openTags = EMPTY_ARRAY
         @tagsToReopen = @decorationIterator.seek(@getEndBufferPosition())
       else
         decorationIteratorPosition = @decorationIterator.getPosition()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -52,9 +52,9 @@

   player.update()

-  equals player.I.y,
+  equals player.I.y, 18

-  window.keydown.right = false
+  window.keydown.ri = false

   equals player.I.x, 12


Handle dotless commands in the REPL.

Handle dotless commands in the REPL.

Node 0.11 switched to storing the REPL commands dotless internally.
This fixes the problem brought up in #3450.

--- repl.coffee
+++ repl.coffee
@@ -28,7 +28,7 @@
       ]
       js = ast.compile bare: yes, locals: Object.keys(context)
       result = if context is global
-        vm.runInThisContext js, filename
+        vm.runInThisContext js, filename
       else
         vm.runInContext js, context, filename
       cb null, result
@@ -111,8 +111,9 @@

   fd = fs.openSync filename, 'a'

+  historyCommand = if repl.commandsWithLeadingDot() then '.history' else 'history'
   repl.rli.addListener 'line', (code) ->
-    if code and code.length and code isnt '.history' and lastLine isnt code
+    if code and code.length and code isnt historyCommand and lastLine isnt code
       # Save the latest command in the file
       fs.write fd, "#{code}\n"
       lastLine = code
@@ -120,11 +121,16 @@
   repl.rli.on 'exit', -> fs.close fd

   # Add a command to show the history stack
-  repl.commands['.history'] =
+  repl.commands[historyCommand] =
     help: 'Show command history'
     action: ->
       repl.outputStream.write "#{repl.rli.history[..].reverse().join '\n'}\n"
       repl.displayPrompt()
+
+# Adapt load help inherited from the node REPL
+correctLoadHelp = (repl) ->
+  loadCommand = if repl.commandsWithLeadingDot() then '.load' else 'load'
+  repl.commands[loadCommand].help = 'Load code from a file into this REPL session'

 module.exports =
   start: (opts = {}) ->
@@ -139,8 +145,8 @@
     opts = merge replDefaults, opts
     repl = nodeREPL.start opts
     repl.on 'exit', -> repl.outputStream.write '\n'
+    repl.commandsWithLeadingDot = -> ! @commands.help
     addMultilineHandler repl
     addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
-    # Correct the description inherited from the node REPL
-    repl.commands['.load'].help = 'Load code from a file into this REPL session'
+    correctLoadHelp repl
     repl


Fix help for .load

Fix help for .load

--- repl.coffee
+++ repl.coffee
@@ -138,4 +138,6 @@
     repl.on 'exit', -> repl.outputStream.write '\n'
     addMultilineHandler repl
     addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
+    # Correct the description inherited from the node REPL
+    repl.commands['.load'].help = 'Load code from a file into this REPL session'
     repl


add `new_metrics()`, `new_otjs_font()`

add `new_metrics()`, `new_otjs_font()`

--- src/main.coffee
+++ src/main.coffee
@@ -38,6 +38,38 @@
 OT                        = @_OT      = require 'opentype.js'
 SvgPath                   = @_SvgPath = require 'svgpath'
 path_precision            = 5
+
+#===========================================================================================================
+# METRICS
+#-----------------------------------------------------------------------------------------------------------
+@new_metrics = ->
+  R =
+    em_size:          4096  ### a.k.a. design size, grid size ###
+    ascender:         null,
+    descender:        null,
+    font_size:        360   ### in pixels ###
+    scale_factor:     null
+    # ### TAINT magic number
+    # for whatever reason, we have to calculate advanceWidth with an additional tracking factor:
+    # advanceWidth = glyph.advanceWidth * metrics.scale_factor * metrics.tracking_factor ###
+    # tracking_factor:  256 / 182
+  R.scale_factor        =  R.em_size / R.font_size
+  R.ascender            =  R.em_size / ( 256 / 220 )
+  R.descender           = -R.em_size / 5
+  # R.global_glyph_scale  = 50 / 48.5 ### TAINT value must come from configuration ###
+  R.global_glyph_scale  = 256 / 248 ### TAINT value must come from configuration ###
+  return R
+
+#-----------------------------------------------------------------------------------------------------------
+@new_otjs_font = ( me, name, glyphs ) ->
+  validate.nonempty_text name
+  return new OT.Font {
+    familyName:   name,
+    styleName:    'Medium',
+    unitsPerEm:   me.em_size,
+    ascender:     me.ascender,
+    descender:    me.descender,
+    glyphs:       glyphs }

 #===========================================================================================================


workaround fixing double clipboard content on paste

--- src/ui/views/input.coffee
+++ src/ui/views/input.coffee
@@ -62,8 +62,10 @@
                     if e.keyIdentifier is "Down" then historyWalk e.target, +1
             action 'lastkeydown', Date.now() unless isAltCtrlMeta(e)
         , onpaste: (e) ->
-            if not clipboard.readImage().isEmpty() and not clipboard.readText()
-              action 'onpasteimage'
+            setTimeout () ->
+                if not clipboard.readImage().isEmpty() and not clipboard.readText()
+                    action 'onpasteimage'
+            , 2
         button title:'Attach image', onclick: (ev) ->
             document.getElementById('attachFile').click()
         , ->


Routes middlewares no longer require a final route after them

--- lib/plugins/router.coffee
+++ lib/plugins/router.coffee
@@ -49,7 +49,7 @@
     i ?= 0
     while i < routes.length
         route = routes[i]
-        fn = route.callback
+        #fn = route.callback
         regexp = route.regexp
         keys = route.keys
         captures = regexp.exec req.command
@@ -98,7 +98,6 @@
         route = {}
         route.command = args.shift()
         route.description = args.shift() if typeof args[0] is 'string'
-        route.callback = args.pop()
         route.middlewares = utils.flatten args
         keys = []
         route.regexp =
@@ -158,11 +157,12 @@
                             else if fn
                                 fn req, res, nextMiddleware
                             else
-                                route.callback.call self, req, res, (err) ->
-                                    if err
-                                        next err
-                                    else
-                                        pass req._route_index + 1
+                                pass req._route_index + 1
+                                #route.callback.call self, req, res, (err) ->
+                                    #if err
+                                        #next err
+                                    #else
+                                        #pass req._route_index + 1
                         nextMiddleware()
                     # More params
                     else


Fixed #372 datepicker year menu

Fixed #372 datepicker year menu

--- wzk/ui/DatePicker.coffee
+++ wzk/ui/DatePicker.coffee
@@ -40,4 +40,25 @@
       @i18nDateFormatterYear_.format(@activeMonth_)
     )

+  ###*
+    @suppress {visibility}
+    @protected
+    @param {number} currentYear
+    @param {number} itemIndex
+    @return {number}
+  ###
+  computePickedYear: (currentYear, itemIndex) ->
+    return (
+      if @yearMenuRange? then @yearMenuRange[0] + itemIndex
+      else currentYear + itemIndex - goog.ui.DatePicker.YEAR_MENU_RANGE_
+    )

+  ###*
+    @suppress {visibility}
+  ###
+  handleYearMenuClick_: (target) ->
+    if target.firstChild.nodeType is goog.dom.NodeType.TEXT
+      @activeMonth_.setFullYear(
+        @computePickedYear(@activeMonth_.getFullYear(), Number(target.getAttribute('itemIndex'))))
+      @updateCalendarGrid_()
+    @elYear_.focus()


added fair events to the fabricator

added fair events to the fabricator

--- node/fabricate.coffee
+++ node/fabricate.coffee
@@ -739,4 +739,23 @@
         blurb: undefined
       partner: fabricate 'partner'

+    when 'fair_event_group'
+      fair: fabricate 'fair'
+      id: _.uniqueId()
+      name: 'The China Symposium'
+      description: "\nOrganized by Philip Tinari\nMarch 8-9, 2014\n\nFor the first time, The Armory Show will host a symposium in conjunction with its annual regional Focus initiative. Organized by Philip Tinari, Director of the Ullens Center for Contemporary Art, Beijing, this inaugural weekend-long forum comprises eight discussions that aim to elaborate and clarify the state of contemporary art in China today."
+      updated_at: "2014-02-24T16:34:25Z"
+
+    when 'fair_event'
+      id: _.uniqueId()
+      fair: fabricate 'fair'
+      fair_event_groups: [ fabricate('fair_event_group') ]
+      name: "Welcome"
+      description: "PARTICIPANTS: Noah Horowitz, Executive Director, The Armory Show\nPhilip Tinari, Director, Ullens Center for Contemporary Art (UCCA), Beijing\nAdrian Cheng, Founder and Chairman, K11 Art Foundation, Hong Kong\n"
+      extended_description: "This panel is organized in conjunction with The Armory Show – Modern exhibition, VENUS DRAWN OUT: 20th Century Works by Great Women Artists on Pier 92, and will feature a rare conversation amongst several of its participants.  The panelists will discuss their nuanced artistic practices, works of art on view at the fair, alongside broader topics such as the context of working as a female artist and the field of twentieth century Modern Art as a whole\n\nFeaturing panelists: Inka Essenhigh, Artist, New York; Lynn Gumpert, Director, Grey Art Gallery, New York University; Pat Steir, Artist, New York. Moderated by Susan Harris, New York-based Independent Curator and Writer."
+      venue: "T: The New York Times Style Magazine Media Lounge on Pier 94"
+      start_at: "2014-03-08T17:15:00+00:00"
+      end_at: "2014-03-08T17:30:00+00:00"
+      updated_at: "2014-02-24T16:34:25Z"
+
   , extObj


Small refactor.

Small refactor.

--- app/client/js/storage.coffee
+++ app/client/js/storage.coffee
@@ -48,9 +48,8 @@
         # TODO(steida): Investigate it. Native .toJSON is too verbose.
         json = JSON.parse JSON.stringify store.toJson()
         goog.asserts.assertObject json
-        @firebase
-          .userRefOf @userStore.user
-          .set json
+        # TODO(steida): Use more granular approach to store user data.
+        @firebase.userRef.set json

     @notify()


fix a potential type error

fix a potential type error

--- lib/server.storage.coffee
+++ lib/server.storage.coffee
@@ -43,7 +43,7 @@
   console.log("presenter state change: ", stateChange)
   publish(channels.slaveEvents, stateChange)

-PRESENTER_USER = {id: "236886", provider: "github"}
+PRESENTER_USER = {id: 236886, provider: "github"}
 do ->
   subscribe(channels.getUserEventChannelName(PRESENTER_USER), publishEventsFromPresenterToSlaves)


:memo: Doc how to require WorkspaceView in package specs

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -37,6 +37,11 @@
 #  * `application:bring-all-windows-to-front` - Brings all {AtomWindow}s to the
 #    the front.
 #
+# ## Requiring in package specs
+#
+# ```coffee
+#   {WorkspaceView} = require 'atom'
+# ```
 module.exports =
 class WorkspaceView extends View
   Delegator.includeInto(this)


follow/unfollow state is not decorated when state is passed via argument

--- client/landing/app/Applications/Members.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Members.kdapplication/AppView.coffee
@@ -203,17 +203,22 @@

     super options, data

-    unless @getData().followee?
+    decorator = (following)=>
+      if @getData().followee
+        @setClass 'following-btn'
+        @setState "Unfollow"
+      else
+        @setState "Follow"
+        @unsetClass 'following-btn'
+
+    if @getData().followee?
+      decorator @getData().followee
+    else
       KD.whoami().isFollowing? @getData().getId(), "JAccount", \
         (err, following) =>
           @getData().followee = following
           warn err  if err and KD.isLoggedIn()
-          if @getData().followee
-            @setClass 'following-btn'
-            @setState "Unfollow"
-          else
-            @setState "Follow"
-            @unsetClass 'following-btn'
+          decorator following

   decorateState:(name)->


updates contract map

updates contract map

--- maps/contracts.coffee
+++ maps/contracts.coffee
@@ -38,4 +38,18 @@
   ENGY:
     channel_id: 33208
   NEUT:
-    channel_id: 33207+    channel_id: 33207
+  DEVO:
+    channel_id: 33218
+  NOID:
+    channel_id: 34069
+  EXCO:
+    channel_id: 34061
+  LESS:
+    channel_id: 34065
+  ASTR:
+    channel_id: 34099
+  UVAC:
+    channel_id: 34052
+  OFF:
+    channel_id: 34120


added test to the schema

added test to the schema

--- test/orpheus.spec.coffee
+++ test/orpheus.spec.coffee
@@ -74,6 +74,23 @@
 		# Jasmine .toThrow() is shit.
 		expect('To Catch an Error').toBe true
 		done()
+
+describe 'Schema', ->
+
+	it 'can call the different models using the schema', (done) ->
+		class Hello extends Orpheus
+			constructor: ->
+				@str 'name'
+
+		Hello.create()
+
+		Orpheus.schema.hello('id')
+			.name.set('test')
+			.exec ->
+				r.hget "#{PREFIX}:he:id", 'name', (err, res) ->
+					expect(res).toEqual 'test'
+					done()
+

 # Redis Commands


activityticker : lower the ticker request size to 5

--- workers/social/lib/social/models/activityticker.coffee
+++ workers/social/lib/social/models/activityticker.coffee
@@ -80,7 +80,7 @@
           group   : groupSlug

       relOptions  =    # do not fetch more than 15 at once
-        limit     : 10 # Math.min options.limit ? 15, 15
+        limit     : 5 # Math.min options.limit ? 15, 15
         sort      : timestamp : -1

       Relationship.some relSelector, relOptions, (err, relationships) ->


Revert last

Revert last

--- client/app/MainApp/ContentDisplay/ContentDisplayController.coffee
+++ client/app/MainApp/ContentDisplay/ContentDisplayController.coffee
@@ -3,8 +3,6 @@
     super options
     @displays = {}
     @attachListeners()
-    @lastShownViewDataId = null
-    @lastShownViewConstructorName = null

   attachListeners:->
     @registerListener
@@ -32,24 +30,11 @@
         @hideAllContentDisplays()

   showContentDisplay:(view)->
-    log "View: ", view.constructor.name
-    ###
-    if view.getData().getId?() is @lastShownViewDataId and
-       view.constructor.name is @lastShownViewConstructorName
-      new KDNotificationView
-        title      : "Already in this!"
-        type       : "mini"
-      return
-    ###
     contentPanel = @getSingleton "contentPanel"
     wrapper = new ContentDisplay
     @displays[view.id] = view
     wrapper.addSubView view
     contentPanel.addSubView wrapper
-
-    # @lastShownViewDataId = view.getData().getId?()
-    # @lastShownViewConstructorName = view.constructor.name
-
     @slideWrapperIn wrapper

   hideContentDisplay:(view)->


home/myteam: minor change

home/myteam: minor change

--- client/home/lib/myteam/components/hometeamteammates/member.coffee
+++ client/home/lib/myteam/components/hometeamteammates/member.coffee
@@ -57,11 +57,11 @@
     lastName = @props.member.getIn ['profile', 'lastName']
     fullName = "#{firstName} #{lastName}"

-    if member.get('status') is 'pending'
+    if @props.member.get('status') is 'pending'
       role = 'Invitation Sent'
-      firstName = member.get('firstName') or ''
-      lastName = member.get('lastName') or ''
-      fullName = member.get 'email'
+      firstName = @props.member.get('firstName') or ''
+      lastName = @props.member.get('lastName') or ''
+      fullName = @props.member.get 'email'
       email = "#{firstName} #{lastName}"
       nickname = ''


added test for .txt files

added test for .txt files

--- test/test-helpers.coffee
+++ test/test-helpers.coffee
@@ -107,6 +107,15 @@
           engines: []
         }
       )
+    it 'javascripts/main.js', ->
+      assert.deepEqual(
+        helpers.parse_filename('foo.txt')
+        {
+          type: ''
+          base: 'foo.txt'
+          engines: []
+        }
+      )

   describe 'find_file', ->


Don't log

Don't log

--- app/models/user_group.coffee
+++ app/models/user_group.coffee
@@ -56,7 +56,6 @@
   @delete: (id) =>
     req = Api.delete "/user_groups/#{ id }"
     req.always =>
-      console.log 'here'
       @trigger 'destroy-group', id
       if @current?.id is id
         @current.destroy()


Use CSP. Closes #101.

Use CSP. Closes #101.

--- main.coffee
+++ main.coffee
@@ -122,7 +122,7 @@
 			admin: sessionData.admin
 			userid: sessionData.userid
 	# CSP
-	response.header 'Content-Security-Policy-Report-Only', "default-src 'self'"
+	response.header 'Content-Security-Policy', "default-src 'self'; style-src 'self' 'unsafe-inline'"
 	# Anti-clickjacking
 	response.header 'X-Frame-Options', 'DENY'
 	# PJAX


No need to expose bootstrap/ anymore.

No need to expose bootstrap/ anymore.

--- main.coffee
+++ main.coffee
@@ -62,7 +62,6 @@
 app.use express.urlencoded()
 app.use express.compress()

-app.use '/static/bootstrap', express.static(__dirname + '/bootstrap')
 #app.use '/img', express.static(__dirname + '/img')
 app.use '/static/browserified', express.static(__dirname + '/browserified')
 app.use '/static/bower_components', express.static(__dirname + '/bower_components')
@@ -87,16 +86,16 @@

 app.use ((request, response) ->
 	# Read basic stuff
-	request.uonline = {}
-	request.uonline.basicOpts = {}
-	request.uonline.basicOpts.now = new Date()
-	request.uonline.basicOpts.pjax = false
 	sessionData = lib.user.sessionInfoRefreshing.sync(null,
 		dbConnection, request.cookies.sessid, config.sessionExpireTime, true)
-	request.uonline.basicOpts.loggedIn = sessionData.sessionIsActive
-	request.uonline.basicOpts.username = sessionData.username
-	request.uonline.basicOpts.admin = sessionData.admin
-	request.uonline.basicOpts.userid = sessionData.userid
+	request.uonline =
+		basicOpts:
+			now: new Date()
+			pjax: false
+			loggedIn: sessionData.sessionIsActive
+			username: sessionData.username
+			admin: sessionData.admin
+			userid: sessionData.userid
 	# CSP
 	response.header 'Content-Security-Policy-Report-Only',
 		"default-src 'self'; script-src 'self' http://code.jquery.com"


fix tests for travis

fix tests for travis

--- test/all.coffee
+++ test/all.coffee
@@ -1,7 +1,6 @@
 silo = require '../'
 should = require 'should'
 redis = require 'redis'
-mongo = require 'mongodb'
 require 'mocha'

 for adapter,v of silo when adapter isnt 'Store'


Added bin tests

Added bin tests

--- test/bin.coffee
+++ test/bin.coffee
@@ -90,9 +90,28 @@
       stderr.should.match /unknown/i
       done()

-  it 'should compile a kdapp'

-  it 'should support coffee kdapps'
+  it 'should compile a kdapp', (done) ->
+    stub = path.join __dirname, 'stubs', 'nodeps'
+    bin [stub], (err, stdout, stderr) ->
+      should.not.exist err
+      stdout.should.equal ''
+      stderr.should.match /success/i
+      done()

-  it 'should support commonjs kdapps'
+  it 'should support plain javascript kdapps', (done) ->
+    stub = path.join __dirname, 'stubs', 'plainjs'
+    bin [stub], (err, stdout, stderr) ->
+      should.not.exist err
+      stdout.should.equal ''
+      stderr.should.match /success/i
+      done()

+  it 'should support commonjs kdapps', (done) ->
+    stub = path.join __dirname, 'stubs', 'commonjs'
+    bin [stub], (err, stdout, stderr) ->
+      should.not.exist err
+      stdout.should.equal ''
+      stderr.should.match /success/i
+      done()
+


added identity test for bc

added identity test for bc

--- test/binomial_coefficient.test.coffee
+++ test/binomial_coefficient.test.coffee
@@ -17,6 +17,17 @@
     assert.equal bc(16, 8), 12870
     assert.equal bc(52, 13), 635013559600

+  it 'should satisfy the identity theorem for binomial coefficients (n k) == (n (n - k))', ->
+    identity = (n, k) ->
+      assert.equal bc(n, k), bc(n, (n - k))
+
+    i = 52
+    while i--
+      j = i
+
+      while j--
+        identity i, j
+

   it 'should throw an error when k is greater than n', ->
     assert.throws (-> bc 0, 1), /must be greater than or equal to/


Testing

Testing

--- widgets/cusi_progress_bars/cusi_progress_bars.coffee
+++ widgets/cusi_progress_bars/cusi_progress_bars.coffee
@@ -90,7 +90,8 @@

     innerProgressBar = $("<div/>")
       .attr("class", "inner-progress-bar")
-      .text("0%")
+      .text("0")
+#      .text("0%")
     innerProgressBar.css("width", "0%")

     # Put it all together.


Changed how messages are updated after keypresses.

Now messages are updated after each valid keypress, no matter whether the
movement was allowed or not.

This way, if the player can move from the starting position only by going up or
down, she will still get the instruction on how to do that.

--- maze.coffee
+++ maze.coffee
@@ -249,16 +249,22 @@
     $(document).keyup((event) =>
       if event.which == 82 # R key
         @go_up()
+        @update_msg()
       else if event.which == 70 # F key
         @go_down()
+        @update_msg()
       else if event.which == 37 # Left key
         @go_left()
+        @update_msg()
       else if event.which == 38 # Up key
         @go_forward()
+        @update_msg()
       else if event.which == 39 # Right key
         @go_right()
+        @update_msg()
       else if event.which == 40 # Down key
         @go_backward()
+        @update_msg()
     )

     # messagebox
@@ -271,14 +277,12 @@
       @floors[@z].animate(@below, 1500)
       @z += 1
       @floors[@z].animate(@here, 1500)
-      @update_msg()

   go_down: ->
     if @maze.passage_exists([[@x, @y, @z - 1], [@x, @y, @z]])
       @floors[@z].animate(@above, 1500)
       @z -= 1
       @floors[@z].animate(@here, 1500)
-      @update_msg()

   go_backward: ->
     if @maze.passage_exists([[@x, @y, @z], [@x, @y + 1, @z]])
@@ -305,7 +309,6 @@
         top: @y * 71
         left: @x * 71
     })
-    @update_msg()

   update_msg: ->
     if @maze.is_target([@x, @y, @z])


Fix test for settings-split

Fix test for settings-split

--- tests/integration/components/settings-split-test.coffee
+++ tests/integration/components/settings-split-test.coffee
@@ -13,4 +13,4 @@

   @render hbs """{{settings-split}}"""

-  assert.equal @$().text().trim(), 'GeneralSecurityNamespaceNo Namespace!!!+ Add NamespaceAdd NamespaceAdd NamespaceLanguageSelect the preferred language belowEnglish日本語JIRA IntegrationIntegrate JIRAAre you sure you want to revoke JIRA Integration?CancelOkGitHub IntegrationIntegrate GitHubAre you sure you want to revoke Github Integration?CancelOk'
+  assert.equal @$().text().trim(), 'GeneralSecurityDeveloper SettingsNamespaceNo Namespace!!!+ Add NamespaceAdd NamespaceAdd NamespaceLanguageSelect the preferred language belowEnglish日本語JIRA IntegrationIntegrate JIRAAre you sure you want to revoke JIRA Integration?CancelOkGitHub IntegrationIntegrate GitHubAre you sure you want to revoke Github Integration?CancelOk'


Update - D:09032021-H:215001

Update - D:09032021-H:215001

--- assets/js/contact.coffee
+++ assets/js/contact.coffee
@@ -4,25 +4,48 @@
 #  Load data
 {% include liquid/data %}

-($) ->
-    $('form').submit (e) ->
-        event.preventDefault()
-        $.ajax
-            url: 'https://formspree.io/f/{{ load_data.website.content.contact.formspree.endpoint }}'
-            method: 'POST'
-            data: {
-                name: $('#name').val()
-                subject: $('#subject').val()
-                email: $('#email').val()
-                message: $('#message').val()
-            }
-            dataType: 'json'
-        .done ->
-            $('#name').val('')
-            $('#subject').val('')
-            $('#email').val('')
-            $('#message').val('')
-    false
+
+$('#submit').click ->
+  $('#name').val ''
+  $('#subject').val ''
+  $('#email').val ''
+  $('#message').val ''
+  return
+
+# $('#submit').click(function() {
+#      $("#name").val("");
+#      $("#subject").val("");
+#      $("#email").val("");
+#      $("#message").val("");
+# });
+
+# $(function($){
+#  	$("form").submit(function(event) {
+#  		event.preventDefault();
+
+#  	});
+#  }) ;
+
+#  ($) ->
+#     $('form').submit (e) ->
+#         event.preventDefault()
+#         $.ajax
+#             url: 'https://formspree.io/f/{{ load_data.website.content.contact.formspree.endpoint }}'
+#             method: 'POST'
+#             data: {
+#                 name: $('#name').val()
+#                 subject: $('#subject').val()
+#                 email: $('#email').val()
+#                 message: $('#message').val()
+#             }
+#             dataType: 'json'
+#         .done ->
+#             $('#name').val('')
+#             $('#subject').val('')
+#             $('#email').val('')
+#             $('#message').val('')
+#     false
+

 ###### DEPRECATED #########


making INDEX_SEGMENT_TYPE_ID statically accessible

--- js/src/indexing/ObjectIndexingService.coffee
+++ js/src/indexing/ObjectIndexingService.coffee
@@ -44,12 +44,12 @@
   # constants
   MINIMUM_TOKEN_LENGTH = 1

-  # defined in com.kryptnostic.v2.storage.types.TypeUUIDs
-  INDEX_SEGMENT_TYPE_ID = '00000000-0000-0000-0000-000000000007'
-
   { validateVersionedObjectKey } = Validators

   class ObjectIndexingService
+
+    # defined in com.kryptnostic.v2.storage.types.TypeUUIDs
+    @INDEX_SEGMENT_TYPE_ID = '00000000-0000-0000-0000-000000000007'

     constructor: ->
       @cryptoServiceLoader = new CryptoServiceLoader()
@@ -120,7 +120,7 @@
     createInvertedIndexSegmentObject: (segmentAddressHash, objectKey, parentObjectKey) ->

       createObjectRequest = new CreateObjectRequest({
-        type: INDEX_SEGMENT_TYPE_ID,
+        type: ObjectIndexingService.INDEX_SEGMENT_TYPE_ID,
         parentObjectId: parentObjectKey,
         requiredCryptoMats: CryptoMaterial.DEFAULT_REQUIRED_CRYPTO_MATERIAL
       })


Remove debugging messages for Travis CI.

Removed the debugging messages used to debug the Travis CI build.

--- t/compiler/harness.coffee
+++ t/compiler/harness.coffee
@@ -21,13 +21,11 @@
         JOIN information_schema.columns AS columns USING (table_schema, table_name)
        WHERE table_type = 'BASE TABLE' AND tables.table_schema = ?
     """, [ mysql.name ], (error, results, fields) =>
-      console.log results
       if error
         callback error
       else
         for column in results
           (schema[column.TABLE_NAME] or= []).push(column.COLUMN_NAME)
         client.destroy()
-        console.log schema
         callback null, schema
 module.exports = require("proof") context


Updates atom config

Updates atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -6,7 +6,8 @@
     preferredLineLength: 100
     softWrap: true
     softWrapAtPreferredLineLength: true
-    invisibles: {}
+    invisibles:
+      {}
   core:
     ignoredNames: [
       ".git"
@@ -46,12 +47,18 @@
     js_preserve_newlines: false
     js_space_before_conditional: false
     beautifyEntireFileOnSave: false
-  linter: {}
+  linter:
+    ignoredLinterErrors: [
+      "jshint"
+    ]
   "autocomplete-plus":
-    confirmCompletion: "enter"
-  "linter-jshint": {}
-  "git-plus": {}
-  react: {}
+    {}
+  "linter-jshint":
+    {}
+  "git-plus":
+    {}
+  react:
+    {}
 ".js.jsx.source":
   editor:
     preferredLineLength: 100


Remove imdone-atom

Remove imdone-atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -4,6 +4,7 @@
     invisibles: {}
     showInvisibles: true
     fontFamily: "Roboto Mono"
+    fontSize: 15
   core:
     excludeVcsIgnoredPaths: true
     ignoredNames: [
@@ -20,7 +21,6 @@
       "exception-reporting"
       "metrics"
       "language-todo"
-      "imdone-atom"
     ]
     projectHome: "/home/mbaxa/git"
   "spell-check":


prepare test for ember view and controller/model binding

--- test/cases/client/viewTest.coffee
+++ test/cases/client/viewTest.coffee
@@ -12,4 +12,37 @@
     test '#renderEmberView', ->
       view.renderEmberView('posts/index')

-      assert.ok Tower.stateManager.get('currentView')+      assert.ok Tower.stateManager.get('currentView')
+
+    describe 'ember'
+      # @todo
+      test 'index', ->
+        Ember.TEMPLATES['posts/index'] = Ember.Handlebars.compile """
+

+  {{each App.postsController.all}}
+

+      {{title}}
+

+  {{/each}}
+

+"""
+        ### going to look something like this in a day or two
+        class App.PostsController extends Tower.Controller
+          all: App.Post.all()
+        ###
+
+        App.Post.create(rating: 8, title: "First Post!")
+
+        App.subscribe 'posts', App.Post.all()
+
+        App.setPath('postsController', App.posts)
+
+        view.renderEmberView('posts/index')
+
+        assert.equal $('#posts-list').html(), """
+

+  First Post!
+

+"""
+
+


whitespace :scissors:

whitespace :scissors:

--- lib/capybara/poltergeist/client/agent.coffee
+++ lib/capybara/poltergeist/client/agent.coffee
@@ -100,7 +100,7 @@
     event.keyCode  = keyCode
     event.which    = keyCode
     event.charCode = 0
-    @element.dispatchEvent(event)
+    @element.dispatchEvent(event)

   keypressed: (altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) ->
     event = document.createEvent('UIEvents')
@@ -152,14 +152,14 @@
       value = value.substr(0, @element.maxLength)

     @element.value = ''
-    this.trigger('focus')
+    this.trigger('focus')

     for char in value
       @element.value += char

       keyCode = this.characterToKeyCode(char)
       this.keyupdowned('keydown', keyCode)
-      this.keypressed(false, false, false, false, char.charCodeAt(0), char.charCodeAt(0))
+      this.keypressed(false, false, false, false, char.charCodeAt(0), char.charCodeAt(0))
       this.keyupdowned('keyup', keyCode)

     this.changed()
@@ -243,7 +243,7 @@

   characterToKeyCode: (character) ->
     code = character.toUpperCase().charCodeAt(0)
-    specialKeys =
+    specialKeys =
       96: 192  #`
       45: 189  #-
       61: 187  #=


Tests: Added deleteWorkspace test.

Tests: Added deleteWorkspace test.

--- tests/src/ide/ide.coffee
+++ tests/src/ide/ide.coffee
@@ -194,3 +194,23 @@
     helpers.createWorkspace(browser)
     browser.end()

+
+  deleteWorkspace: (browser) ->
+
+    workspaceName = helpers.createWorkspace(browser)
+
+    browser.url (data) =>
+      url               = data.value
+      vmName            = url.split('/IDE/')[1].split('/')[0]
+      workspaceSelector = 'a[href="/IDE/' + vmName + '/' + workspaceName + '"]'
+      modalSelector     = '.activity-modal.ws-settings'
+
+      browser
+        .waitForElementVisible     workspaceSelector, 20000
+        .click                     workspaceSelector
+        .click                     workspaceSelector + ' .ws-settings-icon'
+        .waitForElementVisible     modalSelector, 20000
+        .click                     modalSelector + ' button.red'
+        .waitForElementNotVisible  workspaceSelector, 20000
+        .end()
+


Increase the tiemout for one test for OSX

--- test/integration/move_file.coffee
+++ test/integration/move_file.coffee
@@ -44,7 +44,7 @@
             fs.rename srcPath, dstPath, done

         it 'waits a bit', (done) ->
-            setTimeout done, 4000
+            setTimeout done, 6000

         it 'has the file on local', ->
             files = fs.readdirSync @syncPath


fix tests

fix tests

--- test/pagerv2_commands_test.coffee
+++ test/pagerv2_commands_test.coffee
@@ -652,7 +652,7 @@
         say 'pager incident 1234', ->
           it 'returns details on the incident', ->
             expect(hubotResponse())
-            .to.eql 'PT4KHLK The server is on fire. - resolved (Earline Greenholt)'
+            .to.eql '[My Mail Service] PT4KHLK The server is on fire. - resolved (Earline Greenholt)'

     # ----------------------------------------------------------------------------------------------
     describe '".pager sup"', ->


Auth is not a valid call, adding some more debugging to investigate

--- scripts/jira-linkifier.coffee
+++ scripts/jira-linkifier.coffee
@@ -36,6 +36,7 @@
       robot.http(process.env.HUBOT_JIRA_INSTANCE_URL + "/rest/api/2/issue/" + shortcode + "-" + mention.match[1])
         .get( (err, req) ->
           console.log("adding username and password to request")
+          console.log("Auth keys are: " + Object.keys(req))
           req.auth(process.env.HUBOT_JIRA_READER_USERNAME, process.env.HUBOT_JIRA_READER_PASSWORD)
         ) (err, res, body) ->
           console.log("Recieved response from jira: " + body)


Fix a dumb issue

Fix a dumb issue

I attempted to abstract out some variables, and then forgot to reference
them in the header. We were trying with no useful auth, so it just blew up.

--- scripts/jira-linkifier.coffee
+++ scripts/jira-linkifier.coffee
@@ -64,7 +64,7 @@
     auth_header = 'Basic ' + new Buffer(credentials).toString('base64')

     robot.http(process.env.HUBOT_JIRA_INSTANCE_URL + "/rest/api/2/issue/" + project + "-" + ticket_number)
-      .header('Authorization', )
+      .header('Authorization', auth_header)
       .get() (err, res, body) ->
         issue = JSON.parse(body)
         console.log("Got back issue: " + body)


typo error in markdown plugin renderer

typo error in markdown plugin renderer

--- lib/plugins/renderers/markdown.plugin.coffee
+++ lib/plugins/renderers/markdown.plugin.coffee
@@ -12,7 +12,7 @@

 	# Render some content
 	render: ({inExtension,outExtension,templateData,file}, next) ->
-		tru
+		try
 			if inExtension in ['md','markdown'] and outExtension is 'html'
 				file.content = markdown.parse file.content
 				next()
@@ -22,4 +22,4 @@
 			return next(err)

 # Export Plugin
-module.exports = MarkdownPlugin+module.exports = MarkdownPlugin


#1534 class then "use strict": modified strict error condition

--- test/classes.coffee
+++ test/classes.coffee
@@ -623,7 +623,7 @@
 test "#1534: class then 'use strict'", ->
   # [14.1 Directive Prologues and the Use Strict Directive](http://es5.github.com/#x14.1)
   nonce = {}
-  error = '`arguments.callee`'
+  error = 'do -> ok this'
   strictTest = "do ->'use strict';#{error}"
   return unless (try CoffeeScript.run strictTest, bare: yes catch e then nonce) is nonce


Add find-next key commands

Add find-next key commands

--- keymaps/search-in-buffer.cson
+++ keymaps/search-in-buffer.cson
@@ -1,6 +1,9 @@
 '.editor':
   'meta-f': 'search-in-buffer:display-find'
   'alt-meta-f': 'search-in-buffer:display-replace'
+
+  'meta-g': 'search-in-buffer:find-next'
+  'meta-G': 'search-in-buffer:find-previous'

 '.search-in-buffer .mini.editor input':
   'enter': 'core:confirm',


Fix broken coffeescript tests.

Fix broken coffeescript tests.

--- Src/coffeescript/cql-execution/src/cql-datatypes.coffee
+++ Src/coffeescript/cql-execution/src/cql-datatypes.coffee
@@ -91,7 +91,7 @@
         date.getSeconds(),
         date.getMilliseconds())

-  constructor: (@year, @month, @day, @hour, @minute, @second, @millisecond, @timeZoneOffset) ->
+  constructor: (@year=null, @month=null, @day=null, @hour=null, @minute=null, @second=null, @millisecond=null, @timeZoneOffset=null) ->

   copy: () ->
     new DateTime(@year, @month, @day, @hour, @minute, @second, @millisecond, @timeZoneOffset)


Unused tests removed

Unused tests removed

--- test/database_test.coffee
+++ test/database_test.coffee
@@ -27,29 +27,6 @@
       user.id.should.equal 1
       done()

-  it 'should create new order for user', (done) ->
-    db.Order.create
-      UserId: 1
-      bid: 2.3666
-      value: 1
-    .complete (err, order) ->
-      done err if err?
-      order.should.exist
-      order.should.have.property 'bid'
-      order.should.have.property 'ask'
-      order.should.have.property 'value'
-      order.should.have.property 'UserId'
-      order.id.should.equal 1
-      done()
-
-  it 'should get orders related to test user', (done) ->
-    db.User.find(1).complete (err, user) ->
-      done err if err?
-      user.getOrders().complete (err, orders) ->
-        done err if err?
-        orders.should.have.length 1
-        done()
-
   it 'should be a available databases', (done) ->
     db.sequelize
       .query 'SHOW DATABASES'


Remove unneeded option from test helper

Remove unneeded option from test helper

--- test/deadline_test.coffee
+++ test/deadline_test.coffee
@@ -2,9 +2,12 @@
 Dateline = require '../lib'
 timekeeper = require 'timekeeper'

-testNativeMethod = (methodName, dateObj=new Date()) ->
+testNativeMethod = (methodName) ->
+  dateObj = new Date()
+  datelineObj = new Dateline(dateObj)
+
   it "calls through to native #{methodName} method", ->
-    assert.equal dateObj[methodName](), new Dateline(dateObj)[methodName]()
+    assert.equal dateObj[methodName](), datelineObj[methodName]()

 describe 'Dateline', ->
   before ->


fix counters

fix counters

--- server/models/message.coffee
+++ server/models/message.coffee
@@ -757,7 +757,6 @@

 module.exports = Message
-require('./model-events').wrapModel Message
 mailutils = require '../utils/jwz_tools'
 CONSTANTS = require '../utils/constants'
 {MSGBYPAGE, LIMIT_DESTROY, LIMIT_UPDATE, CONCURRENT_DESTROY} = CONSTANTS


Fixed bug with anonymous players' email addresses not making it through.

--- server/routes/contact.coffee
+++ server/routes/contact.coffee
@@ -17,7 +17,7 @@
     return res.end()

 createMailContext = (req, done) ->
-  sender = req.body.sender
+  sender = req.body.sender or req.body.email
   message = req.body.message
   user = req.user
   recipientID = req.body.recipientID


switch to 10 for O(n lg n) algos

switch to 10 for O(n lg n) algos

--- main.coffee
+++ main.coffee
@@ -381,13 +381,13 @@
                                 rectWidth = 32
                                 sort = isort
                         when 'qsort1'
-                                rectWidth = 4
+                                rectWidth = 10
                                 sort = -> qsort(false)
                         when 'qsort2'
-                                rectWidth = 4
+                                rectWidth = 10
                                 sort = -> qsort(true)
                         when 'hsort'
-                                rectWidth = 4
+                                rectWidth = 10
                                 sort = hsort

                 rectHeight = rectWidth


If env is debug display line and filename

--- main.coffee
+++ main.coffee
@@ -31,7 +31,21 @@
             text = JSON.stringify text
         return text

+    getFileAndLine: ->
+        stacklist = (new Error()).stack.split('\n').slice(3);
+        stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/gi;
+        stackReg2 = /at\s+()(.*):(\d*):(\d*)/gi;
+
+        s = stacklist[0]
+        sp = stackReg.exec(s) or stackReg2.exec(s)
+
+        filePath = sp[2].substr(process.cwd().length)
+        line = sp[3]
+        return ".#{filePath}:#{line} |"
+
     format: (level, texts) ->
+        texts.unshift(@getFileAndLine()) if process.env.DEBUG
+
         text = (@stringify text for text in texts).join(" ")

         text = "#{@options.prefix} | #{text}" if @options.prefix?
@@ -52,18 +66,6 @@
         console.warn @format 'warn', texts if process.env.NODE_ENV isnt 'test'

     error: (texts...) ->
-        stacklist = (new Error()).stack.split('\n').slice(2);
-        stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/gi;
-        stackReg2 = /at\s+()(.*):(\d*):(\d*)/gi;
-
-        s = stacklist[0]
-        sp = stackReg.exec(s) or stackReg2.exec(s)
-
-        filePath = sp[2].substr(process.cwd().length)
-        line = sp[3]
-        errDetails = ".#{filePath}:#{line} |"
-        texts.unshift(errDetails)
-
         console.error @format 'error', texts if process.env.NODE_ENV isnt 'test'

     debug: (texts...) ->


Move attribute deletion out of experimental mode

--- src/View/AttributeRow.coffee
+++ src/View/AttributeRow.coffee
@@ -277,7 +277,7 @@
     {hoverManager, editor} = @context

     isHovered = hoverManager.hoveredAttribute == attribute
-    canHaveMenu = editor.experimental
+    canHaveMenu = true
     isMenuHovered = @isMenuHovered
     isMenuVisible = canHaveMenu and (isHovered or isMenuHovered)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/metered.coffee
+++ test/metered.coffee
@@ -27,5 +27,6 @@
     name: 'turbo'

   equals obj.I.turbo, 100
+  equals obj.

 module()


destroy a placebo instance

destroy a placebo instance

--- test/placebo.coffee
+++ test/placebo.coffee
@@ -1,13 +1,10 @@
-# run with mocha
+# Placebo and its Mocha tests.

-# Mocha tests for the placebo.
-# a cloud server, or part of a configuration.
 should = require 'should'
-_      = require 'underscore'
+_      = require 'underscore'

 class Placebo
   @instances: []
-
   # TODO: Which methods should have what arguments? Should
   # destroy be an instance method?

@@ -17,7 +14,8 @@
     @instances.push new Placebo

   # Destroy a previously created server.
-  @destroy: ->
+  @destroy: (instance) ->
+    @instances.pop instance

   # List instances in the cloud
   @list: ->
@@ -43,19 +41,22 @@
   it 'can create a placebo instance with a config', ->
     should.exist Placebo.create

-  it 'can destroy a placebo instance, given its name', ->
-    should.exist Placebo.destroy
-
   describe 'when two instances exist', ->
+    l = null
+
     before ->
       (_ 2).times -> Placebo.create()
+      l = Placebo.list()

     it 'can list created instances', ->
-      l = Placebo.list()
       l.should.be.an.instanceof Array
       l.length.should.equal 2
       l[0].should.be.an.instanceof Placebo
       l[1].should.be.an.instanceof Placebo
+
+    it 'can destroy a placebo instance, given its name', ->
+      Placebo.destroy Placebo.list()[0]
+      l.length.should.equal 1

   describe 'a new placebo instance', ->
     placebo = null


Validating model attributes before saving an edited field

--- ribs.coffee
+++ ribs.coffee
@@ -683,6 +683,12 @@
                 value = editField.val()
                 changeSet = {}
                 changeSet[@options.field] = value
+
+                attrs = $.extend true, changeSet, @model.attributes
+                valid = @model._validate(attrs, @model)
+                unless valid
+                    return
+
                 # do whatever it takes to re-render
                 try
                     @model.save changeSet,


Add error message when encountering an error posting back without a proper error response object

--- lms/static/coffee/src/staff_grading/staff_grading.coffee
+++ lms/static/coffee/src/staff_grading/staff_grading.coffee
@@ -112,6 +112,7 @@
     else
       # TODO: replace with postWithPrefix when that's loaded
       $.post(@ajax_url + cmd, data, callback)
+        .error => callback({success: false, error: "Error occured while performing this operation"})

 class StaffGrading


Adjusted Map::forEach test

Adjusted Map::forEach test

--- test/spec/Snippets.coffee
+++ test/spec/Snippets.coffee
@@ -596,15 +596,15 @@
 		'''
 		'forEach iterates over entries': '''
 			var s = 0;
-			var map = new Map([["a", 123], ["b", "321"]]);
+			var map = new Map([["a", 123], ["b", 321]]);
 			map.forEach(function (value) {
 				s = s + value;
 			});
 			s
 		'''
 		'forEach keys': '''
-			var s = 0;
-			var map = new Map([["a", 123], ["b", "321"]]);
+			var s = "";
+			var map = new Map([["a", 123], ["b", 321]]);
 			map.forEach(function (value, key) {
 				s = s + key;
 			});


close after attr for js flash messages

close after attr for js flash messages

--- app/assets/javascripts/active_admin/lib/flash.js.coffee
+++ app/assets/javascripts/active_admin/lib/flash.js.coffee
@@ -1,14 +1,19 @@
 ActiveAdmin.flash =
   class Flash
-    @error: (message) ->
-      new @ message, "error"
-    @notice: (message) ->
-      new @ message, "notice"
+    @error: (message, close_after) ->
+      new @ message, "error", close_after
+    @notice: (message, close_after) ->
+      new @ message, "notice", close_after
     reference: ->
       @reference
-    constructor: (@message, @type = "notice") ->
+    constructor: (@message, @type = "notice", close_after) ->
       @reference = jQuery("<div>").addClass("flash flash_#{type}").text(message)
       jQuery ".flashes"
         .append @reference
+      @close_after close_after if close_after?
+    close_after: (close_after) ->
+      setTimeout =>
+        @close()
+      , close_after * 1000
     close: ->
       @reference.remove()


Fixes the extra-line bug when a message is posted

Signed-off-by: Akash Manohar J <e4cf979cf717fd295f4e4edc427ee1aee78fa7dc@akash.im>

--- app/assets/javascripts/backbone/views/chatbox.js.coffee
+++ app/assets/javascripts/backbone/views/chatbox.js.coffee
@@ -11,7 +11,9 @@

   postMessageOnEnter: (event)->
-    @postMessage(event) if event.keyCode== 13
+    if event.keyCode== 13
+      @postMessage(event)
+      event.preventDefault()

   postMessage: (event)->


Added Cart.changeVariant

Added Cart.changeVariant

--- app/assets/javascripts/sprangular/resources/cart.coffee
+++ app/assets/javascripts/sprangular/resources/cart.coffee
@@ -75,6 +75,11 @@
       $http.put '/api/cart/update_variant', params
         .success(@load)

+    changeVariant: (oldVariant, newVariant) ->
+      params = $.param(old_variant_id: oldVariant.id, new_variant_id: newVariant.id)
+
+      $http.put '/api/cart/change_variant', params
+        .success(@load)

   service.reload()
   service


rtmp/framedata: send video pakets, provide more information

--- rtmp.coffee
+++ rtmp.coffee
@@ -1974,12 +1974,16 @@
               seq.done()
             when 9  # Video Message (incoming)
               videoData = parseVideoMessage @stream, rtmpMessage.body
-              if videoData.isKeyFrame && @stream.name.indexOf("_proxy") != -1
+              if @stream.name.indexOf("_proxy") != -1
                 sps = h264.concatWithStartCodePrefix @stream.avcInfo.sps
                 pps = h264.concatWithStartCodePrefix @stream.avcInfo.pps
-                iframeNalUnitGlob = Buffer.concat [sps, pps, videoData.nalUnitGlob]
-
-                @emit 'video_iframe', @stream, iframeNalUnitGlob
+
+                iframeNalUnitGlob = videoData.nalUnitGlob
+
+                if (videoData.isKeyFrame)
+                  iframeNalUnitGlob = Buffer.concat [sps, pps, videoData.nalUnitGlob]
+
+                @emit 'video_framedata', @stream, iframeNalUnitGlob, videoData.isKeyFrame

               if videoData.nalUnitGlob?

@@ -2109,8 +2113,8 @@
         @emit 'stream_reset', args...
       sess.on 'video_start', (args...) =>
         @emit 'video_start', args...
-      sess.on 'video_iframe', (args...) =>
-        @emit 'video_iframe', args...
+      sess.on 'video_framedata', (args...) =>
+        @emit 'video_framedata', args...
       sess.on 'audio_start', (args...) =>
         @emit 'audio_start', args...
       sess.on 'video_data', (args...) =>
@@ -2310,8 +2314,8 @@
           @emit 'stream_reset', args...
         session.on 'video_start', (args...) =>
           @emit 'video_start', args...
-        session.on 'video_iframe', (args...) =>
-          @emit 'video_iframe', args...
+        session.on 'video_framedata', (args...) =>
+          @emit 'video_framedata', args...
         session.on 'audio_start', (args...) =>
           @emit 'audio_start', args...
         session.on 'video_data', (args...) =>
@@ -2394,8 +2398,8 @@
       @emit 'stream_reset', args...
     @rtmpSession.on 'video_start', (args...) =>
       @emit 'video_start', args...
-    @rtmpSession.on 'video_iframe', (args...) =>
-      @emit 'video_iframe', args...
+    @rtmpSession.on 'video_framedata', (args...) =>
+      @emit 'video_framedata', args...
     @rtmpSession.on 'audio_start', (args...) =>
       @emit 'audio_start', args...
     @rtmpSession.on 'video_data', (args...) =>


Fixed bug in group setup

Fixed bug in group setup

--- app/components/group-setup-page/group-setup-page.coffee
+++ app/components/group-setup-page/group-setup-page.coffee
@@ -15,7 +15,7 @@
     $scope.createGroup = (formData) ->
       LoadBar.start()
       Records.groups.build(name: formData.name, currencyCode: formData.currency.code, currencySymbol: formData.currency.symbol).save().then ->
-        Records.memberships.fetchMyMemberships(group.id).then (data) ->
+        Records.memberships.fetchMyMemberships().then (data) ->
           newGroup = _.find data.groups, (group) ->
             group.name == formData.name
           $state.go('group', {groupId: newGroup.id, firstTimeSeeingGroup: true})


modified fixture file name

modified fixture file name

--- test/typetalk.test.coffee
+++ test/typetalk.test.coffee
@@ -2,7 +2,7 @@
 nock = require 'nock'

 Adapter = require '../src/typetalk'
-Fixture = require './Fixtures'
+Fixture = require './fixtures'
 RobotMock = require './mock/robot'

 clientId = 'deadbeef'


Tinytest fix for pull request.

Tinytest fix for pull request.

--- tests/client.coffee
+++ tests/client.coffee
@@ -1,6 +1,6 @@
 renderToDiv = (comp) ->
   div = document.createElement("DIV")
-  Blaze.render(comp).attach(div)
+  Blaze.render(comp,div)
   div

 Tinytest.add "Accounts Entry - {{accountButtons}} helper", (test) ->


extra scores test added to BuildModels #46

--- tests/dbtest.coffee
+++ tests/dbtest.coffee
@@ -103,17 +103,17 @@

         it('should take a place at 2014-04-10', ()->
           gameObj = models.Game
-          should(moment(gameObj.getDataValue('date')).format('YYYY-MM-DD')).be.eql('2014-04-10')
+          moment(gameObj.date).format('YYYY-MM-DD').should.be.eql('2014-04-10')
         )

         it('should have kazzantip be a referee', ()->
           gameObj = models.Game
-          should(gameObj.getDataValue('referee')).be.eql('kazzantip')
+          gameObj.referee.should.be.eql('kazzantip')
         )

         it('should have mafia as a winner', ()->
           gameObj = models.Game
-          should(gameObj.getDataValue('result')).be.eql(constants.GAME_RESULT.MAFIA_WIN)
+          gameObj.result.should.be.eql(constants.GAME_RESULT.MAFIA_WIN)
         )

         it('should contain 10 players', ()->
@@ -173,7 +173,7 @@
           )
         )

-        it('should have FrankLin, Хедин and Кошка the best players', (done)->
+        it('should have FrankLin, Хедин and Кошка as the best players', (done)->
           buildModels(paper, (err, dbmodels)->
             if err
               done(err)
@@ -195,6 +195,30 @@
             ).error((err)->done(err))
           )
         )
+
+        it('should have FrankLin, Хедин and Кошка as players with 0.5 extra scores', (done)->
+          buildModels(paper, (err, dbmodels)->
+            if err
+              done(err)
+            models = dbmodels
+            gameID = models.Game.id
+            chainer = new Sequelize.Utils.QueryChainer
+            ['FrankLin', 'Хедин', 'Кошка'].forEach((playerName)->
+              chainer.add(db.Player.find({where: {name: playerName}}))
+            )
+            chainer.run().success((players)->
+              chainer2 = new Sequelize.Utils.QueryChainer
+              for player in players
+                chainer2.add(db.PlayerGame.find({where: ["PlayerId=#{player.id} and GameId=#{gameID}"]}))
+              chainer2.run().success((playerGames)->
+                for playerGame in playerGames
+                  playerGame.extra_scores.should.be.eql(0.5)
+                done()
+              ).error((err)->done(err))
+            ).error((err)->done(err))
+          )
+        )
+
         it('should have Марвел as a first killed by day player', (done)->
           buildModels(paper, (err, dbmodels)->
             if err


Client: Activity: Test: Included channel participants and channelparticipantinputwidget tests

--- client/activity/lib/components/test.coffee
+++ client/activity/lib/components/test.coffee
@@ -5,3 +5,6 @@
 require './browsepublicchannelsmodal/test'
 require './channelinfo/test'
 require './channellabel/test'
+require './channelparticipants/test'
+require './channelparticipantsinputwidget/test'
+


[Group Notifications] add case for jgroup, do nothing when user clicks jgroup item

--- client/app/CommonViews/messagesList.coffee
+++ client/app/CommonViews/messagesList.coffee
@@ -181,11 +181,15 @@
           title : "This post has been deleted!"
           duration : 1000

-    if @snapshot.anchor.constructorName is "JPrivateMessage"
-      appManager = KD.getSingleton "appManager"
-      appManager.open "Inbox"
-      appManager.tell 'Inbox', "goToMessages"
-    else if @snapshot.anchor.constructorName in ["JComment", "JReview", "JOpinion"]
-      KD.remote.api[@snapshot.anchor.constructorName].fetchRelated @snapshot.anchor.id, showPost
-    else unless @snapshot.anchor.constructorName is "JAccount"
-      KD.remote.api[@snapshot.anchor.constructorName].one _id : @snapshot.anchor.id, showPost
+    switch @snapshot.anchor.constructorName
+      when  "JPrivateMessage"
+        appManager = KD.getSingleton "appManager"
+        appManager.open "Inbox"
+        appManager.tell 'Inbox', "goToMessages"
+      when "JComment", "JReview", "JOpinion"
+        KD.remote.api[@snapshot.anchor.constructorName].fetchRelated @snapshot.anchor.id, showPost
+      when "JGroup"
+        # do nothing
+      else
+        unless @snapshot.anchor.constructorName is "JAccount"
+          KD.remote.api[@snapshot.anchor.constructorName].one _id : @snapshot.anchor.id, showPost


auth worker: add replyExchange param

auth worker: add replyExchange param

--- workers/auth/lib/auth/authworker.coffee
+++ workers/auth/lib/auth/authworker.coffee
@@ -153,7 +153,7 @@
     username, correlationName, socketId, deadService } = options

     params = { routingKey, username, correlationName
-               serviceGenericName, deadService }
+               serviceGenericName, deadService, replyExchange: @authExchange }

     @publishToService serviceUniqueName, method, params, callback


Rename root view serialization keys

Rename root view serialization keys

--- spec/fuzzy-finder-spec.coffee
+++ spec/fuzzy-finder-spec.coffee
@@ -142,7 +142,7 @@
           rootView.trigger 'fuzzy-finder:toggle-buffer-finder'
           rootView.open()

-          states = rootView.serialize().packageStates
+          states = rootView.serialize().packages
           states = _.map states['fuzzy-finder'], (path, time) -> [ path, time ]
           states = _.sortBy states, (path, time) -> -time


:fire: escapeSelector

:fire: escapeSelector

--- spec/fuzzy-finder-spec.coffee
+++ spec/fuzzy-finder-spec.coffee
@@ -8,9 +8,6 @@

 PathLoader = require '../lib/path-loader'
 DefaultFileIcons = require '../lib/default-file-icons'
-
-escapeSelector = (_selector) ->
-  _selector.replace(/\\/g, '\\\\')

 rmrf = (_path) ->
   if fs.statSync(_path).isDirectory()
@@ -120,7 +117,7 @@

           runs ->
             eachFilePath [rootDir1, rootDir2], (filePath) ->
-              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(escapeSelector(filePath)))
+              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(filePath))
               expect(item).toExist()
               nameDiv = item.querySelector("div:first-child")
               expect(nameDiv.dataset.name).toBe(path.basename(filePath))
@@ -136,12 +133,12 @@

           runs ->
             eachFilePath [rootDir1], (filePath) ->
-              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(escapeSelector(filePath)))
+              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(filePath))
               expect(item).toExist()
               expect(item.querySelectorAll("div")[1].textContent).toBe(path.join(path.basename(rootDir1), filePath))

             eachFilePath [rootDir2], (filePath) ->
-              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(escapeSelector(filePath)))
+              item = Array.from(projectView.element.querySelectorAll('li')).find((a) -> a.textContent.includes(filePath))
               expect(item).toExist()
               expect(item.querySelectorAll("div")[1].textContent).toBe(path.join(path.basename(rootDir2), filePath))

@@ -329,7 +326,7 @@
           runs ->
             items = Array.from(projectView.element.querySelectorAll('li'))
             eachFilePath [rootDir1], (filePath) ->
-              item = items.find((a) -> a.textContent.includes(escapeSelector(filePath)))
+              item = items.find((a) -> a.textContent.includes(filePath))
               expect(item).toExist()
               expect(item).not.toHaveText(path.basename(rootDir1))


Fix infinite loop caused by lack of function call

Need parens since there is no param

--- src/Lidsys/Application/Controller/assets/lidsys/football-models.js.coffee
+++ src/Lidsys/Application/Controller/assets/lidsys/football-models.js.coffee
@@ -349,7 +349,7 @@

                 pickCount = (k for own k of picksHash).length

-                @errors.pop while @errors.length
+                @errors.pop() while @errors.length > 0
                 data   = {fantasy_picks: picksHash}
                 @$http.post("/api/v1.0/football/fantasy-picks/", data)
                     .success((response) =>


once we've expanded += into a + on the rhs, make sure to replace += with =.  fixes all the pirouette animation demos

--- lib/closure-conversion.coffee
+++ lib/closure-conversion.coffee
@@ -1241,6 +1241,9 @@
                         property.value = @visit property.value
                 n

+        # we split up assignment operators +=/-=/etc into their
+        # component operator + assignment so we can mark lhs as
+        # setLocal/setGlobal/etc, and rhs getLocal/getGlobal/etc
         visitAssignmentExpression: (n) ->
                 lhs = n.left
                 rhs = @visit n.right
@@ -1253,6 +1256,7 @@
                                 left:     lhs
                                 right:    rhs
                         }
+                        n.operator = '='

                 if is_intrinsic "%slot", lhs
                         create_intrinsic setSlot_id, [lhs.arguments[0], lhs.arguments[1], new_rhs]


ensured Collection and attached Model works properly

--- node.coffee
+++ node.coffee
@@ -1,4 +1,5 @@
 autobahn = require "autobahn"
+_ = require "underscore"
 Backbone = require "backbone"
 [WAMP_Model, WAMP_Collection] = require "./backbone.wamp.coffee"

@@ -13,20 +14,38 @@

         url : "test_collection"

-        wamp_read : (options, autobahn)->
+        wamp_read : (options)->
+            {extra} = options
+
+            if extra.wamp_model_id
+                @get extra.wamp_model_id
+                .toJSON()
+            else
+                @toJSON()
+
+        wamp_create : (options)->
+            {data} = options
+
+            @add _.extend(data, id : parseInt _.uniqueId())
+            @last().toJSON()
+
+        wamp_update : (options)->
             {data, extra} = options

-            if extra.wamp_model_id
-                {id: 1, name: "John", age: 25}
-            else if extra.wamp_model_id is null
-                {id: 1, name: "John", age: 20}
-            else
-                [{a: 1, b: 2}, {c: 1, d: 2}]
+            @get extra.wamp_model_id
+            .set data

-            console.log arguments
-            [{a: 1, b: 2}, {c: 1, d: 2}]
+        wamp_patch : (options)->
+            {data, extra} = options

+            @get extra.wamp_model_id
+            .set data

+        wamp_delete : (options)->
+            {extra} = options
+
+            @remove @get extra.wamp_model_id
+            {}

     c = new Collection()


Clean up comment

Clean up comment

--- lib/hacks/filter-value.coffee
+++ lib/hacks/filter-value.coffee
@@ -3,7 +3,7 @@
 class FilterValue extends Value
   @names = ['filter']

-  # Use prefixed and unprefixed filter for Webkit transition
+  # Use prefixed and unprefixed filter for WebKit transition
   replace: (value, prefix) ->
     if prefix == '-webkit-'
       if value.indexOf('-webkit-filter') == -1


Fix bug multiple match in the same line

Fix bug multiple match in the same line

--- lib/php-class-provider.coffee
+++ lib/php-class-provider.coffee
@@ -30,10 +30,21 @@

     # Get the text for the line up to the triggered buffer position
     line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
-    console.log(line)

     # Match the regex to the line, and return the match
-    line.match(regex)?[0] or ''
+    matches = line.match(regex)
+
+    # Looking for the correct match
+    if matches?
+      for match in matches
+        start = bufferPosition.column - match.length
+
+        if start >= 0
+          word = editor.getTextInBufferRange([[bufferPosition.row, bufferPosition.column - match.length], bufferPosition])
+          if word == match
+            return match
+
+    return ''

   confirm: (suggestion) ->
     selection = @editor.getSelection()


Hound refactoring for access script

Hound refactoring for access script

--- src/scripts/hound.coffee
+++ src/scripts/hound.coffee
@@ -127,14 +127,8 @@
                 hound status for the morning"
     Logger.logToChannel response, 'ibizan-diagnostics'

-  robot.respond /hound\s*(.*)?$/i, id: 'hound', (res) ->
-    if res.message.user.name is 'hubot'
-      return
+  robot.respond /hound\s*(.*)?$/i, id: 'hound', userRequired: true, (res) ->
     user = Organization.getUserBySlackName res.message.user.name
-    if not user
-      res.reply "#{res.message.user.name} is not a valid user"
-      Logger.addReaction 'x', res.message
-      return

     command = res.match[1]
     if not command


Adds new url for old future-of-art page

Adds new url for old future-of-art page

--- desktop/apps/static/index.coffee
+++ desktop/apps/static/index.coffee
@@ -14,7 +14,7 @@
 app.set 'views', __dirname + '/templates'
 app.set 'view engine', 'jade'

-app.get '/future-of-art', (req, res) ->
+app.get '/the-future-of-art', (req, res) ->
   new Page(id: 'future-of-art').fetch
     cache: true
     error: res.backboneError


Use config schema, remove deprecatoins.

Use config schema, remove deprecatoins.

--- lib/simple-flake8-view.coffee
+++ lib/simple-flake8-view.coffee
@@ -13,12 +13,12 @@
   params = ["--show-source", filePath]
   ignoreErrors = atom.config.get "simple-flake8.ignoreErrors"
   mcCabeComplexityThreshold = atom.config.get "simple-flake8.mcCabeComplexityThreshold"
-  flake8cmd = atom.config.get "simple-flake8.flake8Command"
-
-  if not not ignoreErrors
+  flake8cmd = atom.config.get("simple-flake8.flake8Command", "flake8")
+  console.log(flake8cmd)
+  if ignoreErrors
     params.push("--ignore=#{ ignoreErrors }")

-  if not not mcCabeComplexityThreshold
+  if mcCabeComplexityThreshold
     params.push("--max-complexity=#{ mcCabeComplexityThreshold }")

   proc = process.spawn flake8cmd, params
@@ -53,13 +53,20 @@

 module.exports =
 class SimpleFlake8View extends SelectListView
-
-  configDefaults:
-    flake8Command: "flake8"
-    ignoreErrors: ""
-    mcCabeComplexityThreshold: ""
-    validateOnSave: true
   keyBindings: null
+  config:
+    flake8Command:
+      type: "string"
+      default: "flake8"
+    ignoreErrors:
+      type: "boolean"
+      default: false
+    mcCabeComplexityThreshold:
+      type: "string"
+      default: ""
+    validateOnSave:
+      type: "boolean"
+      default: true

   @activate: ->
     view = new SimpleFlake8View
@@ -68,9 +75,9 @@
   @deactivate: ->
     @disposable.dispose()

-  activate: (state) ->
-    atom.workspaceView.command 'simple-flake8:toggle', => @toggle()
-    atom.workspaceView.command 'core:save', =>
+  activate: ->
+    atom.commands.add 'atom-text-editor', 'simple-flake8:toggle', => @toggle()
+    atom.commands.add 'atom-text-editor', 'core:save', =>
       on_save = atom.config.get "simple-flake8.validateOnSave"
       if on_save == true
         @toggle()
@@ -79,13 +86,9 @@
     super
     @addClass('simple-flake8')

+
   getFilterKey: ->
     'message'
-
-  getGrammar: ->
-    editor = atom.workspace.getActiveTextEditor()
-    return unless editor?
-    return editor.getGrammar().name

   cancelled: -> @hide()

@@ -97,7 +100,9 @@

   show: ->
     # Get out of here unless this is a python file
-    return unless @getGrammar() == 'Python'
+    editor = atom.workspace.getActiveTextEditor()
+    return unless editor?
+    return unless editor.getGrammar().name == 'Python'

     @panel ?= atom.workspace.addModalPanel(item: this)
     @panel.show()
@@ -111,6 +116,7 @@
       @eventElement = atom.views.getView(atom.workspace)

     filePath = editor.getPath()
+    console.log(filePath)
     flake filePath, (errors) =>
       error_list = []
       if errors.length == 0
@@ -145,7 +151,7 @@
   confirmed: (error) ->
     @cancel()
     if error
-      editor = atom.workspace.getActiveEditor()
+      editor = atom.workspace.getActiveTextEditor()

       # Go to line -1 due to differencing in indexing
       editor.cursors[0].setBufferPosition(


Minor: remove unnecessary simicolumns

Minor: remove unnecessary simicolumns

--- src/resources-packaged/ops/javascript/orbeon/xforms/control/Upload.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/control/Upload.coffee
@@ -10,16 +10,16 @@
 #
 # The full text of the license is available at http://www.gnu.org/copyleft/lesser.html

-OD = ORBEON.util.Dom;
-ExecutionQueue = ORBEON.util.ExecutionQueue;
-Properties = ORBEON.util.Properties;
-UploadServer = ORBEON.xforms.server.UploadServer;
-Control = ORBEON.xforms.control.Control;
-Upload = ORBEON.xforms.control.Upload;
-Page = ORBEON.xforms.Page;
-Event = YAHOO.util.Event;
-YD = YAHOO.util.Dom;
-ProgressBar = YAHOO.widget.ProgressBar;
+OD = ORBEON.util.Dom
+ExecutionQueue = ORBEON.util.ExecutionQueue
+Properties = ORBEON.util.Properties
+UploadServer = ORBEON.xforms.server.UploadServer
+Control = ORBEON.xforms.control.Control
+Upload = ORBEON.xforms.control.Upload
+Page = ORBEON.xforms.Page
+Event = YAHOO.util.Event
+YD = YAHOO.util.Dom
+ProgressBar = YAHOO.widget.ProgressBar

 class Upload extends Control

@@ -99,4 +99,4 @@
         parentElement.replaceChild newInputElement, inputElement

 Page.registerControlConstructor Upload, (container) -> YD.hasClass container, "xforms-upload"
-ORBEON.xforms.control.Upload = Upload+ORBEON.xforms.control.Upload = Upload


Correct class/type/function labels

Correct class/type/function labels

--- lib/suggestion-builder.coffee
+++ lib/suggestion-builder.coffee
@@ -75,13 +75,25 @@
         m.symbols)...

   getMatches: (prefix,type) =>
+    isType = (type) ->
+      /^(?:class|type|data|newtype)/.test(type)
+    isClass = (type) ->
+      /^(?:class)/.test(type)
     @getSymbols()
       .filter (s) ->
-        s.name.startsWith(prefix)
+        s.name.startsWith(prefix)\
+          and (if type? then isType(s.type) else true)
       .map (s) =>
         text: s.name
         rightLabel: @trim s.type
-        type: type ? 'function'
+        type:
+          if isType(s.type)
+            if isClass(s.type)
+              'class'
+            else
+              'type'
+          else
+            'function'
         replacementPrefix: prefix
         description: s.type


syntactical changes

syntactical changes

--- library/nucleus/plumbs.coffee
+++ library/nucleus/plumbs.coffee
@@ -113,8 +113,8 @@
     (busy = require "toobusy").maxLag options.lag
     message = "Setting threshold maximum lag to %s ms"
     logger.info message.magenta, "#{options.lag}".bold
-    return do -> (request, response, next) ->
-        return next() unless busy() is yes
+    return (request, response, next, additional) ->
+        return next undefined unless busy() is yes
         response.writeHead 503, options.reason
         return response.end options.reason


Remove no-op code

Remove no-op code

--- src/scripts/modules/media/footer/inherits/tab/tab.coffee
+++ src/scripts/modules/media/footer/inherits/tab/tab.coffee
@@ -15,14 +15,11 @@

     events:
       'click > .book-page-toggle > .btn:not(.active)': 'toggleMedia'
-      'click > .book-page-toggle > .btn.active': 'stayHere'
       'click .content-display-button': 'contentDisplay'

     initialize: () ->
       super()
       @listenTo(@model, 'change:currentPage change:loaded change:currentPage.loaded', @render)
-
-    stayHere: (e) ->

     toggleMedia: (e) ->
       @media = $(e.currentTarget).data('media')


Nicer karma regex

Nicer karma regex

This lets us use punctuation.

It would be nice if we get tests ;)

--- scripts/karma.coffee
+++ scripts/karma.coffee
@@ -84,7 +84,7 @@
   karma = new Karma robot
   allow_self = process.env.KARMA_ALLOW_SELF or "true"

-  robot.hear /(?:[\(]([\w\d\. ]+)[\)]|([\w\d\.]+))\+\+(\s|$)/, (msg) ->
+  robot.hear /(?:[\(]([\S\s]+)[\)]|([\S]+[^()]))\+\+(\s|$)/, (msg) ->
     subject = (msg.match[1] || msg.match[2]).toLowerCase()
     if allow_self is true or msg.message.user.name.toLowerCase() != subject
       karma.increment subject
@@ -92,7 +92,7 @@
     else
       msg.send msg.random karma.selfDeniedResponses(msg.message.user.name)

-  robot.hear /(?:[\(]([\w\d\. ]+)[\)]|([\w\d\.]+))--(\s|$)/, (msg) ->
+  robot.hear /(?:[\(]([\S\s]+)[\)]|([\S]+[^()]))--(\s|$)/, (msg) ->
     subject = (msg.match[1] || msg.match[2]).toLowerCase()
     if allow_self is true or msg.message.user.name.toLowerCase() != subject
       karma.decrement subject


coroutines test script now can optionally take an IP address

--- Dev/scripts/tutorial_coroutines.coffee
+++ Dev/scripts/tutorial_coroutines.coffee
@@ -23,6 +23,8 @@

   .describe 'd',    'debug transport protocol'
   .alias    'd',    'debug'
+
+  .describe 'ip',   'specificy the ip address'

   .argv

@@ -83,11 +85,13 @@

 start = (itr) ->

+  url = if argv.ip? then "ws://#{argv.ip}:8342/ws" else 'ws://localhost:8342/ws'
+
   try

     # connect to game

-    yield from socket.open itr, 'ws://localhost:8342/ws'
+    yield from socket.open itr, url
     log.info "Connected to " + chalk.cyan socket.ws.url

     # check this is the right scene


Slightly cleaner syntax

Slightly cleaner syntax

--- resources/assets/coffee/react/beatmap-discussions/nominations.coffee
+++ resources/assets/coffee/react/beatmap-discussions/nominations.coffee
@@ -55,7 +55,7 @@

   render: =>
     requiredHype = @props.beatmapset.nominations.required_hype
-    hypeByUser = _.countBy @props.currentDiscussions.byFilter['praises']['generalAll'], 'user_id'
+    hypeByUser = _.countBy @props.currentDiscussions.byFilter.praises.generalAll, 'user_id'
     filteredHype = _.reject hypeByUser, (k, v) =>
       # no hyping your own maps
       parseInt(v) == @props.beatmapset.user_id


Refactor CreateAssignmentViewSpec.coffee

Refs: SIS-2692

Test plan:  Jenkins passes all the day long, forever and ever!

Change-Id: I3c7885f654440afc3c127869503f4a318cd2be11
Reviewed-on: https://gerrit.instructure.com/101959
Reviewed-by: Nick Houle <972e9d73d0c431cb094492b619fbc612b5441e91@instructure.com>
Tested-by: Jenkins
QA-Review: Mark McDermott <20dd8ba615f2257ea7254f93d6f30ae11aa4f904@instructure.com>
Product-Review: Brad Humphrey <9233b6f5388d6867a2a7be14d8b4ba53c86cfde2@instructure.com>

--- spec/coffeescripts/views/assignments/CreateAssignmentViewSpec.coffee
+++ spec/coffeescripts/views/assignments/CreateAssignmentViewSpec.coffee
@@ -14,7 +14,20 @@
   'helpers/fakeENV'
   'helpers/jquery.simulate'
   'compiled/behaviors/tooltip'
-], (Backbone, _, AssignmentGroupCollection, AssignmentGroup, Assignment, CreateAssignmentView, DialogFormView, $, tz, juneau, french, I18nStubber, fakeENV) ->
+], (
+  Backbone,
+  _,
+  AssignmentGroupCollection,
+  AssignmentGroup,
+  Assignment,
+  CreateAssignmentView,
+  DialogFormView,
+  $,
+  tz,
+  juneau,
+  french,
+  I18nStubber,
+  fakeENV) ->

   fixtures = $('#fixtures')

@@ -109,6 +122,12 @@
     view.$el.appendTo $('#fixtures')
     view.render()

+  nameLengthHelper = (view, length, maxNameLengthRequiredForAccount, maxNameLength, postToSis) ->
+    name = 'a'.repeat(length)
+    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = maxNameLengthRequiredForAccount
+    ENV.MAX_NAME_LENGTH = maxNameLength
+    return view.validateBeforeSave({name: name, post_to_sis: postToSis}, [])
+
   QUnit.module 'CreateAssignmentView',
     setup: ->
       @assignment1 = new Assignment(buildAssignment1())
@@ -335,70 +354,38 @@
     equal errors["name"].length, 1
     equal errors["name"][0]["message"], "Name is required!"

-  test "has an error when a name > 255 chars", ->
-    view = createView(@assignment3)
-
-    l1 = 'aaaaaaaaaa'
-    l2 = l1 + l1 + l1 + l1 + l1 + l1
-    l3 = l2 + l2 + l2 + l2 + l2 + l2
-
-    errors = view.validateBeforeSave(name: l3, [])
+  test "has an error when a name > 256 chars", ->
+    view = createView(@assignment3)
+    errors = nameLengthHelper(view, 257, false, 30, '0')
     ok errors["name"]
     equal errors["name"].length, 1
     equal errors["name"][0]["message"], "Name is too long, must be under 256 characters"

   test "allows assignment to save when a name < 255 chars, MAX_NAME_LENGTH is not required and post_to_sis is true", ->
     view = createView(@assignment3)
-    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = false
-
-    l1 = 'aaaaaaaaaa'
-    l2 = l1 + l1 + l1 + l1 + l1 + l1
-    l3 = l2 + l2 + l2 + l2 + l2 + l2
-
-    errors = view.validateBeforeSave({name: l3, post_to_sis: '1'}, [])
+    errors = nameLengthHelper(view, 254, false, 30, '1')
     equal errors.length, 0

   test "allows assignment to save when a name < 255 chars, MAX_NAME_LENGTH is not required and post_to_sis is false", ->
     view = createView(@assignment3)
-    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = false
-
-    l1 = 'aaaaaaaaaa'
-    l2 = l1 + l1 + l1 + l1 + l1 + l1
-    l3 = l2 + l2 + l2 + l2 + l2 + l2
-
-    errors = view.validateBeforeSave({name: l3, post_to_sis: '0'}, [])
+    errors = nameLengthHelper(view, 254, false, 30, '0')
     equal errors.length, 0

   test "has an error when a name > MAX_NAME_LENGTH chars if MAX_NAME_LENGTH is custom, required and post_to_sis is true", ->
     view = createView(@assignment3)
-    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = true
-    ENV.MAX_NAME_LENGTH = 5
-
-    l1 = 'aaaaaaaaaaa'
-
-    errors = view.validateBeforeSave({name: l1, post_to_sis: '1'}, [])
+    errors = nameLengthHelper(view, 7, true, 5, '1')
     ok errors["name"]
     equal errors["name"].length, 1
     equal errors["name"][0]["message"], "Name is too long, must be under #{ENV.MAX_NAME_LENGTH + 1} characters"

   test "allows assignment to save when name > MAX_NAME_LENGTH chars if MAX_NAME_LENGTH is custom, required and post_to_sis is false", ->
     view = createView(@assignment3)
-    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = true
-    ENV.MAX_NAME_LENGTH = 5
-
-    l1 = 'aaaaaaaaaaa'
-
-    errors = view.validateBeforeSave({name: l1, post_to_sis: '0'}, [])
+    errors = nameLengthHelper(view, 7, true, 5, '0')
     equal errors.length, 0

   test "allows assignment to save when name < MAX_NAME_LENGTH chars if MAX_NAME_LENGTH is custom, required and post_to_sis is true", ->
     view = createView(@assignment3)
-    ENV.MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT = true
-    ENV.MAX_NAME_LENGTH = 30
-
-    l1 = 'aaaaaaaaaaa'
-
-    errors = view.validateBeforeSave({name: l1, post_to_sis: '1'}, [])
+    errors = nameLengthHelper(view, 30, true, 30, '1')
     equal errors.length, 0

   test "don't validate name if it is frozen", ->


beacon_map load after window load - fix load syntax

--- app/assets/javascripts/actions/beacons_map.js.coffee
+++ app/assets/javascripts/actions/beacons_map.js.coffee
@@ -15,7 +15,7 @@
       onColor: 'primary'
       size: 'small'
   if $("#beacons-map").length > 0
-    console.log $("#beacons-maps").length
+    console.log $("#beacons-map").length
     map = new MicelloMap('rrVDMQe2qjBRuJP5dXv59kAeK77SD7','beacons-map')

     paramsMapper = new ParamsMapper('.map-view')


Update add-playlist-option.js.coffee

Update add-playlist-option.js.coffee

Select2 seems to have changed the way dynamic option creation works. This handles the change.

--- app/assets/javascripts/add-playlist-option.js.coffee
+++ app/assets/javascripts/add-playlist-option.js.coffee
@@ -5,7 +5,7 @@
 select_element.prepend(new Option(addnew))

 getSearchTerm = () ->
-  return $("#post_playlist_id").data('select2').$dropdown.find("input").val();
+  return $('span.select2-search--dropdown input').val();

 matchWithNew = (params, data) ->
   term = params.term || ''


did it just?!

did it just?!

--- app/assets/javascripts/components/articles.js.coffee
+++ app/assets/javascripts/components/articles.js.coffee
@@ -10,7 +10,6 @@
 		@setState articles: articles
 	doOrderFilta: (orderFilta) ->
 		console.log 'wtfbro'
-		@setState articles: articles
 	render: ->
 		React.DOM.div
 			className: 'articles'


Remove compare helper

Remove compare helper

--- app/assets/javascripts/ember/helpers/teams.js.coffee
+++ app/assets/javascripts/ember/helpers/teams.js.coffee
@@ -1,37 +1,2 @@
-Handlebars.registerHelper "compare", (lvalue, rvalue, options) ->
-  throw new Error("Handlerbars Helper 'compare' needs 2 parameters")  if arguments.length < 3
-  operator = options.hash.operator or "=="
-  operators =
-    "==": (l, r) ->
-      l is r
-
-    "===": (l, r) ->
-      l is r
-
-    "!=": (l, r) ->
-      l isnt r
-
-    "<": (l, r) ->
-      l < r
-
-    ">": (l, r) ->
-      l > r
-
-    "<=": (l, r) ->
-      l <= r
-
-    ">=": (l, r) ->
-      l >= r
-
-    typeof: (l, r) ->
-      typeof l is r
-
-  throw new Error("Handlerbars Helper 'compare' doesn't support the operator " + operator)  unless operators[operator]
-  result = operators[operator](lvalue, rvalue)
-  if result
-    options.fn this
-  else
-    options.inverse this
-
 Handlebars.registerHelper "signed_in", ->
   UsersController.signedInUser?


Added a filter th wraper moment.fromNow function

--- app/coffee/filters.coffee
+++ app/coffee/filters.coffee
@@ -31,6 +31,13 @@
     return (input, format) ->
         return moment(input).format(format)

+MomentFromNowFilter = ->
+    return (input, without_suffix) ->
+        if input
+            return moment(input).fromNow(without_suffix or false)
+        else
+           return ""
+
 LowercaseFilter = ->
     return (input) ->
         return if input then input.toLowerCase() else ""
@@ -55,6 +62,7 @@
 module = angular.module('greenmine.filters', [])
 module.filter("lowercase", LowercaseFilter)
 module.filter("momentFormat", MomentFormatFilter)
+module.filter("momentFromNow", MomentFromNowFilter)
 module.filter("slugify", SlugifyFilter)
 module.filter("truncate", TruncateFilter)
 module.filter("onlyVisible", OnlyVisibleFilter)


Updata ko.coffee (#5648)

Updata ko.coffee (#5648)

Co-authored-by: Valentin Bryukhanov <53545457af642b0f8712bb2cc004f120ce4436f4@gmail.com>
Co-authored-by: Matias Forbord <7d4dc3970a879d64548b3a155f22f7990dc8fc0c@users.noreply.github.com>

--- app/locale/ko.coco.coffee
+++ app/locale/ko.coco.coffee
@@ -42,7 +42,7 @@
     featured_partners_title1: "특집 기사"
     featured_partners_title2: "수상 & 파트너"
     featured_partners_blurb1: "CollegeBoard Endorsed Provider"
-    featured_partners_blurb2: "Best Creativity Tool for Students"
+    featured_partners_blurb2: "학생들을 위한 가장 좋은 창의력 도구"
     featured_partners_blurb3: "Top Pick for Learning"
     featured_partners_blurb4: "Code.org Official Partner"
     featured_partners_blurb5: "CSforAll Official Member"


Scrollbar integration goes on. New Scrollbar options. Some refactoring.

--- src/jquery.rondell.coffee
+++ src/jquery.rondell.coffee
@@ -77,18 +77,24 @@
       effect: null              # Special effect function for the focused item, not used currently
       onAfterShift: null
       scrollbar:
+        _instance: null
+        enabled: false
+        orientation: "bottom"
         start: 0
         end: 100
         stepSize: 1
         position: 50
+        padding: 10
+        width: "100%"
+        repeating: false
         onScroll: undefined
         scrollOnHover: false
         scrollOnDrag: true
-        animationDuration: 400
+        animationDuration: 200
         easing: "easeInOutQuad"
-        drag:
-          dragging: false
-          lastDragEvent: 0
+        _drag:
+          _dragging: false
+          _lastDragEvent: 0

   ### Add default easing function for rondell to jQuery if missing ###
   unless $.easing.easeInOutQuad
@@ -100,7 +106,7 @@
     @rondellCount: 0            # Globally stores the number of rondells for uuid creation
     @activeRondell: null        # Globally stores the last activated rondell for keyboard interaction

-    constructor: (options, numItems, initCallback=undefined) ->
+    constructor: (container, options, numItems, initCallback=undefined) ->
       @id = Rondell.rondellCount++
       @items = [] # Holds the items
       @maxItems = numItems
@@ -133,6 +139,26 @@
       @size =
         width: @size.width or @center.left * 2
         height: @size.height or @center.top * 2
+
+      # Wrap elements in new container
+      @container = container.wrapAll($("
").css(@size)).parent()
+
+      # Show items hidden parent container to prevent graphical glitch
+      @container.parent().show() if @showContainer
+
+      # Create scrollbar
+      if @scrollbar.enabled
+        scrollbarContainer = $ "
"
+        @container.append scrollbarContainer
+
+        $.extend true, @scrollbar,
+          onScroll: @shiftTo
+          start: 1
+          end: @maxItems
+          position: @currentLayer
+          repeating: @repeating
+
+        @scrollbar._instance = new RondellScrollbar(scrollbarContainer, @scrollbar)

     # Animation functions, can be different for each rondell
     funcLeft: (layerDiff, rondell, idx) ->
@@ -209,7 +235,6 @@
           when 'mouseenter' then @_onMouseEnterItem layerNum
           when 'mouseleave' then @_onMouseLeaveItem layerNum
           when 'click'
-            console.log layerNum
             e.preventDefault() if @currentLayer isnt layerNum
             @shiftTo(layerNum) if item.object.is(':visible') and not item.hidden
             return false
@@ -300,7 +325,7 @@

       if icon.width() > 0 or (icon[0].complete and icon[0].width > 0)
         # Image is already loaded (i.e. from cache)
-        @_onloadItem(itemIndex, obj)
+        @_onloadItem itemIndex, obj
       else
         # Create copy of the image and wait for the copy to load to get the real dimensions
         copy = $("")
@@ -323,23 +348,21 @@
       controls = @controls
       if controls.enabled
         @controls._shiftLeft = $('').text(@strings.prev).click(@shiftLeft)
-        .css(
+        .css
           left: controls.margin.x
           top: controls.margin.y
-          "z-index": @zIndex + @maxItems + 2
-        )
+          zIndex: @zIndex + @maxItems + 2

         @controls._shiftRight = $('').text(@strings.next).click(@shiftRight)
-        .css(
+        .css
           right: controls.margin.x
           top: controls.margin.y
-          "z-index": @zIndex + @maxItems + 2
-        )
+          zIndex: @zIndex + @maxItems + 2

-        @container.append(@controls._shiftLeft, @controls._shiftRight)
+        @container.append @controls._shiftLeft, @controls._shiftRight

       # Attach keydown event to document for each rondell instance
-      $(document).keydown(@keyDown)
+      $(document).keydown @keyDown

       # Enable rondell traveling with mousewheel if plugin is available
       @container.bind('mousewheel', @_onMousewheel) if @mousewheel.enabled and $.fn.mousewheel?
@@ -470,12 +493,13 @@
         @_autoShiftInit()
         @showCaption(layerNum) if @hovering or @alwaysShowCaption or @_onMobile()

+      # If icon isn't resizeable animate margins
       if item.icon and not item.resizeable
         margin = (@itemProperties.sizeFocused.height - item.icon.height()) / 2
-        item.icon.stop(true).animate(
+        item.icon.stop(true).animate
             marginTop: margin
             marginBottom: margin
-          , @fadeTime)
+          , @fadeTime

     layerFadeOut: (layerNum) =>
       item = @_getItem(layerNum)
@@ -512,6 +536,7 @@

         newTarget.opacity = @funcOpacity layerDiff, @, layerNum

+        # Do nothing if target hasn't changed
         lastTarget = item.lastTarget
         return if lastTarget \
           and lastTarget.width is newTarget.width \
@@ -545,6 +570,7 @@
                 marginTop: margin
                 marginBottom: margin
               , fadeTime
+
       else if item.hidden
         # Update position even if out of view to fix animation when reappearing
         item.object.css newTarget
@@ -577,7 +603,12 @@
         @layerFadeIn(@currentLayer)

       @_refreshControls()
+
+      # Fire shift callback
       @onAfterShift? layerNum
+
+      # Update scrollbar
+      @scrollbar._instance.setPosition(layerNum, false) if @scrollbar.enabled

     _refreshControls: =>
       return unless @controls.enabled
@@ -615,111 +646,129 @@
       Rondell.activeRondell is @id

     keyDown: (e) =>
+      return unless @isActive() and @isFocused()
+
       # Ignore event if some time has passed since last keyevent
       now = (new Date()).getTime()
       return if @_lastKeyEvent > now - @keyDelay

-      if @isActive() and @isFocused()
-        # Clear current rotation timer on user interaction
-        if @autoRotation._timer >= 0
-          window.clearTimeout(@autoRotation._timer)
-          @autoRotation._timer = -1
-
-        @_lastKeyEvent = now
-
-        switch e.which
-          # arrow left
-          when 37 then @shiftLeft(e)
-          # arrow right
-          when 39 then @shiftRight(e)
+      # Clear current rotation timer on user interaction
+      if @autoRotation._timer >= 0
+        window.clearTimeout @autoRotation._timer
+        @autoRotation._timer = -1
+
+      @_lastKeyEvent = now
+
+      switch e.which
+        # arrow left
+        when 37 then @shiftLeft(e)
+        # arrow right
+        when 39 then @shiftRight(e)

   class RondellScrollbar

     constructor: (container, options) ->
-      @id = Wonderbar.wonderbarCount++
       @container = container.addClass "rondell-scrollbar"

       $.extend true, @, $.rondell.defaults.scrollbar, options
+
+      @container.addClass("rondell-scrollbar-#{@orientation}")
+      .css "width", @width

       @_initControls()
-
+
+      @_minX = @padding + @scrollLeftControl.outerWidth() + @scrollControl.outerWidth() / 2
+      @_maxX = @container.innerWidth() - @padding - @scrollRightControl.outerWidth() - @scrollControl.outerWidth() / 2
+
     _initControls: =>
-      @scrollLeftControl = $("
")
+      @scrollLeftControl = $("
")
         .bind "click", @scrollLeft

-      @scrollRightControl = $("
")
+      @scrollRightControl = $("
")
         .bind "click", @scrollRight

-      @scrollControl = $("
").css
+      @scrollControl = $("
").css
         left: @container.innerWidth() / 2

-      @scrollBackground = $("
")
-
-      @container.bind "mousedown mouseup click", @doControl
-      window.bind "mousemove", @doWindowControl
+      @scrollBackground = $("
")
+
+      @container.bind "mousedown click", @onControlEvent
+      $(window).bind "mousemove mouseup", @onWindowEvent

       @container.append @scrollBackground, @scrollLeftControl, @scrollRightControl, @scrollControl

-    updatePosition: (position) =>
+    updatePosition: (position, fireCallback=true) =>
       return if position < @start or position > @end or position is @position

       @position = position
-
+
       # Fire callback with new position
-      @onScroll?(position)
-
-    scrollTo: (x, duration=@animationDuration) =>
-      innerWidth = @container.innerWidth()
-      return if x <= 0 or x >= innerWidth
-
-      @scrollControl.stop(true).animate(
-        left: x
-      , duration, @easing)
+      @onScroll? position if fireCallback
+
+    scrollTo: (x, animate=true, fireCallback=true) =>
+      return if x < @_minX or x > @_maxX
+
+      target = { left: x }
+      if animate
+        @scrollControl.stop(true).animate target, @animationDuration, @easing
+      else
+        @scrollControl.stop(true).css target

       # Translate event coordinates to new position between start and end option
-      newPosition = Math.round(x / innerWidth * (@end - @start) + @start)
-      @updatePosition(newPosition) if newPosition isnt @position
-
-    setPosition: (position) =>
+      newPosition = Math.round((x - @_minX) / (@_maxX - @_minX) * (@end - @start)) + @start
+      @updatePosition(newPosition, fireCallback) if newPosition isnt @position
+
+    setPosition: (position, fireCallback=true) =>
+      if @repeating
+        position = @end if position < @start
+        position = @start if position > @end
+
       return if position < @start or position > @end or position is @position

-      @position = position
-
       # Translate position to new position for control dot in container
-      @scrollTo(Math.round((position - @start) / (@end - @start) * @container.innerWidth()))
-
-    doWindowControl: (e) =>
-      switch e.type
-        when "mousemove"
-          return unless @drag.dragging
-          @scrollTo(e.offsetX, 0) if e.target is @container[0]
-
-    doControl: (e) =>
+      newX = Math.round((position - @start) / (@end - @start) * (@_maxX - @_minX)) + @_minX
+      @scrollTo newX, true, fireCallback
+
+    onWindowEvent: (e) =>
+      return unless @_drag._dragging
+
+      if e.type is "mouseup"
+        # Release drag on mouseup
+        @_drag._dragging = false
+        @scrollControl.removeClass "rondell-scrollbar-dragging"
+      else if e.type is "mousemove"
+        # Move scroll dot to new position
+        newX = 0
+        if @orientation is "top" or @orientation is "bottom"
+          newX = Math.max(@_minX, Math.min(@_maxX, e.pageX - @container.offset().left))
+        else
+          newX = Math.max(@_minX, Math.min(@_maxX, e.pageY - @container.offset().top))
+
+        @scrollTo newX, false
+
+    onControlEvent: (e) =>
       e.preventDefault()
-
-      switch e.type
-        when "mousedown" then @drag.dragging = e.target is @scrollControl[0]
-        when "mouseup" then @drag.dragging = false
-        when "click" then @scrollTo(e.offsetX) if e.target is @container[0]
+
+      if e.type is "mousedown" and e.target is @scrollControl[0]
+        # Start drag event
+        @_drag._dragging = true
+        @scrollControl.addClass "rondell-scrollbar-dragging"
+      else if e.type is "click" and e.target is @scrollBackground[0] or e.target is @container[0]
+        # Jump to new position when clicking scroller background
+        @scrollTo(e.offsetX)

     scrollLeft: (e) =>
       e.preventDefault()
-      @setPosition(@position - @stepSize)
+      @setPosition @position - @stepSize

     scrollRight: (e) =>
       e.preventDefault()
-      @setPosition(@position + @stepSize)
+      @setPosition @position + @stepSize

   $.fn.rondell = (options={}, callback=undefined) ->
     # Create new rondell instance
-    rondell = new Rondell(options, @length, callback)
-
-    # Wrap elements in new container
-    rondell.container = @wrapAll($("
").css(rondell.size)).parent()
-
-    # Show items hidden parent container to prevent graphical glitch
-    rondell.container.parent().show() if rondell.showContainer
+    rondell = new Rondell(@, options, @length, callback)

     # Setup each item
     @each (idx) ->
@@ -727,10 +776,10 @@
       itemIndex = idx + 1

       if obj.is('img') or $('img:first', obj).length
-        rondell._loadItem(itemIndex, obj)
+        rondell._loadItem itemIndex, obj
       else
         # Init item without an icon
-        rondell._initItem(itemIndex,
+        rondell._initItem itemIndex,
           object: obj
           icon: null
           small: false
@@ -738,7 +787,6 @@
           resizeable: false
           sizeSmall: rondell.itemProperties.size
           sizeFocused: rondell.itemProperties.sizeFocused
-        )

     # Return rondell instance
     rondell


refactor BaseModel

refactor BaseModel

--- src/lib/base-model.coffee
+++ src/lib/base-model.coffee
@@ -78,15 +78,6 @@
         return props

-    ###
-    properties to cache, private.
-    ###
-    @_propOfCreatedAt: undefined
-    @_propOfUpdatedAt: undefined
-    @_modelProps: undefined
-
-
-
     ###*
     get prop name whose type is CREATED_AT
     notice: only one prop should be enrolled to CREATED_AT
@@ -96,6 +87,7 @@
     @static
     @return {String} propName
     ###
+    @_propOfCreatedAt: undefined
     @getPropOfCreatedAt: ->

         if @_propOfCreatedAt is undefined
@@ -118,6 +110,7 @@
     @static
     @return {String} propName
     ###
+    @_propOfUpdatedAt: undefined
     @getPropOfUpdatedAt: ->

         if @_propOfUpdatedAt is undefined
@@ -138,6 +131,7 @@
     @static
     @return {Array}
     ###
+    @_modelProps: undefined
     @getModelProps: ->

         if not @_modelProps?


refactor BaseModel

refactor BaseModel

--- src/lib/base-model.coffee
+++ src/lib/base-model.coffee
@@ -350,13 +350,13 @@

             # strip submodel's relation
-            if typeInfo.name is 'MODEL'
+            if typeInfo.equals 'MODEL'
                 if value instanceof BaseModel
                     plainObject[prop] = value.toPlainObject()
                 else
                     plainObject[prop] = value

-            else # typeInfo.name is 'MODELS'
+            else # typeInfo.equals 'MODELS'
                 plainObject[prop] =
                     for subData in value
                         if subData instanceof BaseModel
@@ -434,7 +434,7 @@
             for modelProp in @constructor.getModelProps()
                 propInfo = @constructor.properties[modelProp]

-                if propInfo.name is 'MODELS' and Array.isArray @[modelProp]
+                if propInfo.equals('MODELS') and Array.isArray @[modelProp]
                     for model in @[modelProp]
                         if model instanceof BaseModel
                             promise = model.include(recursive: true, modelPool: modelPool)


add check installed php on construct

add check installed php on construct

--- src/lib/parser/php.coffee
+++ src/lib/parser/php.coffee
@@ -11,11 +11,12 @@

   constructor: () ->
     @weigth = 1
-    @varToken = parseInt(exec("php -r \"echo T_VARIABLE;\"", {silent:true}).output)
-
     ignore = "T_INLINE_HTML,T_COMMENT,T_DOC_COMMENT,T_OPEN_TAG,T_OPEN_TAG_WITH_ECHO,T_CLOSE_TAG,T_WHITESPACE,T_USE,T_NS_SEPARATOR"
-    getIgnore = util.format "php -r \"echo json_encode([%s]);\"", ignore
-    @ignoreTokens = JSON.parse(exec(getIgnore, {silent:true}).output)
+    @foundphp = which.sync("php")
+    if @foundphp
+        @varToken = parseInt(exec("php -r \"echo T_VARIABLE;\"", {silent:true}).output)
+        getIgnore = util.format "php -r \"echo json_encode([%s]);\"", ignore
+        @ignoreTokens = JSON.parse(exec(getIgnore, {silent:true}).output)

   parse:  (file, content, fuzzy) ->
     stack = []
@@ -40,4 +41,4 @@
     token in @ignoreTokens

   registers: (mime, extension) ->
-    !!which.sync('php') && extension in ['php', 'php3', 'php4', 'php5']
+    !!@foundphp && extension in ['php', 'php3', 'php4', 'php5']