Translate menu_linux.cson to Spanish

Translate menu_linux.cson to Spanish

Signed-off-by: Santos Gallegos <c7d20f0b590f7c49e45e22db249ad9b63899f894@outlook.com>

--- def/es/menu_linux.cson
+++ def/es/menu_linux.cson
@@ -1,296 +1,296 @@
 Menu:
   "&File":
-    value: "File(&F)"
+    value: "Archivo(&F)"
     submenu:
       "New &Window":
-        value: "New Window(&W)"
+        value: "Nueva Ventana(&W)"
       "&New File":
-        value: "New File(&N)"
+        value: "Nuevo Archivo(&N)"
       "&Open File…":
-        value: "Open File(&O)..."
+        value: "Abrir Archivo(&O)..."
       "Open Folder…":
-        value: "Open Folder..."
+        value: "Abrir Carpeta..."
       "Add Project Folder…":
-        value: "Add Project Folder..."
+        value: "Agregar Carpeta al Proyecto..."
       "Reopen Last &Item":
-        value: "Reopen Last Item(&I)"
+        value: "Reabrir Último Ítem(&I)"
       "&Save":
-        value: "Save(&S)"
+        value: "Guardar(&S)"
       "Save &As…":
-        value: "Save As(&A)..."
+        value: "Guardar Como(&A)..."
       "Save A&ll":
-        value: "Save All(&L)"
+        value: "Guardar Todo(&L)"
       "&Close Tab":
-        value: "Close Tab(&C)"
+        value: "Cerrar Pestaña(&C)"
       "Close &Pane":
-        value: "Close Pane(&P)"
+        value: "Cerrar Panel(&P)"
       "Clos&e Window":
-        value: "Close Window(&E)"
+        value: "Cerrar Ventana(&E)"
       "Quit":
-        value: "Quit"
+        value: "Salir"
       "Close All Tabs":
-        value: "Close All Tabs"
+        value: "Cerrar Todas las Pestañas"
   "&Edit":
-    value: "Edit(&E)"
+    value: "Editar(&E)"
     submenu:
       "&Undo":
-        value: "Undo(&U)"
+        value: "Deshacer(&U)"
       "&Redo":
-        value: "Redo(&R)"
+        value: "Rehacer(&R)"
       "&Cut":
-        value: "Cut(&C)"
+        value: "Cortar(&C)"
       "C&opy":
-        value: "Copy(&O)"
+        value: "Copiar(&O)"
       "Copy Pat&h":
-        value: "Copy Path(&H)"
+        value: "Copiar Ruta(&H)"
       "&Paste":
-        value: "Paste(&P)"
+        value: "Pegar(&P)"
       "Select &All":
-        value: "Select All(&A)"
+        value: "Seleccionar Todo(&A)"
       "&Toggle Comments":
-        value: "Toggle Comments(&T)"
+        value: "Comentar/Descomentar"
       Lines:
-        value: "Lines"
+        value: "Líneas"
         submenu:
           "&Indent":
-            value: "Indent(&I)"
+            value: "Indentar(&I)"
           "&Outdent":
-            value: "Outdent(&O)"
+            value: "Quitar Indentado(&O)"
           "&Auto Indent":
-            value: "Auto Indent(&A)"
+            value: "Auto Indentar(&A)"
           "Move Line &Up":
-            value: "Move Line Up(&U)"
+            value: "Mover Línea Hacia Arriba(&U)"
           "Move Line &Down":
-            value: "Move Line Down(&D)"
+            value: "Mover Línea Hacia Abajo(&D)"
           "Du&plicate Lines":
-            value: "Duplicate Lines(&P)"
+            value: "Duplicar Líneas(&P)"
           "D&elete Line":
-            value: "Delete Line(&E)"
+            value: "Eliminar Líneas(&E)"
           "&Join Lines":
-            value: "Join Lines(&J)"
+            value: "Unir Líneas(&J)"
       Columns:
-        value: "Columns"
+        value: "Columnas"
         submenu:
           "Move Selection &Left":
-            value: "Move Selection Left(&L)"
+            value: "Mover Selección a la Izquierda(&L)"
           "Move Selection &Right":
-            value: "Move Selection Right(&R)"
+            value: "Mover Selección a la Derecha(&R)"
       Text:
-        value: "Text"
+        value: "Texto"
         submenu:
           "&Upper Case":
-            value: "Upper Case(&U)"
+            value: "Mayúsculas(&U)"
           "&Lower Case":
-            value: "Lower Case(&L)"
+            value: "Minúsculas(&L)"
           "Delete to End of &Word":
-            value: "Delete to End of Word(&W)"
+            value: "Eliminar Hasta el Final de la Palabra(&W)"
           "Delete to Previous Word Boundary":
-            value: "Delete to Previous Word Boundary"
+            value: "Eliminar Hasta el Límite de la Palabra Anterior"
           "Delete to Next Word Boundary":
-            value: "Delete to Next Word Boundary"
+            value: "Eliminar Hasta el Límite de la Siguiente Palabra"
           "&Delete Line":
-            value: "Delete Line(&D)"
+            value: "Eliminar Línea(&D)"
           "&Transpose":
-            value: "Transpose(&T)"
+            value: "Transponer(&T)"
       Folding:
-        value: "Folding"
+        value: "Plegar"
         submenu:
           "&Fold":
-            value: "Fold(&F)"
+            value: "Plegar(&F)"
           "&Unfold":
-            value: "Unfold(&U)"
+            value: "Desplegar(&U)"
           "Unfold &All":
-            value: "Unfold All(&A)"
+            value: "Desplegar Todo(&A)"
           "Fol&d All":
-            value: "Fold All(&D)"
+            value: "Plegar Todo(&D)"
           "Fold Level 1":
-            value: "Fold Level 1"
+            value: "Plegar Nivel 1"
           "Fold Level 2":
-            value: "Fold Level 2"
+            value: "Plegar Nivel 2"
           "Fold Level 3":
-            value: "Fold Level 3"
+            value: "Plegar Nivel 3"
           "Fold Level 4":
-            value: "Fold Level 4"
+            value: "Plegar Nivel 4"
           "Fold Level 5":
-            value: "Fold Level 5"
+            value: "Plegar Nivel 5"
           "Fold Level 6":
-            value: "Fold Level 6"
+            value: "Plegar Nivel 6"
           "Fold Level 7":
-            value: "Fold Level 7"
+            value: "Plegar Nivel 7"
           "Fold Level 8":
-            value: "Fold Level 8"
+            value: "Plegar Nivel 8"
           "Fold Level 9":
-            value: "Fold Level 9"
+            value: "Plegar Nivel 9"
       "&Preferences":
-        value: "Preferences(&P)"
+        value: "Preferencias(&P)"
       "Config…":
-        value: "Config..."
+        value: "Configuraciones..."
       "Init Script…":
-        value: "Init Script..."
+        value: "Script Inicial..."
       "Keymap…":
-        value: "Keymap..."
+        value: "Atajos..."
       "Snippets…":
         value: "Snippets..."
       "Stylesheet…":
-        value: "Stylesheet..."
+        value: "Hoja de Estilos..."
       "Reflow Selection":
-        value: "Reflow Selection"
+        value: "Formatear Selección"
       Bookmark:
-        value: "Bookmark"
+        value: "Marcador"
         submenu:
           "View All":
-            value: "View All"
+            value: "Ver Todo"
           "Toggle Bookmark":
-            value: "Toggle Bookmark"
+            value: "Mostrar/Ocular Marcador"
           "Jump to Next Bookmark":
-            value: "Jump to Next Bookmark"
+            value: "Saltar al Marcador Siguiente"
           "Jump to Previous Bookmark":
-            value: "Jump to Previous Bookmark"
+            value: "Saltar al Marcador Anterior"
       "Select Encoding":
-        value: "Select Encoding"
+        value: "Seleccionar Codificación"
       "Go to Line":
-        value: "Go to Line"
+        value: "Ir a Línea"
       "Select Grammar":
-        value: "Select Grammar"
+        value: "Seleccionar Gramática"
   "&View":
-    value: "View(&V)"
+    value: "Ver(&V)"
     submenu:
       "Toggle &Full Screen":
-        value: "Toggle Full Screen(&F)"
+        value: "Entrar/Salir de Pantalla Completa(&F)"
       "Toggle Menu Bar":
-        value: "Toggle Menu Bar"
+        value: "Mostrar/Ocultar Barra de Menú"
       Panes:
-        value: "Panes"
+        value: "Paneles"
         submenu:
           "Split Up":
-            value: "Split Up"
+            value: "Dividir Hacia Arriba"
           "Split Down":
-            value: "Split Down"
+            value: "Dividir Hacia Abajo"
           "Split Left":
-            value: "Split Left"
+            value: "Dividir Hacia la Izquierda"
           "Split Right":
-            value: "Split Right"
+            value: "Dividir Hacia la Derecha"
           "Focus Next Pane":
-            value: "Focus Next Pane"
+            value: "Enfocar Panel Siguiente"
           "Focus Previous Pane":
-            value: "Focus Previous Pane"
+            value: "Enfocar Panel Anterior"
           "Focus Pane Above":
-            value: "Focus Pane Above"
+            value: "Enfocar Panel Superior"
           "Focus Pane Below":
-            value: "Focus Pane Below"
+            value: "Enfocar Panel Inferior"
           "Focus Pane On Left":
-            value: "Focus Pane On Left"
+            value: "Enfocar Panel de la Izquierda"
           "Focus Pane On Right":
-            value: "Focus Pane On Right"
+            value: "Enfocar Panel de la Derecha"
           "Close Pane":
-            value: "Close Pane"
+            value: "Cerrar Panel"
       Developer:
-        value: "Developer"
+        value: "Desarrollador"
         submenu:
           "Open In &Dev Mode…":
-            value: "Open In Dev Mode(&D)..."
+            value: "Abrir en Modo Desarrollador(&D)..."
           "&Reload Window":
-            value: "Reload Window(&R)"
+            value: "Recargar Ventana(&R)"
           "Run Package &Specs":
-            value: "Run Package Specs(&S)"
+            value: "Ejecutar Specs de Paquete(&S)"
           "Toggle Developer &Tools":
-            value: "Toggle Developer Tools(&T)"
+            value: "Mostrar/Ocultar Herramientas de Desarrollador(&T)"
       "&Increase Font Size":
-        value: "Increase Font Size(&I)"
+        value: "Aumentar Tamaño de la Fuente(&I)"
       "&Decrease Font Size":
-        value: "Decrease Font Size(&D)"
+        value: "Disminuir Tamaño de la Fuente(&D)"
       "Re&set Font Size":
-        value: "Reset Font Size(&S)"
+        value: "Restablecer Tamaño de la Fuente(&S)"
       "Toggle Soft &Wrap":
-        value: "Toggle Soft Wrap(&W)"
+        value: "Activar/Desactivar Soft Wrap(&W)"
       "Toggle Command Palette":
-        value: "Toggle Command Palette"
+        value: "Mostrar/Ocultar Paleta de Comandos"
       "Toggle Tree View":
-        value: "Toggle Tree View"
+        value: "Mostrar/Ocultar Tree View"
   "&Selection":
-    value: "Selection(&S)"
+    value: "Selección(&S)"
     submenu:
       "Add Selection &Above":
-        value: "Add Selection Above(&A)"
+        value: "Agregar Selección Arriba(&A)"
       "Add Selection &Below":
-        value: "Add Selection Below(&B)"
+        value: "Agregar Selección Abajo(&B)"
       "S&plit into Lines":
-        value: "Split into Lines(&P)"
+        value: "Dividir en Líneas(&P)"
       "Single Selection":
-        value: "Single Selection"
+        value: "Seleccionar Única"
       "Select to &Top":
-        value: "Select to Top(&T)"
+        value: "Seleccionar hasta Arriba(&T)"
       "Select to Botto&m":
-        value: "Select to Bottom(&M)"
+        value: "Seleccionar hasta Abajo(&M)"
       "Select &Line":
-        value: "Select Line(&L)"
+        value: "Seleccionar Línea(&L)"
       "Select &Word":
-        value: "Select Word(&W)"
+        value: "Seleccionar Palabra(&W)"
       "Select to Beginning of W&ord":
-        value: "Select to Beginning of Word(&O)"
+        value: "Seleccionar hasta el Inicio de la Palabra(&O)"
       "Select to Beginning of L&ine":
-        value: "Select to Beginning of Line(&I)"
+        value: "Seleccionar hasta el Inicio de la Línea(&I)"
       "Select to First &Character of Line":
-        value: "Select to First Character of Line(&C)"
+        value: "Seleccionar hasta el Primer Carácter de la Línea(&C)"
       "Select to End of Wor&d":
-        value: "Select to End of Word(&D)"
+        value: "Seleccionar hasta el Final de la Palabra(&D)"
       "Select to End of Lin&e":
-        value: "Select to End of Line(&E)"
+        value: "Seleccionar hasta el Final de la Línea(&E)"
       "Select Inside Brackets":
-        value: "Select Inside Brackets"
+        value: "Seleccionar Dentro de Corchetes"
   "F&ind":
-    value: "Find(&I)"
+    value: "Buscar(&I)"
     submenu:
       "Find in Buffer":
-        value: "検索"
+        value: "Buscar en Buffer"
       "Replace in Buffer":
-        value: "置換"
+        value: "Reemplazar en Buffer"
       "Select Next":
-        value: "Select Next"
+        value: "Seleccionar Siguiente"
       "Select All":
-        value: "Select All"
+        value: "Seleccionar Todo"
       "Toggle Find in Buffer":
-        value: "Toggle Find in Buffer"
+        value: "Mostrar/Ocultar Buscar en Buffer"
       "Find in Project":
-        value: "Find in Project"
+        value: "Buscar en Proyecto"
       "Toggle Find in Project":
-        value: "Toggle Find in Project"
+        value: "Mostrar/Ocultar Buscar en Proyecto"
       "Find Next":
-        value: "Find Next"
+        value: "Buscar Siguiente"
       "Find Previous":
-        value: "Find Previous"
+        value: "Buscar Anterior"
       "Replace Next":
-        value: "Replace Next"
+        value: "Reemplazar Siguiente"
       "Replace All":
-        value: "Replace All"
+        value: "Reemplazar Todo"
       "Clear History":
-        value: "Clear History"
+        value: "Limpiar Historial"
       "Find Buffer":
-        value: "Find Buffer"
+        value: "Buscar Buffer"
       "Find File":
-        value: "Find File"
+        value: "Buscar Archivo"
       "Find Modified File":
-        value: "Find Modified File"
+        value: "Buscar Archivo Modificado"
   "&Packages":
-    value: "Packages(&P)"
+    value: "Paquetes(&P)"
   "&Help":
-    value: "Help(&H)"
+    value: "Ayuda(&H)"
     submenu:
       "View &Terms of Use":
-        value: "View Terms of Use(&T)"
+        value: "Ver Términos de Uso(&T)"
       "View &License":
-        value: "View License(&L)"
+        value: "Ver Licencia(&L)"
       "&Documentation":
-        value: "Documentation(&D)"
+        value: "Documentación(&D)"
       "Frequently Asked Questions":
-        value: "Frequently Asked Questions"
+        value: "Preguntas Frecuentes"
       "Community Discussions":
-        value: "Community Discussions"
+        value: "Discussions de la Comunidad"
       "Report Issue":
-        value: "Report Issue"
+        value: "Reportar Problema"
       "Search Issues":
-        value: "Search Issues"
+        value: "Buscar Problema"
       "About Atom":
-        value: "About Atom"
+        value: "Acerca de Atom"
       "Welcome Guide":
-        value: "Welcome Guide"
+        value: "Guía de Bienvenida"


spawn and ignore stdio

spawn and ignore stdio

--- tasks/spec-ci.coffee
+++ tasks/spec-ci.coffee
@@ -13,11 +13,8 @@
     try
       done = @async()
       args = ["ci", "-f", path.resolve("#{process.cwd()}/config/spec.json")]
-      child = spawn(testemRunnerPath(), args)
-      output = ""
-      child.stdout.on "data", (chunk) ->
-        process.stdout.write(chunk)
-        output += chunk
+      options = { stdio: 'ignore'}
+      child = spawn(testemRunnerPath(), args, options)

       child.on "exit", (code, signal) ->
         if code != 0


Fix profile language is shown twice after submit

--- client/views/profile/profile.coffee
+++ client/views/profile/profile.coffee
@@ -16,8 +16,8 @@
   isDefaultGender: ->
     return "default" unless @profile.gender
   languageText: ->
-    return i18n "profile.#{@profile.language}" if @profile.language
-    return i18n "profile.chooseLanguage"
+    return i18n "profile.#{@.profile.language}" if @profile.language and not Session.get('reloadLanguage')
+    return i18n "profile.chooseLanguage" unless Session.get('reloadLanguage')
   isDefaultLanguage: ->
     return "default" unless @profile.language

@@ -51,6 +51,8 @@

     data = SimpleForm.processForm(event.target)

+    Session.set('reloadLanguage', true) if data.language
+
     data.gender = @profile.gender unless data.gender
     data.style = @profile.style unless data.style
     data.language = @profile.language unless data.language
@@ -83,3 +85,6 @@

   $('.ui.selection.dropdown')
     .dropdown()
+
+
+  Session.set('reloadLanguage', false) if Session.get('reloadLanguage')


disable redirect to team with code now that all teams are created

--- controllers/login.coffee
+++ controllers/login.coffee
@@ -32,7 +32,8 @@
             res.redirect "/people/#{req.person.id}"
       else
         res.redirect '/teams/new'
-  else if code = req.session.team
+  else if false and req.user.contestant and (code = req.session.team)
+    # no longer needed now that all teams are created
     Team.findOne code: code, (err, team) ->
       return next err if err
       if team


DRY up the teams controller                       [finishes #15726107]

--- controllers/teams.coffee
+++ controllers/teams.coffee
@@ -1,6 +1,25 @@
 _ = require 'underscore'
 app = require '../config/app'
 Team = app.db.model 'Team'
+
+# middleware
+loadTeam = (req, res, next) ->
+  if id = req.param('id')
+    Team.findById id, (err, team) ->
+      return next err if err
+      return res.send 404 unless team
+      req.team = team
+      next()
+
+loadPeople = (req, res, next) ->
+  req.team.people (err, people) ->
+    return next err if err
+    req.people = people
+    next()
+
+ensureAccess = (req, res, next) ->
+  return res.send 401 unless req.team.includes(req.user, req.session.team)
+  next()

 # index
 app.get '/teams', (req, res, next) ->
@@ -31,53 +50,28 @@
       res.redirect "/teams/#{team.id}"

 # show (join)
-app.get '/teams/:id', (req, res, next) ->
+app.get '/teams/:id', [loadTeam, loadPeople], (req, res) ->
   req.session.invite = req.param('invite') if req.param('invite')
-  Team.findById req.param('id'), (err, team) ->
-    return next err if err
-    return next() unless team
-    team.people (err, people) ->
-      return next err if err
-      res.render2 'teams/show',
-        team: team
-        people: people
+  res.render2 'teams/show', team: req.team, people: req.people

 # resend invitation
-app.all '/teams/:id/invite/:inviteId', (req, res, next) ->
-  return res.redirect '/auth/github' unless req.loggedIn
-
-  Team.findById req.param('id'), (err, team) ->
-    return next err if err
-    return next() unless team
-    return res.send 401 unless team.includes(req.user, req.session.team)
-    team.invites.id(req.param('inviteId')).send(true)
-    res.redirect "/teams/#{team.id}"
+app.all '/teams/:id/invite/:inviteId', [loadTeam, ensureAccess], (req, res) ->
+  req.team.invites.id(req.param('inviteId')).send(true)
+  res.redirect "/teams/#{req.team.id}"

 # edit
-app.get '/teams/:id/edit', (req, res, next) ->
-  Team.findById req.param('id'), (err, team) ->
-    return next err if err
-    return next() unless team
-    return res.send 401 unless team.includes(req.user, req.session.team)
-    team.people (err, people) ->
-      return next err if err
-      res.render2 'teams/edit', team: team, people: people
+app.get '/teams/:id/edit', [loadTeam, loadPeople, ensureAccess], (req, res) ->
+  res.render2 'teams/edit', team: req.team, people: req.people

 # update
-app.put '/teams/:id', (req, res, next) ->
-  return res.redirect '/auth/github' unless req.loggedIn
-
-  Team.findById req.param('id'), (err, team) ->
-    return next err if err
-    return next() unless team
-    return res.send 401 unless team.includes(req.user, req.session.team)
-    _.extend team, req.body
-    team.save (err) ->
-      return next err if err and err.name != 'ValidationError'
-      if team.errors
-        team.people (err, people) ->
-          return next err if err
-          res.render2 'teams/edit', team: team, people: people
-      else
-        res.redirect "/teams/#{team.id}"
+app.put '/teams/:id', [loadTeam, ensureAccess], (req, res, next) ->
+  _.extend req.team, req.body
+  req.team.save (err) ->
+    return next err if err and err.name != 'ValidationError'
+    if req.team.errors
+      req.team.people (err, people) ->
+        return next err if err
+        res.render2 'teams/edit', team: req.team, people: req.people
+    else
+      res.redirect "/teams/#{req.team.id}"
   null


Better user update API

Better user update API

--- controllers/users.coffee
+++ controllers/users.coffee
@@ -31,10 +31,10 @@
       res.end users

 exports.update = (req, res, next) ->
-  User.findByIdAndUpdate req.model._id,
-    status: req.model.status
-    disabled: req.model.disabled
-  , (err, user) ->
-    console.log user
+  changes = {}
+  changes.status = req.model.status if req.model.status?
+  changes.disabled = req.model.disabled if req.model.disabled?
+
+  User.findByIdAndUpdate req.model._id, changes, (err, user) ->
     return next(err) if err
     res.end user


d3 treemap: fixes

d3 treemap: fixes

--- app/assets/javascripts/d3/treemap.coffee
+++ app/assets/javascripts/d3/treemap.coffee
@@ -10,7 +10,7 @@
       D3.treemap.series.push @gquery

     # value is apparently a reserved name
-    val: => @gquery.future_value()
+    val: => @gquery.safe_future_value()

     label: => "#{@get('sector')} #{@get('carrier')}"

@@ -44,7 +44,7 @@

     draw: =>
       @width = 494
-      @height = @container_node().height() || 502
+      @height = 350
       @treemap = d3.layout.treemap()
         .size([@width, @height])
         .sticky(true)


minimize/maximize fixed

minimize/maximize fixed

--- app/assets/javascripts/sprints.js.coffee
+++ app/assets/javascripts/sprints.js.coffee
@@ -2,33 +2,19 @@
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

-minimize = (count, interval) ->
-  $('#userstory_details_box').queue 'myQueue', ->
-    $(this).delay count * 50, 'myQueue'
-    $(this).height($('#userstory_details_box').height() - interval)
-  .dequeue 'myQueue'
-
-maximize = (count, interval) ->
-  $('#userstory_details_box').queue 'myQueue', ->
-    $(this).delay count * 50, 'myQueue'
-    $(this).height($('#userstory_details_box').height() + interval)
-  .dequeue 'myQueue'
-
 $(document).ready ->

   $('#userstory_details_box').delegate '.ui-icon-minus', 'click', ->
-    interval = 10
-    endNumber = ($('#userstory_details_box').height() - $('.ui-tabs-nav').height()) / interval
-    minimize(count, interval) for count in [0..endNumber]
-    $(this).addClass 'ui-icon-plus'
-    $(this).removeClass 'ui-icon-minus'
+    $('#userstory_details_box').animate height: $('.ui-tabs-nav').height(), 1000
+    icon = $('#userstory_details_box .ui-icon-minus')
+    icon.addClass 'ui-icon-plus'
+    icon.removeClass 'ui-icon-minus'
     false

   $('#userstory_details_box').delegate '.ui-icon-plus', 'click', ->
-    interval = 10
-    endNumber = (150 - $('.ui-tabs-nav').height()) / interval
-    maximize(count, interval) for count in [0..endNumber]
-    $(this).addClass 'ui-icon-minus'
-    $(this).removeClass 'ui-icon-plus'
+    $('#userstory_details_box').animate height: 150, 1000
+    icon = $('#userstory_details_box .ui-icon-plus')
+    icon.addClass 'ui-icon-minus'
+    icon.removeClass 'ui-icon-plus'
     false


update the url when locations change, closes #48

--- app/assets/transit/lib/views/plan.coffee
+++ app/assets/transit/lib/views/plan.coffee
@@ -36,6 +36,10 @@
     @model.set
       from: @map.get('from').position.toHash()
       to: @map.get('to').position.toHash()
+    # update the url and history with new locations
+    from_url = @map.get('from').position.toUrlValue()
+    to_url = @map.get('to').position.toUrlValue()
+    Transit.router.navigate "plan/#{from_url}/#{to_url}"
     # then load the new plan
     @model.trigger 'fetch'


Mount static middleware for any sub-app/component

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -43,6 +43,7 @@
 logger = require 'morgan'
 apiCache = require './middleware/api_cache'
 raven = require 'raven'
+fs = require 'graceful-fs'

 # Setup sharify constants & require dependencies that use sharify data
 sharify.data =
@@ -214,7 +215,13 @@

   # Static files middleware
   app.use favicon(path.resolve __dirname, '../public/images/favicon.ico')
-  app.use express.static(path.resolve __dirname, "../public")
+
+  # Mount static middleware for sub apps, components, and project-wide
+  fs.readdirSync(path.resolve __dirname, '../apps').forEach (fld) ->
+    app.use express.static(path.resolve __dirname, "../apps/#{fld}/public")
+  fs.readdirSync(path.resolve __dirname, '../components').forEach (fld) ->
+    app.use express.static(path.resolve __dirname, "../components/#{fld}/public")
+  app.use express.static(path.resolve __dirname, '../public')

   if SENTRY_DSN
     client = new raven.Client SENTRY_DSN, {


Better message.

Better message.

--- app/client/js/react/pages/mysongs.coffee
+++ app/client/js/react/pages/mysongs.coffee
@@ -42,4 +42,6 @@
               , "Trash (#{deletedSongs.length})"

   @MSG_ADD_NEW_SONG: goog.getMsg 'New Song'
-  @MSG_NO_SONGS: goog.getMsg 'No songs.'
+  @MSG_NO_SONGS: goog.getMsg "
+    You have no songs stored on your device yet. Add or search one.
+  "


fix delete/restore comment in IE

fix delete/restore comment in IE

--- app/coffee/modules/common/history.coffee
+++ app/coffee/modules/common/history.coffee
@@ -333,11 +333,15 @@
             $el.find(".history section").toggleClass("hidden")

         $el.on "click", ".comment-delete", debounce 2000, (event) ->
+            event.preventDefault()
+
             target = angular.element(event.currentTarget)
             activityId = target.data('activity-id')
             $ctrl.deleteComment(type, objectId, activityId)

         $el.on "click", ".comment-restore", debounce 2000, (event) ->
+            event.preventDefault()
+
             target = angular.element(event.currentTarget)
             activityId = target.data('activity-id')
             $ctrl.undeleteComment(type, objectId, activityId)


reduce max file size (should probably reduce more)

--- src/smc-util/syncstring.coffee
+++ src/smc-util/syncstring.coffee
@@ -13,8 +13,8 @@
 [TODO: High level description of algorithm here, or link to article.]
 ###

-# How big of files can be opened
-MAX_FILE_SIZE_MB = 4
+# How big of files we allow users to open using syncstrings.
+MAX_FILE_SIZE_MB = 2

 # Client -- when it has this syncstring open and connected -- will touch the
 # syncstring every so often so that it stays opened in the local hub,


Sort buys by most recently run.

Sort buys by most recently run.

--- assets/javascripts/models/buy.coffee
+++ assets/javascripts/models/buy.coffee
@@ -18,7 +18,7 @@
   name: "buys"
   url: "/spending",
   model: POV.models.Buy,
-  comparator: (model) -> model.get('start_date')
+  comparator: (model) -> -model._start_date
   total_cost: ->
     this.reduce ((grand_total, buy) -> grand_total + buy.get 'total_cost'), 0
   sorter: (property) ->


if we maek content_type properly, jquery parses the json

--- assets/scripts/mandrill_merge.coffee
+++ assets/scripts/mandrill_merge.coffee
@@ -14,7 +14,7 @@
       params = $(this).serialize()
       callback = $(this).attr('ajax-callback')
       $.post(action, params).done((response) ->
-        window['MandrillMerge'].app[callback] jQuery.parseJSON(response)
+        window['MandrillMerge'].app[callback] response
       ).fail (response) ->
         alert 'something went wrong'
       e.preventDefault()


Close drowpdown on click outside

Close drowpdown on click outside

--- src/dropdown.coffee
+++ src/dropdown.coffee
@@ -7,12 +7,30 @@
     constructor: (@$document) ->

     open: (dropdownScope) =>
+      unless @openScope
+        @$document.bind('click', @onClick)
       @openScope.isOpen = false  if @openScope and @openScope isnt dropdownScope
       @openScope = dropdownScope

     close: (dropdownScope) =>
       if @openScope is dropdownScope
         @openScope = null
+        @$document.unbind('click', @onClick)
+
+    onClick: (event) =>
+      # This method may still be called during the same mouse event that
+      # unbound this event handler. So check @openScope before proceeding.
+      return unless @openScope
+
+      # Ignore clicks inside the dropdown
+      toggleElement = @openScope.getToggleElement()
+      return if toggleElement and toggleElement[0].contains(event.target)
+
+      @closeDropdown()
+
+    closeDropdown: (event) =>
+      @openScope.$apply =>
+        @openScope.isOpen = false
 ])

 .controller('DropdownController', [


Cleanup: Change if to unless when looking for an error

As per the coding standards requested by @enyo

--- src/dropzone.coffee
+++ src/dropzone.coffee
@@ -537,7 +537,7 @@
       @errorProcessing file, xhr.responseText || "Server responded with #{xhr.status} code."

     xhr.onload = (e) =>
-      if xhr.status < 200 or xhr.status >= 300
+      unless 200 <= xhr.status < 300
         handleError()
       else
         @emit "uploadprogress", file, 100


Delete log

Delete log

--- public/views/cart_detail_view.coffee
+++ public/views/cart_detail_view.coffee
@@ -78,7 +78,6 @@
     if @collection.isEmpty()
       @$(".epages-cart-overlay-is-empty").show()
     else
-      console.log @collection.storage.storage
       html = @collection.map (lineItem) ->
         view = new CartLineItemView(model: lineItem)
         view.render().el


Starting at the starting star.

Starting at the starting star.

--- src/game/states/game.coffee
+++ src/game/states/game.coffee
@@ -2,6 +2,7 @@
   {
     name: 'The Little Dipper',
     numStars: 7,
+    startingStar: 0,
     starsArray: [
         {x: 309, y: 40},
         {x: 257, y: 125},
@@ -14,6 +15,7 @@
   },{
     name: 'The Big Dipper',
     numStars: 7,
+    startingStar: 0,
     starsArray: [
         {x: 46, y: 275},
         {x: 142, y: 200},
@@ -27,6 +29,7 @@
   {
     name: 'The Plough',
     numStars: 9,
+    startingStar: 0,
     starsArray: [
         {x: 381, y: 409},
         {x: 215, y: 286},
@@ -49,17 +52,19 @@

   create: ->
     #setup game window
-    x = @game.width / 3
-    y = @game.height / 2
+    @levelnum = 0
+    @level = LEVELS[@levelnum]
+    x = @level.starsArray[@level.startingStar].x
+    y = @level.starsArray[@level.startingStar].y

     #add Sprites
     @game.add.sprite 0, 0, 'Plough'
     #Plot empty stars
+    @constellation = []
+    @levelcomplete = false
+    @drawConstellation(@level)
     @player = @add.sprite x, y, 'player'
     @player.scale.set 0.5,0.5
-    @constellation = []
-    @levelcomplete = false
-    @drawConstellation(LEVELS[0])

     #add sounds
     #@soundSputnik = @game.add.audio 'soundSputnik'
@@ -117,9 +122,12 @@

   drawConstellation: (level) ->
      console.log @constellation
-     for star in level.starsArray
+     for star, i in level.starsArray
         star = @add.sprite star.x, star.y, 'litstar'
-        star.alpha = 0.3
+        if i == level.startingStar
+             star.alpha = 1
+        else
+             star.alpha = 0.3
         star.anchor.setTo 0.5, 0.5
         star.scale.set 0.5, 0.5
         @constellation.push(star)


disable second test for now

disable second test for now

--- test/flickr_test.coffee
+++ test/flickr_test.coffee
@@ -26,4 +26,5 @@
     test.expect(1)
     # tests here
     test.equal(flickr.awesome(), 'awesome', 'should be awesome.')
+#    test.equal(flickr.get_f(), 'client', 'should be awesome.')
     test.done()


adding elapsedTime

adding elapsedTime

--- test/game_object.coffee
+++ test/game_object.coffee
@@ -42,7 +42,7 @@
   gameObject = GameObject()

   gameObject.bind "update", (t) ->
-
+    equals t

 test "[event] destroy", 2, ->
   GameObject


Groups: autoupdate is regressed from group member search

--- client/Dashboard/views/groupsmemberpermissionsview.coffee
+++ client/Dashboard/views/groupsmemberpermissionsview.coffee
@@ -19,9 +19,6 @@
       callback     : =>
         @emit 'SearchInputChanged', @search.getValue()
         @search.focus()
-      keyup        : =>
-        return unless @search.getValue() is ""
-        @emit 'SearchInputChanged', ''

     @searchIcon = new KDCustomHTMLView
       tagName  : 'span'


homepage copy: correct english for education and business slides

I still think we should come up with better copy for these slides tho.

--- client/app/Applications/Home.kdapplication/AppView.coffee
+++ client/app/Applications/Home.kdapplication/AppView.coffee
@@ -56,7 +56,7 @@
                    Koding for Education

-                  Have a group where your students enjoy the resources you provide to them. Have it private, invite-only, let them share, collaborate and submit their assignments together.10 students, or 10,000. Just 1 or 100s of computers.
+                  Create a group where your students enjoy the resources you provide to them. Make it private or invite-only.  Let them share, collaborate and submit their assignments together.  It doesn't matter if you have ten students, or ten thousand.  Scale from just one to hundreds of computers.

                   Koding is your new classroom.
@@ -74,7 +74,7 @@
                    Koding for Business

-                  When you hire someone, let them be in your environment in 5 minutes, collaborating with others, contributing code without sharing ssh keys, passwords. Stop cc'ing your team, stop looking for emails.
+                  When you hire someone, they can get up to speed in your development environment in 5 minutes—easily collaborating with others and contributing code.  All without sharing ssh keys or passwords.  Stop cc'ing your team; stop searching through old emails.

                   Koding is your new workspace.


Created new IntroductionTooltipController. Finalised v1.

--- client/landing/app/CommonViews/introductiontooltip.coffee
+++ client/landing/app/CommonViews/introductiontooltip.coffee
@@ -4,55 +4,114 @@

     super options, data

-    introData = @getData() or @getIntroData() # make sure we have the data
-    return unless introData # we know introId but we have no JIntroSnippet for this view, should return
-    @setData introData unless @getData() # we just know the intro view and should find the data, called from viewAppended
+    {tooltipView, parentView} = @getOptions()

-    {@introId} = @getData() # we have an intro view and data for this view, go on!
-    @storage   = @getSingleton("mainController").introductionTooltipStatusStorage # to store tooltip status
-    return if @shouldNotDisplay() # user has already closed this introduction before, so don't show it again
-
-    parentView = @getOptions().parentView or @getParentView() # we came from db query and don't know the view, should find
-    return unless parentView # view not appended to dom yet, probably came from db query
-
-    view       = null
-    try view   = eval Encoder.htmlDecode @getData().snippet.split("@").join("this.") # trying to eval snippet
-    return unless view instanceof KDView # we will add this as a subview, should be a KDView instance
-
-    view.addSubView @closeButton = new KDCustomHTMLView
+    tooltipView.addSubView @closeButton = new KDCustomHTMLView
       tagName  : "span"
       cssClass : "close-icon"
       click    : => @close()

-    parentView.setTooltip {
-      view,
-      cssClass: "introduction-tooltip"
-    }
+    parentView.setTooltip
+      view     : tooltipView
+      cssClass : "introduction-tooltip"
+      sticky   : yes
+
     @utils.defer =>
       parentView.tooltip.show()

   close: ->
-    @storage.setValue @introId, yes
+    @emit "IntroductionTooltipClosed"

-  shouldNotDisplay: ->
-    return @storage.getValue(@introId) is yes

-  getIntroData: ->
-    {introSnippets} = @getSingleton "mainController"
+class IntroductionTooltipController extends KDController
+
+  constructor: (options = {}, data) ->
+
+    super options, data
+
+    @shouldAddOverlay = no
+    @visibleTooltips  = []
+
+    @getSingleton("mainController").on "FrameworkIsReady", =>
+      @init()
+
+  init: ->
+    KD.remote.api.JIntroSnippet.fetchAll (err, snippets) =>
+      return log err if err # TODO: error handling
+
+      @introductionTooltipStatusStorage = new AppStorage "IntroductionTooltipStatus"
+      @introductionTooltipStatusStorage.fetchStorage (storage) =>
+        @introSnippets = snippets
+        for snippet in snippets
+          @shouldAddOverlay = yes if snippet.overlay
+          for item in snippet.snippets
+            item.expiryDate = snippet.expiryDate
+            @createInstance null, item
+
+        # @addOverlay() if @shouldAddOverlay and @visibleTooltips.length > 0
+
+  createInstance: (parentView, data) ->
+    assets = @getAssets parentView, data
+    return unless assets
+
+    {parentView, tooltipView} = assets
+    tooltip = new IntroductionTooltip {
+      parentView
+      tooltipView
+    }
+    , assets.data
+
+    @visibleTooltips.push tooltip
+
+    tooltip.on "IntroductionTooltipClosed", =>
+      @close parentView.getOptions().introId
+      parentView.tooltip.destroy()
+      @visibleTooltips.splice @visibleTooltips.indexOf(tooltip), 1
+
+  getAssets: (parentView, data) ->
+    return no if not @introSnippets
+
+    introData = data or @getIntroData parentView # make sure we have the data
+    if not data and introData # we just know the intro view and should find the data, called from viewAppended
+      @setData introData
+      data = introData
+    return no unless data # we know introId but we have no JIntroSnippet for this view, should return
+
+    {introId} = data # we have an intro view and data for this view, go on!
+    @storage  = @introductionTooltipStatusStorage # to store tooltip status
+    return no if @shouldNotDisplay introId # user has already closed this introduction before, so don't show it again
+
+    parentView = parentView or @getParentView data # we came from db query and don't know the view, should find
+    return no unless parentView # view not appended to dom yet, probably came from db query
+
+    tooltipView = null
+    try tooltipView = eval Encoder.htmlDecode data.snippet.split("@").join("this.") # trying to eval snippet
+    return no unless tooltipView instanceof KDView # we will add this as a subview, should be a KDView instance
+
+    return { parentView, tooltipView, data }
+
+  shouldNotDisplay: (introId) ->
+    return @storage.getValue(introId) is yes
+
+  getIntroData: (parentView) ->
+    {introId} = parentView.getOptions()
+    {introSnippets} = @
     ourSnippet = null
     for introSnippet in introSnippets
       for snippet in introSnippet.snippets
-        if @getOptions().parentView?.getOptions().introId is snippet.introId
+        if introId is snippet.introId
           ourSnippet = snippet
-      return ourSnippet
+    return ourSnippet

-  getParentView: ->
-    view      = null
-    {introId} = @getData()
-    instances = KD.introInstances
+  getParentView: (data) ->
+    return KD.introInstances[data.introId] or null

-    for key, instance of instances
-      if instance.getOptions().introId is introId
-        view = instance
+  close: (tooltipIntroId) ->
+    @storage.setValue tooltipIntroId, yes

-    return view+  addOverlay: ->
+    @overlay = $ "<div/>",
+      class : "kdoverlay"
+    @overlay.hide()
+    @overlay.appendTo "body"
+    @overlay.fadeIn 200


stop keyboard event when using o shortcut

--- app/js/views/notification_details.coffee
+++ app/js/views/notification_details.coffee
@@ -42,6 +42,7 @@

   # Go to the page on GitHub for this notification
   open: (e) ->
+    e.preventDefault()
     window.open @subject.url(), '_blank'

   # Focus the reply textarea


fix sable antelope

fix sable antelope

--- app/lib/field-guide-content/index.coffee
+++ app/lib/field-guide-content/index.coffee
@@ -30,7 +30,7 @@
     pangolin: require './pangolin'
     porcupine: require './porcupine'
     reedbuck: require './reedbuck'
-    sable_antelope: require './sable'
+    sable_antelope: require './sable_antelope'
     samango_monkey: require './samango_monkey'
     serval: require './serval'
     vervet: require './vervet'


added csv output

added csv output

--- src/git-timetracking.coffee
+++ src/git-timetracking.coffee
@@ -4,7 +4,7 @@
 spawn = childProcess.spawn
 cliTable = require "cli-table"

-outputPossibilities = ["csv", "ascii"]
+outputPossibilities = ["ascii", "csv"]

 defaultOutputFormat = outputPossibilities[0]
 defaultPauseTime = 20
@@ -56,7 +56,7 @@
 	return "#{h}:#{m}:#{s}"

-outputSummary = (data, total, grouped) ->
+outputAscii = (data, total, grouped) ->
 	table = new cliTable
 		head: ['Issue', 'Time spent', 'Commit count']
 		colWidth: [100,100,100]
@@ -67,6 +67,13 @@

 	table.push ["TOTAL:",formatTimeToString(total),data.length]
 	console.log table.toString()
+
+outputCsv = (data, total, grouped) ->
+	console.log "Issue;Time;Count"
+	if grouped?
+		for k,v of grouped
+			console.log "#{k};" + formatTimeToString(v.effort) + ";#{v.count}"
+	console.log "TOTAL;" + formatTimeToString(total) + ";#{data.length}"

 calcTime = (data) ->
@@ -121,10 +128,9 @@
 					grouped["other"].count++
 					grouped["other"].effort += commit.effort

-	if program.group?
-		outputSummary data, total, grouped
-	else
-		outputSummary data, total
+	switch program.output
+		when "ascii" then outputAscii data, total, grouped
+		when "csv" then outputCsv data, total, grouped

 	process.exit()


improve isURL regex

improve isURL regex

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -136,9 +136,9 @@
     throw new Error("Cannot find reference tag for specified link")

 URL_REGEX = ///
-  ^(https?|ftp):\/\/
-  [^\s\/$.?#].
-  [^\s]*$
+  ^(?:\w+:)?\/\/
+  ([^\s\.]+\.\S{2}|localhost[\:?\d]*)
+  \S*$
   ///i

 isUrl = (url) -> URL_REGEX.test(url)


KDFramework: KDView::destroy fixed

KDFramework: KDView::destroy fixed

--- core/KDView.coffee
+++ core/KDView.coffee
@@ -371,8 +371,9 @@
     @destroySubViews()  if @getSubViews().length > 0

     # instance drops itself from its parent's subviews array
-    if @parent?.subViews and index = @parent.subViews.indexOf @ >= 0
-        @subViews.splice index, 1
+
+    if @parent?.subViews and (index = @parent.subViews.indexOf @) >= 0
+        @parent.subViews.splice index, 1
         @unsetParent()

     # instance removes itself from DOM


remove debug js logging

remove debug js logging

--- www/src/models/stencil.coffee
+++ www/src/models/stencil.coffee
@@ -10,9 +10,7 @@
             mixpanel.track "take stencil"
             $.post("#{ @url() }/take")
             .success =>
-                console.log "posted"
                 @fetch().success =>
-                    console.log "fetched"
                     success()

         myQuests: ->


Renamed trigger to publish

Renamed trigger to publish

--- src/eventbus.coffee
+++ src/eventbus.coffee
@@ -1,5 +1,6 @@
 class EventBus
-	constructor : ({@debug} = options) ->
+	constructor : (options) ->
+		@debug = options?.debug
 		@bus = []
 		@registrationId = 0
 		@id = 0
@@ -18,9 +19,9 @@
 		console.log "EventBus: (#{eventName}): new subscription - #{stack} (#{id})" if @debug
 		id

-	trigger: (eventName, parameter) =>
+	publish: (eventName, parameter) =>
 		id = ++@id
-		console.log "EventBus: event #{id} (#{eventName}): triggered event #{eventName} from #{@getStack()}" if @debug
+		console.log "EventBus: event #{id} (#{eventName}): published event #{eventName} from #{@getStack()}" if @debug
 		return console.log "EventBus: event #{id} (#{eventName}): no subscription" if @debug and !@bus[eventName]
 		for regid, callback of @bus[eventName]
 			console.log "EventBus: event #{id} (#{eventName}): calling #{callback.stack} (#{regid})" if @debug


adjust message

adjust message

--- content/gitoe-repo.coffee
+++ content/gitoe-repo.coffee
@@ -270,14 +270,14 @@
           @git_command "git push"
           @span ": update "
           @ref_fullname change
+          @span " to "
+          @span change.oid_new, "sha1_commit"
           if change.oid_old isnt "0000000000000000000000000000000000000000"
             @span " ( was "
           if change.oid_old isnt "0000000000000000000000000000000000000000"
             @span change.oid_old, "sha1_commit"
           if change.oid_old isnt "0000000000000000000000000000000000000000"
             @span " )"
-          @span " to "
-          @span change.oid_new, "sha1_commit"
         ]
       fetch: (matched, change)->
         @li [


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine.coffee
+++ test/engine.coffee
@@ -180,7 +180,7 @@

   engine.collides(Rectangle(0, 0, 10, 10), null)

-test "#setState", ->
+test "#setState", 3, ->
   engine = Engine()

   nextState = GameState()


update help

update help

--- src/factoids.coffee
+++ src/factoids.coffee
@@ -15,6 +15,8 @@
 #   hubot learn <factoid> =~ s/expression/replace/gi - edit a factoid
 #   hubot alias <factoid> = <factoid>
 #   hubot forget <factoid> - forget a factoid
+#   hubot remember <factoid> - remember a factoid
+#   hubot drop <factoid> - permanently forget a factoid
 #   hubot factoids - get a link to the raw factoid data
 #   !<factoid> - play back a factoid
 #


update w3d product description and link to tech specs

--- assets/coffeescript/product_list.coffee
+++ assets/coffeescript/product_list.coffee
@@ -38,11 +38,11 @@
     w3d:
       id: 'w3d'
       title_store: '3d'
-      description_store: "Intel RealSense R200 RGBD camera. Provides stereo RGB images and depth image."
-      tech_specs:
-        sensor: "See Intel R200 Docs for details"
-        fov: "See Intel R200 Docs for details"
-        latency: "See Intel R200 Docs for details"
+      description_store: "Intel RealSense R200 RGBD camera. Provides depth image and monocular RGB color image."
+      tech_specs:
+        sensor: "See Intel R200 data sheet for details"
+        fov:"See Intel R200 data sheet for details"
+        latency: "See Intel R200 data sheet for details"
         audio: "Record audio via host device microphone"
       title_cart: "World Camera: 3d"
       description_cart: "Intel RealSense R200. Provides stereo RGB images and depth image."


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -16,7 +16,7 @@
   enemy.include(Follow)
   enemy.follow(player)

-  ok enemy.I.velocity.equal(Point(1, 0)), 'enemy should head toward pla'
+  ok enemy.I.velocity.equal(Point(1, 0)), 'enemy should head toward player with '

   fastEnemy = GameObject
     x: 50


Tweak vomnibar for custom search.

Tweak vomnibar for custom search.

This applies only to custom searches for which we have a completion engine.

Status quo: Exclusively offer suggestions generated by this completer.

This PR: Also include other suggestions (e.g. history) if their URL and
query match this custom search engine.

--- background_scripts/completion.coffee
+++ background_scripts/completion.coffee
@@ -362,17 +362,13 @@
     CompletionSearch.cancel()

   # This looks up the custom search engine and, if one is found, notes it and removes its keyword from the
-  # query terms.  It also sets request.completers to indicate that only this completer should run (but only if
-  # it finds a completion engine).
+  # query terms.
   triageRequest: (request) ->
     @searchEngines.use (engines) =>
       { queryTerms, query } = request
       keyword = queryTerms[0]
       # Note. For a keyword "w", we match "w search terms" and "w ", but not "w" on its own.
       if keyword and engines[keyword] and (1 < queryTerms.length or /\s$/.test query)
-        # This is a query for a custom search engine.  If we have a completion engine, then we *only* want
-        # suggestions from SearchEngineCompleter.
-        request.completers = [ this ] if CompletionSearch.haveCompletionEngine engines[keyword].searchUrl
         extend request,
           queryTerms: queryTerms[1..]
           keyword: keyword
@@ -395,6 +391,7 @@
           keyword: keyword
           searchUrl: url
           description: description
+          searchUrlPrefix: url.split("%s")[0]

       callback engines

@@ -441,11 +438,22 @@

     # This distinguishes two very different kinds of vomnibar baviours, the newer bahviour (true) and the
     # legacy behavior (false).  We retain the latter for the default search engine, and for custom search
-    # engines for which we do not have a completion engine.  By "exclusive vomnibar", we mean suggestions
-    # from other completers are suppressed (so the vomnibar "exclusively" uses suggestions from this search
-    # engine).
+    # engines for which we do not have a completion engine.  By "exclusive vomnibar", we mean that
+    # this completer exclusively controls which suggestions may or may not be included, including filtering
+    # out suggestions from other completers.
     useExclusiveVomnibar = custom and haveCompletionEngine
-    filter = if useExclusiveVomnibar then (suggestion) -> suggestion.type == description else null
+
+    filter = null
+    if useExclusiveVomnibar
+      # We accept suggestions from this completer; and we also accept suggestions from other completers, but
+      # only if their URL matches this search engine and the query (ie. they could have been generated by this
+      # search engine previously).
+      filter = (suggestion) ->
+        suggestion.type == description or
+          # This is a suggestion for the same search engine.
+          (suggestion.url.startsWith(engine.searchUrlPrefix) and
+            # And the URL suffix (which must contain the query part) matches the current query.
+            RankingUtils.matches queryTerms, suggestion.url[engine.searchUrlPrefix.length..])

     # For custom search engines, we add a single, top-ranked entry for the unmodified query.  This
     # suggestion always appears at the top of the list.
@@ -514,13 +522,8 @@
     return @mostRecentQuery = arguments if @filterInProgress

     # Provide each completer with an opportunity to see (and possibly alter) the request before it is
-    # launched.  Each completer is also provided with a list of all of the completers we're using
-    # (request.completers), and may change that list to override the default (for example, the
-    # search-engine completer does this if it wants to be the *only* completer).
-    request.completers = @completers
+    # launched.
     completer.triageRequest? request for completer in @completers
-    completers = request.completers
-    delete request.completers

     RegexpCache.clear()
     { queryTerms } = request
@@ -529,7 +532,7 @@
     [ suggestions, continuations, filters ] = [ [], [], [] ]

     # Run each of the completers (asynchronously).
-    jobs = new JobRunner completers.map (completer) ->
+    jobs = new JobRunner @completers.map (completer) ->
       (callback) ->
         completer.filter request, (newSuggestions = [], { continuation, filter } = {}) ->
           suggestions.push newSuggestions...


Added count

Added count

--- src/builtin/string.coffee
+++ src/builtin/string.coffee
@@ -29,6 +29,18 @@
       return pad + @value + pad
     else
       return pad + @value + pad + fillchar
+
+  count: (sub, start = 0, end = sub.length) ->
+    count = 0
+    curIndex = start
+    while curIndex < end
+      substringIndex = @value.indexOf(sub, curIndex)
+      if substringIndex < 0
+        break
+      else
+        curIndex = substringIndex + sub.__len__
+        count++
+    return count

   isalpha: ->
     alphas = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'


remove unused method

remove unused method

--- test/parser.coffee
+++ test/parser.coffee
@@ -8,16 +8,6 @@
   opts.compiler ?= CoffeeScript

   HamletCompiler.compile source, opts
-
-schwaza = (template, data) ->
-  code = "return " + compile(template)
-
-  fragment = Function("Runtime", code)(Runtime)(data)
-
-  div = document.createElement("div")
-  div.appendChild fragment
-
-  return div

 compileDirectory = (directory, mode) ->
   fs.readdirSync(directory).forEach (file) ->


Added SI unit support via environment variable.

--- src/forecast.coffee
+++ src/forecast.coffee
@@ -9,6 +9,7 @@
 #   HUBOT_LATITUDE - Latitude in decimal degrees
 #   HUBOT_LONGITUDE - Longitude in decimal degrees
 #   HUBOT_SLACK_BOTNAME - (Optional) Botname in slack
+#   HUBOT_FORECAST_UNITS - (Optional) Units to use. Use either 'us' or 'si'. Defaults to 'si'.
 #
 # Commands:
 #   hubot weather - shows brief weather forecast from last cached data
@@ -278,10 +279,11 @@
   fetchForecast = (callback) ->

     forecastKey = process.env.HUBOT_FORECAST_KEY
+    unitType = process.env.HUBOT_FORECAST_UNITS || 'si'
     exclude = 'flags'

     base_url = "https://api.forecast.io/forecast/#{forecastKey}/#{LOCATION}"
-    url = "#{base_url}?units=us&exclude=#{exclude}"
+    url = "#{base_url}?units=#{unitType}&exclude=#{exclude}"

     console.log "[Forecast] Requesting forecast data: #{url}"

@@ -353,7 +355,11 @@
   forecast()

   processLast = (msg, last_json) ->
-    response = "Currently: #{last_json.currently.summary} #{last_json.currently.temperature}°F"
+    unitType = process.env.HUBOT_FORECAST_UNITS || 'si'
+    temperatureUnit = "C"
+    if unitType == "us"
+      temperatureUnit = "F"
+    response = "Currently: #{last_json.currently.summary} #{last_json.currently.temperature}°#{temperatureUnit}"
     response += "\nToday: #{last_json.hourly.summary}"
     response += "\nComing week: #{last_json.daily.summary}"
     if robot.adapterName == 'slack'


add validation

add validation

--- src/fotolife.coffee
+++ src/fotolife.coffee
@@ -43,6 +43,8 @@
   #   Promise
   create: ({ file, title, type, folder, generator }, callback) ->
     return @_reject('options.file is required', callback) unless file?
+    unless fs.existsSync(file)
+      return @_reject('options.file does not exist', callback)
     title = title ? ''
     type = type ? mime.lookup(file)
     encoded = fs.readFileSync(file).toString('base64')


LEV-23 fixed cleanup issues

LEV-23 fixed cleanup issues

--- modules/levelcreator/app/assets/javascripts/level_creator/data_handler.coffee
+++ modules/levelcreator/app/assets/javascripts/level_creator/data_handler.coffee
@@ -35,7 +35,7 @@

     Request.send(
       _.extend(
-        Routes.controllers.levelcreator.ArbitraryBinaryData.missionViaAjax(@dataSetName, @levelId, @missionId, "color")
+        Routes.controllers.levelcreator.BinaryData.viaAjax(@dataSetName, @levelId, @missionId, "color")
         dataType : "arraybuffer"
       )
     ).then(
@@ -48,7 +48,7 @@

     Request.send(
       _.extend(
-        Routes.controllers.levelcreator.ArbitraryBinaryData.missionViaAjax(@dataSetName, @levelId, @missionId, "segmentation")
+        Routes.controllers.levelcreator.BinaryData.viaAjax(@dataSetName, @levelId, @missionId, "segmentation")
         dataType : "arraybuffer"
       )
     ).then(
@@ -61,7 +61,7 @@

     Request.send(
       _.extend(
-        Routes.controllers.levelcreator.ArbitraryBinaryData.missionViaAjax(@dataSetName, @levelId, @missionId, "classification")
+        Routes.controllers.levelcreator.BinaryData.viaAjax(@dataSetName, @levelId, @missionId, "classification")
         dataType : "arraybuffer"
       )
     ).then(


cooldown finilazation

cooldown finilazation

--- test/cooldown.coffee
+++ test/cooldown.coffee
@@ -7,7 +7,7 @@
       bullet:
         target: 3
         approachBy: 1
-        value:
+        value: 95

   obj.include(Cooldown)


cooldown finilazation

cooldown finilazation

--- test/cooldown.coffee
+++ test/cooldown.coffee
@@ -108,6 +108,6 @@
   obj.cooldown 'health',
     target: 10

-  ob
+  obj.update

 module()


download: update tests

download: update tests

--- test/download.coffee
+++ test/download.coffee
@@ -173,7 +173,6 @@
         destination = "#{scratch}/check_md5"
         mecano.download
           ssh: ssh
-          cache_file: false
           source: source
           destination: destination
           md5: '2f74dbbee4142b7366c93b115f914fff'
@@ -187,7 +186,6 @@
         destination = "#{scratch}/check_md5"
         mecano.download
           ssh: ssh
-          cache_file: false
           source: source
           destination: destination
           md5: 'df8fede7ff71608e24a5576326e41c75'
@@ -202,7 +200,6 @@
         destination = "#{scratch}/check_md5"
         mecano
           ssh: ssh
-          cache_dir: false
         .download
           source: source
           destination: destination
@@ -249,7 +246,6 @@
       destination = "#{scratch}/download_test"
       mecano
         ssh: ssh
-        cache_dir: false
       .download
         source: source
         destination: destination # Download a non existing file
@@ -275,7 +271,6 @@
       # Download a non existing file
       mecano
         ssh: ssh
-        cache_dir: false
       .download
         source: source
         destination: destination


Update statistics when model changes

Update statistics when model changes

--- core/app/backbone/views/users/user_statistics_view.coffee
+++ core/app/backbone/views/users/user_statistics_view.coffee
@@ -1,3 +1,6 @@
 class window.UserStatisticsView extends Backbone.Marionette.ItemView
   className: 'statistics'
   template: 'users/statistics'
+
+  initialize: ->
+    @listenTo @model, 'change', @render


clean up users table

clean up users table

--- test/seeder.coffee
+++ test/seeder.coffee
@@ -29,6 +29,9 @@
           knex('users').insert id: 1, name: 'foo'
           knex('users').insert id: 2, name: 'bar'
         ]
+
+    afterEach ->
+      knex('users').del()

     it 'import the seed failed', ->
       @timeout 10000


Fix reflection when chained after a resize

--- src/coffee/obscura.coffee
+++ src/coffee/obscura.coffee
@@ -211,30 +211,31 @@
         @context.globalCompositeOperation = 'source-over'

         startPos =
-          x:0
-          y:0
+            x:0
+            y:0

         targetPos =
-          x:0
-          y:0
-
+            x:0
+            y:0
+
+        currentDimensions = JSON.parse(JSON.stringify(@imageDimensions))
         {w,h} = @imageDimensions
         @context.drawImage(@target,0,0)
+
         if direction is 'vertical'
-          h = @imageDimensions.h * reflectionAmount
-          @dimensions.h = @imageDimensions.h + gap + h
-          gradientContext.translate(0,h)
-          gradientContext.scale(1,-1)
-          @context.translate(0,h)
-          @context.scale(1,-1)
-          targetPos.y = @dimensions.h
-          startPos.y = @imageDimensions.h-h
-
-        gradientImageData = gradientContext.getImageData(0, 0, w, h);
-
+            h = @imageDimensions.h * reflectionAmount
+            @dimensions.h = @imageDimensions.h + gap + h
+            gradientContext.translate(0,h)
+            gradientContext.scale(1,-1)
+            @context.translate(0,h)
+            @context.scale(1,-1)
+            targetPos.y = @dimensions.h
+            startPos.y = currentDimensions.h-h
+
+        w = Math.floor(w)
+        h = Math.floor(h)
         gradientContext.drawImage(@target,startPos.x,startPos.y,w,h,0,0,w,h)

-        imageData = @context.getImageData(0,0,w,h)
         reflectionImageData = gradientContext.getImageData(0,0,w,h)
         opacity=1

@@ -242,18 +243,17 @@
         row = 1;
         alphaStep = (255*alphaStart)/h
         until row > h
-          until col > w
-            alpha = reflectionImageData.data[((row*(w*4)) + (col*4)) + 3]
-            alpha = Math.min(alpha,((h-(row-1))*alphaStep))
-            reflectionImageData.data[((row*(w*4)) + (col*4)) + 3] = alpha
-            col++
-          col=1
-          row++
-
-        @context.putImageData(reflectionImageData, 0,@imageDimensions.h)
-
-        @imageDimensions = @dimensions
-
+            until col > w
+                alpha = reflectionImageData.data[((row*(w*4)) + (col*4)) + 3]
+                alpha = Math.min(alpha,((h-(row-1))*alphaStep))
+                reflectionImageData.data[((row*(w*4)) + (col*4)) + 3] = alpha
+                col++
+            col=1
+            row++
+
+        @context.putImageData(reflectionImageData, 0,currentDimensions.h)
+
+        @imageDimensions = @dimensions

         @render()
         @context.restore()


Store Qualities as Instantiated

Store Qualities as Instantiated

I just know this Instantiator thing is going to turn into a big mess
before all is said and done, but I don't yet see the path through it.
Maybe in time…

--- src/coffee/quality.coffee
+++ src/coffee/quality.coffee
@@ -1,12 +1,12 @@
 class Quality
   constructor: (@name, @description, @defaultValue, @defaultProgress, @maxProgress) ->

-angular.module 'qbn.quality', []
-  .factory 'qualityLibrary', () ->
+angular.module 'qbn.quality', ['qbn.instantiator']
+  .factory 'qualityLibrary', (instantiator) ->
     library = {}
     api =
       register: (id, name, options) ->
-        quality = new Quality()
+        quality = instantiator new Quality()
         library[id] = Object.freeze(quality)
         return this # Allow Chaining
       resolve: (q) ->


fixes stray = instead of == and adds linux case to terminal launching

--- lib/connection/terminal.coffee
+++ lib/connection/terminal.coffee
@@ -15,8 +15,11 @@
     if process.platform == "darwin"
       @exec "osascript -e 'tell application \"Terminal\" to activate'"
       @exec "osascript -e 'tell application \"Terminal\" to do script \"#{@escape(sh)}\"'"
-    else if process.platform = "windows"
+    else if process.platform == "windows"
       @exec "cmd /C start cmd /C #{@escape(sh)}"
+    else if process.platform == "linux"
+      # probably debian-specific
+      @exec "x-terminal-emulator -e \"#{@escape(sh)}\""
     else
       console.log 'unsupported platform'


Remove unused import

Remove unused import

--- bokehjs/src/coffee/api/figure.coffee
+++ bokehjs/src/coffee/api/figure.coffee
@@ -4,7 +4,6 @@
 FactorRange = require "../range/factor_range"
 Range1d = require "../range/range1d"
 ColumnDataSource = require "../source/column_data_source"
-helpers = "./helpers"

 Collections = base.Collections
 logger = Logging.logger


Testimonial quote should stay up for 9 seconds

--- desktop/apps/gallery_partnerships2/client/index.coffee
+++ desktop/apps/gallery_partnerships2/client/index.coffee
@@ -9,7 +9,7 @@
     $('.gallery-partnerships2__chat__fallback_image').show()

   initCarousel $('.js-partner-stats-slideshow'), { autoPlay: 2500, wrapAround: true, draggable: false }
-  initCarousel $('.js-partner-testimonials-slideshow'), { autoPlay: 3000, wrapAround: true, prevNextButtons: false }
+  initCarousel $('.js-partner-testimonials-slideshow'), { autoPlay: 9000, wrapAround: true, prevNextButtons: false }

   $('.gallery-partnerships2__connect-with-collectors__image').waypoint ((direction) ->
     $('.gallery-partnerships2__connect-with-collectors__sub_image').css(display: 'inline', animation: 'popup 0.2s') if direction == 'down'


Add more gifs

Add more gifs

--- src/highfive.coffee
+++ src/highfive.coffee
@@ -210,4 +210,30 @@
     'http://i.giphy.com/WdxAL8nmOCQ5a.gif',
     'http://a.fod4.com/images/GifGuide/dancing/tumblr_llatbbCeky1qbnthu.gif',
     'http://i.giphy.com/FrDlVZMD96nzG.gif',
+    'http://i.giphy.com/lcYFNTaz4U9jy.gif',
+    'http://i.giphy.com/Dwu7IpRyVA5Nu.gif',
+    'http://i.giphy.com/JQNM4AgN7lFUA.gif',
+    'http://i.giphy.com/9MGNxEMdWB2tq.gif',
+    'http://i.giphy.com/V5VZ64VJp1neo.gif',
+    'http://i.giphy.com/LdnaND03GRE9q.gif',
+    'http://i.giphy.com/2FazevvcDdyrf1E7C.gif',
+    'http://i.giphy.com/il5XqHUQxAdVe.gif',
+    'http://i.giphy.com/2AlVpRyjAAN2.gif',
+    'http://i.giphy.com/r2BtghAUTmpP2.gif',
+    'http://i.giphy.com/fD2tbCl4snSi4.gif',
+    'http://persephonemagazine.com/wp-content/uploads/2013/02/borat-letterman-high-five.gif',
+    'http://i.giphy.com/10ThjPOApliaSA.gif',
+    'http://i.giphy.com/14rRtgywkOitDa.gif',
+    'http://i.giphy.com/rM9Cl7MZphBqU.gif',
+    'http://i.giphy.com/t8JeALG3O5SPS.gif',
+    'http://i.giphy.com/rSCVJasn8uZP2.gif',
+    'http://i.giphy.com/10LKovKon8DENq.gif',
+    'http://i.giphy.com/M9TuBZs3LIQz6.gif',
+    'http://i.giphy.com/Ch7el3epcW3Wo.gif',
+    'http://i.giphy.com/1HPzxMBCTvjMs.gif',
+    'http://i.giphy.com/BP9eSu9cnnGN2.gif',
+    'http://i.giphy.com/vuFJaBLVTtnZS.gif',
+    'http://i.giphy.com/PTJGTImkgRycU.gif',
+    'http://i.giphy.com/l41lHvfYqxWus1oYw.gif',
+    'http://i.giphy.com/xIhGpmuVtuEpi.gif',
 ]


re-impl holdWhen again. Now it's really fast.

--- src/holdwhen.coffee
+++ src/holdwhen.coffee
@@ -3,23 +3,32 @@
 # build-dependencies: once

 Bacon.EventStream :: holdWhen = (valve) ->
+  composite = new CompositeUnsubscribe()
   onHold = false
   bufferedValues = []
-  combined = Bacon.when(
-    [this], (value) -> { value: value, hasValue: true },
-    [valve.toEventStream()], (value) -> { newOnHold: value })
-  withDescription this, "holdWhen", valve, combined.flatMap ({ value, newOnHold, hasValue }) ->
-      onHold = newOnHold if newOnHold?
-      if hasValue
+  src = this
+  new EventStream describe(this, "holdWhen", valve), (sink) ->
+    endIfBothEnded = (unsub) ->
+      unsub()
+      sink endEvent() if composite.empty()
+    composite.add (unsubAll, unsubMe) -> src.subscribe (event) ->
+      if onHold and event.hasValue()
+        bufferedValues.push(event.value())
+      else if event.isEnd() && bufferedValues.length
+        endIfBothEnded(unsubMe)
+      else
+        sink(event)
+    composite.add (unsubAll, unsubMe) -> valve.subscribe (event) ->
+      if event.hasValue()
+        onHold = event.value()
         if !onHold
-          Bacon.once(value)
-        else
-          bufferedValues.push(value)
-          Bacon.never()
-      else
-        if onHold
-          Bacon.never()
-        else
           toSend = bufferedValues
           bufferedValues = []
-          Bacon.fromArray(toSend)
+          _.each toSend, (index, value) ->
+            sink nextEvent(value)
+      else if event.isEnd()
+        endIfBothEnded(unsubMe)
+      else
+        sink(event)
+    composite.unsubscribe
+


Add logger stub to unit test

Add logger stub to unit test

--- services/track-changes/test/unit/coffee/MongoManager/MongoManagerTests.coffee
+++ services/track-changes/test/unit/coffee/MongoManager/MongoManagerTests.coffee
@@ -15,6 +15,7 @@
 			"./mongojs" : { db: @db = {}, ObjectId: ObjectId }
 			"./PackManager" : @PackManager = {}
 			'metrics-sharelatex': {timeAsyncMethod: ()->}
+			'logger-sharelatex': {log: ()->}
 		@callback = sinon.stub()
 		@doc_id = ObjectId().toString()
 		@project_id = ObjectId().toString()


- some better formating for logger debug output

--- logger.coffee
+++ logger.coffee
@@ -3,6 +3,16 @@
 logger = {}
 logger.level = 'info'
 logger.levels = ['error', 'warn', 'info', 'debug'];
+
+formatMessage=(message...)->
+  result = []
+  for item in message[0]
+    if typeof item != 'string'
+      item = JSON.stringify(item)
+      result.push(item)
+    else
+      result.push(item)
+  result

 logger.log = (level, message)->
   levels = ['error', 'warn', 'info', 'debug'];
@@ -12,11 +22,10 @@
     log(level+': '+message)

 logger.debug = (message...)->
+  message = formatMessage(message)
   message = message.join(" ")
   level = 'debug'
   if logger.levels.indexOf(level) <= logger.levels.indexOf(logger.level)
-    if (typeof message is not 'string')
-      message = JSON.stringify(message)
     log.debug(message)

 logger.info = (message...)->


Fix view of global progress counter

Fix view of global progress counter

--- src/lib/webInterface.coffee
+++ src/lib/webInterface.coffee
@@ -158,9 +158,9 @@

     imd = ctx.getImageData 0, 0, 60, 60

-    changeText = (percent) ->
-      text.innerHTML = percent + '%'
-      @setDoneStatus() if percent is 100
+    changeText = (percent) =>
+      text.innerHTML = if percent >= 100 then 'done' else percent + '%'
+      @setDoneStatus() if percent >= 100

     return {
       draw: (current) ->


Remove 0.2 net server creation

Remove 0.2 net server creation

--- test/test_client.coffee
+++ test/test_client.coffee
@@ -6,13 +6,10 @@

 config = __dirname + "/fixtures/hello.ru"

-createDuplexServer = if net.createServer().allowHalfOpen?
-  (listener) ->
-    server = net.createServer allowHalfOpen: true
-    server.on 'connection', listener
-    server
-else
-  (listener) -> net.createServer listener
+createDuplexServer = (listener) ->
+  server = net.createServer allowHalfOpen: true
+  server.on 'connection', listener
+  server

 exports.testClientRequestBeforeConnect = (test) ->
   test.expect 14


Mesh: Remove unused member.

Mesh: Remove unused member.

--- engine/mesh.coffee
+++ engine/mesh.coffee
@@ -103,7 +103,6 @@
         @materials = []
         @passes = [0]
         @armature = null
-        @sort_dot = 0
         @uv_rect = vec4.fromValues 0, 0, 1, 1 # x, y, w, h
         @uv_right_eye_offset = [0, 0]
         #TODO move to MeshData


Added some of changes from ufal branch

Added some of changes from ufal branch

--- src/license-selector.coffee
+++ src/license-selector.coffee
@@ -29,8 +29,8 @@
     name: 'Creative Commons Attribution (CC-BY)'
     priority: 1
     available: true
-    url: 'http://creativecommons.org/licenses/by/4.0/'
-    description: 'This is the ‘standard’ creative commons license that gives others maximum freedom to do what they want with your work.'
+    url: 'http://creativecommons.org/licenses/by/3.0/'
+    description: 'This is the standard creative commons license that gives others maximum freedom to do what they want with your work.'
     categories: ['data', 'by']

   'odc-by':
@@ -45,7 +45,7 @@
     name: 'Creative Commons Attribution-ShareAlike (CC-BY-SA)'
     priority: 1
     available: true
-    url: 'https://creativecommons.org/licenses/by-sa/4.0'
+    url: 'http://creativecommons.org/licenses/by-sa/3.0/'
     description: 'This creative commons license is very similar to the regular Attribution license, but requires you to release all derivative works under this same license.'
     categories: ['data', 'by', 'sa']

@@ -61,15 +61,15 @@
     name: 'Creative Commons Attribution-NoDerivs (CC-BY-ND)'
     priority: 1
     available: true
-    url: 'https://creativecommons.org/licenses/by-nd/4.0'
-    description: 'The no derivatives creative commons license is straightforward; you can take a work released under this license and re-distribute it but you can’t change it.'
+    url: 'http://creativecommons.org/licenses/by-nd/3.0/'
+    description: 'The no derivatives creative commons license is straightforward; you can take a work released under this license and re-distribute it but you cannot change it.'
     categories: ['data', 'by', 'nd']

   'cc-by-nc':
     name: 'Creative Commons Attribution-NonCommercial (CC-BY-NC)'
     priority: 1
     available: true
-    url: 'https://creativecommons.org/licenses/by-nc/4.0'
+    url: 'http://creativecommons.org/licenses/by-nc/3.0/'
     description: 'A creative commons license that bans commercial use.'
     categories: ['data', 'by', 'nc']

@@ -77,7 +77,7 @@
     name: 'Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA)'
     priority: 1
     available: true
-    url: 'https://creativecommons.org/licenses/by-nc-sa/4.0'
+    url: 'http://creativecommons.org/licenses/by-nc-sa/3.0/'
     description: 'A creative commons license that bans commercial use and requires you to release any modified works under this license.'
     categories: ['data', 'by', 'nc', 'sa']

@@ -85,11 +85,19 @@
     name: 'Creative Commons Attribution-NonCommercial-NoDerivs (CC-BY-NC-ND)'
     priority: 1
     available: true
-    url: 'https://creativecommons.org/licenses/by-nc-nd/4.0'
+    url: 'http://creativecommons.org/licenses/by-nc-nd/3.0/'
     description: 'The most restrictive creative commons license. This only allows people to download and share your work for no commercial gain and for no other purposes.'
     categories: ['data', 'by', 'nc', 'nd']

-  'perl-artistic':
+  'perl-artistic-1':
+    name: 'Artistic License 1.0'
+    priority: 2
+    available: true
+    url: 'http://opensource.org/licenses/Artistic-Perl-1.0'
+    description: 'NOTE: This license has been superseded by the Artistic License, Version 2.0. This is a license for software packages with the intent of giving the original copyright holder some measure of control over his software while still remaining open source. It is flexible and allows you to distribute or sell modified versions as long as you fulfill one of various conditions. Look at section 4 in the full text for a better explanation.'
+    categories: ['software', 'perl']
+
+  'perl-artistic-2':
     name: 'Artistic License 2.0'
     priority: 1
     available: true
@@ -109,7 +117,7 @@
     name: 'GNU General Public License 2 (GPL-2.0)'
     priority: 10
     available: false
-    url: 'http://opensource.org/licenses/GPL-2.0'
+    url: 'http://www.gnu.org/licenses/gpl-2.0.html'
     description: 'Standard GNU GPL version 2 but without support for later versions i.e. you cannot relicense under GPL 3.'
     categories: ['software', 'gpl', 'copyleft', 'strong']

@@ -189,7 +197,7 @@
     name: 'The MIT License (MIT)'
     priority: 1
     available: true
-    url: 'http://opensource.org/licenses/MIT'
+    url: 'http://opensource.org/licenses/mit-license.php'
     description: 'A short, permissive software license. Basically, you can do whatever you want as long as you include the original copyright and license.'
     categories: ['software', 'permissive']

@@ -449,7 +457,7 @@
     return

   reset: ->
-    @current = -1;
+    @current = -1
     @historyStack = []
     @update()
     return


Module test

Module test

--- test/type-walker.coffee
+++ test/type-walker.coffee
@@ -1850,24 +1850,24 @@
         @a = 1
       a :: Int = M.N.a

-    # test 'nested module declare', ->
-    #   shouldBeTypeError """
-    #   module X.Y
-    #     @a :: Int
-    #     @a = 1
-    #   a :: String = X.Y.a
-    #   """
-
-    # test 'nested module declare', ->
-    #   module X.Y.Z
-    #     @a :: Int
-    #     @a = 1
-    #   a :: Int = X.Y.Z.a
-
-    # test 'nested module declare', ->
-    #   shouldBeTypeError """
-    #   module X.Y.Z
-    #     @a :: Int
-    #     @a = 1
-    #   a :: Int = X.Y.Z.a
-    #   """
+    test 'nested module declare', ->
+      shouldBeTypeError """
+      module X.Y
+        @a :: Int
+        @a = 1
+      a :: String = X.Y.a
+      """
+
+    test 'nested module declare', ->
+      module X.Y.Z
+        @a :: Int
+        @a = 1
+      a :: Int = X.Y.Z.a
+
+    test 'nested module declare', ->
+      shouldBeTypeError """
+      module X.Y.Z
+        @a :: Int
+        @a = 1
+      a :: String = X.Y.Z.a
+      """


bad route

bad route

--- nodeko.coffee
+++ nodeko.coffee
@@ -130,7 +130,7 @@
   throw new Error('Foo')

 # list teams
-get '/teams|/entries', ->
+get '/(teams|entries)', ->
   Team.all { validDeploy: true }, (error, teams) =>
     @teams = _.shuffle teams
     if @currentPerson?


Updating packge.cson

Updating packge.cson

--- packages.cson
+++ packages.cson
@@ -1,28 +1,27 @@
 packages: [
-  "linter-shellcheck"
-  "linter"
   "browser-plus"
-  "language-liquid"
-  "language-gentoo"
-  "language-rust"
   "dark-bint-syntax"
+  "file-icons"
   "fusion-ui"
-  "terminal-fusion"
-  "language-archlinux"
-  "language-debian"
-  "file-icons"
   "git-plus"
   "git-time-machine"
+  "language-archlinux"
   "language-asciidoc"
+  "language-debian"
   "language-docker"
+  "language-gentoo"
+  "language-gfm2"
   "language-ini-desktop"
+  "language-lisp"
   "fusion809/language-patch2"
-  "language-gentoo"
-  "language-lisp"
   "language-rpm-spec"
+  "language-rust"
+  "language-scala"
+  "language-unix-shell"
+  "linter"
+  "linter-shellcheck"
   "markdown-writer"
   "minimap"
   "pigments"
-  "language-unix-shell"
-  "language-gfm2"
+  "terminal-fusion"
 ]


fix total_entries style

fix total_entries style

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -94,16 +94,20 @@

-
-
-                    {
-                      if @props.cards.pagination
-                        @props.cards.pagination.total_entries
-                      else
-
-                    }
-
-
+

+

+
+
+                        {
+                          if @props.cards.pagination
+                            @props.cards.pagination.total_entries
+                          else
+
+                        }
+
+
+

+

             {


Put leftover argument

Put leftover argument

--- lib/build-text-editor.coffee
+++ lib/build-text-editor.coffee
@@ -1,5 +1,5 @@
 TextEditor = null
-module.exports = ->
+module.exports = (params) ->
   if atom.workspace.buildTextEditor?
     atom.workspace.buildTextEditor(params)
   else


:bug: narrow:close on protected narrow-editor now re-render control-bar

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -351,8 +351,13 @@
   narrowClose: (event) ->
     if @protected
       event.stopImmediatePropagation()
-      @setQuery() # clear query
+      @resetQuery()
       @activateProviderPane()
+
+  resetQuery: ->
+    @setQuery() # clear query
+    @moveToPrompt()
+    @controlBar.show()

   # Line-wrapped version of 'core:move-up' override default behavior
   moveUpOrDown: (event, direction) ->
@@ -537,10 +542,7 @@
     texts = items.map (item) => @provider.viewForItem(item)
     @withIgnoreChange =>
       if @editor.getLastBufferRow() is 0
-        # Need to recover query prompt
-        @setQuery()
-        @moveToPrompt()
-        @controlBar.show()
+        @resetQuery()
       itemArea = new Range(@itemAreaStart, @editor.getEofBufferPosition())
       range = @editor.setTextInBufferRange(itemArea, texts.join("\n"), undo: 'skip')
       @setModifiedState(false)


Remove unused state variable

Remove unused state variable

--- lib/exception-reporting.coffee
+++ lib/exception-reporting.coffee
@@ -4,7 +4,7 @@
 Reporter = require './reporter'

 module.exports =
-  activate: (state) ->
+  activate: ->
     atom.config.set('exception-reporting.userId', Guid.raw()) unless atom.config.get('exception-reporting.userId')
     atom.on 'error.exception-reporting', (message, url, line) ->
       Reporter.send(message, url, line) unless atom.inDevMode()


wording

wording

--- lib/connection/client.coffee
+++ lib/connection/client.coffee
@@ -120,7 +120,7 @@

   connectedError: ->
     if @isActive()
-      atom.notifications.addError "Can't create a new client.",
+      atom.notifications.addError "Can't start a Julia process.",
         detail: "There is already a Julia client running."
       true
     else


Denorm resetWatchers selector bugfix

Denorm resetWatchers selector bugfix

--- denorm.coffee
+++ denorm.coffee
@@ -111,15 +111,17 @@
                 newValue = newSubValues[subFieldName]

                 term = $or: [{}, {}]
-                term.$or[0][selectorPath] = $in: [null]
-                term.$or[1]["#{selectorPath}.*DOLLAR*in"] = $in: []
+                term.$or[0][selectorPath] =
+                    $in: [null]
+                term.$or[1]["#{selectorPath}.*DOLLAR*in"] =
+                    $elemMatch: $in: [null]

                 if oldValue?
                     term.$or[0][selectorPath].$in.push oldValue
-                    term.$or[1]["#{selectorPath}.*DOLLAR*in"].$in.push oldValue
+                    term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push oldValue
                 if newValue? and not EJSON.equals oldValue, newValue
                     term.$or[0][selectorPath].$in.push newValue
-                    term.$or[1]["#{selectorPath}.*DOLLAR*in"].$in.push newValue
+                    term.$or[1]["#{selectorPath}.*DOLLAR*in"].$elemMatch.$in.push newValue

                 subFieldSelectorMatcher.push term


added testcase for sub-objects

added testcase for sub-objects

--- tests/basic.coffee
+++ tests/basic.coffee
@@ -7,6 +7,16 @@

   post = posts.findOne postId
   test.equal post.updateCount, 2
+
+Tinytest.add 'ComputedFields - Subobject', (test) ->
+  posts = new Mongo.Collection null
+  posts.computedFields.add 'computed.updateCount', (post) ->
+    @set (post.computed?.updateCount or 0) + 1
+  postId = posts.insert name: 'test'
+  posts.update postId, $set: name: 'passed'
+
+  post = posts.findOne postId
+  test.equal post.computed.updateCount, 2

 Tinytest.add 'ComputedFields - external dependencies', (test) ->
   posts = new Mongo.Collection null


Log some more progress.

Log some more progress.

--- previous-statements-downloader.coffee
+++ previous-statements-downloader.coffee
@@ -36,7 +36,9 @@

       # Find incomplete statements
       for statement in list.statements
+        console.log "    Analysing #{statement.title}"
         if !@statements[statement.title]?.complete
+          console.log "      -> Incomplete!"
           return @loadStatement statement
       # Must have completed the page!
       if list.nextSet?


Client: Small bugfix with ids.

Client: Small bugfix with ids.

--- client/app/js/concerns/modals.coffee
+++ client/app/js/concerns/modals.coffee
@@ -5,7 +5,7 @@
   [domId, options, initialize] = [null, domId, options]  if !_.isString(domId)
   [options, initialize] = [{}, options]  if _.isFunction(options)
   $modal = $(JST[modalPath](options))
-  id = domId || '#' + $modal.prop('id')
+  id = '#' + (domId || $modal.prop('id'))
   if $(id).length == 0
     $modal.appendTo($('body'))
     initialize?($modal)


Adapt to Paw JS API version 0.2.0

Adapt to Paw JS API version 0.2.0

--- Base64ToHexDynamicValue.coffee
+++ Base64ToHexDynamicValue.coffee
@@ -1,4 +1,10 @@
-require "b64.js"
+# in API v0.2.0 and below (Paw 2.2.2 and below), require had no return value
+((root) ->
+  if root.bundle?.minApiVersion('0.2.0')
+    root.base64js = require("./b64")
+  else
+    require("b64.js")
+)(this)

 Base64ToHexDynamicValue = () ->


Adding limit to publication.

Adding limit to publication.

--- server/publications/roomFiles.coffee
+++ server/publications/roomFiles.coffee
@@ -12,6 +12,7 @@
     fields:
       _id: 1
       'file._id': 1
+    limit: 50
   cursorFileMessages = RocketChat.models.Messages.find(msgQuery, msgOptions);
   uploadedFilesMessages = cursorFileMessages.fetch()
   unless uploadedFilesMessages


just adding comments to link to 3rd party libraries

--- test/ssh_keys.coffee
+++ test/ssh_keys.coffee
@@ -1,13 +1,18 @@
 # basic.coffee

+child_process = require 'child_process'
+fs     = require 'fs'
 http = require 'http'
+
+# https://github.com/flatiron/nock
+nock   = require 'nock'
 # https://github.com/mikeal/request
 request = require 'request'
+# https://github.com/visionmedia/should.js/
 should = require 'should'
-nock   = require 'nock'
+# http://sinonjs.org/docs/
 sinon  = require 'sinon'
-fs     = require 'fs'
-child_process = require 'child_process'
+# http://underscorejs.org/
 _ = require 'underscore'

 User = require 'models/user'


Fix Yetis looking in the wrong direction when spawning

--- app/models/Yeti.coffee
+++ app/models/Yeti.coffee
@@ -18,6 +18,8 @@
     super x, y, width/2, height/2, owningLevel, settings
     @_visual_init()
     @_movable_init()
+
+    @spriteState.viewDirection = 2

     @size.x = width
     @size.y = height


Add some warning when clearing dirty ranges

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -213,6 +213,10 @@
     if intactRanges.length == 0
       @lines[0].innerHTML = ''
     else if currentLine = @lines[0].firstChild
+      unless currentLine?
+        console.warn "Unexpected undefined first line in clearing dirty ranges"
+        return
+
       domPosition = 0
       for intactRange in intactRanges
         while intactRange.domStart > domPosition
@@ -220,6 +224,9 @@
           domPosition++

         for i in [intactRange.start..intactRange.end]
+          unless currentLine?
+            console.warn "Unexpected undefined line when clearing dirty range #{intactRange.start}..#{intactRange.end}"
+            return
           currentLine = currentLine.nextSibling
           domPosition++

@@ -230,7 +237,6 @@
     next = lineElement.nextSibling
     @lines[0].removeChild(lineElement)
     next
-

   fillDirtyRanges: (intactRanges, renderFrom, renderTo) ->
     i = 0


instructions book: slide in sidebar to make chat icon visible

--- client/app/MainApp/book/bookview.coffee
+++ client/app/MainApp/book/bookview.coffee
@@ -444,9 +444,12 @@

     # find conversations panel icon position.
     @setClass "moveUp"
-    offsetTo = @mainView.sidebar.footerMenu.$(".chat").offset()
-    # move cursor to conv. panel button position.
-    @pointer.$().offset offsetTo
+    {sidebar} = @mainView
+    sidebar.animateLeftNavIn()
+    @utils.wait 200, =>
+      offsetTo = sidebar.footerMenu.$(".chat").offset()
+      # move cursor to conv. panel button position.
+      @pointer.$().offset offsetTo

   startNewConversation:->
     @pointer.once 'transitionend', =>


client: stackeditor: open chatlio when editor is opened

--- client/stack-editor/lib/index.coffee
+++ client/stack-editor/lib/index.coffee
@@ -16,6 +16,8 @@

   openEditor: (stackTemplateId) ->
+
+    kd.singletons.mainController.tellChatlioWidget 'show', { expanded: no }

     { computeController } = kd.singletons


expose codemirror

expose codemirror

--- app/compat.coffee
+++ app/compat.coffee
@@ -2,6 +2,7 @@
   Q = require 'q'
   _ = require 'underscore'
   moment = require 'moment'
+  CodeMirror = require 'codemirror'

   modules = require './modules'
   graphite = require './graphite'
@@ -216,5 +217,6 @@

     context_vars:
       moment: moment
+      CodeMirror: CodeMirror
       require: (module_name) ->
         requireables[module_name] ? module.exports.load_module module_name


add shortcuts for week, today, month

add shortcuts for week, today, month

--- app/models/task.coffee
+++ app/models/task.coffee
@@ -314,4 +314,8 @@
         @tags = []

         if tags?
-            @tags.push tag.substring(1) for tag in tags
+            for tag in tags
+                tag = "#today" if tag is "#t"
+                tag = "#week" if tag is "#w"
+                tag = "#month" if tag is "#m"
+                @tags.push tag.substring(1)


clean up requires

clean up requires

--- app/editor.coffee
+++ app/editor.coffee
@@ -7,8 +7,8 @@
 require 'codemirror/mode/coffeescript/coffeescript'
 require 'codemirror/addon/hint/show-hint'

-context = require './context'
-notebook = require './notebook'
+Context = require './context'
+Notebook = require './notebook'

 create_editor = (target) ->
   if is_nodejs?
@@ -87,11 +87,11 @@
   last_interesting_token

 collect_string_suggestions = (ctx, string) ->
-  Q.all(_.flatten _.map context.collect_extension_points(ctx, 'suggest_strings'), (fn) -> fn string)
+  Q.all(_.flatten _.map Context.collect_extension_points(ctx, 'suggest_strings'), (fn) -> fn string)
   .then (suggestions) -> _.flatten suggestions

 collect_key_suggestions = (ctx, string) ->
-  _.flatten _.map context.collect_extension_points(ctx, 'suggest_keys'), (fn) -> fn string
+  _.flatten _.map Context.collect_extension_points(ctx, 'suggest_keys'), (fn) -> fn string

 follow_path = (o, path) ->
   result = o
@@ -180,32 +180,32 @@

 commands =
   run: cmd 'Runs the contents of the cell and advances the cursor to the next cell', (cm) ->
-    notebook.run cm.lead_cell, advance: true
+    Notebook.run cm.lead_cell, advance: true

   run_in_place: cmd 'Runs the contents of the cell and keeps the cursor in the cell', (cm) ->
-    notebook.run cm.lead_cell, advance: false
+    Notebook.run cm.lead_cell, advance: false

   context_help: cmd 'Shows help for the token under the cursor', (cm) ->
     cur = cm.getCursor()
     token = cm.getTokenAt(cur)
-    notebook.context_help cm.lead_cell, token.string
+    Notebook.context_help cm.lead_cell, token.string

   suggest: cmd 'Suggests a function or metric', (cm) ->
     CodeMirror.showHint cm, suggest, async: true

   fill_with_last_value: cmd 'Replaces the cell with the contents of the previous cell', (cm) ->
-    cell = notebook.input_cell_at_offset cm.lead_cell, -1
+    cell = Notebook.input_cell_at_offset cm.lead_cell, -1
     if cell?
-      set_value cm, notebook.cell_value cell
+      set_value cm, Notebook.cell_value cell
     else
       CodeMirror.Pass

   next_cell: cmd 'Moves the cursor to the next cell', (cm) ->
-    unless notebook.move_focus cm.lead_cell, 1
+    unless Notebook.move_focus cm.lead_cell, 1
       CodeMirror.Pass

   previous_cell: cmd 'Moves the cursor to the previous cell', (cm) ->
-    unless notebook.move_focus cm.lead_cell, -1
+    unless Notebook.move_focus cm.lead_cell, -1
       CodeMirror.Pass

   maybe_next_cell: cmd 'Moves the cursor to the next cell if the cursor is at the end', (cm) ->
@@ -223,7 +223,7 @@
       CodeMirror.Pass

   save: (cm) ->
-    notebook.save cm.lead_cell
+    Notebook.save cm.lead_cell

 key_map =
   Tab: (cm) ->


flux/teams: show delete team overlay after password is confirmed

--- client/app/lib/flux/teams/actions.coffee
+++ client/app/lib/flux/teams/actions.coffee
@@ -17,6 +17,7 @@
 KodingKontrol = require 'app/kite/kodingkontrol'
 globals = require 'globals'
 showError = require 'app/util/showError'
+DeleteTeamOverlay = require 'app/components/deleteteamoverlay'

 loadTeam = ->

@@ -312,6 +313,9 @@

           return reject err.message  if err
           return reject 'Current password cannot be confirmed'  unless confirmed
+
+          # show delete team overlay
+          new DeleteTeamOverlay()

           { groupsController, reactor } = kd.singletons
           team = groupsController.getCurrentGroup()


Fix tool model to remove changes made for tool view

--- app/models/tool.coffee
+++ app/models/tool.coffee
@@ -11,9 +11,6 @@
     relatedModel: require 'models/settings'
   ]

-  url: ->
-    "/dashboards/#{@get('dashboard_id')}/tools/#{@id}"
-
   defaults:
     data_source: {}
     height: 480
@@ -22,11 +19,10 @@
     width: 640

   initialize: ->
-    if @get('saveable')
-      unless @get('name') then @set 'name', "#{@get('tool_type')}-#{@collection.length + 1}"
-      unless @get('channel') then @set 'channel', "#{@get('tool_type')}-#{@collection.length + 1}"
+    unless @get('name') then @set 'name', "#{@get('tool_type')}-#{@collection.length + 1}"
+    unless @get('channel') then @set 'channel', "#{@get('tool_type')}-#{@collection.length + 1}"

-    if @isNew() and @get('saveable')
+    if @isNew()
       @generatePosition()
       @collection.focus @, false
       @save()


Fix but in tool_setup cause by fix to #59

--- app/models/tool.coffee
+++ app/models/tool.coffee
@@ -112,7 +112,7 @@
       left: x

   setupUbretTool: =>
-    if @get('data_source').isInternal()
+    if @get('data_source').isInternal() and @get('data_source.source_id')?
       if @sourceTool().tool?
         @tool.parentTool(@sourceTool().tool)
       else
@@ -137,6 +137,8 @@

   sourceTool: =>
     if @get('data_source').isInternal()
+      console.log @collection.get(@get('data_source.source_id'))
+      console.trace()
       @collection.get(@get('data_source.source_id'))
     else
       false


Add tabindex attr to table rows after table is loaded

--- client/controllers/reactiveTable.coffee
+++ client/controllers/reactiveTable.coffee
@@ -1,7 +1,9 @@
 Template.reactiveTable.onRendered ->
   if @data.settings.keyboardFocus
-    attrs = tabindex: '0'
-    @$('tbody > tr').attr(attrs)
+    @autorun =>
+      if @context.ready.get()
+        Meteor.defer =>
+          @$('tbody > tr').attr(tabindex: '0')

 Template.reactiveTable.events
   'click tbody > tr': (event, instance) ->


IDE: Much better variable names.

IDE: Much better variable names.

--- client/ide/views/tabview/ideview.coffee
+++ client/ide/views/tabview/ideview.coffee
@@ -47,9 +47,9 @@

     @tabView.on 'PaneRemoved', (paneInstance) =>
       { view } = paneInstance.pane
-      isDetach = paneInstance.pane.getDelegate().detachInProgress
-
-      if view instanceof IDE.TerminalPane and not isDetach
+      { detachInProgress } = paneInstance.pane.getDelegate()
+
+      if view instanceof IDE.TerminalPane and not detachInProgress
         sessionId = view.session or view.webtermView.sessionId
         @terminateSession @mountedMachine, sessionId


Use new AppStorage

Use new AppStorage

--- client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
+++ client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
@@ -39,10 +39,10 @@
       @lowQualitySwitch = new KDCustomHTMLView

     @appStorage.fetchStorage (storage)=>
-      state = @appStorage.getValue 'liveUpdates', off
+      state = @appStorage.getValue('liveUpdates') or off
       @liveUpdateButton.setValue state
       @getSingleton('activityController').flags = liveUpdates : state
-      @lowQualitySwitch.setValue? @appStorage.getValue 'showLowQualityContent', off
+      @lowQualitySwitch.setValue? @appStorage.getValue('showLowQualityContent') or off

   pistachio:(newCount)->
     "Latest Activity{{> @lowQualitySwitch}}{{> @liveUpdateButton}}{{> @showNewItemsLink}}"


payment: keep track of the planCode in the product create form

--- client/app/Applications/Dashboard.kdapplication/views/productcreateform.coffee
+++ client/app/Applications/Dashboard.kdapplication/views/productcreateform.coffee
@@ -2,10 +2,12 @@

   constructor: (options = {}, data = {}) ->

+    { @planCode } = data
+
     options.isRecurOptional ?= yes

     options.callback ?= =>
-      @emit 'CreateRequested', @getProductData()
+      @emit 'SaveRequested', @getProductData()

     options.buttons ?=
       Save        :
@@ -65,7 +67,7 @@

         perMonth      :
           itemClass   : KDCustomHTMLView
-          partial     : "/ mo"
+          partial     : "/ #{data.subscriptionType}"
           cssClass    : 'fr'

     if options.showOverage
@@ -99,6 +101,7 @@
     { subscriptionType, feeUnit, feeInterval } = @getPlanInfo subType.getValue()

     {
+      @planCode
       title             : title.getValue()
       description       : description.getValue()
       feeAmount         : feeAmount.getValue()


fix js bug

fix js bug

--- public/javascripts/application.coffee
+++ public/javascripts/application.coffee
@@ -13,7 +13,7 @@
       if location.hash
         [h, location.hash] = [location.hash, null]
         location.hash = h
-      else if $('#inner nav').offset().top < $(window).scrollTop()
+      else if $('#inner nav').length > 0 and $('#inner nav').offset().top < $(window).scrollTop()
         $(window).scrollTop 0

 $(document).bind 'pjax', (e, xhr, options) ->


Add TODO for fsUtils.isValidPath()

Add TODO for fsUtils.isValidPath()

--- lib/fs-utils/fs-utils.coffee
+++ lib/fs-utils/fs-utils.coffee
@@ -1,4 +1,5 @@
 _ = require('lodash')

+# TODO: There should be more complex checks here
 exports.isValidPath = (p) ->
 	return _.isString(p)


simplifying customizations by eliminating . notation

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -16,9 +16,6 @@
 #
 # The customization method returns the proper value of the field for this
 # subdomain, or the default value if it hasn't been defined for the subdomain.
-#
-# Nested customizations can be fetched with . notation, by passing e.g.
-# "auth.use_footer" or with a bracket, like "auth.use_footer['on good days']"
 #
 # object_or_key is optional. If passed, customization will additionally check for
 # special configs for that object (object.key) or key.
@@ -142,7 +139,7 @@

   value = undefined
   for config in chain_of_configs
-    value = customization_value(field, config)
+    value = config[field]

     break if value?

@@ -150,36 +147,6 @@
   #   console.error "Could not find a value for #{field} #{if key then key else ''}"

   value
-
-
-# Checks to see if this configuration is defined for a customization field
-customization_value = (field, config) ->
-  val = config
-
-  fields = field.split('.')
-
-  for f, idx in fields
-
-    if f.indexOf('[') > 0
-      brackets = f.match(/\[(.*?)\]/g)
-      f = f.substring(0, f.indexOf('['))
-
-    if val[f]? || idx == fields.length - 1
-      val = val[f]
-
-      if brackets?.length > 0
-        for b in brackets
-          f = b.substring(2,b.length - 2)
-          if val? && val[f]?
-            val = val[f]
-
-          else
-            return undefined
-
-    else
-      return undefined
-
-  val


Updated generic-parser

Updated generic-parser

--- src/generic-parser.coffee
+++ src/generic-parser.coffee
@@ -7,23 +7,23 @@
       throw new Error "Expected inputString to be a string"

     @inputArray = inputString.split ''
-
     @head = 0
-
     @headStack = []

   pushHead: ->
-    @headStack.push head
+    @headStack.push @head
+    return

   popHead: ->
     @head = @headStack.pop()
+    return

   current: ->
     return @inputArray[@head]

   moveForward: ->
     @head += 1
-    return @current()
+    return


fix stack overflow in common-exponent simplification

--- coffeequate/src/operators/Mul.coffee
+++ coffeequate/src/operators/Mul.coffee
@@ -314,19 +314,21 @@
 				[base0, power0] = term0

 				found = false
-				for term1 in newLikeTerms
-					[base1, power1] = term1
-
-					if power1.equals?(power0, equivalencies)
-						unless base1 instanceof Mul
-							base1 = new Mul(base1)
-							term1[0] = base1
-						base1.children.push(base0)
-						found = true
-						break
+				unless power0.evaluate?() == 1
+					for term1 in newLikeTerms
+						[base1, power1] = term1
+
+						if power1.equals?(power0, equivalencies)
+							base1.push(base0)
+							found = true
+							break

-				newLikeTerms.push(term0) unless found
-			liketerms = ([base.expandAndSimplify(), power] for [base, power] in newLikeTerms)
+				newLikeTerms.push([[base0], power0]) unless found
+			liketerms = ([
+				(if base.length == 1 then base[0] else new Mul(base...))
+					.expandAndSimplify(),
+				power
+			] for [base, power] in newLikeTerms)

 			newMul = null
 			for liketerm in liketerms


Fix block comments style.

Fix block comments style.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/tweening.coffee
+++ test/tweening.coffee
@@ -1,7 +1,7 @@
 module "Tweening"

 test "should allow for simple tweening", ->
-  one = 1
+

   # Test for equality of two objects
   equals one, 1


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/tweening.coffee
+++ test/tweening.coffee
@@ -10,7 +10,7 @@
   11.times (i) ->
     o.update(1)

-    equals o.I.x, i +
+    equals o.I.x, i + 1

 # Clear out the module
 module()


Validate protocol

Validate protocol

--- components/UrlToTempFile-node.coffee
+++ components/UrlToTempFile-node.coffee
@@ -43,6 +43,10 @@
       do callback
       return
     if urlOptions.protocol
+      unless urlOptions.protocol in ['http:', 'https:']
+        callback new Error "Images with #{urlOptions.protocol} protocol not allowed"
+        return
+
       # Remote image
       tmpFile = new temporary.File
       stream = fs.createWriteStream tmpFile.path


Remove console.log

Remove console.log

--- src/longtext.coffee
+++ src/longtext.coffee
@@ -23,7 +23,6 @@
         flattened = []
         for string in strings
             flattened = flattened.concat string.toString().split(/\r?\n/)
-        console.log flattened
         flattened

     _pasteIfMaxChars = (s, cb) ->