Adding Cody to users.

Adding Cody to users.

--- assets/javascripts/views/username.coffee
+++ assets/javascripts/views/username.coffee
@@ -13,6 +13,7 @@
     jenleereeves:  "Jen Lee Reeves"
     projectopenvault: "Project OpenVault Team"
     stacewelsh:     "Stacey Welsh"
+    codylagrow:     "Cody LaGrow"

   affiliations:
     knowtheory:    "Project Open Vault"
@@ -25,6 +26,7 @@
     swaffords:     "The Columbia Missourian"
     jenleereeves:  "KOMU8"
     stacewelsh:    "KOMU8"
+    codylagrow:    "KOMU8"

   initialize: (options) ->
     @username = (options.username || options.el.html() || "").toLowerCase()


Added chart extension

Added chart extension

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -75,9 +75,12 @@
         stripe:
           coffee: '<%=folder.app%>extension/stripe/**/*.coffee'
           stylus: '<%=folder.app%>extension/stripe/style/*.styl'
+        chart:
+          coffee: '<%=folder.app%>extension/chart/**/*.coffee'
+          stylus: '<%=folder.app%>extension/chart/style/*.styl'

     icons:
-      stylus: 'extensions/icons/style/*.styl'
+      stylus: '<%=folder.icons%>/style/*.styl'

     doc:
       es: 'extensions/app/docs/ES/*.md'
@@ -93,6 +96,7 @@
       app_carousel      : files: '<%=folder.build%>app.carousel.coffee'         : '<%= app.extension.carousel.coffee %>'
       app_gmaps         : files: '<%=folder.build%>app.gmaps.coffee'            : '<%= app.extension.gmaps.coffee %>'
       app_stripe        : files: '<%=folder.build%>app.stripe.coffee'           : '<%= app.extension.stripe.coffee %>'
+      app_chart        : files: '<%=folder.build%>app.chart.coffee'             : '<%= app.extension.chart.coffee %>'
       # Test
       test              :   files: '<%=folder.build%>test.coffee'               : '<%= core.test %>'

@@ -105,6 +109,7 @@
       app_carousel      : files: '<%=folder.build%>app.carousel.js'             : '<%=folder.build%>app.carousel.coffee'
       app_gmaps         : files: '<%=folder.build%>app.gmaps.js'                : '<%=folder.build%>app.gmaps.coffee'
       app_stripe        : files: '<%=folder.build%>app.stripe.js'               : '<%=folder.build%>app.stripe.coffee'
+      app_chart        : files: '<%=folder.build%>app.chart.js'                 : '<%=folder.build%>app.chart.coffee'
       # Test
       test              : files: '<%=folder.build%>test.js'                     : '<%=folder.build%>test.coffee'

@@ -129,6 +134,9 @@
       app_stripe:
         options: mangle: false
         files: '<%=folder.app%>extension/stripe/<%=pkg.name%>.app.stripe.js'    : '<%=folder.build%>app.stripe.js'
+      app_chart:
+        options: mangle: false
+        files: '<%=folder.app%>extension/chart/<%=pkg.name%>.app.chart.js'      : '<%=folder.build%>app.chart.js'

     copy:
       doc_es:
@@ -149,10 +157,10 @@
     stylus:
       # App
       app_stylus:
-        options: compress: true, import: [ '__init']
+        options: compress: true, import: ['__init']
         files: '<%=folder.bower%><%=pkg.name%>.app.css'                         : '<%=app.stylus%>'
       app_theme:
-        options: compress: false, import: [ '__init']
+        options: compress: true, import: ['__init']
         files: '<%=folder.bower%><%=pkg.name%>.app.theme.css'                   : '<%=app.theme%>'
       app_appnima_user:
         options: compress: true
@@ -165,7 +173,10 @@
         files: '<%=folder.app%>extension/gmaps/<%=pkg.name%>.app.gmaps.css'     : '<%=app.extension.gmaps.stylus%>'
       app_stripe:
         options: compress: true
-        files: '<%=folder.app%>extension/stripe/<%=pkg.name%>.app.stripe.css'     : '<%=app.extension.stripe.stylus%>'
+        files: '<%=folder.app%>extension/stripe/<%=pkg.name%>.app.stripe.css'   : '<%=app.extension.stripe.stylus%>'
+      app_chart:
+        options: compress: true
+        files: '<%=folder.app%>extension/chart/<%=pkg.name%>.app.chart.css'     : '<%=app.extension.chart.stylus%>'
       # Icons
       icons:
         options: compress: true
@@ -197,7 +208,7 @@
       app_coffee:
         files: ['<%= app.coffee %>']
         tasks: ['concat:app', 'coffee:app', 'uglify:app', 'notify:app']
-      app_stylys:
+      app_stylus:
         files: ['<%= app.stylus %>']
         tasks: ['stylus:app_stylus', 'notify:app_stylus']
       app_theme:
@@ -216,6 +227,9 @@
       app_stripe:
         files: ['<%= app.extension.stripe.coffee %>']
         tasks: ['concat:app_stripe', 'coffee:app_stripe', 'uglify:app_stripe']
+      app_chart:
+        files: ['<%= app.extension.chart.coffee %>']
+        tasks: ['concat:app_chart', 'coffee:app_chart', 'uglify:app_chart']
       app_appnima_user_stylus:
         files: ['<%= app.extension.appnima.user.stylus %>']
         tasks: ['stylus:app_appnima_user']
@@ -228,6 +242,9 @@
       app_stripe_stylus:
         files: ['<%= app.extension.stripe.stylus %>']
         tasks: ['stylus:app_stripe']
+      app_chart_stylus:
+        files: ['<%= app.extension.chart.stylus %>']
+        tasks: ['stylus:app_chart']
       # Icons
       icons:
         files: ['<%= icons.stylus %>']


added folders (mkdirp) and colors fns

added folders (mkdirp) and colors fns


コーディングスタイルを統一

コーディングスタイルを統一


remove contact records

remove contact records

--- vue/src/shared/services/records.coffee
+++ vue/src/shared/services/records.coffee
@@ -12,7 +12,6 @@
 import NotificationRecordsInterface from '@/shared/interfaces/notification_records_interface'
 import UserRecordsInterface from '@/shared/interfaces/user_records_interface'
 import SearchResultRecordsInterface from '@/shared/interfaces/search_result_records_interface'
-import ContactRecordsInterface from '@/shared/interfaces/contact_records_interface'
 import VersionRecordsInterface from '@/shared/interfaces/version_records_interface'
 import TranslationRecordsInterface from '@/shared/interfaces/translation_records_interface'
 import SessionRecordsInterface from '@/shared/interfaces/session_records_interface'
@@ -48,7 +47,6 @@
 records.addRecordsInterface NotificationRecordsInterface
 records.addRecordsInterface UserRecordsInterface
 records.addRecordsInterface SearchResultRecordsInterface
-records.addRecordsInterface ContactRecordsInterface
 records.addRecordsInterface VersionRecordsInterface
 records.addRecordsInterface TranslationRecordsInterface
 records.addRecordsInterface SessionRecordsInterface


current option template fix

current option template fix

--- jquery-select7.coffee
+++ jquery-select7.coffee
@@ -1,9 +1,9 @@
 ###
 @name jquery-select7
-@version 1.2.3
+@version 1.2.4
 @author Se7enSky studio <info@se7ensky.com>
 ###
-###! jquery-select7 1.2.3 http://github.com/Se7enSky/jquery-select7 ###
+###! jquery-select7 1.2.4 http://github.com/Se7enSky/jquery-select7 ###

 plugin = ($) ->

@@ -127,8 +127,8 @@
 				$value.html @config.currentTemplate @selected
 			else
 				$value.text @selected.title
-			$value.find(".select7__icon").remove()
-			$value.prepend """""" if @selected.icon
+				$value.find(".select7__icon").remove()
+				$value.prepend """""" if @selected.icon

 		open: ->
 			return if @opened


:art: map c-c, c-[ to core:cancel to invoke cancel()

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -314,6 +314,8 @@
 'atom-text-editor.vim-mode-search':
   'ctrl-r ctrl-w': 'vim-mode:search-set-cursor-word'
   'ctrl-v': 'vim-mode:search-set-literal-char'
+  'ctrl-c': 'core:cancel'
+  'ctrl-[': 'core:cancel'

   # Don't afraid to set following agressive keymap
   # If you want input literlly, `ctrl-v` then input char you want to insert


add standalone library

add standalone library

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -1,16 +1,47 @@
-gulp = require 'gulp'
-gutil = require 'gulp-util'
-mocha = require 'gulp-mocha'
-coffee = require 'gulp-coffee'
+gulp       = require 'gulp'
+gutil      = require 'gulp-util'
+mocha      = require 'gulp-mocha'
+coffee     = require 'gulp-coffee'
+browserify = require 'browserify'
+coffeeify  = require 'coffeeify'
+source     = require 'vinyl-source-stream'
+rename     = require 'gulp-rename'
+uglify     = require 'gulp-uglify'
+streamify  = require 'gulp-streamify'

+# application entry point to generate standalone library
+ENTRY = './src/gerber-to-svg.coffee'
+DIST = 'gerber-to-svg'
+DISTDIR = './dist'
+NAME = 'gerberToSvg'
+
+# source code and destination code locations
 SRCDIR = './src/*.coffee'
-DESTDIR = './lib'
+LIBDIR = './lib'

-gulp.task 'default', ->
+gulp.task 'default', [ 'standalone' ], ->
   gulp.src SRCDIR
     .pipe coffee()
       .on 'error', gutil.log
-    .pipe gulp.dest DESTDIR
+    .pipe gulp.dest LIBDIR
+
+gulp.task 'standalone', ->
+  browserify ENTRY, {
+      extensions: [ '.coffee' ]
+      standalone: NAME
+    }
+    .transform 'coffeeify'
+    .bundle()
+      .on 'error', gutil.log
+    .pipe source DIST+'.js'
+    .pipe gulp.dest DISTDIR
+    .pipe rename DIST+'.min.js'
+    .pipe streamify uglify {
+      preamble: '/* view source at github.com/mcous/gerber-to-svg */'
+      compress: { drop_console: true }
+      mangle: true
+    }
+    .pipe gulp.dest DISTDIR

 gulp.task 'test', ->
   gulp.src './test/*_test.coffee', { read: false }


add standalone library

add standalone library


Add task: build-handlebars

Add task: build-handlebars

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -7,7 +7,12 @@
 declare = require 'gulp-declare'

 # main task
-gulp.task 'build',['build-assets', 'build-typescript', 'build-bower-components']
+gulp.task 'build',[
+  'build-assets',
+  'build-typescript',
+  'build-bower-components',
+  'build-templates',
+]

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

@@ -31,5 +36,16 @@

 gulp.task 'build-bower-components',->
   bowerFiles()
-    .pipe concat 'venders.js'
+    .pipe concat 'vendors.js'
     .pipe gulp.dest './dest/js/'
+
+gulp.task 'build-templates',->
+  gulp.src './src/tpl/*.hbs'
+    .pipe handlebars()
+    .pipe wrap 'Handlebars.template(<%= contents %>)'
+    .pipe declare {
+      namespace: 'Diccal.templates',
+      noRedeclare: true,
+    }
+    .pipe concat 'templates.js'
+    .pipe gulp.dest './dest/js/'


updating gulp file to only run watchJS on serve

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -82,7 +82,7 @@

   return # Since this is async

-gulp.task 'tdd', ['build'],  (done) ->
+gulp.task 'tdd', (done) ->
   buildTests(true)
   .on 'end', ->
     config =
@@ -169,8 +169,9 @@

 gulp.task 'dist', ['build']
 gulp.task 'prod', ['archive']
-gulp.task 'watch', ['build', 'watchJS'], ->
+gulp.task 'watch', ['watchJS', 'styles', 'copyResources', 'copyFonts'], () ->
   gulp.watch 'style/**/{*.less, *.css}', ['styles']
+  gulp.watch ['test/**/*.coffee'], ['tdd']

 gulp.task 'build',
   ['buildJS', 'styles', 'copyResources', 'copyFonts']


Make byId and byTemplate only work in localhost

--- viewmodel.coffee
+++ viewmodel.coffee
@@ -5,6 +5,8 @@
     in: 1
     return: 1
     typeof: 1
+
+  isDev = window.location.hostname is "localhost"

   viewmodels = []
   @byId = (id) ->
@@ -383,15 +385,17 @@
         addParent vm, template
         [template, template.$(db)]

-      if template instanceof Blaze.TemplateInstance
-        viewmodels.push
-          vm: @
-          id: @_vm_id.substring("_vm_".length)
-          template: template.view.name.substring("Template.".length)
-      else
-        viewmodels.push
-          vm: @
-          id: @_vm_id.substring("_vm_".length)
+      if isDev
+        if template instanceof Blaze.TemplateInstance
+          viewmodels.push
+            vm: @
+            id: @_vm_id.substring("_vm_".length)
+            template: template.view.name.substring("Template.".length)
+        else
+          viewmodels.push
+            vm: @
+            id: @_vm_id.substring("_vm_".length)
+

       self = @
       if container?.autorun


Quickfix syntax error

Quickfix syntax error

--- client/app/components/application.coffee
+++ client/app/components/application.coffee
@@ -84,7 +84,7 @@

         keyFirst = 'left-panel-' + layout.firstPanel.action + '-' +
             Object.keys(layout.firstPanel.parameters).join('-')
-        if layout.secondPaenl?
+        if layout.secondPanel?
             keySecond = 'right-panel-' + layout.secondPanel.action + '-' +
                 Object.keys(layout.secondPanel.parameters).join('-')
         # Actual layout
@@ -128,8 +128,8 @@
                             div
                                 className: panelClasses.secondPanel,
                                 key: keySecond,
-                                    secondPanel @getPanelComponent
-                                        layout.secondPanel, 'second'
+                                    @getPanelComponent layout.secondPanel,
+                                        'second'

     # Panels CSS classes are a bit long so we get them from a this subfunction


Reorder imports

Reorder imports


Tests: Teams: Inviteteams: added pause selector for notification remove.

--- client/test/lib/teams/inviteteams.coffee
+++ client/test/lib/teams/inviteteams.coffee
@@ -20,6 +20,7 @@
     teamsHelpers.clickTeamSettings(browser)
     teamsHelpers.openInvitationsTab(browser)
     email = teamsHelpers.inviteUser(browser)
+    browser.pause 5000 # Wait for notification remove
     teamsHelpers.invitationAction(browser, email)
     browser.end()

@@ -30,5 +31,6 @@
     teamsHelpers.clickTeamSettings(browser)
     teamsHelpers.openInvitationsTab(browser)
     email = teamsHelpers.inviteUser(browser)
+    browser.pause 5000 # Wait for notification remove
     teamsHelpers.invitationAction(browser, email, yes)
     browser.end()


Remove useless argument.

Remove useless argument.

--- server.coffee
+++ server.coffee
@@ -34,6 +34,8 @@
 			index: previous
 			question: question
 			time: time
+			finished: false
+			result: []

 		Timer.cancel()
 		Timer.set duration, 'newRound'


interval

interval

--- server.coffee
+++ server.coffee
@@ -40,7 +40,14 @@
 app.set 'crowler',crowler

 ### start hatena-hotentry crowler ###
-hatenaCrowler = require(path.resolve 'crowler','hatenaHotentry') app
+hatenaCrowler = require(path.resolve 'crowler','hatenaHotentry')
+hatenaCrowler(app)
+recursiveCrowl = ->
+  setTimeout ->
+    hatenaCrowler(app)
+    recursiveCrowl()
+  ,1000*60*60 # 1hour
+

 server.listen app.get("port"), ->
   debug "Express server listening on port " + app.get("port")


Fix bug with server side updates of decks

--- server.coffee
+++ server.coffee
@@ -115,7 +115,9 @@
   if req.user
     deck.username = req.user.username
     if deck._id
-      db.collection('decks').update {_id: deck._id}, deck, (err) ->
+      id = deck._id
+      delete deck._id
+      db.collection('decks').update {_id: mongoskin.helper.toObjectID(id)}, deck, (err) ->
         console.log(err) if err
         res.send {message: 'OK'}, 200
     else


Server.coffee belonging to last commit

Server.coffee belonging to last commit

--- server.coffee
+++ server.coffee
@@ -24,25 +24,31 @@

 #========== Client calls ==========
 # Add a beacon (during setup phase)
-exports.client_addMarker = (location) ->
-	log 'Adding marker: lat=', location.lat, ', lng=', location.lng
-	nextNumber = 0
-	while Db.shared.get('game', 'beacons', nextNumber)?
-		nextNumber++
-
-	Db.shared.set 'game', 'beacons', nextNumber, {location: location}
-	Db.shared.set 'game', 'beacons', nextNumber, 'owner', -1
-	Db.shared.set 'game', 'beacons', nextNumber, 'nextOwner', -1
-	Db.shared.set 'game', 'beacons', nextNumber, 'percentage', 0
-	Db.shared.set 'game', 'beacons', nextNumber, 'captureValue', 10
-	Db.shared.set 'game', 'beacons', nextNumber, 'action', "none"
-
-exports.client_deleteMarker = (location) ->
+exports.client_addMarker = (client, location) ->
+	if Db.shared.get('gameState') isnt 0
+		log Plugin.userName(client), ' (id=', client, ') tried to add a marker while game is not in setup phase!'
+	else
+		log 'Adding marker: lat=', location.lat, ', lng=', location.lng
+		nextNumber = 0
+		while Db.shared.get('game', 'beacons', nextNumber)?
+			nextNumber++
+
+		Db.shared.set 'game', 'beacons', nextNumber, {location: location}
+		Db.shared.set 'game', 'beacons', nextNumber, 'owner', -1
+		Db.shared.set 'game', 'beacons', nextNumber, 'nextOwner', -1
+		Db.shared.set 'game', 'beacons', nextNumber, 'percentage', 0
+		Db.shared.set 'game', 'beacons', nextNumber, 'captureValue', 10
+		Db.shared.set 'game', 'beacons', nextNumber, 'action', "none"
+
+exports.client_deleteMarker = (client, location) ->
 	#Finding the right beacon
-	log 'Deleting marker: lat=', location.lat, ', lng=', location.lng
-	Db.shared.iterate 'game', 'beacons', (beacon) !->
-		if beacon.get('location', 'lat') == location.lat and beacon.get('location', 'lng') == location.lng
-			Db.shared.remove 'game', 'beacons', beacon.n
+	if Db.shared.get('gameState') isnt 0
+		log Plugin.userName(client), ' (id=', client, ') tried to delete a marker while game is not in setup phase!'
+	else
+		log 'Deleting marker: lat=', location.lat, ', lng=', location.lng
+		Db.shared.iterate 'game', 'beacons', (beacon) !->
+			if beacon.get('location', 'lat') == location.lat and beacon.get('location', 'lng') == location.lng
+				Db.shared.remove 'game', 'beacons', beacon.n

 # Set the round time unit and number
 exports.client_setRoundTime = (roundTimeNumber, roundTimeUnit) ->
@@ -105,11 +111,11 @@
 				Timer.cancel 'onNeutralize', {beacon: beacon.n, players: getInrangePlayers(beacon.n)}
 				if newStatus
 					owner = beacon.get 'owner'
-					log 'Adding to inRange: id=', client, ', name=', Plugin.userName(client)
+					log 'Added to inRange: id=', client, ', name=', Plugin.userName(client)
 					beacon.set 'inRange', client, 'true'
 					# Start takeover
 				else
-					log 'Removed from inRange: ', client, ', name=', Plugin.userName(client)
+					log 'Removed from inRange: id=', client, ', name=', Plugin.userName(client)
 					# clean takeover
 					beacon.remove 'inRange', client

@@ -119,7 +125,7 @@
 				Db.shared.iterate 'game', 'beacons', beacon.n, 'inRange', (player) !->
 					team = getTeamOfUser(player.n)
 					teamMembers[team] = teamMembers[team]+1
-				log 'teamMembers count: ', teamMembers
+				#log 'teamMembers count: ', teamMembers

 				# Determine who is competing
 				max = 0
@@ -144,16 +150,16 @@
 						if owner == -1
 							# Capturing
 							log 'Team ', activeTeam, ' is capturing beacon ', beacon.n
+							beacon.set 'actionStarted', new Date()/1000
 							beacon.set 'action', 'capture'
-							beacon.set 'actionStarted', new Date()/1000
 							# Set timer for capturing
 							playersStr = getInrangePlayers(beacon.n)
 							Timer.set (100-percentage)*10*30, 'onCapture', {beacon: beacon.n, players: playersStr}
 						else
 							# Neutralizing
 							log 'Team ', activeTeam, ' is neutralizing beacon ', beacon.n
+							beacon.set 'actionStarted', new Date()/1000
 							beacon.set 'action', 'neutralize'
-							beacon.set 'actionStarted', new Date()/1000

 							playersStr = getInrangePlayers(beacon.n)
 							Timer.set percentage*10*30, 'onNeutralize', {beacon: beacon.n, players: playersStr}
@@ -162,8 +168,8 @@

 				else if competing.length > 1 or competing.length is 0
 					# No progess, stand-off
+					beacon.set 'actionStarted', new Date()
 					beacon.set 'action', 'none'
-					beacon.set 'actionStarted', new Date()
 					if competing.length > 1
 						log 'Capture of beacon ', beacon.n, ' on hold, competing teams: ', competing
 					else
@@ -188,14 +194,13 @@

 # Called by the beacon capture timer
 exports.onCapture = (args) !->
-	log 'args=', args
 	beacon = Db.shared.ref 'game', 'beacons', args.beacon
 	nextOwner = beacon.get('nextOwner')
 	log 'Team ', nextOwner, ' has captured beacon ', beacon.n, ', players: ', args.players
 	beacon.set 'percentage', 100
 	beacon.set 'owner', nextOwner
+	beacon.set 'actionStarted', new Date()/1000
 	beacon.set 'action', 'none'
-	beacon.set 'actionStarted', new Date()/1000

 	# Add event log entrie(s)
 	maxId = Db.shared.ref('game', 'eventlist').incr 'maxId'
@@ -208,7 +213,7 @@
 	# TODO: Personalize for team members or dubed players
 	Event.create
 		unit: 'capture'
-		text: "Team " + Db.shared.get('colors', nextOwner , 'name') + " captured a beacon"
+		text: "Team " + Db.shared.peek('colors', nextOwner , 'name') + " captured a beacon"

 	# Handle points and statistics
 	client = args.players.split(', ')[0]
@@ -223,7 +228,6 @@

 # Called by the beacon neutralize timer
 exports.onNeutralize = (args) !->
-	log 'args=', args
 	beacon = Db.shared.ref 'game', 'beacons', args.beacon
 	neutralizer = beacon.get('nextOwner')
 	log 'Team ', neutralizer, ' has neutralized beacon ', beacon.n, ', players: ', args.players
@@ -351,9 +355,9 @@
 		Db.shared.set 'game', 'eventlist', maxId, 'timestamp', new Date()/1000
 		Db.shared.set 'game', 'eventlist', maxId, 'type', "score"
 		Db.shared.set 'game', 'eventlist', maxId, 'leading', teamClient
-		log "Team " + Db.shared.get('colors', teamMax, 'name') + " took the lead!"
+		log "Team " + Db.shared.peek('colors', teamMax, 'name') + " took the lead!"
 		Event.create
 			unit: 'score'
-			text: "Team " + Db.shared.get('colors', teamMax, 'name') + " took the lead!"
-
-
+			text: "Team " + Db.shared.peek('colors', teamMax, 'name') + " took the lead!"
+
+


Change Metric

Change Metric


add data column ui

add data column ui

--- coffee/operations/add_data_column.coffee
+++ coffee/operations/add_data_column.coffee
@@ -39,10 +39,10 @@
       style: {display: "none"}
       type: "file", on: {change: @$.on.changeFile}

-     @button on: {click: @$.on.openFile}, 'Open file'
+     @button ".u-full-width", on: {click: @$.on.openFile}, 'Open file'

-     @button '.button-primary', on: {click: @$.on.loadData}, 'Load'
-     @button on: {click: @$.on.cancel}, 'Cancel'
+     @button ".u-full-width.button-primary", on: {click: @$.on.loadData}, 'Load'
+     @button ".u-full-width", on: {click: @$.on.cancel}, 'Cancel'

     Weya elem: @elems.content, context: this, ->
      @$.elems.textArea = @textarea ".textarea-data", '',


:memo: Mention single string argument support

--- src/scope-selector.coffee
+++ src/scope-selector.coffee
@@ -24,7 +24,7 @@

   # Check if this scope selector matches the scopes.
   #
-  # scopes - An {Array} of {String}s.
+  # scopes - An {Array} of {String}s or a single {String}.
   #
   # Returns a {Boolean}.
   matches: (scopes) -> @matcher.matches(scopes)


phpdoc: use cheerio instead of jquery, to support non-GUI environments

--- src/scripts/phpdoc.coffee
+++ src/scripts/phpdoc.coffee
@@ -2,8 +2,7 @@
 #   PHP's functions reference.
 #
 # Dependencies:
-#   "jsdom": ""
-#   "jquery": ""
+#   "cheerio": ""
 #
 # Configuration:
 #   None
@@ -11,31 +10,23 @@
 # Commands:
 #   hubot phpdoc for <function> - Shows PHP function information.
 #
-# Author:
+# Authors:
 #   nebiros
-
-jsdom = require("jsdom").jsdom
+#   Carter McKendry

 module.exports = (robot) ->
   robot.respond /phpdoc for (.+)$/i, (msg) ->
     msg
       .http("http://www.php.net/manual/en/function." + msg.match[1].replace(/[_-]+/, "-") + ".php")
       .get() (err, res, body) ->
-        window = (jsdom body, null,
-          features:
-            FetchExternalResources: false
-            ProcessExternalResources: false
-            MutationEvents: false
-            QuerySelector: false
-        ).createWindow()

-        $ = require("jquery").create(window)
-        ver = $.trim $(".refnamediv p.verinfo").text()
-        desc = $.trim $(".refnamediv span.dc-title").text()
-        syn = $.trim $(".methodsynopsis").text().replace(/\s+/g, " ").replace(/(\r\n|\n|\r)/gm, " ")
+        $ = require("cheerio").load(body)
+        ver = $(".refnamediv p.verinfo").text()
+        desc = $(".refnamediv span.dc-title").text()
+        syn = $(".methodsynopsis").text().replace(/\s+/g, " ").replace(/(\r\n|\n|\r)/gm, " ")

         if ver and desc and syn
           msg.send "#{ver} - #{desc}"
           msg.send syn
         else
-          msg.send "Not found."+          msg.send "Not found."


Update atom linter config

Update atom linter config

--- .config/atom/config.cson
+++ .config/atom/config.cson
@@ -38,6 +38,8 @@
     onlyConfig: true
   "linter-jshint":
     disableWhenNoJshintrcFileInPath: true
+  "linter-ui-default":
+    showPanel: true
   "spell-check": {}
   tabs:
     enableVcsColoring: true


init draggables and enable them when activating the editor. Trigger a change event in the editor when an image is added, moved or removed.

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -173,6 +173,9 @@
             @options.toolbar.append buttonset
             @options.dialog.dialog(@options.dialogOpts)

+            # Add DragnDrop
+            @_addDragnDrop()
+
         _init: ->

         _openDialog: ->
@@ -190,9 +193,6 @@
             xposition = jQuery(@options.editable.element).offset().left + jQuery(@options.editable.element).outerWidth() - 3 # 3 is the border width of the contenteditable border
             yposition = jQuery(@options.toolbar).offset().top - jQuery(document).scrollTop() - 29
             @options.dialog.dialog("option", "position", [xposition, yposition])
-
-            # Add DragnDrop
-            @_addDragnDrop()

             # Show Dialog
             @options.dialog.dialog("open")
@@ -309,7 +309,10 @@

                 handleStopEvent: (event, ui) ->
                     internalDrop = helper.checkOrigin(event)
-                    $(event.target).remove()  if internalDrop
+                    if internalDrop
+                        $(event.target).remove()
+                    else
+                        editable.trigger('change')

                     overlay.big.hide()
                     overlay.left.hide()
@@ -318,10 +321,10 @@
                     $(document).trigger('stopPreventSave');

                 handleDropEvent: (event, ui) ->
-                    # check whether it's an internal drop or not
+                    # check whether it is an internal drop or not
                     internalDrop = helper.checkOrigin(event)
                     helper.removeTmpNodes()
-                    position = helper.calcPosition(ui, offset, internalDrop)
+                    position = helper.calcPosition(ui, offset)
                     imageInsert = helper.createInsertElement(ui, false)
                     if position is "middle"
                         imageInsert.css('display', 'block')
@@ -336,12 +339,9 @@
                     overlay.big.hide()
                     overlay.left.hide()
                     overlay.right.hide()
-                     # add draggable functionality to the image after it has been dropped
-                    imageInsert.draggable
-                        cursor: "move"
-                        helper: dnd.createHelper
-                        drag: dnd.handleDragEvent
-                        stop: dnd.handleStopEvent
+                    # Let the editor know we did a change
+                    editable.trigger('change')
+                    dnd.init(editable)

                 handleOverEvent: (event, ui) ->
                   # todo: handle with a class
@@ -370,13 +370,55 @@
                     helper.removeTmpNodes()

                 createHelper: (event) ->
-                    console.log(event.currentTarget)
                     $('<div>').css({
                         backgroundImage: "url(" + $(event.currentTarget).attr('src') + ")"
                     }).addClass('customHelper').appendTo('body');

-
+                # initialize draggable and droppable elements in the page
+                # Safe to be called multiple times
+                init: () ->
+                    draggable = []
+
+                    initDraggable = (elem) ->
+                        if not elem.jquery_draggable_initialized
+                            elem.jquery_draggable_initialized = true
+                            $(elem).draggable
+                                cursor: "move"
+                                helper: dnd.createHelper
+                                drag: dnd.handleDragEvent
+                                start: dnd.handleStartEvent
+                                stop: dnd.handleStopEvent
+                                disabled: not editable.hasClass('inEditMode')
+                        draggables.push elem
+
+                    $(".rotationWrapper img", widgetOptions.dialog).each (index, elem) ->
+                        initDraggable(elem) if not elem.jquery_draggable_initialized
+
+                    $("img", editable).each (index, elem) ->
+                        elem.contentEditable = false
+                        initDraggable(elem) if not elem.jquery_draggable_initialized
+
+                    $("p", editable).each (index, elem) ->
+                        if not elem.jquery_droppable_initialized
+                            elem.jquery_droppable_initialized = true
+                            $('p', editable).droppable
+                                tolerance: "pointer"
+                                drop: dnd.handleDropEvent
+                                over: dnd.handleOverEvent
+                                out: dnd.handleLeaveEvent
+
+                enableDragging: () ->
+                    jQuery.each draggables, (index, d) ->
+                        jQuery(d).draggable('option', 'disabled', false)
+
+                disableDragging: () ->
+                    jQuery.each draggables, (index, d) ->
+                        jQuery(d).draggable('option', 'disabled', true)
+
+            draggables = []
             editable = $(@options.editable.element)
+            # keep a reference of options for context changes
+            widgetOptions = @options
             offset = editable.offset()
             third = parseFloat(editable.width() / 3)
             overlayMiddleConfig =
@@ -391,16 +433,8 @@
                 left: $("<div/>").addClass("smallDottedOverlay smallDottedOverlayLeft").css(overlayMiddleConfig)
                 right: $("<div/>").addClass("smallDottedOverlay smallDottedOverlayRight").css(overlayMiddleConfig).css("left", third * 2)

-            $(".rotationWrapper img").draggable
-                cursor: "move"
-                helper: dnd.createHelper
-                drag: dnd.handleDragEvent
-                start: dnd.handleStartEvent
-                stop: dnd.handleStopEvent
-
-            $(@options.editable.element).children('p').droppable
-                tolerance: "pointer"
-                drop: dnd.handleDropEvent
-                over: dnd.handleOverEvent
-                out: dnd.handleLeaveEvent
+            dnd.init()
+
+            editable.bind 'halloactivated', dnd.enableDragging
+            editable.bind 'hallodeactivated', dnd.disableDragging
 )(jQuery)


KDRouter: filter xss vector

KDRouter: filter xss vector

--- core/KDRouter.coffee
+++ core/KDRouter.coffee
@@ -59,15 +59,20 @@

   @handleNotFound =(route)->
     console.trace()
-    log "The route #{route} was not found!"
+    log "The route #{ Encoder.XSSEncode route } was not found!"

   getCurrentPath:-> @currentPath

   handleNotFound:(route)->
+    message =
+      if /<|>/.test route
+      then "Invalid route!"
+      else"404 Not found! #{ Encoder.XSSEncode route }"
+
     delete @userRoute
     @clear()
     log "The route #{route} was not found!"
-    new KDNotificationView title: "404 Not found! #{route}"
+    new KDNotificationView title: message

   routeWithoutEdgeAtIndex =(route, i)->
     "/#{route.slice(0, i).concat(route.slice i + 1).join '/'}"
@@ -102,7 +107,7 @@
     _gaq?.push ['_trackPageview', path]

   handleRoute:(userRoute, options={})->
-
+    return @handleRoute '/Activity'  if /<|>/.test userRoute
     userRoute = userRoute.slice 1  if (userRoute.indexOf '!') is 0
     @visitedRoutes.push userRoute  if @visitedRoutes.last isnt userRoute


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -17,4 +17,4 @@
       I[property] = 10

-
+  tween: () ->


Added rudimentary tweening, wut!

Added rudimentary tweening, wut!

--- src/tween.coffee
+++ src/tween.coffee
@@ -22,6 +22,30 @@
         t = (I.age - data.startTime) / data.duration
         I[property] = f(t)

+  ###*
+  A convenient way to set the flicker instance variables on a sprite. You can modify the
+  instance variables by hand but the suggested way to do it is through this method.
+
+

+  player = GameObject()
+
+  player.include(Flickerable)
+
+  player.flicker()
+  # => This causes the sprite to flicker between full opacity
+  # => and 50% opacity every 3 frames for 30 frames
+
+  player.flicker(90, 5, 0.3)
+  # => This causes the sprite to flicker between full opacity
+  # => and 30% opacity every 5 frames for 90 frames
+

+
+  @name flicker
+  @methodOf Flickerable#
+  @param {Number} [duration=30] How long the effect lasts
+  @param {Number} [frequency=3] The number of frames in between opacity changes
+  @param {Number} [alpha=0.5] The alpha value to flicker to
+  ###
   tween: (duration, properties) ->
     properties = Object.extend({}, properties) # Make a local copy


Added X-Powered-By: Zappa header (#68)

Added X-Powered-By: Zappa header (#68)


strip extra spaces

strip extra spaces

--- plugin/browserify.coffee
+++ plugin/browserify.coffee
@@ -8,52 +8,52 @@

   # holds all data read from bundle
   string = ''
-
+
   # concatenate data chunk to string
   bundle.on 'data', (data) -> string += data
-
+
   # when we reach the end, call Meteor.wrapAsync's callback with string result
   bundle.once 'end', -> cb undefined, string  # undefined = error

 # TODO: how to know if it's production or dev? change value of debug...
 # TODO: inputPath may include directories we need to strip for basedir
 processFile = (step) ->
-
+
   # Meteor's CompileStep provides the file as a Buffer
   buffer = step.read()
-
+
   # Browserify accepts a Readable stream as input, so, we'll use a PassThrough
   # stream to hold the Buffer
   readable = new stream.PassThrough()
-
+
   # add the buffer into the stream and end the stream with one call to end()
   readable.end buffer
-
+
   # must tell Browserify where to find npm modules.
   # ComppileStep has the absolute path to the file in `fullInputPath`
   # CompileStep has the name of the file in `inputPath`
   # so basedir is the fullInputPath with the file removed and '.npm/package' added
   basedir = step.fullInputPath.slice(0, -(step.inputPath.length)) + '.npm/package'

-  # create a browserify instance passing our readable stream as input,
+  # create a browserify instance passing our readable stream as input,
   # and options with debug set to true for a dev build, and the basedir
   browserify = Browserify [readable], debug:true, basedir:basedir
-
+
   # have browserify process the file and include all required modules.
   # we receive a readable stream as the result
   bundle = browserify.bundle()
-
+
   # set the readable stream's encoding so we read strings from it
   bundle.setEncoding('utf8')
-
+
   # use Meteor.wrapAsyn to wrap `getString` so it's done synchronously and
   # returns the result right here when it's done
   wrappedFn = Meteor.wrapAsync getString
-
+
   # call our wrapped function with the readable stream as its argument
   string = wrappedFn bundle

-  # now that we have the compiled result as a string we can add it using CompileStep
+  # now that we have the compiled result as a string we can add it using CompileStep
   step.addJavaScript
     path:       step.inputPath  # name of the file
     sourcePath: step.inputPath  # use same name, we've just browserified it


cargo commands worker

cargo commands worker

--- lib/cargo-view.coffee
+++ lib/cargo-view.coffee
@@ -26,7 +26,7 @@
       'tokamak:clean': => @attachCargo('clean')
       'tokamak:build-run': => @attachCargo('build-run')
       'tokamak:rebuild': => @attachCargo('rebuild')
-      'tokamak:run': => @attachCargo('bin')
+      'tokamak:run': => @attachCargo('run')

     @miniEditor.on 'blur', => @close()
     atom.commands.add @element,
@@ -47,20 +47,32 @@
     @miniEditor.focus()

   attachCargo: (@cmd) ->
+    @cargoCmdRunner(@cmd, @cargoCmdExitCallback)
+
+  cargoCmdExitCallback: (@cmd, code) =>
+    console.log code
+    if code != 0
+      atom.notifications.addError("Tokamak: Cargo #{@cmd} failed!", {
+        detail: "Cargo #{@cmd} exited with #{code}"
+      })
+    else
+      atom.notifications.addSuccess("Tokamak: Cargo #{@cmd} successful!")
+
+  cargoCmdRunner: (@cmd, callback) ->
     cargoPath = atom.config.get("tokamak.cargoBinPath")
     switch @cmd
       when "build"
-          @runCommand(cargoPath, ["build"], callback)
+          @runCommand(cargoPath, ["build"], exit = (code) => callback(@cmd, code))
       when "clean"
-          @runCommand(cargoPath, ["clean"], callback)
+          @runCommand(cargoPath, ["clean"], exit = (code) => callback(@cmd, code))
       when "build-run"
-          @runCommand(cargoPath, ["build"], callback)
-          @runCommand(cargoPath, ["run"], callback)
+          @runCommand(cargoPath, ["build"], exit = (code) => callback(@cmd, code))
+          @runCommand(cargoPath, ["run"], exit = (code) => callback(@cmd, code))
       when "rebuild"
-          @runCommand(cargoPath, ["clean"], callback)
-          @runCommand(cargoPath, ["build"], callback)
+          @runCommand(cargoPath, ["clean"], exit = (code) => callback(@cmd, code))
+          @runCommand(cargoPath, ["build"], exit = (code) => callback(@cmd, code))
       when "run"
-          @runCommand(cargoPath, ["run"], callback)
+          @runCommand(cargoPath, ["run"], exit = (code) => callback(@cmd, code))
       else null

   serialize: ->
@@ -101,3 +113,6 @@

   runCommand: (command, args, exit) ->
     new BufferedProcess({command, args, exit})
+
+  runCommandStdout: (command, args, stdout, exit) ->
+    new BufferedProcess({command, args, stdout, exit})


remove unused size2 avatar settings

remove unused size2 avatar settings

--- server/startup/migrations/v8.coffee
+++ server/startup/migrations/v8.coffee
@@ -12,6 +12,4 @@
 				Settings.insert { _id: 'KADIRA_APP_SECRET', value: settings.kadira.appSecret, type: 'string', group: 'API' } if settings.kadira?.appSecret?
 				Settings.insert { _id: 'avatarStore_type', value: settings.public.avatarStore.type, type: 'string', group: 'API' } if settings.public?.avatarStore?.type?
 				Settings.insert { _id: 'avatarStore_path', value: settings.public.avatarStore.path, type: 'string', group: 'API' } if settings.public?.avatarStore?.path?
-				Settings.insert { _id: 'avatarStore_size2_height', value: settings.public.avatarStore.size2.height, type: 'string', group: 'API' } if settings.public?.avatarStore?.size2?.height?
-				Settings.insert { _id: 'avatarStore_size2_width', value: settings.public.avatarStore.size2.width, type: 'string', group: 'API' } if settings.public?.avatarStore?.size2?.width?
 				Settings.remove { _id: 'settings' }


Give tiles an opaque background

Give tiles an opaque background

--- src/tile-component.coffee
+++ src/tile-component.coffee
@@ -37,6 +37,10 @@

     @newTileState = @newState.tiles[@id]
     @oldTileState = @oldState.tiles[@id]
+
+    if @newState.backgroundColor isnt @oldState.backgroundColor
+      @domNode.style.backgroundColor = @newState.backgroundColor
+      @oldState.backgroundColor = @newState.backgroundColor

     if @newTileState.display isnt @oldTileState.display
       @domNode.style.display = @newTileState.display


syncstrings -- code to go through and compact all syncstrings

--- salvus/syncstring.coffee
+++ salvus/syncstring.coffee
@@ -46,7 +46,7 @@
 # having to apply hundreds of patches when opening a string, and saves
 # space.   (Of course, having the complete history could also be
 # interesting...)
-DB_PATCH_SQUASH_THRESH = 50
+DB_PATCH_SQUASH_THRESH = 20

 async    = require('async')
 {EventEmitter} = require('events')
@@ -294,10 +294,6 @@
         syncstring_db = new StringsDB(database)
         cb?()

-# queries the syncstring_acls table for all syncstring id’s, one by one goes through and
-# loads them and combines all the patches into a single patch.  As it goes, it also
-# record the total length of the resulting syncstring.
-exports.compact_all_syncstrings = (cb) ->   # cb(err, lengths); where lengths[string_id] = length of that string

 exports.get_syncstring_db = () ->
     return syncstring_db
@@ -381,10 +377,64 @@
                     s.live = s.last_sync # start initialized to what is in db
                     f(undefined, s)

+    # This is mostly a throw-away function for maintenance in the early low-usage days.
+    # This queries the syncstring_acls table for all syncstring id’s, one by one
+    # goes through and loads them and combines all the patches into a single patch.
+    # As it goes, it also record the total length of the resulting syncstring.
+    # x={};require('bup_server').global_client(cb:(e,c)->x.c=c; x.s = require('syncstring'); x.s.init_syncstring_db(x.c.database); x.ss=x.s.get_syncstring_db(); x.lengths={}; x.ss.compact_all_syncstrings(start:0,stop:100,lengths:x.lengths,cb:(e)->console.log("DONE",e)))
+    compact_all_syncstrings: (opts)  =>
+        opts = defaults opts,
+            start   : 0
+            stop    : 100
+            lengths : undefined
+            cb      : undefined
+
+        lengths = {}
+        v = undefined
+        async.series([
+            (cb) =>
+                ## v = ['4bd8cb98-506c-45a5-8042-5c6bd8fddff0']; cb(); return
+                winston.info("compact_all_syncstrings: querying for all string ids...")
+                @db.select
+                    table   : 'syncstring_acls'
+                    columns : ['string_id']
+                    cb      : (err, results) =>
+                        if err
+                            cb(err)
+                        else
+                            v = (x[0] for x in results)
+                            v.sort()
+                            if opts.stop?
+                                v = v.slice(opts.start, opts.stop)
+                            else if opts.start
+                                v = v.slice(opts.start)
+                            winston.info("compact_all_syncstrings: there are #{v.length} syncstrings")
+                            cb()
+            (cb) =>
+                i = opts.start
+                f = (string_id, c) =>
+                    winston.info("compact_all_syncstrings: #{i}/#{v.length-1+opts.start} - loading #{string_id}...")
+                    i += 1
+                    @get_string
+                        string_id     : string_id
+                        squash_thresh : 1  # causes it to be squashed to 1 for sure
+                        cb            : (err, s) ->
+                            if err
+                                c(err)
+                            else
+                                if opts.lengths?
+                                    opts.lengths[string_id] = s.live.length
+                                c()
+                async.mapLimit(v, 1, f, (err) => cb(err))
+            ], (err) =>
+                opts.cb?(err)
+        )
+
+
     poll_for_updates: (interval=INIT_POLL_INTERVAL) =>
         retry = (interval) =>
             next_interval = Math.max(INIT_POLL_INTERVAL, Math.min(MAX_POLL_INTERVAL, POLL_DECAY_RATIO*interval))
-            @dbg("poll_for_updates", "waiting #{next_interval}ms...")
+            @dbg("poll_for_updates", "waiting #{next_interval/1000}s...")
             setTimeout((()=>@poll_for_updates(next_interval)), interval)

         if misc.len(@strings) == 0
@@ -450,7 +500,10 @@
     _read_updates_from_db: (string_ids, age, squash_thresh, cb) =>
         if not @db?
             cb("database not initialized"); return
-        @dbg("_read_updates_from_db", misc.to_json(string_ids))
+        if string_ids.length == 1
+            @dbg("_read_updates_from_db", "querying updates for #{string_ids[0]}")
+        else
+            @dbg("_read_updates_from_db", "querying updates for #{string_ids.length} strings")
         where = {string_id:{'in':string_ids}}
         if age
             where.timestamp = {'>=' : cass.now() - age}
@@ -548,8 +601,8 @@
                 string.timestamp = 0
                 string.applied_patches = {}

-            # Apply unapplied patches in order.
-            if string.last_sync == '' and patches.length > squash_thresh
+            # Determine whether or not to squash the patches into a single patch.
+            if patches.length > squash_thresh
                 squash = true
                 squash_time = new Date() - 1.2*TIMESTAMP_OVERLAP
             else
@@ -557,6 +610,7 @@

             #@dbg("_process_updates", "squash=#{squash}; squash_time=#{squash_time}")

+            # Apply unapplied patches in order.
             i = 0
             for p in patches
                 #@dbg("_process_updates","applying unapplied patch #{misc.to_json(p.patch)}")
@@ -601,10 +655,10 @@
         opts = defaults opts,
             to_delete : required
             string_id : required
-            last_sync    : required
+            last_sync : required
             timestamp : required
             cb        : undefined
-        @dbg("_squash_patches", misc.to_json(opts))
+        @dbg("_squash_patches", "string_id=#{opts.string_id}")
         async.series([
             (cb) =>
                 # write big new patch


Update snippets for coursescript

Update snippets for coursescript

--- snippets/language-coursescript.cson
+++ snippets/language-coursescript.cson
@@ -36,11 +36,9 @@
     'prefix': 'sentf'
     'body': """
       [TYPE SentenceFragments]
-      TR_Text: $1
+      Text: $1
       Text: $2
-      Text: $3
-      Text: $4
-      Text: $5
+      TR_Text: $3
     """
   'SpotErrors':
     'prefix': 'spote'
@@ -58,7 +56,6 @@
     'prefix': 'cloze'
     'body': """
       [TYPE Cloze]
-      // The first word in {{increases/changes/reductions/estimations}} is the correct answer.
       Audio: $1
       Audio: $2
     """
@@ -72,16 +69,16 @@
   'MCQ5':
     'prefix': 'mcq5'
     'body': """
-      [TYPE MCQ5][${1:true}]
-      Audio: $2
-      Pic: $3
+      [TYPE MCQ5]
+      Audio: $1
+      Pic: $1
     """
   'MCQ5a':
     'prefix': 'mcq5a'
     'body': """
-      [TYPE MCQ5a][${1:true}]
-      Audio(question=true): $2
-      Audio(matching=true): $3
+      [TYPE MCQ5a]
+      Audio(question=true): $1
+      Audio(matching=true): $2
     """
   'Sequencing':
     'prefix': 'seq'
@@ -123,10 +120,8 @@
     'prefix': 'cnd'
     'body': """
       [TYPE C&D]
-      // {{late/early/often}}默认第一个是正确答案
       Pic: $1
       Text: $2
-      TR: $3
     """
   'MCQ6':
     'prefix': 'mcq6'


Fix kitkat's touchcancel bug

Fix kitkat's touchcancel bug

Fix kitkat's touchcancel bug

--- source/quo.gestures.rotation.coffee
+++ source/quo.gestures.rotation.coffee
@@ -39,7 +39,7 @@
         _last = {touches: data, delta: delta, rotationsCount: _num_rotations}
         _check(true)

-    end = (target, data) ->
+    cancel = end = (target, data) ->
       if _start and _last
         _check(false)
         _target = null


spec: Suppress beginFrameSubscription for now

Since the callback is called asynchronously there is no way to prevent
the callback from being called twice.

--- spec/api-browser-window-spec.coffee
+++ spec/api-browser-window-spec.coffee
@@ -304,10 +304,7 @@
         done()
       w.loadUrl url

-  describe 'beginFrameSubscription method', ->
-    # It is not very reliable on Travis CI.
-    return if process.env.TRAVIS is 'true'
-
+  xdescribe 'beginFrameSubscription method', ->
     it 'subscribes frame updates', (done) ->
       w.loadUrl "file://#{fixtures}/api/blank.html"
       w.webContents.beginFrameSubscription (data) ->


Adjusts atom config.

Adjusts atom config.

--- .atom/config.cson
+++ .atom/config.cson
@@ -1,4 +1,7 @@
 "*":
+  "atom-ctags":
+    autoBuildTagsWhenActive: true
+    cmdArgs: "--exclude=core --exclude=deploy --exclude=dist --exclude=gulp --exclude=node_modules --exclude=sql --exclude=tests --exclude=vendor"
   "atom-ide-ui":
     use:
       "atom-ide-debugger": "default"
@@ -15,6 +18,7 @@
       "whitespace"
       "welcome"
       "metrics"
+      "symbols-view"
     ]
     openEmptyEditorOnStart: false
     restorePreviousWindowsOnStart: "always"
@@ -31,8 +35,14 @@
     userId: "04f06dcc-b813-4b0f-91fc-66b568d2dcd7"
   "file-watcher":
     promptWhenChange: true
+  "go-plus":
+    panel:
+      displayMode: "closed"
   "linter-flake8":
     maxComplexity: 10
+  "linter-phpcs":
+    autoExecutableSearch: false
+  "linter-phpmd": {}
   "linter-ui-default":
     panelHeight: 235
   minimap:


WorkspaceView is extended

WorkspaceView is extended

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -20,7 +20,7 @@
   'window:decrease-font-size': -> @getModel().decreaseFontSize()
   'window:reset-font-size': -> @getModel().resetFontSize()

-# Essential: The top-level view for the entire window. An instance of this class is
+# Extended: The top-level view for the entire window. An instance of this class is
 # available via the `atom.workspaceView` global.
 #
 # It is backed by a model object, an instance of {Workspace}, which is available


Fixing error handler to call the correct proto repl method.

--- lib/graph-view.coffee
+++ lib/graph-view.coffee
@@ -66,7 +66,8 @@
               displayInRepl: false,
               resultHandler: (result)->
                 if result.error
-                  protoRepl.appendText("Failure to execute handler #{handler}: #{result.error}")
+                  console.error("Failure to execute handler #{handler}: #{result.error}")
+                  window.protoRepl.stderr("Failure to execute handler #{handler}: #{result.error}")

     # Redraws the graph
     redraw: ->


STL/ajax JSONP interface fix to emulate the 'getResponseHeader' method

--- stl/ajax/src/jsonp.coffee
+++ stl/ajax/src/jsonp.coffee
@@ -14,7 +14,7 @@
     @ajax  = ajax
     @name  = '__lovely_jsonp' + new Date().getTime()
     @param = ajax.options.jsonp
-    @param = 'callback' if typeof(@jsonp) isnt 'string'
+    @param = 'callback' if typeof(@param) isnt 'string'
     @param += "="+ @name

     @script = new Element 'script',
@@ -57,6 +57,7 @@
     @readyState = 4

     @ajax.responseJSON = data
+    @script.remove()

     @onreadystatechange()

@@ -72,4 +73,5 @@

   # XMLHttpRequest dummy methods
   setRequestHeader:   ->
+  getResponseHeader:  ->
   onreadystatechange: ->


Emulator is started after inserting cartridge.

--- src/UI.coffee
+++ src/UI.coffee
@@ -86,7 +86,8 @@
     insertCartridge = (arrayBuffer) ->
         try
             nesCoffee.insertCartridge arrayBuffer
-            nesCoffee.pressPower()
+            document.pressPower()
+            document.startEmulator() if not nesCoffee.isRunning()
         catch error
             alert error


Rename Selection.modifySelections to modifySelectedText

--- src/atom/composite-selection.coffee
+++ src/atom/composite-selection.coffee
@@ -44,16 +44,16 @@
     @lastSelection().selectToScreenPosition(position)

   selectRight: ->
-    @modifySelections (selection) -> selection.selectRight()
+    selection.selectRight() for selection in @getSelections()

   selectLeft: ->
-    @modifySelections (selection) -> selection.selectLeft()
+    selection.selectLeft() for selection in @getSelections()

   selectUp: ->
-    @modifySelections (selection) -> selection.selectUp()
+    selection.selectUp() for selection in @getSelections()

   selectDown: ->
-    @modifySelections (selection) -> selection.selectDown()
+    selection.selectDown() for selection in @getSelections()

   setBufferRange: (bufferRange) ->
     @lastSelection().setBufferRange(bufferRange)