Special behaviour of reading $2002 during vblank.

--- emulator/core/units/ppu.coffee
+++ emulator/core/units/ppu.coffee
@@ -45,10 +45,11 @@
         @tempXScroll = 0    #  3-bit

     resetVariables: ->
-        @scanline = -1         # Total 262 scanlines (0..261)
-        @cycle = 0             # Total 341 cycles per scanline (0..340)
-        @renderedSprite = null # Currently rendered sprite
-        @delayedNMI = false    # Generate NMI after next instruction when its enabled (from 0 to 1) during VBLANK
+        @scanline = -1          # Total 262 scanlines (0..261)
+        @cycle = 0              # Total 341 cycles per scanline (0..340)
+        @renderedSprite = null  # Currently rendered sprite
+        @delayedNMI = false     # Whether to generate NMI after next instruction
+        @suppressVBlank = false # Whether to supress VBLANK flag setting and NMI generation during VBLANK

     setNTSCMode: (ntscMode) ->
         @ntscMode = ntscMode
@@ -90,7 +91,7 @@
         nmiEnabledOld = @nmiEnabled
         @setControl value
         @tempAddress = (@tempAddress & 0xF3FF) | (value & 0x03) << 10 # T[11,10] = C[1,0]
-        @delayedNMI = true if @vblankStarted and not nmiEnabledOld and @nmiEnabled # Generate NMI after next instruction when its enabled (from 0 to 1) during VBLANK
+        @delayedNMI = true if @vblankFlag and not nmiEnabledOld and @nmiEnabled # Generate NMI after next instruction when its enabled (from 0 to 1) during VBLANK
         value

     setControl: (value) ->
@@ -123,21 +124,24 @@

     readStatus: ->
         value = @getStatus()
-        @vblankStarted = 0
-        @writeToogle = 0
+        @vblankFlag = 0     # Cleared by reading status
+        @writeToogle = 0    # Cleared by reading status
+        if @scanline is 241
+            @suppressVBlank = true if @cycle is 1                   # Reading just before VBLANK disables NMI generation and VBLANK flag setting
+            @cpu.clearInterrupt Interrupt.NMI if @cycle in [ 2, 3 ] # Reading at the start of VBLANK disables only NMI generation
         value

     getStatus: ->
         @vramWritesIgnored     << 4 | # S[4]
         @spriteScalineOverflow << 5 | # S[5]
         @spriteZeroHit         << 6 | # S[6]
-        @vblankStarted         << 7   # S[7]
+        @vblankFlag            << 7   # S[7]

     setStatus: (value) ->
         @vramWritesIgnored     = (value >>> 4) & 1 # S[4]
         @spriteScalineOverflow = (value >>> 5) & 1 # S[5]
         @spriteZeroHit         = (value >>> 6) & 1 # S[6]
-        @vblankStarted         = (value >>> 7)     # S[7]
+        @vblankFlag            = (value >>> 7)     # S[7]

     ###########################################################
     # Object attribute memory access
@@ -363,15 +367,17 @@
                 @leaveVBlank()

     enterVBlank: ->
-        @vblankStarted = 1
+        unless @suppressVBlank
+            @vblankFlag = 1
+            @cpu.activateInterrupt Interrupt.NMI if @nmiEnabled
         @vblankActive = 1
         @frameAvailable = true
-        @cpu.activateInterrupt Interrupt.NMI if @nmiEnabled

     leaveVBlank: ->
-        @vblankStarted = 0
+        @vblankFlag = 0
         @vblankActive = 0
         @spriteZeroHit = 0
+        @suppressVBlank = false

     generateDelayedNMI: ->
         @cpu.activateInterrupt Interrupt.NMI


Added use strict and removed parentheses in Gulpfile

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -1,7 +1,9 @@
+'use strict'
+
 gulp  = require 'gulp'
 mocha = require 'gulp-mocha'

-gulp.task 'test', () ->
+gulp.task 'test', ->
   gulp.src 'specs/*'
     .pipe mocha
       reporter: 'spec'


テンプレートがwatch対象になっていなかった点を修正

テンプレートがwatch対象になっていなかった点を修正

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -20,7 +20,7 @@
 gulp.task 'watch',['build'],->
   gulp.watch './assets/**/*.*',['build-assets']
   gulp.watch './src/ts/**/*.ts',['build-typescript']
-  gulp.watch './src/tpl/*.hbs',['build-templates']
+  gulp.watch './src/tpl/**/*.hbs',['build-templates']

 # sub task
 gulp.task 'build-assets',->


Update test suite outline

Update test suite outline

--- test/suite.coffee
+++ test/suite.coffee
@@ -4,12 +4,15 @@
 hash = require('crypto').createHash
 rand = require('crypto').pseudoRandomBytes

+S3 = require('aws-sdk').S3
+
 client = null
+cleanup = []

 beforeEach ->
   client = new Upload 'turadmin',
+    awsBucketPath: 'images_test/'
     awsBucketUrl: 'https://s3-eu-west-1.amazonaws.com/turadmin/'
-    awsBucketPath: 'images_test/'
     awsBucketAcl: 'public-read'
     versions: [{
       original: true
@@ -37,10 +40,95 @@
     client.s3.putObject = (opts, cb) ->
       process.nextTick -> cb null, ETag: hash('md5').update(rand(32)).digest('hex')

+# Clean up S3 objects
+if process.env.INTEGRATION_TEST is 'true'
+  afterEach (done) ->
+    return process.nextTick done if cleanup.length is 0
+
+    client.s3.deleteObjects Delete: Objects: cleanup, (err) ->
+      throw err if err
+      cleanup = []
+      done()
+
 describe 'Upload', ->
-  @timeout 20000
-  describe '#upload()', ->
+  describe 'constructor', ->
+    it 'should set default values if not provided', ->
+      client = new Upload 'myBucket'
+
+      assert client.s3 instanceof S3
+      assert client.versions instanceof Array
+      assert.equal client.awsBucketPath, ''
+      assert.equal client.awsBucketUrl, undefined
+      assert.equal client.awsBucketAcl, 'privat'
+      assert.equal client.resizeQuality, 70
+      assert.equal client.keepOriginal, true
+      assert.equal client.returnExif, false
+      assert.equal client.tmpDir, '/tmp/'
+      assert.equal client.tmpPrefix, 'gm-'
+
+    it 'should override default values'
+
+  describe '#_getRandomPath()', ->
+    it 'should return a new random path'
+
+  describe '#_uploadPathIsAvailable()', ->
+    it 'should return true for avaiable path'
+    it 'should return false for unavaiable path'
+
+  describe '#__uploadGeneratePath()', ->
+    it 'should return an avaiable path'
+
+  describe.skip '#upload()', ->
+    describe 'Image', ->
+      image = null
+
+      beforeEach ->
+        src = __dirname + 'test/assets/photo.jpg'
+        dest = 'images_test/Wm/PH/f3/I0'
+        opts = {}
+
+        image = new Upload.Image src, dest, opts, client
+
+      describe 'constructor', ->
+        it 'should set default values'
+
+      describe '#getMeta()', ->
+        it 'should store image matadata'
+        it 'should store gm image instance'
+        it 'should return image metadata'
+        it 'should return exif data if returnExif is set to true'
+
+      describe '#resize()', ->
+        it 'should return updated properties for original image'
+        it 'should return updated properties for resized image'
+        it 'should write resized image to temp destination'
+        it 'should set hegith and width for reszied image'
+        it 'should set corret orientation for resized image'
+        it 'should set colorspace to RGB for resized image'
+        it 'should set quality for resized image'
+
+      describe '#upload()', ->
+        it 'should not upload original image if keepOriginal is set to false'
+        it 'should set object Key to correct location on AWS S3'
+        it 'should set ojbect ACL to specified ACL'
+        it 'should set object ACL to default if not specified'
+        it 'should set object Body to version src file'
+        it 'should set object ContentType according to version type'
+        it 'should set object Metadata from default metadata'
+        it 'should set object Metadata from upload metadata'
+        it 'should return updated version object on successfull upload'
+
+      describe '#resizeAndUpload()', ->
+        it 'should set version suffix if not provided'
+        it 'should resize and upload according to image version'
+
+      describe '#exec()', ->
+        it 'should get source image metadata'
+        it 'should make a copy of master version objects array'
+        it 'should resize and upload original image accroding to versions'
+
     it 'should upload', (done) ->
+      @timeout 20000
       client.upload 'test/assets/photo.tiff', {}, (err, versions, meta) ->
         assert.ifError err
         console.log versions


Adds destructive methods to expressino components

--- javascripts/lib/math/expression_components.coffee
+++ javascripts/lib/math/expression_components.coffee
@@ -78,6 +78,10 @@
     expr.push new_last
     @clone(expression: expr)

+  # @destructive
+  appendD: (new_last)->
+    @expression.push new_last
+
   replaceLast: (new_last)->
     @withoutLast().append(new_last)

@@ -140,6 +144,13 @@
         "#{@val}#{number}"
     Number.build(value: new_val)

+  # @destructive
+  concatenateD: (number)->
+    if @future_as_decimal
+      @val = "#{@val}.#{number}"
+    else
+      @val = "#{@val}#{number}"
+
   futureAsDecimal: ->
     future_as_decimal = !@hasDecimal()
     @clone(future_as_decimal: future_as_decimal)
@@ -151,6 +162,7 @@

 class Exponentiation extends ExpressionComponent
   initialize: (opts={})->
+    super
     @baseval = opts.base
     @powerval = opts.power
   isOperator: -> true


Fixed unwrapping instead of removing

Fixed unwrapping instead of removing

--- js-library/app/js/jail_iframe/classes/fact.coffee
+++ js-library/app/js/jail_iframe/classes/fact.coffee
@@ -118,7 +118,6 @@

   destroy: ->
     for el in @elements
-      $el = $(el)
-      $el.remove()
+      $(el).contents().unwrap()

     @fact_interaction.destroy()


:art: compact cursor position check utility methods, and fix was at on wrong place

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -136,6 +136,28 @@
     _.times @getCount(@defaultCount), ->
       fn()

+  isAt: (cursor, where) ->
+    switch where
+      when 'BoL' then cursor.isAtBeginningOfLine()
+      when 'EoL' then cursor.isAtEndOfLine()
+      when 'EoF' then cursor.getEofBufferPosition().isEqual(@editor.getEofBufferPosition())
+      when 'BoF' then cursor.getEofBufferPosition().isEqual(Point.ZERO)
+
+  getLastScreenRow: ->
+    @editor.getLastScreenRow()
+
+  getLastBufferRow: ->
+    @editor.getLastBufferRow()
+
+  lineTextForBufferRow: (bufferRow) ->
+    @editor.lineTextForBufferRow(bufferRow)
+
+  bufferRangeForBufferRow: (bufferRow) ->
+    @editor.bufferRangeForBufferRow(bufferRow)
+
+  getEofBufferPosition: ->
+    @editor.getEofBufferPosition()
+
 class CurrentSelection extends Motion
   @extend()
   constructor: ->
@@ -170,37 +192,6 @@
       newEnd = start.traverse(lastSelectionExtent)
       selection.setBufferRange([start, newEnd])
     return
-
-  isAtBoL: (cursor) ->
-    cursor.isAtBeginningOfLine()
-
-  isAtEOL: (cursor) ->
-    cursor.isAtEndOfLine()
-
-  isAtEoF: (cursor) ->
-    point = cursor.getBufferPosition()
-    eof = cursor.getEofBufferPosition()
-    point.isEqual eof
-
-  isAtBoF: (cursor) ->
-    point = cursor.getBufferPosition()
-    bof = Point.ZERO
-    point.isEqual bof
-
-  getLastScreenRow: ->
-    @editor.getLastScreenRow()
-
-  getLastBufferRow: ->
-    @editor.getLastBufferRow()
-
-  lineTextForBufferRow: (bufferRow) ->
-    @editor.lineTextForBufferRow(bufferRow)
-
-  bufferRangeForBufferRow: (bufferRow) ->
-    @editor.bufferRangeForBufferRow(bufferRow)
-
-  getEofBufferPosition: ->
-    @editor.getEofBufferPosition()

 class MoveLeft extends Motion
   @extend()


Add additional assessment filter to teacher dashboard assessments tab (#142)

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -331,6 +331,7 @@
     @courseAssessmentPairs = []
     for course in @courses.models
       assessmentLevels = @classroom.getLevels({courseID: course.id, assessmentLevels: true}).models
+      assessmentLevels = _.filter(assessmentLevels, (l) => l.get('assessment') == true)
       fullLevels = _.filter(@levels.models, (l) => l.get('original') in _.map(assessmentLevels, (l2)=>l2.get('original')))
       @courseAssessmentPairs.push([course, fullLevels])
     return @courseAssessmentPairs


Work on number.coffee

Work on number.coffee

--- lib/number.coffee
+++ lib/number.coffee
@@ -1,4 +1,4 @@
-# A general number class, currently supporting integral Javascript numbers,
+# A generic number type, currently supporting integral Javascript numbers,
 # arbitrary precision integers and fractions.
 #
 # Arguments and results of arithmetic operations are coerced to the best
@@ -19,7 +19,7 @@

 # ----

-# If this source file was executed directly, some simple tests are performed.
+# If this source file is being executed directly, run in test mode.

 quicktest = module? and not module.parent
 log = if quicktest then (str) -> console.log str else (str) ->
@@ -39,13 +39,30 @@
 #
 # In production mode, the number `BASE` is computed as the largest power of 100
 # that fits into a Javascript number twice with full precision. The number
-# `HALFBASE` it its square root.
-
-[BASE, HALFBASE] = if quicktest then [10000, 100] else
+# `HALFBASE` it its square root. According to the Javascript specification, we
+# should expect `BASE == 10e14` and `HALFBASE == 10e7`.
+
+BASE_LENGTH = if quicktest then 4 else
   seq.from(1)
-    .map((n) -> [Math.pow(10, 2 * n), Math.pow(10, n)])
-    .takeWhile(([b,h]) -> 2 * b - 2 != 2 * b - 1 and -2 * b + 2 != -2 * b + 1)
+    .map((n) -> 2 * n)
+    .takeWhile((n) ->
+      b = Math.pow 10, n
+      2 * b - 2 != 2 * b - 1 and -2 * b + 2 != -2 * b + 1
+    )
     .last()
+
+BASE     = Math.pow 10, BASE_LENGTH
+HALFBASE = Math.sqrt BASE
+
+# ----
+
+# Internal helpers for constructing number representations.
+
+asNum = (n) ->
+  if Math.abs(n) < BASE then new CheckedInt n else LongInt.fromNative n
+
+digits = (m) ->
+  if m then seq.conj m % BASE, -> digits Math.floor(m / BASE) else null

 # ----

@@ -56,8 +73,6 @@
 class CheckedInt
   getval = (x) -> if x instanceof CheckedInt then x.val else x

-  yield  = (x) -> if Math.abs(x) < BASE then new CheckedInt x else new LongInt x
-
   constructor: (@val = 0) ->

   neg: -> new CheckedInt -@val
@@ -66,24 +81,24 @@

   sgn: -> if @val < 0 then -1 else if @val > 0 then 1 else 0

-  sqrt: -> new CheckedInt Math.sqrt(@val) >> 0
+  sqrt: -> new CheckedInt Math.floor Math.sqrt @val

   cmp: (other) ->
     x = getval other
     if @val < x then -1 else if @val > x then 1 else 0

-  plus: (other) -> yield @val + getval other
-
-  minus: (other) -> yield @val - getval other
+  plus: (other) -> asNum @val + getval other
+
+  minus: (other) -> asNum @val - getval other

   times: (other) ->
-    tmp = @val * getval other
-    if Math.abs(tmp) < BASE
-      new CheckedInt tmp
+    x = @val * getval other
+    if Math.abs(x) < BASE
+      new CheckedInt x
     else
-      new LongInt(@val).times other
-
-  div: (other) -> new CheckedInt (@val / getval other) >> 0
+      LongInt.fromNative(@val).times other
+
+  div: (other) -> new CheckedInt Math.floor @val / getval other

   mod: (other) -> new CheckedInt @val % getval other

@@ -100,14 +115,9 @@
 # Here are the beginnings of the `LongInt` class.

 class LongInt
-  make_digits = (m) ->
-    if m then seq.conj m % BASE, -> make_digits (m / BASE) >> 0 else null
-
-  constructur: (n = 0) ->
-    [m, @sign] = if n < 0 then [-n, -1] else [n, 1]
-    @digits = make_digits m
-
-  times: (other) ->
+  constructor: (@sign = 0, @digits = null) ->
+
+  times: (other) -> throw new Error "not yet implemented"

   zeroes = BASE.toString()[1..]

@@ -120,26 +130,91 @@
     else
       '0'

+  @fromNative: (n) ->
+    if n < 0
+      new LongInt -1, digits -n
+    else if n > 0
+      new LongInt 1, digits n
+    else
+      new LongInt 0, null
+
+# ----
+
+# The `number` function provides the public interface.
+
+number = (n = 0) ->
+  switch typeof n
+    when 'number'
+      number.fromNative n
+    when 'string'
+      number.parse n
+
+number.fromNative = (n) ->
+  throw new Error "expected an integer, got #{n}" unless n == Math.floor n
+  asNum n
+
+number.parse = (n) ->
+  unless /^[+-]?\d+$/.test n
+    throw new Error "expected an integer literal, got '#{n}'"
+
+  [s, m] = switch n[0]
+    when '-' then [-1, n[1..]]
+    when '+' then [ 1, n[1..]]
+    else          [ 1, n]
+
+  if m.length <= BASE_LENGTH
+    new CheckedInt parseInt n
+  else
+    parsed = (to) ->
+      if to > 0
+        from = Math.max 0, to - BASE_LENGTH
+        seq.conj parseInt(m[from...to]), -> parsed from
+      else
+        null
+
+    new LongInt s, parsed m.length
+
+
+# ----
+# Exporting.
+
+exports ?= this.pazy ?= {}
+exports.number = number
+
 # ----

 # Some quick tests.

 if quicktest
-  do ->
-    log "------"
-    a = 98
-    b = 21
-    log "gcd(#{a}, #{b}) = #{new CheckedInt(a).gcd b}"
-
-  do ->
-    log "------"
-    a = new CheckedInt Math.pow 2, 13
-    log "a        = #{a}"
-    log "a * 2    = #{a.times 2}"
-    log "a + 2    = #{a.plus 2}"
-    log "a + 2000 = #{a.plus 2000}"
-
-  do ->
-    log "------"
-    a = -123456789000000
-    log "a = #{a}"
+  blanks = "                                    "
+
+  show = (code) ->
+    s = code.toString().replace /^function\s*\(\)\s*{\s*return\s+(.*);\s*}/, "$1"
+    input = s + blanks[s.length..]
+
+    output =
+      try
+        res = code()
+        type = if res?.constructor? then res.constructor.name else typeof res
+        "#{type} #{res}"
+      catch ex
+        "-- #{ex} --"
+
+    log "#{input} -> #{output}"
+
+
+  a = b = c = 0
+
+  log ''
+  show -> number(98).gcd 21
+
+  log ''
+  show -> a = number Math.pow 2, 13
+  show -> a.plus 2
+  show -> a.times 2
+  show -> a.plus 2000
+
+  log ''
+  show -> number -123456789000000
+  show -> number '-1234'
+  show -> number '-123456789000000'


adds icon to notification

adds icon to notification

--- src/ui/views/notifications.coffee
+++ src/ui/views/notifications.coffee
@@ -55,7 +55,7 @@

         # maybe trigger OS notification
         return if !text or quietIf(c, chat_id)
-
+
         if viewstate.showPopUpNotifications
             notifier.notify
                 title: if viewstate.showUsernameInNotification
@@ -69,6 +69,7 @@
                 wait: true
                 sender: 'com.github.yakyak'
                 sound: true
+                icon: path.join __dirname, '..', '..', 'icons', 'icon@8.png'
             , (err, res) ->
               if res?.trim().match(/Activate/i)
                 action 'appfocus'


Re-evaluate on save config

Re-evaluate on save config

--- lib/index.coffee
+++ lib/index.coffee
@@ -33,7 +33,8 @@
         @view = new ConsoleRuntimeView(editorId: pathname.substring(1))
         @subscriptions.add @view.onDidDestroy => @blankRuntime.stop()
         @subscriptions.add @view.onDidSave (ev) =>
-          @runBlank()
+          if atom.config.get 'magic-console.evaluateOnSave'
+            @runBlank()
         @view
       else
         @view = new ConsoleRuntimeView(filePath: pathname)


Register deserializer via atom.deserializers

--- lib/index.coffee
+++ lib/index.coffee
@@ -21,7 +21,7 @@
   name: 'SettingsView'
   version: 1
   deserialize: (state) -> createSettingsView(state)
-registerDeserializer(deserializer)
+atom.deserializers.add(deserializer)

 module.exports =
   activate: ->


fix #258

fix #258

--- lib/input.coffee
+++ lib/input.coffee
@@ -59,7 +59,7 @@
     @finished = false
     if @options.hide?
       unless @mounted
-        @vimState.editorElement.parentElement.appendChild(this)
+        @vimState.editorElement.parentNode.parentNode.appendChild(this)
         @mounted = true
     else
       @panel ?= atom.workspace.addBottomPanel(item: this, visible: false)


Refacroring.

Refacroring.

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -150,6 +150,19 @@

     @cmd = cmd

+
+  makeLintInfo: (fileName, originFileName) =>
+    if not originFileName
+      originFileName = fileName
+    cmd = @cmd[0..]
+    cmd.push fileName
+    info =
+      fileName: originFileName
+      command: cmd[0]
+      args: cmd.slice 1
+      options: {cwd: path.dirname originFileName}
+
+
   lintFile: (lintInfo, callback) ->
     console.log 'lintFile'
     results = []
@@ -168,7 +181,7 @@
         messages.push {
           type: type or 'Warning'
           text: match.message
-          filePath: lintInfo.origFileName
+          filePath: lintInfo.fileName
           range: [
             [match.line - 1, 0]
             [match.line - 1, 0]
@@ -185,18 +198,15 @@
         detail: "#{error.message}"
         dismissable: true
       handle()
-      callback([])
+      callback []

   lintOnFly: (textEditor) =>
     console.log 'lintOnFly'
     return new Promise (resolve, reject) =>
-      results = []
-
-      file = do textEditor.getPath
       tmpOptions = {
         prefix: 'AtomLinter'
-        suffix: "_#{path.basename file}"
+        suffix: "_#{path.basename do textEditor.getPath}"
       }

       temp.open(tmpOptions, (err, info) =>
@@ -206,21 +216,7 @@
         fs.close(info.fd, (err) =>
           return reject(err) if err

-          curDir = path.dirname file
-          cmd = @cmd[0..]
-          console.log cmd
-          cmd.push info.path
-          command = cmd[0]
-          options = {cwd: curDir}
-          args = cmd.slice 1
-          console.log cmd
-
-          lintInfo =
-            command: command
-            args: args
-            options: options
-            curDir: curDir
-            origFileName: file
+          lintInfo = @makeLintInfo info.path, do textEditor.getPath
           @lintFile lintInfo, (results) ->
             fs.unlink(info.path)
             resolve(results)
@@ -231,25 +227,7 @@
   lintOnSave: (textEditor) =>
     console.log 'lintOnSave'
     return new Promise (resolve, reject) =>
-      results = []
-
-      file = do textEditor.getPath
-      curDir = path.dirname file
-      cmd = @cmd[0..]
-      cmd.push file
-      console.log cmd
-      command = cmd[0]
-      options = {cwd: curDir}
-      args = cmd.slice 1
-
-
-      lintInfo =
-        command: command
-        args: args
-        options: options
-        curDir: curDir
-        origFileName: file
-
+      lintInfo = @makeLintInfo do textEditor.getPath
       @lintFile lintInfo, (results) ->
         resolve(results)


Fix JSHint highlight position

Fix JSHint highlight position

Related to #11.

--- lib/linter/jshint.coffee
+++ lib/linter/jshint.coffee
@@ -24,7 +24,7 @@
     for violation in jsHintResults.checkstyle.file[0].error
       # JSHint only returns one point instead of a range, so we're going to set
       # both sides of the range to the same thing.
-      point = [violation.$.line, violation.$.column]
+      point = [violation.$.line - 1, violation.$.column - 1]
       violations.push
         severity: violation.$.severity
         message: violation.$.message


Fix features

Fix features

--- src/videojs.chromecastTech.coffee
+++ src/videojs.chromecastTech.coffee
@@ -9,12 +9,10 @@
     source.type is "video/mp4"

   constructor: (player, options, ready) ->
-    # Set the features that this Tech has
-    @features["volumeControl"] = true
-    @features["movingMediaElementInDOM"] = false
-    @features["fullscreenResize"] = false
-    @features["progressEvents"] = true
-    @features["timeupdateEvents"] = true
+    @["featuresVolumeControl"] = true
+    @["movingMediaElementInDOM"] = false
+    @["featuresFullscreenResize"] = false
+    @["featuresProgressEvents"] = true

     vjs.MediaTechController.call this, player, options, ready


Fix issue to preserve reference to mail storage array during delete all.

--- server.coffee
+++ server.coffee
@@ -49,7 +49,7 @@
     return false

 deleteAllMail = ->
-  mailStore = []
+  mailStore.length = 0
   return true


Fix config format

Fix config format

--- server.coffee
+++ server.coffee
@@ -46,7 +46,7 @@
 loadApp = (logger, loadedConfig) ->
   app = express()

-  APP_ROOT = process.env.APP_ROOT ? loadedConfig.server?.appRoot ? ''
+  APP_ROOT = process.env.APP_ROOT ? loadedConfig.get('server.appRoot').get() ? ''

   moduleGroups = {}
   loadModuleGroup = (group) ->
@@ -107,7 +107,7 @@
     app.get "#{ APP_ROOT }/v1/health-check", (req, res) ->
       res.send('OK\n')

-    port = process.env.PORT ? loadedConfig.server?.port ? 5000
+    port = process.env.PORT ? loadedConfig.get('server.port').get() ? 5000
     app.listen(port)

     logger.log('Server listening on port %d in %s mode', port, app.settings.env)


Made runner use requestAnimationFrame if found, otherwise fallback to setTimeout

--- lib/runner.coffee
+++ lib/runner.coffee
@@ -26,7 +26,6 @@

   settings:
     autostart: false
-    interval: 20
     countdown: false
     stopAt: null
     startAt: 0
@@ -75,18 +74,19 @@
       @running = true
       @reset() if not @startTime or @finished
       @lastTime = $.now()
-      @interval = setInterval(=>
-        @update()
+      step = =>
+        if @running
+          @update()
+          _requestAnimationFrame(step)
         return
-      , @settings.interval)

+      _requestAnimationFrame(step)
       @fire 'runnerStart'
     return

   stop: ->
     if @running
       @running = false
-      clearInterval @interval
       @update()
       @fire 'runnerStop'
     return


Updating documentation/var name for colons

Documentation and variable name incorrectly suggested that lines ending
with a colon could only come from the end of a function definition, when
in fact they can come from lots of control statements such as if, elif,
else, try, except, for, while, etc.

--- lib/python-indent.coffee
+++ lib/python-indent.coffee
@@ -29,7 +29,8 @@
     lastClosedRow = parseOutput.lastClosedRow
     # A stack containing the row number where each bracket was closed.
     shouldHang = parseOutput.shouldHang
-    lastFunctionRow = parseOutput.lastFunctionRow
+    # The last row a def/for/if/elif/else/try/except etc. block started
+    lastColonRow = parseOutput.lastColonRow

     if shouldHang
         @indentHanging(row, @editor.buffer.lineForRow(row - 1))
@@ -44,8 +45,9 @@
             # row where it was opened
             indentLevel = @editor.indentationForBufferRow(lastClosedRow[0])

-            if lastFunctionRow == row - 1
-                # we just finished defining a function, need to increase indentation
+            if lastColonRow == row - 1
+                # we just finished def/for/if/elif/else/try/except etc. block,
+                # need to increase indent level by 1.
                 indentLevel += 1

             @editor.setIndentationForBufferRow(row, indentLevel)
@@ -142,7 +144,7 @@
     # i.e., did this string start with ' or with "?
     stringDelimiter = []
     # this is the row of the last function definition
-    lastFunctionRow = NaN
+    lastColonRow = NaN

     # NOTE: this parsing will only be correct if the python code is well-formed
     #       statements like "[0, (1, 2])" might break the parsing
@@ -158,8 +160,8 @@
         # true if we should have a hanging indent, false otherwise
         shouldHang = false

-        # this is the last defined function row
-        lastLastFunctionRow = lastFunctionRow
+        # this is the last defined def/for/if/elif/else/try/except row
+        lastlastColonRow = lastColonRow

         for col in [0 .. line.length - 1] by 1
             c = line[col]
@@ -211,13 +213,13 @@

                     # Similar to above, we've already skipped all irrelevant characters,
                     # so if we saw a colon earlier in this line, then we would have
-                    # incorrectly thought it was the end of a function definition when
-                    # it was actually a dictionary being defined, reset the lastFunctionRow
-                    # variable to whatever it was when we started parsing this line.
-                    lastFunctionRow = lastLastFunctionRow
+                    # incorrectly thought it was the end of a def/for/if/elif/else/try/except
+                    # block when it was actually a dictionary being defined, reset the
+                    # lastColonRow variable to whatever it was when we started parsing this line.
+                    lastColonRow = lastlastColonRow

                     if c == ':'
-                        lastFunctionRow = row
+                        lastColonRow = row
                     else if c in '})]' and openBracketStack.length
                         # Note that the .pop() will take the element off of the openBracketStack
                         # as it adds it to the array for lastClosedRow.
@@ -230,7 +232,7 @@
         openBracketStack: openBracketStack
         lastClosedRow: lastClosedRow
         shouldHang: shouldHang
-        lastFunctionRow: lastFunctionRow
+        lastColonRow: lastColonRow

   indentHanging: (row, previousLine) ->
     # Indent at the current block level plus the setting amount (1 or 2)


pending for request.accept test

pending for request.accept test

--- test/unit/sky_helpers.coffee
+++ test/unit/sky_helpers.coffee
@@ -6,7 +6,7 @@
 Sky = require "../.."
 sky = Sky(AWS)

-describe "sky.method wrapper function", ({describe, test}) ->
+describe "sky.method", ({describe, test}) ->

   describe "Interface", ({test}) ->

@@ -50,3 +50,5 @@
           scheme: "GrossScheme"
           token: "thisisjustanatomictoken"

+    describe "request.accept"
+


context is already aliased by mocha-given (and mocha-gwt)

--- test/general-helper.coffee
+++ test/general-helper.coffee
@@ -1,5 +1,4 @@
 global.expect = chai.expect
-global.context = describe
 global.requireSubject = (path) ->
   return testdouble unless path?
   [lib, pathComponents...] = path.split('/')


Do not just run my test

Do not just run my test

--- test/yayson/presenter.coffee
+++ test/yayson/presenter.coffee
@@ -282,7 +282,7 @@
     expect(json.data.relationships.car.links.related).to.eq '/cars/3/car'
     expect(json.data.relationships.car.data).to.eq undefined

-  it.only 'should not include relationships with nothing in them', ->
+  it 'should not include relationships with nothing in them', ->
     class CarPresenter extends Presenter
       type: 'cars'


Improved workaround of selenium bug

Improved workaround of selenium bug

--- test/utils.coffee
+++ test/utils.coffee
@@ -9,9 +9,9 @@
   driver.wait( ->
     driver.findElement(id: 'popup-confirm')
   , 1000)
-  driver.executeScript "window.scrollTo(0, \
-    document.getElementById('popup-confirm').getBoundingClientRect().top);"
-  driver.findElement(id: 'popup-confirm').click()
+  driver.executeScript "setTimeout((function() {
+      document.getElementById('popup-confirm').click();
+    }), 250);"

 answer_question = (driver, all) ->
   driver.findElements(css: '.alternative')


Disable network retry

Disable network retry

--- lib/proxy.coffee
+++ lib/proxy.coffee
@@ -19,7 +19,7 @@
 {log, warn, error, resolveBody, isStaticResource, findHack, findHackExecPath, findCache, findCacheExecPath} = require './utils'

 # Network error retries
-retries = config.get 'poi.proxy.retries', 30
+retries = config.get 'poi.proxy.retries', 1

 resolve = (req) ->
   switch config.get 'proxy.use'


Monkey patch for ShimakazeGo

Monkey patch for ShimakazeGo

--- lib/proxy.coffee
+++ lib/proxy.coffee
@@ -134,6 +134,10 @@
                 self.emit 'network.error.retry', i + 1 if i < retries
               # Delay 3s for retry
               yield Promise.delay(3000) unless success
+          # Monkey Patch for Shimakaze GO
+          else if parsed.hostname in ['connect.facebook.net', 'pixel.rubiconproject.com'] and config.get('proxy.use') is 'http'
+            res.writeHead 200
+            res.end()
           else
             [response, body] = yield requestAsync resolve options
             res.writeHead response.statusCode, response.headers


restore `check backup` command

restore `check backup` command

--- lib/sync-settings.coffee
+++ lib/sync-settings.coffee
@@ -28,6 +28,9 @@
       atom.commands.add 'atom-workspace', "sync-settings:view-backup", =>
         @viewBackup()
         @tracker.track 'View backup'
+      atom.commands.add 'atom-workspace', "sync-settings:check-backup", =>
+        @checkForUpdate()
+        @tracker.track 'Check backup'

       @checkForUpdate() if atom.config.get('sync-settings.checkForUpdatedBackup')


add setCountryInput function

add setCountryInput function

--- vendor/assets/javascripts/form.authy.coffee
+++ vendor/assets/javascripts/form.authy.coffee
@@ -483,6 +483,11 @@
   @setCountryCode = (listId, countryCode) ->
     document.getElementById("country-code-" + listId).value = countryCode

+  @setCountryInput = (listId, countryCode) ->
+    filteredCountriesList = countriesList.filter (countryObj) ->
+      return countryObj.code == countryCode
+    document.getElementById("countries-input-" + listId).value = filteredCountriesList[0].country
+
   @setTooltip = (title, msg) ->
     tooltip = document.getElementById("authy-tooltip")
     return  unless tooltip


add quest plugin support

add quest plugin support

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -24,31 +24,43 @@
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
       ,
         name: '未接受'
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
       ,
         name: '未接受'
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
       ,
         name: '未接受'
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
       ,
         name: '未接受'
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
       ,
         name: '未接受'
         id: 100000
         content: '...'
         progress: ''
+        category: 0
+        type: 0
     ]
   handleResponse: (e) ->
     {method, path, body, postBody} = e.detail
@@ -76,6 +88,8 @@
               id: task.api_no
               content: task.api_detail
               progress: progress
+              category: task.api_category
+              type: task.api_type
           # Update current
           else
             tasks[idx] =
@@ -83,6 +97,8 @@
               id: task.api_no
               content: task.api_detail
               progress: progress
+              category: task.api_category
+              type: task.api_type
       # Finish quest
       when '/kcsapi/api_req_quest/clearitemget'
         idx = _.findIndex tasks, (e) ->
@@ -93,6 +109,8 @@
           id: 100000
           content: '...'
           progress: ''
+          category: 0
+          type: 0
       # Stop quest
       when '/kcsapi/api_req_quest/stop'
         idx = _.findIndex tasks, (e) ->
@@ -103,10 +121,18 @@
           id: 100000
           content: '...'
           progress: ''
+          category: 0
+          type: 0
     tasks = _.sortBy tasks, (e) ->
       e.id
     @setState
       tasks: tasks
+    event = new CustomEvent 'task.change',
+      bubbles: true
+      cancelable: true
+      detail:
+        tasks: tasks
+    window.dispatchEvent event
   refreshDay: ->
     curHours = (new Date()).getUTCHours()
     return if prevHours == curHours
@@ -119,14 +145,28 @@
           id: 100000
           content: '...'
           progress: ''
+          category: 0
+          type: 0
       @setState
         tasks: tasks
+      event = new CustomEvent 'task.change',
+        bubbles: true
+        cancelable: true
+        detail:
+          tasks: tasks
+      window.dispatchEvent event
     prevHours = curHours
+  handleTaskInfo: (e) ->
+    {tasks} = e.detail
+    @setState
+      tasks: tasks
   componentDidMount: ->
     window.addEventListener 'game.response', @handleResponse
+    window.addEventListener 'task.info', @handleTaskInfo
     interval = setInterval @refreshDay, 30000
   componentWillUnmount: ->
     window.removeEventListener 'game.response', @handleResponse
+    window.removeEventListener 'task.info', @handleTaskInfo
     clearInterval interval
   render: ->
     <Panel header="任务" bsStyle="success">


Clean daily task only

Clean daily task only

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -138,15 +138,27 @@
     return if prevHours == curHours
     # UTC 20:00 -> Beijing 4:00 -> Tokyo 5:00
     if prevHours <= 19 and curHours >= 20
-      tasks = []
-      for idx in [0..5]
-        tasks[idx] =
-          name: '未接受'
-          id: 100000
-          content: '...'
-          progress: ''
-          category: 0
-          type: 0
+      {tasks} = @state
+      for task, idx in tasks
+        continue if task.id == 100000
+        if task.type in [2, 4, 5]
+          tasks[idx] =
+            name: '未接受'
+            id: 100000
+            content: '...'
+            progress: ''
+            category: 0
+            type: 0
+        if task.type is 3 and (new Date()).getUTCDay() is 0
+          tasks[idx] =
+            name: '未接受'
+            id: 100000
+            content: '...'
+            progress: ''
+            category: 0
+            type: 0
+      tasks = _.sortBy tasks, (e) ->
+        e.id
       @setState
         tasks: tasks
       event = new CustomEvent 'task.change',


Refactoring worker script

Refactoring worker script

--- src/api/worker.coffee
+++ src/api/worker.coffee
@@ -7,51 +7,61 @@
 http = require 'http'
 TransactionModel = require("../model/transactions").Transaction

+
+#####################################################################################################
+# Worker Process - Register the worker - Start the worker - Consume 'jobs' awaiting to be processed #
+#####################################################################################################
+
 worker = client.worker([ "transactions" ])
 worker.register rerun_transaction: (params, callback) ->
-  try
-    transactionID = params.transactionID;
-    taskID = params.taskID;
-
-    # Get the task object and update
-    # ensure transactionID is within task object
-    # pull and respond with transaction object
-    rerunGetTaskTransactionsData taskID, transactionID, (err, transaction) ->
+
+  transactionID = params.transactionID;
+  taskID = params.taskID;
+
+  # Get the task object and update
+  # ensure transactionID is within task object
+  # pull and respond with transaction object
+  rerunGetTaskTransactionsData taskID, transactionID, (err, transaction) ->
+
+    if err
+      logger.error(err)
+      return callback err, null
+
+    # setup the option object for the HTTP Request
+    rerunSetHTTPRequestOptions transaction, (err, options) ->

       if err
         logger.error(err)
         return callback err, null

-      # setup the option object for the HTTP Request
-      rerunSetHTTPRequestOptions transaction, (err, options) ->
+      #############################################################################
+      ### The job has processed correctly and is preparing to send HTTP Request ###
+      ### Move on to another job while this one waits for HTTPResponse to save  ###
+      ###     the result - "callback null, trasnactionID" completes the job     ###
+      #############################################################################
+      callback null, transactionID
+
+      # Run the HTTP Request with details supplied in options object
+      rerunHttpRequestSend options, transaction, (err, HTTPResponse) ->

         if err
           logger.error(err)
           return callback err, null
-
-        # Run the HTTP Request with details supplied in options object
-        rerunHttpRequestSend options, transaction, (err, HTTPResponse) ->
+
+        # Update the task object with the response details
+        rerunUpdateTaskObject taskID, transactionID, HTTPResponse, (err, updatedTask) ->

           if err
             logger.error(err)
             return callback err, null

-          # Update the task object with the response details
-          rerunUpdateTaskObject taskID, transactionID, HTTPResponse, (err, updatedTask) ->
-
-            if err
-              logger.error(err)
-              return callback err, null
-
-            # Return and process next job when rerun has completed
-            callback null, transactionID
-
-  catch err
-    callback err, null
-
 logger.info('Starting the workers')
 worker.start()

+#####################################################################################################
+# Worker Process - Register the worker - Start the worker - Consume 'jobs' awaiting to be processed #
+#####################################################################################################
+

 ###############################################################################
@@ -59,6 +69,7 @@
 ###############################################################################

 rerunGetTaskTransactionsData = (taskID, transactionID, callback) ->
+
   # find the tasks object for the transaction being processed
   TaskModel.findById taskID, (err, task) ->
     if err
@@ -201,6 +212,9 @@

 rerunUpdateTaskObject = (taskID, transactionID, response, callback) ->

+  console.log(JSON.parse(JSON.stringify(response)))
+
+
   # decrement the remainingTransactions property
   TaskModel.update
     _id: taskID
@@ -216,9 +230,6 @@
   TaskModel.findOne
     _id: taskID
   , (err, task) ->
-
-    if task.status == 'NotStarted'
-      task.status = 'Processing'

     task.transactions.forEach (tx) ->
       if tx.tid == transactionID
@@ -244,6 +255,9 @@
 ###############################################################

+#########################################################
+# Export these functions when in the "test" environment #
+#########################################################

 if process.env.NODE_ENV == "test"
   exports.rerunGetTaskTransactionsData = rerunGetTaskTransactionsData


load content around the focus, sequence, key or unread

--- vue/src/shared/loaders/thread_loader.coffee
+++ vue/src/shared/loaders/thread_loader.coffee
@@ -1,5 +1,5 @@
 import Records from '@/shared/services/records'
-import { isNumber, uniq, compact, orderBy, camelCase, forEach, isObject, sortedUniq, sortBy, without, map } from 'lodash'
+import { max, isNumber, uniq, compact, orderBy, camelCase, forEach, isObject, sortedUniq, sortBy, without, map } from 'lodash'
 import Vue from 'vue'
 import RangeSet         from '@/shared/services/range_set'
 import EventBus         from '@/shared/services/event_bus'
@@ -205,42 +205,43 @@
           discussionId: @discussion.id
           positionKey: {$jgte: positionKey}
         simplesort: 'positionKey'
-        limit: @padding
+        limit: parseInt(@padding/2)
       remote:
         discussion_id: @discussion.id
         position_key_gte: positionKey
         order_by: 'position_key'
-        per: @padding
-    #
-    # @rules.push
-    #   name: "positionKey rollback"
-    #   local:
-    #     find:
-    #       discussionId: @discussion.id
-    #       positionKey: {$lt: positionKey}
-    #     simplesort: 'positionKey'
-    #     simplesortDesc: true
-    #     limit: 1
-    #   remote:
-    #     discussion_id: @discussion.id
-    #     position_key_lt: positionKey
-    #     order_by: 'position_key'
-    #     order_desc: 1
-    #     per: 1
+        per: parseInt(@padding/2)
+
+    @rules.push
+      name: "positionKey rollback"
+      local:
+        find:
+          discussionId: @discussion.id
+          positionKey: {$lt: positionKey}
+        simplesort: 'positionKey'
+        simplesortDesc: true
+        limit: parseInt(@padding/2)
+      remote:
+        discussion_id: @discussion.id
+        position_key_lt: positionKey
+        order_by: 'position_key'
+        order_desc: 1
+        per: parseInt(@padding/2)

   addLoadSequenceIdRule: (sequenceId) ->
-    @loading = sequenceId
+    id = max([parseInt(sequenceId) - parseInt(@padding/2), 0])
+    @loading = id
     @titleKey = 'strand_nav.from_sequence_id'
     @rules.push
       name: "sequenceId from url"
       local:
         find:
           discussionId: @discussion.id
-          sequenceId: {'$jgte': parseInt(sequenceId)}
+          sequenceId: {'$jgte': id}
         simplesort: 'sequenceId'
         limit: @padding
       remote:
-        sequence_id_gte: sequenceId
+        sequence_id_gte: id
         discussion_id: @discussion.id
         order: 'sequence_id'
         per: @padding
@@ -256,9 +257,9 @@
         limit: @padding
       remote:
         discussion_id: @discussion.id
-        per: @padding
         order_by: 'sequence_id'
         order_desc: true
+        per: @padding

   addContextRule: ->
     @rules.push
@@ -279,6 +280,7 @@
       remote:
         discussion_id: @discussion.id
         order_by: 'sequence_id'
+        per: @padding

   addLoadUnreadRule: ->
     @titleKey = 'strand_nav.unread'
@@ -289,17 +291,35 @@
           find:
             id: @discussion.createdEvent().id

+    # I don't think we need this..
+    # @rules.push
+    #   name: {path: "strand_nav.new_to_you"}
+    #   local:
+    #     find:
+    #       discussionId: @discussion.id
+    #       sequenceId: {$or: @discussion.unreadRanges().map((r) -> {$between: r} )}
+    #     limit: @padding
+    #   remote:
+    #     discussion_id: @discussion.id
+    #     unread: true
+    #     order_by: "sequence_id"
+    #     per: @padding
+
+    # padding around new to you
+    id = max([@discussion.firstUnreadSequenceId() - parseInt(@padding/2), @discussion.firstSequenceId()])
     @rules.push
       name: {path: "strand_nav.new_to_you"}
       local:
         find:
           discussionId: @discussion.id
-          sequenceId: {$or: @discussion.unreadRanges().map((r) -> {$between: r} )}
-        limit: @padding
-      remote:
-        discussion_id: @discussion.id
-        unread: true
+          sequenceId: {$jgte: id}
+        limit: @padding
+        order: 'sequenceId'
+      remote:
+        discussion_id: @discussion.id
+        sequence_id_gte: id
         order_by: "sequence_id"
+        per: @padding

   addRule: (rule) ->
     @rules.push(rule)


Add missing arg

Add missing arg


operations: fix PushInbox notification

operations: fix PushInbox notification

op.notification is a function, so if it is set to an array then
"op.notification?()" will be null.

Fixes #48.

--- src/local/operations.coffee
+++ src/local/operations.coffee
@@ -1146,7 +1146,7 @@
             , cb2
         , (cb2) =>
             # Memorize updates for notifications, same format:
-            @notification = notification
+            @notification = -> notification
             if newNodes.length > 0
                 @newNodes = newNodes
             if newModerators.length > 0


operations: fix Notify subscriptios node items

--- src/local/operations.coffee
+++ src/local/operations.coffee
@@ -1098,7 +1098,7 @@
                                         node: subscription.node
                                     itemAttrs['pubsub:subscription'] ?= subscription.subscription
                                     itemAttrs['pubsub:affiliation'] ?= affiliations[subscription.node]
-                                    item.el.c('item', itemAttrs)
+                                    el.c('item', itemAttrs)

                                 cb4 null, { id, el }
                         , (err, items) =>


operations: Unsubscribed is not a PrivilegedOperation but a ModelOperation

--- src/local/operations.coffee
+++ src/local/operations.coffee
@@ -514,8 +514,8 @@

 ##
 # Not privileged as anybody should be able to unsubscribe him/herself
-class Unsubscribe extends PrivilegedOperation
-    privilegedTransaction: (t, cb) ->
+class Unsubscribe extends ModelOperation
+    transaction: (t, cb) ->
         if @req.node.indexOf("/user/#{@req.actor}/") == 0
             return cb new errors.Forbidden("You may not unsubscribe from your own nodes")


Moved to other config name.

Moved to other config name.

--- app/assets/javascripts/app/controllers/layout_ref.coffee
+++ app/assets/javascripts/app/controllers/layout_ref.coffee
@@ -1788,13 +1788,13 @@

     # read state
     if state is undefined
-      value = App.SessionStorage.get('chat')
+      value = App.SessionStorage.get('chat_layout_ref')
       if value is undefined
         value = false
       return value

     # write state
-    App.SessionStorage.set('chat', state)
+    App.SessionStorage.set('chat_layout_ref', state)

   updateNavMenu: =>
     delay = ->


avoid unnecessary assignment of bytes_array

--- src/attributes.coffee
+++ src/attributes.coffee
@@ -16,23 +16,21 @@
     @handler_pc = bytes_array.get_uint 2
     cti = bytes_array.get_uint 2
     @catch_type = if cti==0 then "<any>" else constant_pool.get(cti).deref()
-    return bytes_array

 class Code
   parse: (bytes_array,constant_pool) ->
     @max_stack = bytes_array.get_uint 2
     @max_locals = bytes_array.get_uint 2
     @code_len = bytes_array.get_uint 4
-    throw "Attribute._parse_code: Code length is zero" if @code_len == 0
+    throw "Code.parse error: Code length is zero" if @code_len == 0
     code_array = bytes_array.splice(@code_len)
     @opcodes = @parse_code code_array, constant_pool
     except_len = bytes_array.get_uint 2
     @exception_handlers = (new ExceptionHandler for [0...except_len])
     for eh in @exception_handlers
-      bytes_array = eh.parse(bytes_array,constant_pool)
+      eh.parse bytes_array, constant_pool
     # yes, there are even attrs on attrs. BWOM... BWOM...
     @attrs = root.make_attributes(bytes_array,constant_pool)
-    return bytes_array

   parse_code: (bytes_array, constant_pool) ->
     rv = new Array @code_len
@@ -60,12 +58,10 @@
       spc = bytes_array.get_uint 2
       ln = bytes_array.get_uint 2
       @entries.push {'start_pc': spc,'line_number': ln}
-    return bytes_array

 class SourceFile
   parse: (bytes_array,constant_pool) ->
     @name = constant_pool.get(bytes_array.get_uint 2).value
-    return bytes_array

 class StackMapTable
   parse: (bytes_array, constant_pool) ->
@@ -129,14 +125,12 @@

     @num_entries = bytes_array.get_uint 2
     @entries = (parse_entries() for i in [0...@num_entries] by 1)
-    return bytes_array

 class LocalVariableTable
   parse: (bytes_array, constant_pool) ->
     @num_entries = bytes_array.get_uint 2
     @entries = (@parse_entries bytes_array, constant_pool for i in [0...@num_entries] by 1)
-    return bytes_array

   parse_entries: (bytes_array, constant_pool) ->
     {
@@ -152,13 +146,11 @@
     @num_exceptions = bytes_array.get_uint 2
     exc_refs = (bytes_array.get_uint 2 for i in [0...@num_exceptions] by 1)
     @exceptions = (constant_pool.get(ref).deref() for ref in exc_refs)
-    return bytes_array

 class InnerClasses
   parse: (bytes_array, constant_pool) ->
     num_classes = bytes_array.get_uint 2
     @classes = (@parse_class bytes_array, constant_pool for i in [0...num_classes] by 1)
-    return bytes_array

   parse_class: (bytes_array, constant_pool) ->
     {
@@ -172,25 +164,22 @@
   parse: (bytes_array, constant_pool) ->
     @ref = bytes_array.get_uint 2
     @value = constant_pool.get(@ref).value
-    return bytes_array

 class Synthetic
-  parse: (bytes_array) -> bytes_array # NOP
+  parse: () ->  # NOP

 class Deprecated
-  parse: (bytes_array) -> bytes_array # NOP
+  parse: () ->  # NOP

 class Signature
   parse: (bytes_array, constant_pool) ->
     ref = bytes_array.get_uint 2
     @sig = constant_pool.get(ref).value
-    bytes_array

 class RuntimeVisibleAnnotations
   parse: (bytes_array, constant_pool, attr_len) ->
     num_annotations = bytes_array.get_uint 2
     @raw_bytes = bytes_array.splice attr_len-2
-    bytes_array

 class EnclosingMethod
   parse: (bytes_array, constant_pool) ->
@@ -198,7 +187,6 @@
     method_ref = bytes_array.get_uint 2
     if method_ref > 0
       @enc_method = constant_pool.get(method_ref).deref()
-    bytes_array

 root.make_attributes = (bytes_array,constant_pool) ->
@@ -221,7 +209,7 @@
     if attr_types[name]?
       attr = new attr_types[name]
       old_len = bytes_array.size()
-      bytes_array = attr.parse(bytes_array,constant_pool,attr_len)
+      attr.parse bytes_array, constant_pool, attr_len
       new_len = bytes_array.size()
       if old_len - new_len != attr_len
         #throw new Error "#{name} attribute didn't consume all bytes"


[backport] Escape project.name in invitation page

--- app/coffee/modules/auth.coffee
+++ app/coffee/modules/auth.coffee
@@ -364,7 +364,7 @@
             $analytics.trackEvent("auth", "invitationAccept", "invitation accept with existing user", 1)
             $location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug}))
             $confirm.notify("success", "You've successfully joined this project",
-                                       "Welcome to #{$scope.invitation.project_name}")
+                                       "Welcome to #{_.escape($scope.invitation.project_name)}")

         onErrorSubmitLogin = (response) ->
             $confirm.notify("light-error", "According to our Oompa Loompas, your are not registered yet or
@@ -393,7 +393,7 @@
             $analytics.trackEvent("auth", "invitationAccept", "invitation accept with new user", 1)
             $location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug}))
             $confirm.notify("success", "You've successfully joined this project",
-                                       "Welcome to #{$scope.invitation.project_name}")
+                                       "Welcome to #{_.escape($scope.invitation.project_name)}")

         onErrorSubmitRegister = (response) ->
             $confirm.notify("light-error", "According to our Oompa Loompas, that


filter alarm

filter alarm

--- port_scan/coffee/web.coffee
+++ port_scan/coffee/web.coffee
@@ -119,12 +119,13 @@
   <input type="submit" port="Filter" />
   </form>
   Usage:
-
只填写端口则返回开放该端口的IP列表,可填写格式为单个端口或端口段,如"22-53"

+
只填写端口格式为单个端口或端口段,如"22-53",则返回开放该端口段的IP

+
只填写端口格式为用竖线'|'隔开的多个端口或单个端口+'|',如"22|53"或"22|",则返回所有主机除了列出的端口以外开放的端口

只填写IP则返回该IP的端口信息,可填写格式为单个IP或IP段,如"192.168.1.1-192.168.1.255"

若既填写IP也填写端口,则返回该IP段除了填写的端口之外开放的端口信息,可填写IP格式,单个IP或IP段,可填写端口格式为单个端口或用竖线"|"隔开的多个端口,如"22|80"

   API:
+
Filter port: http://localhost/fport?from=22&to=80

Filter ip: http://localhost/fip?from=192.168.1.1&to=192.168.1.254

-
Filter port: http://localhost/fport?from=22&to=80

Alarm data: http://localhost/alarm?ports=22|53|80|500 (替换为要排除的端口)

White list: http://localhost/wlst?from=192.168.1.1&to=192.168.1.254&ports=22|53|80|500 (替换为要排除的端口)

   '''
@@ -140,11 +141,14 @@
     else
       res.redirect "/fip?from=#{ips[0]}&to=#{ips[1]}"
   else if ip_tmp == '' and port_tmp != ''
-    ports = port_tmp.split '-'
-    if ports.length == 1
-      res.redirect "/fport?from=#{ports[0]}&to=#{ports[0]}"
+    if port_tmp.indexOf('|') >= 0
+      res.redirect "/alarm?ports=#{port_tmp}"
     else
-      res.redirect "/fport?from=#{ports[0]}&to=#{ports[1]}"
+      ports = port_tmp.split '-'
+      if ports.length == 1
+        res.redirect "/fport?from=#{ports[0]}&to=#{ports[0]}"
+      else
+        res.redirect "/fport?from=#{ports[0]}&to=#{ports[1]}"
   else
     ips = ip_tmp.split '-'
     res.redirect "/wlst?from=#{ips[0]}&to=#{ips[1]}&ports=#{port_tmp}"


input: added focus and wasFocused methods

--- input/index.coffee
+++ input/index.coffee
@@ -52,7 +52,22 @@
       isDisabled
       autocapitalize
       isFocused: false
+      wasFocused: false
     }
+
+  afterMount: (@$$el) => null
+  beforeUnmount: =>
+    @$$el = null
+    @state.set
+      isFocused: false
+      wasFocused: false
+
+  focus: =>
+    if @$$el?
+      $$input = @$$el.querySelector '.zp-input > .input'
+      $$input.focus()
+
+  wasFocused: => @state.getValue().wasFocused

   render: =>
     {
@@ -94,6 +109,7 @@
         onfocus: z.ev (e, $$el) =>
           @state.set
             isFocused: true
+            wasFocused: true
         onblur: z.ev (e, $$el) =>
           @state.set
             isFocused: false


disabled publishing container stats

disabled publishing container stats

--- lib/docker.coffee
+++ lib/docker.coffee
@@ -68,8 +68,8 @@

   publishDockerInfo()
   publishExistingContainers()
-  publishContainerStats()
-  setInterval publishContainerStats, 10000
+  # publishContainerStats()
+  # setInterval publishContainerStats, 10000
   listenForEvents()

   eventEmitter # return eventEmitter so clients can register callbacks


change of Archive.complete() to be @stats.complete == @stats.total instead of some ratio calculation on progress_strict

--- app/models/Archive.coffee
+++ app/models/Archive.coffee
@@ -67,7 +67,7 @@
     @formatNumber @stats.total

   complete: =>
-    @progress_strict() is 100
+    (@stats.complete === @stats.total)

   # Private
   formatNumber: (n) ->


Hack progress number

Hack progress number

--- app/models/Archive.coffee
+++ app/models/Archive.coffee
@@ -56,7 +56,8 @@
     unless @stats? then return 0
     result = Math.ceil ( (@classification_count / @transcriptions_needed() ) * 100)

-    if result > 100 then 100 else result
+    # fake it until we are sure its complete
+    if result >= 100 then 99 else result

   recordsComplete: =>
     formatNumber @stats.complete


add ability to add a marker in freeform edit

--- app/scripts/controllers/map_edit_modal_controller.coffee
+++ app/scripts/controllers/map_edit_modal_controller.coffee
@@ -3,14 +3,16 @@

   constructor: (@$scope, @$modalInstance, @snippet, @leafletData, @$timeout, @leafletEvents) ->
     @$scope.close = $.proxy(@close, this)
+    @$scope.addMarker = $.proxy(@addMarker, this)
     @$scope.center = @snippet.data('center')
     @$scope.markers = @snippet.data('markers')
     @$scope.editState = {}

-    @$scope.events =
-      map:
-        enable: @leafletEvents.getAvailableMapEvents()
+    @addGeosearch()
+    @setupMapEvents()

+
+  addGeosearch: ->
     @$timeout =>
       @leafletData.getMap().then (map) =>
         new L.Control.GeoSearch(
@@ -19,6 +21,14 @@
         ).addTo(map)
     , 100

+
+  setupMapEvents: ->
+    @$scope.events =
+      map:
+        enable: ['click']
+      markers:
+        enable: ['click']
+
     @$scope.$on 'leafletDirectiveMap.click', (e, args) =>
       @$scope.editState.addMarker = true
       @$scope.editState.boundingBox =
@@ -26,6 +36,28 @@
         bottom: args.leafletEvent.originalEvent.clientY
         left: args.leafletEvent.originalEvent.clientX - 7
         width: 0
+      @$scope.editState.geolocation =
+        lat: args.leafletEvent.latlng.lat
+        lng: args.leafletEvent.latlng.lng
+
+    @$scope.$on 'leafletDirectiveMarker.click', (e, args) =>
+      @disableAddMarkerState()
+
+
+  disableAddMarkerState: ->
+    @$scope.editState.addMarker = false
+
+
+  addMarker: ->
+    # NOTE: since the snippet data is a reference to the scope var, we
+    # can work with the collection directly. For once the non-deep-copy thing
+    # comes in handy :)
+    @$scope.markers.push
+      lat: @$scope.editState.geolocation.lat
+      lng: @$scope.editState.geolocation.lng
+      uuid: livingmapsUid.guid()
+
+    @$scope.editState.addMarker = false

   close: (event) ->


mark import as failed when credentials are wrong

--- app/models/mailbox.coffee
+++ app/models/mailbox.coffee
@@ -120,6 +120,7 @@
             imported: false
             importing: false
             activated: false
+            status: "Import failed"

         @updateAttributes data, (error) =>
             if error
@@ -303,7 +304,7 @@
         @importStarted =>
             @openInbox (err) =>
                 if err
-                    LogMessage.createImportPreparationError @, =>
+                    @importFailed =>
                         callback err
                 else
                     @mailGetter.getAllMails (err, results) =>


Update survey ratios

Update survey ratios

--- app/models/subject.coffee
+++ app/models/subject.coffee
@@ -33,10 +33,13 @@
   @url: (params) -> @withParams "/projects/galaxy_zoo/groups/#{ params.surveyId }/subjects", limit: params.limit
   @randomSurveyId: ->
     return @::surveys.sloan.id if UserGroup.current
-    if Math.random() > 0.5
-      if Math.random() > (1/3) then @::surveys.ukidss.id else @::surveys.ferengi.id
+    n = Math.random()
+    if n <= 0.1
+      @::surveys.sloan.id   # 10%
+    else if n <= 0.6
+      @::surveys.ukidss.id  # 50%
     else
-      @::surveys.sloan.id
+      @::surveys.ferengi.id # 40%

   @next: ->
     if @current


fixed on Marker added bug

fixed on Marker added bug

--- lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay.js.coffee
+++ lib/assets/javascripts/socmap_adf/modules/gmap/views/overlay.js.coffee
@@ -172,7 +172,7 @@
       @pane.appendChild(@div)
     else
       $(@body).append(@div)
-      @view.onMarkerAdded(@view.point)
+    @view.onMarkerAdded(@view.point)

   draw: () ->
     overlayProjection = @getProjection()


Fix a potential race condition

Fix a potential race condition

--- integration_test/cobalt.coffee
+++ integration_test/cobalt.coffee
@@ -280,7 +280,7 @@

   describe 'When Cobalt has started', ->
     before (done) ->
-      ssh_cmd_root "service cobalt stop && rm -f /var/run/cobalt.socket && service cobalt start", done
+      ssh_cmd_root "service cobalt stop && rm -f /var/run/cobalt.socket && service cobalt start && sleep 2", done

     describe "the created unix socket", ->


Resolve conflicts.

Resolve conflicts.

--- app/assets/javascripts/ample_assets/classes/ample_assets_gravity.js.coffee
+++ app/assets/javascripts/ample_assets/classes/ample_assets_gravity.js.coffee
@@ -17,7 +17,7 @@

   test: ->
     if @image.width() > 0
-      @html() if @image.height() > @options.min_width && @image.height() > @options.min_height
+      @html()
     else
       @log "@image not loaded"
       setTimeout (=> @test()), 500
@@ -25,7 +25,7 @@
   html: ->
     @log "html()"
     # Don't show this for tiny images
-    return false unless @image.width() > 100 && @image.width() > 100
+    return false unless @image.height() > @options.min_width && @image.height() > @options.min_height
     @gravity = $("#file_attachment_gravity").val() || "c"
     @gravity_grid =
       top: @image.height() / 3


Making modal medium man

Making modal medium man

--- app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
+++ app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
@@ -9,7 +9,7 @@
     open: (path = false)=>
       @modalInstance = $modal.open
         templateUrl: 'authentication.html'
-        windowClass: "login-modal small"
+        windowClass: "login-modal medium"
       @modalInstance.result.then @close, @close
       @selectedPath = path || @selectedPath
       Navigation.navigate @selectedPath


updated id field for seed resource

updated id field for seed resource

--- libs/seeds.coffee
+++ libs/seeds.coffee
@@ -37,7 +37,7 @@
 		if err
 			next new restify.ResourceNotFoundError 'resource with id: ' + id + 'cannot be found'
 		response = {}
-		response.id = docs[0]._id
+		response.id = docs[0].id
 		response.urls = docs[0].urls
 		res.status 200
 		res.send response


Animate the progress indicator (now the animation loop is always started again)

--- framer/Extras/Preloader.coffee
+++ framer/Extras/Preloader.coffee
@@ -116,7 +116,7 @@

 	_handleProgress: =>
 		@emit("progress", @progress)
-		@progressIndicator?.setProgress(@progress, false)
+		@progressIndicator?.setProgress(@progress)
 		@_handleLoaded() if @isReady

 	_handleLoaded: ->
@@ -144,7 +144,7 @@

 		@progressIndicator.railsColor = Color.grey(0, 0.1)
 		@progressIndicator.progressColor = "rgb(75,169,248)"
-		@progressIndicator.setProgress(@progress, false)
+		@progressIndicator.setProgress(@progress)

 		@brand = new Layer
 			size: 96


:art: Clean up displaySuggestions

:art: Clean up displaySuggestions

--- lib/autocomplete-manager.coffee
+++ lib/autocomplete-manager.coffee
@@ -137,16 +137,14 @@
     , []

   displaySuggestions: (suggestions, suggestionsPromise, options) =>
-    unless suggestions.length
+    suggestions = _.uniq(suggestions, (s) -> s.word)
+    suggestionsAreLatest = @currentSuggestionsPromise is suggestionsPromise
+    if @shouldDisplaySuggestions and suggestions.length and suggestionsAreLatest
+      @showSuggestionList(suggestions)
+    else
       @hideSuggestionList()
-      @emitter.emit('did-autocomplete', {options, suggestions})
-      return
-    suggestions = _.uniq(suggestions, (s) -> s.word)
-
-    # Show the suggestion list if we have not already requested more suggestions
-    if @shouldDisplaySuggestions and @currentSuggestionsPromise is suggestionsPromise
-      @showSuggestionList(suggestions)
-      @emitter.emit('did-autocomplete', {options, suggestions})
+
+    @emitter.emit('did-autocomplete', {options, suggestions})

   prefixForCursor: (cursor) =>
     return '' unless @buffer? and cursor?


virtualmachines: make sure only non-managed vms are rendered

--- client/home/lib/virtualmachines/components/virtualmachineslist/view.coffee
+++ client/home/lib/virtualmachines/components/virtualmachineslist/view.coffee
@@ -19,6 +19,11 @@
     onSharedWithUser    : kd.noop
     onUnsharedWithUser  : kd.noop
     onCancelSharing     : kd.noop
+
+
+  getStacks: ->
+
+    @props.stacks.filter (stack) -> stack.get('title').toLowerCase() isnt 'managed vms'

   onChangeAlwaysOn: (machine, state) ->
@@ -51,12 +56,8 @@
   numberOfSections: -> 1

-  numberOfRowsInSection: ->
+  numberOfRowsInSection: -> @getStacks().size

-    @props.stacks
-      .toList()
-      .filter (stack) -> stack.get('title').toLowerCase() isnt 'managed vms'
-      .size

   renderSectionHeaderAtIndex: -> null
@@ -64,7 +65,7 @@

   renderRowAtIndex: (sectionIndex, rowIndex) ->

-    stack = @props.stacks.toList().get rowIndex
+    stack = @getStacks().toList().get rowIndex

     stack.get 'machines'
       .sort (a, b) -> a.get('label').localeCompare(b.get('label')) # Sorting from a to z


fix(editor): remove render status

fix(editor): remove render status

Remove render status if the preview panel is not open
fix #73

--- lib/asciidoc-preview.coffee
+++ lib/asciidoc-preview.coffee
@@ -128,7 +128,14 @@

   changeRenderMode: ->
     document.querySelector('#asciidoc-changemode')?.remove()
-    return unless @checkFile()?
+    editor = @checkFile()
+    return unless editor?
+
+    uri = "asciidoc-preview://editor/#{editor.id}"
+
+    previewPane = atom.workspace.paneForURI(uri)
+    return unless previewPane?
+

     statusBar = document.querySelector('status-bar')


add default style and size to inputs

add default style and size to inputs

--- lib/components/eui-input.coffee
+++ lib/components/eui-input.coffee
@@ -6,7 +6,9 @@
 input = Em.Component.extend errorSupport, textSupport, className, widthSupport,
   tagName: 'eui-input'
   baseClass: 'input'
-
+  style: 'default'
+  size: 'medium'
+
   maxlength: null
   type: 'text'


home: counters fixed / copy changed

home: counters fixed / copy changed

--- client/landing/app/Applications/Home.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Home.kdapplication/AppView.coffee
@@ -27,13 +27,13 @@
       tagName  : "section"
     ,
       "MEMBERS"          : count : 0
-      "Virtual Machines" : count : 0
+      "RUNNING VMS"      : count : 0
       # "Lines of Code"    : count : 0
       "GROUPS"           : count : 0
       "TOPICS"           : count : 0
       "Thoughts shared"  : count : 0

-    vms          = @counterBar.counters["Virtual Machines"]
+    vms          = @counterBar.counters["RUNNING VMS"]
     # loc          = @counterBar.counters["Lines of Code"]
     members      = @counterBar.counters.MEMBERS
     groups       = @counterBar.counters.GROUPS
@@ -42,12 +42,12 @@
     vmController = KD.getSingleton("vmController")
     {JAccount, JTag, JGroup, CActivity} = KD.remote.api

-    members.ready => JAccount.count "",         (err, count)=> members.update count    or 0
+    members.ready => JAccount.count             (err, count)=> members.update count    or 0
     vms.ready => vmController.fetchTotalVMCount (err, count)=> vms.update count        or 0
     # loc.ready => vmController.fetchTotalLoC     (err, count)=> loc.update count        or 0
-    groups.ready => JGroup.count "",            (err, count)=> groups.update count     or 0
-    topics.ready => JTag.count "",              (err, count)=> topics.update count     or 0
-    activities.ready => CActivity.count "",     (err, count)=> activities.update count or 0
+    groups.ready => JGroup.count                (err, count)=> groups.update count     or 0
+    topics.ready => JTag.count                  (err, count)=> topics.update count     or 0
+    activities.ready => CActivity.fetchCount    (err, count)=> activities.update count or 0

     KD.getSingleton("activityController").on "ActivitiesArrived", (newActivities=[])->
       activities.increment newActivities.length


Preload function is only used within loadTree

--- lib/loader.coffee
+++ lib/loader.coffee
@@ -71,6 +71,21 @@
         rawmetas[name.replace(stripDotMeta,'$1')]= raw
         extend(superMeta, raw, name)

+      preload= (modules,superMeta,supersites)->
+        for modname in modules
+          m= require(modname)
+          if m?.meta
+            rawmetas[modname]= m.meta
+            itsMeta= meta_lookup(modname)
+            metacache[modname]= extend(itsMeta,m.meta,modname)
+          if sitesModuleSignature.test(modname)
+            siteroot= path.dirname(modname)
+            siteLookupRoot ?= siteroot
+            sites[siteroot]= m
+            (xsupersites= supersites.slice(0)).push(siteroot)
+            for sitepath in m.paths
+              loadTree(normalize(sitepath),superMeta,xsupersites)
+
       modules= []
       loadDir= (dirname,superMeta,visited) ->   #recursive
         defaultModName = path.join(dirname,'_default.meta')
@@ -103,21 +118,6 @@
       preload(modules,meta,supersites)
       return meta

-    preload= (modules,superMeta,supersites)->
-        for modname in modules
-          m= require(modname)
-          if m?.meta
-            rawmetas[modname]= m.meta
-            itsMeta= meta_lookup(modname)
-            metacache[modname]= extend(itsMeta,m.meta,modname)
-          if sitesModuleSignature.test(modname)
-            siteroot= path.dirname(modname)
-            siteLookupRoot ?= siteroot
-            sites[siteroot]= m
-            (xsupersites= supersites.slice(0)).push(siteroot)
-            for sitepath in m.paths
-              loadTree(normalize(sitepath),superMeta,xsupersites)
-
     dirs = baseSiteStack  # note: the stack is maintained in reverse order
     userPath= dirs[0]
     defaultPath= dirs[1]


Manually set a label offset on the problems chart

--- app/scripts/dcplotsctrl.coffee
+++ app/scripts/dcplotsctrl.coffee
@@ -403,6 +403,7 @@
         .ordering((x) -> -x.value)
         .dimension(dim)
         .cap(10)
+        .labelOffsetY(10)
         .label((d) -> d.key)
         .title((d) -> d.key)
         .elasticX(true)


Add crystal language key

Add crystal language key

--- app/utils/keys-map.coffee
+++ app/utils/keys-map.coffee
@@ -24,6 +24,7 @@
   clojure:     'Clojure'
   lein:        'Lein'
   compiler:    'Compiler'
+  crystal:     'Crystal'
 }

 configKeys = {


Fixed setting an object instead of JSON

Fixed setting an object instead of JSON

--- core/app/backbone/views/sub_comments/sub_comments_add_view.coffee
+++ core/app/backbone/views/sub_comments/sub_comments_add_view.coffee
@@ -25,7 +25,7 @@

     @model = new SubComment
       content: $.trim(@text())
-      created_by: currentUser
+      created_by: currentUser.toJSON()

     return @addModelError() unless @model.isValid()


added a api for update comment

added a api for update comment

--- src/coffee/api.coffee
+++ src/coffee/api.coffee
@@ -3,7 +3,26 @@
  * @namespace
 ###
 api =
+  ###
+   * @param {String} user
+   * @param {String} type
+   * @param {String} target
+   * @param {Number} limit is optional
+   * @type Deferred
+  ###
   getComment:( user, type, target, limit = 10 )->

     ajax.jsonp "#{API_DOMAIN}user/#{user}/type/#{type}/target/#{target}/Comment", limit:limit

+  ###
+   * @param {String} user
+   * @param {String} type
+   * @param {String} target
+   * @param {Object} data
+   * @type Deferred
+  ###
+  putComment:( user, type, target, data = {} )->
+
+    if data._id then delete data._id
+    ajax.postJson "#{API_DOMAIN}user/#{user}/type/#{type}/target/#{target}/Comment", data:data
+


splice updates length by itself

splice updates length by itself

--- src/collection.coffee
+++ src/collection.coffee
@@ -35,7 +35,6 @@
   splice: (start, deleteCount, list...) ->
     old = @clone()
     deleted = Array.prototype.splice.apply(@, [start, deleteCount, list...])
-    @length = getLength(@)
     @trigger("update", old, @)
     @trigger("change", @)
     new Collection(deleted)
@@ -76,14 +75,12 @@
     return item for item in @ when fun(item)
   insertAt: (index, value) ->
     Array.prototype.splice.call(@, index, 0, value)
-    @length = getLength(@)
     @trigger("insert", index, value)
     @trigger("change", @)
     value
   deleteAt: (index) ->
     value = @[index]
     Array.prototype.splice.call(@, index, 1)
-    @length = getLength(@)
     @trigger("delete", index, value)
     @trigger("change", @)
     value


LoginView: Trimmed user name on login view.

--- client/app/MainApp/login/loginview.coffee
+++ client/app/MainApp/login/loginview.coffee
@@ -240,7 +240,7 @@
         KD.track "userSignedUp", account

   doLogin:(credentials)->
-    credentials.username = credentials.username.toLowerCase()
+    credentials.username = credentials.username.toLowerCase().trim()
     KD.remote.api.JUser.login credentials, @afterLoginCallback.bind this

   runExternal = (token)->


ShortcutsController: Turn off max listeners limit

--- client/app/lib/shortcutscontroller.coffee
+++ client/app/lib/shortcutscontroller.coffee
@@ -76,6 +76,8 @@

     super()

+    @setMaxListeners 0
+

   # Prepares buffer for the next batch of changes.
   #


Rename persistance variable.

Rename persistance variable.

--- lib/malifi.coffee
+++ lib/malifi.coffee
@@ -21,8 +21,8 @@
 class ParseHost
   constructor: (req)->
     @host= req.headers.host
-  hostname: -> @qhostname||= @host.replace(extractHostFromHost,'$1')
-  port: -> @qport||= @host.replace(extractPortFromHost,'$1')
+  hostname: -> @_hostname||= @host.replace(extractHostFromHost,'$1')
+  port: -> @_port||= @host.replace(extractPortFromHost,'$1')

 malifi= (root,options)->
   unless root?


OAuth: add ::validateOAuth method for all providers

--- workers/social/lib/social/models/oauth.coffee
+++ workers/social/lib/social/models/oauth.coffee
@@ -1,9 +1,9 @@
 bongo       = require 'bongo'
 { secure, signature } = bongo
 crypto      = require 'crypto'
-oauth       = require 'oauth'
-parser      = require 'url'
 KodingError = require '../error'
+
+{ isAddressValid } = require './utils'

 module.exports = class OAuth extends bongo.Base
@@ -17,6 +17,8 @@

   ERRORS =
     NOTSUPPORTED : new KodingError 'OAuth provider is not supported'
+    VALIDATION   : new KodingError 'OAuth validation failed'
+
   # -- OAUTH PROVIDERS ----------------------------------------------------8<--

   @PROVIDERS =
@@ -76,6 +78,24 @@

           callback null, url

+      validateOAuth: (options, callback) ->
+
+        { url, applicationId, applicationSecret } = options
+
+        MissingFieldError = 'Missing field for validating oauth'
+
+        if not url then return callback new KodingError \
+          MissingFieldError, 'MissingField', { fields: ['url'] }
+        if not applicationId then return callback new KodingError \
+          MissingFieldError, 'MissingField', { fields: ['applicationId'] }
+        if not applicationSecret then return callback new KodingError \
+          MissingFieldError, 'MissingField', { fields: ['applicationSecret'] }
+
+        isAddressValid url, (err) ->
+
+          if err
+            err.error = { fields: ['url'] }
+            return callback err

     # -- GITHUB PROVIDER --------------------------------------------------8<--

@@ -95,6 +115,9 @@

         callback null, url

+      validateOAuth: (options, callback) ->
+        callback ERROR.VALIDATION
+

     # -- FACEBOOK PROVIDER ------------------------------------------------8<--

@@ -111,6 +134,9 @@
         url += "redirect_uri=#{redirectUri}&scope=email"

         callback null, url
+
+      validateOAuth: (options, callback) ->
+        callback ERROR.VALIDATION

     # -- GOOGLE PROVIDER --------------------------------------------------8<--
@@ -140,6 +166,9 @@

           callback null, url

+      validateOAuth: (options, callback) ->
+        callback ERROR.VALIDATION
+

     # -- LINKEDIN PROVIDER ------------------------------------------------8<--

@@ -163,6 +192,10 @@

         callback null, url

+      validateOAuth: (options, callback) ->
+        callback ERROR.VALIDATION
+
+
   # -- END OF PROVIDERS ---------------------------------------------------8<--

@@ -170,7 +203,7 @@

     { provider } = urlOptions

-    if _provider = @PROVIDER[provider] and _provider.enabled
+    if (_provider = @PROVIDERS[provider]) and _provider.enabled
       { context: { group } } = client
       urlOptions.redirectUri = \
         "http://#{group}.#{KONFIG.hostname}/-/oauth/#{provider}/callback"
@@ -178,3 +211,10 @@
     else
       callback ERROR.NOTSUPPORTED

+
+  @validateOAuth = (provider, options, callback) ->
+
+    if (_provider = @PROVIDERS[provider]) and _provider.enabled
+      _provider.validateOAuth options, callback
+    else
+      callback ERROR.NOTSUPPORTED


Log to a file

Log to a file

--- lib/Server.coffee
+++ lib/Server.coffee
@@ -14,6 +14,10 @@
   constructor: ->
     winston.clear()
     winston.add winston.transports.Console, level: 'verbose'
+    winston.add winston.transports.File,
+      filename: 'jarvis.log'
+      level: 'verbose'
+      json: false
     winston.cli()
     @log 'info', 'Jarvis Home Automation server'
     @config = @readConfig()


New quat.to_euler formula

New quat.to_euler formula

--- engine/glmatrix_extra.coffee
+++ engine/glmatrix_extra.coffee
@@ -1,42 +1,23 @@
 glm = require 'gl-matrix'
-glm.quat.to_euler = (out=[0,0,0], quat, order='XZY') ->
-    if order != 'XZY'
-        throw new Error "Euler order "+order+" not supported yet."
-    # It will return XZY euler. TODO: implement other orders
-    x = quat[0]
-    y = quat[1]
-    z = quat[2]
-    w = quat[3]

-    test = x*y + z*w;
-    if test > 0.499 # singularity at north pole
-        heading = 2 * Math.atan2 x,w
-        attitude = Math.PI/2
-        bank = 0
+# http://stackoverflow.com/questions/1031005/is-there-an-algorithm-for-converting-quaternion-rotations-to-euler-angle-rotatio

-    else if test < -0.499 # singularity at south pole
-        heading = -2 * Math.atan2 x,w
-        attitude = - Math.PI/2
-        bank = 0
+threeaxisrot = (out, r11, r12, r21, r31, r32) ->
+    out[0] = Math.atan2( r31, r32 )
+    out[1] = Math.asin ( r21 )
+    out[2] = Math.atan2( r11, r12 )

-    else if isNaN heading
-        sqx = x*x
-        sqy = y*y
-        sqz = z*z
-        heading = Math.atan2 2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz # Heading
-        attitude = Math.asin 2*test  # attitude
-        bank = Math.atan2 2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz # bank
-
-    # Compatibility with turntable camera (bank limited to 0-180)
-    if bank < 0
-        bank += Math.PI
-        heading += Math.PI
-        attitude = Math.PI - attitude
-
-    out[1] = heading
-    out[2] = attitude
-    out[0] = bank
-
+glm.quat.to_euler = (out=[0,0,0], q, order='XYZ') ->
+    [x, y, z, w] = q
+    switch order
+        when 'XYZ'
+            threeaxisrot(out, 2*(x*y + w*z),
+                            w*w + x*x - y*y - z*z,
+                           -2*(x*z - w*y),
+                            2*(y*z + w*x),
+                            w*w - x*x - y*y + z*z)
+        else
+            throw new Error "Euler order "+order+" not supported yet."
     return out

 module.exports = glm


Log out incoming and outgoing real-time updates

--- services/web/app/coffee/Features/Editor/EditorUpdatesController.coffee
+++ services/web/app/coffee/Features/Editor/EditorUpdatesController.coffee
@@ -18,9 +18,11 @@
 			if takeSnapshot
 				AutomaticSnapshotManager.markProjectAsUpdated(project_id)

+		logger.log doc_id: doc_id, project_id: project_id, client_id: update.meta.source, version: update.v, "sending update to doc updater"
+
 		DocumentUpdaterHandler.queueChange project_id, doc_id, update, (error) ->
 			if error?
-				logger.error err:error, project_id: project_id, "document was not available for update"
+				logger.error err:error, project_id: project_id, doc_id: doc_id, client_id: update.meta.source, version: update.v, "document was not available for update"
 				client.disconnect()
 			callback(error)

@@ -50,6 +52,7 @@

 	_applyUpdateFromDocumentUpdater: (doc_id, update) ->
 		io = require('../../infrastructure/Server').io
+		logger.log doc_id: doc_id, version: update.v, source: update.meta.source, "distributing update"
 		for client in io.sockets.clients(doc_id)
 			if client.id == update.meta.source
 				client.emit "otUpdateApplied", v: update.v, doc: update.doc


Delete js source files before your coffeefy to prevent errors


:fire: Remove some indirect function( don't be too serious )

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -49,20 +49,8 @@
       @wise = @vimState.submode
     @initialize()

-  isInclusive: ->
-    @inclusive
-
-  isJump: ->
-    @jump
-
-  isVerticalMotion: ->
-    @verticalMotion
-
-  isLinewise: ->
-    @wise is 'linewise'
-
-  isBlockwise: ->
-    @wise is 'blockwise'
+  isLinewise: -> @wise is 'linewise'
+  isBlockwise: -> @wise is 'blockwise'

   forceWise: (wise) ->
     if wise is 'characterwise'
@@ -79,7 +67,7 @@
     cursor.setScreenPosition(point) if point?

   moveWithSaveJump: (cursor) ->
-    if cursor.isLastCursor() and @isJump()
+    if cursor.isLastCursor() and @jump
       cursorPosition = cursor.getBufferPosition()

     @moveCursor(cursor)
@@ -111,7 +99,7 @@
         swrap(selection).translateSelectionEndAndClip('forward')
         swrap(selection).saveProperties() if @isMode('visual')

-      else if succeeded and (@isInclusive() or @isLinewise())
+      else if succeeded and (@inclusive or @isLinewise())
         swrap(selection).translateSelectionEndAndClip('forward')

     @editor.mergeCursors()
@@ -132,7 +120,7 @@
     return @moveSucceeded ? not selection.isEmpty()

   setCursorBuffeRow: (cursor, row, options) ->
-    if @isVerticalMotion() and @getConfig('moveToFirstCharacterOnVerticalMotion')
+    if @verticalMotion and @getConfig('moveToFirstCharacterOnVerticalMotion')
       cursor.setBufferPosition(@getFirstCharacterPositionForBufferRow(row), options)
     else
       setBufferRow(cursor, row, options)


Fix freeze animation when not showPaletteInTextMode.

--- src/controller.coffee
+++ src/controller.coffee
@@ -3280,7 +3280,7 @@
           @paletteHeader.style.zIndex = 0

         @dropletElement.style.top = "0px"
-        if @paletteEnabled
+        if @paletteEnabled and not paletteAppearingWithFreeze
           @dropletElement.style.left = "#{@paletteWrapper.offsetWidth}px"
         else
           @dropletElement.style.left = "0px"


Quote discourage bug fix

Quote discourage bug fix

--- src/controller.coffee
+++ src/controller.coffee
@@ -1452,9 +1452,10 @@

     @oldFocusValue = null

-
+    # Prevent kids from deleting a necessary quote accidentally
     @hiddenInput.addEventListener 'keydown', (event) =>
-      if event.keyCode is 8 and @hiddenInput.value[0] is @hiddenInput.value[@hiddenInput.value.length - 1] and
+      if event.keyCode is 8 and @hiddenInput.value.length > 1 and
+          @hiddenInput.value[0] is @hiddenInput.value[@hiddenInput.value.length - 1] and
           @hiddenInput.value[0] in ['\'', '\"'] and @hiddenInput.selectionEnd is 1
         event.preventDefault()


Fix get/set order in meltAnimation

Fix get/set order in meltAnimation

--- src/controller.coffee
+++ src/controller.coffee
@@ -1885,12 +1885,12 @@

   Editor::performMeltAnimation = ->
     if @currentlyUsingBlocks and not @currentlyAnimating
+      @aceEditor.setValue @getValue(), -1
+
       @currentlyUsingBlocks = false
       @currentlyAnimating = true

       @redrawMain()
-
-      @aceEditor.setValue @getValue(), -1

       # Move the palette header into the background
       @paletteHeader.style.zIndex = 0


fix(web): Fixing actor library path

fix(web): Fixing actor library path

--- apps/actor-web/gulpfile.coffee
+++ apps/actor-web/gulpfile.coffee
@@ -48,7 +48,7 @@
   gulp.src ['./assets/**/*']
     .pipe gulp.dest './dist/assets/'
   gulp.src ['./bower_components/actor/**/*.js']
-    .pipe gulp.dest './dist/assets/actor'
+    .pipe gulp.dest './dist/assets/js/actor'

 gulp.task 'usemin', ->
   gulp.src ['./index.html']


Fix backend-idle notification

Fix backend-idle notification

--- lib/ghc-modi-process.coffee
+++ lib/ghc-modi-process.coffee
@@ -79,7 +79,7 @@
     .then (res) =>
       if qe(queueName)
         @emitter.emit 'queue-idle', {queue: queueName}
-        if (1 for k of @commandQueues when qe(k)).length
+        if (k for k of @commandQueues).every(qe)
           @emitter.emit 'backend-idle'
       res


restore original CC help content

restore original CC help content

--- tutor/src/components/cc-dashboard/help.cjsx
+++ tutor/src/components/cc-dashboard/help.cjsx
@@ -28,28 +28,48 @@

This guide is always accessible from your main menu.

-

-              In January 2017, you’ll see the following improvements to Concept Coach:
-

-
+
+              Add <CourseGroupingLabel plural {...glprops} /> to your course.
+

-                Improved course setup. There
-                will be an easy way to teach this course again. You
-                no longer need to add or archive sections to teach this course.
+                Click your name in the top right corner and select “Course Settings and Roster”

-
-                  The ability to copy your Question Library and use it in a future course.
-                 If you excluded any questions, you’ll be able to carry over those exclusions to the next course you teach
+                Click the blue “Add Section” link and follow the prompts to create your section.
+                If you have more than one section, repeat this step as needed.
+

+

+            Get student enrollment code and send to your students.
+

+

+                Select your first section and click the blue “Get Student Enrollment Code” link.

-                Errata fixes. We’ve processed corrections for items found to be incorrect.
+                Copy the example message and share this message with your students in that section.
+

+

+                Repeat this step for each section of your course (every section has a different enrollment code).

-
-              Please return here on January 3rd to set up your new Concept Coach course!
-
+            Assign Concept Coach.
+

+

+                On the top menu, click “Get Assignment Links.” Follow the instructions to assign Concept Coach question sets.
+

+

+                View your students’ progress.
+

+

+                As your students begin using Concept Coach, you will be able to track
+                their performance in your dashboard.
+

+

+

+              Tip:
+              To view all Concept Coach questions, click your name in the top right corner of your dashboard
+              and select “Question Library.”
+


fix the add clause

fix the add clause

--- lib/idris-controller.coffee
+++ lib/idris-controller.coffee
@@ -154,7 +154,7 @@
         lineRange = cursor.getCurrentLineBufferRange(includeNewline: true)
         editor.setTextInBufferRange lineRange, split

-  doAddClause: ({target}) ->
+  doAddClause: ({target}) =>
     editor = atom.workspace.getActiveEditor()
     line = editor.getCursor(0).getBufferRow()
     word = @getWordUnderCursor target


Utils: throttle and debounce updated

Utils: throttle and debounce updated

--- src/core/utils.coffee
+++ src/core/utils.coffee
@@ -490,42 +490,76 @@
   //     http://documentcloud.github.com/underscore
   ###

-  throttle : (wait, func)->
-    # for backwards compatibility
-    if (typeof func) is "number"
-      [wait, func] = [func, wait]
-
-    context = args = timeout = throttling = more = null
-    whenDone = KD.utils.debounce wait, -> more = throttling = false
+  throttle : (wait, func, options) ->
+
+    [wait, func] = [func, wait]  if (typeof func) is 'number'
+
+    context  = null
+    args     = null
+    result   = null
+    timeout  = null
+    previous = 0
+    options ?= {}
+
+    later = ->
+      previous = (if options.leading is false then 0 else Date.now)
+      timeout  = null
+      result   = func.apply context, args
+      context  = args = null  unless timeout
+
     ->
-      context = this
-      args = arguments
-      later = ->
+      now       = Date.now
+      previous  = now  if not previous and options.leading is false
+      remaining = wait - (now - previous)
+      context   = this
+      args      = arguments
+
+      if remaining <= 0 or remaining > wait
+        if timeout
+          clearTimeout timeout
+          timeout = null
+        previous = now
+        result = func.apply context, args
+        context = args = null  unless timeout
+      else if not timeout and options.trailing isnt false
+        timeout = setTimeout later, remaining
+
+      return result
+
+
+  debounce : (wait, func, immediate) ->
+
+    [wait, func] = [func, wait]  if (typeof func) is 'number'
+
+    timeout   = null
+    args      = null
+    context   = null
+    timestamp = null
+    result    = null
+    later     = ->
+      last = Date.now - timestamp
+      if last < wait and last >= 0
+        timeout = setTimeout(later, wait - last)
+      else
         timeout = null
-        if more then func.apply context, args
-        whenDone()
-
-      if !timeout then timeout = setTimeout later, wait
-
-      if throttling then more = yes else func.apply(context, args)
-
-      whenDone()
-      throttling = yes
-
-  debounce : (wait, func)->
-    if (typeof func) is "number"
-      [wait, func] = [func, wait]
-
-    timeout   = null
+        unless immediate
+          result  = func.apply(context, args)
+          context = args = null  unless timeout
+
     ->
-      context = this
-      args    = arguments
-      later   = ->
-        timeout = null
-        func.apply context, args
-
-      clearTimeout timeout
-      timeout = setTimeout later, wait
+      context   = this
+      args      = arguments
+      timestamp = Date.now
+      callNow   = immediate and not timeout
+      timeout  ?= setTimeout later, wait
+
+      if callNow
+        result  = func.apply(context, args)
+        context = args = null
+
+      return result
+
+

   relativeOffset: (child, parent) ->
     x = 0; y = 0


query explicitly for indices

query explicitly for indices

--- apps/search/routes.coffee
+++ apps/search/routes.coffee
@@ -21,7 +21,10 @@
   return res.redirect("/") unless req.query.q

   term = removeDiacritics req.query.q
+  indexes = ['Artwork', 'Artist', 'Article', 'Tag', 'Gene', 'Feature', 'Profile', 'PartnerShow', 'Sale']
   data = { term: term, size: 10 }
+  data['indexes[]'] = indexes
+
   res.locals.sd.term = term
   page = Number(req.query.page)
   if page && page > 1


Add in tooltips to make the radio buttons clearer in the history view

--- services/web/public/coffee/track-changes/ChangeListView.coffee
+++ services/web/public/coffee/track-changes/ChangeListView.coffee
@@ -211,6 +211,17 @@
 			else
 				@$el.addClass("first-in-day")

+			@$(".change-selector-from").tooltip({
+				title: "Show back to this change",
+				placement: "left",
+				animation: false
+			})
+			@$(".change-selector-to").tooltip({
+				title: "Show up to this change",
+				placement: "left",
+				animation: false
+			})
+
 			return this

 		onClick: (e) ->


Refactoring dockerfile

Refactoring dockerfile

--- src/dockerfile.coffee
+++ src/dockerfile.coffee
@@ -1,10 +1,12 @@
 extend = require('extend')
 clone = require('clone')
+Cmd = require('./commands/cmd')
 MultiEnv = require('./commands/multi-env')
 MultiRun = require('./commands/multi-run')
 MultiExpose = require('./commands/multi-expose')
 MultiVolume = require('./commands/multi-volume')
 MultiLabel = require('./commands/multi-label')
+groupByAppearanceOrder = require('../group-by-appearance-order')

 PRIORITIES = [
   'FROM'
@@ -68,10 +70,20 @@
     commands.forEach((c) -> c.next = [])
     commands.forEach((c) -> c.after.next.push(c))
     walkLayer = (layer) ->
+      return unless layer.length > 0
+      ###
+      sorted = extend([], layer)
+      for current, i in sorted[..-2]
+        for lookAhead, j in sorted[(i + 1)..]
+          if (current.constructor != lookAhead.constructor)
+            [sorted[i], sorted[j]] = [sorted[j], sorted[i]]
+            break
+      ###
+
       sorted = layer.sort(comparePriorities)
       aggregate = (list, keyword, ctor) ->
         byKeyword = list.filter((c) -> c.keyword() == keyword)
-        if byKeyword.length > 1
+        if byKeyword.length > 0
           aggregated = new ctor(byKeyword[0])
           aggregated.next = byKeyword[0].next
           aggregateMore = (more) ->


Add weibo link to poi about

Add weibo link to poi about

--- views/components/settings/parts/others.cjsx
+++ views/components/settings/parts/others.cjsx
@@ -11,6 +11,7 @@
         <Col xs={12}>

poi v{POI_VERSION} 基于 Electron v{process.versions.electron} 和 React.js 开发，是一个开源的跨平台舰队 Collection 浏览器。poi 的游戏行为与 Chrome 一致，原则上不提供任何影响收发包的功能。poi 仅提供基本浏览器功能，扩展功能请等待插件开发。

+
微博:  今天 poi 出新版本了吗

开发讨论与意见交流群: 378320628

poi 掉落数据统计: http://db.kcwiki.moe

更多帮助与指南查看 poi wiki:  https://github.com/poooi/poi/wiki


Fix variable typo

Fix variable typo

--- virtual-file-system/util/atom-helper.coffee
+++ virtual-file-system/util/atom-helper.coffee
@@ -94,12 +94,13 @@
       # TODO: this happens if an untitled editor is saved. need to build a 'Save As' or sorts
       return console.log 'Cannot save file without path'

-    content = new Buffer(textEditor.getText()).toString('base64')
+    text = convertEOL(textEditor.getText())
+    content = new Buffer(text).toString('base64')
     @virtualFileSystem.learnSave(textEditor.getPath(), content)

   onEditorSave: ({path}) =>
     @findOrCreateBuffer(path).then (textBuffer) =>
-      text = convertEOL(textbuffer.getText())
+      text = convertEOL(textBuffer.getText())
       content = new Buffer(text).toString('base64')
       @virtualFileSystem.editorSave(path, content)


Diff algo improved to maintain correct positions for removed lines

--- lib/foundry-xray/app/assets/javascripts/lib/nodes/block.js.coffee
+++ lib/foundry-xray/app/assets/javascripts/lib/nodes/block.js.coffee
@@ -10,10 +10,7 @@
   titleizeInstructions: (previousState) ->
     unless previousState
       result = ""
-
-      @instructions.each (x) ->
-        result += JST['nodes/diff/unchanged_line'] line: x.title()
-
+      result += JST['nodes/diff/unchanged_line'] line: x.title() for x in @instructions
       result
     else
       result    = ""
@@ -22,23 +19,37 @@
       changed   = Object.extended()
       unchanged = Object.extended()

-      previousState.each (ps, i) =>
-        if !@instructions.any((cs) -> ps.name == cs.name)
-          removed[i] = ps.title
-
-      @instructions.each (cs, i) =>
+      for cs, i in @instructions
         previous = previousState.find (ps) -> ps.name == cs.name
         currentTitle = cs.title()

         if previous && previous.title == currentTitle
           unchanged[i] = previous.title
+          previous.newPosition = i
         else if previous
           changed[i] = [previous.title, currentTitle]
+          previous.newPosition = i
         else
           added[i] = currentTitle

+      extendedLength = 0
+
+      for ps, i in previousState
+        if !ps.newPosition?
+          position = 0
+
+          while --i >= 0
+            if previousState[i].newPosition?
+              position = previousState[i].newPosition+1
+              break
+
+          removed[position] ||= []
+          removed[position].push ps.title
+
       [@instructions.length, previousState.length].max().times (i) ->
-        result += JST['nodes/diff/removed_line'](line: removed[i]) if removed[i]
+        if removed[i]
+          result += JST['nodes/diff/removed_line'](line: l) for l in removed[i]
+
         result += JST['nodes/diff/added_line'](line: added[i]) if added[i]
         result += JST['nodes/diff/changed_line'](before: changed[i][0], after:changed[i][1]) if changed[i]
         result += JST['nodes/diff/unchanged_line'](line: unchanged[i]) if unchanged[i]


refactored parsedsn function

refactored parsedsn function

--- lib/sentry.coffee
+++ lib/sentry.coffee
@@ -5,16 +5,14 @@
 util    = require 'util'
 events  = require 'events'

-parseDSN = (dsn) =>
-  parsed = nodeurl.parse(dsn)
+parseDSN = (dsn) ->
   try
-    credentials =
-      project_id: parsed.path.split('/')[1]
-      key: parsed.auth.split(':')[0]
-      secret: parsed.auth.split(':')[1]
+    {auth, pathname} = nodeurl.parse dsn
+    [key, secret] = auth.split ':'
+    project_id = pathname.split('/')[1]
+    {key, secret, project_id}
   catch err
-    credentials = {}
-  return credentials
+    {}

 module.exports = class Sentry extends events.EventEmitter

@@ -29,8 +27,7 @@
     else
       @disable_message = "Credentials you passed in aren't complete."

-    _.defaults @,
-      hostname: os.hostname()
+    _.defaults @, hostname: os.hostname()

   error: (err, logger, culprit, extra = {}) =>
     unless err instanceof Error


set options in pagination helpers for tests instead of long parameter list

Signed-off-by: Dominik Richter <b7323add517e187efe0283b76511b7ed762bfe13@gmail.com>

--- test/spec/controllers/main.coffee
+++ test/spec/controllers/main.coffee
@@ -102,7 +102,8 @@
   ## Helpers:
   ##---------

-  paginateResponse = (httpBackend, baseUrl, response, action, limit=50)->
+  paginateResponse = (httpBackend, baseUrl, response, action, opts = {})->
+    limit = opts.limit || 50
     # 1. working pagination
     #    it will request page 1, get it,
     #    and request page 2 and finish
@@ -116,7 +117,8 @@
     action()
     httpBackend.flush()

-  dontPaginateResponse = (httpBackend, baseUrl, response, action, limit=50)->
+  dontPaginateResponse = (httpBackend, baseUrl, response, action, opts = {})->
+    limit = opts.limit || 50
     # 2. no pagination
     #    it will request page 1, won't get it
     #    and try without pagination


Revert sort order of statuses array

Revert sort order of statuses array

Connects to #7

change-type: patch

--- lib/status.coffee
+++ lib/status.coffee
@@ -47,11 +47,11 @@

 	# The order of statuses in this list is important, as it's reflected
 	# anywhere state are displayed -- currently in the device pie-chart.
+	{ key: exports.status.IDLE, name: 'Online' }
 	{ key: exports.status.CONFIGURING, name: 'Configuring' }
-	{ key: exports.status.IDLE, name: 'Online' }
+	{ key: exports.status.UPDATING, name: 'Updating' }
 	{ key: exports.status.OFFLINE, name: 'Offline' }
 	{ key: exports.status.POST_PROVISIONING, name: 'Post Provisioning' }
-	{ key: exports.status.UPDATING, name: 'Updating' }

 ]


move sorting fields left of search form

move sorting fields left of search form

--- public/views/widget_view.coffee
+++ public/views/widget_view.coffee
@@ -5,15 +5,20 @@
     @_grabOptions()

   template: _.template """
-

-

-

+

+

+

+

+

Loading ...