Add some translations (#3632)

Add some translations (#3632)

--- app/locale/uk.coffee
+++ app/locale/uk.coffee
@@ -32,12 +32,12 @@
     real_code: "Кодування"
     from_the_first_level: "з першого рівня"
     getting_students: "Написання коду самостійно сприяє вивченню синтаксису та структури програми."
-#    educator_resources: "Educator resources"
-#    course_guides: "and course guides"
-#    teaching_computer_science: "Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds."
-#    accessible_to: "Accessible to"
-#    everyone: "everyone"
-#    democratizing: "Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code."
+    educator_resources: "Путівник по курсах" # Educator resources
+    course_guides: "і додаткові матеріали" # and course guides
+    teaching_computer_science: "Щоб викладати комп'ютерні науки не обов'язково мати науковий ступінь, адже ми підтримуємо вчителів з будь-яким досвідом." # Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds.
+    accessible_to: "Доступно" # Accessible to
+    everyone: "кожному" # everyone
+    democratizing: "Навчання, доступне кожному, — наша головна мета. Кожен повинен мати можливість навчитись програмувати." # Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code.
 #    forgot_learning: "I think they actually forgot that they were actually learning something."
 #    wanted_to_do: " Coding is something I've always wanted to do, and I never thought I would be able to learn it in school."
 #    why_games: "Why is learning through games important?"


Extends Spine.List. Adds currentTarget to the change event.

error: pathspec 'list.coffee' did not match any file(s) known to git

--- list.coffee
+++ list.coffee
@@ -0,0 +1,11 @@
+SpineList ?= require('spine/lib/list')
+$ ?= Spine.$
+
+class List extends SpineList
+
+  click: (e) ->
+    item = $(e.currentTarget).item()
+    @trigger('change', item, $(e.currentTarget))
+    false
+
+module.exports = List


Update pt-PT.coffee

Update pt-PT.coffee

--- app/locale/pt-PT.coffee
+++ app/locale/pt-PT.coffee
@@ -322,7 +322,7 @@
     tip_lines_of_code: "Medir o progresso em programação pelo número de linhas de código é como medir o progresso da construção de um avião pelo peso. — Bill Gates"
     tip_source_code: "Quero mudar o mundo, mas não há maneira de me darem o código-fonte."
     tip_javascript_java: "Java é para JavaScript o mesmo que Carro (Car) para Tapete (Carpet). - Chris Heilmann"
-#    tip_move_forward: "Whatever you do, keep moving forward. - Martin Luther King Jr."
+    tip_move_forward: "Faças o que fizeres, segue em frente. - Martin Luther King Jr."

   game_menu:
     inventory_tab: "Inventário"
@@ -341,18 +341,18 @@
     multiplayer_caption: "Joga com amigos!"
     auth_caption: "Guarda o teu progresso."

-#  leaderboard:
-#    leaderboard: "Leaderboard"
-#    view_other_solutions: "View Other Solutions"
-#    top_solutions: "Top Solutions"
-#    day: "Today"
-#    week: "This Week"
-#    all: "All-Time"
-#    time: "Time"
-#    damage_taken: "Damage Taken"
-#    damage_dealt: "Damage Dealt"
-#    difficulty: "Difficulty"
-#    gold_collected: "Gold Collected"
+  leaderboard:
+    leaderboard: "Tabela de Classificação"
+    view_other_solutions: "Ver Outras Soluções"
+    top_solutions: "Melhores Soluções"
+    day: "Hoje"
+    week: "Esta Semana"
+    all: "Sempre"
+    time: "Tempo"
+    damage_taken: "Dano Recebido"
+    damage_dealt: "Dano Infligido"
+    difficulty: "Dificuldade"
+    gold_collected: "Ouro Recolhido"

   inventory:
     choose_inventory: "Equipar Itens"
@@ -401,7 +401,7 @@
     subscribe_button: "Subscrever Agora"
     stripe_description: "Subscrição Mensal"
     subscription_required_to_play: "Precisas de uma subscrição para jogares este nível."
-#    unlock_help_videos: "Subscribe to unlock all video tutorials."
+    unlock_help_videos: "Subscreve-te para desbloqueares todos os tutoriais em vídeo."

   choose_hero:
     choose_hero: "Escolhe o Teu Herói"


Added ping url which sends a ping to slack but could ping other services

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/rwky/rwky.net.git/'


made lambdas => expr rather than => { return expr; } on boundfuncs where the body was return expr;

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -1321,6 +1321,8 @@
       else if not @bound
         [@makeCode('function'), argscode, bodycode]
       else if @bound and not @name?
+        if @body.expressions.length == 1 and @body.expressions[0] instanceof Return
+          bodycode = @body.expressions[0].expression.compileNode o
         [argscode, @makeCode(' => '), bodycode]
       else if @bound and @name?
         @nogen "bound non-method function has a name (internal compiler error)"


更新 get_uin 方法说明

更新 get_uin 方法说明

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/hohogpb/qqbot.git/'


Compromise for passing a config file to flake8

Issue #66 is something that I ran into, too, and when I looked at
the code configFileName wasn't even implemented.

I'm also not a flake8 expert, but it looks like flake8 has some
default locations that it looks in for config files, but what
I really want is the ability to add a project specific flake8
config file.

I removed the unused config file config parameter and added
a projectConfigFile setting that won't conflict with any previous
config settings that might exist (they'll remain no-ops).

There isn't a load of error checking in the code so I didn't try
too hard to bulletproof this, and it works perfectly for my needs.

If anyone else wants it, feel free to accept, modify, whatever.

--- lib/main.coffee
+++ lib/main.coffee
@@ -3,20 +3,11 @@
     executablePath:
       type: 'string'
       default: 'flake8'
-      description: 'You might need a different binary name for python2 ' +
-        '(e.g. flake8-python2)'
-    configFileNames:
-      type: 'array'
-      default: []
-      items:
-        type: 'string'
-      description: 'Use configuration for flake8 in this file (search is ' +
-        'from CWD up until the file is found or the root is ' +
-        'reached). If this is empty, or the file is not found, ' +
-        'the configuration options from this settings panel will ' +
-        'be used. Can be a comma-separated list, in which case ' +
-        'filenames are searched left to right and the first one ' +
-        'found is used.'
+      description: 'Full path to binary (e.g. /usr/local/bin/flake8)'
+    projectConfigFile:
+      type: 'string'
+      default: ''
+      description: 'flake config file relative path from project (e.g. tox.ini or .flake8rc)'
     maxLineLength:
       type: 'integer'
       default: 0
@@ -40,6 +31,7 @@

   provideLinter: ->
     helpers = require('atom-linter')
+    path = require('path')

     provider =
       grammarScopes: ['source.python', 'source.python.django']
@@ -60,6 +52,8 @@
           parameters.push('--hang-closing')
         if (selectErrors = atom.config.get('linter-flake8.selectErrors')).length
           parameters.push('--select', selectErrors.join(','))
+        if (projectConfigFile = atom.config.get('linter-flake8.projectConfigFile'))
+          parameters.push('--config', path.join(atom.project.getPaths()[0], projectConfigFile))
         parameters.push('-')

         return helpers.exec(atom.config.get('linter-flake8.executablePath'), parameters, stdin: fileText).then (result) ->


Code style

Code style

--- src/watch.coffee
+++ src/watch.coffee
@@ -4,6 +4,7 @@
 chokidar = require 'chokidar'
 debug = require('debug')('brunch:watch')
 sysPath = require 'path'
+{spawn} = require 'child_process'
 logger = require 'loggy'
 pushserve = require 'pushserve'
 # worker must be loaded before fs_utils
@@ -80,13 +81,13 @@
     else
       server.startServer port, publicPath, serverCb
   else if config.server.command
-    spawn = require('child_process').spawn
-    commandComponents = config.server.command.split " "
+    commandComponents = config.server.command.split ' '
     debug "Invoking custom server command with: #{config.server.command}"
-    throw new Error 'Server command needs to have at least one word' if(commandComponents.length == 0)
-    child = spawn(commandComponents.shift(), commandComponents, {stdio: 'inherit'});
-    # fn to kill the server
-    child.close= (cb)=>
+    unless commandComponents.length
+      throw new Error 'Custom server command invalid'
+    child = spawn commandComponents.shift(), commandComponents, stdio: 'inherit'
+    # fn to kill the custom server
+    child.close = (cb) =>
       child.kill()
       cb?()


Add compress task

Add compress task

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/frostney/shopkeeper.git/'


Oh you

Oh you

error: pathspec 'scripts/oh-you.coffee' did not match any file(s) known to git

--- scripts/oh-you.coffee
+++ scripts/oh-you.coffee
@@ -0,0 +1,3 @@
+module.exports = (robot) ->
+  robot.hear /oh you/i, (msg) ->
+    msg.send "http://i.imgur.com/sDCSJ.jpg"


Change a straight alert to a showError call and other cosmetic changes.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-dashboard.git/'


add comment

add comment

--- spec/BaconSpec.coffee
+++ spec/BaconSpec.coffee
@@ -17,7 +17,9 @@
 toValues = th.toValues
 sc = TickScheduler()
 Bacon.scheduler = sc
-# some streams are unstable when testing with verifySwitching2.
+# Some streams are unstable when testing with verifySwitching2.
+# Generally, all flatMap-based streams are unstable because flatMap discards
+# child streams on unsubscribe.
 unstable = {unstable:true}


Just one test for?

Just one test for?

error: pathspec 'spec/main-spec.coffee' did not match any file(s) known to git

--- spec/main-spec.coffee
+++ spec/main-spec.coffee
@@ -0,0 +1,7 @@
+_ = require('./fixtures')
+
+deref = require('../lib')
+
+describe 'resolving $ref values', ->
+  it 'should resolve internal only', ->
+    expect(_.personWithAddress.example).toHaveSchema deref(_.personWithAddress.schema, _.schemas)


Add integration test for states (create, update, delete)

error: pathspec 'src/spec/integration/states.spec.coffee' did not match any file(s) known to git

--- src/spec/integration/states.spec.coffee
+++ src/spec/integration/states.spec.coffee
@@ -0,0 +1,90 @@
+_ = require 'underscore'
+Q = require 'q'
+SphereClient = require '../../lib/client'
+Config = require('../../config').config
+
+uniqueId = (prefix) ->
+  _.uniqueId "#{prefix}#{new Date().getTime()}_"
+
+newState = ->
+  key: uniqueId 's'
+  type: 'LineItemState'
+
+updateState = (version) ->
+  version: version
+  actions: [
+    {action: 'setName', name: {en: 'A State'}}
+    {action: 'setDescription', description: {en: 'This is a State'}}
+  ]
+
+# Increase timeout
+jasmine.getEnv().defaultTimeoutInterval = 10000
+
+describe 'Integration Channels', ->
+
+  beforeEach (done) ->
+    @client = new SphereClient
+      config: Config
+      logConfig:
+        levelStream: 'info'
+        levelFile: 'error'
+    @logger = @client._logger
+
+    @client.states.save(newState())
+    .then (result) =>
+      expect(result.statusCode).toBe 201
+      @state = result.body
+      @logger.info @state, 'New state created'
+      done()
+    .fail (error) =>
+      @logger.error error
+      done(error)
+
+  afterEach (done) ->
+    @client.states.byId(@state.id).delete(@state.version)
+    .then (result) =>
+      @logger.info "State deleted: #{@state.id}"
+      expect(result.statusCode).toBe 200
+      done()
+    .fail (error) =>
+      @logger.error error
+      done(error)
+
+  it 'should update a state', (done) ->
+    @client.states.byId(@state.id).update(updateState(@state.version))
+    .then (result) =>
+      expect(result.statusCode).toBe 200
+      @state = result.body
+      expect(@state.name).toEqual {en: 'A State'}
+      expect(@state.description).toEqual {en: 'This is a State'}
+      done()
+    .fail (error) =>
+      @logger.error error
+      done(error)
+
+  it 'should create some states and use them as transitions references', (done) ->
+    Q.all _.map [1..101], => @client.states.save(newState())
+    .then (results) =>
+      mainState = _.head results
+      otherStates = _.tail results
+      transitions = _.map otherStates, (r) ->
+        id: r.body.id
+        typeId: 'state'
+      @client.states.byId(mainState.body.id).update
+        version: mainState.body.version
+        actions: [
+          {action: 'setTransitions', transitions: transitions}
+        ]
+      .then (result) =>
+        expect(result.statusCode).toBe 200
+        mainState = result.body
+        expect(mainState.transitions.length).toBe 100
+
+        # delete states
+        Q.all _.map results, (r) => @client.states.byId(r.body.id).delete(r.body.version)
+      .then (results) ->
+        done()
+    .fail (error) =>
+      @logger.error error
+      done(error)
+


direct wemo communication

direct wemo communication

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/blandinw/cherry.git/'


Remove newlines.

Remove newlines.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/fulcrumapp/fulcrum-expressions.git/'


fixed "show more" logic

fixed "show more" logic

--- client/app/CommonViews/opinions/opinionlistitemview.coffee
+++ client/app/CommonViews/opinions/opinionlistitemview.coffee
@@ -131,7 +131,7 @@
     maxHeight = 300

     if @markup.height()>maxHeight
-      @textMaxHeight = @getHeight()
+      @textMaxHeight = @markup.height()
       @markup.css {maxHeight}
       @larger.show()


Добавил место для тестов

Добавил место для тестов

error: pathspec 'test/test.coffee' did not match any file(s) known to git

--- test/test.coffee
+++ test/test.coffee
@@ -0,0 +1,10 @@
+describe 'rubles', ->
+
+  {rubles} = require '../src/rubles'
+
+  it 'first tests', ->
+    text = rubles "4,99"
+    text.should.equal 'четыре рубля 99 копеек'
+
+    text = rubles 11.12
+    text.should.equal 'одиннадцать рублей 12 копеек'


Small performance improvement for web UI servers index

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/grandquista/rethinkdb.git/'


Add GitLabCrop class

Add GitLabCrop class

error: pathspec 'app/assets/javascripts/gl_crop.js.coffee' did not match any file(s) known to git

--- app/assets/javascripts/gl_crop.js.coffee
+++ app/assets/javascripts/gl_crop.js.coffee
@@ -0,0 +1,118 @@
+class GitLabCrop
+  constructor: (el, opts = {}) ->
+    # Input file
+    @fileInput = $(el)
+
+    # Set defaults
+    {
+      @filename
+      @form = @fileInput.parents('form')
+      @modalCrop = '.modal-profile-crop'
+
+      # Button where user clicks to open file dialog
+      # If not passed as argument let's pick a default one
+      @pickImageEl = @fileInput.parent().find('.js-choose-user-avatar-button')
+      @uploadImageBtn = $('.js-upload-user-avatar')
+    } = opts
+
+    # Ensure @modalCrop is a jQuery Object
+    @modalCrop = $(@modalCrop)
+    @modalCropImg = $('.modal-profile-crop-image')
+    @cropActionsBtn = @modalCrop.find('[data-method]')
+
+    @bindEvents()
+
+  bindEvents: ->
+    self = @
+    @fileInput.on 'change', (e) ->
+      self.onFileInputChange(e, @)
+
+    @pickImageEl.on 'click', @onPickImageClick
+    @modalCrop.on 'shown.bs.modal', @onModalShow
+    @modalCrop.on 'hidden.bs.modal', @onModalHide
+    @uploadImageBtn.on 'click', @onUploadImageBtnClick
+    @cropActionsBtn.on 'click', (e) ->
+      btn = @
+      self.onActionBtnClick(btn)
+    @croppedImageBlob = null
+
+  onPickImageClick: =>
+    @fileInput.trigger('click')
+
+  onModalShow: =>
+    @modalCropImg.cropper(
+      viewMode: 1
+      center: false
+      aspectRatio: 1
+      modal: true
+      scalable: false
+      rotatable: false
+      zoomable: true
+      dragMode: 'move'
+      guides: false
+      zoomOnTouch: false
+      zoomOnWheel: false
+      cropBoxMovable: false
+      cropBoxResizable: false
+      toggleDragModeOnDblclick: false
+      built: ->
+        container = $(@).cropper 'getContainerData'
+        cropBoxWidth = 200;
+        cropBoxHeight = 200;
+
+        $(@).cropper('setCropBoxData',
+          width: cropBoxWidth,
+          height: cropBoxHeight,
+          left: (container.width - cropBoxWidth) / 2,
+          top: (container.height - cropBoxHeight) / 2
+        )
+    )
+
+
+  onModalHide: =>
+    @modalCropImg
+      .attr('src', '') # Remove attached image
+      .cropper('destroy') # Destroy cropper instance
+
+  onUploadImageBtnClick: (e) =>
+    e.preventDefault()
+    @setBlob()
+    @modalCrop.modal('hide')
+    # @form.submit();
+
+  onActionBtnClick: (btn) ->
+    data = $(btn).data()
+
+    if @modalCropImg.data('cropper') && data.method
+      data = $.extend {}, data
+      result = @modalCropImg.cropper data.method, data.option
+
+  onFileInputChange: (e, input) ->
+    @readFile(input)
+
+  readFile: (input) ->
+    self = @
+    reader = new FileReader
+    reader.onload = ->
+      self.modalCropImg.attr('src', reader.result)
+      self.modalCrop.modal('show')
+
+    reader.readAsDataURL(input.files[0])
+
+  dataURLtoBlob: (dataURL) ->
+    binary = atob(dataURL.split(',')[1])
+    array = []
+    for v, k in  binary
+      array.push(binary.charCodeAt(k))
+    new Blob([new Uint8Array(array)], type: 'image/png')
+
+  setBlob: ->
+    dataURL = @modalCropImg.cropper('getCroppedCanvas').toDataURL('image/png')
+    @croppedImageBlob = @dataURLtoBlob(dataURL)
+
+  getBlob: ->
+    @croppedImageBlob
+
+$.fn.glCrop = (opts) ->
+  return @.each ->
+    $(@).data('glcrop', new GitLabCrop(@, opts))


CoffeeScript stylistic changes

CoffeeScript stylistic changes

--- assets/javascripts/mailcatcher.js.coffee
+++ assets/javascripts/mailcatcher.js.coffee
@@ -6,34 +6,34 @@
 #= require xslt

 # Add a new jQuery selector expression which does a case-insensitive :contains
-jQuery.expr[':'].icontains = (a, i, m) ->
+jQuery.expr[":"].icontains = (a, i, m) ->
   (a.textContent ? a.innerText ? "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0

 class MailCatcher
   constructor: ->
-    $('#messages tr').live 'click', (e) =>
-      e.preventDefault()
-      @loadMessage $(e.currentTarget).attr 'data-message-id'
-
-    $('input[name=search]').keyup (e) =>
+    $("#messages tr").live "click", (e) =>
+      e.preventDefault()
+      @loadMessage $(e.currentTarget).attr("data-message-id")
+
+    $("input[name=search]").keyup (e) =>
       query = $.trim $(e.currentTarget).val()
       if query
         @searchMessages query
       else
         @clearSearch()

-    $('#message .views .format.tab a').live 'click', (e) =>
-      e.preventDefault()
-      @loadMessageBody @selectedMessage(), $($(e.currentTarget).parent('li')).data 'message-format'
-
-    $('#message .views .analysis.tab a').live 'click', (e) =>
+    $("#message .views .format.tab a").live "click", (e) =>
+      e.preventDefault()
+      @loadMessageBody @selectedMessage(), $($(e.currentTarget).parent("li")).data("message-format")
+
+    $("#message .views .analysis.tab a").live "click", (e) =>
       e.preventDefault()
       @loadMessageAnalysis @selectedMessage()

-    $('#message iframe').load =>
+    $("#message iframe").load =>
       @decorateMessageBody()

-    $('#resizer').live
+    $("#resizer").live
       mousedown: (e) =>
         e.preventDefault()
         $(window).bind events =
@@ -46,66 +46,66 @@

     @resizeToSaved()

-    $('nav.app .clear a').live 'click', (e) =>
+    $("nav.app .clear a").live "click", (e) =>
       e.preventDefault()
       if confirm "You will lose all your received messages.\n\nAre you sure you want to clear all messages?"
         $.ajax
-          url: '/messages'
-          type: 'DELETE'
+          url: "/messages"
+          type: "DELETE"
           success: =>
             @unselectMessage()
           error: ->
-            alert 'Error while clearing all messages.'
-
-    $('nav.app .quit a').live 'click', (e) =>
+            alert "Error while clearing all messages."
+
+    $("nav.app .quit a").live "click", (e) =>
       e.preventDefault()
       if confirm "You will lose all your received messages.\n\nAre you sure you want to quit?"
         $.ajax
-          type: 'DELETE'
+          type: "DELETE"
           success: ->
-            location.replace $('body > header h1 a').attr('href')
+            location.replace $("body > header h1 a").attr("href")
           error: ->
-            alert 'Error while quitting.'
-
-    key 'up', =>
+            alert "Error while quitting."
+
+    key "up", =>
       if @selectedMessage()
-        @loadMessage $('#messages tr.selected').prev().data('message-id')
+        @loadMessage $("#messages tr.selected").prev().data("message-id")
       else
-        @loadMessage $('#messages tbody tr[data-message-id]:first').data('message-id')
-      false
-
-    key 'down', =>
+        @loadMessage $("#messages tbody tr[data-message-id]:first").data("message-id")
+      false
+
+    key "down", =>
       if @selectedMessage()
-        @loadMessage $('#messages tr.selected').next().data('message-id')
+        @loadMessage $("#messages tr.selected").next().data("message-id")
       else
-        @loadMessage $('#messages tbody tr[data-message-id]:first').data('message-id')
-      false
-
-    key '⌘+up, ctrl+up', =>
-      @loadMessage $('#messages tbody tr[data-message-id]:first').data('message-id')
-      false
-
-    key '⌘+down, ctrl+down', =>
-      @loadMessage $('#messages tbody tr[data-message-id]:last').data('message-id')
-      false
-
-    key 'left', =>
+        @loadMessage $("#messages tbody tr[data-message-id]:first").data("message-id")
+      false
+
+    key "⌘+up, ctrl+up", =>
+      @loadMessage $("#messages tbody tr[data-message-id]:first").data("message-id")
+      false
+
+    key "⌘+down, ctrl+down", =>
+      @loadMessage $("#messages tbody tr[data-message-id]:last").data("message-id")
+      false
+
+    key "left", =>
       @openTab @previousTab()
       false

-    key 'right', =>
+    key "right", =>
       @openTab @nextTab()
       false

-    key 'backspace, delete', =>
+    key "backspace, delete", =>
       id = @selectedMessage()
       if id?
         $.ajax
-          url: '/messages/' + id
-          type: 'DELETE'
+          url: "/messages/" + id
+          type: "DELETE"
           success: =>
-            messageRow = $("#messages tbody tr[data-message-id='#{id}']")
-            switchTo = messageRow.next().data('message-id') || messageRow.prev().data('message-id')
+            messageRow = $("""#messages tbody tr[data-message-id="#{id}"]""")
+            switchTo = messageRow.next().data("message-id") || messageRow.prev().data("message-id")
             messageRow.remove()
             if switchTo
               @loadMessage switchTo
@@ -113,7 +113,7 @@
               @unselectMessage()

           error: ->
-            alert 'Error while removing message.'
+            alert "Error while removing message."
       false

     @refresh()
@@ -137,19 +137,19 @@
     date &&= date.toString("dddd, d MMM yyyy h:mm:ss tt")

   messagesCount: ->
-    $('#messages tr').length - 1
+    $("#messages tr").length - 1

   tabs: ->
-    $('#message ul').children('.tab')
+    $("#message ul").children(".tab")

   getTab: (i) =>
     $(@tabs()[i])

   selectedTab: =>
-    @tabs().index($('#message li.tab.selected'))
+    @tabs().index($("#message li.tab.selected"))

   openTab: (i) =>
-    @getTab(i).children('a').click()
+    @getTab(i).children("a").click()

   previousTab: (tab)=>
     i = if tab || tab is 0 then tab else @selectedTab() - 1
@@ -157,7 +157,7 @@
     if @getTab(i).is(":visible")
       i
     else
-      @previousTab(i-1)
+      @previousTab(i - 1)

   nextTab: (tab) =>
     i = if tab then tab else @selectedTab() + 1
@@ -165,87 +165,87 @@
     if @getTab(i).is(":visible")
       i
     else
-      @nextTab(i+1)
+      @nextTab(i + 1)

   haveMessage: (message) ->
     message = message.id if message.id?
-    $("#messages tbody tr[data-message-id=\"#{message}\"]").length > 0
+    $("""#messages tbody tr[data-message-id="#{message}"]""").length > 0

   selectedMessage: ->
-    $('#messages tr.selected').data 'message-id'
+    $("#messages tr.selected").data "message-id"

   searchMessages: (query) ->
-    selector = (":icontains('#{token}')" for token in query.split /\s+/).join ""
+    selector = (":icontains('#{token}')" for token in query.split /\s+/).join("")
     $rows = $("#messages tbody tr")
     $rows.not(selector).hide()
     $rows.filter(selector).show()

   clearSearch: ->
-    $('#messages tbody tr').show()
+    $("#messages tbody tr").show()

   addMessage: (message) ->
-    $('
').attr('data-message-id', message.id.toString())
-      .append($('').text(message.sender or "No sender").toggleClass("blank", !message.sender))
-      .append($('').text((message.recipients || []).join(', ') or "No receipients").toggleClass("blank", !message.recipients.length))
-      .append($('').text(message.subject or "No subject").toggleClass("blank", !message.subject))
-      .append($('').text(@formatDate(message.created_at)))
-      .prependTo($('#messages tbody'))
+    $("
").attr("data-message-id", message.id.toString())
+      .append($("").text(message.sender or "No sender").toggleClass("blank", !message.sender))
+      .append($("").text((message.recipients || []).join(", ") or "No receipients").toggleClass("blank", !message.recipients.length))
+      .append($("").text(message.subject or "No subject").toggleClass("blank", !message.subject))
+      .append($("").text(@formatDate(message.created_at)))
+      .prependTo($("#messages tbody"))

   scrollToRow: (row) ->
-    relativePosition = row.offset().top - $('#messages').offset().top
+    relativePosition = row.offset().top - $("#messages").offset().top
     if relativePosition < 0
-      $('#messages').scrollTop($('#messages').scrollTop() + relativePosition - 20)
+      $("#messages").scrollTop($("#messages").scrollTop() + relativePosition - 20)
     else
-      overflow = relativePosition + row.height() - $('#messages').height()
+      overflow = relativePosition + row.height() - $("#messages").height()
       if overflow > 0
-        $('#messages').scrollTop($('#messages').scrollTop() + overflow + 20)
+        $("#messages").scrollTop($("#messages").scrollTop() + overflow + 20)

   unselectMessage: ->
-    $('#messages tbody, #message .metadata dd').empty()
-    $('#message .metadata .attachments').hide()
-    $('#message iframe').attr 'src', 'about:blank'
+    $("#messages tbody, #message .metadata dd").empty()
+    $("#message .metadata .attachments").hide()
+    $("#message iframe").attr("src", "about:blank")
     null

   loadMessage: (id) ->
     id = id.id if id?.id?
-    id ||= $('#messages tr.selected').attr 'data-message-id'
+    id ||= $("#messages tr.selected").attr "data-message-id"

     if id?
-      $("#messages tbody tr:not([data-message-id='#{id}'])").removeClass 'selected'
+      $("#messages tbody tr:not([data-message-id='#{id}'])").removeClass("selected")
       messageRow = $("#messages tbody tr[data-message-id='#{id}']")
-      messageRow.addClass 'selected'
+      messageRow.addClass("selected")
       @scrollToRow(messageRow)

       $.getJSON "/messages/#{id}.json", (message) =>
-        $('#message .metadata dd.created_at').text @formatDate message.created_at
-        $('#message .metadata dd.from').text message.sender
-        $('#message .metadata dd.to').text (message.recipients || []).join(', ')
-        $('#message .metadata dd.subject').text message.subject
-        $('#message .views .tab.format').each (i, el) ->
+        $("#message .metadata dd.created_at").text(@formatDate message.created_at)
+        $("#message .metadata dd.from").text(message.sender)
+        $("#message .metadata dd.to").text((message.recipients || []).join(", "))
+        $("#message .metadata dd.subject").text(message.subject)
+        $("#message .views .tab.format").each (i, el) ->
           $el = $(el)
-          format = $el.attr 'data-message-format'
+          format = $el.attr("data-message-format")
           if $.inArray(format, message.formats) >= 0
-            $el.find('a').attr('href', "/messages/#{id}.#{format}")
+            $el.find("a").attr("href", "/messages/#{id}.#{format}")
             $el.show()
           else
             $el.hide()

         if $("#message .views .tab.selected:not(:visible)").length
-          $("#message .views .tab.selected").removeClass "selected"
-          $("#message .views .tab:visible:first").addClass "selected"
+          $("#message .views .tab.selected").removeClass("selected")
+          $("#message .views .tab:visible:first").addClass("selected")

         if message.attachments.length
-          $ul = $('
').appendTo($('#message .metadata dd.attachments').empty())
+          $ul = $("
").appendTo($("#message .metadata dd.attachments").empty())

           $.each message.attachments, (i, attachment) ->
-            $ul.append($('
').append($('').attr('href', attachment['href']).addClass(attachment['type'].split('/', 1)[0]).addClass(attachment['type'].replace('/', '-')).text(attachment['filename'])));
-          $('#message .metadata .attachments').show()
+            $ul.append($("
").append($("").attr("href", attachment["href"]).addClass(attachment["type"].split("/", 1)[0]).addClass(attachment["type"].replace("/", "-")).text(attachment["filename"])))
+          $("#message .metadata .attachments").show()
         else
-          $('#message .metadata .attachments').hide()
-
-        $('#message .views .download a').attr 'href', "/messages/#{id}.eml"
-
-        if $('#message .views .tab.analysis.selected').length
+          $("#message .metadata .attachments").hide()
+
+        $("#message .views .download a").attr("href", "/messages/#{id}.eml")
+
+        if $("#message .views .tab.analysis.selected").length
           @loadMessageAnalysis()
         else
           @loadMessageBody()
@@ -254,40 +254,38 @@

   loadMessageBody: (id, format) ->
     id ||= @selectedMessage()
-    format ||= $('#message .views .tab.format.selected').attr 'data-message-format'
-    format ||= 'html'
-
-    $("#message .views .tab[data-message-format=\"#{format}\"]:not(.selected)").addClass 'selected'
-    $("#message .views .tab:not([data-message-format=\"#{format}\"]).selected").removeClass 'selected'
+    format ||= $("#message .views .tab.format.selected").attr("data-message-format")
+    format ||= "html"
+
+    $("""#message .views .tab[data-message-format="#{format}"]:not(.selected)""").addClass("selected")
+    $("""#message .views .tab:not([data-message-format="#{format}"]).selected""").removeClass("selected")

     if id?
-      $('#message iframe').attr "src", "/messages/#{id}.#{format}"
-
-      app = this
+      $("#message iframe").attr("src", "/messages/#{id}.#{format}")

   decorateMessageBody: ->
-    format = $('#message .views .tab.format.selected').attr 'data-message-format'
+    format = $("#message .views .tab.format.selected").attr("data-message-format")

     switch format
-      when 'html'
-        body = $('#message iframe').contents().find('body')
+      when "html"
+        body = $("#message iframe").contents().find("body")
         $("a", body).attr("target", "_blank")
-      when 'plain'
-        message_iframe = $('#message iframe').contents()
+      when "plain"
+        message_iframe = $("#message iframe").contents()
         text = message_iframe.text()
-        text = text.replace(/((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?)/g, '$1')
-        text = text.replace(/\n/g, '
')
-        message_iframe.find('html').html('' + text + '')
+        text = text.replace(/((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?)/g, """$1""")
+        text = text.replace(/\n/g, "
")
+        message_iframe.find("html").html("#{text}")

   loadMessageAnalysis: (id) ->
     id ||= @selectedMessage()

-    $("#message .views .analysis.tab:not(.selected)").addClass 'selected'
-    $("#message .views :not(.analysis).tab.selected").removeClass 'selected'
+    $("#message .views .analysis.tab:not(.selected)").addClass("selected")
+    $("#message .views :not(.analysis).tab.selected").removeClass("selected")

     if id?
       # Makes a new iframe and populate it with a quick intro and a button
-      $iframe = $('#message iframe').contents().children()
+      $iframe = $("#message iframe").contents().children()
         .html("""

@@ -304,16 +302,16 @@

         """)
-      $form = $iframe.find('form')
+      $form = $iframe.find("form")
         .submit (e) ->
           e.preventDefault()
           $(this)
-            .find('input[type="submit"]').attr('disabled', 'disabled').end()
-            .find('.loading').show()
-          $('#message iframe').contents().find('body').xslt("/messages/#{id}/analysis.xml", "/stylesheets/analysis.xsl")
+            .find("""input[type="submit"]""").attr("disabled", "disabled").end()
+            .find(".loading").show()
+          $("#message iframe").contents().find("body").xslt("/messages/#{id}/analysis.xml", "/stylesheets/analysis.xsl")

   refresh: ->
-    $.getJSON '/messages', (messages) =>
+    $.getJSON "/messages", (messages) =>
       $.each messages, (i, message) =>
         unless @haveMessage message
           @addMessage message
@@ -325,8 +323,8 @@
       @subscribePoll()

   subscribeWebSocket: ->
-    secure = window.location.scheme == 'https'
-    @websocket = new WebSocket("#{if secure then 'wss' else 'ws'}://#{window.location.host}/messages")
+    secure = window.location.scheme == "https"
+    @websocket = new WebSocket("#{if secure then "wss" else "ws"}://#{window.location.host}/messages")
     @websocket.onmessage = (event) =>
       @addMessage $.parseJSON event.data

@@ -334,11 +332,11 @@
     unless @refreshInterval?
       @refreshInterval = setInterval (=> @refresh()), 1000

-  resizeToSavedKey: 'mailcatcherSeparatorHeight'
+  resizeToSavedKey: "mailcatcherSeparatorHeight"

   resizeTo: (height) ->
-    $('#messages').css
-      height: height - $('#messages').offset().top
+    $("#messages").css
+      height: height - $("#messages").offset().top
     window.localStorage?.setItem(@resizeToSavedKey, height)

   resizeToSaved: ->


Add positionString utility function for parsing position-type strings.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/JoshuaToenyes/stout-client.git/'


Search completion; add Merriam-Webster.

Search completion; add Merriam-Webster.

--- background_scripts/completion_engines.coffee
+++ background_scripts/completion_engines.coffee
@@ -102,6 +102,12 @@
   parse: (xhr) ->
     suggestion.phrase for suggestion in JSON.parse xhr.responseText

+class Webster extends RegexpEngine
+  # Example search URL: http://www.merriam-webster.com/dictionary/%s
+  constructor: -> super [ new RegExp "^https?://www.merriam-webster.com/dictionary/" ]
+  getUrl: (queryTerms) -> Utils.createSearchUrl queryTerms, "http://www.merriam-webster.com/autocomplete?query=%s"
+  parse: (xhr) -> JSON.parse(xhr.responseText).suggestions
+
 # A dummy search engine which is guaranteed to match any search URL, but never produces completions.  This
 # allows the rest of the logic to be written knowing that there will always be a completion engine match.
 class DummyCompletionEngine
@@ -119,6 +125,7 @@
   Wikipedia
   Bing
   Amazon
+  Webster
   DummyCompletionEngine
 ]


Make tests pass

Make tests pass

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/kevgo/asynchronizer.git/'


statusupdate: share the likeIsRemoved event

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/andrewjcasal/koding.git/'


Scopes the nock response to only the 2 tests that need it.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/usermindinc/hubot-jira-reporter.git/'


Added tests for poi.initial.

Added tests for poi.initial.

error: pathspec 'test/specs/initial-spec.coffee' did not match any file(s) known to git

--- test/specs/initial-spec.coffee
+++ test/specs/initial-spec.coffee
@@ -0,0 +1,22 @@
+describe 'poi.initial', ->
+    it 'Initial module will setup $locationProvider.html5Mode.', ->
+        locationProvider = null
+        routerProvider = null
+
+        locationModule = angular.module 'locationModule', []
+        locationModule.config ($locationProvider) ->
+            locationProvider = $locationProvider
+            spyOn locationProvider, 'html5Mode'
+
+        fakeModule = angular.module 'fakeModule', ['poi']
+        fakeModule.config ($routerProvider) ->
+            routerProvider = $routerProvider
+
+        module 'locationModule'
+        module 'poi'
+        module 'fakeModule'
+
+        inject ($router) ->
+            expect(locationProvider.html5Mode).toHaveBeenCalledWith
+                enabled: yes
+                requireBase: no


Initial version

Initial version

--- src/hoard.coffee
+++ src/hoard.coffee
@@ -0,0 +1,607 @@
+fs = require('fs')
+Buffer = require('buffer').Buffer
+Binary = require('binary')
+_ = underscore = require('underscore')
+async = require('async')
+pack = require('jspack').jspack
+path = require('path')
+Put = require('put')
+
+
+# Monkey patch since modulo operator is broken in JS
+Number.prototype.mod = (n) -> ((@ % n) + n) % n
+
+longFormat = "!L"
+longSize = pack.CalcLength(longFormat)
+floatFormat = "!f"
+floatSize = pack.CalcLength(floatFormat)
+timestampFormat = "!L"
+timestampSize = pack.CalcLength(timestampFormat)
+valueFormat = "!d"
+valueSize = pack.CalcLength(valueFormat)
+pointFormat = "!Ld"
+pointSize = pack.CalcLength(pointFormat)
+metadataFormat = "!2LfL"
+metadataSize = pack.CalcLength(metadataFormat)
+archiveInfoFormat = "!3L"
+archiveInfoSize = pack.CalcLength(archiveInfoFormat)
+
+# FIXME: Determine this in a better way
+POINT_SIZE = 4 + 8 # long, double
+
+unixTime = -> parseInt(new Date().getTime() / 1000)
+
+create = (filename, archives, xFilesFactor, cb) ->
+    # FIXME: Check parameters
+    # FIXME: Check that values are correctly formatted
+    archives.sort (a, b) -> a[0] - b[0]
+
+    if path.existsSync(filename)
+        cb new Error('File ' + filename + ' already exists')
+
+    oldest = (a[0] * a[1] for a in archives).sort().reverse()[0]
+
+    encodeFloat = (value) ->
+        # Dirty hack.
+        # Using 'buffer_ieee754' from node 0.5.x
+        # as no libraries had a working IEEE754 encoder
+        buffer = new Buffer(4)
+        require('buffer_ieee754').writeIEEE754(buffer, 0.5, 0, 'big', 23, 4);
+        buffer
+
+    buffer = Put()
+        .word32be(unixTime()) # last update
+        .word32be(oldest) # max retention
+        .put(encodeFloat(xFilesFactor))
+        .word32be(archives.length)
+
+    headerSize = metadataSize + (archiveInfoSize * archives.length)
+    archiveOffset = headerSize
+
+    for archive in archives
+        secondsPerPoint = archive[0]; points = archive[1]
+        buffer.word32be(archiveOffset)
+        buffer.word32be(secondsPerPoint)
+        buffer.word32be(points)
+        archiveOffset += (points * pointSize)
+
+    # Pad archive data itself with zeroes
+    buffer.pad(archiveOffset - headerSize)
+
+    # FIXME: Check file lock?
+    # FIXME: fsync this?
+    fs.writeFile filename, buffer.buffer(), 'binary', cb
+
+propagate = (fd, timestamp, xff, higher, lower, cb) ->
+    lowerIntervalStart = timestamp - timestamp.mod(lower.secondsPerPoint)
+    lowerIntervalEnd = lowerIntervalStart + lower.secondsPerPoint
+
+    packedPoint = new Buffer(pointSize)
+    fs.read fd, packedPoint, 0, pointSize, higher.offset, (err, written, buffer) ->
+        cb(err) if err
+        [higherBaseInterval, higherBaseValue] = pack.Unpack(pointFormat, packedPoint)
+
+        if higherBaseInterval == 0
+            higherFirstOffset = higher.offset
+        else
+            timeDistance = lowerIntervalStart - higherBaseInterval
+            pointDistance = timeDistance / higher.secondsPerPoint
+            byteDistance = pointDistance * pointSize
+            higherFirstOffset = higher.offset + byteDistance.mod(higher.size)
+
+        higherPoints = lower.secondsPerPoint / higher.secondsPerPoint
+        higherSize = higherPoints * pointSize
+        relativeFirstOffset = higherFirstOffset - higher.offset
+        relativeLastOffset = (relativeFirstOffset + higherSize).mod(higher.size)
+        higherLastOffset = relativeLastOffset + higher.offset
+
+        # !!!!!!!!!!!!!!!!!
+        #fh.seek(higherFirstOffset)
+        #console.log 'seriesSize'
+        #console.log 'seriesSize', 123
+        if higherFirstOffset < higherLastOffset
+            # We don't wrap the archive
+
+            seriesSize = higherLastOffset - higherFirstOffset
+
+            seriesString = new Buffer(seriesSize)
+
+            #console.log 'seriesSize', seriesSize
+            #console.log 'seriesSize', seriesSize
+
+            fs.read fd, seriesString, 0, seriesSize, higherFirstOffset, (err, written, buffer) ->
+                parseSeries(seriesString)
+            #parseSeries(seriesString)
+
+        else
+            console.log 'seriesSize', 124
+            # We do wrap the archive
+            higherEnd = higher.offset + higher.size
+            # !!!!!!!!!!!!!!!!!
+            firstSeriesSize = higherEnd - higherFirstOffset
+            secondSeriesSize = higherLastOffset - higher.offset
+
+            seriesString = new Buffer(firstSeriesSize + secondSeriesSize)
+
+            console.log 'seriesSize here', (firstSeriesSize + secondSeriesSize)
+            console.log 'higherFirstOffset', higherFirstOffset
+            console.log 'firstSeriesSize', firstSeriesSize
+            console.log 'ASDASD'
+            fs.read fd, seriesString, 0, firstSeriesSize, higherFirstOffset, (err, written, buffer) ->
+                cb(err) if err
+                console.log 'higher.offset', higher.offset
+                console.log 'firstSeriesSize', firstSeriesSize
+                console.log 'secondSeriesSize', secondSeriesSize
+                if secondSeriesSize > 0
+                    fs.read fd, seriesString, firstSeriesSize, secondSeriesSize, higher.offset, (err, written, buffer) ->
+                        cb(err) if err
+                        parseSeries(seriesString)
+                else
+                    ret = new Buffer(firstSeriesSize)
+                    seriesString.copy(ret, 0, 0, firstSeriesSize)
+                    parseSeries(ret)
+
+    parseSeries = (seriesString) ->
+        # Now we unpack the series data we just read
+        [byteOrder, pointTypes] = [pointFormat[0], pointFormat.slice(1)]
+        points = seriesString.length / pointSize
+
+        seriesFormat = byteOrder + (pointTypes for f in [0...points]).join("")
+        unpackedSeries = pack.Unpack(seriesFormat, seriesString, 0)
+
+        # And finally we construct a list of values
+        neighborValues = (null for f in [0...points])
+        currentInterval = lowerIntervalStart
+        step = higher.secondsPerPoint
+
+        for i in [0...unpackedSeries.length] by 2
+            pointTime = unpackedSeries[i]
+            if pointTime == currentInterval
+                neighborValues[i/2] = unpackedSeries[i+1]
+            currentInterval += step
+
+
+
+        # Propagate aggregateValue to propagate from neighborValues if we have enough known points
+        knownValues = (v for v in neighborValues when v isnt null)
+        if knownValues.length == 0
+            cb null, false
+            return
+
+        sum = (list) ->
+            s = 0
+            for x in list
+                s += x
+            s
+
+        knownPercent = knownValues.length / neighborValues.length
+        if knownPercent >= xff
+            # We have enough data to propagate a value!
+            aggregateValue = sum(knownValues) / knownValues.length # TODO: Another CF besides average?
+            myPackedPoint = pack.Pack(pointFormat, [lowerIntervalStart, aggregateValue])
+
+            # !!!!!!!!!!!!!!!!!
+            packedPoint = new Buffer(pointSize)
+            fs.read fd, packedPoint, 0, pointSize, lower.offset, (err) ->
+                [lowerBaseInterval, lowerBaseValue] = pack.Unpack(pointFormat, packedPoint)
+
+                if lowerBaseInterval == 0
+                    # First propagated update to this lower archive
+                    offset = lower.offset
+                else
+                    # Not our first propagated update to this lower archive
+                    timeDistance = lowerIntervalStart - lowerBaseInterval
+                    pointDistance = timeDistance / lower.secondsPerPoint
+                    byteDistance = pointDistance * pointSize
+                    offset = lower.offset + byteDistance.mod(lower.size)
+
+                #console.log 'myPackedPoint', myPackedPoint
+                #console.log 'pointSize', pointSize
+                #console.log 'offset', offset
+                mypp = new Buffer(myPackedPoint)
+                fs.write fd, mypp, 0, pointSize, offset, (err) ->
+                    #console.log 'apa'
+                    cb(null, true)
+        else
+            cb(null, false)
+
+
+update = (filename, value, timestamp, cb) ->
+    # FIXME: Check file lock?
+    # FIXME: Don't use info(), re-use fd between internal functions
+    info filename, (err, header) ->
+        cb(err) if err
+        now = unixTime()
+        diff = now - timestamp
+        if not (diff < header.maxRetention and diff >= 0)
+            cb(new Error('Timestamp not covered by any archives in this database.'))
+            return
+
+        #console.log('Header', header)
+
+        # Find the highest-precision archive that covers timestamp
+        for i in [0...header.archives.length]
+            archive = header.archives[i]
+            continue if archive.retention < diff
+            # We'll pass on the update to these lower precision archives later
+            lowerArchives = header.archives.slice(i + 1)
+            break
+
+        fs.open filename, 'r+', (err, fd) ->
+            cb(err) if err
+            # First we update the highest-precision archive
+            myInterval = timestamp - timestamp.mod(archive.secondsPerPoint)
+            myPackedPoint = new Buffer(pack.Pack(pointFormat, [myInterval, value]))
+
+            packedPoint = new Buffer(pointSize)
+            fs.read fd, packedPoint, 0, pointSize, archive.offset, (err, bytesRead, buffer) ->
+                cb(err) if err
+                [baseInterval, baseValue] = pack.Unpack(pointFormat, packedPoint)
+
+                if baseInterval == 0
+                    # This file's first update
+                    fs.write fd, myPackedPoint, 0, pointSize, archive.offset, (err, written, buffer) ->
+                        cb(err) if err
+                        [baseInterval, baseValue] = [myInterval, value]
+                        propagateLowerArchives()
+                else
+                    # File has been updated before
+                    timeDistance = myInterval - baseInterval
+                    pointDistance = timeDistance / archive.secondsPerPoint
+                    byteDistance = pointDistance * pointSize
+                    myOffset = archive.offset + byteDistance.mod(archive.size)
+                    fs.write fd, myPackedPoint, 0, pointSize, myOffset, (err, written, buffer) ->
+                        cb(err) if err
+                        propagateLowerArchives()
+
+            propagateLowerArchives = ->
+                # Propagate the update to lower-precision archives
+                #higher = archive
+                #for lower in lowerArchives:
+                #    if not __propagate(fd, myInterval, header.xFilesFactor, higher, lower):
+                #        break
+                #    higher = lower
+
+                #__changeLastUpdate(fh)
+
+                # FIXME: Also fsync here?
+                fs.close fd, cb
+    return
+
+updateMany = (filename, points, cb) ->
+    points.sort((a, b) -> a[0] - b[0]).reverse()
+    # FIXME: Check lock
+    info filename, (err, header) ->
+        cb err if err
+        fs.open filename, 'r+', (err, fd) ->
+            now = unixTime()
+            archives = header.archives
+            currentArchiveIndex = 0
+            currentArchive = header.archives[currentArchiveIndex]
+            currentPoints = []
+
+            console.log 'HEJ'
+            updateArchiveCalls = []
+            for point in points
+                age = now - point[0]
+
+                while currentArchive.retention < age # We can't fit any more points in this archive
+                    if currentPoints
+                        # Commit all the points we've found that it can fit
+                        currentPoints.reverse() # Put points in chronological order
+                        do (header, currentArchive, currentPoints) ->
+                            f = (cb) -> updateManyArchive fd, header, currentArchive, currentPoints, cb
+                            updateArchiveCalls.push(f)
+                        currentPoints = []
+
+                    if currentArchiveIndex < (archives.length - 1)
+                        currentArchiveIndex++
+                        currentArchive = archives[currentArchiveIndex]
+                    else
+                        # Last archive
+                        currentArchive = null
+                        break
+
+                if not currentArchive
+                    break # Drop remaining points that don't fit in the database
+
+                currentPoints.push(point)
+
+            console.log 'last uac'
+            async.series updateArchiveCalls, (err, results) ->
+                throw err if err
+                console.log 'async series 1'
+                if currentArchive and currentPoints.length > 0
+                    # Don't forget to commit after we've checked all the archives
+                    currentPoints.reverse()
+                    console.log 'async series 2'
+                    updateManyArchive fd, header, currentArchive, currentPoints, (err) ->
+                        console.log 'async series 3'
+                        throw err if err
+                        fs.close fd, cb
+                else
+                    console.log 'DONE IN UAC'
+                    fs.close fd, cb
+
+            # FIXME: touch last update
+            # FIXME: fsync here?
+            # FIXME: close fd fh.close()
+        #cb(null)
+
+
+
+updateManyArchive = (fd, header, archive, points, cb) ->
+    step = archive.secondsPerPoint
+    alignedPoints = []
+    #alignedPoints = [(timestamp - (timestamp % step), value) for (timestamp,value) in points]
+    for p in points
+        [timestamp, value] = p
+        alignedPoints.push([timestamp - timestamp.mod(step), value])
+
+
+    # Create a packed string for each contiguous sequence of points
+    packedStrings = []
+    previousInterval = null
+    currentString = []
+
+    #console.log 'ap', alignedPoints
+    for ap in alignedPoints
+        [interval, value] = ap
+
+        if !previousInterval or (interval == previousInterval + step)
+            currentString.concat(pack.Pack(pointFormat, [interval, value]))
+            previousInterval = interval
+        else
+            numberOfPoints = currentString.length / pointSize
+            startInterval = previousInterval - (step * (numberOfPoints - 1))
+            packedStrings.push([startInterval, new Buffer(currentString)])
+            currentString = pack.Pack(pointFormat, [interval, value])
+            previousInterval = interval
+
+    if currentString.length > 0
+        numberOfPoints = currentString.length / pointSize
+        startInterval = previousInterval - (step * (numberOfPoints - 1))
+        console.log 'packing', startInterval, currentString
+        packedStrings.push([startInterval, new Buffer(currentString, 'binary')])
+
+    # FIXME!!!
+    # currentString is an array with tuples of arrayer of data
+    # convert to buffers before writing
+
+    console.log 'APA1'
+    # Read base point and determine where our writes will start
+    packedBasePoint = new Buffer(pointSize)
+    fs.read fd, packedBasePoint, 0, pointSize, archive.offset, (err) ->
+        cb err if err
+        console.log 'APA2'
+        [baseInterval, baseValue] = pack.Unpack(pointFormat, packedBasePoint)
+
+        if baseInterval == 0
+            # This file's first update
+            # Use our first string as the base, so we start at the start
+            baseInterval = packedStrings[0][0]
+
+        # Write all of our packed strings in locations determined by the baseInterval
+
+        writePackedString = (ps, callback) ->
+            [interval, packedString] = ps
+            timeDistance = interval - baseInterval
+            pointDistance = timeDistance / step
+            byteDistance = pointDistance * pointSize
+            myOffset = archive.offset + byteDistance.mod(archive.size)
+            archiveEnd = archive.offset + archive.size
+            bytesBeyond = (myOffset + packedString.length) - archiveEnd
+
+            #console.log 'APA3'
+            #fh.seek(myOffset)
+            if bytesBeyond > 0
+                # FIXME fh.write( packedString[:-bytesBeyond] ) # Everything but not last bytesBeyond
+                #console.log 'APA4'
+                fs.write fd, packedString, 0, packedString.length - bytesBeyond, myOffset, (err) ->
+                    cb err if err
+                    #console.log 'APA4.1'
+                    assert.equal archiveEnd, myOffset + packedString.length - bytesBeyond
+                    #assert fh.tell() == archiveEnd, "archiveEnd=%d fh.tell=%d bytesBeyond=%d len(packedString)=%d" % (archiveEnd,fh.tell(),bytesBeyond,len(packedString))
+                    # Safe because it can't exceed the archive (retention checking logic above)
+                    fs.write fd, packedString, packedString.length - bytesBeyond, bytesBeyond, archive.offset, (err) ->
+                        cb err if err
+                        #console.log 'APA4.2'
+                        callback()
+            else
+                ## FIXME ALL THIS SHIT IT IS A looping, ARGH WTF
+                #console.log 'APA5'
+                #console.log 'ps', ps
+                #console.log 'packedString', packedString
+                fs.write fd, packedString, 0, packedString.length, myOffset, (err) ->
+                    #console.log "HELLO?"
+                    callback()
+
+        async.forEachSeries packedStrings, writePackedString, (err) ->
+            throw err if err
+            console.log 'Propagating to lower...'
+            propagateLowerArchives()
+
+
+        propagateLowerArchives = ->
+            # Now we propagate the updates to lower-precision archives
+            higher = archive
+            lowerArchives = (arc for arc in header.archives when arc.secondsPerPoint > archive.secondsPerPoint)
+            console.log 'prop1'
+
+            if lowerArchives.length > 0
+                # Collect a list of propagation calls to make
+                # This is easier than doing async looping
+                propagateCalls = []
+                console.log 'prop2'
+                for lower in lowerArchives
+                    fit = (i) -> i - i.mod(lower.secondsPerPoint)
+                    lowerIntervals = (fit(p[0]) for p in alignedPoints)
+                    uniqueLowerIntervals = _.uniq(lowerIntervals)
+                    for interval in uniqueLowerIntervals
+                        propagateCalls.push {interval: interval, header: header, higher: higher, lower: lower}
+                    higher = lower
+
+                callPropagate = (args, callback) ->
+                    propagate fd, args.interval, args.header.xFilesFactor, args.higher, args.lower, (err, result) ->
+                        cb err if err
+                        callback err, result
+
+                #callPropagate()
+                async.forEachSeries propagateCalls, callPropagate, (err, result) ->
+                    throw err if err
+                    console.log 'done dirty prop loop'
+                    cb null
+            else
+                console.log 'prop1.end'
+                cb null
+
+info = (path, cb) ->
+    # FIXME: Close this stream?
+    # FIXME: Signal errors to callback?
+
+    # FIXME: Stream parsing with node-binary dies
+    # Looks like an issue, see their GitHub
+    # Using fs.readFile() instead of read stream for now
+    fs.readFile path, (err, data) ->
+        cb err if err
+        archives = []; metadata = {}
+
+        Binary.parse(data)
+            .word32bu('lastUpdate')
+            .word32bu('maxRetention')
+            .buffer('xff', 4) # Must decode separately since node-binary can't handle floats
+            .word32bu('archiveCount')
+            .tap (vars) ->
+                metadata = vars
+                metadata.xff = pack.Unpack('!f', vars.xff, 0)[0]
+                @flush()
+                for index in [0...metadata.archiveCount]
+                    @word32bu('offset').word32bu('secondsPerPoint').word32bu('points')
+                    @tap (archive) ->
+                        @flush()
+                        archive.retention = archive.secondsPerPoint * archive.points
+                        archive.size = archive.points * POINT_SIZE
+                        archives.push(archive)
+            .tap ->
+                cb null,
+                    maxRetention: metadata.maxRetention
+                    xFilesFactor: metadata.xff
+                    archives: archives
+    return
+
+fetch = (path, from, to, cb) ->
+    info path, (err, header) ->
+        now = unixTime()
+        oldestTime = now - header.maxRetention
+        from = oldestTime if from < oldestTime
+        throw new Error('Invalid time interval') unless from < to
+        to = now if to > now or to < from
+        diff = now - from
+        fd = null
+
+        # Find closest archive to look in, that iwll contain our information
+        for archive in header.archives
+            break if archive.retention >= diff
+
+        fromInterval = parseInt(from - from.mod(archive.secondsPerPoint)) + archive.secondsPerPoint
+        toInterval = parseInt(to - to.mod(archive.secondsPerPoint)) + archive.secondsPerPoint
+
+        file = fs.createReadStream(path)
+
+        Binary.stream(file)
+            .skip(archive.offset)
+            .word32bu('baseInterval')
+            .word32bu('baseValue')
+            .tap (vars) ->
+                if vars.baseInterval == 0
+                    # Nothing has been written to this hoard
+                    step = archive.secondsPerPoint
+                    points = (toInterval - fromInterval) / step
+                    timeInfo = [fromInterval, toInterval, step]
+                    values = (null for n in [0...points])
+                    cb(null, timeInfo, values)
+                else
+                    #console.log 'vars', vars
+                    #console.log 'fromInterval', fromInterval
+                    #console.log 'toInterval', toInterval
+
+                    #console.log '---------------'
+                    # We have data in this hoard, let's read it
+                    getOffset = (interval) ->
+                        timeDistance = interval - vars.baseInterval
+                        #console.log 'timeDistance', timeDistance
+                        pointDistance = timeDistance / archive.secondsPerPoint
+                        #console.log 'pointDistance', pointDistance
+                        byteDistance = pointDistance * pointSize
+                        #console.log 'byteDistance', byteDistance
+                        a = archive.offset + byteDistance.mod(archive.size)
+                        #console.log 'archive.offset', archive.offset
+                        #console.log 'archive.size', archive.size
+                        #console.log 'modulo', byteDistance.mod(archive.size)
+                        a
+
+                    fromOffset = getOffset(fromInterval)
+                    toOffset = getOffset(toInterval)
+
+                    #console.log 'fromOffset', fromOffset
+                    #console.log 'toOffset', toOffset
+
+
+                    fs.open path, 'r', (err, fd) ->
+                        if err then throw err
+                        if fromOffset < toOffset
+                            #console.log 'NO WRAP'
+                            # We don't wrap around, can everything in a single read
+                            size = toOffset - fromOffset
+                            seriesBuffer = new Buffer(size)
+                            fs.read fd, seriesBuffer, 0, size, fromOffset, (err, num) ->
+                                cb(err) if err
+                                fs.close fd, (err) ->
+                                    cb(err) if err
+                                    unpack(seriesBuffer) # We have read it, go unpack!
+                        else
+                            # We wrap around the archive, we need two reads
+                            archiveEnd = archive.offset + archive.size
+                            size1 = archiveEnd - fromOffset
+                            size2 = toOffset - archive.offset
+                            seriesBuffer = new Buffer(size1 + size2)
+                            fs.read fd, seriesBuffer, 0, size1, fromOffset, (err, num) ->
+                                cb(err) if err
+                                fs.read fd, seriesBuffer, size1, size2, archive.offset, (err, num) ->
+                                    cb(err) if err
+                                    unpack(seriesBuffer) # We have read it, go unpack!
+                                    fs.close(fd)
+
+        unpack = (seriesData) ->
+            #console.log 'SERIES DATA', seriesData
+
+            #console.log((f for f in seriesData).join(","))
+            # Optmize this?
+            numPoints = seriesData.length / POINT_SIZE
+            #console.log 'SERIES LEN', numPoints
+            seriesFormat = "!" + ('Ld' for f in [0...numPoints]).join("")
+            #console.log 'SERIES FORMAT', seriesFormat
+            unpackedSeries = pack.Unpack(seriesFormat, seriesData)
+            #console.log 'SERIES UNPACKED', unpackedSeries
+
+            # Use buffer/pre-allocate?
+            valueList = (null for f in [0...numPoints])
+            currentInterval = fromInterval
+            step = archive.secondsPerPoint
+
+            for i in [0...unpackedSeries.length] by 2
+                pointTime = unpackedSeries[i]
+                if pointTime == currentInterval
+                    pointValue = unpackedSeries[i + 1]
+                    valueList[i / 2] = pointValue
+                currentInterval += step
+
+            timeInfo = [fromInterval, toInterval, step]
+            cb(null, timeInfo, valueList)
+    return
+
+exports.create = create
+exports.update = update
+exports.updateMany = updateMany
+exports.info = info
+exports.fetch = fetch


Update index.coffee

Update index.coffee

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/DsXack/nodedotenv.git/'


use user storage info to select the default lang

--- app/coffee/app.coffee
+++ app/coffee/app.coffee
@@ -232,7 +232,11 @@

     $compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false)

-    preferedLangCode = window.taigaConfig.defaultLanguage || "en"
+    if localStorage.userInfo
+        userInfo = JSON.parse(localStorage.userInfo)
+
+    preferedLangCode = userInfo?.lang || window.taigaConfig.defaultLanguage || "en"
+
     $translateProvider
         .useStaticFilesLoader({
             prefix: "/locales/locale-",


servers: rename card to source for customer creation

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- servers/lib/server/handlers/createteam.coffee
+++ servers/lib/server/handlers/createteam.coffee
@@ -234,7 +234,7 @@
       (fin) ->
         params = { sessionToken: client.sessionToken }
         params.coupon = coupon  if coupon
-        params.card = { token: stripeToken, default: true }  if stripeToken
+        params.source = { token: stripeToken, default: true }  if stripeToken
         createPaymentPlan params, (err) ->
           console.error 'Err while creating payment plan', err  if err
           fin()


add Promise.mapSeries

add Promise.mapSeries

error: pathspec 'coffee/Promise.coffee' did not match any file(s) known to git

--- coffee/Promise.coffee
+++ coffee/Promise.coffee
@@ -0,0 +1,18 @@
+_.extend Promise,
+  mapSeries = (array, mapper) ->
+    [first, next...] = array
+    if not first?
+      return null
+    if first instanceof Promise
+      first
+        .then (firstValue) ->
+          ret.push firstValue
+        .catch Promise.reject
+    else
+      ret.push mapper first
+    if next?
+      Promise.mapSeries.apply next, mapper
+        .then (nextValue) ->
+          ret.concat nextValue
+    else
+      Promise.resolve ret


[atom] initial config.cson commit

[atom] initial config.cson commit

error: pathspec '.atom/config.cson' did not match any file(s) known to git

--- .atom/config.cson
+++ .atom/config.cson
@@ -0,0 +1,8 @@
+"*":
+  "exception-reporting":
+    userId: "1f590c8c-b4c8-6163-1c46-64df5999717e"
+  "tree-view":
+    hideVcsIgnoredFiles: true
+    squashDirectoryNames: true
+  welcome:
+    showOnStartup: false


Client: Activity: Test: Added CommentInputWidget view tests


use generateClassName for combining styles


ignore first slash when constructing id from link url

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/leonidas/qa-reports.git/'


ubersicht: fade in/out vox

ubersicht: fade in/out vox

error: pathspec 'osx/Library/Application' did not match any file(s) known to git
error: pathspec 'Support/Übersicht/widgets/vox.widget/vox.coffee' did not match any file(s) known to git


fix: remove console.log

fix: remove console.log

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/keboola/kbc-ui-manage-apps.git/'


monitoring bbdb less frequently

monitoring bbdb less frequently

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bubblegroup/bubblebot.git/'


Removing unused file

Removing unused file

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/opentable/grunt-loadstats.git/'


[Group Notifications] deleted unused file


Tests: Added gulpfile.

Tests: Added gulpfile.

error: pathspec 'tests/gulpfile.coffee' did not match any file(s) known to git

--- tests/gulpfile.coffee
+++ tests/gulpfile.coffee
@@ -0,0 +1,8 @@
+gulp   = require 'gulp'
+coffee = require 'gulp-coffee'
+
+
+gulp.task 'default', ->
+  gulp.src './src/**/*.coffee'
+  .pipe coffee()
+  .pipe gulp.dest './output/'


Fixed the bug of calendar doesn't display properly on click first. (#2495)

* Fixed the bug of calendar doesn't display properly on click first.

* Fixed extra lines of code.

* Fixed the bug of snapshot info for null value.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-dashboard.git/'


variables name changed

variables name changed


Fix threads expanding when they shouldn't

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/grantovich/CSH-WebNews.git/'


Added .react.js extension

Added .react.js extension

Since its another popular extension for JSX files.

/bin/sh: 1: Syntax error: "(" unexpected


allow recursive function argument compilation

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/andykent/river.git/'


activity: disable topic follow test

activity: disable topic follow test


commit

commit

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Romaboy/awesomeadmin.git/'


commit

commit


shared.js.coffee added

shared.js.coffee added


Add example purely for output demonstration

error: pathspec 'quests/outputexample/outputexample.coffee' did not match any file(s) known to git

--- quests/outputexample/outputexample.coffee
+++ quests/outputexample/outputexample.coffee
@@ -0,0 +1,29 @@
+Quest = require '../../src/quest'
+
+module.exports =
+class OutputExampleQuest extends Quest
+  adventure: ->
+
+    console.log "So, what's a person like?".bold
+
+    @sql """
+         CREATE TEMP TABLE people (
+           name varchar(256),
+           birthdate date,
+           title varchar(256)
+         );
+         """
+
+    console.log "It's like that.".italic.gray
+
+    console.log "What are these creatures?".bold
+
+    res = @sql """INSERT INTO people
+                    VALUES
+                      ('Anthony', '02-02-1994', 'Brother of Matthew'),
+                      ('Daniel', '07-08-1993', 'Son of Doug'),
+                      ('Scott', '11-19-1992', 'Son of Kim');"""
+
+    console.log "They're us. They're all of us.".italic.gray
+
+    @table @sql "SELECT * from people;"


Add disabled auth tests, until I figure out a testing strategy.

error: pathspec 'test/auth.coffee' did not match any file(s) known to git

--- test/auth.coffee
+++ test/auth.coffee
@@ -0,0 +1,60 @@
+describe.skip 'Authentication', ->
+    afterEach(common.stop)
+
+    it 'Authorized clients can connect', (done) ->
+        calls = 0
+        options =
+            canConnect: (data, cb) ->
+                calls++
+                cb(null, true)
+        common.startServer options, (err) ->
+            return done(err) if err
+            common.createClient (err) =>
+                return done(err) if err
+                assert.equal(calls, 1)
+                done()
+
+    it 'Unauthorized clients cannot connect', (done) ->
+        calls = 0
+        options =
+            canConnect: (data, cb) ->
+                calls++
+                cb(null, false)
+        common.startServer options, (err) ->
+            return done(err) if err
+            common.createClient (err, client) =>
+                return done(err) if err
+                client.on 'error', (err) =>
+                    assert.equal(calls, 1)
+                    assert.equal(err, 'handshake unauthorized')
+                    done()
+
+    it 'Server can authenticate channels', (done) ->
+        calls = 0
+        options =
+            canSubscribe: (data, channel, cb) ->
+                calls++
+                cb(null, true)
+        common.startServer options, (err) ->
+            return done(err) if err
+            common.createClient (err, client) =>
+                return done(err) if err
+                client.subscribe 'test', (err) ->
+                    return done(err) if err
+                    assert.equal(calls, 2) # Two: Also for the test channel
+                    done()
+
+    it 'Server can refuse channel subscriptions', (done) ->
+        calls = 0
+        options =
+            canSubscribe: (data, channel, cb) ->
+                calls++
+                cb(null, false)
+        common.startServer options, (err) ->
+            return done(err) if err
+            common.createClient (err, client) =>
+                return done(err) if err
+                client.subscribe 'test', (err) ->
+                    assert.equal(calls, 2) # Two: Also for the test channel
+                    assert.equal('subscription refused', err)
+                    done()


test: Add targetParser unit test

test: Add targetParser unit test

error: pathspec 'test/unit.coffee' did not match any file(s) known to git

--- test/unit.coffee
+++ test/unit.coffee
@@ -0,0 +1,14 @@
+expect = require 'expect.js'
+{ targetParser, server } = require '../lib'
+
+
+describe 'targetParser', ->
+
+  it 'should return host and port', ->
+    expect(targetParser 'localhost:8080').to.eql {
+      host: 'localhost'
+      port: 8080
+    }
+
+  it 'should default to port 80', ->
+    expect(targetParser('').port).to.equal 80


[bot] [fix] ignore messages from yourself

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Mikuia/Mikuia.git/'


Adding a fake clock implementation

Adding a fake clock implementation

error: pathspec 'code/models/FakeClock.coffee' did not match any file(s) known to git

--- code/models/FakeClock.coffee
+++ code/models/FakeClock.coffee
@@ -0,0 +1,30 @@
+module.exports = class
+  constructor: ()->
+    @total = 0
+    @ranges = []
+
+  ###
+  Adds a period of time which this clock will loop over
+  ###
+  add: (start, end)->
+    diff = end.getTime() - start.getTime()
+    @ranges.push start: start.getTime(), length: diff
+    @total += diff
+
+  ###
+  Return a time which exists in one of the periods set with:
+    .add(start, end)
+  Which is derived from the current real time
+  ###
+  getTime: ->
+    offset = @getRealTime() % @total
+    for range in @ranges
+      withinRange = offset < range.length
+      return new Date(range.start + offset) if withinRange
+      offset -= range.length
+
+  ###
+  Return the current time in milliseconds since 1970. In a production
+  environment, this function should return a value with increments over time.
+  ###
+  getRealTime: -> new Date().getTime()


add resethandlerhelper.coffee file

add resethandlerhelper.coffee file

error: pathspec 'servers/testhelper/resethandlerhelper.coffee' did not match any file(s) known to git

--- servers/testhelper/resethandlerhelper.coffee
+++ servers/testhelper/resethandlerhelper.coffee
@@ -0,0 +1,43 @@
+querystring = require 'querystring'
+
+{ generateUrl
+  deepObjectExtend
+  generateRandomString
+  generateDefaultRequestParams } = require './index'
+
+
+generateResetRequestBody = (opts = {}) ->
+
+  defaultBodyObject =
+    password      : generateRandomString()
+    recoveryToken : generateRandomString()
+
+  deepObjectExtend defaultBodyObject, opts
+
+  return defaultBodyObject
+
+
+generateResetRequestParams = (opts = {}) ->
+
+  token = opts?.body?.email or 'someToken'
+
+  url  = generateUrl
+    route : "#{encodeURIComponent token}/Reset"
+
+  body = generateResetRequestBody()
+
+  params               = { url, body }
+  defaultRequestParams = generateDefaultRequestParams params
+  requestParams        = deepObjectExtend defaultRequestParams, opts
+  # after deep extending object, encodes body param to a query string
+  requestParams.body   = querystring.stringify requestParams.body
+
+  return requestParams
+
+
+module.exports = {
+  generateResetRequestBody
+  generateResetRequestParams
+}
+
+


fix HTML display of math (it wasn't queueing mathjax)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bmedx/modulestore.git/'


Environment: SceneView: No need to updateScene while connecting internal nodes, don't forget to reset connections before updating existings

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/andrewjcasal/koding.git/'


squash to template.getId

squash to template.getId

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/sidebar/components/ownedresourceslist.coffee
+++ client/app/lib/sidebar/components/ownedresourceslist.coffee
@@ -98,19 +98,19 @@
         linkController.openOrFocus originalUrl

       when 'Make Team Default'
-        computeController.fetchStackTemplate templateId, (err, template) =>
+        computeController.fetchStackTemplate template.getId(), (err, template) =>
           return @onMenuItemClickError 'making team default'  if err
           if template
             computeController.makeTeamDefault template

       when 'Share With Team'
-        computeController.fetchStackTemplate templateId, (err, template) =>
+        computeController.fetchStackTemplate template.getId(), (err, template) =>
           return @onMenuItemClickError 'sharing'  if err
           if template
             computeController.setStackTemplateAccessLevel template, 'group'

       when 'Make Private'
-        computeController.fetchStackTemplate templateId, (err, template) =>
+        computeController.fetchStackTemplate template.getId(), (err, template) =>
           return @onMenuItemClickError 'cloning'  if err
           if template
             computeController.setStackTemplateAccessLevel template, 'private'


Workspace: Code clean up. Removed commented codes.


make monitoring less sensitive

make monitoring less sensitive


cleanup

cleanup

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/civilframe/resistance.git/'


Check in the implementation of the remoting foundation

error: pathspec 'library/membrane/remote.coffee' did not match any file(s) known to git

--- library/membrane/remote.coffee
+++ library/membrane/remote.coffee
@@ -0,0 +1,78 @@
+###
+Copyright (c) 2013, Alexander Cherniuk <ts33kr@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+###
+
+_ = require "lodash"
+{EOL} = require "os"
+
+asciify = require "asciify"
+connect = require "connect"
+logger = require "winston"
+events = require "events"
+assert = require "assert"
+colors = require "colors"
+nconf = require "nconf"
+https = require "https"
+http = require "http"
+util = require "util"
+
+# An internal method that will be bolted on the remote objects.
+# Knows how to compile the citizens to be transferred onto the
+# foreign environments under the specified or inherited symbol.
+# Please refer to the implementation for greater understanding!
+# The method knows how to recursively compile class hierarchies.
+compiler = module.exports.compiler = (symbol) ->
+    noSymbol = "symbol must be non empty"
+    @symbol = symbol unless _.isEmpty symbol
+    assert not _.isEmpty(@symbol), noSymbol
+    f = => "var #{@symbol} = (#{@source})()"
+    return d() unless _.isObject @compiled
+    hierarchy = try @compiled.hierarchy?()
+    assert _.isArray(hierarchy), "no hierarchy"
+    hasRemote = (x) ->_.isObject x.remote
+    compilation = (x) -> x.remote.compile()
+    areRemote = _.filter hierarchy, hasRemote
+    compiled = _.map areRemote, compilation
+    bases = compiled.reverse().join EOL + EOL
+    return "#{bases}#{EOL + EOL}#{f()}"
+
+# A decorator style of routine that is used to capture the
+# source code of classes, functions and other first class
+# citizens for later transportation on the other environment.
+# Typically this would be the browser JS engine environment.
+# Call it with an empty function argument wrapping target.
+remote = module.exports.remote = (wrapper) ->
+    noWrapper = "wrapper must be a function"
+    invalidArgs = "wrapper cannot have arguments"
+    assert _.isFunction wrapper, noWrapper
+    assert wrapper.length is 0, invalidArgs
+    try compiled = wrapper() catch error
+        msg = "compilation failed: #{error.message}"
+        error.message = msg; throw error
+    compiled.remote = Object.create {}
+    compiled.remote.compiled = compiled
+    compiled.remote.symbol = compiled.name
+    compiled.remote.source = wrapper.toString()
+    compiled.remote.compile = compiler
+    return compiled


Add my keymaps

Add my keymaps

error: pathspec '.atom/keymap.cson' did not match any file(s) known to git

--- .atom/keymap.cson
+++ .atom/keymap.cson
@@ -0,0 +1,9 @@
+'atom-text-editor:not([mini])':
+  'alt-y':'clipboard-plus:toggle'
+  'ctrl-a': 'editor:move-to-beginning-of-line'
+  'ctrl-x ctrl-x': 'mark:swap'
+  'alt-a': 'editor:move-to-beginning-of-previous-paragraph'
+  'alt-e': 'editor:move-to-beginning-of-next-paragraph'
+  'ctrl-shift-o': 'file-explorer:toggle-home-directory'
+  'ctrl-d': 'find-and-replace:select-next'
+  'ctrl-k': 'editor:delete-line'


fix auth

fix auth

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/stevelacy/rialtoir-server.git/'


Tests: Parallel-sets: Enabled messages privatemessage suite.

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -35,7 +35,7 @@
   ]

   [
-    # 'messages privatemessage'
+    'messages privatemessage'
     'account accountsettings'
     'activity postwith'
   ]


Removed Request view caching

Removed Request view caching

--- SingularityUI/app/lib/router.coffee
+++ SingularityUI/app/lib/router.coffee
@@ -108,14 +108,10 @@
         app.show app.views.current

     request: (requestId) ->
-        app.views.requestViews = {} if not app.views.requestViews
-        if not app.views.requestViews[requestId]
-            app.views.requestViews[requestId] = new RequestView requestId: requestId
-            app.views.current = app.views.requestViews[requestId]
-            app.show app.views.requestViews[requestId].render().refresh()
-        else
-            app.views.current = app.views.requestViews[requestId]
-            app.show app.views.requestViews[requestId].refresh()
+        app.views.current = new RequestView requestId: requestId
+        app.views.current.refresh()
+        app.views.current.render()
+        app.show app.views.current

     requestHistoricalTasks: (requestId) ->
         app.views.requestHistoricalTasksViews = {} if not app.views.requestHistoricalTasksViews


remove hounds and code-climate errors

remove hounds and code-climate errors

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-dashboard.git/'


First cut at a chat channel.

First cut at a chat channel.

error: pathspec 'lib/chat_channel.coffee' did not match any file(s) known to git

--- lib/chat_channel.coffee
+++ lib/chat_channel.coffee
@@ -0,0 +1,14 @@
+builder = require('xmlbuilder')
+
+class ChatChannel
+  constructor: (@reflector) ->
+
+  sendMessage: (player, message) ->
+    xml = builder.create('root')
+      .ele('chat', { from : player.name, message : message })
+      .toString({ pretty: false })
+
+    console.log(xml)
+
+    @reflector.sendAll "<chat from='#{player.name}'>"
+    @reflector.scene.dispatchEvent 'chat', { player : player, message : message }