Converted editor to commonjs style

Converted editor to commonjs style

--- src/js/app/editor.coffee
+++ src/js/app/editor.coffee
@@ -1,551 +1,550 @@
-define [
-  "ejquery"
-  "vendor/prelude/prelude-browser-min"
-  "vendor/codemirror/codemirror"
-  "app/UniqueTimeLine"
-  "app/Commands"
-  "app/History"
-  "vendor/jsDump"
-], ($, Prelude, CodeMirror, TimeLine, Commands, History, jsDump) ->
-  console.log "Loaded sourceArea"
-  Prelude.installPrelude window
-  sourceFragment = "try:"
-  compiledJS = ""
-  compiler = null
-  compilerOptions = null
-  sourceCompiled = false
-  autoCompile = true
-  lastHit = 0
-  lastErrorType = ""
-  currentMode = ""
-  AUTOSAVE_DELAY = 6000
-  LAST_CODE = "lastEditedSourceCodeCOOKIE"
-  UNNAMED_CODE = "@unnamed"
-  TIMELINE_COOKIE = "timelineCOOKIE"
-  sourceChanged = false
-  saveName = UNNAMED_CODE
-  cookieFilePrefix = "TeaTableFile_"
-  timeline = new TimeLine
-
-  addMessage = (text, id) ->
-    tag = if id?
-      " data-id=#{id}"
+$ = require 'ejquery'
+Prelude = require 'vendor/prelude/prelude-browser-min'
+CodeMirror = require 'vendor/codemirror/codemirror'
+TimeLine = require 'app/UniqueTimeLine'
+Commands = require 'app/Commands'
+History = require 'app/History'
+jsDump = require 'vendor/jsDump'
+
+console.log "Loaded sourceArea"
+Prelude.installPrelude window
+sourceFragment = "try:"
+compiledJS = ""
+compiler = null
+compilerOptions = null
+sourceCompiled = false
+autoCompile = true
+lastHit = 0
+lastErrorType = ""
+currentMode = ""
+AUTOSAVE_DELAY = 6000
+LAST_CODE = "lastEditedSourceCodeCOOKIE"
+UNNAMED_CODE = "@unnamed"
+TIMELINE_COOKIE = "timelineCOOKIE"
+sourceChanged = false
+saveName = UNNAMED_CODE
+cookieFilePrefix = "TeaTableFile_"
+timeline = new TimeLine
+
+addMessage = (text, id) ->
+  tag = if id?
+    " data-id=#{id}"
+  else
+    ""
+  newMessage = $("
#{text}
")
+  $("#output").prepend newMessage
+  setMaxPreWidth newMessage
+
+eraseMessages = (except...) ->
+  excepts = join ", ", except
+  $("#output").children().not ->
+    $(this).find(excepts).size() > 0
+  .remove()
+
+getMessage = (n) ->
+  $("#output pre").eq n
+
+getCurrentMessage = ->
+  getMessage 0
+
+setCurrentMessage = (text, id) ->
+  getCurrentMessage().text(text).data "id", id
+
+isCurrentMessage = (id) ->
+  getCurrentMessage().data("id") is id
+
+log = (input...) ->
+  input = for i in input
+    jsDump.parse i ? "Nothing"
+  message = input.join ", "
+  if message.length > 0
+    addMessage lastMessage = message
+
+showImportantMessage = (type, message) ->
+  $("#messages").attr "class", type
+  $("#messages pre").text message
+  $("#messages").stop(true, true).fadeIn 200
+
+showErrorMessage = (type, message) ->
+  lastErrorType = type
+  showImportantMessage "errorMessage", message
+
+showFileMessage = (message) ->
+  showImportantMessage "fileMessage", message
+
+currentMessage = ->
+  $("#messages pre").text()
+
+hideError = (types...) ->
+  if lastErrorType in types
+    $("#messages").fadeOut 700
+
+# TODO: get rid of the duplication between dump and run
+dump = ->
+  compileCode() unless sourceCompiled
+  if compiledJS
+    log compiledJS
+  else
+    showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
+
+run = ->
+  compileCode() unless sourceCompiled
+  if compiledJS
+    execute compiledJS
+  else
+    showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
+
+# TODO: create help out of the command definitions, make them pluggable instead of defined here
+commands = Commands.initialize [
+  "dump", "d", -> dump()
+  "run", "r", -> run()
+  "erase", "e", -> eraseMessages arguments...
+  "copy", "c", -> selectLastOutput()
+  "link", "l", -> saveToAdress()
+  "toggle", "t", -> toggleAutoCompilation()
+  "save", -> switchCurrentCode arguments...
+  "load", -> loadFromClient arguments...
+  "close", -> exitCurrentCode()
+  "delete", -> removeFromClient arguments...
+  "modes", "m", -> displayModes()
+  "mode", -> setMode arguments...
+  "canvas", -> createCanvas arguments...
+  "browse", "b", -> displayClient()
+  "help", "h", -> log(helpDescription)
+  "ph", -> history.print(log)
+]
+
+compileAndRun = ->
+  # TODO use prelude trim
+  source = $.trim commandArea.getValue()
+  return if source.length is 0
+
+  timeline.push source
+  hideError "command", "runtime"
+  try
+    if pref = source.match(/^(< |:)/)
+      source = source[pref[0].length..]
+      for command in commands
+        match = command.match source
+        break if match?
+      saveTimeline()
+      outputScrollTop()
     else
-      ""
-    newMessage = $("
#{text}
")
-    $("#output").prepend newMessage
-    setMaxPreWidth newMessage
-
-  eraseMessages = (except...) ->
-    excepts = join ", ", except
-    $("#output").children().not ->
-      $(this).find(excepts).size() > 0
-    .remove()
-
-  getMessage = (n) ->
-    $("#output pre").eq n
-
-  getCurrentMessage = ->
-    getMessage 0
-
-  setCurrentMessage = (text, id) ->
-    getCurrentMessage().text(text).data "id", id
-
-  isCurrentMessage = (id) ->
-    getCurrentMessage().data("id") is id
-
-  log = (input...) ->
-    input = for i in input
-      jsDump.parse i ? "Nothing"
-    message = input.join ", "
-    if message.length > 0
-      addMessage lastMessage = message
-
-  showImportantMessage = (type, message) ->
-    $("#messages").attr "class", type
-    $("#messages pre").text message
-    $("#messages").stop(true, true).fadeIn 200
-
-  showErrorMessage = (type, message) ->
-    lastErrorType = type
-    showImportantMessage "errorMessage", message
-
-  showFileMessage = (message) ->
-    showImportantMessage "fileMessage", message
-
-  currentMessage = ->
-    $("#messages pre").text()
-
-  hideError = (types...) ->
-    if lastErrorType in types
-      $("#messages").fadeOut 700
-
-  # TODO: get rid of the duplication between dump and run
-  dump = ->
-    compileCode() unless sourceCompiled
-    if compiledJS
-      log compiledJS
-    else
-      showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
-
-  run = ->
-    compileCode() unless sourceCompiled
-    if compiledJS
-      execute compiledJS
-    else
-      showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
-
-  # TODO: create help out of the command definitions, make them pluggable instead of defined here
-  commands = Commands.initialize [
-    "dump", "d", -> dump()
-    "run", "r", -> run()
-    "erase", "e", -> eraseMessages arguments...
-    "copy", "c", -> selectLastOutput()
-    "link", "l", -> saveToAdress()
-    "toggle", "t", -> toggleAutoCompilation()
-    "save", -> switchCurrentCode arguments...
-    "load", -> loadFromClient arguments...
-    "close", -> exitCurrentCode()
-    "delete", -> removeFromClient arguments...
-    "modes", "m", -> displayModes()
-    "mode", -> setMode arguments...
-    "canvas", -> createCanvas arguments...
-    "browse", "b", -> displayClient()
-    "help", "h", -> log(helpDescription)
-    "ph", -> history.print(log)
-  ]
-
-  compileAndRun = ->
-    # TODO use prelude trim
-    source = $.trim commandArea.getValue()
-    return if source.length is 0
-
-    timeline.push source
-    hideError "command", "runtime"
-    try
-      if pref = source.match(/^(< |:)/)
-        source = source[pref[0].length..]
-        for command in commands
-          match = command.match source
-          break if match?
+      command = compiler.compile source, getCompilerOptions()
+      try
+        log execute compiledJS + command
         saveTimeline()
         outputScrollTop()
+      catch error
+        showErrorMessage "runtime", "Runtime: #{error}"
+  catch error
+    console.log error
+    showErrorMessage "command", "Command Line: #{error.message}"
+  return
+
+modes =
+  CoffeeScript:
+    id: "coffeescript"
+    options:
+      bare: true
+
+  IcedCoffeeScript:
+    id: "icedcoffeescript"
+    options:
+      bare: true
+
+  Ometa:
+    id: "ometa"
+
+  MetaCoffee:
+    id: "metacoffee"
+
+modesList = ->
+  join "\n", map keys(modes), (mode) ->
+    "#{if mode is currentMode then "> " else "  "}#{mode}"
+
+displayModes = ->
+  addMessage modesList(), "modesList"
+
+setNewMode = (name, callback) ->
+  if name isnt currentMode
+    setMode name, callback
+  else
+    callback?()
+
+setMode = (name, callback) ->
+  mode = modes[name]
+  if mode?
+    id = mode.id
+    require [
+      "vendor/compilers/" + id + "/compiler"
+      "vendor/compilers/" + id + "/highlighter"
+    ], (compilerClass, highlighter) ->
+      compiler = compilerClass
+      compilerOptions = mode.options
+      sourceArea.setOption "mode", id
+      commandArea.setOption "mode", id
+      mode.init?()
+      currentMode = name
+      if isCurrentMessage "modesList"
+        setCurrentMessage modesList(), "modesList"
       else
-        command = compiler.compile source, getCompilerOptions()
-        try
-          log execute compiledJS + command
-          saveTimeline()
-          outputScrollTop()
-        catch error
-          showErrorMessage "runtime", "Runtime: #{error}"
-    catch error
-      console.log error
-      showErrorMessage "command", "Command Line: #{error.message}"
+        log "#{name} compiler loaded"
+      compileCode()
+      callback?()
+    , (error) ->
+      log "#{name} loading failed"
+  else
+    log "Wrong mode name, choose from:\n\n#{modesList()}"
+
+createCanvas = (width, height) ->
+  log "#canvas\n<canvas id='canvas' width=#{width} height=#{height}></canvas>"
+
+toggleAutoCompilation = ->
+  autoCompile = not autoCompile
+  log "Autocompilation switched #{if autoCompile then 'on' else 'off'}"
+
+getCompilerOptions = ->
+  # TODO: use prelude
+  $.extend {}, compilerOptions
+
+compileCode = ->
+  startColor = "#151515"
+  endColor = "#ccc"
+  normalColor = "#050505"
+  indicator = $ "#compilationIndicator"
+  indicateBy = (color) ->
+    indicator.animate
+      color: color
+    ,
+      complete: ->
+        indicator.css color: color
+
+  compileSource ->
+    indicateBy startColor
+  , ->
+    indicateBy endColor
+    indicateBy normalColor
+
+compileSource = (start, finish) ->
+  start()
+  source = sourceArea.getValue()
+  compiledJS = ""
+  saveCurrent()
+  try
+    compiledJS = compiler.compile source, getCompilerOptions()
+    hideError "compiler", "runtime"
+  catch error
+    showErrorMessage "compiler", "Compiler: #{error.message ? error}"
+  sourceCompiled = true
+  finish()
+  $("#repl_permalink").attr "href", "##{sourceFragment}#{encodeURIComponent(source)}"
+
+execute = (code) ->
+  eval (compiler.preExecute? code) ? code
+
+history = new History
+sourceChange = (inst, e) ->
+  sourceCompiled = false
+  sourceChanged = true
+  history.add e
+  return unless autoCompile
+  DELAY = 700
+  lastHit = +new Date
+  setTimeout ->
+    if +new Date() - lastHit > DELAY
+      compileCode() unless sourceCompiled
+  , 2 * DELAY
+
+# TODO: this is not used, it is connected to History
+printHistory = ->
+  insert = undefined
+  point = undefined
+  text = undefined
+  _i = undefined
+  _len = undefined
+  _results = undefined
+  text = [""]
+  insert = (from, to, what) ->
+    appended = undefined
+    curr = undefined
+    newLines = undefined
+    oldLines = undefined
+    singleLine = undefined
+    singleLine = from.line is to.line
+    if singleLine
+      curr = text[from.line]
+      text[from.line] = curr.slice(0, from.ch) + what[0] + curr.slice(to.ch)
+    else
+      text[from.line] = text[from.line].slice(0, from.ch) + what[0]
+      text[to.line] = what[what.length - 1] + text[to.line].slice(to.ch)
+    newLines = what.length
+    oldLines = 1 + to.line - from.line
+    if newLines > 2 or oldLines > 2
+      appended = (if singleLine then what.slice(1) else what.slice(1, -1))
+      text.splice.apply text, [
+        from.line + 1
+        Math.max(0, oldLines - newLines)
+      ].concat(__slice_.call(appended))
+
+  _results = []
+  _i = 0
+  _len = history.length
+
+  while _i < _len
+    point = history[_i]
+    insert point.from, point.to, point.text
+    _results.push log(text)
+    _i++
+  _results
+
+BROWSE_COOKIE = "table"
+autosave = ->
+  setTimeout ->
+    if sourceChanged
+      saveCurrent()
+      sourceChanged = false
+    autosave()
+  , AUTOSAVE_DELAY
+
+fileCookie = (name, value) ->
+  $.totalStorage cookieFilePrefix + name, value
+
+saveCurrent = ->
+  exists = undefined
+  source = undefined
+  value = undefined
+  valueLines = undefined
+  source = sourceArea.getValue()
+  value =
+    source: source
+    mode: currentMode
+
+  valueLines = (source.split "\n").length
+  exists = false
+
+  ammendClientTable saveName, "#{saveName},#{valueLines}"
+  fileCookie saveName, value
+  $.totalStorage LAST_CODE, saveName
+
+saveTimeline = ->
+  $.totalStorage TIMELINE_COOKIE, timeline.newest(200)
+
+loadTimeline = ->
+  timeline.from ($.totalStorage TIMELINE_COOKIE) ? []
+
+removeFromClient = (name) ->
+  return unless name?
+  fileCookie saveName, null
+  ammendClientTable name
+  showFileMessage "" + name + " deleted"
+
+ammendClientTable = (exclude, addition) ->
+  addition = null unless addition?
+  table = []
+  oldTable = $.totalStorage BROWSE_COOKIE
+  if oldTable?
+    for pair in oldTable.split ";"
+      [name, lines] = pair
+      table.push pair if name isnt exclude
+
+  table.push addition if addition
+  table = table.join ";"
+  table = null if table.length is 0
+  $.totalStorage BROWSE_COOKIE, table
+
+loadFromClient = (name) ->
+  name = $.totalStorage(LAST_CODE) unless name?
+  unless name?
+    setMode "IcedCoffeeScript" unless compiler?
     return
-
-  modes =
-    CoffeeScript:
-      id: "coffeescript"
-      options:
-        bare: true
-
-    IcedCoffeeScript:
-      id: "icedcoffeescript"
-      options:
-        bare: true
-
-    Ometa:
-      id: "ometa"
-
-    MetaCoffee:
-      id: "metacoffee"
-
-  modesList = ->
-    join "\n", map keys(modes), (mode) ->
-      "#{if mode is currentMode then "> " else "  "}#{mode}"
-
-  displayModes = ->
-    addMessage modesList(), "modesList"
-
-  setNewMode = (name, callback) ->
-    if name isnt currentMode
-      setMode name, callback
-    else
-      callback?()
-
-  setMode = (name, callback) ->
-    mode = modes[name]
-    if mode?
-      id = mode.id
-      require [
-        "vendor/compilers/" + id + "/compiler"
-        "vendor/compilers/" + id + "/highlighter"
-      ], (compilerClass, highlighter) ->
-        compiler = compilerClass
-        compilerOptions = mode.options
-        sourceArea.setOption "mode", id
-        commandArea.setOption "mode", id
-        mode.init?()
-        currentMode = name
-        if isCurrentMessage "modesList"
-          setCurrentMessage modesList(), "modesList"
-        else
-          log "#{name} compiler loaded"
-        compileCode()
-        callback?()
-      , (error) ->
-        log "#{name} loading failed"
-    else
-      log "Wrong mode name, choose from:\n\n#{modesList()}"
-
-  createCanvas = (width, height) ->
-    log "#canvas\n<canvas id='canvas' width=#{width} height=#{height}></canvas>"
-
-  toggleAutoCompilation = ->
-    autoCompile = not autoCompile
-    log "Autocompilation switched #{if autoCompile then 'on' else 'off'}"
-
-  getCompilerOptions = ->
-    # TODO: use prelude
-    $.extend {}, compilerOptions
-
-  compileCode = ->
-    startColor = "#151515"
-    endColor = "#ccc"
-    normalColor = "#050505"
-    indicator = $ "#compilationIndicator"
-    indicateBy = (color) ->
-      indicator.animate
-        color: color
-      ,
-        complete: ->
-          indicator.css color: color
-
-    compileSource ->
-      indicateBy startColor
-    , ->
-      indicateBy endColor
-      indicateBy normalColor
-
-  compileSource = (start, finish) ->
-    start()
-    source = sourceArea.getValue()
-    compiledJS = ""
-    saveCurrent()
-    try
-      compiledJS = compiler.compile source, getCompilerOptions()
-      hideError "compiler", "runtime"
-    catch error
-      showErrorMessage "compiler", "Compiler: #{error.message ? error}"
-    sourceCompiled = true
-    finish()
-    $("#repl_permalink").attr "href", "##{sourceFragment}#{encodeURIComponent(source)}"
-
-  execute = (code) ->
-    eval (compiler.preExecute? code) ? code
-
-  history = new History
-  sourceChange = (inst, e) ->
-    sourceCompiled = false
-    sourceChanged = true
-    history.add e
-    return unless autoCompile
-    DELAY = 700
-    lastHit = +new Date
-    setTimeout ->
-      if +new Date() - lastHit > DELAY
-        compileCode() unless sourceCompiled
-    , 2 * DELAY
-
-  # TODO: this is not used, it is connected to History
-  printHistory = ->
-    insert = undefined
-    point = undefined
-    text = undefined
-    _i = undefined
-    _len = undefined
-    _results = undefined
-    text = [""]
-    insert = (from, to, what) ->
-      appended = undefined
-      curr = undefined
-      newLines = undefined
-      oldLines = undefined
-      singleLine = undefined
-      singleLine = from.line is to.line
-      if singleLine
-        curr = text[from.line]
-        text[from.line] = curr.slice(0, from.ch) + what[0] + curr.slice(to.ch)
+  stored = fileCookie(name)
+  if stored?
+    saveName = name
+    source = stored.source
+    mode = stored.mode
+
+    sourceArea.setValue source
+    setNewMode mode, ->
+      showFileMessage "" + saveName + " loaded"  if saveName isnt UNNAMED_CODE
+
+  else
+    showFileMessage "There is no " + name  if name isnt UNNAMED_CODE
+
+exitCurrentCode = ->
+  saveCurrent()
+  saveName = UNNAMED_CODE
+  sourceArea.setValue ""
+  saveCurrent()
+
+switchCurrentCode = (name) ->
+  saveCurrent()
+  saveName = name
+  saveCurrent()
+  showFileMessage "Working on " + saveName
+
+displayClient = ->
+  table = $.totalStorage(BROWSE_COOKIE)
+  output = ""
+  if table?.length > 0
+    for snippet in table.split ";"
+      [name, lines] = snippet.split ","
+      output += "#{name}, lines: #{lines}\n" if name isnt UNNAMED_CODE
+  if output is ""
+    log "No files saved"
+  else
+    log output
+
+CodeMirror.keyMap.commandLine =
+  Up: "doNothing"
+  Down: "doNothing"
+  PageUp: "doNothing"
+  PageDown: "doNothing"
+  Enter: "doNothing"
+  fallthrough: "default"
+
+CodeMirror.commands.doNothing = (cm) ->
+  true
+
+outputScrollTop = ->
+  $("#rightColumn").animate
+    scrollTop: 0
+  , $("#rightColumn").scrollTop() / 10
+
+commandAreaKeyEvent = (inst, e) ->
+  shouldStop = undefined
+  if e.type is "keyup"
+    shouldStop = true
+    switch CodeMirror.keyNames[e.keyCode]
+      when "Enter"
+        compileAndRun()
+        commandArea.setValue ""
+      when "Up"
+        timeline.temp commandArea.getValue() unless timeline.isInPast()
+        commandArea.setValue timeline.goBack()
+      when "Down"
+        commandArea.setValue timeline.goForward() if timeline.isInPast()
+      when "Esc"
+        sourceArea.focus()
       else
-        text[from.line] = text[from.line].slice(0, from.ch) + what[0]
-        text[to.line] = what[what.length - 1] + text[to.line].slice(to.ch)
-      newLines = what.length
-      oldLines = 1 + to.line - from.line
-      if newLines > 2 or oldLines > 2
-        appended = (if singleLine then what.slice(1) else what.slice(1, -1))
-        text.splice.apply text, [
-          from.line + 1
-          Math.max(0, oldLines - newLines)
-        ].concat(__slice_.call(appended))
-
-    _results = []
-    _i = 0
-    _len = history.length
-
-    while _i < _len
-      point = history[_i]
-      insert point.from, point.to, point.text
-      _results.push log(text)
-      _i++
-    _results
-
-  BROWSE_COOKIE = "table"
-  autosave = ->
-    setTimeout ->
-      if sourceChanged
-        saveCurrent()
-        sourceChanged = false
-      autosave()
-    , AUTOSAVE_DELAY
-
-  fileCookie = (name, value) ->
-    $.totalStorage cookieFilePrefix + name, value
-
-  saveCurrent = ->
-    exists = undefined
-    source = undefined
-    value = undefined
-    valueLines = undefined
-    source = sourceArea.getValue()
-    value =
-      source: source
-      mode: currentMode
-
-    valueLines = (source.split "\n").length
-    exists = false
-
-    ammendClientTable saveName, "#{saveName},#{valueLines}"
-    fileCookie saveName, value
-    $.totalStorage LAST_CODE, saveName
-
-  saveTimeline = ->
-    $.totalStorage TIMELINE_COOKIE, timeline.newest(200)
-
-  loadTimeline = ->
-    timeline.from ($.totalStorage TIMELINE_COOKIE) ? []
-
-  removeFromClient = (name) ->
-    return unless name?
-    fileCookie saveName, null
-    ammendClientTable name
-    showFileMessage "" + name + " deleted"
-
-  ammendClientTable = (exclude, addition) ->
-    addition = null unless addition?
-    table = []
-    oldTable = $.totalStorage BROWSE_COOKIE
-    if oldTable?
-      for pair in oldTable.split ";"
-        [name, lines] = pair
-        table.push pair if name isnt exclude
-
-    table.push addition if addition
-    table = table.join ";"
-    table = null if table.length is 0
-    $.totalStorage BROWSE_COOKIE, table
-
-  loadFromClient = (name) ->
-    name = $.totalStorage(LAST_CODE) unless name?
-    unless name?
-      setMode "IcedCoffeeScript" unless compiler?
-      return
-    stored = fileCookie(name)
-    if stored?
-      saveName = name
-      source = stored.source
-      mode = stored.mode
-
-      sourceArea.setValue source
-      setNewMode mode, ->
-        showFileMessage "" + saveName + " loaded"  if saveName isnt UNNAMED_CODE
-
-    else
-      showFileMessage "There is no " + name  if name isnt UNNAMED_CODE
-
-  exitCurrentCode = ->
-    saveCurrent()
-    saveName = UNNAMED_CODE
-    sourceArea.setValue ""
-    saveCurrent()
-
-  switchCurrentCode = (name) ->
-    saveCurrent()
-    saveName = name
-    saveCurrent()
-    showFileMessage "Working on " + saveName
-
-  displayClient = ->
-    table = $.totalStorage(BROWSE_COOKIE)
-    output = ""
-    if table?.length > 0
-      for snippet in table.split ";"
-        [name, lines] = snippet.split ","
-        output += "#{name}, lines: #{lines}\n" if name isnt UNNAMED_CODE
-    if output is ""
-      log "No files saved"
-    else
-      log output
-
-  CodeMirror.keyMap.commandLine =
-    Up: "doNothing"
-    Down: "doNothing"
-    PageUp: "doNothing"
-    PageDown: "doNothing"
-    Enter: "doNothing"
-    fallthrough: "default"
-
-  CodeMirror.commands.doNothing = (cm) ->
-    true
-
-  outputScrollTop = ->
-    $("#rightColumn").animate
-      scrollTop: 0
-    , $("#rightColumn").scrollTop() / 10
-
-  commandAreaKeyEvent = (inst, e) ->
-    shouldStop = undefined
-    if e.type is "keyup"
-      shouldStop = true
-      switch CodeMirror.keyNames[e.keyCode]
-        when "Enter"
-          compileAndRun()
-          commandArea.setValue ""
-        when "Up"
-          timeline.temp commandArea.getValue() unless timeline.isInPast()
-          commandArea.setValue timeline.goBack()
-        when "Down"
-          commandArea.setValue timeline.goForward() if timeline.isInPast()
-        when "Esc"
-          sourceArea.focus()
-        else
-          shouldStop = false
-      if shouldStop
-        e.stop()
-
-  defaultEditor = ->
-    winSize =
-      w: $(window).width()
-      h: $(window).height()
-
-    column = floor winSize.w / 2
-    $("#leftColumn").width column - 30
-    resizeEditor()
-
-  resizeEditor = (e) ->
-    winSize =
-      w: $(window).width()
-      h: $(window).height()
-
-    $("#centerBar").height winSize.h - 20
-    $("#sourceWrap .CodeMirror-scroll").css "max-height", (winSize.h - 175) + "px"
-    $("#rightColumn").width winSize.w - $("#leftColumn").width() - 60
-    $("#rightColumn").css "max-height", (winSize.h - 25) + "px"
-    setMaxPreWidth $("#output pre")
-
-  selectLastOutput = ->
-    (getMessage(0)).selectText()
-
-  setMaxPreWidth = ($pre) ->
-    $pre.css "max-width", ($("#rightColumn").width() - 45) + "px"
-
-  loadWith = (coffee) ->
-    sourceArea.setValue sourceArea.getValue() + coffee
-
-  saveToAdress = ->
-    source = sourceArea.getValue()
-    window.location = "#" + sourceFragment + (encodeURIComponent(source))
-
-  # TODO: an easy way to distinguish code from other text in logs
-  helpDescription = """
-    Issue commands by typing \"< \" or \":\"
-    followed by space separated commands:
-
-    erase / e      - Clear all results
-    erase <not...> - Don't clear results containing givens
-    dump / d       - Dump generated javascript
-    run / r        - Run just the source code
-    copy / c       - Select last output (right-click to copy)
-    toggle / t     - Toggle autocompilation
-    link / l       - Create a link with current source code
-    mode <name>    - Switch to a different compiler
-    modes / m      - Show all available modes
-    canvas <w> <h> - Create a canvas given width and height
-    save <name>    - Save current code locally under name
-    load <name>    - Load code from local storage under name
-    delete <name>  - Remove code from local storage
-    browse / b     - Show content of local storage
-    help / h       - Show this help
-
-    Name with arbitrary characters (spaces) must be closed by \\
-    save Long file name.txt\\
-  """
-
-  sourceArea = CodeMirror.fromTextArea $("#sourceArea")[0],
-    tabSize: 2
-    indentUnit: 2
-    lineNumbers: true
-    extraKeys:
-      Tab: "indentMore"
-      "Shift-Tab": "indentLess"
-
-    onChange: (inst, e) ->
-      sourceChange inst, e
-
-    onCursorActivity: ->
-      sourceArea.setLineClass hlLine, null, null
-      hlLine = sourceArea.setLineClass sourceArea.getCursor().line, null, "activeline"
-
-  hlLine = sourceArea.setLineClass 1, null, "activeline"
-  commandArea = CodeMirror.fromTextArea $("#commandArea")[0],
-    tabSize: 2
-    indentUnit: 2
-    keyMap: "commandLine"
-    onKeyEvent: (inst, e) ->
-      commandAreaKeyEvent inst, e
-
-  $(sourceArea.getInputField()).keyup (e) ->
-    switch CodeMirror.keyNames[e.keyCode]
-      when "Esc"
-        commandArea.focus()
-
-  $("#commandWrap .CodeMirror").mouseenter (e) ->
-    commandArea.focus()
-
-  $("#sourceWrap .CodeMirror").mouseenter (e) ->
-    sourceArea.focus()
-
-  $("#centerBar").draggable
-    axis: "x"
-    drag: (e, ui) ->
-      newRightColumnWidth = $(window).width() - ui.offset.left - 60
-      if newRightColumnWidth > 0
-        $("#leftColumn").width ui.offset.left - $("#leftColumn").position().left
-        $("#rightColumn").width newRightColumnWidth
-      ui.position = ui.originalPosition
-
-  defaultEditor()
-  $(window).resize resizeEditor
-  $(window).unload ->
-    saveCurrent()
-
-  hash = decodeURIComponent window.location.hash.replace /^#/, ""
-  if hash.indexOf(sourceFragment) is 0
-    src = hash.substr(sourceFragment.length)
-    loadWith src
-    window.location.hash = ""
-    log "File loaded from URI, use the link command to generate new link."
-  else
-    loadFromClient()
-  loadTimeline()
-  if timeline.size() < 10
-    log helpDescription
+        shouldStop = false
+    if shouldStop
+      e.stop()
+
+defaultEditor = ->
+  winSize =
+    w: $(window).width()
+    h: $(window).height()
+
+  column = floor winSize.w / 2
+  $("#leftColumn").width column - 30
+  resizeEditor()
+
+resizeEditor = (e) ->
+  winSize =
+    w: $(window).width()
+    h: $(window).height()
+
+  $("#centerBar").height winSize.h - 20
+  $("#sourceWrap .CodeMirror-scroll").css "max-height", (winSize.h - 175) + "px"
+  $("#rightColumn").width winSize.w - $("#leftColumn").width() - 60
+  $("#rightColumn").css "max-height", (winSize.h - 25) + "px"
+  setMaxPreWidth $("#output pre")
+
+selectLastOutput = ->
+  (getMessage(0)).selectText()
+
+setMaxPreWidth = ($pre) ->
+  $pre.css "max-width", ($("#rightColumn").width() - 45) + "px"
+
+loadWith = (coffee) ->
+  sourceArea.setValue sourceArea.getValue() + coffee
+
+saveToAdress = ->
+  source = sourceArea.getValue()
+  window.location = "#" + sourceFragment + (encodeURIComponent(source))
+
+# TODO: an easy way to distinguish code from other text in logs
+helpDescription = """
+  Issue commands by typing \"< \" or \":\"
+  followed by space separated commands:
+
+  erase / e      - Clear all results
+  erase <not...> - Don't clear results containing givens
+  dump / d       - Dump generated javascript
+  run / r        - Run just the source code
+  copy / c       - Select last output (right-click to copy)
+  toggle / t     - Toggle autocompilation
+  link / l       - Create a link with current source code
+  mode <name>    - Switch to a different compiler
+  modes / m      - Show all available modes
+  canvas <w> <h> - Create a canvas given width and height
+  save <name>    - Save current code locally under name
+  load <name>    - Load code from local storage under name
+  delete <name>  - Remove code from local storage
+  browse / b     - Show content of local storage
+  help / h       - Show this help
+
+  Name with arbitrary characters (spaces) must be closed by \\
+  save Long file name.txt\\
+"""
+
+sourceArea = CodeMirror.fromTextArea $("#sourceArea")[0],
+  tabSize: 2
+  indentUnit: 2
+  lineNumbers: true
+  extraKeys:
+    Tab: "indentMore"
+    "Shift-Tab": "indentLess"
+
+  onChange: (inst, e) ->
+    sourceChange inst, e
+
+  onCursorActivity: ->
+    sourceArea.setLineClass hlLine, null, null
+    hlLine = sourceArea.setLineClass sourceArea.getCursor().line, null, "activeline"
+
+hlLine = sourceArea.setLineClass 1, null, "activeline"
+commandArea = CodeMirror.fromTextArea $("#commandArea")[0],
+  tabSize: 2
+  indentUnit: 2
+  keyMap: "commandLine"
+  onKeyEvent: (inst, e) ->
+    commandAreaKeyEvent inst, e
+
+$(sourceArea.getInputField()).keyup (e) ->
+  switch CodeMirror.keyNames[e.keyCode]
+    when "Esc"
+      commandArea.focus()
+
+$("#commandWrap .CodeMirror").mouseenter (e) ->
+  commandArea.focus()
+
+$("#sourceWrap .CodeMirror").mouseenter (e) ->
+  sourceArea.focus()
+
+$("#centerBar").draggable
+  axis: "x"
+  drag: (e, ui) ->
+    newRightColumnWidth = $(window).width() - ui.offset.left - 60
+    if newRightColumnWidth > 0
+      $("#leftColumn").width ui.offset.left - $("#leftColumn").position().left
+      $("#rightColumn").width newRightColumnWidth
+    ui.position = ui.originalPosition
+
+defaultEditor()
+$(window).resize resizeEditor
+$(window).unload ->
+  saveCurrent()
+
+hash = decodeURIComponent window.location.hash.replace /^#/, ""
+if hash.indexOf(sourceFragment) is 0
+  src = hash.substr(sourceFragment.length)
+  loadWith src
+  window.location.hash = ""
+  log "File loaded from URI, use the link command to generate new link."
+else
+  loadFromClient()
+loadTimeline()
+if timeline.size() < 10
+  log helpDescription


fix colors

fix colors

--- src/daily-report/services/report-builder.coffee
+++ src/daily-report/services/report-builder.coffee
@@ -15,9 +15,9 @@
       index = getCurrentDayIndex sprint.bdcData
       diff = sprint.bdcData[index].done - sprint.bdcData[index].standard
       if diff > 0
-        true
+        return true
       if diff < 0
-       false
+       return false

   renderBehindAhead = (message) ->
     isAhead().then (ahead) ->


Jumping! with no floor checking

Jumping! with no floor checking

--- scrolling/player-controller.coffee
+++ scrolling/player-controller.coffee
@@ -9,8 +9,9 @@
     xVelocity: 0
     yVelocity: 0

-    accelerationStep: 1000
-    accelerationCap: 400
+    yAccelerationStep: 1000
+    xAccelerationStep: 1000
+    xAccelerationCap: 400

     hitBox: null

@@ -28,30 +29,33 @@
         stage.addChild @hitBox

     accelerateRight: (timeRatio) ->
-        @xVelocity += @accelerationStep * timeRatio
+        @xVelocity += @xAccelerationStep * timeRatio
         @capVelocity()

     accelerateLeft: (timeRatio) ->
-        @xVelocity -= @accelerationStep * timeRatio
+        @xVelocity -= @xAccelerationStep * timeRatio
         @capVelocity()
+
+    accelerateDown: (timeRatio) ->
+        @yVelocity -= @yAccelerationStep * timeRatio

     slow: (timeRatio) ->
         if @xVelocity < 0
-            @xVelocity += @accelerationStep * timeRatio
+            @xVelocity += @xAccelerationStep * timeRatio
             if @xVelocity > 0
                 @xVelocity = 0

         else if @xVelocity > 0
-            @xVelocity -= @accelerationStep * timeRatio
+            @xVelocity -= @xAccelerationStep * timeRatio
             if @xVelocity < 0
                 @xVelocity = 0

     capVelocity: ->
-        if @xVelocity < -@accelerationCap
-            @xVelocity = -@accelerationCap
+        if @xVelocity < -@xAccelerationCap
+            @xVelocity = -@xAccelerationCap

-        if @xVelocity > @accelerationCap
-            @xVelocity = @accelerationCap
+        if @xVelocity > @xAccelerationCap
+            @xVelocity = @xAccelerationCap

     update: (elapsedTime, inputState) ->
         timeRatio = elapsedTime / 1000
@@ -65,8 +69,17 @@
         else
             @slow timeRatio

+        if inputState.jump and not @jumping
+            console.log 'jumping'
+            @jumping = true
+            @yVelocity += 500
+
+        if @jumping
+            @accelerateDown timeRatio
+
         @updatePosition timeRatio

     updatePosition: (timeRatio) ->
         @hitBox.position.x += @xVelocity * timeRatio
+        @hitBox.position.y -= @yVelocity * timeRatio


feature: textBackgroundExpand

feature: textBackgroundExpand

--- lib/editor-background.coffee
+++ lib/editor-background.coffee
@@ -54,22 +54,23 @@
       type:'string'
       default:''
       order:1
-      description:"Search for 'background loop' or similar on youtube and
-      paste url here."
+      description:"Search for 'background loop',
+      'background animation' or similar on youtube and paste url here."
     animationSpeed:
       type:"integer"
       default:100
       order:2
-      description:"animation speed in ms, LOWER VALUE = HIGHER CPU USAGE"
+      description:"animation speed in ms (original is 50),
+      LOWER VALUE = HIGHER CPU USAGE"
     startTime:
       type:"string"
       default:'0s'
       order:3
-      description:"video start time like 1h30m10s"
+      description:"video start time like 1h30m10s or 10s"
     endTime:
       type:"string"
       default:"20s"
-      description:"video end time like 1h30m30s"
+      description:"video end time like 1h30m30s or 30s"
       order:4
     textBackground:
       type:"color"
@@ -84,59 +85,64 @@
       type:"integer"
       default:5
       order:7
+    textBackgroundExpand:
+      type:"integer"
+      default:4
+      description:"If you want larger area under text - try 4 or 10"
+      order:8
     backgroundSize:
       type:"string"
       default:"original"
       enum:["original","100%","cover","manual"]
       description:"Background size"
-      order:8
+      order:9
     manualBackgroundSize:
       type:"string"
       default:""
       description:"'100px 100px' or '50%' try something..."
-      order:9
+      order:10
     customOverlayColor:
       type:"boolean"
       default:false
-      order:10
+      order:11
       description:"Do you want different color on top of background? check this"
     overlayColor:
       type:'color'
       default:'rgba(0,0,0,0)'
       description:"Color used to overlay background image"
-      order:11
+      order:12
     opacity:
       type:'integer'
       default:'100'
       description:"Background image visibility percent 1-100"
-      order:12
+      order:13
     treeViewOpacity:
       type:'integer'
       default:"35"
       description:"Tree View can be transparent too :)"
-      order:13
+      order:14
     transparentTabBar:
       type:"boolean"
       default:true
       desctiption:"Transparent background under file tabs"
-      order:14
+      order:15
     mouseFactor:
       type:"integer"
       default: 0
       description: "move background with mouse (higher value = slower)
       try 8 or 4 for 3dbox or 20 for wallpaper"
-      order:15
+      order:16
     textShadow:
       type:"string"
       default:"none"
       description:"Add a little text shadow to code like
       '0px 2px 2px rgba(0,0,0,0.3)' "
-      order:16
+      order:17
     style:
       type:"string"
       default:"background:radial-gradient(rgba(0,0,0,0) 30%,rgba(0,0,0,0.75));"
       description:"Your custom css rules :]"
-      order:17
+      order:18
     boxDepth:
       type:"integer"
       default: 0
@@ -579,6 +585,7 @@
           textBlur = conf.textBackgroundBlurRadius
           opacity = (conf.textBackgroundOpacity/100).toFixed(2)
           color = conf.textBackground.toRGBAString()
+          expand = conf.textBackgroundExpand

           root = editor.shadowRoot
           scrollView = root.querySelector '.scroll-view'
@@ -608,6 +615,9 @@
           if !/[0-9]+px$/.test(fontSize)
             fontSize+='px'

+          scaleX = 1 + parseFloat((expand / 100).toFixed(2))
+          scaleY = 1 + parseFloat((expand / 10).toFixed(2))
+
           css = @elements.textBackgroundCss

           css.innerText="
@@ -619,7 +629,8 @@
               color:transparent;
               background:#{color};
               width:auto;
-              transform:translate3d(0,0,0);
+              border-radius:10px;
+              transform:translate3d(0,0,0) scale(#{scaleX},#{scaleY});
               float:left;
               clear:both;
             }
@@ -881,7 +892,7 @@
             applyBlur = true
           else
             setTimeout (=> @blurImage.apply @),1000
-      if applyBlur
+      if applyBlur and conf.imageUrl
         imageData = blur.stackBlurImage @elements.image, conf.blurRadius, false
         base64Data = imageData.replace(/^data:image\/png;base64,/, "")
         filename = atom.packages.resolvePackagePath('editor-background')+


fix for field-lists in web form

fix for field-lists in web form

--- frontend/coffeescript/app/webform/views.coffee
+++ frontend/coffeescript/app/webform/views.coffee
@@ -177,7 +177,7 @@
               question_info = @input_fields[question]

               while question_info.tree is current_tree
-                question_change = $('#' + $($('.control-group').eq(question)[0]).data('key') + "_field")
+                question_change = $('#' + question_info.name + "_field")
                 question_change.fadeIn(1).addClass('active')
                 $('.active input').focus()
                 question++


NEW: can turn on/off spellcheck for text input

--- source/Art/Engine/Forms/TextInputElement.coffee
+++ source/Art/Engine/Forms/TextInputElement.coffee
@@ -72,6 +72,7 @@
       autocapitalize: normalizeAuto options.autoCapitalize  ? options.autocapitalize
       autocomplete:   normalizeAuto options.autoComplete    ? options.autocomplete
       autocorrect:    normalizeAuto options.autoCorrect     ? options.autocorrect
+      spellcheck:     if options.spellcheck? then "#{!!options.spellcheck}"

     Factory = if props.type == "textarea"
       delete props.type


Revert "skip ExtractColors graph spec for now"

This reverts commit 3f9d4e114a0568561f6eb79a816bc618ca842191.

--- spec/ExtractColors.coffee
+++ spec/ExtractColors.coffee
@@ -1,60 +1,60 @@
-# noflo = require 'noflo'
-# unless noflo.isBrowser()
-#   chai = require 'chai' unless chai
-#   path = require 'path'
-#   baseDir = path.resolve __dirname, '../'
-# else
-#   baseDir = '/noflo-image'
+noflo = require 'noflo'
+unless noflo.isBrowser()
+  chai = require 'chai' unless chai
+  path = require 'path'
+  baseDir = path.resolve __dirname, '../'
+else
+  baseDir = '/noflo-image'

-# describe 'ExtractColors graph', ->
-#   c = null
-#   ins = null
-#   out = null
-#   beforeEach (done) ->
-#     @timeout 10000
-#     loader = new noflo.ComponentLoader baseDir
-#     loader.load 'image/ExtractColors', (instance) ->
-#       c = instance
-#       c.once 'ready', ->
-#         ins = noflo.internalSocket.createSocket()
-#         out = noflo.internalSocket.createSocket()
-#         c.inPorts.url.attach ins
-#         c.outPorts.colors.attach out
-#         done()
+describe 'ExtractColors graph', ->
+  c = null
+  ins = null
+  out = null
+  beforeEach (done) ->
+    @timeout 10000
+    loader = new noflo.ComponentLoader baseDir
+    loader.load 'image/ExtractColors', (instance) ->
+      c = instance
+      c.once 'ready', ->
+        ins = noflo.internalSocket.createSocket()
+        out = noflo.internalSocket.createSocket()
+        c.inPorts.url.attach ins
+        c.outPorts.colors.attach out
+        done()

-#   describe 'with remote JPG image', ->
-#     url = 'http://farm8.staticflickr.com/7395/12952090783_ce023450da_b.jpg'
-#     unless noflo.isBrowser()
-#       it 'should have the correct group', (done) ->
-#         out.once 'begingroup', (group) ->
-#           chai.expect(group).to.equal url
-#           done()
-#         ins.send url
-#         ins.disconnect()
-#       it 'should find colors', (done) ->
-#         @timeout 10000
-#         out.once 'data', (data) ->
-#           chai.expect(data).to.be.an 'array'
-#           chai.expect(data[0]).to.be.an 'array'
-#           chai.expect(data[0].length).to.equal 3
-#           done()
-#         ins.send url
-#         ins.disconnect()
+  describe 'with remote JPG image', ->
+    url = 'http://farm8.staticflickr.com/7395/12952090783_ce023450da_b.jpg'
+    unless noflo.isBrowser()
+      it 'should have the correct group', (done) ->
+        out.once 'begingroup', (group) ->
+          chai.expect(group).to.equal url
+          done()
+        ins.send url
+        ins.disconnect()
+      it 'should find colors', (done) ->
+        @timeout 10000
+        out.once 'data', (data) ->
+          chai.expect(data).to.be.an 'array'
+          chai.expect(data[0]).to.be.an 'array'
+          chai.expect(data[0].length).to.equal 3
+          done()
+        ins.send url
+        ins.disconnect()

-#   describe 'with local JPG image', ->
-#     url = 'http://localhost:8000/spec/fixtures/extract.jpg'
-#     it 'should have the correct group', (done) ->
-#       out.once 'begingroup', (group) ->
-#         chai.expect(group).to.equal url
-#         done()
-#       ins.send url
-#       ins.disconnect()
-#     it 'should find colors', (done) ->
-#       @timeout 10000
-#       out.once 'data', (data) ->
-#         chai.expect(data).to.be.an 'array'
-#         chai.expect(data[0]).to.be.an 'array'
-#         chai.expect(data[0].length).to.equal 3
-#         done()
-#       ins.send url
-#       ins.disconnect()
+  describe 'with local JPG image', ->
+    url = 'http://localhost:8000/spec/fixtures/extract.jpg'
+    it 'should have the correct group', (done) ->
+      out.once 'begingroup', (group) ->
+        chai.expect(group).to.equal url
+        done()
+      ins.send url
+      ins.disconnect()
+    it 'should find colors', (done) ->
+      @timeout 10000
+      out.once 'data', (data) ->
+        chai.expect(data).to.be.an 'array'
+        chai.expect(data[0]).to.be.an 'array'
+        chai.expect(data[0].length).to.equal 3
+        done()
+      ins.send url
+      ins.disconnect()


add specs for change operation

add specs for change operation

Mostly cribbed from the delete ones, except skipping the `dd` one (for
deleting/changing an entire line).

The main difference is making sure the editor is in insert mode (and
not in command mode) after the action is performed.

--- spec/vim-mode-spec.coffee
+++ spec/vim-mode-spec.coffee
@@ -200,6 +200,74 @@

           expect(editor.getText()).toBe "ee four"
           expect(editor.getCursorScreenPosition()).toEqual([0,0])
+
+    describe "the c keybinding", ->
+      describe "when followed by an h", ->
+        it "deletes the previous letter on the current line and enters insert mode", ->
+          editor.setText("abcd\n01234")
+          editor.setCursorScreenPosition([1,1])
+
+          keydown('c', element: editor[0])
+          keydown('h', element: editor[0])
+
+          expect(editor.getText()).toBe "abcd\n1234"
+          expect(editor.getCursorScreenPosition()).toEqual([1,0])
+          expect(editor).not.toHaveClass 'command-mode'
+          expect(editor).toHaveClass 'insert-mode'
+
+      describe "when followed by a w", ->
+        it "deletes to the beginning of the next word and enters insert mode", ->
+          editor.setText("abcd efg")
+          editor.setCursorScreenPosition([0,2])
+
+          keydown('c', element: editor[0])
+          keydown('w', element: editor[0])
+
+          expect(editor.getText()).toBe "abefg"
+          expect(editor.getCursorScreenPosition()).toEqual([0,2])
+          expect(editor).not.toHaveClass 'command-mode'
+          expect(editor).toHaveClass 'insert-mode'
+
+          editor.trigger keydownEvent('escape')
+
+          editor.setText("one two three four")
+          editor.setCursorScreenPosition([0,0])
+
+          keydown('c', element: editor[0])
+          keydown('3', element: editor[0])
+          keydown('w', element: editor[0])
+
+          expect(editor.getText()).toBe "four"
+          expect(editor.getCursorScreenPosition()).toEqual([0,0])
+          expect(editor).not.toHaveClass 'command-mode'
+          expect(editor).toHaveClass 'insert-mode'
+
+      describe "when followed by a b", ->
+        it "deletes to the beginning of the previous word and enters insert mode", ->
+          editor.setText("abcd efg")
+          editor.setCursorScreenPosition([0,2])
+
+          keydown('c', element: editor[0])
+          keydown('b', element: editor[0])
+
+          expect(editor.getText()).toBe "cd efg"
+          expect(editor.getCursorScreenPosition()).toEqual([0,0])
+          expect(editor).not.toHaveClass 'command-mode'
+          expect(editor).toHaveClass 'insert-mode'
+
+          editor.trigger keydownEvent('escape')
+
+          editor.setText("one two three four")
+          editor.setCursorScreenPosition([0,11])
+
+          keydown('c', element: editor[0])
+          keydown('3', element: editor[0])
+          keydown('b', element: editor[0])
+
+          expect(editor.getText()).toBe "ee four"
+          expect(editor.getCursorScreenPosition()).toEqual([0,0])
+          expect(editor).not.toHaveClass 'command-mode'
+          expect(editor).toHaveClass 'insert-mode'

     describe "the y keybinding", ->
       beforeEach ->


QUALITY: Improve readability and tidy audio recorder

--- src/app/common/services/recorder-service.coffee
+++ src/app/common/services/recorder-service.coffee
@@ -1,16 +1,17 @@
+# Parts adapted from https://github.com/kaliatech/web-audio-recording-tests
+
 angular.module("doubtfire.common.services.recorder-service", [])
 #
-# Services for working with media Recording APIs
+# Services for working with cross-platform, media Recording APIs
 #
 .factory("recorderService", ($rootScope, $timeout, $sce) ->
   return class RecorderService
     constructor: () ->
       window.AudioContext = window.AudioContext || window.webkitAudioContext
+
       @em = document.createDocumentFragment()
       @state = 'inactive'
-
       @audioCtx = {}
-
       @chunks = []
       @chunkType = ''

@@ -18,7 +19,7 @@

       @encoderMimeType = 'audio/wav'

-      @config =
+      @config = {
         broadcastAudioProcessEvents: false,
         createAnalyserNode: true,
         createDynamicsCompressorNode: false,
@@ -27,19 +28,14 @@
         micGain: 1.0,
         processorBufferSize: 2048,
         stopTracksAndCloseCtxWhenFinished: true,
-        userMediaConstraints:
+        userMediaConstraints: {
           audio: true
-      return
-
-    createWorker: (fn) ->
-      js = fn
-        .toString()
-        .replace(/^function\s*\(\)\s*{/, '')
-        .replace(/}$/, '')
-      blob = new Blob([js])
-      return new Worker(URL.createObjectURL(blob))
-
-    startRecording: (timeslice) ->
+        }
+      }
+      return
+
+    # Called once when the recording is initated
+    startRecording: () ->
       if (@state != 'inactive')
         return

@@ -73,23 +69,10 @@
       else
         @destinationNode = @audioCtx.destination

-
       #  Create web worker for doing the encoding
       if (!@usingMediaRecorder)
-        if (@config.manualEncoderId == 'mp3')
-          #  This also works and avoids weirdness imports with workers
-          #  encoderWorker = new Worker(BASE_URL + '/workers/encoder-ogg-worker.js')
-          # encoderWorker = createWorker(EncoderMp3)
-          # encoderWorker.postMessage(['init', {baseUrl: BASE_URL, sampleRate: mediaRecorder.audioCtx.sampleRate}])
-          # encoderMimeType = 'audio/mpeg'
-        else if (@config.manualEncoderId == 'ogg')
-          # encoderWorker = createWorker(EncoderOgg)
-          # encoderWorker.postMessage(['init', {baseUrl: BASE_URL, sampleRate: mediaRecorder.audioCtx.sampleRate}])
-          # encoderMimeType = 'audio/ogg'
-        else
-          # @encoderWorker = new Worker(WavEncoder)
-          @encoderWorker = new Worker('/assets/wav-worker.js') #@createWorker('/assets/wav-worker.js')
-          @encoderMimeType = 'audio/wav'
+        @encoderWorker = new Worker('/assets/wav-worker.js')
+        @encoderMimeType = 'audio/wav'

         that = this
         @encoderWorker.addEventListener('message', (e) ->
@@ -97,8 +80,7 @@
           if (that.config.manualEncoderId == 'ogg')
             event.data = e.data
           else
-            event.data = new Blob(e.data, {type: that.encoderMimeType})
-            # console.log("Safari Blob created: " + event.data)
+            event.data = new Blob(e.data, { type: that.encoderMimeType })
           that._onDataAvailable(event)
         )

@@ -106,10 +88,10 @@
       that = this
       return navigator.mediaDevices.getUserMedia(@config.userMediaConstraints)
         .then((stream) ->
-          that._startRecordingWithStream(stream, timeslice)
+          that._startRecordingWithStream(stream)
         )
         .catch((error) ->
-          console.log('Error with getUserMedia: ' + error.message) # temp: helps when testing for strange issues on ios/safari
+          console.log('Error with getUserMedia: ' + error.message)
           console.log(error)
           return
         )
@@ -121,13 +103,13 @@
         @micGainNode.gain.setValueAtTime(newGain, @audioCtx.currentTime)
       return

-    _startRecordingWithStream: (stream, timeslice) ->
+    _startRecordingWithStream: (stream) ->
       @micAudioStream = stream
       @inputStreamNode = @audioCtx.createMediaStreamSource(@micAudioStream)
       @audioCtx = @inputStreamNode.context

       #  Kind-of a hack to allow hooking in to audioGraph mediaRecorder.inputStreamNode
-      if (@onGraphSetupWithInputStream) # use ?
+      if (@onGraphSetupWithInputStream)
         @onGraphSetupWithInputStream(@inputStreamNode)

       @inputStreamNode.connect(@micGainNode)
@@ -149,10 +131,6 @@
         nextNode.connect(@outputGainNode)

       if (@analyserNode)
-        # TODO: If we want the analyser node to receive the @processorNode's output, this needs to be changed _and_
-        #       processor node needs to be modified to copy input to output. It currently doesn't because it's not
-        #       needed when doing manual encoding.
-        # @processorNode.connect(@analyserNode)
         nextNode.connect(@analyserNode)

       @outputGainNode.connect(@destinationNode)
@@ -163,34 +141,12 @@
         @mediaRecorder.addEventListener('dataavailable', (evt) -> that._onDataAvailable(evt))
         @mediaRecorder.addEventListener('error', (evt) -> @_onError(evt))

-        @mediaRecorder.start(timeslice)
-      else
-        # Output gain to zero to prevent feedback. Seems to matter only on Edge, though seems like should matter
-        # on iOS too.  Matters on chrome when connecting graph to directly to mediaRecorder.audioCtx.destination, but we are
-        # not able to do that when using MediaRecorder.
+        @mediaRecorder.start()
+      else
         @outputGainNode.gain.setValueAtTime(0, @audioCtx.currentTime)
-        # mediaRecorder.outputGainNode.gain.value = 0
-
-        # Todo: Note that time mediaRecorder.slicing with manual wav encoderWav won't work. To allow it would require rewriting the encoderWav
-        # to assemble all chunks at end instead of adding header to each chunk.
-        if (timeslice) # USE ?
-          console.log('Time slicing without MediaRecorder is not yet supported. The resulting recording will not be playable.')
-          @slicing = setInterval( () ->
-            if (@state == 'recording')
-              @encoderWorker.postMessage(['dump', @context.sampleRate])
-          ,timeslice)
       return

     _onAudioProcess: (e) ->
-      # console.log('onaudioprocess', e)
-      # inputBuffer = e.inputBuffer
-      # outputBuffer = e.outputBuffer
-      # console.log(micAudioStream)
-      # console.log(mediaRecorder.audioCtx)
-      # console.log(micAudioStream.getTracks().forEach((track) -> console.log(track)))
-
-      # onAudioEm.dispatch(new Event('onaudioprocess', {inputBuffer:inputBuffer,outputBuffer:outputBuffer}))
-
       if (@config.broadcastAudioProcessEvents)
         @em.dispatchEvent(new CustomEvent('onaudioprocess', {
           detail: {
@@ -198,38 +154,6 @@
             outputBuffer: e.outputBuffer
           }
         }))
-
-      # # Example handling:
-      # inputBuffer = e.inputBuffer
-      # outputBuffer = e.outputBuffer
-      # # Each channel (usually only one)
-      # for (channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
-      #   inputData = inputBuffer.getChannelData(channel)
-      #   outputData = outputBuffer.getChannelData(channel)
-      #
-      #   # Each sample
-      #   for (sample = 0; sample < inputBuffer.length; sample++) {
-      #     # Make output equal to the same as the input (thus processor is doing nothing at this time)
-      #     outputData[sample] = inputData[sample]
-      #   }
-      # }
-
-      # When manually encoding (safari/edge), there's no reason to copy data to output buffer.  We set the output
-      # gain to 0 anyways (which is required on Edge if we did copy data to output). However, if using a MediaRecorder
-      # and a processor (all other browsers), then it would be required to copy the data otherwise the graph would
-      # generate no data for the MediaRecorder to consume.
-      # if (forceScriptProcessor) {
-
-      # # Copy input to output
-      # inputBuffer = e.inputBuffer
-      # outputBuffer = e.outputBuffer
-      # # This doesn't work on iOS/Safari. Guessing it doesn't have copyToChannel support, but haven't verified.
-      # for (channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
-      #   outputBuffer.copyToChannel(inputBuffer.getChannelData(channel), channel)
-      # }
-
-      # Safari and Edge require manual encoding via web worker. Single channel only for now.
-      # Example stereo encoderWav: https:#github.com/MicrosoftEdge/Demos/blob/master/microphone/scripts/recorderworker.js
       if (!@usingMediaRecorder)
         if (@state == 'recording')
           if (@config.broadcastAudioProcessEvents)
@@ -238,6 +162,7 @@
             @encoderWorker.postMessage(['encode', e.inputBuffer.getChannelData(0)])
       return

+    # Called once when the recording has been stopped
     stopRecording: () ->
       if (@state == 'inactive')
         return
@@ -248,25 +173,17 @@
         @state = 'inactive'
         @encoderWorker.postMessage(['dump', @audioCtx.sampleRate])
         clearInterval(@slicing)
-
-        # TODO: There should be a more robust way to handle this
-        # Without something like this, I think  the last recorded sample could be lost due to timing
-        # setTimeout(() -> {
-        #   state = 'inactive'
-        #   mediaRecorder.encoderWorker.postMessage(['dump', audioCtx.sampleRate])
-        # }, 100)
-      return
-
+      return
+
+    # Called each time a chunk of recording becomes available
     _onDataAvailable: (evt) ->
-      # console.log('state', mediaRecorder.state)
-      # console.log('evt.data', evt.data)
       @chunks.push(evt.data)
       @chunkType = evt.data.type

       if (@state != 'inactive')
         return

-      blob = new Blob(@chunks, {'type': @chunkType})
+      blob = new Blob(@chunks, { 'type': @chunkType })
       blobUrl = URL.createObjectURL(blob)
       recording = {
         ts: new Date().getTime(),
@@ -279,6 +196,7 @@
       @chunks = []
       @chunkType = null

+      # cleanup
       if (@destinationNode)
         @destinationNode.disconnect()
         @destinationNode = null
@@ -312,12 +230,11 @@
         @audioCtx.close()
         @audioCtx = null

-      @em.dispatchEvent(new CustomEvent('recording', {detail: {recording: recording}}))
+      @em.dispatchEvent(new CustomEvent('recording', { detail: { recording: recording } }))
       return

     _onError: (evt) ->
       console.log('error', evt)
       @em.dispatchEvent(new Event('error'))
-      alert('error:' + evt) # for debugging purposes
       return
 )


Client: Activity: Using `from` parameter instead of `skip`

--- client/activity/lib/flux/actions/message.coffee
+++ client/activity/lib/flux/actions/message.coffee
@@ -20,7 +20,7 @@

   dispatch LOAD_MESSAGES_BEGIN, { channelId }

-  socialapi.channel.fetchActivities {id: channelId, skip}, (err, messages) ->
+  socialapi.channel.fetchActivities {id: channelId, from}, (err, messages) ->
     if err
       dispatch LOAD_MESSAGES_FAIL, { err, channelId }
       return


Ensure dump folder exists before running LinkedFiles tests

The folder is also created in another test, so it will work the second
time the tests are executed, but it fails the first time.

--- services/web/test/acceptance/coffee/LinkedFilesTests.coffee
+++ services/web/test/acceptance/coffee/LinkedFilesTests.coffee
@@ -1,7 +1,9 @@
 async = require "async"
 expect = require("chai").expect
 _ = require 'underscore'
+mkdirp = require "mkdirp"

+Settings = require "settings-sharelatex"
 MockFileStoreApi = require './helpers/MockFileStoreApi'
 request = require "./helpers/request"
 User = require "./helpers/User"
@@ -21,8 +23,9 @@
 	before (done) ->
 		LinkedUrlProxy.listen 6543, (error) =>
 			return done(error) if error?
-			@owner = new User()
-			@owner.login done
+			@owner = new User()
+			@owner.login ->
+				mkdirp Settings.path.dumpFolder, done

 	describe "creating a URL based linked file", ->
 		before (done) ->
@@ -181,4 +184,4 @@
 						done()

 		# TODO: Add test for asking for host that return ENOTFOUND
-		# (This will probably end up handled by the proxy)+		# (This will probably end up handled by the proxy)


removed iOS specific code.

removed iOS specific code.

--- src/bridges/Bridge.coffee
+++ src/bridges/Bridge.coffee
@@ -13,8 +13,8 @@
       TizenBridge
       WebBridge
       AndroidBridge
+      WebsocketBridge
       JSCoreBridge
-      WebsocketBridge
     ]

     unless @bestNativeBridge?
@@ -26,11 +26,6 @@

   constructor: ->

-  bindNativeBridge: ->
-    # reset the bestNativeBridge and search again.. since now the native side is ready
-    Bridge.bestNativeBridge = null;
-    steroids.nativeBridge = Bridge.getBestNativeBridge()
-
   sendMessageToNative: (options={})->
     throw "ERROR: Bridge#sendMessageToNative not overridden by subclass!"

@@ -39,11 +34,7 @@

   # Handles incoming API messages
   message_handler: (e)=>
-    msg = if e.constructor.name == "String"
-      JSON.parse(e)
-    else
-      # iOS parameters come as objects and not as Strings
-      e
+    msg = JSON.parse(e)

     if msg?.callback?
       if @callbacks[msg.callback]?


added comment

added comment

--- _assets/js/_keyboard.coffee
+++ _assets/js/_keyboard.coffee
@@ -13,6 +13,7 @@
 highlightSelection = () ->
   $('#search-posts').off 'keydown'
   $('#search-posts').on 'keydown', (e) ->
+
     if e.which == 40 # if the down arrow is pressed . . .
       if e.preventDefault
         e.preventDefault()
@@ -35,7 +36,7 @@

       traverseUp() unless topOfList

-    else if e.which == 13
+    else if e.which == 13 # if the enter key is pressed . . .
       if e.preventDefault
         e.preventDefault()
       else


bootstrap-custom.js.coffee:removed scroll spy

--- app/assets/javascripts/bootstrap-custom.js.coffee
+++ app/assets/javascripts/bootstrap-custom.js.coffee
@@ -1,5 +1,3 @@
-$ ->
-  $(".topbar").scrollspy()
 $ ->
   $(".tabs").tabs()
 $ ->


OX-721 support for stopping loading

OX-721 support for stopping loading

--- app/assets/javascripts/oxalis/model/binary.coffee
+++ app/assets/javascripts/oxalis/model/binary.coffee
@@ -79,7 +79,12 @@
       plane.updateContrastCurves(@contrastCurves)

-  pingImpl : (position, {zoomStep, area, activePlane}) ->
+  pingImpl : (position, {zoomStep, area, activePlane}, doLoad = true) ->
+
+    unless doLoad
+
+      @queue.clear()
+      return

     if @lastPosition?


show past appointments in the scheduler

show past appointments in the scheduler

fixes #11105

Change-Id: I0ecd4447a250fe84cad8ff6ff672e415e59642d0
Reviewed-on: https://gerrit.instructure.com/15490
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Marc LeGendre <d33c80bc45d65303e33ca83108a9952b745af9ef@instructure.com>
Reviewed-by: Zach Pendleton <514dbb4d54d4f29e454990df7d075678f43f92aa@instructure.com>

--- app/coffeescripts/calendar/EventDataSource.coffee
+++ app/coffeescripts/calendar/EventDataSource.coffee
@@ -163,7 +163,7 @@
       fetchJobs = [[ '/api/v1/appointment_groups', { include: [ 'appointments', 'child_events' ] } ]]

       if fetchManageable
-        fetchJobs.push [ '/api/v1/appointment_groups', { scope: 'manageable', include: [ 'appointments', 'child_events' ] } ]
+        fetchJobs.push [ '/api/v1/appointment_groups', { scope: 'manageable', include: [ 'appointments', 'child_events' ], include_past_appointments: true } ]

       @startFetch fetchJobs, dataCB, doneCB


use annotran's event module

use annotran's event module

--- annotran/static/scripts/widget-controller.coffee
+++ annotran/static/scripts/widget-controller.coffee
@@ -92,7 +92,7 @@
       loaded = []
       loadAnnotations crossframe.frames

-    $scope.$on events.LANGUAGE_FOCUSED, ->
+    $scope.$on eventsa.LANGUAGE_FOCUSED, ->
       _resetAnnotations(annotationMapper, drafts, threading)
       loaded = []
       loadAnnotations crossframe.frames


fixed endless loop when searching for an unavailable value

--- src/core/fetch/value.coffee
+++ src/core/fetch/value.coffee
@@ -24,7 +24,14 @@
     if variable of node.d3plus.data[depth]
       return node.d3plus.data[depth][variable]

-    node = fetch vars, node, depth
+    if depth of node
+      node = node[depth]
+    else if depth of vars.data.keys or
+            depth of vars.attrs.keys and
+            depth isnt variable
+      node = fetch vars, node, depth
+    else
+      return null

   node = uniqueValues node if node instanceof Array and not validObject node[0]


Added a little snippet to make sure images in the connection lost splash are pre-loaded.

--- community/server/src/main/coffeescript/neo4j/webadmin/modules/connectionmonitor/ConnectionMonitor.coffee
+++ community/server/src/main/coffeescript/neo4j/webadmin/modules/connectionmonitor/ConnectionMonitor.coffee
@@ -38,6 +38,13 @@
         # check if the server is alive.
         @db.heartbeat.addListener ->

+        # Make sure any images in the connection
+        # lost splash have been pre-loaded, so we
+        # have them in case the server dies.
+        splash = $(template())
+        splash.hide()
+        $("body").append(splash)
+
       connectionLost : =>

         if not @visible


remove merge code

remove merge code

--- app/assets/javascripts/analytics/presenter.coffee
+++ app/assets/javascripts/analytics/presenter.coffee
@@ -91,10 +91,7 @@
       @automatedTranslation = $('div').hasClass('Automated-translation')

     startHover = $.now()
-<<<<<<< HEAD
     @moreInfo = $('span.more_information_theme').html()
-=======
->>>>>>> origin/master

     $('dfn.JS-tooltip').hover (->
       startHover = $.now()


Made it so Highcharts resizes automatically on window resizing. Fixes #766.

--- app/assets/javascripts/chart/highcharts.js.coffee
+++ app/assets/javascripts/chart/highcharts.js.coffee
@@ -30,7 +30,19 @@

   $.loadHighcharts = ->
     $("*[data-highcharts]").each ->
-      $(this).highchart()
+      chartitem = $(this)
+      chartitem.highchart()
+      $(window).resize ->
+        chartitem.highcharts().setSize(
+                0,
+                chartitem.parent().height(),
+                false
+            );
+        chartitem.highcharts().setSize(
+                chartitem.parent().width(),
+                chartitem.parent().height(),
+                false
+            )
     return

   $(document).ready $.loadHighcharts


remove legacy prop

remove legacy prop

--- app/assets/javascripts/components/app-router.cjsx
+++ app/assets/javascripts/components/app-router.cjsx
@@ -9,7 +9,7 @@
 Verify        = require './verify'
 GroupPage     = require './group-page'
 GroupBrowser  = require './group-browser'
-AboutPage     = require './yale-about-page'
+AboxutPage    = require './yale-about-page'
 YaleLogin     = require './yale-login'

 Project       = require 'models/project.coffee'
@@ -59,7 +59,7 @@
   runRoutes: (project) ->
     self = this
     routes =
-      <Route name="root" path="/" handler={App} onLogin={@userLoggedIn}>
+      <Route name="root" path="/" handler={App} >

         <Redirect from="_=_" to="/" />


Removed print for queue-status

Removed print for queue-status

--- app/assets/javascripts/oxalis/model/binary.coffee
+++ app/assets/javascripts/oxalis/model/binary.coffee
@@ -92,7 +92,7 @@

     interval = new Date() - @lastPingTime
     if @queue.queue and @queue.queue.length > 0
-      console.log interval, @queueStatus - @queue.queue.length, @queue.queue[0].priority
+      #console.log interval, @queueStatus - @queue.queue.length, @queue.queue[0].priority
     @queueStatus = @queue.queue.length
     @lastPingTime = new Date()


registerGameObject

registerGameObject

--- app/assets/javascripts/pirates/gameObjects.coffee
+++ app/assets/javascripts/pirates/gameObjects.coffee
@@ -18,6 +18,8 @@
     @image.src = @img
     @lifeTime = 0

+  @registerGameObject = (name, clazz) =>
+    @ALL[name] = clazz

   isEqual: (other) =>
     if !other?


intendation fix

intendation fix

--- app/assets/javascripts/search/queries/base.coffee
+++ app/assets/javascripts/search/queries/base.coffee
@@ -6,9 +6,8 @@

   constructor:
     (@query = '', @category = null, @facet_filters = [], @page = null) ->
-
-    # Algolia seems to want this string in an array
-    @categoryArray = if @category then [@category] else []
+      # Algolia seems to want this string in an array
+      @categoryArray = if @category then [@category] else []

   query_hash: ->


added initial version of notification.coffee

--- src/lib/notification.coffee
+++ src/lib/notification.coffee
@@ -0,0 +1,35 @@
+# [Template](http://neocotic.com/template)
+# (c) 2012 Alasdair Mercer
+# Freely distributable under the MIT license.
+# For all details and documentation:
+# <http://neocotic.com/template>
+
+#### Private variables
+
+# Easily accessible reference to the extension controller.
+{ext} = chrome.extension.getBackgroundPage()
+
+#### Notification page setup
+
+notification = window.notification =
+
+  # Initialize the notification page.
+  init: ->
+    div      = document.getElementById 'tip'
+    duration = utils.get 'notificationDuration'
+    result   = if ext.status then 'copy_success' else 'copy_fail'
+    # Style the tip and insert a relevant internationalized string depending on
+    # the outcome of the copy request or the existence of an override message.
+    div.className = result;
+    div.innerHTML = if ext.message then ext.message else utils.i18n result
+    # Reset `ext` to avoid affecting copy other copy requests. If the user has
+    # disabled the notifications option this should still be called in
+    # `ext.showNotification` for safety.
+    ext.reset()
+    # Set a timer to close the notification after a specified period of time,
+    # if the user enabled the corresponding option; otherwise it should stay
+    # open until it is closed manually by the user.
+    if duration > 0
+      window.setTimeout ->
+        window.close()
+      , duration


add workspace item methods

add workspace item methods

--- lib/notifications-log.coffee
+++ lib/notifications-log.coffee
@@ -46,12 +46,15 @@

   destroy: ->
     @element.remove()
+    @emitter.emit 'did-destroy'

   getElement: -> @element

   getURI: -> 'atom://notifications/log'

   getTitle: -> 'Log'
+
+  getLongTitle: -> 'Notifications Log'

   getDefaultLocation: -> 'bottom'

@@ -76,3 +79,8 @@

   onItemClick: (callback) ->
     @emitter.on 'item-clicked', callback
+
+  onDidDestroy: (callback) ->
+    @emitter.on 'did-destroy', callback
+
+  getIconName: -> 'comment'


formatting

formatting

--- lib/project-find-view.coffee
+++ lib/project-find-view.coffee
@@ -374,4 +374,4 @@
     @search(onlyRunIfActive: true, caseSensitive: not @model.getFindOptions().caseSensitive)

   toggleWholeWordOption: ->
-    @search(onlyRunIfActive: true, wholeWord: not @model.getFindOptions().wholeWord)
+    @search(onlyRunIfActive: true, wholeWord: not @model.getFindOptions().wholeWord)


cleanup: remove glob in favor of fs.readdir

--- src/linter/used_module_finder/executed_module_finder.coffee
+++ src/linter/used_module_finder/executed_module_finder.coffee
@@ -2,7 +2,6 @@
 async = require 'async'
 asyncHandlers = require 'async-handlers'
 fs = require 'fs'
-glob = require 'glob'
 ModuleNameParser = require './module_name_parser'
 path = require 'path'

@@ -57,15 +56,22 @@

   getModuleExecutables: (dir, done) ->
+    binPath = path.join dir, 'node_modules', '.bin'
     async.auto {
-      files: (next) -> glob "#{dir}/node_modules/.bin/*", next
-      links: ['files', (next, {files}) -> async.map files, fs.readlink, next]
+      executables: (next) ->
+        fs.access binPath, (err) ->
+          if err then return done null, []
+          fs.readdir binPath, next
+
+      links: ['executables', (next, {executables}) ->
+        files = executables.map (file) -> path.join binPath, file
+        async.map files, fs.readlink, next
+      ]
     }, asyncHandlers.transform(@parseModuleExecutables, done)

-  parseModuleExecutables: ({files, links}) ->
+  parseModuleExecutables: ({executables, links}) ->
     result = {}
-    executables = files.map (file) -> path.basename file
     links.forEach (link, index) ->
       name = ModuleNameParser.stripSubpath path.relative('..', link)
       result[name] = [] unless result[name]


Expect access_token instead of token

Expect access_token instead of token

--- components/RemoteLogin.coffee
+++ components/RemoteLogin.coffee
@@ -16,10 +16,10 @@
         data = JSON.parse req.responseText
       catch e
         return callback e
-      unless data.token
+      unless data.access_token
         return callback null, null

-      callback null, data.token
+      callback null, data.access_token # always expect access_token, http://tools.ietf.org/html/rfc6749#section-4.2.2
   # get token directly from provider
   if '$NOFLO_OAUTH_CLIENT_SECRET' isnt ''
     redirect = params.redirect or window.location.href


methods startApp and stopInstance both return the instance document

--- server/cluster.coffee
+++ server/cluster.coffee
@@ -135,7 +135,8 @@
     HTTP.post "#{agentUrl}/app/install-and-run?access_token=#{Settings.get('agentAuthToken')}", callOpts, (err, result) ->
       throw new Meteor.Error err if err
       console.log "Sent request to start instance. Response from the agent is", result.content.toString()
-    ""
+
+    Instances.findOne {name: instance}

   stopInstance: (instanceName) ->
     unless Instances.findOne {name: instanceName}
@@ -171,7 +172,8 @@
     HTTP.post "#{agentUrl}/app/stop?access_token=#{Settings.get('agentAuthToken')}", callOpts, (err, result) ->
       throw new Meteor.Error err if err
       console.log "Sent request to stop instance. Response from the agent is #{result.content}"
-    ""
+
+    Instances.findOne {name: instanceName}

   clearInstance: (project, instance) ->
     console.log "Cluster.clearInstance #{project}, #{instance}"


Use the privacy module instead of wesabe.taint etc.

--- application/chrome/content/wesabe/dom/Page.coffee
+++ application/chrome/content/wesabe/dom/Page.coffee
@@ -11,6 +11,7 @@
 file      = require 'io/file'
 snapshot  = require 'canvas/snapshot'
 english   = require 'util/words'
+privacy   = require 'util/privacy'
 {tryCatch, tryThrow} = require 'util/try'

 # ==== Types (shortcuts for use in this file)
@@ -38,22 +39,22 @@
   # Returns the title of this page.
   #
   @::__defineGetter__ 'title', ->
-    wesabe.taint @document.title
+    privacy.taint @document.title

   @::__defineGetter__ 'name', ->
-    wesabe.taint @defaultView.name
+    privacy.taint @defaultView.name

   #
   # Returns the +Window+ associated with this page.
   #
   @::__defineGetter__ 'defaultView', ->
-    wesabe.taint @document.defaultView
+    privacy.taint @document.defaultView

   #
   # Returns the URL of this page.
   #
   @::__defineGetter__ 'url', ->
-    wesabe.taint @defaultView.location.href
+    privacy.taint @defaultView.location.href

   #
   # Returns true if this page is in a frame, false otherwise.
@@ -95,7 +96,7 @@
   # Shorthand for finding an element by id, returns null if not found.
   #
   byId: (id) ->
-    wesabe.taint @document.getElementById(id)
+    privacy.taint @document.getElementById(id)

   #
   # Finds all nodes matching +xpathOrNode+ with optional
@@ -157,15 +158,15 @@
   #
   fill: (xpathOrNode, valueOrXpathOrNode) ->
     tryThrow 'Page.fill', (log) =>
-      element = wesabe.untaint @findStrict(xpathOrNode)
-      log.info 'element=', wesabe.taint(element)
-
-      value = wesabe.untaint(valueOrXpathOrNode)
+      element = privacy.untaint @findStrict(xpathOrNode)
+      log.info 'element=', privacy.taint(element)
+
+      value = privacy.untaint(valueOrXpathOrNode)
       value = value.toString() if type.isNumber(value)

       if value and not type.isString(value)
-        valueNode = wesabe.untaint @findStrict(value, element)
-        log.debug 'valueNode=', wesabe.taint(valueNode)
+        valueNode = privacy.untaint @findStrict(value, element)
+        log.debug 'valueNode=', privacy.taint(valueNode)
         value = valueNode.value

       log.radioactive 'value=', value
@@ -243,7 +244,7 @@
     tryThrow 'Page.check', (log) =>
       element = @findStrict xpathOrNode
       log.info 'element=', element
-      wesabe.untaint(element).checked = true
+      privacy.untaint(element).checked = true

   #
   # Unchecks the element given by +xpathOrNode+.
@@ -260,7 +261,7 @@
     tryThrow 'Page.uncheck', (log) =>
       element = @findStrict xpathOrNode
       log.info('element=', element)
-      wesabe.untaint(element).checked = false
+      privacy.untaint(element).checked = false

   #
   # Simulates submitting a form.
@@ -299,7 +300,7 @@
   #
   fireEvent: (xpathOrNode, eventType, args...) ->
     options = if args.length is 1 and typeof args[args.length-1] is 'object' then args.pop() else {}
-    element = wesabe.untaint(@findStrict xpathOrNode)
+    element = privacy.untaint(@findStrict xpathOrNode)
     event = element.ownerDocument.createEvent EVENT_TYPE_MAP[eventType]

     if eventType in ['keydown', 'keypress', 'keyup']
@@ -332,7 +333,7 @@
   # @public
   #
   visible: (xpathOrNode) ->
-    element = wesabe.untaint @find(xpathOrNode)
+    element = privacy.untaint @find(xpathOrNode)

     # no element? not visible
     return false unless element
@@ -396,7 +397,7 @@
   # @public
   #
   cells: (xpathOrNode) ->
-    node = wesabe.untaint @findStrict(xpathOrNode)
+    node = privacy.untaint @findStrict(xpathOrNode)
     name = node.tagName.toLowerCase()

     switch name
@@ -436,7 +437,7 @@
       textNodes = [node]
     else
       textNodes = @select './/text()', node
-    wesabe.taint (wesabe.untaint(node.nodeValue) for node in textNodes).join('')
+    privacy.taint (privacy.untaint(node.nodeValue) for node in textNodes).join('')

   #
   # Returns +true+ if +xpathOrNode+ has class +className+, +false+ otherwise.
@@ -489,7 +490,7 @@
       html.append "#{basename}.html"
       png.append "#{basename}.png"

-      wesabe.debug 'Dumping contents of current page to ', html.path, ' and ', png.path
+      logger.debug 'Dumping contents of current page to ', html.path, ' and ', png.path
       file.write html, "<html>#{@document.documentElement.innerHTML}</html>"
       snapshot.writeToFile @document.defaultView, png.path

@@ -501,10 +502,10 @@
     indent += '  ' for i in [0...level]

     for node in @select '*', scope or @document
-      selector = wesabe.untaint node.tagName.toLowerCase()
+      selector = privacy.untaint node.tagName.toLowerCase()
       selector += "##{node.id}" if node.id
       selector += ".#{node.className.replace /\s+/g, '.'}" if node.className
-      wesabe.debug indent, selector
+      logger.debug indent, selector
       @dumpStructure node, level + 1

     return null
@@ -514,7 +515,7 @@
   # then dumps the page as usual.
   dumpPrivately: ->
     for text in @select '//body//text()'
-      text = wesabe.untaint text
+      text = privacy.untaint text
       value = text.nodeValue
       sanitized = []


Removed debugging output

Removed debugging output

--- maze.coffee
+++ maze.coffee
@@ -238,8 +238,8 @@
     @floors = []
     for z in [0...@maze.dimensions[2]]
       floor = $('<canvas class=floor></canvas>').attr({
-          width: ear(@here.width)
-          height: ear(@here.height)
+          width: @here.width
+          height: @here.height
       })
       context = floor[0].getContext('2d')
       context.font = "50px 'Slabo 27px'"
@@ -248,14 +248,14 @@
         for x in [-1...@maze.dimensions[0]]
           context.strokeStyle = 'black'
           context.lineWidth = 1
-          if ear(!@maze.passageExists([[x, y, z], [x + 1, y, z]]))
+          if !@maze.passageExists([[x, y, z], [x + 1, y, z]])
             # paint right wall
             context.beginPath()
             context.moveTo(71.5 + 71 * x, 0.5 + 71 * y)
             context.lineTo(71.5 + 71 * x, 71.5 + 71 * y)
             context.lineWidth = 1
             context.stroke()
-          if ear(!@maze.passageExists([[x, y, z], [x, y + 1, z]]))
+          if !@maze.passageExists([[x, y, z], [x, y + 1, z]])
             # paint bottom wall
             context.beginPath()
             context.moveTo(0.5 + 71 * x, 71.5 + 71 * y)
@@ -299,7 +299,6 @@
       floor.css({
           position: 'absolute'
       })
-      console.log(z, @z)
       if z < @z
         floor.css(@below)
       else if z == @z


Fix wrong lon attribute name.

Fix wrong lon attribute name.

--- app/assets/javascripts/controllers/map.js.coffee
+++ app/assets/javascripts/controllers/map.js.coffee
@@ -15,7 +15,7 @@
       zoom: 12

     if $.cookie('last_lat')? and $.cookie('last_lon')?
-      properties.center = new L.LatLng($.cookie('last_lat'), $.cookie('last_lng'))
+      properties.center = new L.LatLng($.cookie('last_lat'), $.cookie('last_lon'))

     if $.cookie('last_zoom')?
       properties.zoom = parseInt($.cookie('last_zoom'), 10)


Fix removing markers from scrubber

Fix removing markers from scrubber

--- app/assets/javascripts/me-add-to-playlist.coffee
+++ app/assets/javascripts/me-add-to-playlist.coffee
@@ -105,7 +105,7 @@

")
               $('#heading0').after(new_marker_section)
             offset = response.marker.start_time/1000
-            new_marker = $("

+            new_marker = $("

                 <form accept-charset='UTF-8' action='/avalon_marker/"+response.id+"' class='edit_avalon_marker' data-remote='true' id='edit_avalon_marker_"+response.id+"' method='post'>

                     <input name='utf8' type='hidden' value='✓' />
@@ -135,7 +135,7 @@
             else
               $('#markers').append(new_marker)
             offset_percent = Math.round(if isNaN(parseFloat(offset)) then 0 else (100*offset / currentPlayer.media.duration))
-            $('.mejs-time-total').append('')
+            $('.mejs-time-total').append('')
             new_marker.find('button.edit_marker').click(enableMarkerEditForm);
             new_marker.find('.edit_avalon_marker').on('ajax:success', handle_edit_save).on 'ajax:error', (e, xhr, status, error) ->
               alert 'Request failed.'


Add span and p to update displays

Add span and p to update displays

--- app/assets/javascripts/models/active_page.coffee
+++ app/assets/javascripts/models/active_page.coffee
@@ -44,7 +44,7 @@
   update_displays_on_page: ->
     $.each @attributes, (attr, val) =>
       # TODO make this work with span and p
-      $("[data-k-uuid='" + @uuid + "']div[data-attr='" + attr + "']").html(val)
+      $("div[data-k-uuid='" + @uuid + "'][data-attr='" + attr + "'], span[data-k-uuid='" + @uuid + "'][data-attr='" + attr + "'], p[data-k-uuid='" + @uuid + "'][data-attr='" + attr + "']").html(val)

   dirty_from_page: ->
     dirty = []


update header brand

update header brand

--- app/assets/javascripts/partials/yale-header.cjsx
+++ app/assets/javascripts/partials/yale-header.cjsx
@@ -23,9 +23,10 @@

-
ENSEMBLE

+

+
+

-
YALE THEATRE HISTORY TRANSCRIBED


revert side panel calcs

revert side panel calcs

--- app/assets/javascripts/weather/weather.js.coffee
+++ app/assets/javascripts/weather/weather.js.coffee
@@ -47,7 +47,7 @@
   $block = $('.weather_panel').html('')
   space = window.innerHeight - 15 - $('.navbar-fixed-top').outerHeight()
   item_max_height = 50
-  offset = 99999
+  offset = 0

   for block in window.wheater#[..window.weather_limit]
     date = new Date(block.time * 1000);
@@ -68,7 +68,7 @@
     if ((space -= item_max_height) > 0)
       $block.append($elem)

-      offset = Math.min(offset, $elem.find('img').position().left + 10)
+      offset = Math.max(offset, $elem.find('img').position().left)

     else break


[#85679260] add namespace for foods

[#85679260] add namespace for foods

--- app/assets/javascripts/yoolk/namespace.js.coffee
+++ app/assets/javascripts/yoolk/namespace.js.coffee
@@ -14,6 +14,7 @@
 window.Yoolk.Views.Services             ||= {}
 window.Yoolk.Views.Services.Categories  ||= {}
 window.Yoolk.Views.Menu                 ||= {}
+window.Yoolk.Views.Menu.Foods           ||= {}
 window.Yoolk.Views.Menu.Categories      ||= {}
 window.Yoolk.Views.People               ||= {}
 window.Yoolk.Views.Home                 ||= {}


Fixed: Incorrect cache logic of friendship: /friendship/delete, /friendship/set_display_name, /friendship/:friendId/profile.

--- src/routes/friendship.coffee
+++ src/routes/friendship.coffee
@@ -344,6 +344,7 @@
     DataVersion.updateFriendshipVersion currentUserId, timestamp
     .then ->
       Cache.del "friendship_profile_displayName_#{currentUserId}_#{friendId}"
+      Cache.del "friendship_profile_user_#{currentUserId}_#{friendId}"
       Cache.del "friendship_all_#{currentUserId}"
       Cache.del "friendship_all_#{friendId}"

@@ -376,7 +377,7 @@
     # 更新版本号（时间戳）
     DataVersion.updateFriendshipVersion currentUserId, timestamp
     .then ->
-      Cache.del "friendship_profile_#{currentUserId}_#{friendId}"
+      Cache.del "friendship_profile_displayName_#{currentUserId}_#{friendId}"

       res.send new APIResult 200
   .catch next
@@ -427,7 +428,7 @@

   Cache.get "friendship_profile_displayName_#{currentUserId}_#{friendId}"
   .then (displayName) ->
-    Cache.get "friendship_profile_user_#{friendId}"
+    Cache.get "friendship_profile_user_#{currentUserId}_#{friendId}"
     .then (profile) ->
       if displayName and profile
         results = {
@@ -463,7 +464,7 @@
           results = Utility.encodeResults friend, [['user', 'id']]

           Cache.set "friendship_profile_displayName_#{currentUserId}_#{friendId}", results.displayName
-          Cache.set "friendship_profile_user_#{friendId}", results.user
+          Cache.set "friendship_profile_user_#{currentUserId}_#{friendId}", results.user

           res.send new APIResult 200, results
   .catch next


Remove unneeded requires

Remove unneeded requires

--- src/extensions/fuzzy-finder/fuzzy-finder.coffee
+++ src/extensions/fuzzy-finder/fuzzy-finder.coffee
@@ -1,8 +1,5 @@
 {View, $$} = require 'space-pen'
 SelectList = require 'select-list'
-stringScore = require 'stringscore'
-fuzzyFilter = require 'fuzzy-filter'
-$ = require 'jquery'
 _ = require 'underscore'
 Editor = require 'editor'


Quiet noisy invitation spec

Quiet noisy invitation spec

--- angular/test/protractor/invitations_spec.coffee
+++ angular/test/protractor/invitations_spec.coffee
@@ -43,7 +43,7 @@
                '.group-welcome-modal__close-button',
                '.members-card__invite-members-btn',
                '.invitation-form__add-members',
-               '.add-members-modal__list-item',
+               '.add-members-modal__list-item:first-of-type',
                '.add-members-modal__submit'

     page.expectFlash 'Jennifer Grey added to Subgroup'


Fix visualization/show tables tab selection

--- app/frontend/javascripts/visualization.js.coffee
+++ app/frontend/javascripts/visualization.js.coffee
@@ -5,6 +5,10 @@
   constructor: (_id) ->
     console.log 'Visualization'
     super _id
+    # activate table tabs selector
+    $('#visualization-table-selector a').click (e) ->
+      e.preventDefault()
+      $(this).tab 'show'

   resize: =>
     # setup container height


Disable people binding for topics pages

Disable people binding for topics pages

--- app/assets/javascripts/gmaps4histvest.js.coffee
+++ app/assets/javascripts/gmaps4histvest.js.coffee
@@ -26,8 +26,6 @@
         $(document).on('click', '.infowindow .marker-person[data-url]', ->
             window.open $(this).data('url') unless $('body').hasClass('touch')
         )
-
-        google.maps.event.addListener @my_map, 'zoom_changed', @togglePeople

     extend_bounds_with_objects: (objects) ->
         for obj in objects
@@ -174,8 +172,7 @@

         @markers.splice i, 1 for i in indexes

-    togglePeople: =>
-
+    togglePeople: =>
         # load new from server
         params =
             n: @my_map.getBounds().getNorthEast().lat()


Change timing and sequence of save-like events.

--- app/assets/javascripts/image_question.js.coffee
+++ app/assets/javascripts/image_question.js.coffee
@@ -32,6 +32,11 @@
       @set_svg_input(image_tag)
       @submit_svg_form()
       @$sb_svg_src.empty().hide()
+      @copy_annotation_to_live_submit("annotation")
+      @copy_annotation_to_live_submit("answer_text")
+      @hide()
+      # TODO: validate response and calling showSaved() or saveFailed().
+      @show_saved()
     ,"svg_" + @image_question_id)

     @$snapshot_button = $("#{@button_sel} .take_snapshot")
@@ -90,25 +95,8 @@
       @hide()

     @$done_button.click =>
-      @get_svg_canvas().getSvgString() (data, error) =>
-        @svg_annotation_data = data
-        $svg = $(data)
-
-        @$sb_svg_src.show();
-        w = $svg.attr('width')
-        h = $svg.attr('height')
-
-        @$sb_svg_src.css('width',w)
-        @$sb_svg_src.css('height',h)
-        @$sb_svg_src.css('background-color', '#ffffff')
-        @$sb_svg_src.css('background-image',  "url(#{@current_src})")
-        @$sb_svg_src.css('background-repeat', 'no-repeat')
-        @$sb_svg_src.css('background-position', 'center')
-        @$sb_svg_src.css('background-size', "contain")
-        @$sb_svg_src.html(data)
-        @shutterbug_svg.getDomSnapshot()
-        @hide()
-        @save()
+      @save()
+

     @$delete_button.click =>
       @delete_image()
@@ -184,12 +172,25 @@

   save: ->
     @show_saving()
-    # TODO: validate response and calling showSaved() or saveFailed().
-    @copy_annotation_to_live_submit("annotation")
-    @copy_annotation_to_live_submit("answer_text")
-    @show_saved()
-
-
+    @get_svg_canvas().getSvgString() (data, error) =>
+      @svg_annotation_data = data
+      $svg = $(data)
+
+      @$sb_svg_src.show();
+      w = $svg.attr('width')
+      h = $svg.attr('height')
+
+      @$sb_svg_src.css('width',w)
+      @$sb_svg_src.css('height',h)
+      @$sb_svg_src.css('background-color', '#ffffff')
+      @$sb_svg_src.css('background-image',  "url(#{@current_src})")
+      @$sb_svg_src.css('background-repeat', 'no-repeat')
+      @$sb_svg_src.css('background-position', 'center')
+      @$sb_svg_src.css('background-size', "contain")
+      @$sb_svg_src.html(data)
+      @shutterbug_svg.getDomSnapshot()
+
+
   copy_annotation_to_live_submit: (name) ->
     field_name   = """ [name="embeddable_image_question_answer[#{name}]"] """
     live_field   = $("#{@button_sel} #{field_name}")


:+1: fixed progress bug:

:+1: fixed progress bug:

--- app/assets/javascripts/lib/nypl_progress.coffee
+++ app/assets/javascripts/lib/nypl_progress.coffee
@@ -104,6 +104,7 @@

       html += "</select>"
     else
+      layer = loadedData.layers[0]
       html = "<strong>#{layer.name}, #{layer.year}</strong>"

     $("#legend").prepend(html)


Reload cart for each checkout step

Reload cart for each checkout step

--- app/assets/javascripts/sprangular/routes.coffee
+++ app/assets/javascripts/sprangular/routes.coffee
@@ -70,11 +70,16 @@
       templateUrl: 'checkout/details.html'
       resolve:
         countries: (Geography) -> Geography.getCountryList()
+        order: (Cart) ->
+          Cart.reload().then -> Cart.current

     .when '/checkout/confirm',
       requires: {user: true, cart: true}
       controller: 'CheckoutConfirmCtrl'
       templateUrl: 'checkout/confirm.html'
+      resolve:
+        order: (Cart) ->
+          Cart.reload().then -> Cart.current

     .when 'checkout/complete',
       controller: 'CheckoutCompleteCtrl'


ignore timestamps for now

ignore timestamps for now

--- app/assets/javascripts/sse_connection.js.coffee
+++ app/assets/javascripts/sse_connection.js.coffee
@@ -23,4 +23,4 @@

   sseSource.onmessage = (event) ->
     data = JSON.parse(event.data)
-    window.pushMessages.push(data) if data.payload
+    window.pushMessages.push(data) unless data.timestamp


fix shaking roll-over-cube

fix shaking roll-over-cube

--- app/assets/javascripts/static_editors.js.coffee
+++ app/assets/javascripts/static_editors.js.coffee
@@ -209,6 +209,7 @@
     oldmouse2D.y = mouse2D.y
     #キューブ配置位置
     intersects = raycaster.intersectObjects(scene.children)
+    #ロールオーバーキューブ含む
     intersects = faceIntersectOnly(intersects)

     if intersects.length > 0
@@ -223,6 +224,9 @@
         voxelPos = {}
         voxelPos.x = Math.floor(position.x) + 0.5
         voxelPos.y = Math.floor(position.y) + 0.5
+        #荒治療(TODO)
+        if voxelPos.y < 0
+          voxelPos.y += 1.0
         voxelPos.z = Math.floor(position.z) + 0.5

   faceIntersectOnly = (intersects) ->


fixes #722 学习计划页面课程搜索之后课程不能从右边返回到左边

fixes #722 学习计划页面课程搜索之后课程不能从右边返回到左边

--- app/coffeescripts/bundles/learning_plans.coffee
+++ app/coffeescripts/bundles/learning_plans.coffee
@@ -45,6 +45,8 @@
       data: $(this).serialize()
       success: (data)->
         $('.course_selection').html(data)
+        $('#courses option').each ->
+          $(this).data 'optgroup', $(this).parent().attr('label')
   # controls for course selection
   $(document).on 'click', '.add', ->
     $('#courses option:selected').appendTo $('#selected_courses')


Put notice on the left, on the right didn't *feel* right (pun intended).

If someone who owns a site opens Factlink in the proxy and is all like, what the heck is this doing on my site, they should always see some kind of explanation. Hiding away the explanation under the sidebar seems therefore not a good idea.

--- app/js/jail_iframe/classes/proxy_message.coffee
+++ app/js/jail_iframe/classes/proxy_message.coffee
@@ -13,8 +13,7 @@

   frame.$el.css
     top: '10px'
-    left: 'auto'
-    right: '10px'
+    left: '10px'
     position: 'fixed'

   frame.fadeIn()


sigh, trigger

sigh, trigger

--- apps/personalize/client/mixins/followable.coffee
+++ apps/personalize/client/mixins/followable.coffee
@@ -40,7 +40,7 @@

     # Fallback in case model doesn't have display_model
     displayModel = model.get('display_model') or 'displayModelUnknown'
-    analyticsHooks 'followable:followed',
+    analyticsHooks.trigger 'followable:followed',
       message: @analyticsFollowMessage
       label: modelNameAndIdToLabel(displayModel, model.get('id'))

@@ -50,6 +50,6 @@
     @following.unfollow id

     displayModel = model.get('display_model') or 'displayModelUnknown'
-    analyticsHooks 'followable:followed',
+    analyticsHooks.trigger 'followable:followed',
       message: @analyticsFollowMessage
       label: modelNameAndIdToLabel(displayModel, model.get('id'))


Typo, the missing e is killing me

Typo, the missing e is killing me

--- app/assets/javascripts/Blackmailr.js.coffee
+++ app/assets/javascripts/Blackmailr.js.coffee
@@ -1,5 +1,5 @@
 if not Blackmailr? and jQuery?
 	$ = jQuery
 	window.Blackmailr = class extends caseyWebDev
-	Blackmailer.init()
+	Blackmailr.init()


Fixed hovering over name of image while anonymous [#79287690]

--- app/assets/javascripts/anonymizer.js.coffee
+++ app/assets/javascripts/anonymizer.js.coffee
@@ -10,6 +10,8 @@
   constructor: ->
     @selector      = ".learner_response_name"
     @alt_selector  = "div.user"
+    @feedback_selector = "div.feedback_link"
+    @title_selector = "img.portray"
     @button_select = "anonymize_button"
     @real_to_fake_map  = {}
     @fake_to_real_map  = {}
@@ -19,46 +21,40 @@
       $(@button_select).observe 'click', (evt) =>
         @toggle()
         evt.stop();
-
-  record_fake_and_real: (real_name) ->
-    fake = @real_to_fake_map[real_name]
-    unless fake
-      fake = "Student #{@counter}"
-      @counter++
-      @real_to_fake_map[real_name] = fake
-      @fake_to_real_map[fake] = real_name
-    return fake
-
-  rename_button: ->
-    if @anonymous
-      $(@button_select).textContent = "Show names"
-    else
-      $(@button_select).textContent = "Hide names"
+    $$(@selector).each (item) =>
+      real_name = trim(item.textContent)
+      if not @real_to_fake_map[real_name]
+        fake = "Student #{@counter++}"
+        @real_to_fake_map[real_name] = fake
+        @fake_to_real_map[fake] = real_name

   publicize: ->
     @anonymous = false
     $$(@selector).each (item) =>
-      fake_name = trim(item.textContent)
-      item.textContent = @fake_to_real_map[fake_name]
+      item.textContent = @fake_to_real_map[trim(item.textContent)]
     $$(@alt_selector).each (item) =>
-      fake_name = trim(item.textContent)
-      item.textContent = @fake_to_real_map[fake_name]
+      item.textContent = @fake_to_real_map[trim(item.textContent)]
+    $$(@title_selector).each (item) =>
+      item.title = @fake_to_real_map[trim(item.title)]
+    $$(@feedback_selector).each (Element.show)

   anonymize: ->
     @anonymous = true
     $$(@selector).each (item) =>
-      real_name = trim(item.textContent)
-      item.textContent = @record_fake_and_real(real_name)
+      item.textContent = @real_to_fake_map[trim(item.textContent)]
     $$(@alt_selector).each (item) =>
-      real_name = trim(item.textContent)
-      item.textContent = @real_to_fake_map[real_name]
+      item.textContent = @real_to_fake_map[trim(item.textContent)]
+    $$(@title_selector).each (item) =>
+      item.title = @real_to_fake_map[trim(item.title)]
+    $$(@feedback_selector).each (Element.hide)

   toggle: ->
-    if @anonymous
+    $(@button_select).textContent = if @anonymous
       @publicize()
+      "Hide names"
     else
       @anonymize()
-    @rename_button()
+      "Show names"

 document.observe "dom:loaded", ->
   a = new Anonymizer


SetUp the Chat Channel Client side

SetUp the Chat Channel Client side

--- app/assets/javascripts/channels/chat.coffee
+++ app/assets/javascripts/channels/chat.coffee
@@ -7,6 +7,13 @@

   received: (data) ->
     # Called when there's incoming data on the websocket for this channel
+    $('#messages').append(data.message)

-  speak: ->
-    @perform 'speak'
+  speak: (msg) ->
+    @perform 'speak', message: msg
+
+$(document).on 'keypress', '#chat-speak', (event) ->
+  if event.keyCode is 13
+    App.chat.speak(event.target.value)
+    event.target.value = ''
+    event.preventDefault()


add missing quote

add missing quote

--- src/hubot-confluence.coffee
+++ src/hubot-confluence.coffee
@@ -105,7 +105,7 @@
   url = "#{protocol}://#{host}:#{port}/#{context_root}"
   # account for an empty context root
   if !context_root?.length
-    url = "#{protocol}://#{host}:#{port}
+    url = "#{protocol}://#{host}:#{port}"
   if api
     url = "#{url}/rest/api#{suffix}"
   else