Take flexbox spec version from Can I Use

--- data/prefixes.coffee
+++ data/prefixes.coffee
@@ -1,18 +1,8 @@
 browsers = require('./browsers')

-# Convert Can I Use data
-feature = (data, opts, callback) ->
-  [callback, opts] = [opts, { }] unless callback
-
-  match = opts.match || /\sx($|\s)/
-  need  = []
-
-  for browser, versions of data.stats
-    for version, support of versions
-      if browsers[browser] and support.match(match)
-        need.push(browser + ' ' + version)
-
-  sorted = need.sort (a, b) ->
+# Sort browsers
+sort = (array) ->
+  array.sort (a, b) ->
     a = a.split(' ')
     b = b.split(' ')
     if a[0] > b[0]
@@ -22,7 +12,19 @@
     else
       parseFloat(a[1]) - parseFloat(b[1])

-  callback(sorted)
+# Convert Can I Use data
+feature = (data, opts, callback) ->
+  [callback, opts] = [opts, { }] unless callback
+
+  match = opts.match || /\sx($|\s)/
+  need  = []
+
+  for browser, versions of data.stats
+    for version, support of versions
+      if browsers[browser] and support.match(match)
+        need.push(browser + ' ' + version)
+
+  callback(sort(need))

 # Select only special browsers
 map = (browsers, callback) ->
@@ -32,11 +34,18 @@
     callback(browser, name, version)

 # Add data for all properties
+result = { }
+
 prefix = (names..., data) ->
   for name in names
-    module.exports[name] = data
-
-module.exports = { }
+    if result[name]
+      result[name].browsers = sort(result[name].browsers.concat(data.browsers))
+    else
+      result[name] = { }
+      for i of data
+        result[name][i] = data[i]
+
+module.exports = result

 # Border Radius
 feature require('caniuse-db/features-json/border-radius'), (browsers) ->
@@ -127,30 +136,32 @@
           browsers: browsers

 # Flexible Box Layout
-feature require('caniuse-db/features-json/flexbox'), (browsers) ->
-  browsers = map browsers, (browser, name, version) ->
-    if name == 'safari' and version < 6.1
-      browser + ' 2009'
-    else if name == 'ios_saf' and version < 7
-      browser + ' 2009'
-    else if name == 'chrome' and version < 21
-      browser + ' 2009'
-    else if name == 'android' and version < 4.4
-      browser + ' 2009'
-    else
-      browser
-
+flexbox = require('caniuse-db/features-json/flexbox')
+
+feature flexbox, match: /a\sx/, (browsers) ->
+  browsers = browsers.map (i) -> if /ie|firefox/.test(i) then i else "#{i} 2009"
   prefix 'display-flex', 'inline-flex',
           props:  ['display']
           browsers: browsers
-
   prefix 'flex', 'flex-grow', 'flex-shrink', 'flex-basis',
           transition: true
           browsers:   browsers
-
   prefix 'flex-direction', 'flex-wrap', 'flex-flow', 'justify-content',
          'order', 'align-items', 'align-self', 'align-content',
           browsers: browsers
+
+feature flexbox, match: /y\sx/, (browsers) ->
+  prefix 'display-flex', 'inline-flex',
+          props:  ['display']
+          browsers: browsers
+  prefix 'flex', 'flex-grow', 'flex-shrink', 'flex-basis',
+          transition: true
+          browsers:   browsers
+  prefix 'flex-direction', 'flex-wrap', 'flex-flow', 'justify-content',
+         'order', 'align-items', 'align-self', 'align-content',
+          browsers: browsers
+
+require('fs').writeFileSync('2', result.flex.browsers.join('\n'))

 # calc() unit
 feature require('caniuse-db/features-json/calc'), (browsers) ->
@@ -294,6 +305,7 @@

 # Resolution Media Queries
 resolution = require('caniuse-db/features-json/css-media-resolution')
+
 feature resolution, match: /( x($| )|a #3)/, (browsers) ->
   prefix '@resolution',
           browsers: browsers


Update es-419.coffee

Update es-419.coffee

Updated my friends!.

--- app/locale/es-419.coffee
+++ app/locale/es-419.coffee
@@ -261,9 +261,9 @@
     victory_hour_of_code_done_yes: "¡Si, he terminado con mi Hora de Código!"
     victory_experience_gained: "XP Ganada"
     victory_gems_gained: "Gemas Ganadas"
-#    victory_new_item: "New Item"
-#    victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
-#    victory_become_a_viking: "Become a Viking"
+    victory_new_item: "Objeto Nuevo"
+    victory_viking_code_school: "Santo cielo, Holy smokes, el nivel que acabas de pasar era dificil! Si todavía no eres un desarrollador de software, deberías serlo. Acabas de conseguir una aceptación por vía rápida con la Escuela Vikinga de Có, donde tú puedes llevar tus habilidades al siguiente nivel y convertirteen un desarrollador web profesional en 14 semanas."
+    victory_become_a_viking: "Conviértete en un Vikingo"
     guide_title: "Guía"
     tome_minion_spells: "Hechizos de tus Secuaces" # Only in old-style levels.
     tome_read_only_spells: "Hechizos de Sólo Lectura" # Only in old-style levels.
@@ -291,11 +291,11 @@
     time_current: "Ahora:"
     time_total: "Max:"
     time_goto: "Ir a:"
-#    non_user_code_problem_title: "Unable to Load Level"
-#    infinite_loop_title: "Infinite Loop Detected"
+    non_user_code_problem_title: "No se puede cargar el nivel"
+    infinite_loop_title: "Loop infinito detectado"
 #    infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know."
-#    check_dev_console: "You can also open the developer console to see what might be going wrong."
-#    check_dev_console_link: "(instructions)"
+    check_dev_console: "Tú puedes también abrir la consola de desarrollo para ver que puede salir mal."
+    check_dev_console_link: "(instrucciones)"
     infinite_loop_try_again: "Intentar nuevamente"
     infinite_loop_reset_level: "Reiniciar Nivel"
     infinite_loop_comment_out: "Comente Mi Código"
@@ -344,8 +344,8 @@
     tip_hate_computers: "Esa es la razón por la cual la gente piensa que odia las computadoras. Lo que ellos odian de verdad, es los pesimos programadores. - Larry Niven"
     tip_open_source_contribute: "¡Tú puedes ayudar a CodeCombat a mejorar!"
     tip_recurse: "Iterar es humano, recursar es divino. - L. Peter Deutsch"
-#    tip_free_your_mind: "You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind. - Morpheus"
-#    tip_strong_opponents: "Even the strongest of opponents always has a weakness. - Itachi Uchiha"
+    tip_free_your_mind: "Tienes que dejar ir todo, Neo. Miedo, duda, e incredulidad. Libera tu mente. - Morpheus"
+    tip_strong_opponents: "Hasta los oponentes mas fuertes siempre tienen una debilidad. - Itachi Uchiha"

   game_menu:
     inventory_tab: "Inventario"
@@ -412,7 +412,7 @@
     feature4: "3500 gemas bonus cada mes!"
     feature5: "Video tutoriales"
     feature6: "Soporte Premium vía email"
-#    feature7: "Private Clans"
+    feature7: "Clan Privado"
     free: "Gratis"
     month: "mes"
     subscribe_title: "Suscribirse"
@@ -438,10 +438,10 @@
 #    parents_blurb1a: "Computer programming is an essential skill that your child will undoubtedly use as an adult. By 2020, basic software skills will be needed by 77% of jobs, and software engineers are in high demand across the world. Did you know that Computer Science is the highest-paid university degree?"
     parents_blurb2: "Por $9.99 USD/mes, recibirán nuevos desafíos todas las semanas y soporte personal por email de programadores profesionales." # {change}
     parents_blurb3: "Sin Riesgo: Garantía de 100% de devolución, fácil 1-click y des- suscribirse."
-#    payment_methods: "Payment Methods"
-#    payment_methods_title: "Accepted Payment Methods"
-#    payment_methods_blurb1: "We currently accept credit cards and Alipay."
-#    payment_methods_blurb2: "If you require an alternate form of payment, please contact"
+    payment_methods: "Metodos de pago"
+    payment_methods_title: "Metodos de pago aceptados."
+    payment_methods_blurb1: "Actualmente aceptamos tarjetas de credito y Alipay."
+    payment_methods_blurb2: "Si necesitas una forma alternativa de pago, por favor contactarse"
     stripe_description: "Suscripción Mensual"
     subscription_required_to_play: "Necesitas una suscripción para jugar este nivel."
     unlock_help_videos: "Suscríbete para desbloquear todos los video tutoriales."


remove unused var

remove unused var

--- app/scripts/hello.coffee
+++ app/scripts/hello.coffee
@@ -4,7 +4,6 @@
 writer.controller 'MainCtrl', ($scope) ->
 	$scope.pad = ""
 	pad = $scope.pad
-	stats = {}
 	$scope.readability = 100
 	$scope.check = (e) ->
     # Only recalculate when hitting the 'space' or 'return' keys


highlight all the creatures at point selected

--- evolution.coffee
+++ evolution.coffee
@@ -192,8 +192,7 @@
     ret
   # highlight an organism by coloring its belly
   highlight: ( x, y, color ) ->
-    t = ( grep @thingsAt( x, y ), (t) -> t instanceof Organism )[0]
-    if t
+    for t in @thingsAt( x, y ) when t instanceof Organism
       t.belly = color
       t.draw()
   # remove all highlights


Improved translations

Improved translations

--- def/de/settings.cson
+++ def/de/settings.cson
@@ -19,7 +19,7 @@
     }
     {
       _label: "Packages"
-      value: "Pakete"
+      value: "Plugins"
     }
     {
       _label: "Themes"
@@ -40,21 +40,21 @@
     {_label: "Editor Settings", value: "Editor-Einstellungen"}
     {_label: "System Settings", value: "Systemeinstellungen"}
     {_label: "Keybindings", value: "Tastenkürzel"}
-    {_label: "Installed Packages", value: "Installierte Pakete"}
+    {_label: "Installed Packages", value: "Installierte Plugins"}
     {_label: "Choose a Theme", value: "Ein Theme auswählen"}
     {_label: "Installed Themes", value: "Installierte Themes"}
-    {_label: "Install Packages", value: "Paket installieren"}
-    {_label: "Featured Packages", value: "Vorgestellte Pakete"}
+    {_label: "Install Packages", value: "Plugin installieren"}
+    {_label: "Featured Packages", value: "Vorgestellte Plugins"}
     {_label: "Install Themes", value: "Themes installieren"}
     {_label: "Featured Themes", value: "Vorgestellte Themes"}
     {_label: "Available Updates", value: "Verfügbare Aktualisierungen"}
   ]
   subSectionHeadings: [
     {_label: "Invisible", value: "Unsichtbar"}
-    {_label: "Community Packages", value: "Community-Pakete"}
-    {_label: "Core Packages", value: "Core-Pakete"}
-    {_label: "Development Packages", value: "Entwicklungs-Pakete"}
-    {_label: "Git Packages", value: "Git-Pakete"}
+    {_label: "Community Packages", value: "Community-Plugins"}
+    {_label: "Core Packages", value: "Core-Plugins"}
+    {_label: "Development Packages", value: "Entwicklungs-Plugins"}
+    {_label: "Git Packages", value: "Git-Plugins"}
     {_label: "Community Themes", value: "Community-Themes"}
     {_label: "Core Themes", value: "Core-Themes"}
     {_label: "Development Themes", value: "Entwickler-Themes"}
@@ -64,11 +64,11 @@
     notes: [
       {
         _id: 'core-settings-note'
-        html: 'Dies sind Atoms Core-Einstellungen, welche aber nicht das Verhalten zum Bearbeiten von Texten beeinflussen (zu finden unter Editor). Individuelle Pakete können eigene Einstellungen haben, welche auf der jeweiligen Package-Einstellungsseite in der Liste aller installierten Pakete zu finden sind.'
+        html: 'Dies sind Atoms Core-Einstellungen, welche aber nicht das Verhalten zum Bearbeiten von Texten beeinflussen (zu finden unter Editor). Individuelle Plugins können eigene Einstellungen haben, welche auf der jeweiligen Package-Einstellungsseite in der Liste aller installierten Plugins zu finden sind.'
       }
       {
         _id: 'editor-settings-note'
-        html: 'Diese Einstellungen hängen mit dem Bearbeiten von Text zusammen. Einige davon können auf Basis der jeweiligen Sprache übergangen werden. Prüfe die jeweiligen Spracheinstellungen auf der jeweiligen Package-Einstellungsseite in der Liste aller installierten Pakete.'
+        html: 'Diese Einstellungen hängen mit dem Bearbeiten von Text zusammen. Einige davon können auf Basis der jeweiligen Sprache übergangen werden. Prüfe die jeweiligen Spracheinstellungen auf der jeweiligen Package-Einstellungsseite in der Liste aller installierten Plugins.'
       }
     ]
     controls: [
@@ -110,7 +110,7 @@
       {
         _id: 'core.excludeVcsIgnoredPaths'
         title: "Von VCS ignorierte Pfade ausschließen "
-        desc: "Dateien und Pfade welche durch das VCS eines Projektes ignoriert werden, werden auch von einigen Packagesn wie fuzzy Finder sowie Suchen/Ersetzen ignoriert. Zum Beispiel, wenn Projekte welche Git benutzen gewisse Pfade in .gitignore definiert haben. Individuelle Pakete könnten auch zusätzliche Einstellungen bzgl. ignorieren von VCS ignorierten Dateien oder Ordnern enthalten."
+        desc: "Dateien und Pfade welche durch das VCS eines Projektes ignoriert werden, werden auch von einigen Packagesn wie fuzzy Finder sowie Suchen/Ersetzen ignoriert. Zum Beispiel, wenn Projekte welche Git benutzen gewisse Pfade in .gitignore definiert haben. Individuelle Plugins könnten auch zusätzliche Einstellungen bzgl. ignorieren von VCS ignorierten Dateien oder Ordnern enthalten."
       }
       {
         _id: 'core.fileEncoding'
@@ -133,7 +133,7 @@
       {
         _id: 'core.ignoredNames'
         title: "Ignorierte Namen"
-        desc: "Liste von glob patterns. Dateien und Ordner, welche diesen Mustern entsprechen werden von einigen Packagesn ignoriert, z. B. fuzzy Finder und Baumansicht. Individuelle Pakete könnten zusätzliche Einstellungen zum Ignorieren von Namen in deren jeweiligen Einstellungen enthalten."
+        desc: "Liste von glob patterns. Dateien und Ordner, welche diesen Mustern entsprechen werden von einigen Packagesn ignoriert, z. B. fuzzy Finder und Baumansicht. Individuelle Plugins könnten zusätzliche Einstellungen zum Ignorieren von Namen in deren jeweiligen Einstellungen enthalten."
       }
       {
         _id: 'core.openEmptyEditorOnStart'
@@ -142,12 +142,12 @@
       }
       {
         _id: 'core.packagesWithKeymapsDisabled'
-        title: "Pakete mit deaktivierten Tastaturkürzeln"
+        title: "Plugins mit deaktivierten Tastaturkürzeln"
       }
       {
         _id: 'core.projectHome'
         title: "Projekt-Heimverzeichnis"
-        desc: "Verzeichnis, in dem Projekte gespeichert werden. Pakete, welche mittels dem Packages-Generator erstellt werden, werden dort standardmäßig abgelegt."
+        desc: "Verzeichnis, in dem Projekte gespeichert werden. Plugins, welche mittels dem Plugin-Generator erstellt werden, werden dort standardmäßig abgelegt."
       }
       {
         _id: 'core.reopenProjectMenuCount'
@@ -320,7 +320,7 @@
       {
         _id: 'editor.softWrapAtPreferredLineLength'
         title: "Soft Wrap anhand bevorzugter Zeilenlänge"
-        desc: "Anstelle eines Zeilenumbruches an der Fensterbreite, wird die Zeile bei der Anzahl der Zeichen umgebrochen, welche in Bevorzugte Zeilenlänge Einstellung defininiert ist. Dies hat nur einen Effekt, wenn die Soft Wrap Einstellung global oder für die aktuelle Sprache aktiviert ist. Beachte: Wenn du die Wrap-Hilfe (vertikale Linie) verbergen willst kannst du das Paket wrap-guide de-aktivieren."
+        desc: "Anstelle eines Zeilenumbruches an der Fensterbreite, wird die Zeile bei der Anzahl der Zeichen umgebrochen, welche in Bevorzugte Zeilenlänge Einstellung defininiert ist. Dies hat nur einen Effekt, wenn die Soft Wrap Einstellung global oder für die aktuelle Sprache aktiviert ist. Beachte: Wenn du die Wrap-Hilfe (vertikale Linie) verbergen willst kannst du das Plugin wrap-guide de-aktivieren."
       }
       {
         _id: 'editor.softWrapHangingIndent'
@@ -382,12 +382,12 @@
     "table-header-selector": "Selektor"
   }
   packages: {
-    searchBarText: 'Pakete nach Namen filtern'
+    searchBarText: 'Plugins nach Namen filtern'
   }
   themes: {
     notes: {
       text1: "Atom kann durch editieren "
-      text2: "Deines Stylesheets"
+      text2: "deines Stylesheets"
       text3: " angepasst werden"   # optional
       _template: "${text1} ${text2} ${text3}"
     }
@@ -401,17 +401,17 @@
     "check-updates": "Suche nach Aktualisierungen"
     "update-all": "Alles aktualisieren"
     "checking-updates": "Suche nach Aktualisierungen..."
-    "all-updated-message": "Alle deine installierten Pakete sind aktuell!"
+    "all-updated-message": "Alle deine installierten Plugins sind aktuell!"
   }
   install: {
     notes: {
-      text1: "Pakete sind veröffentlicht "
-      text2: " und wurden installiert nach "
-      text3: ""   # optional
+      text1: "Plugins sind auf "
+      text2: " veröffentlicht und wurden in "
+      text3: " installiert"   # optional
       _template: "${text1}atom.io${text2} /path/to/pkg ${text3}"
     }
-    "searchbar-placeholder": "Suche Pakete"
-    "btn-packages": "Pakete"
+    "searchbar-placeholder": "Durchsuche Plugins"
+    "btn-packages": "Plugins"
     "btn-themes": "Themes"
   }
   "control-btns":{


Add label to gradebook settings button

Add label to gradebook settings button

flag=none
fixes TALLY-61

Test plan:

- Using Firefox with JAWS installed, open New Gradebook
- Check that the Gradebook Settings cog button is labelled appropriately

Change-Id: I93c912b8a41d7641a2afcad91f121b27950d0876
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/210211
Tested-by: Service Cloud Jenkins <9144042a601061f88f1e1d7a1753ea3e2972119d@instructure.com>
QA-Review: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>
Product-Review: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>
Reviewed-by: Gary Mei <4dff5ebcff9ed76793b70b9470ac64791a16ed11@instructure.com>
Reviewed-by: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>

--- app/coffeescripts/gradezilla/Gradebook.coffee
+++ app/coffeescripts/gradezilla/Gradebook.coffee
@@ -79,6 +79,7 @@
 import LatePolicyApplicator from 'jsx/grading/LatePolicyApplicator'
 import {Button} from '@instructure/ui-buttons'
 import {IconSettingsSolid} from '@instructure/ui-icons'
+import {ScreenReaderContent} from '@instructure/ui-a11y'
 import * as FlashAlert from 'jsx/shared/FlashAlert'
 import 'jquery.ajaxJSON'
 import 'jquery.instructure_date_and_time'
@@ -1516,13 +1517,18 @@
       )

     renderSettingsButton: =>
+      iconSettingsSolid = React.createElement(IconSettingsSolid)
+
       buttonMountPoint = document.getElementById('gradebook-settings-modal-button-container')
       buttonProps =
+        icon: iconSettingsSolid,
         id: 'gradebook-settings-button',
         variant: 'icon',
         onClick: @gradebookSettingsModal.open
-      iconSettingsSolid = React.createElement(IconSettingsSolid, { title: I18n.t('Gradebook Settings') })
-      @gradebookSettingsModalButton = renderComponent(Button, buttonMountPoint, buttonProps, iconSettingsSolid)
+
+      screenReaderContent = React.createElement(ScreenReaderContent, {}, I18n.t('Gradebook Settings'))
+      settingsTitle = I18n.t('Gradebook Settings')
+      @gradebookSettingsModalButton = renderComponent(Button, buttonMountPoint, buttonProps, screenReaderContent)

     renderStatusesModal: =>
       statusesModalMountPoint = document.querySelector("[data-component='StatusesModal']")


Make participant watch map when invited

Make participant watch map when invited

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -286,6 +286,17 @@
   unwatchParticipant: (nickname) -> @myWatchMap.delete nickname

+  makeParticipantWatchMap: (nickname) ->
+
+    return  unless @amIHost
+
+    key  = "#{nickname}WatchMap"
+    host = nick()
+
+    map = @rtm.create 'map', key, {}
+    map.set host, host
+
+
   bindSocialChannelEvents: ->

     @socialChannel
@@ -304,6 +315,7 @@
       {nickname} = account.profile
       @statusBar.createParticipantAvatar nickname, no
       @watchParticipant nickname
+      @makeParticipantWatchMap nickname

   channelMessageAdded: (message) ->


Fix broken symlinks catch condition.

Fix broken symlinks catch condition.

--- client/landing/app/MainApp/fs/fshelper.coffee
+++ client/landing/app/MainApp/fs/fshelper.coffee
@@ -49,7 +49,7 @@
         [itemCount] = lines.splice(0,3)
         parentPath = parentPaths[0]
       for line in lines when line
-        unless line[0] is 'l' # broken symlinks has l type
+        unless line[0] in ['l', '?'] # broken symlinks has l type and it can be ? in someway
           unless systemFilesRegExp.test line
             data.push FSHelper.createFile parseFile parentPath, line
     data


capacity in ArrayList

capacity in ArrayList

--- tds.coffee
+++ tds.coffee
@@ -203,15 +203,14 @@

 INT_SIZE = 16
-MAX_SIZE = (1<<30) - (1<<3)
+MAX_SIZE = 1<<26

 ITER_CHANGE_VIEW = 1
 ITER_SUCCESS = 0
 ITER_FAIL = -1

-ArrayList = (struct) ->
- capacity = null
+ArrayList = (struct, capacity) ->
  arrays = null
  allViews = null
  sum = null
@@ -325,15 +324,37 @@
    @length = 0
    @struct = struct

-   capacity ?= INT_SIZE
-   n = capacity * struct.bytes
-   if n > MAX_SIZE
-    capacity = Math.floor MAX_SIZE / struct.bytes
-   lastArr = TDS.Array struct, capacity
-   lastViews = lastArr.views
-   arrays.push lastArr
-   allViews.push lastViews
-   sum.push capacity
+   if capacity?
+    @length = capacity
+    n = capacity
+    size = INT_SIZE
+    ls = 0
+    while true
+     console.log 'creating ', size
+     lastArr = TDS.Array struct, size
+     lastViews = lastArr.views
+     arrays.push lastArr
+     allViews.push lastViews
+     ls += size
+     sum.push ls
+
+     if n <= size
+      i_lastArr = arrays.length-1
+      i_lastPos = n
+      i_lla = i_lastArr
+      i_llp = n-1
+      break
+
+     n -= size
+     if size isnt MAX_SIZE
+      size = size << 1
+   else
+    capacity = INT_SIZE
+    lastArr = TDS.Array struct, capacity
+    lastViews = lastArr.views
+    arrays.push lastArr
+    allViews.push lastViews
+    sum.push capacity

   begin: ->
    if @length is 0
@@ -418,10 +439,10 @@

   addArray: ->
    n = lastArr.length
-   n *= 2
-   if n * struct.bytes > MAX_SIZE
-    n = Math.floor MAX_SIZE / struct.bytes
-
+   if n isnt MAX_SIZE
+    n = n << 1
+
+   capacity += n
    lastArr = TDS.Array struct, n
    lastViews = lastArr.views
    arrays.push lastArr


#10 检查tag和status

#10 检查tag和status

--- common.coffee
+++ common.coffee
@@ -34,4 +34,12 @@

 #检查文件夹是否存在，如果不存在，则创建
 exports.dirPromise = (dir)->
-  _fs.mkdirSync dir if not _fs.existsSync dir+  _fs.mkdirSync dir if not _fs.existsSync dir
+
+#检查tag
+exports.checkTag = (tag)->
+  if tag in ['bug', '需求', '支持', '功能'] then tag else '需求'
+
+#状态只能是这几种
+exports.checkStatus = (status)->
+  if status in ['new', 'doing', 'done', 'pause', 'trash'] then status else 'new'


fix(inject): remove the tag instantly when `isSource` is true

--- index.coffee
+++ index.coffee
@@ -1,10 +1,15 @@
 module.exports = ( script, isSource ) ->
   tag = window.document.createElement "script"
+
   if isSource
     tag.textContent = script
+    setTimeout ->
+      tag.parentNode.removeChild tag
+
   else
     tag.src = chrome.extension.getURL script
+    tag.onload = ->
+      tag.parentNode.removeChild tag
+
   tag.charset = "UTF-8"
-  tag.onload = ->
-    this.parentNode.removeChild @
   window.document.head.appendChild tag


Changed main object to a factory function

--- index.coffee
+++ index.coffee
@@ -8,14 +8,18 @@
   argv = argv.slice 2, process.argv.lenth

   Cluster = (params = {}) ->
-    @params = params
-    console.log @params
+    {host, port} = params
+    return (
+      host: host,
+      port: port
+    )

   if stdin.isTTY
-    cluster = new Cluster(
+    cluster = Cluster(
       host: argv[0],
       port: argv[1]
     )
+    console.log cluster

   return Cluster
 )()


bytesLeft and resetBits functions for Reader

--- index.coffee
+++ index.coffee
@@ -21,6 +21,8 @@
 		@data = new Uint8Array buf
 		@view = new DataView buf
 		@cur = 0
+	bytesLeft: -> @data.length - @cur
+	resetBits: -> delete @bitsLeft
 	readBits: (count) ->
 		result = 0
 		pos = 0


Removing deprecated Config::getSettings()

Atom's API has deprecated `Config::getSettings()` in favor of `Config::get()`.

In recent versions of Atom, `atom.config.getSettings().editor` doesn't return the right editor config, so variables like `tabLength` don't reflect the current settings. `atom.config.get('editor')` returns the correct settings.

--- index.coffee
+++ index.coffee
@@ -12,7 +12,7 @@
     )

 formatter = (text, sorted) ->
-  editorSettings = atom.config.getSettings().editor
+  editorSettings = atom.config.get('editor')
   if editorSettings.softTabs?
     space = Array(editorSettings.tabLength + 1).join(" ")
   else


[enh] Use path.join to handle path, and change utimes

--- index.coffee
+++ index.coffee
@@ -1,4 +1,5 @@
 fs = require 'fs'
+path = require 'path'
 request = require 'request-json'
 PouchDB = require 'pouchdb'
 mkdirp = require 'mkdirp'
@@ -89,13 +90,20 @@

     db.db.query { map: map }, (err, res) ->
         for doc in res.rows
+            name = path.join remoteConfig.path, doc.value.path, doc.value.name
             if doc.value.docType is 'Folder'
                 # Create folder
-                mkdirp.sync remoteConfig.path + doc.value.path + '/' + doc.value.name
+                mkdirp.sync name
+                fs.utimesSync name,
+                    new Date(doc.value.creationDate),
+                    new Date(doc.value.lastModification)
             else
                 # Create parent folder and touch file
-                mkdirp.sync remoteConfig.path + doc.value.path + '/'
-                touch remoteConfig.path + doc.value.path + '/' + doc.value.name
+                mkdirp.sync path.join remoteConfig.path, doc.value.path
+                touch name
+                fs.utimesSync name,
+                    new Date(doc.value.creationDate),
+                    new Date(doc.value.lastModification)

 fetchBinaries = (devicename) ->
@@ -116,12 +124,19 @@

         for doc in res.rows
             # Fetch every binary
-            filePath = remoteConfig.path + doc.value.path + '/' + doc.value.name
+            filePath = path.join remoteConfig.path, doc.value.path, doc.value.name
             if doc.value.binary?
                 binaryUri = 'cozy/' + doc.value.binary.file.id + '/file'
                 client.saveFile binaryUri, filePath, (err, res, body) ->
                     if err
                         console.log err
+
+                    # Rebuild FS Tree to correct utime
+                    buildFSTree devicename
+
+
+watchChanges = (devicename) ->
+    remoteConfig = config.config.remotes[devicename]

 runSync = (devicename) ->
@@ -162,6 +177,11 @@
     .action runSync

 program
+    .command('watch <devicename>')
+    .description('Watch changes on FS')
+    .action watchChanges
+
+program
     .command('display-config')
     .description('Display device configuration and exit')
     .action displayConfig


conditionally load passed in scripts

conditionally load passed in scripts

--- index.coffee
+++ index.coffee
@@ -1,10 +1,9 @@
 fs = require 'fs'
 path = require 'path'

-module.exports = (robot) ->
+module.exports = (robot, scripts) ->
   scriptsPath = path.resolve(__dirname, 'src')
   fs.exists scriptsPath, (exists) ->
     if exists
       for script in fs.readdirSync(scriptsPath)
-        robot.loadFile(scriptsPath, script)
-        robot.parseHelp(path.join(scriptsPath, script))
+        robot.loadFile(scriptsPath, script) if script in scripts


Helpers for management module namespaces added

--- index.coffee
+++ index.coffee
@@ -11,7 +11,7 @@
 processFile = require './process'
 buildResult = require './result'

-module.exports = (opts, callback) ->
+exports = module.exports = (opts, callback) ->
 	assert.isPlainObject opts
 	assert.isString opts.type
 	assert.isString opts.path
@@ -108,6 +108,24 @@
 		else
 			callback null, bundle

+moduleNamespaces = []
+Module = require 'module'
+Module._load = do (_super = Module._load) -> (req, parent) ->
+	for obj in moduleNamespaces
+		if obj[req]
+			return obj[req]
+	_super.apply @, arguments
+
+exports.addModulesNamespace = (obj) ->
+	moduleNamespaces.push obj
+	return
+
+exports.removeModulesNamespace = (obj) ->
+	index = moduleNamespaces.indexOf obj
+	if index isnt -1
+		moduleNamespaces.splice index, 1
+	return
+
 # if process.argv.length > 2
 # 	[_, _, path, type] = process.argv


Change point-of-view key to F5 (was 'R')

--- index.coffee
+++ index.coffee
@@ -98,7 +98,7 @@
         '<tab>': 'sprint'

         # our extras
-        'R': 'pov'
+        'F5': 'pov'
         'O': 'home'
         'E': 'inventory'


One more check for async behavior.

One more check for async behavior.

--- client/publication.coffee
+++ client/publication.coffee
@@ -28,6 +28,9 @@
     @_pages = []

     PDFJS.getDocument(@url(), null, null, @_progressCallback).then (@_pdf) =>
+      # Maybe this instance has been destroyed in meantime
+      return if @_pages is null
+
       # To make sure we are starting with empty slate
       $('#viewer .display-wrapper').empty()


finally

finally

--- assets/js/student.coffee
+++ assets/js/student.coffee
@@ -10,8 +10,8 @@

 student.on 'class', (data) ->
     console.log data
-    $("#class-num").text(data.cls_num)
-    $("#class-text").text(data.cls_text)
+    $("#class-num").text(data.clsnum)
+    $("#class-text").text(data.clstext)

 student.on 'connect', (data) ->
     $("#connecting").animate {color:'#FFFFFF'}, 1000, () ->


add linter-elixirc

add linter-elixirc

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,4 +1,7 @@
 "*":
+  "advanced-open-file":
+    createDirectories: true
+    createFileInstantly: true
   "atom-material-ui":
     colors:
       abaseColor:
@@ -62,6 +65,9 @@
     goPath: "/Users/holman/Code/go"
   linter:
     showErrorPanel: false
+  "linter-elixirc":
+    elixircPath: "/usr/local/bin/elixirc"
+    mixPath: "/usr/local/bin/mix"
   "linter-eslint":
     useGlobalEslint: true
   "linter-htmlhint": {}


remove some config

remove some config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,38 +1,10 @@
 "*":
-  "atom-beautify":
-    general:
-      _analyticsUserId: "ef914ca0-8149-498d-9ea0-0821033fa1c0"
-    json:
-      indent_size: 2
+  "atom-ide-ui":
+    "atom-ide-code-format":
+      formatOnSave: true
   core:
     disabledPackages: [
-      "exception-reporting"
-      "fast-eslint"
-      "autoclose-html"
     ]
     telemetryConsent: "limited"
-  editor:
-    invisibles: {}
-    showIndentGuide: true
-    softWrapAtPreferredLineLength: true
-  "go-plus":
-    currentPanelHeight: "14.599634846113718vh"
-    formatTool: "gofmt"
-    goPath: "/users/idawson/code/go"
-    lintOnSave: true
-    panelDisplayMode: "closed"
-    test: {}
-  gofmt:
-    formatTool: "gofmt"
-  linter:
-    lintOnChange: false
-  "linter-ui-default": {}
-  "spell-check":
-    grammars: [
-      "text.plain"
-      "source.gfm"
-      "text.git-commit"
-      "text.html.basic"
-    ]
   welcome:
     showOnStartup: false


enh: really do steps during animation

enh: really do steps during animation

--- coffee/application.coffee
+++ coffee/application.coffee
@@ -521,13 +521,20 @@
     Tinterp = interpolateHyperbolic T

     steps = generations * stepsPerGen
+    framesBeforeGeneration = stepsPerGen
+
     timerId = setInterval (=>
       observer.navigateTo @startChain, @startOffset
       p = 1.0-steps/(stepsPerGen * generations)
       observer.modifyView Tinterp(p)
       drawEverything()
       steps -=1
-      #console.log "cur tfm: #{JSON.stringify observer.getViewOffsetMatrix()}"
+      framesBeforeGeneration -= 1
+      if framesBeforeGeneration is 0
+        console.log "Next generaion!"
+        doStep()
+        framesBeforeGeneration = stepsPerGen
+
       if steps < 0
         clearInterval timerId
         console.log "End animation"


Update gruntfile

Update gruntfile

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -1,30 +1,10 @@
-module.exports = (grunt) ->
-
-  banner = '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= date %> */\n'
-
-  grunt.initConfig
-    date: grunt.template.today('dd-mm-yyyy')
-    pkg: grunt.file.readJSON 'package.json'
-    coffee:
-      compile:
-        files:
-          'dist/<%= pkg.name %>.js': ['udefine/*.coffee', 'src/*.coffee']
-    uglify:
-      options:
-        banner: banner
-        report: 'gzip'
-      dist:
-        files:
-          'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.js']
-    coffeelint:
-      options: grunt.file.readJSON 'coffeelint.json'
-      app: ['src/**/*.coffee'],
-      test: ['src/**/*.coffee'],
-      grunt: ['Gruntfile.coffee']
-
-  grunt.loadNpmTasks 'grunt-contrib-coffee'
-  grunt.loadNpmTasks 'grunt-contrib-uglify'
-  grunt.loadNpmTasks 'grunt-coffeelint'
-
-  grunt.registerTask 'test', ['coffeelint']
-  grunt.registerTask 'default', ['coffee', 'coffeelint', 'uglify']
+module.exports = (grunt) ->
+
+  require('time-grunt')(grunt)
+
+  require('load-grunt-config') grunt,
+    jitGrunt: true
+
+  grunt.registerTask 'default', ['clean', 'amd_tamer', 'uglify']
+
+  grunt.registerTask 'test', ['jshint']


lint with jshint

lint with jshint

--- config/application.coffee
+++ config/application.coffee
@@ -5,7 +5,7 @@
   pkg: lineman.grunt.file.readJSON("package.json")

   appTasks:
-    common: [ "concat", "copy", "pages" ]
+    common: [ "jshint", "concat", "copy", "pages" ]
     dev: [ "exec", "watch" ]
     dist: []

@@ -45,6 +45,10 @@
     reloadExtension:
       cmd: "open -g -a 'Google Chrome' http://reload.extensions"

+  jshint:
+    background:
+      src: "<%= files.background.js.app %>"
+
   pages:
     background:
       src: "<%= files.background.pages.source %>"
@@ -66,6 +70,10 @@
       files: [ "<%= files.background.js.vendor %>", "<%= files.background.js.app %>" ]
       tasks: [ "concat:backgroundJs", "exec" ]

+    jshintBackground:
+      files: "<%= files.background.js.app %>"
+      tasks: "jshint:background"
+
     pagesBackground:
       files: "<%= files.background.pages.source %>"
       tasks: [ "pages:background", "exec" ]


Add "new Error(errorMessage)" to Promise.reject arg

--- snippets/promises.cson
+++ snippets/promises.cson
@@ -59,7 +59,7 @@

   "Promise.reject":
     prefix: "reject"
-    body: "Promise.reject(${1:err})"
+    body: "Promise.reject(${1:new Error(${2:errorMessage})})"
   "Promise.reject +":
     prefix: "Promise.reject"
-    body: "Promise.reject(${1:err})"
+    body: "Promise.reject(${1:new Error(${2:errorMessage})})"


[Scene] Added object Save shortcut, added accessor to GameObject class

--- source/js/scene.coffee
+++ source/js/scene.coffee
@@ -12,9 +12,15 @@
       else # Else just copy the value
         @[ prop ] = value

+  save: ->
+    @scene.dash.refreshObject @Name, this
+
 class DashScene
   # Scene object tree
   objects: []
+
+  # Pass through for GameObject class
+  GameObject: GameObject

   constructor: ( dash ) ->
     @dash = dash


.... a SEMI COLON?!

.... a SEMI COLON?!

--- src/scripts/hubot-demolition-man.coffee
+++ src/scripts/hubot-demolition-man.coffee
@@ -46,7 +46,7 @@
     'wank',
     'wichser'
   ]
-  regex = new RegExp("\\b(#{words.join('|')})\\b", 'ig');
+  regex = new RegExp("\\b(#{words.join('|')})\\b", 'ig')

   robot.hear regex, (msg) ->
     credit = msg.message.text.match(regex).length


Trix.Debugger

Trix.Debugger

--- src/trix/core/utilities/debugger.coffee
+++ src/trix/core/utilities/debugger.coffee
@@ -37,113 +37,17 @@
     didKeyDownDialogInput
   "

-{makeFragment} = Trix
-{defaultContent} = TrixToolbarElement::constructor
+{findClosestElementFromNode} = Trix

-defaultContent.querySelector(".button_groups")?.appendChild makeFragment """
-
-    <button type="button" class="debug" data-action="debug" data-error-content="☠">ℹ</button>
-
-"""
+errorListeners = []

-defaultContent.querySelector(".dialogs")?.appendChild makeFragment """
-

-

-
Copy and paste:

-      <textarea readonly></textarea>
-

-

-"""
+Trix.Debugger =
+  addErrorListener: (listener) ->
+    unless listener in errorListeners
+      errorListeners.push(listener)

-TrixToolbarElement::constructor.defaultCSS += """
-  %t button[data-action=debug].error {
-    border: 1px solid red;
-    color: red;
-  }
-
-  %t .dialog[data-attribute=debug] {
-    position: absolute;
-    width: 500px;
-    padding: 10px;
-    margin: 5px 0 0 5px;
-    border-radius: 2px;
-    background-color: white;
-    border: 1px solid black;
-    font-family: monospace;
-    font-size: 12px;
-  }
-
-  %t .dialog[data-attribute=debug] textarea {
-    box-sizing: border-box;
-    width: 100%;
-    margin: 10px 0 0 0;
-    height: 200px;
-    border: none;
-  }
-"""
-
-Trix.EditorController.toolbarActions.debug = test: -> true
-
-
-{tagName, findClosestElementFromNode, handleEvent} = Trix
-
-buttonSelector = "button[data-action=debug]"
-
-handleEvent "click", onElement: document, matchingSelector: buttonSelector, withCallback: (event) ->
-  setDebugInfo(element: event.target, focus: true)
-  event.preventDefault()
-
-setDebugInfo = ({element, error, focus}) ->
-  editorElement = findClosestElementFromNode(element, matchingSelector: "trix-editor")
-  {editorController} = editorElement
-  toolbarElement = editorElement.querySelector("trix-toolbar")
-  buttonElement = toolbarElement.querySelector(buttonSelector)
-  textareaElement = toolbarElement.querySelector(".dialog[data-attribute=debug] textarea")
-  documentElement = editorElement.querySelector("trix-document")
-
-  info = ""
-
-  if error?
-    buttonElement.classList.add("error")
-    buttonElement.textContent = buttonElement.dataset.errorContent
-    info += "Error: #{error.message}\n  #{error.stack}"
-
-  info += """
-    URL:
-      #{window.location}
-    Location range:
-      #{editorController.getLocationRange()?.inspect()}
-    Last input:
-      #{JSON.stringify(editorController.inputController.inputSummary)}
-    Document:
-      #{JSON.stringify(editorController.document)}
-    HTML:
-      #{documentElement.innerHTML}
-  """
-
-  shouldUpdateTextarea = error? or not buttonElement.classList.contains("error")
-
-  textareaElement.value = info if shouldUpdateTextarea
-  textareaElement.select() if focus?
-
-reportError = (error) ->
-  console.error "Trix error!"
-  console.log error.stack
-
-  element = document.activeElement
-  if tagName(element) is "trix-document"
-    setDebugInfo({element, error})
-  else
-    console.warn "Can't find <trix-document> element. document.activeElement =", element
-
-wrapFunctionWithErrorHandler = (fn) ->
-  trixDebugWrapper = ->
-    try
-      fn.apply(this, arguments)
-    catch error
-      reportError(error)
-      throw error
-  trixDebugWrapper
+  removeErrorListener: (listener) ->
+    errorListeners = (l for l in errorListeners when l isnt listener)

 installMethodDebugger = (className, methodName) ->
   [objectName, constructorNames...] = className.split(".")
@@ -159,7 +63,34 @@
   else
     throw new Error "Can't install on non-function"

-install = ->
+wrapFunctionWithErrorHandler = (fn) ->
+  trixDebugWrapper = ->
+    try
+      fn.apply(this, arguments)
+    catch error
+      reportError(error)
+      throw error
+  trixDebugWrapper
+
+reportError = (error) ->
+  Trix.Debugger.lastError = error
+
+  console.error "Trix error!"
+  console.log error.stack
+
+  activeElement = document.activeElement
+  editorElement = findClosestElementFromNode(activeElement, matchingSelector: "trix-editor")
+
+  if editorElement
+    notifyErrorListeners(error, editorElement)
+  else
+    console.warn "Can't find <trix-editor> element. document.activeElement =", activeElement
+
+notifyErrorListeners = (error, element) ->
+  for listener in errorListeners
+    try listener(error, element)
+
+do ->
   console.groupCollapsed("Trix debugger")

   for className, methodNames of DEBUG_METHODS
@@ -171,5 +102,3 @@
         console.warn "✗ #{className}##{methodName}:", error.message

   console.groupEnd()
-
-install()


Render: Fix not drawing meshes with shadeless materials in some platforms.

--- engine/render.coffee
+++ engine/render.coffee
@@ -541,7 +541,7 @@
                 mat3.multiply m3, @_world2cam3, mesh.normal_matrix
                 if mat.u_normal_matrix?
                     gl.uniformMatrix3fv mat.u_normal_matrix, false, m3
-                    gl.drawElements data.draw_method, num_indices, gl.UNSIGNED_SHORT, 0
+                gl.drawElements data.draw_method, num_indices, gl.UNSIGNED_SHORT, 0
             # if mirrors & 178
             #     mat4.multiply m4, @_world2cam_mx, mesh2world
             #     gl.uniformMatrix4fv mat.u_model_view_matrix, false, m4


Send notifications during the type check process (:write-string)

--- lib/idris-model.coffee
+++ lib/idris-model.coffee
@@ -58,6 +58,7 @@
             delete @subjects[id]
           when ':write-string'
             msg = params[0]
+            atom.notifications.addInfo msg
             subject.onNext
               responseType: 'write-string'
               msg: msg


trakttv: Do not store anything into localStorage. Finally.

--- src/js/trakttv.coffee
+++ src/js/trakttv.coffee
@@ -6,7 +6,6 @@
 async = require('async')
 appinfo = require('appinfo')

-shows = Settings.data 'shows'
 events = new Emitter()

 trakttv = {}


only copy Base extenders

only copy Base extenders

--- src/lib/facade.coffee
+++ src/lib/facade.coffee
@@ -107,13 +107,17 @@
         return @classes[name] if @classes[name]?

         path = "#{@dirname}/#{name}"
-        facade = @
+        klass = require path

-        klass = require path
-        Class = copy(klass)
-        Class::getFacade = -> facade

-        @classes[name] = Class
+        if klass::getFacade is @constructor.Base::getFacade
+            facade = @
+            Class = copy(klass)
+            Class::getFacade = -> facade
+            @classes[name] = Class
+        else
+            @classes[name] = klass
+

     ###*
     read a file and returns the instance of the file's class


Implementing subsequent split plans.

Implementing subsequent split plans.

--- src/lib/strata.coffee
+++ src/lib/strata.coffee
@@ -1,11 +1,26 @@
 # Glossary:
-#  * Descent - What we call an attempt to traverse the tree, which may be
-#              paused because it encounters a lock on a tier.
+#  * Descent - What we call an attempt to move from a parent node to a child
+#              node in  the tree, which may be paused because it encounters a
+#              lock on a tier.
 class Mutation
   constructor: (@strata, @object, @fields, initial, subsequent, swap, penultimate, @callback) ->
-    @levels = []
     @decisions = { initial, subsequent, swap, penultimate }
-    @exclusive = false
+    @parent = new Level
+    @child = new Level
+    @exclusive = []
+    @plan = []
+
+  # Descend the tree, optionally starting an exclusive descent. Once the descent
+  # is exclusive, all subsequent descents are exclusive.
+  descend: (exclusive) ->
+    @plan.unshift { operations: [] }
+    if @exclusive.length > 1
+      @parent.release(strata)
+    exclusive or= @exclusive.length > 0
+    @parent = @child
+    @child = new Level(exclusive)
+    if exclusive
+      @exclusive.release(strata)

 class Level
   # Construct a new level. The `exclusive` pararameter determines how this level
@@ -13,6 +28,7 @@
   constructor: (@exclusive) ->
     @operations = []
     @locks = []
+
   lock: (strata, mutation, address, callback) ->
     # TODO Will it matter if we load before we lock? We probably have to.
     strata.io.load strata, mutation, address, (mutation, tier) =>
@@ -134,11 +150,12 @@
     @io             = options.io          or new module.exports.InMemory
     @_initialize(options.rootAddress)

-  _initialize: (@rootAddress) ->
-    if not @rootAddress
-      @rootAddress = @io.allocate false, true, @innerSize
-      # TODO: Rethink construction API.
-      @io.load @, @rootAddress, @_createRoot
+  # TODO: Construction and allocation of the root tier may require an
+  # asynchronous load, so we may need a factory method.
+  _initialize: (@_rootAddress) ->
+    if not @_rootAddress
+      @_rootAddress = @io.allocate false, true, @innerSize
+      @io.load @, @_rootAddress, @_createRoot, ->

   _createRoot: (root) ->
     root.push { pivot: null, address: @io.allocate true, false, @leafSize }
@@ -153,12 +170,12 @@
   #
   # This generalized mutation will insert or remove a single item.
   _generalized: (mutation) ->
-    mutation.levels.unshift new Level
-    mutation.levels[0].lock @, mutation, @rootAddress, @_rootLoaded
+    mutation.descend false
+    mutation.child.lock @, mutation, @_rootAddress, @_rootLoaded

   # Perform the root decision with only a read lock obtained.
   _rootLoaded: (mutation, root) ->
-    mutation.levels[0].tier = root
+    mutation.child.tier = root
     mutation.decisions.initial.call @, mutation
     @_tierDecision mutation

@@ -166,7 +183,7 @@
   # tiers with inner tier children then for penultimate inner tiers with leaf
   # tier children.
   _tierDecision: (mutation) ->
-    if mutation.level[0].tier.penultimate
+    if mutation.levels[0].tier.penultimate
       @_testInnerTier mutation, mutation.decisions.penultimate, @_operate
     else
       @_testInnerTier mutation, mutation.decisions.subsequent, @_tierDescend
@@ -275,9 +292,9 @@

   # If the root is full, we add a root split operation to the operation stack.
   _shouldDrainRoot: (mutation) ->
+    if @innerSize is mutation.child.tier.size()
+      mutation.plan[0].operations.push "splitRoot"
     console.log "_shouldDrainRoot"
-    if @innerSize is mutation.levels[0].tier.size()
-      mutation.levels[0].operations.push "splitRoot"

   # Shorthand to allocate a new inner tier.
   _newInnerTier: (mutation, penultimate) ->
@@ -542,7 +559,7 @@
   # TODO Now there is a chance that this might already be in a split state. What
   # do we do? Do we create a new plan as we decend to test the current plan?
   _howToInsertLeaf: (mutation) ->
-
+    console.log mutation
     # Find the branch that navigates to the leaf child.
     branch = @_find mutation.parentLevel.tier, mutation.fields
     @io.load @, mutation, mutation.parentLevel.tier.get(branch).address, @_inspectLeafForSplitLoaded


Revert "Test that PatchIterator::next() doesn't return boundaries"

This reverts commit dd3b67e7e59707525ed4efd2e41ac67301c3dc7e.

Conflicts:
	spec/patch-spec.coffee

--- spec/patch-spec.coffee
+++ spec/patch-spec.coffee
@@ -119,18 +119,6 @@

           iterator.seekToInputPosition(Point(0, 17))
           iterator.splice(Point(0, 4), Point(0, 2), "hi")
-
-        it "does not return boundaries from ::next()", ->
-          expectHunks patch.buildIterator(), [
-            [Point(0, 5), Point(0, 5), null]
-            [Point(0, 8), Point(0, 9), "abcd"]
-            [Point(0, 10), Point(0, 11), null]
-            [Point(0, 12), Point(0, 14), "efg"]
-            [Point(0, 15), Point(0, 17), null]
-            [Point(0, 17), Point(0, 19), null]
-            [Point(0, 21), Point(0, 21), "hi"]
-            [Point.INFINITY, Point.INFINITY, null]
-          ]

         it "can seek to the boundary to the left of the given position", ->
           iterator.seekToLeftBoundaryForInputPosition(Point(0, 9))


Allow user package specs to override bundled package specs

--- spec/spec-suite.coffee
+++ spec/spec-suite.coffee
@@ -1,10 +1,10 @@
-fs = require 'fs'
-
 require 'window'

 measure 'spec suite require time', ->
+  fs = require 'fs'
   fsUtils = require 'fs-utils'
   path = require 'path'
+  _ = require 'underscore'
   require 'spec-helper'

   requireSpecs = (directoryPath, specType) ->
@@ -19,15 +19,20 @@
   requireSpecs(window.resourcePath)
   setSpecType('core')

+  fixturesPackagesPath = fsUtils.resolveOnLoadPath('fixtures/packages')
+  packagePaths = atom.getAvailablePackageNames().map (packageName) -> atom.resolvePackagePath(packageName)
+  packagePaths = _.groupBy packagePaths, (packagePath) ->
+    if packagePath.indexOf("#{fixturesPackagesPath}#{path.sep}") is 0
+      'fixtures'
+    else if packagePath.indexOf("#{window.resourcePath}#{path.sep}") is 0
+      'bundled'
+    else
+      'user'
+
   # Run bundled package specs
-  if fsUtils.isDirectorySync(config.nodeModulesDirPath)
-    for packageName in fs.readdirSync(config.nodeModulesDirPath)
-      packagePath = path.join(config.nodeModulesDirPath, packageName)
-      requireSpecs(packagePath, 'bundled') if atom.isInternalPackage(packagePath)
-    setSpecType('bundled')
+  requireSpecs(packagePath) for packagePath in packagePaths.bundled
+  setSpecType('bundled')

   # Run user package specs
-  if fsUtils.isDirectorySync(config.userPackagesDirPath)
-    for packageName in fs.readdirSync(config.userPackagesDirPath)
-      requireSpecs(path.join(config.userPackagesDirPath, packageName))
-    setSpecType('user')
+  requireSpecs(packagePath) for packagePath in packagePaths.user
+  setSpecType('user')


fix a couple error messages;

fix a couple error messages;

--- app/assets/javascripts/chr/core/view.coffee
+++ app/assets/javascripts/chr/core/view.coffee
@@ -116,7 +116,7 @@
       @store.update @object._id, serializedFormObj,
         onSuccess: (@object) =>
           @_save_success()
-        onError: (errors) => @_save_error('Changes were not saved.', errors)
+        onError: (errors) => @_save_error('Changes are not saved.', errors)
     else
       @store.push serializedFormObj,
         onSuccess: (@object) =>
@@ -124,7 +124,7 @@
           @_add_delete_button()
           chr.updateHash("#{ @closePath }/view/#{ @object._id }", true)
           @path = window.location.hash
-        onError: (errors) => @_save_error('Item were not created.', errors)
+        onError: (errors) => @_save_error('Document is not created due to an error.', errors)

   _delete: (e) ->
@@ -136,7 +136,7 @@
           chr.updateHash("#{ @closePath }", true)
           @destroy()
           chr.mobileListLock(false)
-        onError: -> chr.showError('Can\'t delete object.')
+        onError: -> chr.showError('Can\'t delete document.')

   _render_form: ->


I sure am silly.

I sure am silly.

--- config.coffee
+++ config.coffee
@@ -254,7 +254,7 @@
     static:
       processors: [
         require('./brunch-static-stuff') {
-          locals: {shaTag: 'dev' or process.env.GIT_SHA}
+          locals: {shaTag: process.env.GIT_SHA or 'dev'}
         }
       ]


removed unneeded coffescript file

removed unneeded coffescript file

--- app/assets/javascripts/statistics.js.coffee
+++ app/assets/javascripts/statistics.js.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


Reinstate currency to Stripe signup button

They hide it for USD and show it for all other currencies so we had it
with AUD before.

--- app/assets/javascripts/supporters.js.coffee
+++ app/assets/javascripts/supporters.js.coffee
@@ -16,7 +16,7 @@
         amount: button.attr("data-amount")
         currency: "USD"
         email: button.attr("data-email")
-        panelLabel: "Signup {{amount}}/mo"
+        panelLabel: "Signup USD {{amount}}/mo"
     else
       $("#supporter-signup-form").submit()

@@ -37,4 +37,4 @@
       amount: amountInCents
       currency: "USD"
       email: button.attr("data-email")
-      panelLabel: "Contribute {{amount}}"
+      panelLabel: "Contribute USD {{amount}}"


Renamed lineData4 into p2h_curve

Renamed lineData4 into p2h_curve


update anim fields proposal

update anim fields proposal

--- app/assets/javascripts/geozone.js.coffee
+++ app/assets/javascripts/geozone.js.coffee
@@ -11,10 +11,11 @@
     hideFields()
   else
     $('#proposal_tipe_proyecto').prop("checked", true)
-  if $('input:radio[name="proposal[level]"]:checked').val() == "Idea"
-    hideFields()
-  else
-    $('#proposal_level_perfil').prop("checked", true)
+    if $('input:radio[name="proposal[level]"]:checked').val() == "Idea"
+      hideFields()
+    else
+      if $('input:radio[name="proposal[level]"]:checked').val() != "Expediente Técnico"
+        $('#proposal_level_perfil').prop("checked", true)
   $("#proposal_tipe_actividad").click ->
     $("#level_of_study").hide()
     hideFields()


fix coffeescript bugs

fix coffeescript bugs

how embarrassing

--- app/assets/transit/lib/views/plan.coffee
+++ app/assets/transit/lib/views/plan.coffee
@@ -130,7 +130,7 @@

   reset: =>
     @$('.progress').hide()
-    remove_itineraries()
+    @remove_itineraries()
     Transit.errorMessage(null)  # clear the error message

   add_itineraries: (plan) =>
@@ -151,7 +151,7 @@

   # remove all itineraries from the map
   remove_itineraries: =>
-    for view in @views if @views?
+    if @views? then for view in @views
       view?.clean_up(true)
       view.remove()
     @$('#itineraries').html('')


Simplify search using window.find

Simplify search using window.find

--- app/js/jail_iframe/util/highlight.coffee
+++ app/js/jail_iframe/util/highlight.coffee
@@ -28,27 +28,18 @@

 # Chrome, Firefox, Safari
 searchWithWindowFind = (searchString) ->
-  # Trim
-  searchString = searchString.trim();

-  # If the user currently has selected some text, store the selection
   selection = window.document.getSelection()
-  selectedRange = selection.getRangeAt(0) if selection.rangeCount > 0
-
   # Reset the selection
-  window.document.getSelection().removeAllRanges()
+  selection.removeAllRanges()

   # Loop through all the results of the search string
   results = []
   while window.find(searchString, false)
-    selection = window.document.getSelection()
     results.push selection.getRangeAt(0)

-  # Reset the selection
-  window.document.getSelection().removeAllRanges()
+  results

-  # Restore previous selection
-  window.document.getSelection().addRange selectedRange if selectedRange?

   results


refactor code to draw the legends

refactor code to draw the legends

add a generic legend rendering function to minimize code duplication.

--- app/scripts/directives/choropleth.coffee
+++ app/scripts/directives/choropleth.coffee
@@ -144,6 +144,11 @@
       renderLegend(scope, valFn)

+
+  #    #############################################
+  #      Legend Rendering
+  #    #############################################
+
   renderLegend = (scope, valFn) ->
     # reset current legend
     scope.legend.selectAll('li.key')
@@ -155,22 +160,27 @@
     isCategorical = mapInstance.getValueType() == 'categorical'

     if isCategorical
-      renderCategoricalLegend(scope, valFn, mapInstance)
+      genericLegendRender(scope, $.proxy(filterDataForCategoricalLegend, this, mapInstance, valFn),
+      (d) ->
+        d.value
+      , (d) ->
+        d.key
+      )
     else
-      renderNumericalLegend(scope, valFn, mapInstance)
-
-
-  renderNumericalLegend = (scope, valFn, mapInstance) ->
-    data = valFn.range()
-
+      genericLegendRender(scope, valFn.range, (d) ->
+        extent = valFn.invertExtent(d)
+        "#{Math.round(10*extent[0])/10} – #{Math.round(10*extent[1])/10}"
+      , (d) ->
+        d
+      )
+
+
+  genericLegendRender = (scope, dataFn, textFn, classFn) ->
     scope.legend.selectAll('li.key')
-        .data(data)
+        .data(dataFn())
       .enter().append('li')
         .attr('class', 'key')
-        .text( (d, index) ->
-          extent = valFn.invertExtent(d)
-          "#{Math.round(10*extent[0])/10} – #{Math.round(10*extent[1])/10}"
-        )
+        .text( (d) -> textFn(d) )
       .append('svg')
         .attr('height', 30)
       .append('rect')
@@ -178,34 +188,19 @@
         .attr('height', 10)
         .attr('y', 10)
         .attr('x', (d, index) -> $(this).outerWidth() * index)
-        .attr('class', (d) -> "#{d}")
-
-
-  renderCategoricalLegend = (scope, valFn, mapInstance) ->
+        .attr('class', (d) -> classFn(d) )
+
+
+  filterDataForCategoricalLegend = (mapInstance, valFn) ->
     data = []
-    dataUsed = mapInstance.usedDataValues #['SVP', 'SP', 'CVP', 'FDP', 'Uebrige', 'BDP']
+    dataUsed = mapInstance.usedDataValues
     for entry, index in valFn.range()
       category = valFn.domain()[index]
       if dataUsed.indexOf(category) != -1
         data.push
           key: entry
           value: category
-
-    scope.legend.selectAll('li.key')
-      .data(data)
-    .enter().append('li')
-      .attr('class', 'key')
-      .text( (d, index) ->
-        d.value
-      )
-    .append('svg')
-      .attr('height', 30)
-    .append('rect')
-      .attr('width', '100%')
-      .attr('height', 10)
-      .attr('y', 10)
-      .attr('x', (d, index) -> $(this).outerWidth() * index)
-      .attr('class', (d) -> "#{d.key}")
+    data

   # Stop progress bar with a timeout to prevent running conditions
@@ -214,6 +209,10 @@
       ngProgress.complete()
     , 1000

+
+  #    #############################################
+  #      Directive Literal
+  #    #############################################

   return {
     restrict: 'EA'


Move on despite errors

Move on despite errors

--- apps/artist/client/views/overview.coffee
+++ apps/artist/client/views/overview.coffee
@@ -81,7 +81,7 @@
   waitForFilter: ->
     dfd = $.Deferred()
     { filter, artworks } = @filterView
-    @listenToOnce artworks, 'sync', dfd.resolve
+    @listenToOnce artworks, 'sync error', dfd.resolve
     dfd.promise()

   renderRelatedArtists: (type) ->


[EVENTRIC-55] Fix rebase fail

[EVENTRIC-55] Fix rebase fail

--- src/projection.coffee
+++ src/projection.coffee
@@ -176,10 +176,12 @@

   destroyInstance: (projectionId, context) ->
+    return unless @_handlerFunctions[projectionId]
+
     for subscriberId in @_handlerFunctions[projectionId]
       context.unsubscribeFromDomainEvent subscriberId
     delete @_handlerFunctions[projectionId]
     delete @_projectionInstances[projectionId]

-module.exports = new Projection+module.exports = new Projection


s/lookahead/non-capturing

s/lookahead/non-capturing

--- lexer.coffee
+++ lexer.coffee
@@ -565,7 +565,7 @@
 LEADING_SPACES  = /^\s+/
 TRAILING_SPACES = /\s+$/
 NO_NEWLINE      = /// ^
-  (?:                                   # lookahead
+  (?:                                   # non-capturing...
     [-+*&|/%=<>!.\\][<>=&|]* |          # symbol operators
     and | or | is(?:nt)? | n(?:ot|ew) | # word operators
     delete |typeof | instanceof


Issue #2060 cleanup

Issue #2060 cleanup

--- lexer.coffee
+++ lexer.coffee
@@ -133,8 +133,8 @@
   numberToken: ->
     return 0 unless match = NUMBER.exec @chunk
     number = match[0]
-    if /[E]/.test number
-      @error "exponential notation must be indicated with a lowercase 'e'"
+    if /E/.test number
+      @error "exponential notation '#{number}' must be indicated with a lowercase 'e'"
     else if /[BOX]/.test number
       @error "radix prefixes must be lowercase '#{number}'"
     else if /^0[89]/.test number


Update navigation.cjsx

Update navigation.cjsx

Updating link for event

--- app/navigation.cjsx
+++ app/navigation.cjsx
@@ -51,7 +51,7 @@
         {links}
         Discuss
         Blog
-        Vote
+        Vote


fix file API for cobalt

fix file API for cobalt

--- code/serv.coffee
+++ code/serv.coffee
@@ -112,7 +112,8 @@
 app.get "/:org/:project/files/*", (req, res) ->
   res.removeHeader('Content-Type')
   user_name = req.params.org + '.' + req.params.project
-  path = req.path.replace "/#{user_name}/files", ''
+  box_name = req.params.org + '/' + req.params.project
+  path = req.path.replace "/#{box_name}/files", ''
   path = path.replace /\'/g, ''
   user_name = user_name.replace /\'/g, ''
   su = child_process.spawn "su", ["-c", "cat '/home#{path}'", "#{user_name}"]


Analytics!

Analytics!

--- app/index.coffee
+++ app/index.coffee
@@ -7,6 +7,7 @@
 Manager = require 'spine/lib/manager'
 Route = require 'spine/lib/route'

+googleAnalytics = require 'zooniverse/lib/google_analytics'
 Config = require 'lib/config'
 Api = require 'zooniverse/lib/api'
 TopBar = require 'zooniverse/lib/controllers/top_bar'
@@ -43,6 +44,8 @@

   constructor: ->
     super
+
+    googleAnalytics.init account: 'UA-1224199-33', domain: 'cyclonecenter.org'

     Api.init host: Config.apiHost


Fix sorting for season 9.5

Fix sorting for season 9.5

--- app/index.coffee
+++ app/index.coffee
@@ -77,6 +77,10 @@
         8.5 - b.season
       else if b.season is '0'
         a.season - 8.5
+      else if a.season is '999'
+        9.5 - b.season
+      else if b.season is '999'
+        a.season - 9.5
       else
         a.season - b.season


simplify input compoments

simplify input compoments

--- app/input.coffee
+++ app/input.coffee
@@ -3,38 +3,23 @@
 modules = require './modules'
 React = require './react_abuse'

-InputMixin =
-  getInitialState: ->
-    value: @props.default_value
+InputMixin = _.extend {}, React.ObservableMixin,
+  get_observable: -> @props.model
   handle_change: (e) ->
-    @setState value: e.target.value
-    @props.bus.push e.target.value
+    @props.model.set e.target.value

 # creates an input component bound to a bacon model
 # changes to the input component will update the model and changes to the
 # model will update the input component
 create_component = (constructor, props) ->
-  bus = new Bacon.Bus()
-  c = React.ComponentProxy()
+  model = Bacon.Model if props.default_value then String(props.default_value) else ''

-  props = _.extend {default_value: ''}, props, {bus, component_proxy: c}
-  value = props.default_value
-  bus.onValue (v) -> value = v
-  model = Bacon.Binding
-    events: bus
-    set: (v) -> c.setState value: (v)
-    get: => value
+  props = _.extend props, {model}
   component = constructor props
-  component.model = model
   {component, model}

-_InputComponent = React.createClass
-  mixins: [React.ComponentProxyMixin, InputMixin]
-  render: ->
-    React.DOM.input type: @props.type, value: @state.value, onChange: @handle_change
-
-_SelectComponent = React.createClass
-  mixins: [React.ComponentProxyMixin, InputMixin]
+SelectComponent = React.createClass
+  mixins: [InputMixin]
   render: ->
     React.DOM.select {value: @state.value, onChange: @handle_change}, _.map @props.options, (o) ->
       if _.isArray o
@@ -43,30 +28,28 @@
         k = v = o
       React.DOM.option {value: k}, v

-SelectComponent = (props) ->
-  default_value = if props.default_value?
-    props.default_value
-  else
-    v = props.options[0]
-    if _.isArray v
-      v[0]
-    else
-      v
-  # TODO the selection context fn will call this with a default_value of undefined,
-  # so the more natural _.extend {default_value}, props doesn't work
-  create_component _SelectComponent, _.extend {}, props, {default_value}
+InputComponent = React.createClass
+  mixins: [InputMixin]
+  render: ->
+    React.DOM.input type: @props.type, value: @state.value, onChange: @handle_change

 input = modules.export exports, 'input', ({fn}) ->
   # inputs and selects return a Bacon.Model, which is a property with get and set methods
   # https://github.com/baconjs/bacon.model

   fn 'text_input', 'A text input field', (default_value='') ->
-    {component, model} = create_component _InputComponent, {type: 'text', default_value}
+    {component, model} = create_component InputComponent, {type: 'text', default_value}
     @add_component component
     @value model

   fn 'select', 'A select field', (options, default_value) ->
-    {component, model} = SelectComponent {options, default_value}
+    unless default_value
+      v = options[0]
+      default_value = if _.isArray v
+        v[0]
+      else
+        v
+    {component, model} = create_component SelectComponent, {options, default_value}
     @add_component component
     @value model


fix bug causing double transform

fix bug causing double transform

--- bokehjs/src/coffee/common/properties.coffee
+++ bokehjs/src/coffee/common/properties.coffee
@@ -28,7 +28,7 @@
       throw new Error("field value for property '#{attr}' is not a string")

     if @fixed_value?
-      @validate(@fixed_value)
+      @validate(@fixed_value, attr)

   value: () ->
     result = if @fixed_value? then @fixed_value else NaN
@@ -37,17 +37,16 @@
   array: (source) ->
     data = source.get('data')
     if @field? and (@field of data)
-      result = source.get_column(@field)
+      return @transform(source.get_column(@field))
     else
       length = source.get_length()
       length = 1 if not length?
-      value = @value()
-      result = (value for i in [0...length])
-    return @transform(result)
+      value = @value() # already transformed
+      return (value for i in [0...length])

   transform: (values) -> values

-  validate: (value) -> true
+  validate: (value, attr) -> true

 #
 # Numeric Properties
@@ -55,7 +54,7 @@

 class Numeric extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not _.isNumber(value)
       throw new Error("numeric property '#{attr}' given invalid value: #{value}")
     return true
@@ -72,8 +71,7 @@
     super(attrs, options)
     obj = @get('obj')
     attr = @get('attr')
-    spec = obj.get(attr)
-    @units = spec?.units ? obj.get("#{attr}_units") ? "rad"
+    @units = @spec?.units ? obj.get("#{attr}_units") ? "rad"
     if @units != "deg" and @units != "rad"
       throw new Error("Angle units must be one of 'deg' or 'rad', given invalid value: #{@units}")

@@ -100,35 +98,35 @@

 class Array extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not _.isArray(value)
       throw new Error("array property '#{attr}' given invalid value: #{value}")
     return true

 class Bool extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not _.isBoolean(value)
       throw new Error("boolean property '#{attr}' given invalid value: #{value}")
     return true

 class Coord extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not _.isNumber(value) and not _.isString(value)
       throw new Error("coordinate property '#{attr}' given invalid value: #{value}")
     return true

 class Color extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not svg_colors[value]? and value.substring(0, 1) != "#"
       throw new Error("color property '#{attr}' given invalid value: #{value}")
     return true

 class String extends Property

-  validate: (value) ->
+  validate: (value, attr) ->
     if not _.isString(value)
       throw new Error("string property '#{attr}' given invalid value: #{value}")
     return true
@@ -139,7 +137,7 @@
     @levels = attrs.values.split(" ")
     super(attrs, options)

-  validate: (value) ->
+  validate: (value, attr) ->
     if value not in @levels
       throw new Error("enum property '#{attr}' given invalid value: #{value},
                        valid values are: #{@levels}")


fix (postMessage) Do not completely hijack postmessages, let them through

--- src/PostMessage.coffee
+++ src/PostMessage.coffee
@@ -1,4 +1,9 @@
 class PostMessage
+
+  @originalPostMessage: do (win = window)->
+    original = win.postMessage
+    (args...)->
+      original.apply win, args

   @postMessage: (message, targetOrigin) =>
     escapedJSONMessage = escape(JSON.stringify(message))
@@ -10,6 +15,8 @@
       successCallbacks: []
       failureCallbacks: []
       recurringCallbacks: []
+
+    @originalPostMessage message, targetOrigin


Only trigger retry if not abort

Only trigger retry if not abort

--- src/retry-ajax.coffee
+++ src/retry-ajax.coffee
@@ -23,7 +23,7 @@
     # whenever we do make this request, pipe its output to our deferred

     nextRequest = ->
-      $(window).trigger(events.RETRY)
+      $(window).trigger(events.RETRY, input)
       $.ajax(ajaxOptions).retry(
         times: times - 1
         timeout: opts.timeout
@@ -48,7 +48,8 @@
       else
         nextRequest()
     else
-      $(window).trigger(events.FAIL_RETRY, input)
+      if (input.statusText isnt 'abort' or jqXHR.statusText isnt 'abort')
+        $(window).trigger(events.FAIL_RETRY, input)
       # no times left, reject our deferred with the current arguments
       output.rejectWith this, arguments
-    output+    output


Fix for spakers array that's not ready yet

--- client/controller/vote-controller.coffee
+++ client/controller/vote-controller.coffee
@@ -14,8 +14,9 @@

   data: ->
     speakers = User.allSpeakers()
-    user = User.current()
-    speakers = if user and (user.admin() or user.moderator()) then sort(speakers) else _.shuffle(speakers)
+    if speakers and speakers.length > 0
+      user = User.current()
+      speakers = if user and (user.admin() or user.moderator()) then sort(speakers) else _.shuffle(speakers)
     return {
       page: 'vote'
       speakers: speakers


:arrows_counterclockwise:

--- atom/config.cson
+++ atom/config.cson
@@ -19,6 +19,8 @@
       "gometalinter-linter"
       "gorename"
       "tester-go"
+      "linter-stylelint"
+      "language-javascript-jsx"
     ]
     ignoredNames: [
       ".git"
@@ -30,6 +32,12 @@
       "coverage"
     ]
     telemetryConsent: "no"
+  docblockr:
+    align_tags: "no"
+    extend_double_slash: false
+    param_description: false
+    return_description: false
+    simple_mode: true
   editor:
     fontFamily: "Hasklig-Light"
     fontSize: 16


Fix atom config.

Fix atom config.

--- atom/config.cson
+++ atom/config.cson
@@ -15,6 +15,7 @@
     fontFamily: "Andale Mono"
     fontSize: 13
     invisibles: {}
+    softWrap: true
   "exception-reporting":
     userId: "ca4ba82f-55d9-6783-63e8-7a2a1588920c"
   minimap:


Remove Atom Beautifier Elm config

Remove Atom Beautifier Elm config

In favor of atom-elm-format

--- atom/config.cson
+++ atom/config.cson
@@ -1,9 +1,6 @@
 "*":
   "atom-beautify":
-    elm:
-      beautify_on_save: true
-    general:
-      _analyticsUserId: "8c763e77-aa28-46fb-8b0e-cb1b727588bf"
+    general: {}
   "atom-ctags": {}
   "autocomplete-plus":
     enableAutoActivation: false


better handling of data to retrieve and send

--- netatmo_librato.coffee
+++ netatmo_librato.coffee
@@ -53,7 +53,7 @@
     device_name[device._id]=norm(device.station_name)
     device_end_time[device._id]=device.last_status_store
     end_time = device.last_status_store
-    time_to_retrieve = 3*ten_min_sec/2
+    time_to_retrieve = 2*ten_min_sec
     if device.type == 'NAMain'
       console.log "Weather Station detected"
       device_thermostat[device._id] = false
@@ -90,7 +90,7 @@
       if device_thermostat[module.main_device]
         console.log "Thermostat module detected"
         module.data_type = ['Temperature', 'Sp_Temperature', 'BoilerOn', 'BoilerOff']
-        time_to_retrieve = 2*one_hour_sec
+        time_to_retrieve = 3*one_hour_sec/2
       else
         console.log "Weather module Station detected"
       if module.data_type != []


Atom snippet for bootstrap text input

Atom snippet for bootstrap text input

Signed-off-by: Caddy Dz <cbc6199cd1cb93e9d3589fb9aa7ecaece7b37833@gmail.com>

--- src/atom/snippets.cson
+++ src/atom/snippets.cson
@@ -2,3 +2,8 @@
   'comment':
     'prefix' : 'comment'
     'body': '/**\n * $1\n * @param $2\n * @var $3\n * @return $4\n */$5'
+'.blade.php':
+  'bstext':
+    'prefix' : 'bstext'
+    'body': '
\n\t$2:\n\t<input type="text" class="form-control" name="$1" id="$1">\n
\n$3'
+


use 204

use 204

--- test/flow-deploy-controller-spec.coffee
+++ test/flow-deploy-controller-spec.coffee
@@ -108,5 +108,5 @@

         @sut.stop request, @response

-      it 'should set status 201', ->
-        expect(@response.status).to.have.been.calledWith 201
+      it 'should set status 204', ->
+        expect(@response.status).to.have.been.calledWith 204


eliminated temporary variable

eliminated temporary variable

--- core/app/backbone/modules/sidebar.coffee
+++ core/app/backbone/modules/sidebar.coffee
@@ -8,10 +8,9 @@

   Sidebar.showForTopicsAndActivateCorrectItem = (topic, user)->
     @setUsernameOnWindowChannels(user)
-    favouriteTopics = currentUser.favourite_topics
-    favouriteTopics.fetch()
+    currentUser.favourite_topics.fetch()
     @sidebarView = new TopicSidebarView
-      collection: favouriteTopics
+      collection: currentUser.favourite_topics
       model: user
     FactlinkApp.leftMiddleRegion.show @sidebarView


Fix for node5 (path.normalize change)

Fix for node5 (path.normalize change)

--- backend/prep.coffee
+++ backend/prep.coffee
@@ -50,7 +50,7 @@
         parts = doc.path.split path.sep
         return doc.path is '.' or
             doc.path is '' or
-            parts[0] is '..'
+            parts.indexOf('..') >= 0

     # Return true if the checksum is invalid
     # If the checksum is missing, it is not invalid, just missing,


Bailing out on file conversion errors.

Bailing out on file conversion errors.

--- file-converter.coffee
+++ file-converter.coffee
@@ -128,6 +128,7 @@
                                                         @log.warn "Failed to unlink file #{tempname}: #{err}"
                                 callback {data: ["Failed to convert.", 500], headers: {}}
                                 return
+                        return
                 fs.stat tempname, (statErr, stats) =>
                         if statErr
                                 callback {data: ["Failed to read resulting file name.", 500], headers: {}}


add view ptr to callbacks

add view ptr to callbacks

--- dist/backbone-mixin.coffee
+++ dist/backbone-mixin.coffee
@@ -121,11 +121,11 @@

       show:(_view, options = {},callback)->
         unless _view?
-          callback?()
+          callback? _view
           return
         view = @getViewDI _view, options
         if view is @_$_p.currentView
-          callback?()
+          callback? view
           return view
         __show = =>
             @_setCurrentView null
@@ -156,7 +156,7 @@
           this.trigger "render"
           @render()

-        finish = _.after 3, => callback?()              #--finish 3 times
+        finish = _.after 3, => callback? this              #--finish 3 times

         if(regions = _.result(this,"regions"))
           keys = _.chain(regions)
@@ -189,7 +189,7 @@
       #
         this.trigger "onBeforeClose"
         @onBeforeClose?()
-        finish = _.after 3, =>  callback?()             #--finish 3 times
+        finish = _.after 3, =>  callback? this         #--finish 3 times

         if(regions = _.result(this,"regions"))
           keys = _.chain(regions)
@@ -217,16 +217,16 @@
       #
       close:(_view, callback)->
         unless _view?
-          callback?()
+          callback? _view
           return
-        finish = _.after 2, => callback?()              #--finish 3 times
+        finish = _.after 2, => callback? _view              #--finish 3 times
         if @_$_p.currentView? and @_$_p.currentView isnt _view
           @close @_$_p.currentView, finish
         else
           finish()

         @_setCurrentView null
-        _view.closeCurrent finish
+        _view.closeCurrent finish, this
         _view

       # Alias showViewAnimation(this)
@@ -240,24 +240,24 @@
       # Helper method which can descride animation/behavior for `view` while base view `show` `view`. By default using `view.$el.show()`
       showViewAnimation:(view, callback)->
         unless view?
-          callback?()
+          callback? view
           return
         if view.showAnimation? and view isnt this
           view.showAnimation callback
         else
           view.$el.show()
-          callback?()
+          callback? view

       # Helper method which can descride animation/behavior for `view` while base view `close` `view`. By default using `view.$el.show()`
       closeViewAnimation:(view, callback)->
         unless view?
-          callback?()
+          callback? view
           return
         if view.closeAnimation? and view isnt this
           view.closeAnimation callback
         else
           view.$el.hide()
-          callback?()
+          callback? view

       # Depedencies Injection functionality
       # `options` - options for `new View(options)`  operations


fix placement of `\par` (must go inside of group)


Evoke init

Evoke init

--- desktop/assets/editorial_features.coffee
+++ desktop/assets/editorial_features.coffee
@@ -3,6 +3,6 @@

 $ ->
   if location.pathname is '/2016-year-in-art'
-    require('../apps/editorial_features/components/eoy/client.coffee').init
+    require('../apps/editorial_features/components/eoy/client.coffee').init()
   else if location.pathname.indexOf('/venice-biennale') > -1
     new VeniceView el: $('.venice-feature')


Continued refactoring set.coffee to account for values of pythonic objects

--- src/builtin/set.coffee
+++ src/builtin/set.coffee
@@ -3,7 +3,7 @@
   constructor: (iterable) ->
     @value = new Dict() # set just is a wrapped version of our own Dict class
     if iterable?
-      for item in iterable # Handles empty constructor call too
+      for item in iterable.value # Temporary assumption: iterable is List of pythonic objects
         @value.__setitem__(item, new Bool(true))

   __and__: (otherSet) ->
@@ -17,12 +17,12 @@
   __contains__: (item) ->
     return @value.__contains__(item)

-  # Checks to see if this is equivalent to set
+  # Checks to see if this is equivalent to otherSet
   __eq__: (otherSet) ->
     xorSet = @__xor__(otherSet)
     return len(xorSet).__eq__(new Int(0))

-  # Checks to see if this is a superset of set
+  # Checks to see if this is a superset of otherSet
   __ge__: (otherSet) ->
     for item in otherSet.value.keys().value
       if not @__contains__(item).value
@@ -32,7 +32,7 @@
   # **Unimplemented**
   __getattribute__: ->

-  # Checks to see if this is a proper superset of set
+  # Checks to see if this is a proper superset of otherSet
   __gt__: (otherSet) ->
     if @__eq__(otherSet).value
       return new Bool(false)
@@ -44,7 +44,7 @@
   __iter__: ->
     return new SetIterator(@)

-  # Checks to see if this is a subset of set
+  # Checks to see if this is a subset of otherSet
   __le__: (otherSet) ->
     for item in @value.keys().value
       if not otherSet.__contains__(item).value
@@ -55,26 +55,26 @@
   __len__: ->
     return @value.__len__()

-  # Checks to see if this is a proper subset of set, meaning this is a subset and not equal to set
+  # Checks to see if this is a proper subset of otherSet, meaning this is a subset and not equal to otherSet
   __lt__: (otherSet) ->
     if @__eq__(otherSet).value
       return new Bool(false)
     return @__le__(otherSet)

-  # Checks to see if this is not equivalent to set
-  __ne__: (set) ->
-    return new Bool(not @__eq__(set).value)
-
-  # Returns a new Set containing items from this or set
-  __or__: (set) ->
-    union = []
-    union.push(item) for item in @value.keys()
-    union.push(item) for item in set.value.keys()
+  # Checks to see if this is not equivalent to otherSet
+  __ne__: (otherSet) ->
+    return new Bool(not @__eq__(otherSet).value)
+
+  # Returns a new Set containing items from this or otherSet
+  __or__: (otherSet) ->
+    union = new List()
+    union.append(item) for item in @value.keys().value
+    union.append(item) for item in otherSet.value.keys().value
     return new Set(union)

   # Same as __and__ since intersection is symmetric
-  __rand__: (set) ->
-    return @__and__(set)
+  __rand__: (otherSet) ->
+    return @__and__(otherSet)

   # **Unimplemented**
   __reduce__: ->
@@ -83,32 +83,32 @@
   __repr__: ->

   # Same as __or__ since union is symmetric
-  __ror__: (set) ->
-    return @__or__(set)
-
-  # Subtract this from set
-  __rsub__: (set) ->
-    return set.__sub__(@)
+  __ror__: (otherSet) ->
+    return @__or__(otherSet)
+
+  # Subtract this from otherSet
+  __rsub__: (otherSet) ->
+    return otherSet.__sub__(@)

   # Same as __xor__ since xor is symmetric
-  __rxor__: (set) ->
-    return @__xor__(set)
+  __rxor__: (otherSet) ->
+    return @__xor__(otherSet)

   # **Unimplemented**
   __sizeof__: ->

-  # Subtract new set containing this - set
-  __sub__: (set) ->
+  # Returns new set containing this - otherSet
+  __sub__: (otherSet) ->
     difference = @copy()
-    for item in set.value.keys()
+    for item in otherSet.value.keys().value
       if @__contains__(item).value
         difference.value.pop(item)
     return difference

-  # Returns new Set containing items in this or set, but not both
-  __xor__: (set) ->
-    diff1 = @__sub__(set)
-    diff2 = set.__sub__(@)
+  # Returns new Set containing items in this or otherSet, but not both
+  __xor__: (otherSet) ->
+    diff1 = @__sub__(otherSet)
+    diff2 = otherSet.__sub__(@)
     xor = diff1.__or__(diff2)
     return xor

@@ -123,7 +123,7 @@

   # http://docs.python.org/library/stdtypes.html#set.copy
   copy: ->
-    keys = @keys()
+    keys = @value.keys()
     return new Set(keys)

   # http://docs.python.org/library/stdtypes.html#set.difference
@@ -159,16 +159,17 @@
     return

   # http://docs.python.org/library/stdtypes.html#set.isdisjoint
-  isdisjoint: (set) ->
-    return @__and__(set).__len__() == 0
+  isdisjoint: (otherSet) ->
+    intersect = @__and__(otherSet)
+    return len(intersect).__eq__(new Int(0))

   # http://docs.python.org/library/stdtypes.html#set.issubset
-  issubset: (set) ->
-    return @__le__(set)
+  issubset: (otherSet) ->
+    return @__le__(otherSet)

   # http://docs.python.org/library/stdtypes.html#set.issuperset
-  issuperset: (set) ->
-    return @__ge__(set)
+  issuperset: (otherSet) ->
+    return @__ge__(otherSet)

   # http://docs.python.org/library/stdtypes.html#set.pop
   pop: ->
@@ -181,19 +182,19 @@

   # http://docs.python.org/library/stdtypes.html#set.remove
   remove: (elem) ->
-    if elem not in @value.value
+    if @value.__contains__(elem).value
+      @value.pop(elem)
+    else
       raise new KeyError("#{elem}")
-    else
-      @value.pop(elem)
     return

   # http://docs.python.org/library/stdtypes.html#set.symmetric_difference
-  symmetric_difference: (other) ->
-    return @__xor__(other)
+  symmetric_difference: (otherSet) ->
+    return @__xor__(otherSet)

   # http://docs.python.org/library/stdtypes.html#set.symmetric_difference_update
-  symmetric_difference_update: (other) ->
-    @__ixor__(other)
+  symmetric_difference_update: (otherSet) ->
+    @__ixor__(otherSet)
     return

   # http://docs.python.org/library/stdtypes.html#set.union


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -43,7 +43,7 @@
   @param {Color} [color="black"] The color to fade from
   ###
   fadeIn: (options={}) ->
-    {alpha, color, duration} = Object.reverseMerge(options, fadeInDefault)
+    {alpha, color, duration} = Object.reverseMerge(options, fadeInDefaults)

     configureFade(duration, color, 0)


really validate in validations

really validate in validations

--- src/util/index.coffee
+++ src/util/index.coffee
@@ -9,22 +9,22 @@
   is_obj_literal: (thing) ->
     # This might be wrong in some cases -
     # the implementation is guided by http://underscorejs.org/#isObject
-    !_.isObject(thing) || Array.isArray(thing) || _.isFunction(thing)
+    _.isObject(thing) && !Array.isArray(thing) && !_.isFunction(thing)

   _check_hooks: (mixin_keys, hooks) ->
-    if hooks?
+    if hooks != undefined
       unless @is_obj_literal(hooks)
         throw new MixinUtils.ArgumentError "Expected object literal for hooks option"
       diff = _.difference(Object.keys(hooks), mixin_keys)
       if diff.length
         throw new MixinUtils.ArgumentError "Some hooks keys aren't in mixin object: #{diff}"
       for own _, value of hooks
-        unless @is_obj_literal(value) && _.contains(Mixin.mixedmethodhook_keys, Object.keys(value))
+        unless @is_obj_literal(value) && _.contains(Mixin.mixinmethod_hooks, Object.keys(value))
           throw new MixinUtils.ArgumentError "Some hooks keys aren't in mixin object: #{diff}"

   _check_omits: (mixin_keys, omits) ->
-    if omits?
-      if !Array.isArray(omits) || !omits
+    if omits != undefined
+      unless Array.isArray(omits) && omits.length
         throw new MixinUtils.ArgumentError "Expected omits option to be a nonempty Array"
       diff = _.difference(omits, mixin_keys)
       if diff.length


this was re-factored out

this was re-factored out

--- src/util/index.coffee
+++ src/util/index.coffee
@@ -5,12 +5,5 @@
       return Array::slice.call arguments, 1
     return []

-  ArgumentError: class ArgumentError extends Error
-
-  postmixin_hooks: [
-    'post_classmixin'
-    'post_protomixin'
-  ]
-

 module.exports = UTIL


Ok we need to keep throwing the error. But you're weird. Safari. Really

--- src/client/auth.coffee
+++ src/client/auth.coffee
@@ -270,6 +270,6 @@
   emitLoginFailure : (err)->
     EventBus.emit("hull.user.fail", err)
     err
-    # throw err
+    throw err

 module.exports = Auth


client-side ability for poll specified voters only

--- vue/src/shared/models/poll_model.coffee
+++ vue/src/shared/models/poll_model.coffee
@@ -60,10 +60,10 @@

   adminsInclude: (user) ->
     stance = @stanceFor(user)
-    @authorIs(user) || (stance && stance.admin) || (@group() && @group().adminsInclude(user))
+    (stance && stance.admin) || (@discussionId && @discussion().adminsInclude(user)) || @group().adminsInclude(user)

   membersInclude: (user) ->
-    @stanceFor(user) || (@group && @group().membersInclude(user))
+    @stanceFor(user) || (@discussionId && @discussion().membersInclude(user)) || @group().membersInclude(user)

   stanceFor: (user) ->
     head orderBy(@recordStore.stances.find(participantId: user.id, latest: true, pollId: @id), 'createdAt', 'desc')


* [bug] typo

* [bug] typo

--- src/codec/index.coffee
+++ src/codec/index.coffee
@@ -114,13 +114,13 @@
       if (SUBKEY_SEPS[1].indexOf(c) >=0) then return i
       --i
     return -1
-  @encode = (aPath, aKey, aSeperator, dontEscapeSeperator)->
-    keyIsStr = isString(aKey) and aKey.length isnt 0
+  @encode =encode = (aPath, aKey, aSeperator, dontEscapeSeperator)->
+    keyIsStr = isString(aKey) and aKey.length > 0
     hasSep   = !!aSeperator
     aSeperator = SUBKEY_SEP unless aSeperator
     if keyIsStr
-      if hasSep && key[0] == aSeperator then key = key.substring(1)
-      key = escapeString(key)
+      if hasSep && aKey[0] == aSeperator then aKey = aKey.substring(1)
+      aKey = escapeString(aKey)
     if dontEscapeSeperator is true
       aSeperator = PATH_SEP + aSeperator if hasSep and aSeperator isnt PATH_SEP
       hasSep = false
@@ -133,10 +133,10 @@
         aSeperator = PATH_SEP + aSeperator
     else if keyIsStr
       #try to find the separator on the key
-      i = SUBKEY_SEPS[0].indexOf(key[0], 1)
+      i = SUBKEY_SEPS[0].indexOf(aKey[0], 1)
       if i > 0
           vSeperator = PATH_SEP + SUBKEY_SEPS[1][i]
-          key = key.substring(1)
+          aKey = aKey.substring(1)
     #console.log("codec.encode:",path.join(e[0]) + vSeperator + key)
     #TODO: I should encode with path.join(e[0], vSeperator + key)) simply in V8.
     #      all separators are same now.
@@ -146,7 +146,7 @@
       aPath = ""
     else
       aPath = PATH_SEP
-    aPath + aSeperator + key
+    aPath + aSeperator + aKey

   #return [path, key, separator, realSeparator]
   #the realSeparator is optional, only (aSeparator && aSeparator !== seperator
@@ -181,7 +181,7 @@
   @decodeKey: decodeKey = (key, keyEncoding, options)->
     #v=[parent, key, separator, realSeparator]
     #realSeparator is optional only opts.separator && opts.separator != realSeparator
-    v = decode(key, options && options.separator)
+    v = _decode(key, options && options.separator)
     vSep = v[2] #separator
     vSep = PATH_SEP unless vSep?  #if the precodec is other codec.
     key = if keyEncoding then keyEncoding.decode(v[1], options) else v[1]


schema: fix warning in test

schema: fix warning in test

--- packages/core/test/options/schema.coffee
+++ packages/core/test/options/schema.coffee
@@ -12,7 +12,6 @@
       a_string: 'a value'
       an_integer: 1
       schema:
-        'id': '/SimplePerson'
         'type': 'object'
         'properties':
           'a_string': 'type': 'string'


add zookeeper resilience url

add zookeeper resilience url

--- hdp/zookeeper.coffee
+++ hdp/zookeeper.coffee
@@ -149,6 +149,11 @@

 ###
 todo: [Securing access to ZooKeeper](http://hadoop.apache.org/docs/r2.2.0/hadoop-yarn/hadoop-yarn-site/HDFSHighAvailabilityWithNFS.html)
+
+Resources:
+
+*   [ZooKeeper Resilience](http://blog.cloudera.com/blog/2014/03/zookeeper-resilience-at-pinterest/)
+
 ###


elektron: save last-route while quitting the app

--- elektron/src/start.coffee
+++ elektron/src/start.coffee
@@ -44,6 +44,12 @@
   mainWindow.webContents.on 'new-window', (e, url) ->
     e.preventDefault()
     shell.openExternal url
+
+  app.on 'will-quit', (e) ->
+    settings = storage.get()
+    settings['last-route'] = mainWindow.webContents.getURL()
+    storage.write settings
+
   # Emitted when the window is closed.
   mainWindow.on 'closed', ->
     # Dereference the window object, usually you would store windows


Remove the needless br-tags which are created on paste operations

--- src/mentions-kinder.coffee
+++ src/mentions-kinder.coffee
@@ -349,6 +349,8 @@
       # clean all children and replace node with them
       if node.childNodes?.length > 0
         @_cleanChildNodes(node)
+        if node.childNodes[node.childNodes.length - 1].nodeName.toUpperCase() == 'BR'
+          $(node.childNodes.item(node.childNodes.length - 1)).remove()
       # remove node
       else
         $(node).remove()


reactivity: chatpane: minor fixes for props

--- client/activity/lib/components/chatpane/container.coffee
+++ client/activity/lib/components/chatpane/container.coffee
@@ -12,16 +12,16 @@

   @propsTypes =
     thread        : React.PropTypes.instanceOf immutable.Map()
-    onLoadMore    : React.PropTypes.func
     onInviteClick : React.PropTypes.func
     showItemMenu  : React.PropTypes.bool
+    onLoadMore    : React.PropTypes.func

   @defaultProps =
     thread        : immutable.Map()
+    onInviteClick : kd.noop
+    showItemMenu  : yes
     onLoadMore    : kd.noop
-    onInviteClick : kd.noop
-    showItemMenu  : no

   flag: (key) -> @props.thread?.getIn ['flags', key]


atom settings update

atom settings update

--- files/atom/config.cson
+++ files/atom/config.cson
@@ -59,11 +59,9 @@
     autoIndentOnPaste: false
     fontFamily: "Source Code Pro"
     invisibles: {}
-    preferredLineLength: 90
     scrollPastEnd: true
     showIndentGuide: true
     softWrap: true
-    softWrapAtPreferredLineLength: true
   "exception-reporting":
     userId: "0dacece5-6c28-aa5c-7949-423cff26188c"
   "linter-ui-default":
@@ -108,6 +106,21 @@
   "nord-atom-ui": {}
   "one-dark-ui": {}
   organized: {}
+  parinfer:
+    "file-extensions": [
+      ".boot"
+      ".cl"
+      ".clj"
+      ".cljc"
+      ".cljs"
+      ".edn"
+      ".el"
+      ".lfe"
+      ".lisp"
+      ".lsp"
+      ".rkt"
+      ".scm"
+    ]
   "proto-repl":
     autoPrettyPrint: true
     bootPath: "/usr/local/bin/boot"


remove outPath

remove outPath

--- docpad.coffee
+++ docpad.coffee
@@ -1,8 +1,6 @@
 # The DocPad Configuration File
 # It is simply a CoffeeScript Object which is parsed by CSON
 docpadConfig = {
-
-	outPath: ''

 	srcPath: 'src'  # default

@@ -122,7 +120,7 @@

 			# Make sure to register a grunt `default` task
 			command = ["#{rootPath}/node_modules/.bin/grunt", 'default']
-
+
 			# Execute
 			balUtil.spawn command, {cwd:rootPath,output:true}, ->
 				src = []
@@ -139,4 +137,4 @@
 }

 # Export our DocPad Configuration
-module.exports = docpadConfig+module.exports = docpadConfig


fixes

fixes

--- client/front.coffee
+++ client/front.coffee
@@ -348,6 +348,7 @@
         editor.open(filename)

     open_push: (res) ->
+        editor.fresh = false
         editor.filename = res.filename
         editor.tokenizer.guess_spec(res.filename)
         m = res.filename.match("\/([^\/]*)$")
@@ -456,6 +457,9 @@
 class UndoStack

     constructor: ->
+        @clear()
+
+    clear: =>
         @undos = []
         @redos = []

@@ -519,7 +523,7 @@

     loggedin: ->
         @$login_box.hide()
-        if window.location.pathname[0...5] == "/edit"
+        if editor.fresh and window.location.pathname[0...5] == "/edit"
             editor.open(window.location.pathname[6..])
         esc()

@@ -557,6 +561,7 @@
 class Editor

     constructor: ->
+        @fresh = true
         window.editor = @
         @con = new Connection()
         @filename = "foo"
@@ -952,3 +957,4 @@

 $ ->
     window.editor = new Editor()
+


adding a default calculation value for calculation questions

--- dkobo/koboform/static/js/xlform/XLF.model.configs.coffee
+++ dkobo/koboform/static/js/xlform/XLF.model.configs.coffee
@@ -101,6 +101,9 @@
   date:
     label:
       value: "Enter a date"
+  calculate:
+    calculation:
+      value: ""
   datetime:
     label:
       value: "Enter a date and time"


添加下划线开头的特殊属性处理规则

添加下划线开头的特殊属性处理规则

--- src/core/entity.coffee
+++ src/core/entity.coffee
@@ -192,7 +192,7 @@
 			else
 				for prop, propFilter of criteria
 					data = null
-					if prop == "$"
+					if prop is "$"
 						matches = false
 						if option.mode is "entity"
 							data = entity._data
@@ -1118,7 +1118,8 @@
 		data = @_data
 		json = {}
 		for prop, value of data
-			if prop.charCodeAt(0) is 36 # `$`
+			c = prop.charCodeAt(0)
+			if c is 36 or c is 95 # `$` or `_`
 				continue

 			if value


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -12,7 +12,9 @@
 Core = (I) ->
   I ||= {}

-  self = {
+  self =
+    I: I
+
     ###
     Generates a public jQuery style getter / setter method for each
     String argument.
@@ -66,5 +68,8 @@
           self[name] = self[name].withAfter(fn)

       return self
-  }

+    # Includes a module
+    include: (Module) ->
+      self.extend Module(I, self)
+