Only lint on save

Only lint on save

--- atom/symlink.config.cson
+++ atom/symlink.config.cson
@@ -22,8 +22,7 @@
   "tabs-to-spaces":
     onSave: "untabify"
   react: {}
-  linter:
-    lintOnFly: false
+  linter: {}
   "atom-alignment":
     alignBy: [
       ":="


Update ko.coffee (#5662)

Update ko.coffee (#5662)

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

* Update ko.coffee

70% translation complement - 'new_home'
50% transltaion complement - 'about'

* Update ko.coffee

100% translation 'about' & "subscribe'

* Update ko.coffee

Co-authored-by: Valentin Bryukhanov <53545457af642b0f8712bb2cc004f120ce4436f4@gmail.com>

--- app/locale/ko.coco.coffee
+++ app/locale/ko.coco.coffee
@@ -1121,9 +1121,9 @@
     shubhangi_title: "소프트웨어 엔지니어 팀장"
     retrostyle_title: "일러스트레이션"
     retrostyle_blurb: "레트로스타일 게임"
-    community_title: "...그리고 저희의 오픈소스 커뮤니티"
     bryukh_title: "게임플레이 개발자"
     bryukh_blurb: "퍼즐 구성자"
+    community_title: "...그리고 저희의 오픈소스 커뮤니티"
     community_subtitle: "500명이 넘는 Contributor분들이 CodeCombat 개발을 도와주고 계십니다, 매주 새로운 분들이 저희 프로젝트에 참여해주시고 계십니다!!"
     community_description_3: "CodeCombat 은"
     community_description_link_2: "커뮤니티 프로젝트입니다"


remove console.log

remove console.log

--- src/tools/SelectShape.coffee
+++ src/tools/SelectShape.coffee
@@ -35,7 +35,6 @@
     @_lc = lc

   _selectKeyDownListener: (e) =>
-    console.log(this)
     if(e.keyCode==46) #delete
       @_lc.deleteShape(@selectedShape)
       @_clearCurrentShape(@_lc)


return a 200 for root path for google health check

--- services/real-time/app.coffee
+++ services/real-time/app.coffee
@@ -43,6 +43,9 @@
 	io.set('transports', ['websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling'])
 	io.set('log level', 1)

+app.get "/", (req, res, next) ->
+	res.send "real-time-sharelatex is alive"
+
 app.get "/status", (req, res, next) ->
 	res.send "real-time-sharelatex is alive"


Update app.coffee

Update app.coffee

--- services/real-time/app.coffee
+++ services/real-time/app.coffee
@@ -61,7 +61,7 @@
 	res.send "debug mode will log next #{Settings.debugEvents} events"

 rclient = require("redis-sharelatex").createClient(Settings.redis.realtime)
-rclient.set "hello", "world"
+
 app.get "/health_check/redis", (req, res, next) ->
 	rclient.healthCheck (error) ->
 		if error?


Truncate error stack traces to 10 lines

Truncate error stack traces to 10 lines

--- services/real-time/app.coffee
+++ services/real-time/app.coffee
@@ -63,4 +63,7 @@

 server.listen port, host, (error) ->
 	throw error if error?
-	logger.log "real-time-sharelatex listening on #{host}:#{port}"+	logger.log "real-time-sharelatex listening on #{host}:#{port}"
+
+# Stop huge stack traces in logs from all the socket.io parsing steps.
+Error.stackTraceLimit = 10


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_clear.coffee
+++ src/engine_clear.coffee
@@ -16,7 +16,8 @@

   self.attrAccessor "clear", "backgroundColor"

-
+  self.bind "init", ->
+    if I.background

   self.bind "beforeDraw", ->
     if I.clear


Fixes elyssa/events module

Fixes elyssa/events module

--- src/events/index.coffee
+++ src/events/index.coffee
@@ -1,2 +1,2 @@
 define 'elyssa/events', ['elyssa/eventmap'], ->
-  Events = Events or new Elyssa.EventMap()
+  Events = Events or new EventMap()


[api] let's make it more RESTful

[api] let's make it more RESTful

--- src/express-bull.coffee
+++ src/express-bull.coffee
@@ -22,12 +22,14 @@
     bindRoutes()

   bindRoutes: ->
-    @router.get "/#{state}", @getHandler state for state in @states
-    @router.get "/data/id/:type/:id",    @dataById
-    @router.get "/pending/id/:type/:id", @makePendingById
-    @router.get "/delete/id/:type/:id",  @deleteById
-    @router.get "/delete/status/:type",  @deleteByStatus
-    @router.get "/queues",               @queues
+    @router.get "/queues",             @queues
+    @router.get "/:state/:id/pending", @makePendingById
+    @router.get "/:state/:id/delete",  @deleteById
+    @router.get "/:state/delete",      @deleteByState
+    @router.del "/:state/:id",         @deleteById
+    @router.get "/:state/:id",         @dataById
+    @router.get "/:state",             @state
+    @router.del "/:state",             @deleteByState

   getHandler: (state) -> (req, res, next) ->
     ideally = errify next


actualy generating a file v1_loader can read

--- src/art/engine/file/v1_writer.coffee
+++ src/art/engine/file/v1_writer.coffee
@@ -17,7 +17,8 @@
   ArtSolidFillTag
   BitmapsTag
   BitmapTag
-} = createTagFactories "bitmaps bitmap art_file pego art_bitmap children art_stencil_shape art_rectangle art_solid_fill"
+  RootTag
+} = createTagFactories "Root bitmaps bitmap art_file pego art_bitmap children art_stencil_shape art_rectangle art_solid_fill"

 elementNameToV1NameMap =
   Element: "pego"
@@ -72,7 +73,7 @@
     .then ([encodedProps, childrenTag]) =>
       encodedProps.art_engine_version = "0.0.2"
       encodedProps.kimi_editor_version = "0.6.0"
-      ArtFileTag encodedProps, childrenTag, @bitmapsTag
+      RootTag ArtFileTag encodedProps, childrenTag, @bitmapsTag

   toEncodedArtFile: (element) =>
     @toArtFileTags element
@@ -102,7 +103,7 @@
     .then (jpg) =>
       @bitmapTags[uniqueId] = BitmapTag
         bitmap_id: @bitmapTagCount++
-        bitmap: jpg
+        pixel_data: jpg

   _populateBitmapSubTagsRecursive: (element) ->
     {bitmap, children} = element


Usage of eval() is forbidden by FirefoxOS CSP

In privileged and certified FirefoxOS apps, the Content Security Policy forbids the usage of potentially hazardous functions such as eval(). This is a quick fix for the only occurrence of eval() in QuoJS.

--- src/quo.gestures.coffee
+++ src/quo.gestures.coffee
@@ -139,8 +139,8 @@
         diff = parseInt(GESTURE.initial_angle - angle, 10)
         if Math.abs(diff) > 20 or GESTURE.angle_difference isnt 0
             i = 0
-            symbol = if GESTURE.angle_difference < 0 then "-" else "+"
-            eval "diff " + symbol + "= 180;" while Math.abs(diff - GESTURE.angle_difference) > 90 and i++ < 10
+            symbol = if GESTURE.angle_difference < 0 then -1 else 1
+            diff += 180 * symbol while Math.abs(diff - GESTURE.angle_difference) > 90 and i++ < 10
             GESTURE.angle_difference = parseInt(diff, 10)
             _trigger "rotating", angle: GESTURE.angle_difference


Switch order of call to _listenTouches and declaration of _listenTouches

When importing this through RequireJS, the document.ready event fires immediately (as Quo is loaded after the document has already become ready) and at this point, _listenTouches is undefined.  Simply switching the order of the declaration prevents this issue.

--- src/quo.gestures.coffee
+++ src/quo.gestures.coffee
@@ -21,14 +21,14 @@
             $$(document.body).delegate @selector, event_name, callback
         @

-    $$(document).ready -> _listenTouches()
-
     _listenTouches = ->
         environment = $$ document.body
         environment.bind "touchstart", _onTouchStart
         environment.bind "touchmove", _onTouchMove
         environment.bind "touchend", _onTouchEnd
         environment.bind "touchcancel", _cleanGesture
+
+    $$(document).ready -> _listenTouches()

     _onTouchStart = (event) ->
         EVENT = event


Send grumpy message before setting volume.

--- src/scripts/spot.coffee
+++ src/scripts/spot.coffee
@@ -82,8 +82,10 @@
     spotRequest message, '/find', 'post', params, (err, res, body) ->
       message.send(":small_blue_diamond: #{body}")

-  robot.respond /(.*) says turn it down.*/i, (message) ->
+  robot.respond /(.*) says.*turn.*down.*/i, (message) ->
     name = message.match[1]
+    message.send("#{name} says, 'Turn down the music and get off my lawn!' :bowtie:")
     params = {volume: 15}
     spotRequest message, '/volume', 'put', params, (err, res, body) ->
-     message.send("#{name} says, 'Turn down the music and get off my lawn!' :bowtie:")+      message.send("Spot volume set to #{body}. :mega:")
+


watch css files

watch css files

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -139,6 +139,7 @@
   gulp.watch [
     paths.appFiles
     paths.testFiles
+    paths.appDir + '/styles/*.css'
     paths.appDir + '/index.html'
   ], ['test-and-build']
   browserSync


Fix js files are minified in __dev

Fix js files are minified in __dev

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -43,8 +43,10 @@

 compileLangHandler = (thisLang, sourcePath, destDir, options) ->
   compilerPipe = plugins[thisLang.compiler](options)
-  hvMinifier = !!plugins[thisLang.minifier]
   nowTime = new Date().toLocaleTimeString()
+
+  # if have minifier and it is now for production
+  hvMinifier = !!plugins[thisLang.minifier] and destDir.startsWith(compilePath)

   minifierPipe =
     if hvMinifier


toggle status

toggle status

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -8,11 +8,25 @@
 	update: ->
 		$('#debug').text $('#editor').html()
 	handleKeyDown: (e)->
+		# debug
 		$('#debug-keydown').text e.keyCode
-		console.log $('#debug-keydown').text()
+
+		switch e.keyCode
+			when 16 then @status.shift = true
+			when 17 then @status.ctrl = true
+			when 18 then @status.alt = true
+			when 91 then @status.cmd = true
+
 	handleKeyUp: (e)->
+		# debug
 		$('#debug-keyup').text e.keyCode
-		console.log e.keyCode
+
+		switch e.keyCode
+			when 16 then @status.shift = false
+			when 17 then @status.ctrl = false
+			when 18 then @status.alt = false
+			when 91 then @status.cmd = false
+
 	init: ->
 		@update()


fix for double js init. closes #758

fix for double js init. closes #758

--- app/assets/javascripts/comfy/admin/cms/base.js.coffee
+++ app/assets/javascripts/comfy/admin/cms/base.js.coffee
@@ -2,7 +2,9 @@

 window.CMS.code_mirror_instances = [ ]

-$ -> window.CMS.init()
+unless Turbolinks?.controller? # Turbolinks 5 verification
+  $ -> window.CMS.init()
+
 $(document).on 'page:load turbolinks:load', -> window.CMS.init()

 window.CMS.init = ->


handle initial drag in subject-viewer

handle initial drag in subject-viewer

--- app/assets/javascripts/components/subject-viewer.cjsx
+++ app/assets/javascripts/components/subject-viewer.cjsx
@@ -129,9 +129,15 @@
         # console.log 'SELECTED MARK: ', @state.selectedMark

   handleInitDrag: (e) ->
-
-    console.log 'handleInitDrag()'
-
+    mark = @state.selectedMark
+    offset = @getEventOffset e
+
+    # update mark
+    mark.x = offset.x
+    mark.y = offset.y
+    @setState selectedMark: mark
+    return offset
+
   handleInitRelease: (e) ->
     console.log 'handleInitRelease()'

@@ -211,6 +217,12 @@
                 isSelected={mark is @state.selectedMark}
                 handleMarkClick={@handleMarkClick.bind null, mark}
                 onClickDelete={@onClickDelete}
+                on={
+                  initStart:   @handleInitStart,
+                  initDrag:    @handleInitDrag,
+                  mouseDown:   @handleMouseDown,
+                  initRelease: @handleInitRelease
+                }
               />
             ), @
           }


Comment on pluralization rules

Comment on pluralization rules

--- app/assets/javascripts/uploadcare/locale/en.js.coffee
+++ app/assets/javascripts/uploadcare/locale/en.js.coffee
@@ -38,6 +38,11 @@
             button: 'Upload'

+  # Pluralization rules taken from:
+  # http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
+  #
+  # Note: English locale is used as a fallback and needs translations
+  # for all possible pluralization variants: zero, one, two, few, many, other.
   uploadcare.namespace 'uploadcare.locale.pluralize', (ns) ->
     ns.en = (n) ->
       return 'one' if n == 1


TerminalPane: Make editable/readonly when terminal is ready.

--- client/ide/lib/workspace/panes/ideterminalpane.coffee
+++ client/ide/lib/workspace/panes/ideterminalpane.coffee
@@ -129,10 +129,10 @@
       cursor.stopBlink()

-  makeEditable: -> @setEditMode yes
+  makeEditable: -> @ready => @setEditMode yes

-  makeReadOnly: -> @setEditMode no
+  makeReadOnly: -> @ready => @setEditMode no

   setSession: (session) ->


small bugfix

small bugfix

--- src/coffee/sphere_transformer.coffee
+++ src/coffee/sphere_transformer.coffee
@@ -219,7 +219,6 @@
         .then (json) =>
           @_incrementCounter(json, _.map(tasks, (t) -> t.defer))
         .fail (error) =>
-          consoel.info "err", error
           if error instanceof ErrorStatusCode and error.code is 404
             @_createSequence(tasks[0].options)
             .then (json) =>


Matching only theoricus files

Matching only theoricus files

--- tests/www/tests/server.coffee
+++ tests/www/tests/server.coffee
@@ -10,7 +10,6 @@

 matcher = (req)->
     parsed = url.parse req.url
-    console.log req.url, (parsed.pathname.match /js\/theoricus/)
     return parsed.pathname.match /js\/theoricus/

 exports.start = (coverage)->
@@ -21,8 +20,8 @@

   if coverage
     app.use '/coverage', istanbul.createHandler verbose: true, resetOnGet: true
-    app.use istanbul.createClientHandler root
-    app.use express.static root, matcher: matcher
+    app.use istanbul.createClientHandler root, matcher: matcher
+    app.use express.static root
   else
     app.use express.static root


removed css class interpolation

removed css class interpolation

--- hexaflip.coffee
+++ hexaflip.coffee
@@ -39,7 +39,7 @@
     @fontSize += 'px' if typeof @fontSize is 'number'

     unless @sets
-      @el.classList.add "#{ cssClass }-timepicker"
+      @el.classList.add cssClass + '-timepicker'
       @sets =
         hour: (i + '' for i in [1..12])
         minute: (i + '0' for i in [0..5])


Go back to the old number of git sha1 characters

--- js/inner.coffee
+++ js/inner.coffee
@@ -157,7 +157,7 @@
     "#{@vcs_url()}/commit/#{@vcs_revision()}"

   github_revision: =>
-    @vcs_revision().substring 0, 8
+    @vcs_revision().substring 0, 9

   author: =>
     @committer_name() or @committer_email()


Fix minor spacing

Fix minor spacing

--- js/inner.coffee
+++ js/inner.coffee
@@ -80,10 +80,12 @@
       _gaq.push(['_trackPageview', '/dashboard'])
     display "dashboard", {}

+
   loadAddProjects: (cx) =>
     @current_user().loadOrganizations()
     @current_user().loadCollaboratorAccounts()
     display "add_projects", {}
+

   loadProject: (cx, username, project) =>
     project_name = "#{username}/#{project}"
@@ -99,9 +101,6 @@
     $.getJSON "/api/v1/project/#{project_name}/#{build_num}", (data) =>
       @build(new CI.inner.Build data)
       @build().maybeSubscribe()
-
-
-
     display "build", {project: project_name, build_num: build_num}


Add param to image src attribute to bust cache

Closes #27

--- lib/image-editor-view.coffee
+++ lib/image-editor-view.coffee
@@ -16,11 +16,11 @@
         @div class: 'image-container-cell', =>
           @img outlet: 'image'

-  initialize: (editor) ->
+  initialize: (@editor) ->
     super

     @loaded = false
-    @image.hide().attr('src', editor.getUri())
+    @image.hide().attr('src', "#{@editor.getUri()}?time=#{Date.now()}")

     @image.load =>
       @originalHeight = @image.height()
@@ -43,7 +43,7 @@
         @changeBackground $(e.target).attr 'value'

       # Hide controls for jpg and jpeg images as they don't have transparency
-      if path.extname(@image.attr 'src').toLowerCase() in ['.jpg', '.jpeg']
+      if path.extname(@editor.getPath()).toLowerCase() in ['.jpg', '.jpeg']
         @imageControls.hide()

   # Retrieves this view's pane.


Add a comment about runtime color generation in ViolationTooltip


Changes the large default color to #333;

--- scripts/dash-spinner/configuration.coffee
+++ scripts/dash-spinner/configuration.coffee
@@ -26,7 +26,7 @@
   corners: 1,
   rotate: 0,
   direction: 1,
-  color: '#fff',
+  color: '#333',
   speed: 1.5,
   trail: 71,
   shadow: false,


fix(LandingExplain): fixed Helmuts changes to Partner section

--- src/components/LandingExplain.coffee
+++ src/components/LandingExplain.coffee
@@ -161,22 +161,17 @@
           div null, "Teammitglieder!"

       hr null
-
-     h2 null,
-        "Ein Projekt von",
-      a href:"http://www.ideenhochdrei.org/de/",
-        img className: "partnerLogo", src: require "../img/ideen.png"
-      a href:"http://slowtec.de",
-        img className: "partnerLogo", src: require "../img/slowtec.png"
-
-      h2 null,
-        "Unsere Partner",
-      a href:"https://www.engagement-global.de/rueckkehrende.html",
-        img className: "partnerLogo", src: require "../img/EngagementGlobal.jpg"
-      a href:"http://www.bmz.de/",
-        img className: "partnerLogo", src: require "../img/BMZ.jpg"
-      a href:"https://www.boell.de/de",
-        img className: "partnerLogo", src: require "../img/Heinrich_Böll.jpg"
-
-
-      hr null
+
+      h2 null, "Ein Projekt von"
+        a href:"http://www.ideenhochdrei.org/de/",
+          img className: "partnerLogo", src: require "../img/ideen.png"
+        a href:"http://slowtec.de",
+          img className: "partnerLogo", src: require "../img/slowtec.png"
+
+      h2 null, "Unsere Partner",
+        a href:"https://www.engagement-global.de/rueckkehrende.html",
+          img className: "partnerLogo", src: require "../img/EngagementGlobal.jpg"
+        a href:"http://www.bmz.de/",
+          img className: "partnerLogo", src: require "../img/BMZ.jpg"
+        a href:"https://www.boell.de/de",
+          img className: "partnerLogo", src: require "../img/Heinrich_Böll.jpg"


updating text and testing async button

updating text and testing async button

--- src/components/task-plan/footer.cjsx
+++ src/components/task-plan/footer.cjsx
@@ -2,6 +2,7 @@
 React = require 'react'
 BS = require 'react-bootstrap'
 {TaskPlanStore, TaskPlanActions} = require '../../flux/task-plan'
+AsyncButton = require '../async-button'

 PlanFooter = React.createClass
   displayName: 'PlanFooter'
@@ -51,6 +52,7 @@
           onClick={onPublish}
           isWaiting={isWaiting}
           isFailed={isFailed}
+          waitingText='Publishing…'
           >
           {'Publish'}
         </AsyncButton>
@@ -69,15 +71,14 @@
       saveLink =
         <BS.Col sm={6} md={2}>
           <AsyncButton
-            bsStyle='primary'
             className='-save'
             onClick={onSave}
             isWaiting={isWaiting}
             isFailed={isFailed}
+            waitingText='Saving…'
             >
             {'Save as Draft'}
           </AsyncButton>
-          <BS.Button className='-save' disabled onClick={onSave}>Save as Draft</BS.Button>
           <p>
             An assignment in draft will not be available to students, even if the open date has passed.
           </p>


fixes #42 The Answer to the Ultimate Question of Life, the Universe, and Everything.

      Seriously -> Prevent mute/unmute when no video is display.

--- src/frontend/modules/userList.coffee
+++ src/frontend/modules/userList.coffee
@@ -68,12 +68,15 @@

     muteStream  : (event) =>
         button = $ event.target
-        video = ((button.parents 'li.thumbnail-wrapper').find 'video')[0] # get the video tag for the li.
-        classI = if (do button.text) is 'mute' then 'icon-microphone' else 'icon-microphone-off'
-        text = if (do button.text) is 'mute' then 'unmute' else 'mute'
-        video.volume = @users[video.getAttribute 'rel']['volume'] = !video.volume
-        do button.empty
-        button.append "#{text}"
+        mainLi = button.parents 'li.thumbnail-wrapper'
+        video = (mainLi.find 'video')[0] # get the video tag for the li.
+        if video?
+            classI = if (do button.text) is 'mute' then 'icon-microphone' else 'icon-microphone-off'
+            text = if (do button.text) is 'mute' then 'unmute' else 'mute'
+            do button.empty
+            button.append "#{text}"
+            @users[video.getAttribute 'rel']['volume'] = !@users[video.getAttribute 'rel']['volume']
+            video.volume = @users[video.getAttribute 'rel']['volume']

     addInterface : (jqLi, login) =>
         intrfc = ($ "


find sprite

find sprite

--- src/layout/test_layout.coffee
+++ src/layout/test_layout.coffee
@@ -38,6 +38,7 @@
     t.ok level = world.find_child(), 'active level'
     t.ok layout = level.find_child(), 'layout'
     t.ok grid = level.find_child('grid'), 'grid'
-    t.ok sprite = level.find_child('sprite'), 'grid'
+    console.log 'grid', grid.doc.x, grid._child_array()
+    t.ok sprite = grid.find_child('sprite'), 'sprite'
     t.end()


Fix the tests.

Fix the tests.

--- spec/fuzzy-finder-spec.coffee
+++ spec/fuzzy-finder-spec.coffee
@@ -50,6 +50,11 @@
   waitForPathsToDisplay = (fuzzyFinderView) ->
     waitsFor "paths to display", 5000, ->
       fuzzyFinderView.list.children("li").length > 0
+
+  waitsForPaths = (finder, expectedPaths) ->
+    waitsFor "specific paths", 3000, ->
+      foundPaths = _.pluck(finder.list.find('li > div.file'), 'outerText')
+      _.isEqual(foundPaths, expectedPaths)

   eachFilePath = (dirPaths, fn) ->
     for dirPath in dirPaths
@@ -257,8 +262,11 @@

         it "shows an empty message with no files in the list", ->
           dispatchCommand('toggle-file-finder')
-          expect(projectView.error.text()).toBe 'Project is empty'
-          expect(projectView.list.children('li').length).toBe 0
+          waitsFor ->
+            projectView.error.text() is 'Project is empty'
+
+          runs ->
+            expect(projectView.list.children('li').length).toBe 0

     describe "when a path selection is confirmed", ->
       it "opens the file associated with that path in that split", ->
@@ -331,7 +339,10 @@
           runs ->
             dispatchCommand('toggle-buffer-finder')
             expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe true
-            expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample.txt', 'sample.js', 'sample-with-tabs.coffee']
+
+          waitsForPaths(bufferView, ['sample.txt', 'sample.js', 'sample-with-tabs.coffee'])
+
+          runs ->
             dispatchCommand('toggle-buffer-finder')
             expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe false

@@ -341,7 +352,10 @@
           runs ->
             dispatchCommand('toggle-buffer-finder')
             expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe true
-            expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample-with-tabs.coffee', 'sample.js', 'sample.txt']
+
+          waitsForPaths(bufferView, ['sample-with-tabs.coffee', 'sample.js', 'sample.txt'])
+
+          runs ->
             expect(bufferView.list.children().first()).toHaveClass 'selected'

         it "serializes the list of paths and their last opened time", ->
@@ -396,7 +410,8 @@
           runs ->
             atom.workspace.getActivePane().splitRight(copyActiveItem: true)
             dispatchCommand('toggle-buffer-finder')
-            expect(_.pluck(bufferView.list.find('li > div.file'), 'outerText')).toEqual ['sample.js']
+
+          waitsForPaths(bufferView, ['sample.js'])

     describe "when a path selection is confirmed", ->
       [editor1, editor2, editor3] = []
@@ -616,8 +631,12 @@
       pane = atom.workspace.getActivePane()

       dispatchCommand('toggle-buffer-finder')
-      {filePath} = bufferView.getSelectedItem()
-      atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-left'
+      waitForPathsToDisplay bufferView
+
+      filePath = null
+      runs ->
+        {filePath} = bufferView.getSelectedItem()
+        atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-left'

       waitsFor ->
         atom.workspace.getPanes().length is 2
@@ -635,8 +654,12 @@
       pane = atom.workspace.getActivePane()

       dispatchCommand('toggle-buffer-finder')
-      {filePath} = bufferView.getSelectedItem()
-      atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-right'
+      waitForPathsToDisplay bufferView
+
+      filePath = null
+      runs ->
+        {filePath} = bufferView.getSelectedItem()
+        atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-right'

       waitsFor ->
         atom.workspace.getPanes().length is 2
@@ -654,8 +677,12 @@
       pane = atom.workspace.getActivePane()

       dispatchCommand('toggle-buffer-finder')
-      {filePath} = bufferView.getSelectedItem()
-      atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-up'
+      waitForPathsToDisplay bufferView
+
+      filePath = null
+      runs ->
+        {filePath} = bufferView.getSelectedItem()
+        atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-up'

       waitsFor ->
         atom.workspace.getPanes().length is 2
@@ -673,8 +700,12 @@
       pane = atom.workspace.getActivePane()

       dispatchCommand('toggle-buffer-finder')
-      {filePath} = bufferView.getSelectedItem()
-      atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-down'
+      waitForPathsToDisplay bufferView
+
+      filePath = null
+      runs ->
+        {filePath} = bufferView.getSelectedItem()
+        atom.commands.dispatch bufferView.filterEditorView.element, 'pane:split-down'

       waitsFor ->
         atom.workspace.getPanes().length is 2
@@ -709,11 +740,14 @@

         bufferView.filterEditorView.getModel().setText('sample.js:4')
         bufferView.populateList()
-        {filePath} = bufferView.getSelectedItem()
-        expect(atom.project.getDirectories()[0].resolve(filePath)).toBe editor1.getPath()
-
-        spyOn(bufferView, 'moveToLine').andCallThrough()
-        atom.commands.dispatch bufferView.element, 'core:confirm'
+        waitForPathsToDisplay bufferView
+
+        runs ->
+          {filePath} = bufferView.getSelectedItem()
+          expect(atom.project.getDirectories()[0].resolve(filePath)).toBe editor1.getPath()
+
+          spyOn(bufferView, 'moveToLine').andCallThrough()
+          atom.commands.dispatch bufferView.element, 'core:confirm'

         waitsFor ->
           bufferView.moveToLine.callCount > 0
@@ -730,42 +764,51 @@
     it "highlights an exact match", ->
       bufferView.filterEditorView.getModel().setText('sample.js')
       bufferView.populateList()
-      resultView = bufferView.getSelectedItemView()
-
-      primaryMatches = resultView.find('.primary-line .character-match')
-      secondaryMatches = resultView.find('.secondary-line .character-match')
-      expect(primaryMatches.length).toBe 1
-      expect(primaryMatches.last().text()).toBe 'sample.js'
-      # Use `toBeGreaterThan` because dir may have some characters in it
-      expect(secondaryMatches.length).toBeGreaterThan 0
-      expect(secondaryMatches.last().text()).toBe 'sample.js'
+
+      waitForPathsToDisplay bufferView
+      runs ->
+        resultView = bufferView.getSelectedItemView()
+
+        primaryMatches = resultView.find('.primary-line .character-match')
+        secondaryMatches = resultView.find('.secondary-line .character-match')
+        expect(primaryMatches.length).toBe 1
+        expect(primaryMatches.last().text()).toBe 'sample.js'
+        # Use `toBeGreaterThan` because dir may have some characters in it
+        expect(secondaryMatches.length).toBeGreaterThan 0
+        expect(secondaryMatches.last().text()).toBe 'sample.js'

     it "highlights a partial match", ->
       bufferView.filterEditorView.getModel().setText('sample')
       bufferView.populateList()
-      resultView = bufferView.getSelectedItemView()
-
-      primaryMatches = resultView.find('.primary-line .character-match')
-      secondaryMatches = resultView.find('.secondary-line .character-match')
-      expect(primaryMatches.length).toBe 1
-      expect(primaryMatches.last().text()).toBe 'sample'
-      # Use `toBeGreaterThan` because dir may have some characters in it
-      expect(secondaryMatches.length).toBeGreaterThan 0
-      expect(secondaryMatches.last().text()).toBe 'sample'
+
+      waitForPathsToDisplay bufferView
+      runs ->
+        resultView = bufferView.getSelectedItemView()
+
+        primaryMatches = resultView.find('.primary-line .character-match')
+        secondaryMatches = resultView.find('.secondary-line .character-match')
+        expect(primaryMatches.length).toBe 1
+        expect(primaryMatches.last().text()).toBe 'sample'
+        # Use `toBeGreaterThan` because dir may have some characters in it
+        expect(secondaryMatches.length).toBeGreaterThan 0
+        expect(secondaryMatches.last().text()).toBe 'sample'

     it "highlights multiple matches in the file name", ->
       bufferView.filterEditorView.getModel().setText('samplejs')
       bufferView.populateList()
-      resultView = bufferView.getSelectedItemView()
-
-      primaryMatches = resultView.find('.primary-line .character-match')
-      secondaryMatches = resultView.find('.secondary-line .character-match')
-      expect(primaryMatches.length).toBe 2
-      expect(primaryMatches.first().text()).toBe 'sample'
-      expect(primaryMatches.last().text()).toBe 'js'
-      # Use `toBeGreaterThan` because dir may have some characters in it
-      expect(secondaryMatches.length).toBeGreaterThan 1
-      expect(secondaryMatches.last().text()).toBe 'js'
+
+      waitForPathsToDisplay bufferView
+      runs ->
+        resultView = bufferView.getSelectedItemView()
+
+        primaryMatches = resultView.find('.primary-line .character-match')
+        secondaryMatches = resultView.find('.secondary-line .character-match')
+        expect(primaryMatches.length).toBe 2
+        expect(primaryMatches.first().text()).toBe 'sample'
+        expect(primaryMatches.last().text()).toBe 'js'
+        # Use `toBeGreaterThan` because dir may have some characters in it
+        expect(secondaryMatches.length).toBeGreaterThan 1
+        expect(secondaryMatches.last().text()).toBe 'js'

     it "highlights matches in the directory and file name", ->
       bufferView.items = [
@@ -870,7 +913,7 @@
       expect(projectView.filterEditorView.getText()).toBe 'this should show up next time we open finder'
       expect(projectView.filterEditorView.getModel().getSelectedText()).toBe 'this should show up next time we open finder'

-  describe "Git integration", ->
+  fdescribe "Git integration", ->
     [projectPath, gitRepository, gitDirectory] = []

     beforeEach ->
@@ -879,7 +922,9 @@
       atom.project.setPaths([rootDir2, projectPath])

       gitDirectory = atom.project.getDirectories()[1]
-      gitRepository = atom.project.getRepositories()[1]
+      gitRepository = atom.project.getRepositories()[1].async
+      waitsFor ->
+        not gitRepository._isRefreshing()

     describe "git-status-finder behavior", ->
       [originalText, originalPath, newPath] = []
@@ -893,21 +938,27 @@
           originalText = editor.getText()
           originalPath = editor.getPath()
           fs.writeFileSync(originalPath, 'making a change for the better')
-          gitRepository.getPathStatus(originalPath)
-
+
+        waitsForPromise ->
+          gitRepository.refreshStatusForPath(originalPath)
+
+        runs ->
           newPath = atom.project.getDirectories()[1].resolve('newsample.js')
           fs.writeFileSync(newPath, '')
-          gitRepository.getPathStatus(newPath)
+
+        waitsForPromise ->
+          gitRepository.refreshStatusForPath(newPath)

       it "displays all new and modified paths", ->
         expect(atom.workspace.panelForItem(gitStatusView)).toBeNull()
         dispatchCommand('toggle-git-status-finder')
         expect(atom.workspace.panelForItem(gitStatusView).isVisible()).toBe true

-        expect(gitStatusView.find('.file').length).toBe 2
-
-        expect(gitStatusView.find('.status.status-modified').length).toBe 1
-        expect(gitStatusView.find('.status.status-added').length).toBe 1
+        waitForPathsToDisplay gitStatusView
+
+        runs ->
+          expect(gitStatusView.find('.status.status-modified').length).toBe 1
+          expect(gitStatusView.find('.status.status-added').length).toBe 3

     describe "status decorations", ->
       [originalText, originalPath, editor, newPath] = []
@@ -929,22 +980,33 @@
         it "displays the modified icon", ->
           editor.setText('modified')
           editor.save()
-          gitRepository.getPathStatus(editor.getPath())
-
-          dispatchCommand('toggle-buffer-finder')
-          expect(bufferView.find('.status.status-modified').length).toBe 1
-          expect(bufferView.find('.status.status-modified').closest('li').find('.file').text()).toBe 'a.txt'
+          waitsForPromise ->
+            gitRepository.refreshStatusForPath(editor.getPath())
+
+          runs ->
+            dispatchCommand('toggle-buffer-finder')
+
+          waitsFor ->
+            bufferView.find('.status.status-modified').length is 1
+
+          runs ->
+            expect(bufferView.find('.status.status-modified').closest('li').find('.file').text()).toBe 'a.txt'

       describe "when a new file is shown in the list", ->
         it "displays the new icon", ->
           waitsForPromise ->
             atom.workspace.open(path.join(projectPath, 'newsample.js'))

-          runs ->
-            gitRepository.getPathStatus(editor.getPath())
-
+          waitsForPromise ->
+            gitRepository.refreshStatusForPath(editor.getPath())
+
+          runs ->
             dispatchCommand('toggle-buffer-finder')
-            expect(bufferView.find('.status.status-added').length).toBe 1
+
+          waitsFor ->
+            bufferView.find('.status.status-added').length > 0
+
+          runs ->
             expect(bufferView.find('.status.status-added').closest('li').find('.file').text()).toBe 'newsample.js'

     describe "when core.excludeVcsIgnoredPaths is set to true", ->


tmp commit

tmp commit

--- js/todos.coffee
+++ js/todos.coffee
@@ -33,6 +33,9 @@
 TodoList = Backbone.Collection.extend
 	url: 'feeds.php'
 	model: TodoModel
+	showOne: (id) ->
+		alert "aslkjasdlkjasd #{id}"
+		console.log @
 #Collection View
 TodoListView = Backbone.View.extend
 	initialize: ->
@@ -58,7 +61,7 @@
 			collection: @todoList
 		$("#container").html @todoListView.el
 	start: -> Backbone.history.start pushState: true
-	show: -> console.log @todoList
+	show: (id)-> @todoList.showOne id
 	index: -> @todoList.fetch()
 )
 # DOM READY


remove some junk, maybe

remove some junk, maybe

--- angular/test/protractor/notifications_spec.coffee
+++ angular/test/protractor/notifications_spec.coffee
@@ -22,10 +22,10 @@
   describe 'invitation accepted', ->

     it 'notifies inviter when invitation is accepted', ->
-      page.loadPath 'setup_group'
+      page.loadPath 'setup_group', 60000
       page.click '.members-card__invite-members-btn'
       page.fillIn '.invitation-form__email-addresses', 'max@example.com'
       page.click '.invitation-form__submit'
-      page.loadPath 'accept_last_invitation'
+      page.loadPath 'accept_last_invitation', 60000
       page.click '.notifications__button'
       page.expectText '.notifications__dropdown', 'Max Von Sydow accepted your invitation to join Dirty Dancing Shoes'


Update React tutorial example template syntax

--- examples/react-tut/main.coffee
+++ examples/react-tut/main.coffee
@@ -12,7 +12,7 @@
 Comment = (args) ->
   div {class: 'comment'}, [
     h2 {class: 'commentAuthor'}, [args.author]
-    span {}, [markdown(args.text)]
+    span [markdown(args.text)]
   ]

 CommentList = (args) ->
@@ -51,7 +51,7 @@
       success: (data) -> comments.replace(data.comments)
     })
   $base = div {class: 'commentBox'}, [
-    h1 {}, ['Comments']
+    h1 'Comments'
     CommentList {comments: comments}
     CommentForm {onCommentSubmit: handleCommentSubmit}
   ]


Fix specs

Fix specs

--- spec/pane-element-spec.coffee
+++ spec/pane-element-spec.coffee
@@ -1,18 +1,13 @@
 PaneContainer = require '../src/pane-container'

 describe "PaneElement", ->
-  [paneElement, container, containerElement, pane] = []
+  [paneElement, containerElement, pane] = []

   beforeEach ->
     spyOn(atom.applicationDelegate, "open")

-    container = new PaneContainer
-      location: 'center'
-      config: atom.config
-      confirm: atom.confirm.bind(atom)
-      viewRegistry: atom.views
-      applicationDelegate: atom.applicationDelegate
-    containerElement = container.getElement()
+    container = atom.workspace.getActivePaneContainer()
+    containerElement = container.paneContainer.getElement()
     pane = container.getActivePane()
     paneElement = pane.getElement()

@@ -247,9 +242,9 @@
       expect(document.activeElement).toBe paneElement

   describe "drag and drop", ->
-    buildDragEvent = (type, files) ->
+    buildDragEvent = (type, items) ->
       dataTransfer =
-        files: files
+        items: items
         data: {}
         setData: (key, value) -> @data[key] = value
         getData: (key) -> @data[key]
@@ -260,7 +255,10 @@

     describe "when a file is dragged to the pane", ->
       it "opens it", ->
-        event = buildDragEvent("drop", [{path: "/fake1"}, {path: "/fake2"}])
+        event = buildDragEvent("drop", [
+          {kind: "file", getAsFile: () -> {path: "/fake1"}},
+          {kind: "file", getAsFile: () -> {path: "/fake2"}}
+        ])
         paneElement.dispatchEvent(event)
         expect(atom.applicationDelegate.open.callCount).toBe 1
         expect(atom.applicationDelegate.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2'], here: true


Make badge json route public

Make badge json route public

--- apps/badges/routes.coffee
+++ apps/badges/routes.coffee
@@ -9,6 +9,11 @@

 routes = (app) ->
   #
+  #SHOW JSON - Public - Returns JSON formatted badge
+  app.get '/badges/:slug.:format', (req, res) ->
+    Badge.findOne slug: req.params.slug, (err, badge) ->
+      formatBadgeResponse(req, res, badge)
+
   #INDEX
   app.get '/badges.:format?', authenticate, (req, res, next) ->
     next() if !req.org
@@ -62,14 +67,11 @@
             issuer: badge.issuer()

     #SHOW
-    app.get '/:slug.:format?', (req, res) ->
+    app.get '/:slug', (req, res) ->
       Badge.findOne slug: req.params.slug, (err, badge) ->
-        if req.params.format == 'json'
-          formatBadgeResponse(req, res, badge)
-        else
-          res.render "#{__dirname}/views/show",
-            badge: badge
-            issuer: badge.issuer()
+        res.render "#{__dirname}/views/show",
+          badge: badge
+          issuer: badge.issuer()

     #SHOW
     app.get '/:slug/edit', (req, res) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -21,7 +21,7 @@
 ###
 TimedEvents = (I={}) ->
   ###*
-  E
+  Execute <

   player = GameObject


Using elapsed time in delayed events

Using elapsed time in delayed events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -19,7 +19,7 @@
         self.sendOrApply(fn)
         event.lastFired += period

-    [I.delayedEvents, firingEvents] = delayedEvents.partition (event) ->
+    [I.delayedEvents, firingEvents] = I.delayedEvents.partition (event) ->
       (event.delay -= elapsedTime) >= 0

     firingEvents.each (event) ->


remove meta in dev mode

remove meta in dev mode

--- src/views/layout.coffee
+++ src/views/layout.coffee
@@ -6,17 +6,18 @@
     title "#{@title} - MadTalk" if @title?
     meta(name: 'description', content: @description) if @description?
     link(rel: 'canonical', href: @canonical) if @canonical?
-    link(rel: 'apple-touch-icon', href: 'madtalk_ios_icon.png')
-
-    meta(name:'viewport', content:'width=device-width, initial-scale=1, user-scalable=no')
-    meta(name:'apple-mobile-web-app-capable', content:'yes')

     if @dev
       style @css
+      # script src: '/socket.io/socket.io+websocket.js'
     else
+      link(rel: 'apple-touch-icon', href: 'madtalk_ios_icon.png')
+
+      meta(name:'viewport', content:'width=device-width, initial-scale=1, user-scalable=no')
+      meta(name:'apple-mobile-web-app-capable', content:'yes')
+
       link rel: 'icon', href: '/favicon.ico'
       link rel: 'stylesheet', href: "/client.css?#{@ts}"
-      #script src: '/socket.io/socket.io.js', defer: on

     # coffeescript -> $ -> alert 'hi!'


Include original Meetup event object

Include original Meetup event object

Include original Meetup event object under raw property.

--- app/meetup.coffee
+++ app/meetup.coffee
@@ -81,6 +81,7 @@
 	title: event.name
 	source: event.event_url
 	date: new Date(event.time)
+	raw: event
 	location:
 		address: event.venue.address
 		name: event.venue.name


Fix gen_dir_listings on Windows.

Fix gen_dir_listings on Windows.

--- tools/gen_dir_listings.coffee
+++ tools/gen_dir_listings.coffee
@@ -15,10 +15,10 @@
       # Avoid infinite loops.
       lstat = fs.lstatSync(fpath)
       if lstat.isSymbolicLink()
-        symLinks[lstat.dev] ?= {}
+        realdir = fs.readlinkSync(fpath)
         # Ignore if we've seen it before
-        continue if symLinks[lstat.dev][lstat.ino]?
-        symLinks[lstat.dev][lstat.ino] = 0
+        continue if symLinks[realdir]?
+        symLinks[realdir] = 1

       fstat = fs.statSync(fpath)
       if fstat.isDirectory()


Add "Email" site functionality

Add "Email" site functionality

--- app/assets/javascripts/social-share-button.coffee
+++ app/assets/javascripts/social-share-button.coffee
@@ -11,6 +11,8 @@
     if url.length == 0
       url = encodeURIComponent(location.href)
     switch site
+      when "email"
+        SocialShareButton.openUrl("mailto:?to=&subject=#{title}&body=#{url}")
       when "weibo"
         SocialShareButton.openUrl("http://service.weibo.com/share/share.php?url=#{url}&type=3&pic=#{img}&title=#{title}")
       when "twitter"


Revert "CHECKPOINT re-implemented binarySearch using slices"

This reverts commit 4454540a3858f512861e376414f8ab41e9da7662.

--- algo/binary-search.coffee
+++ algo/binary-search.coffee
@@ -1,18 +1,23 @@

 { isListAscending } = require './is-list-ascending.coffee'

-_binarySearch = (sortedList, needle)->
-  return -1 if sortedList.length is 0
+_binarySearch = (sortedList, needle, start, end)->

-  mid = Math.floor (sortedList.length / 2)
+  return -1 if end < start
+
+  mid = Math.floor (start + ((end - start) / 2))
+
   return mid if sortedList[mid] is needle

   if sortedList[mid] > needle
-    return _binarySearch sortedList[0..mid - 1], needle
+
+    return _binarySearch sortedList, needle, start, mid - 1
+
   else
-    res = _binarySearch sortedList[mid+1..sortedList.length], needle
-    return (if res is -1 then -1 else res + mid + 1)
+
+    return _binarySearch sortedList, needle, mid + 1, end

 @binarySearch = (sortedList, needle)->
   throw new Error 'Unsorted List' unless isListAscending sortedList
-  return _binarySearch sortedList, needle
+  return _binarySearch sortedList, needle, 0, sortedList.length-1
+


fix a bug

fix a bug

--- src/renderer/Renderer.coffee
+++ src/renderer/Renderer.coffee
@@ -155,6 +155,7 @@
 		if shape.strokeStyle?
 			@context.strokeStyle = shape.strokeStyle
 			@context.lineWidth = shape.lineWidth
+			@context.beginPath()
 			if shape.dashStyle
 				@context.dashedLine(
 						shape.points[0].x, shape.points[0].y,
@@ -162,7 +163,6 @@
 						shape.dashStyle, shape.dashDelta
 				)
 			else
-				@context.beginPath()
 				@context.lineTo(shape.points[0].x, shape.points[0].y)
 				@context.lineTo(shape.points[1].x, shape.points[1].y)
 				@context.closePath()


fixed bugs for homepage editor

fixed bugs for homepage editor

--- app/coffeescripts/bundles/account_homepage.coffee
+++ app/coffeescripts/bundles/account_homepage.coffee
@@ -221,7 +221,8 @@
       #############################

     $("form.edit_jxb_page button.cancel").click ->
-      #$(".sortable").sortable("cancel")
+      $(".sortable").sortable("cancel")
+      $('[data-position]').find('.add_widget_icon').remove()
       $(".sortable").sortable("disable")
       revertWidgets()
       $("#content-wrapper").removeClass("theme_edit")


height calculation adjusted

height calculation adjusted

--- src/scripts/directive.coffee
+++ src/scripts/directive.coffee
@@ -167,7 +167,7 @@
     bottom {visible through #{viewport.scrollTop() + viewport.height()} actual=#{buffer[buffer.length-1].element.offset().top - canvas.offset().top}}"

                   enqueueFetch(true) if reloadRequested || shouldLoadBottom()
-                  enqueueFetch(false) if reloadRequested || shouldLoadTop()
+                  enqueueFetch(false) if !reloadRequested && shouldLoadTop()

                 insert = (item, top) ->
                   itemScope = $scope.$new()
@@ -185,15 +185,22 @@
                       buffer.push wrapper
                   # using watch is the only way I found to gather the 'real' height of the thing - the height after the item
                   # template was processed and values inserted.
-                  itemScope.$watch 'whatever', ->
+                  itemScope.$watch 'heightAdjustment', ->
                     if top
                       newHeight = topPadding.height() - wrapper.element.outerHeight(true)
                       if newHeight >= 0
                         topPadding.height(newHeight)
                       else
-                        viewport.scrollTop(viewport.scrollTop() - newHeight)
+                        scrollTop = viewport.scrollTop() + wrapper.element.outerHeight(true)
+                        if viewport.height() + scrollTop > canvas.height()
+                          bottomPadding.height(bottomPadding.height() + viewport.height() + scrollTop - canvas.height())
+                        viewport.scrollTop(scrollTop)
                     else
                       bottomPadding.height(Math.max(0,bottomPadding.height() - wrapper.element.outerHeight(true)))
+                    console.log "item = " + wrapper.element.text()
+
+                  itemScope
+

                 finalize = ->
                   pending.shift()
@@ -206,6 +213,7 @@
                 fetch = () ->
                   direction = pending[0]
                   #console.log "Running fetch... #{{true:'bottom', false: 'top'}[direction]} pending #{pending.length}"
+                  lastScope = null
                   if direction
                     if buffer.length && !shouldLoadBottom()
                       finalize()
@@ -220,11 +228,12 @@
                           finalize()
                           return
                         for item in result
-                          insert item, false
+                          lastScope = insert item, false
                         next += result.length
                         console.log "appended: #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
                         finalize()
-                        adjustBuffer()
+                        lastScope.$watch 'adjustBuffer', ->
+                          adjustBuffer()

                   else
                     if buffer.length && !shouldLoadTop()
@@ -240,11 +249,12 @@
                           finalize()
                           return
                         for item in result.reverse()
-                          insert item, true
+                          lastScope = insert item, true
                         first -= result.length
                         console.log "prepended #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
                         finalize()
-                        adjustBuffer()
+                        lastScope.$watch 'adjustBuffer', ->
+                          adjustBuffer()

                 viewport.bind 'resize', ->
                   adjustBuffer()


address differences in animation API 1.2 vs. 1.3

--- src/scripts/ui-scroll.coffee
+++ src/scripts/ui-scroll.coffee
@@ -93,13 +93,20 @@

 						removeItem =
 							if $animate
-								(wrapper) ->
-									buffer.splice buffer.indexOf(wrapper), 1
-									deferred = $q.defer()
-									$animate.leave wrapper.element, ->
-										wrapper.scope.$destroy()
-										deferred.resolve()
-									[deferred.promise]
+								if angular.version.minor == 2
+									(wrapper) ->
+										buffer.splice buffer.indexOf(wrapper), 1
+										deferred = $q.defer()
+										$animate.leave wrapper.element, ->
+											wrapper.scope.$destroy()
+											deferred.resolve()
+										[deferred.promise]
+								else
+									(wrapper) ->
+										buffer.splice buffer.indexOf(wrapper), 1
+										[($animate.leave wrapper.element).then ->
+											wrapper.scope.$destroy()
+										]
 							else
 								(wrapper) ->
 									buffer.splice buffer.indexOf(wrapper), 1
@@ -114,10 +121,15 @@

 						insertElementAnimated =
 							if $animate
-								(newElement, previousElement) ->
-									deferred = $q.defer()
-									$animate.enter newElement, element, previousElement, -> deferred.resolve()
-									[deferred.promise]
+								if angular.version.minor == 2
+									(newElement, previousElement) ->
+										deferred = $q.defer()
+										$animate.enter newElement, element, previousElement, -> deferred.resolve()
+										[deferred.promise]
+								else
+									(newElement, previousElement) ->
+										[$animate.enter newElement, element, previousElement]
+
 							else insertElement

 						# Element builder


old 'adater' becomes 'builder'

old 'adater' becomes 'builder'

--- src/scripts/ui-scroll.coffee
+++ src/scripts/ui-scroll.coffee
@@ -66,7 +66,7 @@
 						scrollHeight = (elem)->
 							elem[0].scrollHeight ? elem[0].document.documentElement.scrollHeight

-						adapter = null
+						builder = null

 						# Calling linker is the only way I found to get access to the tag name of the template
 						# to prevent the directive scope from pollution a new scope is created and destroyed
@@ -106,7 +106,7 @@
 								$scope.$on '$destroy', () ->
 									template.remove()

-								adapter =
+								builder =
 									viewport: viewport
 									topPadding: topPadding.paddingHeight
 									bottomPadding: bottomPadding.paddingHeight
@@ -117,7 +117,7 @@
 									topDataPos: ->
 										topPadding.paddingHeight()

-						viewport = adapter.viewport
+						viewport = builder.viewport

 						viewportScope = viewport.scope() || $rootScope

@@ -168,8 +168,8 @@
 							first = 1
 							next = 1
 							removeFromBuffer(0, buffer.length)
-							adapter.topPadding(0)
-							adapter.bottomPadding(0)
+							builder.topPadding(0)
+							builder.bottomPadding(0)
 							pending = []
 							eof = false
 							bof = false
@@ -182,11 +182,11 @@
 							viewport.scrollTop()

 						shouldLoadBottom = ->
-							!eof && adapter.bottomDataPos() < bottomVisiblePos() + bufferPadding()
+							!eof && builder.bottomDataPos() < bottomVisiblePos() + bufferPadding()

 						clipBottom = ->
 							# clip the invisible items off the bottom
-							bottomHeight = 0 #adapter.bottomPadding()
+							bottomHeight = 0 #builder.bottomPadding()
 							overage = 0

 							for i in [buffer.length-1..0]
@@ -195,7 +195,7 @@
 								newRow = rowTop isnt itemTop
 								rowTop = itemTop
 								itemHeight = item.element.outerHeight(true) if newRow
-								if (adapter.bottomDataPos() - bottomHeight - itemHeight > bottomVisiblePos() + bufferPadding())
+								if (builder.bottomDataPos() - bottomHeight - itemHeight > bottomVisiblePos() + bufferPadding())
 									bottomHeight += itemHeight if newRow
 									overage++
 									eof = false
@@ -204,13 +204,13 @@
 									overage++

 							if overage > 0
-								adapter.bottomPadding(adapter.bottomPadding() + bottomHeight)
+								builder.bottomPadding(builder.bottomPadding() + bottomHeight)
 								removeFromBuffer(buffer.length - overage, buffer.length)
 								next -= overage
-								log "clipped off bottom #{overage} bottom padding #{adapter.bottomPadding()}"
+								log "clipped off bottom #{overage} bottom padding #{builder.bottomPadding()}"

 						shouldLoadTop = ->
-							!bof && (adapter.topDataPos() > topVisiblePos() - bufferPadding())
+							!bof && (builder.topDataPos() > topVisiblePos() - bufferPadding())

 						clipTop = ->
 							# clip the invisible items off the top
@@ -221,7 +221,7 @@
 								newRow = rowTop isnt itemTop
 								rowTop = itemTop
 								itemHeight = item.element.outerHeight(true) if newRow
-								if (adapter.topDataPos() + topHeight + itemHeight < topVisiblePos() - bufferPadding())
+								if (builder.topDataPos() + topHeight + itemHeight < topVisiblePos() - bufferPadding())
 									topHeight += itemHeight if newRow
 									overage++
 									bof = false
@@ -229,10 +229,10 @@
 									break if newRow
 									overage++
 							if overage > 0
-								adapter.topPadding(adapter.topPadding() + topHeight)
+								builder.topPadding(builder.topPadding() + topHeight)
 								removeFromBuffer(0, overage)
 								first += overage
-								log "clipped off top #{overage} top padding #{adapter.topPadding()}"
+								log "clipped off top #{overage} top padding #{builder.topPadding()}"

 						enqueueFetch = (rid, direction)->
 							if (!isLoading)
@@ -264,33 +264,33 @@
 									if toBeAppended
 										if index == next
 											hideElementBeforeAppend clone
-											adapter.append clone
+											builder.append clone
 											buffer.push wrapper
 										else
 											buffer[index-first].element.after clone
 											buffer.splice index-first+1, 0, wrapper
 									else
 										hideElementBeforeAppend clone
-										adapter.prepend clone
+										builder.prepend clone
 										buffer.unshift wrapper
 							{appended: toBeAppended, wrapper: wrapper}

 						adjustRowHeight = (appended, wrapper) ->
 							if appended
-								adapter.bottomPadding(Math.max(0,adapter.bottomPadding() - wrapper.element.outerHeight(true)))
+								builder.bottomPadding(Math.max(0,builder.bottomPadding() - wrapper.element.outerHeight(true)))
 							else
 								# an element is inserted at the top
-								newHeight = adapter.topPadding() - wrapper.element.outerHeight(true)
+								newHeight = builder.topPadding() - wrapper.element.outerHeight(true)
 								# adjust padding to prevent it from visually pushing everything down
 								if newHeight >= 0
 									# if possible, reduce topPadding
-									adapter.topPadding(newHeight)
+									builder.topPadding(newHeight)
 								else
 									# if not, increment scrollTop
 									viewport.scrollTop(viewport.scrollTop() + wrapper.element.outerHeight(true))

 						doAdjustment = (rid, finalize)->
-							log "top {actual=#{adapter.topDataPos()} visible from=#{topVisiblePos()} bottom {visible through=#{bottomVisiblePos()} actual=#{adapter.bottomDataPos()}}"
+							log "top {actual=#{builder.topDataPos()} visible from=#{topVisiblePos()} bottom {visible through=#{bottomVisiblePos()} actual=#{builder.bottomDataPos()}}"
 							if shouldLoadBottom()
 								enqueueFetch(rid, true)
 							else
@@ -303,7 +303,7 @@
 									newRow = rowTop isnt itemTop
 									rowTop = itemTop
 									itemHeight = item.element.outerHeight(true) if newRow
-									if newRow and (adapter.topDataPos() + topHeight + itemHeight < topVisiblePos())
+									if newRow and (builder.topDataPos() + topHeight + itemHeight < topVisiblePos())
 											topHeight += itemHeight
 									else
 										topVisible(item) if newRow
@@ -349,7 +349,7 @@
 										newItems = []
 										if result.length < bufferSize
 											eof = true
-											adapter.bottomPadding(0)
+											builder.bottomPadding(0)
 											#log "eof is reached"
 										if result.length > 0
 											clipTop()
@@ -368,7 +368,7 @@
 										newItems = []
 										if result.length < bufferSize
 											bof = true
-											adapter.topPadding(0)
+											builder.topPadding(0)
 											#log "bof is reached"
 										if result.length > 0
 											clipBottom() if buffer.length


Remove the LDAP string as it is irrelevant to end users.

--- packages/rocketchat-ui-login/login/form.coffee
+++ packages/rocketchat-ui-login/login/form.coffee
@@ -40,8 +40,6 @@
 			when 'register'
 				return t('Submit')
 			when 'login'
-				if RocketChat.settings.get('LDAP_Enable')
-					return t('Login') + ' (LDAP)'
 				return t('Login')
 			when 'email-verification'
 				return t('Send_confirmation_email')


Do not init push, only register

Do not init push, only register

--- packages/rocketchat-ui/lib/cordova/push.coffee
+++ packages/rocketchat-ui/lib/cordova/push.coffee
@@ -1,38 +1,21 @@
 if Meteor.isCordova
-	Push.addListener 'token', (token) ->
-		Meteor.call 'log', 'CLIENT', 'token', arguments
-
-	Push.addListener 'error', (err) ->
-		Meteor.call 'log', 'CLIENT', 'error', arguments
-		if err.type == 'apn.cordova'
-			Meteor.call 'log', 'CLIENT', err.error
-
-	Push.addListener 'register', (evt) ->
-		Meteor.call 'log', 'CLIENT', 'register', arguments
-
-	Push.addListener 'alert', (notification) ->
-		Meteor.call 'log', 'CLIENT', 'alert', arguments
-
-	Push.addListener 'sound', (notification) ->
-		Meteor.call 'log', 'CLIENT', 'sound', arguments
-
-	Push.addListener 'badge', (notification) ->
-		Meteor.call 'log', 'CLIENT', 'badge', arguments
-
-	Push.addListener 'startup', (notification) ->
+	window.addEventListener 'push-notification', (evt) ->
 		Meteor.call 'log', 'CLIENT', 'startup', arguments

-		if notification.open is true and notification.payload?.rid?
-			switch notification.payload.type
+		notification = evt.detail
+
+		if notification.additionalData.foreground is true
+			return
+
+		if notification.additionalData.ejson?.rid?
+			switch notification.additionalData.ejson.type
 				when 'c'
-					FlowRouter.go 'channel', name: notification.payload.name
+					FlowRouter.go 'channel', name: notification.additionalData.ejson.name
 				when 'p'
-					FlowRouter.go 'group', name: notification.payload.name
+					FlowRouter.go 'group', name: notification.additionalData.ejson.name
 				when 'd'
-					FlowRouter.go 'direct', username: notification.payload.sender.username
+					FlowRouter.go 'direct', username: notification.additionalData.ejson.sender.username

-	Push.addListener 'message', (notification) ->
-		Meteor.call 'log', 'CLIENT', 'message', arguments

 	Tracker.autorun ->
 		if RocketChat.settings.get('Push_enable') is true and Meteor.userId()?
@@ -40,12 +23,15 @@
 			if android_senderID?
 				localStorage.setItem 'android_senderID', android_senderID

-			Push.Configure
-				android:
-					senderID: android_senderID
-					sound: true
-					vibrate: true
-				ios:
-					badge: true
-					sound: true
-					alert: true
+			if window.pushToken?
+				data =
+					id: localStorage.getItem 'push_stored_id'
+					token: window.pushToken,
+					appName: 'main',
+					userId: Meteor.userId()
+					metadata: undefined
+
+				Meteor.call 'raix:push-update', data, (err, result) ->
+					console.log err, result
+					if not err? and result?
+						localStorage.setItem 'push_stored_id', result._id


Make specs work on stable

Make specs work on stable

--- spec/keybinding-resolver-view-spec.coffee
+++ spec/keybinding-resolver-view-spec.coffee
@@ -35,12 +35,13 @@
       expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 1
       expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 1

-      # It should not render the keyup event data because there is no match
-      document.dispatchEvent atom.keymaps.constructor.buildKeyupEvent('x', target: workspaceElement)
-      expect(workspaceElement.querySelector('.key-binding-resolver .keystroke').textContent).toBe 'x'
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .used')).toHaveLength 1
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 1
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 1
+      if atom.keymaps.constructor.buildKeyupEvent?
+        # It should not render the keyup event data because there is no match
+        document.dispatchEvent atom.keymaps.constructor.buildKeyupEvent('x', target: workspaceElement)
+        expect(workspaceElement.querySelector('.key-binding-resolver .keystroke').textContent).toBe 'x'
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .used')).toHaveLength 1
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 1
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 1

     it "displays all commands for the keydown event but does not clear for the keyup when there is no keyup binding", ->
       atom.keymaps.add 'name', '.workspace': 'x': 'match-1'
@@ -54,9 +55,10 @@
       expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 1
       expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 0

-      # It should not render the keyup event data because there is no match
-      document.dispatchEvent atom.keymaps.constructor.buildKeyupEvent('x', target: workspaceElement)
-      expect(workspaceElement.querySelector('.key-binding-resolver .keystroke').textContent).toBe 'x ^x'
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .used')).toHaveLength 1
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 0
-      expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 0
+      if atom.keymaps.constructor.buildKeyupEvent?
+        # It should not render the keyup event data because there is no match
+        document.dispatchEvent atom.keymaps.constructor.buildKeyupEvent('x', target: workspaceElement)
+        expect(workspaceElement.querySelector('.key-binding-resolver .keystroke').textContent).toBe 'x ^x'
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .used')).toHaveLength 1
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .unused')).toHaveLength 0
+        expect(workspaceElement.querySelectorAll('.key-binding-resolver .unmatched')).toHaveLength 0


file links

file links

--- lib/eval.coffee
+++ lib/eval.coffee
@@ -23,8 +23,10 @@
     editor = atom.workspace.getActiveTextEditor()
     for sel in editor.getSelections()
       client.msg 'eval', @evalData(editor, sel), ({start, end, result, error}) =>
+        view = @ink.tree.fromJson(result)[0]
+        @ink.links.linkify view
         @ink?.results.showForLines editor, start-1, end-1,
-          content: @ink.tree.fromJson(result)[0]
+          content: view
           error: error
         notifications.show "Evaluation Finished"


paneItem?.getBuffer? to paneItem instanceof TextEditor

--- lib/find.coffee
+++ lib/find.coffee
@@ -1,4 +1,4 @@
-{CompositeDisposable, Disposable, TextBuffer} = require 'atom'
+{CompositeDisposable, Disposable, TextBuffer, TextEditor} = require 'atom'

 SelectNext = require './select-next'
 {History, HistoryCycler} = require './history'
@@ -30,7 +30,7 @@
     @resultsModel = new ResultsModel(@findOptions)

     @subscriptions.add atom.workspace.getCenter().observeActivePaneItem (paneItem) =>
-      if paneItem?.getBuffer?()
+      if paneItem instanceof TextEditor
         @findModel.setEditor(paneItem)
       else
         @findModel.setEditor(null)


fixed uploaded file name

fixed uploaded file name

--- lib/gist.coffee
+++ lib/gist.coffee
@@ -50,5 +50,5 @@
   toParams: (data) ->
     description: @description
     files:
-      "file2.txt":
+      "settings.json":
         content: JSON.stringify data


make it so evaluating a cell before it is done evaluating does not lead to problems

--- src/smc-webapp/sagews.coffee
+++ src/smc-webapp/sagews.coffee
@@ -1702,23 +1702,24 @@
             opts.cb?()

         t0 = new Date()
-        cleared_input = false
-        clear_input = =>
-            if not cleared_input
-                cleared_input = true
+        cleared_output = false
+        clear_output = =>
+            if not cleared_output
+                cleared_output = true
                 cell.set_output([])

-        # Give the cell 1s to get output from backend.  If not, then we clear input.
+        # Give the cell one second to get output from backend.  If not, then we clear output.
         # These reduces "flicker", which makes things seem slow.
-        setTimeout(clear_input, 1000)
-
+        setTimeout(clear_output, 1000)
+        first_output = true
         @execute_code
             code         : input
             output_uuid  : output_uuid
             cb           : (mesg) =>
-                if not cleared_input
-                    clear_input()
-                #dbg("got mesg ", mesg, new Date() - t0); t0 = new Date()
+                if first_output  # we *always* clear the first time, even if we cleared above via the setTimeout.
+                    first_output = false
+                    clear_output()
+                #console.log("got mesg ", mesg, new Date() - t0); t0 = new Date()
                 cell.append_output_message(mesg)
                 if mesg.done
                     done()
@@ -2166,6 +2167,9 @@
             if FLAGS.hide_output in flags
                 # output is currently hidden
                 @remove_cell_flag(FLAGS.hide_output)
+            if FLAGS.execute in flags or FLAGS.running in flags
+                # already running or queued up for execution.
+                return
             x = @client_side()
             if x
                 x.cell = @


No need to rejoin the tags

No need to rejoin the tags

--- app/javascript/src/classes/post_quick_edit.coffee
+++ app/javascript/src/classes/post_quick_edit.coffee
@@ -55,5 +55,5 @@

     $(@container).show()
     inputBox = @container.querySelector('#post_tags')
-    inputBox.value = "#{post.tags.join(' ')} rating:#{post.rating.substr(0, 1)} "
+    inputBox.value = "#{@oldTags} rating:#{post.rating.substr(0, 1)} "
     inputBox.focus()


ctrl-9 is fold ctrl-( is fold all

ctrl-9 is fold ctrl-( is fold all

--- src/app/keymaps/editor.coffee
+++ src/app/keymaps/editor.coffee
@@ -15,7 +15,8 @@
   'meta-z': 'undo'
   'meta-Z': 'redo'
   'alt-meta-w': 'toggle-soft-wrap'
-  'alt-meta-f': 'toggle-fold'
+  'ctrl-9': 'toggle-fold'
+  'ctrl-(': 'fold-all'
   'alt-meta-ctrl-f': 'fold-selection'
   'alt-meta-u': 'unfold'
   'alt-meta-left': 'split-left'


Another change to win rates.

Another change to win rates.

--- tasks/shortStats.coffee
+++ tasks/shortStats.coffee
@@ -17,7 +17,7 @@
           playerData = {
             playerName: data.playerName
             elo: data.profile.elo
-            winRate: data.profile.winsPVP / data.profile.playsPVP
+            winRate: (data.profile.winsPVP / data.profile.playsPVP) * 100
           }
           eloArray.push(playerData)
       return map
@@ -33,7 +33,7 @@
         eloArray.sort((a, b)->
           if b.elo is a.elo
             console.log 'same elo', b.playerName, b.elo, a.playerName, a.elo
-            console.log b.winRate, a.winRate
+            console.log b.winRate, a.winRate, b.winRate - a.winRate
             return b.winRate - a.winRate
           return b.elo - a.elo
         )


#FRANKREICH

#FRANKREICH

--- api/services.coffee
+++ api/services.coffee
@@ -11,7 +11,7 @@
         {nickname, password} = req.body
         # check the password
         if not nickname? or not password?
-            res.genericError 'Missing parameters', 'AuthenticationError'
+            res.genericError 'Paramètres invalides', 'AuthenticationError'
         else
             User.findOne
                 where: $or:
@@ -19,11 +19,11 @@
                     email: nickname
             .done (user) ->
                 unless user
-                    res.genericError "User #{nickname} does not exists", 'AuthenticationError'
+                    res.genericError "Utilisateur #{nickname} n\'existe pas", 'AuthenticationError'
                 else
                     bcrypt.compare password, user.password, (err, same) ->
                         unless same
-                            res.genericError "Invalid password for user #{nickname}", 'AuthenticationError'
+                            res.genericError "Mot de passe invalide pour #{nickname}", 'AuthenticationError'
                         else
                             req.session.user = user.dataValues
                             selectUserFromReq user.id, req, (user) ->


fix dependency management

fix dependency management

--- lib/main.coffee
+++ lib/main.coffee
@@ -57,7 +57,7 @@
     # Register commands
     @subscriptions.add atom.commands.add "atom-workspace", "nsl-assembler:save-&-transpile": => @buildScript(@consolePanel)

-    @satisfyDependencies() if atom.config.get("#{meta.name}.manageDependencies") and atom.inSpecMode is false
+    @satisfyDependencies() if atom.config.get("#{meta.name}.manageDependencies") is true
     @isPathSetup() if atom.config.get("#{meta.name}.mutePathWarning") is false

   deactivate: ->


improve error handling

improve error handling

--- lib/main.coffee
+++ lib/main.coffee
@@ -19,6 +19,11 @@

   buildScript: ->
     editor = atom.workspace.getActiveTextEditor()
+
+    unless editor?
+       atom.notifications.addWarning("**language-innosetup**: No active editor", dismissable: false)
+       return
+
     script = editor.getPath()
     scope  = editor.getGrammar().scopeName


Add command to clear the cache

Add command to clear the cache

--- lib/main.coffee
+++ lib/main.coffee
@@ -18,6 +18,11 @@

     atom.workspaceView.command 'incompatible-packages:view', -> atom.workspaceView.open(viewUri)

+    atom.workspaceView.command 'incompatible-packages:clear-cache', ->
+      for key, data of global.localStorage
+        if key.indexOf('installed-packages:') is 0
+          global.localStorage.removeItem(key)
+
     atom.packages.once 'activated', ->
       if atom.workspaceView?.statusBar?
         incompatibleCount = 0


Check the return of lineTextForScreenRow

This function can (and will) return undefined if lines are folded in the
buffer as it uses `tokenizedLineForScreenRow()` internally.

--- lib/main.coffee
+++ lib/main.coffee
@@ -96,6 +96,8 @@
     when 'W291'
       # W291 - trailing whitespace
       screenLine = textEditor.lineTextForScreenRow(lineNumber)
+      if screenLine is undefined
+        break
       return [[lineNumber, colNumber - 1], [lineNumber, screenLine.length]]
   return [[lineNumber, colNumber - 1], [lineNumber, colNumber]]


:bug: Use provided text editor

:bug: Use provided text editor

--- lib/main.coffee
+++ lib/main.coffee
@@ -268,7 +268,7 @@

     Minimap ?= require './minimap'
     new Minimap({
-      textEditor: atom.workspace.getActiveTextEditor()
+      textEditor: textEditor
       standAlone: true
     })


change var name

change var name

--- lib/main.coffee
+++ lib/main.coffee
@@ -101,17 +101,17 @@
   # Services API method which would be registered and trigger
   # a deprecation call
   legacyProvideStatusBar: ->
-    sb = @provideStatusBar()
+    statusbar = @provideStatusBar()

     addLeftTile: (args...) ->
       Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
-      sb.addLeftTile(args...)
+      statusbar.addLeftTile(args...)
     addRightTile: (args...) ->
       Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
-      sb.addRightTile(args...)
+      statusbar.addRightTile(args...)
     getLeftTiles: ->
       Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
-      sb.getLeftTiles()
+      statusbar.getLeftTiles()
     getRightTiles: ->
       Grim.deprecate("Use version ^1.0.0 of the status-bar Service API.")
-      sb.getRightTiles()
+      statusbar.getRightTiles()


update scope for new ink version

update scope for new ink version

--- lib/repl.coffee
+++ lib/repl.coffee
@@ -180,11 +180,8 @@

     # Add new inline view
     r = new @ink.Result editor, [end, end],
-          content: view, error: error, type: if error then 'block' else 'inline'
-
-    # Adding the class here lets us apply proto repl specific styles to the display.
-    r.view.classList.add 'proto-repl'
-
+          content: view, error: error, {type: if error then 'block' else 'inline',
+                                        scope: 'proto-repl'}

   # Makes an inline displaying result handler
   # * editor - the text editor to show the inline display in


fix: get classicRepl preference

fix: get classicRepl preference

--- lib/repl.coffee
+++ lib/repl.coffee
@@ -62,7 +62,7 @@

   eval: (expression, noecho=false, nowExecutingPath=null) ->

-    classic = atom.config.get 'supercollider.classicRepl'
+    classic = atom.config.get 'atom-supercollider.classicRepl'

     ok = (result) =>
       @bus.push "
#{result}
"


Fix the indent calculation.

Fix the indent calculation.

--- lib/star.coffee
+++ lib/star.coffee
@@ -129,10 +129,11 @@
       @latestRowSeen = row

   _starIndexOf: (line) ->
-    match = /^\s*([\*\-\+]|\d+\.)/.exec(line)
-    console.log("_starIndexOf: "+line)
-    console.log(match)
-    return match.index
+    match = /^(\s*)([\*\-\+]|\d+\.)/.exec(line)
+    # No match, ignore
+    return 0 if match.length < 1
+    # count the spaces
+    return match[1].length

   newStarLine: (indentLevel = @indentLevel) ->
     if @indentType isnt "mixed"


Beef up twitter attachments

Beef up twitter attachments

- Add twitter handle
- Only add image element if exists
- Link images, twitter name, handle

--- src/react/attachments/twitter.coffee
+++ src/react/attachments/twitter.coffee
@@ -2,15 +2,27 @@

 class TwitterAttachment extends AttachmentElement
   render: ->
-    imgStyle =
-      "maxWidth": "#{@state.width- 50}px"
-

-
-
-
-
{ @props.attachment.author_name }

-

-
+    console.log(@props.attachment)
+
+

+

+
+
+
+

+
+            { @props.attachment.author_name }
+            { @props.attachment.author_subname }
+
+

+

+
+        { @props.attachment.image_url &&
+
+
+
+        }
+

 module.exports = TwitterAttachment


updated platform.coffee

updated platform.coffee

--- src/tasks/build/base/platform.coffee
+++ src/tasks/build/base/platform.coffee
@@ -27,6 +27,7 @@
       if fn then fn()

   buildPlatform = (platform, fn) ->
+    helpers.exec("cordova platform add #{platform}")  if grunt.config.get('phonegap.config.cli') is 'cordova'
     if helpers.isRemote(platform)
       remote platform, ->
         runAfter 'remote', platform, fn


Adding positioning of dropdown below cursor as well as function that returns new trix attachment

--- src/trix/models/auto_complete.coffee
+++ src/trix/models/auto_complete.coffee
@@ -138,6 +138,7 @@
          HTML = dropDownItem[0].innerText

       return unless HTML?
+      return unless endingPosition >= startingPosition

       @editor.setSelectedRange([startingPosition, endingPosition + 1])
       @editor.deleteInDirection("forward")


json_schema_options

--- src/validators/json-validator.coffee
+++ src/validators/json-validator.coffee
@@ -3,6 +3,25 @@

 {ValidationErrors} = require('./validation-errors')
 errors          = require '../errors'
+
+
+sylables = ['a','e','i','o','u']
+json_schema_options =
+  singleError: false
+  messages:
+    'minLength':   (prop, val, validator) -> "The #{prop} property must be at least #{validator} characters long (currently #{val.length} characters long)."
+    'maxLength':   (prop, val, validator) -> "The #{prop} property must not exceed #{validator} characters (currently #{val.length} characters long)."
+    'length':      (prop, val, validator) -> "The #{prop} property must be exactly #{validator} characters long (currently #{val.length} characters long)."
+    'format':      (prop, val, validator) -> "The #{prop} property must be #{if validator[0].toLowerCase() in sylables then 'an' else 'a'} #{validator} (current value is #{JSON.stringify val})."
+    'type':        (prop, val, validator) -> "The #{prop} property must be #{if validator[0].toLowerCase() in sylables then 'an' else 'a'} #{validator} (current value is #{JSON.stringify val})."
+    'except':      (prop, val, validator) -> "The #{prop} property must not be #{val}."
+    'minimum':     (prop, val, validator) -> "The minimum value of the #{prop} must be #{validator} (current value is #{JSON.stringify val})."
+    'maximum':     (prop, val, validator) -> "The maximum value of the #{prop} must be #{validator} (current value is #{JSON.stringify val})."
+    'pattern':     (prop, val, validator) -> "The #{prop} value (#{val}) does not match the #{validator} pattern."
+    'maxItems':    (prop, val, validator) -> "The #{prop} property must not contain more than #{validator} items (currently contains #{val.length} items)."
+    'minItems':    (prop, val, validator) -> "The #{prop} property must contain at least #{validator} items (currently contains #{val.length} items)."
+    'divisibleBy': (prop, val, validator) -> "The #{prop} property is not divisible by #{validator} (current value is #{JSON.stringify val})."
+    'uniqueItems': (prop, val, validator) -> "All items in the #{prop} property must be unique."

 JsonValidator = class JsonValidator

@@ -51,7 +70,7 @@
   #@private
   validatePrivate: ->
     try
-      return amanda.validate  @data, @schema, {singleError: false}, (error) =>
+      return amanda.validate  @data, @schema, json_schema_options, (error) =>
         return @errors = new ValidationErrors error
     catch error
       error = {


jsdom window.close() for mem leaks

jsdom window.close() for mem leaks

--- hn.coffee
+++ hn.coffee
@@ -35,7 +35,8 @@
         console.error "Total count: #{cnt}"
         console.error "Total error: #{errCnt}"
         console.error "next url: #{nextUrl}"
-        return
+        window.close()
+        return false

        err = false
        d =
@@ -183,6 +184,7 @@

        if index is list.length-1
         callback res
+        window.close()
         return false


initial commit

initial commit

--- index.coffee
+++ index.coffee
@@ -33,12 +33,12 @@
         @_historyState = @state
       delete @state
   _enter: (nextState, nextSubstates...) ->
+    if @enter
+      @enter()
     @state = @[nextState] ? @_historyState ? @[@_default ? @_history ? @_deepHistory]
     if !@state
       throw "Invalid state"
     delete @_historyState
-    if @state.enter
-      @state.enter()
     if nextSubstates[0] || @state._default || @state._historyState || @state._history || @state._deepHistory
       @state._enter(nextSubstates...)
   to: (states...) ->


[Routes] Create two routers, one for the site and another for API responses

This makes it easier to add middleware just for our API responses ex: CORS headers

--- index.coffee
+++ index.coffee
@@ -21,11 +21,18 @@
   @state.config = secret
   yield next

-app.use router app
-app.get '/', require './routes/home'
-app.get '/status', require './routes/status'
-app.all '/sendCode', formatApiErrors, require('./routes/codes').sendCodeAsync
-app.all '/checkCode', formatApiErrors, require('./routes/codes').checkCodeAsync
+siteRouter = router()
+siteRouter.get '/', require './routes/home'
+siteRouter.get '/status', require './routes/status'
+app.use siteRouter.routes()
+app.use siteRouter.allowedMethods()
+
+apiRouter = router()
+apiRouter.use formatApiErrors
+apiRouter.all '/sendCode', require('./routes/codes').sendCodeAsync
+apiRouter.all '/checkCode', require('./routes/codes').checkCodeAsync
+app.use apiRouter.routes()
+app.use apiRouter.allowedMethods()

 if require.main is module
   port = secret?.server?.port ? 3000


Functions in objects bug fixed

Functions in objects bug fixed

--- index.coffee
+++ index.coffee
@@ -47,7 +47,7 @@
 	assert obj.type is ATTRIBUTE, "isBinding: type must be an attribute"

 	try
-		eval "(function(console,module,require){return (#{obj.value});}).call(null,{},{},function(){})"
+		eval "(function(console,module,require){return (#{obj.value});}).call(null,null,{},function(){})"
 		return false

 	# unless BINDING.test(obj.value)
@@ -512,6 +512,12 @@
 # 	code

 stringify =
+	function: (elem) ->
+		args = idsKeys+''
+		if args and elem.params+''
+			args += ","
+		args += elem.params+''
+		"function(#{args}){#{elem.body}}"
 	object: (elem) ->
 		json = {}
 		children = []
@@ -554,6 +560,8 @@
 				# postfix += ", \"#{body.name}\": ((#{valueCode}), new Renderer.Component.Link('#{value.id}'))"
 				# return false
 				value = "((#{valueCode}), new Renderer.Component.Link('#{value.id}'))"
+			else if body.type is 'function'
+				value = stringify.function body
 			else if isAnchor(body)
 				value = anchorAttributeToString(body)
 			else if isBinding(body)
@@ -574,12 +582,7 @@
 					if value isnt false
 						json[body.name] = "`#{value}`"
 				when 'function'
-					args = idsKeys+''
-					if args and body.params+''
-						args += ","
-					args += body.params+''
-					func = "`function(#{args}){#{body.body}}`"
-					json[body.name] = func
+					json[body.name] = "`#{stringify.function body}`"
 				when 'property'
 					json.properties ?= []
 					json.properties.push body.name
@@ -689,6 +692,7 @@

 		code += '_c.item = '
 		code += elemCode
+		code += "_c.itemId = '#{elem.id}'\n"
 		code += "_c.idsOrder = #{JSON.stringify(idsKeys)}\n"
 		code += "_c.objectsOrder = #{JSON.stringify(idsKeys).replace(/\"/g, '')}\n"
 		code += "_c.objects = #{JSON.stringify(objects).replace(/\"`|`\"/g, '')}\n"
@@ -723,11 +727,12 @@

 # codes = module.exports("""
 # Image {
+# 	id: main
 # 	Class {
-# 		when: this.ab('a')
 # 		changes: {
-# 			children.order: Flow {
-# 				text: 'abc'
+# 			ab: 2
+# 			onReady: function(){
+# 				console.log(123);
 # 			}
 # 		}
 # 	}


Updated the controller

Updated the controller

--- dev/helpers/controller.coffee
+++ dev/helpers/controller.coffee
@@ -1,5 +1,18 @@
 'use strict'
+path = require 'path'
+fs = require 'fs'

 module.exports = class Controller
     constructor: ->
-        app = arguments[0]
+        @app = arguments[0]
+
+        @default_path = './controllers'
+        return
+    run: ->
+        console.log 'Run controller helper'
+        base_path_controller = path.resolve @default_path
+
+        files = fs.readdirSync base_path_controller
+
+        n = files.length - 1
+


Update tests for chainable methods

Update tests for chainable methods

--- test/kissmetrics.coffee
+++ test/kissmetrics.coffee
@@ -25,16 +25,16 @@
 		expectedOutput = /^GET \/?e\?_n=test%20event&_k=apiKey&_p=evan%40example\.com HTTP\/1\.1/

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.record('test event').output.pop().match(expectedOutput).should.be.ok
+		km.record('test event').lastQuery.output.pop().match(expectedOutput).should.be.ok

 	it 'should set properties', ->
 		expectedOutput = /GET \/?s\?place=home&_k=apiKey&_p=evan%40example\.com HTTP\/1\.1/

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.set({place: 'home'}).pop().output.pop().match(expectedOutput).should.be.ok
+		km.set({place: 'home'}).lastQuery.output.pop().match(expectedOutput).should.be.ok

 	it 'should alias people', ->
 		expectedOutput  = /GET \/?a\?_n=notevan%40example.com&_k=apiKey&_p=evan%40example\.com HTTP\/1\.1/

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.alias('notevan@example.com').output.pop().match(expectedOutput).should.be.ok
+		km.alias('notevan@example.com').lastQuery.output.pop().match(expectedOutput).should.be.ok


Refactor tests to just check the first line of the output

I mostly care about the query string that's produced

--- test/kissmetrics.coffee
+++ test/kissmetrics.coffee
@@ -1,5 +1,8 @@
 should = require 'should'
 KM     = require '../src/kissmetrics'
+
+String::startsWith = ( comparison ) ->
+	@substring( 0, comparison.length ) is comparison

 describe 'KM module', ->
 	it 'should exist', ->
@@ -22,25 +25,19 @@
 		km.should.have.property 'alias'

 	it 'should record events', ->
-		expectedOutput  = 'GET /e?_n=test%20event&_k=apiKey&_p=evan%40example.com HTTP/1.1\r\n'
-		expectedOutput += 'Host: trk.kissmetrics.com\r\n'
-		expectedOutput += 'Connection: keep-alive\r\n\r\n'
+		expectedOutput = 'GET /e?_n=test%20event&_k=apiKey&_p=evan%40example.com HTTP/1.1'

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.record('test event').output.pop().should.equal expectedOutput
+		km.record('test event').output.pop().startsWith(expectedOutput).should.be.ok

 	it 'should set properties', ->
-		expectedOutput  = 'GET /s?place=home&_k=apiKey&_p=evan%40example.com HTTP/1.1\r\n'
-		expectedOutput += 'Host: trk.kissmetrics.com\r\n'
-		expectedOutput += 'Connection: keep-alive\r\n\r\n'
+		expectedOutput = 'GET /s?place=home&_k=apiKey&_p=evan%40example.com HTTP/1.1'

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.set({place: 'home'}).pop().output.pop().should.equal expectedOutput
+		km.set({place: 'home'}).pop().output.pop().startsWith(expectedOutput).should.be.ok

 	it 'should alias people', ->
-		expectedOutput  = 'GET /a?_n=notevan%40example.com&_k=apiKey&_p=evan%40example.com HTTP/1.1\r\n'
-		expectedOutput += 'Host: trk.kissmetrics.com\r\n'
-		expectedOutput += 'Connection: keep-alive\r\n\r\n'
+		expectedOutput  = 'GET /a?_n=notevan%40example.com&_k=apiKey&_p=evan%40example.com HTTP/1.1'

 		km = new KM.KissmetricsClient 'apiKey', 'evan@example.com'
-		km.alias('notevan@example.com').output.pop().should.equal expectedOutput
+		km.alias('notevan@example.com').output.pop().startsWith(expectedOutput).should.be.ok


add a test for on post page

add a test for on post page

--- test/models/post.coffee
+++ test/models/post.coffee
@@ -122,5 +122,5 @@

     it 'true if on post page', ->
       post = new Post(fabricate('post'))
-      post.onPostPage("/post/#{post.get('id')}").should.equal true
-      post.onPostPage("/post/foo").should.equal false
+      post.onPostPage("/post/#{post.get('id')}").should.be.ok
+      post.onPostPage("/post/foo").should.not.be.ok


remove redundant code

remove redundant code

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -71,10 +71,8 @@
 		jqel.attr 'name', @rand()
 	showInsertion: ->
 		$('#insertion').removeClass 'hidden'
-		$('#insertion .expand-area').removeClass 'hidden'
 	hideInsertion: ->
 		$('#insertion').addClass 'hidden'
-		$('#insertion .expand-area').addClass 'hidden'
 		$('#insertion .expand-area').removeClass 'expand'
 	setInsertionTop: (top)->
 		$('#insertion').css 'top', top


comments

comments

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -1,4 +1,5 @@
 @Editor = class Editor
+
 	## PROPERTIES ##
 	titlePromptMessage: 'New title'
 	promptMessage: 'Type your article here'
@@ -14,6 +15,7 @@
 		changed: false
 		showToolpad: false
 		showTooltip: false
+
 	## INITIALIZERS AND ACCESSORS ##
 	constructor: (options={})->
 		@id = options.id
@@ -41,6 +43,7 @@
 		@status.changed = bool
 	setNew: (bool)->
 		@status.new = bool
+
 	## HELPERS ##
 	assignNameAttribute: (jqel)->
 		jqel.attr 'name', @rand()
@@ -48,43 +51,10 @@
 		result = ''
 		result += Math.random().toString(36).substr(2,1) for i in new Array(len)
 		result.toUpperCase()
+
 	## UI RELATED OPERATIONS ##
+
 	## RANGE OPERATIONS ##
-	## EVENT BINDINGS ##
-	displayPrompt: ->
-		$('#editor').children().first().html ''+@promptMessage+''
-	displayTitlePrompt: ->
-		$('#editor-title').html ''+@titlePromptMessage+''
-	clear: ->
-		$('#editor').children().first().html('
')
-	clearTitle: ->
-		$('#editor-title').html ''
-	clearStatus: ->
-		$('.debug-status').addClass 'hidden'
-		@status.cmd = @status.ctrl = @status.alt = @status.shift = false
-	cleanAttributes: (el)->
-		attributes = $.map el.attributes, (item)->
-			item.name
-		$.each attributes, (i, key)=>
-			$(@).removeAttr(key)
-	divsToPs: ->
-		#transform divs to ps
-		@saveSelection()
-		$('#editor div').not('[name]').each ->
-			el = $('
')
-			el.html $(@).html()
-			$(@).after(el)
-			$(@).remove()
-		@restoreSelection()
-
-	detectChanged: ->
-			title = $('#editor-title').html()
-			content = $('#editor').html()
-			if @lastTitle != title || @lastContent != content
-				@setChanged true
-				@lastTitle = title
-				@lastContent = content
-
 	selection: ->
 		window.getSelection() if window.getSelection
 	saveSelection: (prefix='cursor')->
@@ -120,6 +90,42 @@
 	getSelectedElement: ->
 		el = $(@selection().getRangeAt(0).commonAncestorContainer)
 		return if el[0].nodeType == 3 then el.parent() else el
+
+	## EVENT BINDINGS ##
+	displayPrompt: ->
+		$('#editor').children().first().html ''+@promptMessage+''
+	displayTitlePrompt: ->
+		$('#editor-title').html ''+@titlePromptMessage+''
+	clear: ->
+		$('#editor').children().first().html('
')
+	clearTitle: ->
+		$('#editor-title').html ''
+	clearStatus: ->
+		$('.debug-status').addClass 'hidden'
+		@status.cmd = @status.ctrl = @status.alt = @status.shift = false
+	cleanAttributes: (el)->
+		attributes = $.map el.attributes, (item)->
+			item.name
+		$.each attributes, (i, key)=>
+			$(@).removeAttr(key)
+	divsToPs: ->
+		#transform divs to ps
+		@saveSelection()
+		$('#editor div').not('[name]').each ->
+			el = $('
')
+			el.html $(@).html()
+			$(@).after(el)
+			$(@).remove()
+		@restoreSelection()
+	detectChanged: ->
+			title = $('#editor-title').html()
+			content = $('#editor').html()
+			if @lastTitle != title || @lastContent != content
+				@setChanged true
+				@lastTitle = title
+				@lastContent = content
+
+

 	autosave: (durationInMilliseconds=5000)->
 		(update= =>


Ignore Return Value of gulp.watch()

Ignore Return Value of gulp.watch()

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -35,6 +35,7 @@
 gulp.task 'watch', ['haml', 'coffee'], ->
   gulp.watch HAML_PATH, ['haml']
   gulp.watch COFFEE_PATH, ['coffee']
+  return

 gulp.task 'serve', ->
   serve DEST


Using variables in browserify globs

Using variables in browserify globs

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -8,7 +8,7 @@
 scriptPath = '/src' # within srcPath and destPath, only used with browserify
 coffeeGlobs = ['./gulpfile.coffee', "#{srcPath}/**/*.coffee", "#{testPath}/**/*.coffee"]
 perfGlob = "#{testPath}/**/perf*.coffee"
-transformGlobs = ['./app/src/index.coffee', './app/src/minimax-worker.coffee']
+transformGlobs = ["#{srcPath}#{scriptPath}/index.coffee", "#{srcPath}#{scriptPath}/minimax-worker.coffee"]

 gulp = require 'gulp'
 $ = (require 'gulp-load-plugins')()


fix(less): add paths to less configuration

Closes #20

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -770,6 +770,9 @@
 gulp.task 'less', ['prepare'], ->
 	options =
 		less:
+			paths: [
+				path.resolve SRC_DIRECTORY
+			]
 			sourceMap: true
 			sourceMapBasepath: path.resolve TEMP_DIRECTORY


Added support for running tests in desktop browsers.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -330,8 +330,19 @@
       ]
     )

-runTestsInBrowser = ->
-  # TODO
+runTestsInBrowsers = ->
+  gulp.src "#{paths.build.tests}/**/*.spec.js"
+    .pipe plugins.karmaRunner.server(
+      'singleRun': false
+      'frameworks': [ 'jasmine' ]
+      'browsers': [ 'PhantomJS', 'Chrome', 'Safari', 'Firefox' ]
+      'reporters': [ 'progress', 'kjhtml' ]
+      files: [
+        "#{paths.build.scripts}/vendor/**/*.js"
+        "#{paths.build.scripts}/cyclops.js"
+        "#{paths.build.tests}/**/*.spec.js"
+      ]
+    )

 # Tasks ------------------------------------------------------------------------

@@ -364,4 +375,4 @@

 gulp.task 'test', gulp.series('compile', compileTests, runTests)

-gulp.task 'test-browser', gulp.series('compile', compileTests, runTestsInBrowser)
+gulp.task 'test-browsers', gulp.series('compile', compileTests, runTestsInBrowsers)


bare coffee

bare coffee

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

   gulp.src files
       .pipe plumber()
-      .pipe coffee()
+      .pipe coffee(bare: true)
       .pipe concat('application.js')
       .pipe sourcemaps.write('.')
       .pipe gulp.dest('./public/dist/')


License change from Apache to MIT, approved by all contributors

All the details here: https://github.com/sorich87/bootstrap-tour/issues/257

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -21,14 +21,14 @@
    * <%= pkg.name %> - v<%= pkg.version %>
    * <%= pkg.homepage %>
    * ========================================================================
-   * Copyright 2012-2013 <%= pkg.author.name %>
+   * Copyright 2012-2015 <%= pkg.author.name %>
    *
    * ========================================================================
-   * Licensed under the Apache License, Version 2.0 (the "License");
+   * Licensed under the MIT License (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
-   *     http://www.apache.org/licenses/LICENSE-2.0
+   *     https://opensource.org/licenses/MIT
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,


build source maps for dist

build source maps for dist

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -47,7 +47,7 @@
   es.merge.apply null, items.map (entry) ->
     b = browserify(
       entries: entry[0]
-      debug: true if !dist
+      debug: true
       extensions: ['.coffee']
       paths: ['src'])
     b.exclude 'js-nacl'
@@ -61,7 +61,7 @@

     # comment out this to turn off source maps
     b = b.pipe transform(->
-      exorcist dir + entry[1] + '.map', null, '../', './') if !dist
+      exorcist dir + entry[1] + '.map', null, '../', './')

     b = b.pipe gulp.dest dir
     b = b.pipe rename entry[1].replace('.js', '.min.js') if dist


Explode on coverage fail

Explode on coverage fail

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -11,7 +11,6 @@
 git = require('gulp-git')
 size = require('gulp-size')
 sloc = require('gulp-sloc')
-child_process = require('child_process')
 es = require('event-stream')
 webpack = require('webpack')
 webpackConfig = require('./webpack.config')
@@ -81,7 +80,7 @@

 gulp.task 'check-coverage', ->
   options =
-    silent: false
+    silent: true
     coverage: require('./.coverage.json')

   onCoverageError = (errors) ->
@@ -91,6 +90,7 @@
       .filter((line) -> !line.indexOf("ERROR:"))
       .forEach (error) ->
         gutil.log(gutil.colors.red(error))
+    process.exit(1)

   stream = gulp.src('./')
     .pipe(exec('node_modules/.bin/istanbul check-coverage --statements <%= options.coverage.statements %> --branches <%= options.coverage.branches %> --functions <%= options.coverage.functions %> --lines <%= options.coverage.lines %>', options))


Turn off Markdown beautify for Atom

Turn off Markdown beautify for Atom

--- atom/dot-atom/config.cson
+++ atom/dot-atom/config.cson
@@ -1,6 +1,5 @@
 "*":
   Hydrogen:
-    kernelspec: "{}"
     languageMappings: '''
       {
           "Pweave markdown": "Python 3",
@@ -22,7 +21,6 @@
     general:
       beautifyEntireFileOnSave: false
     markdown:
-      beautify_on_save: true
       commonmark: true
       default_beautifier: "Remark"
     python:


add two address matched spec

add two address matched spec

--- test/address_resolver.coffee
+++ test/address_resolver.coffee
@@ -7,6 +7,13 @@
       it 'returns address', ->
         @resolver.find('0010933').then (results) ->
           assert.ok results[0].prefecture == '北海道'
+
+    context 'when two address matched', ->
+      beforeEach ->
+        @resolver = new AddressResolver
+      it 'returns addresses', ->
+        @resolver.find('0040000').then (results) ->
+          assert.ok results.length == 2

     context 'when the zip code is short', ->
       beforeEach ->


Add click event to tab.coffee

Add click event to tab.coffee

--- src/scripts/modules/media/footer/inherits/tab/tab.coffee
+++ src/scripts/modules/media/footer/inherits/tab/tab.coffee
@@ -15,6 +15,7 @@

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

     initialize: () ->
       super()
@@ -23,3 +24,14 @@
     toggleMedia: (e) ->
       @media = $(e.currentTarget).data('media')
       @render()
+
+    contentDisplay: (e) ->
+      e.preventDefault()
+      currentTarget = $(e.currentTarget)
+      contentDisplay = $('.content-display')
+      contentDisplay.toggle()
+      if contentDisplay.is(':visible')
+        currentTarget.text('Less Details')
+      else
+        currentTarget.text('More Details')
+      return


Minor style fix in main.coffee

Minor style fix in main.coffee

--- frontend/assets/js/main.coffee
+++ frontend/assets/js/main.coffee
@@ -174,7 +174,7 @@
   for course in selectedCourses.array
     url += shorten(course.name) + ':' + course.selectedGroup + ','

-  window.history.pushState(dummy, 'dummy', url);
+  window.history.pushState(dummy, 'dummy', url)

 shorten = (name) ->
   name.replace(/\s+|,|\.|:/g, '')


Fix wrong text in popup when opening links.

--- src/ui/views/messages.coffee
+++ src/ui/views/messages.coffee
@@ -72,7 +72,7 @@

     # Showing message with 3 second delay showing the user that something is happening
     notr {
-      html: i18n.__ 'menu.help.about.title:Opening the link in the browser...'
+      html: i18n.__ 'conversation.open_link:Opening the link in the browser...'
       stay: 3000
     }


remove takeScreenshot() call from fsSelectSpec

--- test/e2e/fsSelectSpec.coffee
+++ test/e2e/fsSelectSpec.coffee
@@ -24,7 +24,6 @@
   it 'should allow to navigate through list with arrows', ->
     $('.first-select .fs-select-active').click()
     $('.first-select input').sendKeys($ptor.Key.DOWN) for [1..10]
-    takeScreenshot()
     $('.first-select input').sendKeys($ptor.Key.ENTER)
     expect($('#valueId').getText()).toBe('2')


Represent pages as objects for Sammy

Represent pages as objects for Sammy

--- js/outer.coffee
+++ js/outer.coffee
@@ -7,20 +7,29 @@
 (($) ->
   circle = $.sammy("body", ->

+    # Page
+    class Page
+      constructor: (@name, @title) ->
+
+      render: ->
+        document.title = "Circle - " + @title
+        $("body").attr("id",@name).html HAML[@name](renderContext)
+
+      load: ->
+        if HAML? and HAML[@name]?
+          @render()
+        else
+          self = this
+          $.getScript "assets/views/outer/#{@name}/#{@name}.hamlc", -> self.render()
+
+    # Pages
+    home = new Page("home", "Continuous Integration made easy")
+    about = new Page("about", "About Us")
+
     # Navigation
-    @get "/", (context) -> loader "home"
-    @get "#/about", (context) -> loader "about"
+    @get "/", (context) -> home.load()
+    @get "#/about", (context) -> about.load()

-    # Render helper
-    render = (page) ->
-      $("body").attr("id",page).html HAML[page](renderContext)
-
-    # Load helper
-    loader = (page) ->
-      if @HAML? and @HAML[page]?
-        render page
-      else
-        $.getScript "assets/views/outer/#{page}/#{page}.hamlc", -> render page
   )

   # Run the application


Set resizable window by default in debug mode.

--- electron.coffee
+++ electron.coffee
@@ -33,8 +33,8 @@
         win = new BrowserWindow options

         # Setting minimum size.
-        resizable = false or options?.resizable
-        win.setResizable false
+        resizable = isDebug or options?.resizable
+        win.setResizable resizable
         # and load the index.html of the app.
         win.loadURL url.format
             pathname: path.join __dirname, '/static_files/index.html'