Update panelframe for d3 version 4

Update panelframe for d3 version 4

--- src/panelframe.coffee
+++ src/panelframe.coffee
@@ -122,8 +122,8 @@
              .attr("transform", if rotate_ylab then "rotate(270,#{ylabpos_x},#{ylabpos_y})" else "")

         # scales (ignoring NA business)
-        xscale = d3.scale.linear().domain(xlim).range([xrange[0]+margin.inner, xrange[1]-margin.inner])
-        yscale = d3.scale.linear().domain(ylim).range([yrange[0]-margin.inner, yrange[1]+margin.inner])
+        xscale = d3.scaleLinear().domain(xlim).range([xrange[0]+margin.inner, xrange[1]-margin.inner])
+        yscale = d3.scaleLinear().domain(ylim).range([yrange[0]-margin.inner, yrange[1]+margin.inner])
         # scales (handling nulls)
         xscale_wnull = (val) ->
             return xNA_xpos unless val?


Use Change case to prettify

Use Change case to prettify

--- lib/save-dialog.coffee
+++ lib/save-dialog.coffee
@@ -2,6 +2,7 @@
 Project = require './project'
 projects = require './projects'
 path = require 'path'
+changeCase = require 'change-case'

 module.exports =
 class SaveDialog extends Dialog
@@ -10,8 +11,9 @@
   constructor: () ->
     firstPath = atom.project.getPaths()[0]
     title = path.basename(firstPath)
+
     if atom.config.get('project-manager.prettifyTitle')
-      title = @prettifyTitle(title)
+      title = changeCase.titleCase(title)

     super
       prompt: 'Enter name of project'
@@ -36,7 +38,3 @@
       @close()
     else
       @showError('You need to specify a name for the project')
-
-  prettifyTitle: (title) ->
-    title = title.replace(/[^\w\s]/gi, ' ')
-    title = title.charAt(0).toUpperCase() + title.slice(1)


Register Atom for file associations in Windows #6177 #4893 #6860

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -20,6 +20,7 @@
 fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'
 directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom'
 backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom'
+applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe'
 environmentKeyPath = 'HKCU\\Environment'

 # Spawn a command and invoke the callback when it completes with an error
@@ -64,6 +65,10 @@
     args.push('/f')
     spawnReg(args, callback)

+  installFileHandler = (callback) ->
+    args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""]
+    addToRegistry(args, callback)
+
   installMenu = (keyPath, arg, callback) ->
     args = [keyPath, '/ve', '/d', 'Open with Atom']
     addToRegistry args, ->
@@ -74,7 +79,8 @@

   installMenu fileKeyPath, '%1', ->
     installMenu directoryKeyPath, '%1', ->
-      installMenu(backgroundKeyPath, '%V', callback)
+      installMenu backgroundKeyPath, '%V', ->
+        installFileHandler(callback)

 isAscii = (text) ->
   index = 0
@@ -124,7 +130,8 @@

   deleteFromRegistry fileKeyPath, ->
     deleteFromRegistry directoryKeyPath, ->
-      deleteFromRegistry(backgroundKeyPath, callback)
+      deleteFromRegistry backgroundKeyPath, ->
+        deleteFromRegistry(applicationsKeyPath, callback)

 # Add atom and apm to the PATH
 #


use dangerouslySetInnerHTML so quotes aren't escaped

--- src/components/TypographyStyle.cjsx
+++ src/components/TypographyStyle.cjsx
@@ -12,4 +12,7 @@
     render: ->
       styles = createStyles(vr, options)

-      <style id="react-typography">{styles}</style>
+      <style
+        id="react-typography">
+        dangerouslySetInnerHTML={{__html: styles}}
+      />


Add atom prefix to globals

Add atom prefix to globals

--- src/window.coffee
+++ src/window.coffee
@@ -49,16 +49,16 @@

   windowEventHandler = new WindowEventHandler
   restoreDimensions()
-  config.load()
-  keymap.loadBundledKeymaps()
+  atom.config.load()
+  atom.keymap.loadBundledKeymaps()
   atom.themes.loadBaseStylesheets()
-  atom.loadPackages()
-  atom.loadThemes()
+  atom.packages.loadPackages()
+  atom.themes.load()
   deserializeEditorWindow()
-  atom.activatePackages()
-  keymap.loadUserKeymaps()
+  atom.packages.activatePackages()
+  atom.keymap.loadUserKeymaps()
   atom.requireUserInitScript()
-  ipc.sendChannel 'update-application-menu', keymap.keystrokesByCommandForSelector('body')
+  ipc.sendChannel 'update-application-menu', atom.keymap.keystrokesByCommandForSelector('body')
   $(window).on 'unload', ->
     $(document.body).hide()
     unloadEditorWindow()
@@ -69,16 +69,15 @@
 window.unloadEditorWindow = ->
   return if not project and not rootView
   windowState = atom.getWindowState()
-  windowState.set('project', project.serialize())
-  windowState.set('syntax', syntax.serialize())
-  windowState.set('rootView', rootView.serialize())
-  atom.deactivatePackages()
+  windowState.set('project', atom.project.serialize())
+  windowState.set('syntax', atom.syntax.serialize())
+  windowState.set('rootView', atom.rootView.serialize())
+  atom.packages.deactivatePackages()
   windowState.set('packageStates', atom.packages.packageStates)
   atom.saveWindowState()
-  rootView.remove()
-  project.destroy()
+  atom.rootView.remove()
+  atom.project.destroy()
   windowEventHandler?.unsubscribe()
-  lessCache?.destroy()
   window.rootView = null
   window.project = null


Reference project and rootView using atom global

--- src/window.coffee
+++ src/window.coffee
@@ -64,7 +64,7 @@
   displayWindow()

 window.unloadEditorWindow = ->
-  return if not project and not rootView
+  return if not atom.project and not atom.rootView
   windowState = atom.getWindowState()
   windowState.set('project', atom.project.serialize())
   windowState.set('syntax', atom.syntax.serialize())


force auto close brackets false for .hs and .lhs files; #972

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -1624,6 +1624,12 @@
                 evaluate_key = "Shift-Enter"
             extraKeys[evaluate_key] = (editor)   => @action_key(execute: true, advance:true, split:false)

+        # turn off autoCloseBrackets for haskell files SMC #972
+        if misc.filename_extension_notilde(filename) == "hs" || misc.filename_extension_notilde(filename) == "lhs"
+            acb = false
+        else
+            acb = opts.auto_close_brackets
+
         make_editor = (node) =>
             options =
                 firstLineNumber         : opts.first_line_number
@@ -1637,7 +1643,7 @@
                 electricChars           : opts.electric_chars
                 undoDepth               : opts.undo_depth
                 matchBrackets           : opts.match_brackets
-                autoCloseBrackets       : opts.auto_close_brackets
+                autoCloseBrackets       : acb
                 autoCloseTags           : opts.auto_close_xml_tags
                 lineWrapping            : opts.line_wrapping
                 readOnly                : opts.read_only


webapp/examples: fully qualified path to data file

--- src/smc-webapp/examples.cjsx
+++ src/smc-webapp/examples.cjsx
@@ -146,7 +146,7 @@
                 # DATA is a global variable!
                 # this file is supposed to be in webapp-lib/examples/examples.json
                 # follow "./install.py examples" to see how the makefile is called during build
-                DATA = require('examples/examples.json')
+                DATA = require('webapp-lib/examples/examples.json')
                 @init_data(DATA)
         else
             @init_data(DATA)


Replace notes ajax with jquery

Replace notes ajax with jquery

--- app/javascript/src/classes/note.coffee
+++ app/javascript/src/classes/note.coffee
@@ -371,9 +371,10 @@

   save: (e) =>
+    e.preventDefault()
+
     if notesManager.debug
       console.debug 'Note#save (id=%d)', @id
-    note = this
     for p of @fullsize
       @old[p] = @fullsize[p]
     @old.raw_body = $('edit-box-text').value
@@ -383,39 +384,39 @@
     @hideEditBox e
     @bodyHide()
     @bodyfit = false
-    params =
-      'id': @id
-      'note[x]': @old.left
-      'note[y]': @old.top
-      'note[width]': @old.width
-      'note[height]': @old.height
-      'note[body]': @old.raw_body
+    params =
+      id: @id
+      note:
+        x: @old.left
+        y: @old.top
+        width: @old.width
+        height: @old.height
+        body: @old.raw_body
+
     if @is_new
-      params['note[post_id]'] = notesManager.post_id
+      params.note.post_id = notesManager.post_id
+
     notice 'Saving note...'
-    new (Ajax.Request)('/note/update.json',
-      requestHeaders: 'X-CSRF-Token': jQuery('meta[name=csrf-token]').attr('content')
-      parameters: params
-      onComplete: (resp) ->
-        resp = resp.responseJSON
-        if resp.success
-          notice 'Note saved'
-          note = notesManager.find(resp.old_id)
-          if resp.old_id < 0
-            note.is_new = false
-            note.id = resp.new_id
-            note.elements.box.id = 'note-box-' + note.id
-            note.elements.body.id = 'note-body-' + note.id
-            note.elements.corner.id = 'note-corner-' + note.id
-          note.elements.body.innerHTML = resp.formatted_body
-          note.elements.box.setOpacity 0.5
-          note.elements.box.removeClassName 'unsaved'
-        else
-          notice 'Error: ' + resp.reason
-          note.elements.box.addClassName 'unsaved'
-        return
-)
-    e.stop()
+
+    jQuery.ajax '/note/update.json',
+      data: params
+      dataType: 'json'
+      method: 'POST'
+    .done (resp) =>
+      notice 'Note saved'
+      if resp.old_id < 0
+        @is_new = false
+        @id = resp.new_id
+        @elements.box.id = "note-box-#{@id}"
+        @elements.body.id = "note-body-#{@id}"
+        @elements.corner.id = "note-corner-#{@id}"
+      @elements.body.innerHTML = resp.formatted_body
+      @elements.box.setOpacity 0.5
+      @elements.box.removeClassName 'unsaved'
+    .fail (xhr) =>
+      notice "Error: #{xhr.responseJSON?.reason ? 'unknown error'}"
+      @elements.box.addClassName 'unsaved'
+
     return

@@ -450,31 +451,31 @@

   remove: (e) =>
+    e.preventDefault()
+
     if notesManager.debug
       console.debug 'Note#remove (id=%d)', @id
     @hideEditBox e
     @bodyHide()
-    this_note = this
+
     if @is_new
       @removeCleanup()
       notice 'Note removed'
     else
       notice 'Removing note...'
-      new (Ajax.Request)('/note/update.json',
-        requestHeaders: 'X-CSRF-Token': jQuery('meta[name=csrf-token]').attr('content')
-        parameters:
-          'id': @id
-          'note[is_active]': '0'
-        onComplete: (resp) ->
-          resp = resp.responseJSON
-          if resp.success
-            notice 'Note removed'
-            this_note.removeCleanup()
-          else
-            notice 'Error: ' + resp.reason
-          return
-)
-    e.stop()
+      jQuery.ajax '/note/update.json',
+        data:
+          id: @id
+          note:
+            is_active: 0
+        dataType: 'json'
+        method: 'POST'
+      .done =>
+        notice 'Note removed'
+        @removeCleanup()
+      .fail (xhr) =>
+        notice "Error: #{xhr.responseJSON?.reason ? 'unknown error'}"
+
     return


Remove unneeded syntax.off() call

Remove unneeded syntax.off() call

syntax.on() is no longer called anywhere in the package.

--- lib/spell-check.coffee
+++ lib/spell-check.coffee
@@ -12,6 +12,3 @@
     rootView.eachEditor (editor) ->
       if editor.attached and not editor.mini
         editor.underlayer.append(new SpellCheckView(editor))
-
-  deactivate: ->
-    syntax.off '.spell-check'


adding ability to test coverage on specific files

--- tools/coverage.coffee
+++ tools/coverage.coffee
@@ -50,25 +50,33 @@
   if unused_count > 0
     console.log "#{unused_count} #{stats_name} have yet to be tested."

-run_all_tests = (quiet) ->
+run_tests = (test_classes, quiet) ->
   # set up the classpath and get the test dir
   doppio_dir = path.resolve __dirname, '..'
-  test_dir = path.resolve doppio_dir, 'classes/test'
+  # get the tests, if necessary
+  if test_classes?.length > 0
+    test_classes = (tc.replace(/\.class$/,'') for tc in test_classes)
+  else
+    test_dir = path.resolve doppio_dir, 'classes/test'
+    test_classes = []
+    for file in fs.readdirSync(test_dir) when path.extname(file) == '.java'
+      test_classes.push "classes/test/#{path.basename(file, '.java')}"
+  # set up the claspath
   jcl_dir = path.resolve doppio_dir, 'vendor/classes'
   jvm.classpath = [doppio_dir, jcl_dir]

   # run each class, reusing the same heap and string pool and class info
   rs = new RuntimeState((->), (->), jvm.read_classfile)
-  for file in fs.readdirSync(test_dir) when path.extname(file) == '.java'
-    c = "classes/test/#{path.basename(file, '.java')}"
+  for c in test_classes
     console.log "running #{c}..." unless quiet
     jvm.run_class(rs, c, [])
   return

+
 if require.main == module
   {argv} = optimist
   optimist.usage '''
-  Usage: $0
+  Usage: $0 [class_file(s)]
   Optional flags:
     --print-usage
     -n, --natives
@@ -86,7 +94,7 @@

   op_stats = setup_opcode_stats() if do_opcodes
   native_stats = setup_native_stats() if do_natives
-  run_all_tests(argv.q? or argv.quiet?)
+  run_tests(argv._, argv.q? or argv.quiet?)

   if argv['print-usage']?
     print_usage op_stats if do_opcodes


Handle missing mcPool gracefully in spriteSheet buildMovieClip (#6196)

Prevents an issue with freezing game dev levels.

--- app/lib/surface/SegmentedSprite.coffee
+++ app/lib/surface/SegmentedSprite.coffee
@@ -124,6 +124,7 @@

   buildMovieClip: (animationName, mode, startPosition, loops) ->
     key = JSON.stringify([@spriteSheetPrefix].concat(arguments))
+    @spriteSheet.mcPool ?= {}
     @spriteSheet.mcPool[key] ?= []
     for mc in @spriteSheet.mcPool[key]
       if not mc.inUse


Fix epics sort

Fix epics sort

--- app/modules/epics/epics.service.coffee
+++ app/modules/epics/epics.service.coffee
@@ -58,14 +58,15 @@
     reorderEpic: (epic, newIndex) ->
         withoutMoved = @.epics.filter (it) => it.get('id') != epic.get('id')
         beforeDestination = withoutMoved.slice(0, newIndex)
+        previous = beforeDestination.last()

-        previous = beforeDestination.last()
-        newOrder = if !previous then 0 else epic.get('epics_order') + 1
+        newOrder = if !previous then 0 else previous.get('epics_order') + 1

         previousWithTheSameOrder = beforeDestination.filter (it) =>
             it.get('epics_order') == previous.get('epics_order')
-        setOrders = Immutable.OrderedMap previousWithTheSameOrder.map (it) =>
+        setOrders = _.fromPairs previousWithTheSameOrder.map((it) =>
             [it.get('id'), it.get('epics_order')]
+        ).toJS()

         data = {
             order: newOrder,


Fix application pool creation and log child output

--- src/pow/server.coffee
+++ src/pow/server.coffee
@@ -1,6 +1,7 @@
 http = require 'http'
-nack = require 'nack/pool'

+{createPool}         = require 'nack/pool'
+{logStream}          = require 'nack/logger'
 {BufferedReadStream} = require 'nack/buffered'

 idle = 1000 * 60 * 15
@@ -17,8 +18,18 @@
   close: ->
     @server.close()

+  createApplicationPool: (config) ->
+    pool = createPool config, size: 3, idle: idle
+
+    pool.on 'spawn', () ->
+      logStream pool.stdout
+      logStream pool.stderr
+
+    pool
+
   applicationForConfig: (config) ->
-    @applications[config] ?= nack.createPool config, size: 3, idle: idle
+    if config
+      @applications[config] ?= @createApplicationPool config

   onRequest: (req, res) ->
     reqBuf = new BufferedReadStream req
@@ -26,9 +37,9 @@
     @configuration.findPathForHost host, (path) =>
       if app = @applicationForConfig path
         app.proxyRequest reqBuf, res
-        reqBuf.flush()
       else
         @respondWithError res, "unknown host #{req.headers.host}"
+      reqBuf.flush()

   respondWithError: (res, err) ->
     res.writeHead 500, "Content-Type": "text/html"


Optimized clear function

Optimized clear function

--- backbone/clonable_view.module.coffee
+++ backbone/clonable_view.module.coffee
@@ -108,7 +108,7 @@

   clear: =>
     # Limit to only one child.
-    child = $(@$('.control-group')[0]).clone()
+    child = @$('.control-group:first').clone()
     @$el.html(child)
     # Empty the child.
     @$('.control-group').find(@subviewContainer).empty()


Escape HTML in vomnibar tab URLs

Escape HTML in vomnibar tab URLs

--- background_scripts/completion.coffee
+++ background_scripts/completion.coffee
@@ -35,7 +35,7 @@
          #{@highlightTerms(Utils.escapeHtml(@title))}

-        #{@shortenUrl(@highlightTerms(@url))}
+        #{@shortenUrl(@highlightTerms(Utils.escapeHtml(@url)))}
         #{relevancyHtml}

       """


Define properties at class-level

Define properties at class-level

--- bokehjs/src/coffee/core/has_props.coffee
+++ bokehjs/src/coffee/core/has_props.coffee
@@ -3,14 +3,58 @@
 Backbone = require "backbone"

 {logger} = require "./logging"
-mixins = require "./property_mixins"
+property_mixins = require "./property_mixins"
 refs = require "./util/refs"

 class HasProps extends Backbone.Model

+  props: {}
   mixins: []

-  props: () -> mixins.create(@mixins)
+  @define: (name_or_object, type, default_value) ->
+    if _.isString(name_or_object)
+      name = name_or_object
+      prop = if _.isUndefined(default_value) then [type] else [type, default_value]
+      object = {}
+      object[name] = prop
+    else
+      object = name_or_object
+
+    for name, prop of object
+      if this.prototype.props[name]?
+        throw new Error("attempted to redefine property '#{this.name}.#{name}'")
+
+      if this.prototype[name]?
+        # XXX: should be an error, but Backbone.Model.url must be removed first
+        console.log("attempted to redefine attribute '#{this.name}.#{name}'")
+
+      #Object.defineProperty(this.prototype, name, {
+      #  get: ()      -> this.get(name)
+      #  set: (value) -> this.set(name, value)
+      #}, {
+      #  configurable: false
+      #  enumerable: true
+      #})
+
+      props = _.clone(this.prototype.props)
+      props[name] = prop
+      this.prototype.props = props
+
+  @mixin: (names...) ->
+    @define(property_mixins.create(names))
+    mixins = this.prototype.mixins.concat(names)
+    this.prototype.mixins = mixins
+
+  @mixins: (names) -> @mixin(names...)
+
+  @override: (name, default_value) ->
+    value = this.prototype.props[name]
+    if not value?
+      throw new Error("attempted to override property '#{this.name}.#{name}' (which wasn't defined)")
+    [type, insignificant_stuff_at_this_point] = value
+    props = _.clone(this.prototype.props)
+    props[name] = [type, default_value]
+    this.prototype.props = props

   toString: () -> "#{@type}(#{@id})"


update global lock key: clientUpdateLock

--- test/config/remote/modify_data.coffee
+++ test/config/remote/modify_data.coffee
@@ -10,7 +10,7 @@

 updateGlobalLock = (isLock)->
 	_val = {
-		"_global" : isLock
+		"clientUpdateLock" : isLock
 	}
 	ZkClient.setData(GLOBAL_LOCK, new Buffer(JSON.stringify(_val)), null)


make cellAt less recursive

make cellAt less recursive

--- evolution.coffee
+++ evolution.coffee
@@ -256,10 +256,13 @@
     x = 0 unless x >= 0
     y = 0 unless y >= 0
     w = @cellWidth
-    column = @cells[ div x, w ]
-    return @cellAt( x - 1, y ) unless column
-    cell = column[ div y, w ]
-    return @cellAt( x, y - 1 ) unless cell
+    until cell
+      column = @cells[ div x, w ]
+      unless column
+        x--
+        continue
+      cell = column[ div y, w ]
+      y--
     cell
   # place a thing in the appropriate cell
   place: (thing, onlyMovingIn) ->
@@ -1159,7 +1162,7 @@
   defaultGenes: ->
     @mergeGenes super(), {
       auditoryRange: [ min( @universe.maxDistance / 3, 20 ), 10, @universe.maxDistance / 2 ]
-      visualAngle: [ .45, .1, .8 ]
+      visualAngle: [ .45, .1, .7 ]
       visualRange: [ min( @universe.maxDistance / 2 , 30 ), 20, @universe.maxDistance ]
       g: [ 250, 1, 5000 ]
       jitter: [ .05, 0.01, 1 ]


reinstate inline image loading

reinstate inline image loading

--- src/ui/views/messages.coffee
+++ src/ui/views/messages.coffee
@@ -104,7 +104,9 @@
                                 mclz = ['message']
                                 mclz.push 'placeholder' if e.placeholder
                                 div id:e.event_id, key:e.event_id, class:mclz.join(' '), ->
-                                    format e.chat_message?.message_content
+                                    content = e.chat_message?.message_content
+                                    format content
+                                    loadInlineImages content
     if lastConv != conv_id
         lastConv = conv_id
         later atTopIfSmall
@@ -132,7 +134,7 @@
 ifpass = (t, f) -> if t then f else pass

 format = (cont) ->
-    if cont?.attachment?.length
+    if cont?.attachment?
         try
           formatAttachment cont.attachment
         catch e
@@ -142,12 +144,23 @@
         continue unless seg.text
         f = seg.formatting ? {}
         href = seg?.link_data?.link_target
-        ifpass(href, ((f) -> a {href, onclick}, f)) ->
-            ifpass(f.bold, b) ->
-                ifpass(f.italics, i) ->
-                    ifpass(f.underline, u) ->
-                        ifpass(f.strikethrough, s) ->
-                            pass seg.text
+        # these are inline links to images that we try loading
+        # as images and show. (not attachments)
+        imgel = seg?.link_data?.imgel # can be set by loadImages below
+        # if we have such image element, we wrap the segment in a div
+        # to get a new line.
+        ifpass(imgel?.loaded, div) ->
+            ifpass(href, ((f) -> a {href, onclick}, f)) ->
+                ifpass(f.bold, b) ->
+                    ifpass(f.italics, i) ->
+                        ifpass(f.underline, u) ->
+                            ifpass(f.strikethrough, s) ->
+                                if imgel?.loaded
+                                    # when we detect an inline image link
+                                    img src:href
+                                else
+                                    # otherwise show text
+                                    pass seg.text
     null

@@ -158,7 +171,8 @@
         else if att?[0]?.embed_item?.type
             {href, thumb} = extractObjectStyle(att)
         else
-            return console.warn 'ignoring attribute', att
+            console.warn 'ignoring attachment', att unless att?.length == 0
+            return
         return unless href
         preload att, href

@@ -212,14 +226,10 @@
         console.warn 'ignoring (new) type', type

-isImg = (url) -> url?.match /\.(png|jpg|gif|svg)$/i
-
-loadImages = (conv_id, cont) ->
+# these are images that are single segments that we detect as being
+# images (not attachments).
+loadInlineImages = (cont) ->
     for seg, i in cont?.segment ? []
         href = seg?.link_data?.link_target
-        if isImg(href) and !seg.link_data.img
-            seg.link_data.img = imgel = document.createElement 'img'
-            imgel.src = href
-            imgel.onload = (ev) ->
-                return unless typeof img.naturalWidth == 'number'
-                action 'imgload', conv_id
+        if isImg(href) and !seg.link_data.imgel
+            preload seg.link_data, href


removes google specific queries as well

removes google specific queries as well

--- src/ui/views/messages.coffee
+++ src/ui/views/messages.coffee
@@ -28,10 +28,9 @@
 onclick = (e) ->
   e.preventDefault()
   address = e.currentTarget.getAttribute 'href'
-  alert address
-  patt = new RegExp("^http(s)?[:][/][/]www[.]google[.](com|[a-z][a-z])[/]url[?]q[=]")
+  patt = new RegExp("^(https?[:][/][/]www[.]google[.](com|[a-z][a-z])[/]url[?]q[=])([^&]+)(&.+)*")
   if patt.test(address)
-    address = address.replace(patt, '')
+    address = address.replace(patt, '$3')
     address = unescape(address)
   shell.openExternal fixlink(address)


Fix assets on html file by prefixing '/'

--- lib/app.init.coffee
+++ lib/app.init.coffee
@@ -62,6 +62,20 @@
   for code in $revealSlidesContainer.find('pre')
     $(code).html($("<code>").html($(code).html()))

+
+fixAssetsPath = () ->
+  fixPath = (attr_name) ->
+    () ->
+      $el = $(@)
+      if $el.attr(attr_name)?.substring(0,1) != "/"
+        $el.attr(attr_name, "/#{$el.attr(attr_name)}")
+      null
+
+  $("img").each(fixPath("src"))
+  $("script").each(fixPath("src"))
+  $("link").each(fixPath("href"))
+  null
+
 ################################################################################
 setStylesheet = (mode) ->
   $("style").remove()
@@ -98,6 +112,7 @@
 exports.init = ()->
   initialCleanupAndTransform()
   setPresentationMode(MODES.AUDIENCE)
+  fixAssetsPath()
   $("body").bind("touchstart", (ev) -> ev.preventDefault())
   Reveal.initialize(
     keyboard: false,


Remove commented code.

Remove commented code.

--- lib/auto-indent.coffee
+++ lib/auto-indent.coffee
@@ -74,7 +74,6 @@

   # command option to format line from a cursor position upwards to JSX start
   autoIndentJsxCommand: () ->
-    #return if atom.workspace.getActiveTextEditor().id isnt @editor.id
     cursorPosition = @editor.getCursorBufferPosition()
     bufferRow = cursorPosition.row
     return if not @jsxInScope(bufferRow)


cosmetics

cosmetics

--- app/routes/router.coffee
+++ app/routes/router.coffee
@@ -154,7 +154,6 @@
   error =
     status: err.statusCode
     message: err.statusText
-
   res.json error

 validate = (req,res, schema) ->


Add overview comments

Add overview comments

--- src/rocketchat.coffee
+++ src/rocketchat.coffee
@@ -1,5 +1,10 @@
-# add documentation here too
-# add something here
+# Hubot adapter for Rocket.Chat
+# For configuration and deployment details, see https://github.com/RocketChat/hubot-rocketchat/blob/master/README.md
+#
+# The RocketChatBotAdapter class implements 'standard' hubot Adapter interface methods.
+#
+# Most of the Rocket.Chat specific code, tied to Rocket.Chat's real-time messaging APIs, are isolated in
+# a seperate RocketChatDriver class.

 try
 		{Robot,Adapter,TextMessage, EnterMessage, User, Response} = require 'hubot'