Tests for the updated Network interface

Tests for the updated Network interface

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

--- spec/Network.coffee
+++ spec/Network.coffee
@@ -0,0 +1,753 @@
+if typeof process isnt 'undefined' and process.execPath and process.execPath.match /node|iojs/
+  chai = require 'chai' unless chai
+  noflo = require '../src/lib/NoFlo.coffee'
+  path = require 'path'
+  root = path.resolve __dirname, '../'
+else
+  noflo = require 'noflo'
+  root = 'noflo'
+
+describe 'NoFlo Network', ->
+  Split = ->
+    new noflo.Component
+      inPorts:
+        in: datatype: 'all'
+      outPorts:
+        out: datatype: 'all'
+      process: (input, output) ->
+        output.sendDone
+          out: input.get 'in'
+  Merge = ->
+    new noflo.Component
+      inPorts:
+        in: datatype: 'all'
+      outPorts:
+        out: datatype: 'all'
+      process: (input, output) ->
+        output.sendDone
+          out: input.get 'in'
+  Callback = ->
+    new noflo.Component
+      inPorts:
+        in: datatype: 'all'
+        callback:
+          datatype: 'all'
+          control: true
+      process: (input, output) ->
+        # Drop brackets
+        return unless input.hasData 'callback', 'in'
+        cb = input.getData 'callback'
+        data = input.getData 'in'
+        cb data
+        output.done()
+
+  describe 'with an empty graph', ->
+    g = null
+    n = null
+    before (done) ->
+      g = new noflo.Graph
+      g.baseDir = root
+      noflo.createNetwork g,
+        subscribeGraph: false
+        delay: true
+      , (err, network) ->
+        return done err if err
+        n = network
+        n.connect done
+    it 'should initially be marked as stopped', ->
+      chai.expect(n.isStarted()).to.equal false
+    it 'should initially have no processes', ->
+      chai.expect(n.processes).to.be.empty
+    it 'should initially have no active processes', ->
+      chai.expect(n.getActiveProcesses()).to.eql []
+    it 'should initially have to connections', ->
+      chai.expect(n.connections).to.be.empty
+    it 'should initially have no IIPs', ->
+      chai.expect(n.initials).to.be.empty
+    it 'should have reference to the graph', ->
+      chai.expect(n.graph).to.equal g
+    it 'should know its baseDir', ->
+      chai.expect(n.baseDir).to.equal g.baseDir
+    it 'should have a ComponentLoader', ->
+      chai.expect(n.loader).to.be.an 'object'
+    it 'should have transmitted the baseDir to the Component Loader', ->
+      chai.expect(n.loader.baseDir).to.equal g.baseDir
+    it 'should be able to list components', (done) ->
+      @timeout 60 * 1000
+      n.loader.listComponents (err, components) ->
+        return done err if err
+        chai.expect(components).to.be.an 'object'
+        done()
+      return
+    it 'should have an uptime', ->
+      chai.expect(n.uptime()).to.be.at.least 0
+
+    describe 'with new node', ->
+      it 'should contain the node', (done) ->
+        n.addNode
+          id: 'Graph'
+          component: 'Graph'
+          metadata:
+            foo: 'Bar'
+        , done
+      it 'should have registered the node with the graph', ->
+        node = g.getNode 'Graph'
+        chai.expect(node).to.be.an 'object'
+        chai.expect(node.component).to.equal 'Graph'
+      it 'should have transmitted the node metadata to the process', ->
+        chai.expect(n.processes.Graph.component.metadata).to.exist
+        chai.expect(n.processes.Graph.component.metadata).to.be.an 'object'
+        chai.expect(n.processes.Graph.component.metadata).to.eql g.getNode('Graph').metadata
+      it 'adding the same node again should be a no-op', (done) ->
+        originalProcess = n.getNode 'Graph'
+        graphNode = g.getNode 'Graph'
+        n.addNode graphNode, (err, newProcess) ->
+          return done err if err
+          chai.expect(newProcess).to.equal originalProcess
+          done()
+      it 'should not contain the node after removal', (done) ->
+        n.removeNode
+          id: 'Graph'
+        , (err) ->
+          return done err if err
+          chai.expect(n.processes).to.be.empty
+          done()
+      it 'should have removed the node from the graph', ->
+        node = g.getNode 'graph'
+        chai.expect(node).to.be.a 'null'
+      it 'should fail when removing the removed node again', (done) ->
+        n.removeNode
+          id: 'Graph'
+        , (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'not found'
+          done()
+    describe 'with new edge', ->
+      before (done) ->
+        n.loader.components.Split = Split
+        n.addNode
+          id: 'A'
+          component: 'Split'
+        , (err) ->
+          return done err if err
+          n.addNode
+            id: 'B'
+            component: 'Split'
+          , done
+      after (done) ->
+        n.removeNode
+          id: 'A'
+        , (err) ->
+          return done err if err
+          n.removeNode
+            id: 'B'
+          , done
+      it 'should contain the edge', (done) ->
+        n.addEdge
+          from:
+            node: 'A'
+            port: 'out'
+          to:
+            node: 'B'
+            port: 'in'
+        , (err) ->
+          return done err if err
+          chai.expect(n.connections).not.to.be.empty
+          chai.expect(n.connections[0].from).to.eql
+            process: n.getNode 'A'
+            port: 'out'
+            index: undefined
+          chai.expect(n.connections[0].to).to.eql
+            process: n.getNode 'B'
+            port: 'in'
+            index: undefined
+          done()
+      it 'should have registered the edge with the graph', ->
+        edge = g.getEdge 'A', 'out', 'B', 'in'
+        chai.expect(edge).to.not.be.a 'null'
+      it 'should not contain the edge after removal', (done) ->
+        n.removeEdge
+          from:
+            node: 'A'
+            port: 'out'
+          to:
+            node: 'B'
+            port: 'in'
+        , (err) ->
+          return done err if err
+          chai.expect(n.connections).to.be.empty
+          done()
+      it 'should have removed the edge from the graph', ->
+        edge = g.getEdge 'A', 'out', 'B', 'in'
+        chai.expect(edge).to.be.a 'null'
+
+  describe 'with a simple graph', ->
+    g = null
+    n = null
+    cb = null
+    before (done) ->
+      @timeout 60 * 1000
+      g = new noflo.Graph
+      g.baseDir = root
+      g.addNode 'Merge', 'Merge'
+      g.addNode 'Callback', 'Callback'
+      g.addEdge 'Merge', 'out', 'Callback', 'in'
+      g.addInitial (data) ->
+        chai.expect(data).to.equal 'Foo'
+        cb()
+      , 'Callback', 'callback'
+      g.addInitial 'Foo', 'Merge', 'in'
+      noflo.createNetwork g,
+        subscribeGraph: false
+        delay: true
+      , (err, nw) ->
+        return done err if err
+        nw.loader.components.Split = Split
+        nw.loader.components.Merge = Merge
+        nw.loader.components.Callback = Callback
+        n = nw
+        nw.connect done
+
+    it 'should send some initials when started', (done) ->
+      chai.expect(n.initials).not.to.be.empty
+      cb = done
+      n.start (err) ->
+        return done err if err
+
+    it 'should contain two processes', ->
+      chai.expect(n.processes).to.not.be.empty
+      chai.expect(n.processes.Merge).to.exist
+      chai.expect(n.processes.Merge).to.be.an 'Object'
+      chai.expect(n.processes.Callback).to.exist
+      chai.expect(n.processes.Callback).to.be.an 'Object'
+    it 'the ports of the processes should know the node names', ->
+      for name, port of n.processes.Callback.component.inPorts.ports
+        chai.expect(port.name).to.equal name
+        chai.expect(port.node).to.equal 'Callback'
+        chai.expect(port.getId()).to.equal "Callback #{name.toUpperCase()}"
+      for name, port of n.processes.Callback.component.outPorts.ports
+        chai.expect(port.name).to.equal name
+        chai.expect(port.node).to.equal 'Callback'
+        chai.expect(port.getId()).to.equal "Callback #{name.toUpperCase()}"
+
+    it 'should contain 1 connection between processes and 2 for IIPs', ->
+      chai.expect(n.connections).to.not.be.empty
+      chai.expect(n.connections.length).to.equal 3
+
+    it 'should have started in debug mode', ->
+      chai.expect(n.debug).to.equal true
+      chai.expect(n.getDebug()).to.equal true
+
+    it 'should emit a process-error when a component throws', (done) ->
+      n.removeInitial
+        to:
+          node: 'Callback'
+          port: 'callback'
+      , (err) ->
+        return done err if err
+        n.removeInitial
+          to:
+            node: 'Merge'
+            port: 'in'
+        , (err) ->
+          return done err if err
+          n.addInitial
+            from:
+              data: (data) -> throw new Error 'got Foo'
+            to:
+              node: 'Callback'
+              port: 'callback'
+          , (err) ->
+            return done err if err
+            n.addInitial
+              from:
+                data: 'Foo'
+              to:
+                node: 'Merge'
+                port: 'in'
+            , (err) ->
+              return done err if err
+              n.once 'process-error', (err) ->
+                chai.expect(err).to.be.an 'object'
+                chai.expect(err.id).to.equal 'Callback'
+                chai.expect(err.metadata).to.be.an 'object'
+                chai.expect(err.error).to.be.an 'error'
+                chai.expect(err.error.message).to.equal 'got Foo'
+                done()
+              n.sendInitials (err) ->
+                return done err if err
+
+    describe 'with a renamed node', ->
+      it 'should have the process in a new location', (done) ->
+        n.renameNode 'Callback', 'Func', (err) ->
+          return done err if err
+          chai.expect(n.processes.Func).to.be.an 'object'
+          done()
+      it 'shouldn\'t have the process in the old location', ->
+        chai.expect(n.processes.Callback).to.be.undefined
+      it 'should have updated the name in the graph', ->
+        chai.expect(n.getNode('Callback')).to.not.exist
+        chai.expect(n.getNode('Func')).to.exist
+      it 'should fail to rename with the old name', (done) ->
+        n.renameNode 'Callback', 'Func', (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'not found'
+          done()
+      it 'should have informed the ports of their new node name', ->
+        for name, port of n.processes.Func.component.inPorts.ports
+          chai.expect(port.name).to.equal name
+          chai.expect(port.node).to.equal 'Func'
+          chai.expect(port.getId()).to.equal "Func #{name.toUpperCase()}"
+        for name, port of n.processes.Func.component.outPorts.ports
+          chai.expect(port.name).to.equal name
+          chai.expect(port.node).to.equal 'Func'
+          chai.expect(port.getId()).to.equal "Func #{name.toUpperCase()}"
+
+    describe 'with process icon change', ->
+      it 'should emit an icon event', (done) ->
+        n.once 'icon', (data) ->
+          chai.expect(data).to.be.an 'object'
+          chai.expect(data.id).to.equal 'Func'
+          chai.expect(data.icon).to.equal 'flask'
+          done()
+        n.processes.Func.component.setIcon 'flask'
+
+    describe 'once stopped', ->
+      it 'should be marked as stopped', (done) ->
+        n.stop ->
+          chai.expect(n.isStarted()).to.equal false
+          done()
+
+    describe 'without the delay option', ->
+      it 'should auto-start', (done) ->
+        newGraph = noflo.graph.loadJSON g.toJSON(), (err, graph) ->
+          return done err if err
+          # Pass the already-initialized component loader
+          graph.componentLoader = n.loader
+          graph.removeInitial 'Func', 'callback'
+          graph.addInitial (data) ->
+            chai.expect(data).to.equal 'Foo'
+            done()
+          , 'Func', 'callback'
+          noflo.createNetwork graph,
+            subscribeGraph: false
+            delay: false
+          , (err, nw) ->
+            return done err if err
+          return
+
+  describe 'with nodes containing default ports', ->
+    g = null
+    testCallback = null
+    c = null
+    cb = null
+
+    beforeEach ->
+      testCallback = null
+      c = null
+      cb = null
+
+      c = new noflo.Component
+      c.inPorts.add 'in',
+        required: true
+        datatype: 'string'
+        default: 'default-value',
+      c.outPorts.add 'out'
+      c.process (input, output) ->
+        output.sendDone input.get 'in'
+
+      cb = new noflo.Component
+      cb.inPorts.add 'in',
+        required: true
+        datatype: 'all'
+      cb.process (input, output) ->
+        return unless input.hasData 'in'
+        testCallback input.getData 'in'
+
+      g = new noflo.Graph
+      g.baseDir = root
+      g.addNode 'Def', 'Def'
+      g.addNode 'Cb', 'Cb'
+      g.addEdge 'Def', 'out', 'Cb', 'in'
+
+    it 'should send default values to nodes without an edge', (done) ->
+      @timeout 60 * 1000
+      testCallback = (data) ->
+        chai.expect(data).to.equal 'default-value'
+        done()
+      noflo.createNetwork g,
+        subscribeGraph: false
+        delay: true
+      , (err, nw) ->
+        return done err if err
+        nw.loader.components.Def = -> c
+        nw.loader.components.Cb = -> cb
+        nw.connect (err) ->
+          return done err if err
+          nw.start (err) ->
+            return done err if err
+
+    it 'should not send default values to nodes with an edge', (done) ->
+      @timeout 60 * 1000
+      testCallback = (data) ->
+        chai.expect(data).to.equal 'from-edge'
+        done()
+      g.addNode 'Merge', 'Merge'
+      g.addEdge 'Merge', 'out', 'Def', 'in'
+      g.addInitial 'from-edge', 'Merge', 'in'
+      noflo.createNetwork g,
+        subscribeGraph: false
+        delay: true
+      , (err, nw) ->
+        return done err if err
+        nw.loader.components.Def = -> c
+        nw.loader.components.Cb = -> cb
+        nw.loader.components.Merge = Merge
+        nw.connect (err) ->
+          return done err if err
+          nw.start (err) ->
+            return done err if err
+
+    it 'should not send default values to nodes with IIP', (done) ->
+      @timeout 60 * 1000
+      testCallback = (data) ->
+        chai.expect(data).to.equal 'from-IIP'
+        done()
+      g.addInitial 'from-IIP', 'Def', 'in'
+      noflo.createNetwork g,
+        subscribeGraph: false
+        delay: true
+      , (err, nw) ->
+        return done err if err
+        nw.loader.components.Def = -> c
+        nw.loader.components.Cb = -> cb
+        nw.loader.components.Merge = Merge
+        nw.connect (err) ->
+          return done err if err
+          nw.start (err) ->
+            return done err if err
+
+  describe 'with an existing IIP', ->
+    g = null
+    n = null
+    before ->
+      g = new noflo.Graph
+      g.baseDir = root
+      g.addNode 'Callback', 'Callback'
+      g.addNode 'Repeat', 'Split'
+      g.addEdge 'Repeat', 'out', 'Callback', 'in'
+    it 'should call the Callback with the original IIP value', (done) ->
+      @timeout 6000
+      cb = (packet) ->
+        chai.expect(packet).to.equal 'Foo'
+        done()
+      g.addInitial cb, 'Callback', 'callback'
+      g.addInitial 'Foo', 'Repeat', 'in'
+      setTimeout ->
+        noflo.createNetwork g,
+          delay: true
+          subscribeGraph: false
+        , (err, nw) ->
+          return done err if err
+          nw.loader.components.Split = Split
+          nw.loader.components.Merge = Merge
+          nw.loader.components.Callback = Callback
+          n = nw
+          nw.connect (err) ->
+            return done err if err
+            nw.start (err) ->
+              return done err if err
+      , 10
+    it 'should allow removing the IIPs', (done) ->
+      n.removeInitial
+        to:
+          node: 'Callback'
+          port: 'callback'
+      , (err) ->
+        return done err if err
+        n.removeInitial
+          to:
+            node: 'Repeat'
+            port: 'in'
+        , (err) ->
+          return done err if err
+          chai.expect(n.initials.length).to.equal 0, 'No IIPs left'
+          chai.expect(n.connections.length).to.equal 1, 'Only one connection'
+          done()
+    it 'new IIPs to replace original ones should work correctly', (done) ->
+      cb = (packet) ->
+        chai.expect(packet).to.equal 'Baz'
+        done()
+      n.addInitial
+        from:
+          data: cb
+        to:
+          node: 'Callback'
+          port: 'callback'
+      , (err) ->
+        return done err if err
+        n.addInitial
+          from:
+            data: 'Baz'
+          to:
+            node: 'Repeat'
+            port: 'in'
+        , (err) ->
+          return done err if err
+          n.start (err) ->
+            return done err if err
+
+    describe 'on stopping', ->
+      it 'processes should be running before the stop call', ->
+        chai.expect(n.started).to.be.true
+        chai.expect(n.processes.Repeat.component.started).to.equal true
+      it 'should emit the end event', (done) ->
+        @timeout 5000
+        # Ensure we have a connection open
+        n.once 'end', (endTimes) ->
+          chai.expect(endTimes).to.be.an 'object'
+          done()
+        n.stop (err) ->
+          return done err if err
+      it 'should have called the shutdown method of each process', ->
+        chai.expect(n.processes.Repeat.component.started).to.equal false
+
+  describe 'with a very large network', ->
+    it 'should be able to connect without errors', (done) ->
+      @timeout 100000
+      g = new noflo.Graph
+      g.baseDir = root
+      called = 0
+      for n in [0..10000]
+        g.addNode "Repeat#{n}", 'Split'
+      g.addNode 'Callback', 'Callback'
+      for n in [0..10000]
+        g.addEdge "Repeat#{n}", 'out', 'Callback', 'in'
+      g.addInitial ->
+        called++
+      , 'Callback', 'callback'
+      for n in [0..10000]
+        g.addInitial n, "Repeat#{n}", 'in'
+
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader.components.Split = Split
+        nw.loader.components.Callback = Callback
+        nw.once 'end', ->
+          chai.expect(called).to.equal 10001
+          done()
+        nw.connect (err) ->
+          return done err if err
+          nw.start (err) ->
+            return done err if err
+      return
+
+  describe 'with a faulty graph', ->
+    loader = null
+    before (done) ->
+      loader = new noflo.ComponentLoader root
+      loader.listComponents (err) ->
+        return done err if err
+        loader.components.Split = Split
+        done()
+    it 'should fail on connect with non-existing component', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Baz'
+      g.addNode 'Repeat2', 'Split'
+      g.addEdge 'Repeat1', 'out', 'Repeat2', 'in'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'not available'
+          done()
+    it 'should fail on connect with missing target port', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      g.addNode 'Repeat2', 'Split'
+      g.addEdge 'Repeat1', 'out', 'Repeat2', 'foo'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'No inport'
+          done()
+    it 'should fail on connect with missing source port', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      g.addNode 'Repeat2', 'Split'
+      g.addEdge 'Repeat1', 'foo', 'Repeat2', 'in'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'No outport'
+          done()
+    it 'should fail on connect with missing IIP target port', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      g.addNode 'Repeat2', 'Split'
+      g.addEdge 'Repeat1', 'out', 'Repeat2', 'in'
+      g.addInitial 'hello', 'Repeat1', 'baz'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'No inport'
+          done()
+    it 'should fail on connect with node without component', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      g.addNode 'Repeat2'
+      g.addEdge 'Repeat1', 'out', 'Repeat2', 'in'
+      g.addInitial 'hello', 'Repeat1', 'in'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          chai.expect(err).to.be.an 'error'
+          chai.expect(err.message).to.contain 'No component defined'
+          done()
+    it 'should fail to add an edge to a missing outbound node', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          return done err if err
+          nw.addEdge {
+            from:
+              node: 'Repeat2'
+              port: 'out'
+            to:
+              node: 'Repeat1'
+              port: 'in'
+          }, (err) ->
+            chai.expect(err).to.be.an 'error'
+            chai.expect(err.message).to.contain 'No process defined for outbound node'
+            done()
+    it 'should fail to add an edge to a missing inbound node', (done) ->
+      g = new noflo.Graph
+      g.addNode 'Repeat1', 'Split'
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        nw.loader = loader
+        nw.connect (err) ->
+          return done err if err
+          nw.addEdge {
+            from:
+              node: 'Repeat1'
+              port: 'out'
+            to:
+              node: 'Repeat2'
+              port: 'in'
+          }, (err) ->
+            chai.expect(err).to.be.an 'error'
+            chai.expect(err.message).to.contain 'No process defined for inbound node'
+            done()
+  describe 'baseDir setting', ->
+    it 'should set baseDir based on given graph', (done) ->
+      g = new noflo.Graph
+      g.baseDir = root
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        chai.expect(nw.baseDir).to.equal root
+        done()
+    it 'should fall back to CWD if graph has no baseDir', (done) ->
+      return @skip() if noflo.isBrowser()
+      g = new noflo.Graph
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        chai.expect(nw.baseDir).to.equal process.cwd()
+        done()
+    it 'should set the baseDir for the component loader', (done) ->
+      g = new noflo.Graph
+      g.baseDir = root
+      noflo.createNetwork g,
+        delay: true
+        subscribeGraph: false
+      , (err, nw) ->
+        return done err if err
+        chai.expect(nw.baseDir).to.equal root
+        chai.expect(nw.loader.baseDir).to.equal root
+        done()
+  describe 'debug setting', ->
+    n = null
+    g = null
+    before (done) ->
+      g = new noflo.Graph
+      g.baseDir = root
+      noflo.createNetwork g,
+        subscribeGraph: false
+        default: true
+      , (err, network) ->
+        return done err if err
+        n = network
+        n.loader.components.Split = Split
+        n.addNode
+          id: 'A'
+          component: 'Split'
+        , (err) ->
+          return done err if err
+          n.addNode
+            id: 'B'
+            component: 'Split'
+          , (err) ->
+            return done err if err
+            n.addEdge
+              from:
+                node: 'A'
+                port: 'out'
+              to:
+                node: 'B'
+                port: 'in'
+            , (err) ->
+              return done err if err
+              n.connect done
+    it 'should initially have debug enabled', ->
+      chai.expect(n.getDebug()).to.equal true
+    it 'should have propagated debug setting to connections', ->
+      chai.expect(n.connections[0].debug).to.equal n.getDebug()
+    it 'calling setDebug with same value should be no-op', ->
+      n.setDebug true
+      chai.expect(n.getDebug()).to.equal true
+      chai.expect(n.connections[0].debug).to.equal n.getDebug()
+    it 'disabling debug should get propagated to connections', ->
+      n.setDebug false
+      chai.expect(n.getDebug()).to.equal false
+      chai.expect(n.connections[0].debug).to.equal n.getDebug()


allow overwriting database size

allow overwriting database size

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


making the build available

making the build available


Add TSV parser

Add TSV parser

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

--- src/tools/tsv.coffee
+++ src/tools/tsv.coffee
@@ -0,0 +1,52 @@
+#
+# TSV parser
+#
+module.exports =
+tsv = (s)->
+  a2o arrays s
+
+arrays = (s)->
+  L = ''
+  F = []
+  res = []
+
+  test = (re)->
+    re.test s
+    L += RegExp.leftContext
+    s = RegExp.rightContext
+
+  while s.length
+    if q
+      test /""?|$/
+      switch RegExp.lastMatch
+        when '"'
+          q = false
+          continue
+        when '""'
+          L += '"'
+          continue
+        when ''
+          eol = true
+    else
+      test /\t|"|\r\n?|\n|$/
+      if '"' == RegExp.lastMatch
+        q = true
+        continue
+      eol = "\t" != RegExp.lastMatch
+    F.push L
+    L = ''
+    continue unless eol
+    res.push F
+    F = []
+  res
+
+a2o = (arr)->
+  res = []
+  for line in arr when line.length > 1 or line[0].length > 0
+    unless F
+      F = line
+      continue
+    res.push rec = {}
+    for n, i in F
+      rec[F] = line[i]
+  res


added test entry-point

added test entry-point

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


AC: Add rough outline for UI interaction test suite

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

--- test/spec/tt.ui.spec.coffee
+++ test/spec/tt.ui.spec.coffee
@@ -0,0 +1,59 @@
+describe "UI interactions", ->
+
+  describe "Tags", ->
+
+    say "I click on a tag", ->
+
+      it "should show up in the tag list", ->
+
+      it "should only show stories with that matching tag", ->
+
+      also "I click on an active tag in a story", ->
+
+        it "should do nothing", ->
+
+      also "I click on an active tag in the tag list", ->
+
+        it "should disable that tag and filter", ->
+
+  describe "Users", ->
+
+    say "I click on a user in a story", ->
+
+      it "should show up in the tag list", ->
+
+      it "should only show stories with that matching user", ->
+
+      also "I click on an active user in the tag list", ->
+
+        it "should disable that tag and filter", ->
+
+  describe "Columns", ->
+
+    say "I click the close button on a column", ->
+
+      it "should look disabled in the column list", ->
+
+      it "should no longer be visible in the main content area", ->
+
+      also "I click on the disabled column in the column list", ->
+
+        it "should look enabled in the column list", ->
+
+        it "should once again be visible in the main content area", ->
+
+  describe "Projects", ->
+
+    say "I click the project initials in a story", ->
+
+      it "should only display that project as active in the project list", ->
+
+      it "should be the only project visible in the main content area", ->
+
+    say "I click a disabled project in the project list", ->
+
+      it "should look enabled in the project list", ->
+
+      it "should make the project stories visible in the main content area", ->
+
+  describe "Search", ->


Add hero. autocomplete entries

Add hero. autocomplete entries

Adding up to 10 highest importance hero. duplicate autocomplete entries
that include ‘hero.’
Increasing max suggestions allowed from 10 to 20

--- app/views/play/level/tome/editor/zatanna.coffee
+++ app/views/play/level/tome/editor/zatanna.coffee
@@ -201,7 +201,7 @@
           # Hide popup if more than 10 suggestions
           # TODO: Completions aren't asked for unless we show popup, so this is super hacky
           # TODO: Backspacing to yield more suggestions does not close popup
-          if editor.completer?.completions?.filtered?.length > 10
+          if editor.completer?.completions?.filtered?.length > 20
             editor.completer.detach()

           # Update popup CSS after it's been launched
@@ -244,6 +244,7 @@

   addCodeCombatSnippets: (level, spellView, e) ->
     snippetEntries = []
+    source = spellView.getSource()
     haveFindNearestEnemy = false
     haveFindNearest = false
     for group, props of e.propGroups
@@ -279,7 +280,6 @@
               else 'while true'
           # For now, update autocomplete to use hero instead of self/this, if hero is already used in the source.
           # Later, we should make this happen all the time - or better yet update the snippets.
-          source = spellView.getSource()
           if /hero/.test(source) or not /(self[\.\:]|this\.|\@)/.test(source)
             thisToken =
               'python': /self/,
@@ -318,6 +318,15 @@
         attackEntry.content = attackEntry.content.replace '${1:enemy}', '"${1:Enemy Name}"'
       snippetEntries.push attackEntry

+    # Add copied hero. entries for most important ones that start with hero.
+    sortedEntries = _.sortBy snippetEntries, (entry) -> -1 * parseInt(entry.importance ? 0)
+    for entry in sortedEntries
+      if entry.content?.indexOf('hero.') is 0
+        newEntry = _.cloneDeep(entry)
+        entry.name = "hero.#{newEntry.name}"
+        snippetEntries.push(newEntry)
+        break if snippetEntries.length - sortedEntries.length >= 10
+
     if haveFindNearest and not haveFindNearestEnemy
       spellView.translateFindNearest()


Bug: Non-200 HTTP Responses are returning an error

When uploading a file with a POST request, it is acceptable to respond
with a 201 created status code.  Dropzone was treating a 201 as an error,
this commit treats all 2XX status codes as a success.

References:
 * http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

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

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


Hide loading animation of failed to load

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


few changes

few changes


fixed angular admin view error

fixed angular admin view error

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


client: remove requireMembership util

client: remove requireMembership util

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

--- client/app/lib/util/requireMembership.coffee
+++ client/app/lib/util/requireMembership.coffee
@@ -1,41 +0,0 @@
-isLoggedIn = require './isLoggedIn'
-notify_ = require './notify_'
-kd = require 'kd'
-globals = require 'globals'
-joinGroup_ = require './joinGroup_'
-
-module.exports = (options = {}) ->
-
-  { callback, onFailMsg, onFail, silence, tryAgain, groupName } = options
-  unless isLoggedIn()
-    # if there is fail message, display it
-    if onFailMsg
-      notify_ onFailMsg, 'error'
-
-    # if there is fail method, call it
-    onFail?()
-
-    # if it's not a silent operation redirect
-    unless silence
-      kd.getSingleton('router').handleRoute '/Login',
-        entryPoint : globals.config.entryPoint
-
-    # if there is callback and we want to try again
-    if callback? and tryAgain
-      unless kd.lastFuncCall
-        kd.lastFuncCall = callback
-
-        mainController = kd.getSingleton('mainController')
-        mainController.once 'accountChanged.to.loggedIn', ->
-          if isLoggedIn()
-            kd.lastFuncCall?()
-            kd.lastFuncCall = null
-            if groupName
-              joinGroup_ groupName, (err) ->
-                return notify_ "Joining #{groupName} group failed", 'error'  if err
-  else if groupName
-    joinGroup_ groupName, (err) ->
-      return notify_ "Joining #{groupName} group failed", 'error'  if err
-      callback?()
-  else
-    callback?()


David badges

David badges

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


update http resource endpoint

update http resource endpoint

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


Support a standalone page for the Buy Now FAQ

--- src/desktop/apps/page/index.coffee
+++ src/desktop/apps/page/index.coffee
@@ -24,6 +24,7 @@
 app.get '/rrf-emerging-curator-competition-official-rules', routes.vanityUrl('rrf-emerging-curator-competition-official-rules')
 app.get '/past-privacy-8-5-13', routes.vanityUrl('past-privacy-8-5-13')
 app.get '/past-terms-9-26-13', routes.vanityUrl('past-terms-9-26-13')
+app.get '/buy-now-feature-faq', routes.vanityUrl('buy-now-feature-faq')

 app.get '/page/:id', routes.index
 app.get '/job/:id', routes.index


Cleaned up and expanded functionality

Cleaned up and expanded functionality

--- example/ArrayTest/client/transitioner.coffee
+++ example/ArrayTest/client/transitioner.coffee
@@ -1,42 +1,44 @@
-@CreateTransitions = (Transitions, LastPage, Page) ->
+# Creates the actual strings inside the object
+CreateTransitions = (Transitions, LastPage, Page) ->
+  console.log 'From: ' + LastPage + ' to ' + Page
+
   # Create object for direction of motion
   ForwardPageKey = LastPage + '->' + Page
   Transitions[ForwardPageKey] = 'right-to-left'
   # Then create the same concept in reverse
   ReversePageKey = Page + '->' + LastPage
   Transitions[ReversePageKey] = 'left-to-right'
+  Transitions

-@TransitionOrder = (Pages) ->
+# Creates an object matching the desired output
+TransitionOrder = (Pages) ->
   # init vars
   Transitions = {}
   LastPage = ''
-  # Loop through array of named flow routes
-  _.each Pages, (Page) ->
-    unless LastPage is ''
-      # console.log Page
-      CreateTransitions(Transitions, LastPage, Page)
-    # Store last page, to compare against
-    LastPage = Page
-    console.log LastPage
+  NumPages = Pages.length
+  PageIndex = 0
+
+  # Loop through string function and update Transitions object
+  while PageIndex < Pages.length
+    LastIndex = 0
+    while LastIndex < PageIndex
+      # unless LastIndex is -1
+      Transitions = CreateTransitions(Transitions, Pages[LastIndex], Pages[PageIndex])
+      LastIndex++
+    PageIndex++

   # Set default value to fade
   Transitions['default'] = 'fade'
-  # console.log Transitions
-
+  console.log Transitions
   # Return transitions to Transitioner.setTransitions
   Transitions

-# Old demo of variable
+# Desired Output:
 # window.Transitions = {
-#   'AdminCompilation->ManageMechanicNotes_Form': 'right-to-left'
-#   'ManageMechanicNotes_Form->AdminCompilation': 'left-to-right'
+#   '1->2': 'right-to-left'
+#   '2->1': 'left-to-right'
 #   'default': 'fade'
 # }

-# Order from left to right and the above function will spit out necessary object
-Transitioner.setTransitions TransitionOrder [
-  '1'
-  '2'
-  '3'
-  '4'
-]+# Order of pages from left to right
+Transitioner.setTransitions TransitionOrder [ '1', '2', '3', '4']


showing error message of creating employee fixed

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


initial commit

initial commit

--- drm-accordion.coffee
+++ drm-accordion.coffee
@@ -0,0 +1,50 @@
+###############################################################################
+# Toggles hiding and showing content with an accordion efffect
+###############################################################################
+
+( ($) ->
+
+	drmAccordion = {
+		container: $ '.drm-accordion'
+		content: $ '.drm-accordion-inner'
+
+		config: {
+			speed: 200,
+			state: $('.drm-accordion').data 'state'
+		}
+
+		init: (config) ->
+			$.extend @.config, config
+			# if no defaultState value is supplied, hide content
+			if drmAccordion.config.state == 'expanded' then @.content.show() else @.content.hide()
+
+			$('<button></button>', {
+				text: 'Show All',
+				class: 'drm-show-all drm-button-inline'
+			}).prependTo(@.container).on 'click', @.showAll
+
+			$('<button></button>', {
+				text: 'Hide All',
+				class: 'drm-hide-all drm-button-inline'
+			}).prependTo(@.container).on 'click', @.hideAll
+
+			@.container.on 'click', '.drm-accordion-label', @.toggle
+
+		toggle: ->
+			content = $(@).next()
+			speed = drmAccordion.config.speed
+			if ( content.is(':hidden') )
+				content.slideDown(speed).siblings('.drm-accordion-inner').slideUp speed
+			else
+				content.slideUp speed
+
+		showAll: ->
+			drmAccordion.content.slideDown drmAccordion.config.speed
+
+		hideAll: ->
+			drmAccordion.content.slideUp drmAccordion.config.speed
+	}
+
+	drmAccordion.init()
+
+) jQuery


Add test for plugins.on|off overrides

Add test for plugins.on|off overrides

--- test/helpers.coffee
+++ test/helpers.coffee
@@ -8,3 +8,25 @@
       unix = require './fixtures/unix_config'
       win = require './fixtures/win_config'
       expect(helpers.replaceConfigSlashes unix.config).to.eql win.config
+
+  describe 'applyOverrides()', ->
+    applyOverrides = helpers.__get__ 'applyOverrides'
+
+    it 'should resolve plugins.on|off merge', ->
+      config =
+        plugins:
+          on: ['a']
+          off: ['b']
+        overrides:
+          foo:
+            plugins:
+              on: ['b']
+          bar:
+            plugins:
+              off: ['a']
+          baz:
+            plugins:
+              on: ['c']
+
+      applyOverrides config, env: ['foo', 'bar', 'baz']
+      expect(config.plugins).to.eql {on: ['c', 'b'], off: ['a']}


enhance history/push state

enhance history/push state

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


bettered examples

bettered examples

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


tests

tests

error: pathspec 'test/can-see-broadcast-sent.coffee' did not match any file(s) known to git

--- test/can-see-broadcast-sent.coffee
+++ test/can-see-broadcast-sent.coffee
@@ -0,0 +1,116 @@
+mongojs = require 'mongojs'
+Datastore = require 'meshblu-core-datastore'
+WhitelistManager = require '../src/whitelist-manager'
+
+describe 'WhitelistManager', ->
+  beforeEach (done) ->
+    @datastore = new Datastore
+      database: mongojs('test-whitelist-manager')
+      collection: 'devices'
+    @datastore.remove => done()
+
+  beforeEach ->
+    @uuidAliasResolver = resolve: (uuid, callback) => callback(null, uuid)
+
+    @sut = new WhitelistManager {@datastore, @uuidAliasResolver}
+
+  describe '->canSeeBroadcastsSent', ->
+    describe 'when called with a valid broadcaster and subscriber', ->
+      beforeEach (done) ->
+        device =
+          uuid: 'oh boy'
+
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        device =
+          uuid: 'great-scott'
+          meshblu:
+            version: '2.0.0'
+            whitelists:
+              broadcast:
+                sent:
+                  ohBoy: {}
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        @sut.canSeeBroadcastsSent broadcaster: 'great-scott', subscriber: 'ohBoy' , (error, @canSeeBroadcastsSent) =>
+          done error
+
+      it 'should have a can broadcast sent of true', ->
+        expect(@canSeeBroadcastsSent).to.be.true
+
+    describe 'when subscriber and broadcaster are the same', ->
+      beforeEach (done) ->
+        device =
+          uuid: 'ohBoy'
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        @sut.canSeeBroadcastsSent subscriber: 'ohBoy', broadcaster: 'ohBoy', (error, @canSeeBroadcastsSent) =>
+          done error
+
+      it 'should have a can broadcast sent of true', ->
+        expect(@canSeeBroadcastsSent).to.be.true
+
+    describe 'when called with a invalid subscriber, broadcaster', ->
+      beforeEach (done) ->
+        device =
+          uuid: 'ya son'
+          meshblu:
+            version: '2.0.0'
+            whitelists:
+              broadcast:
+                sent:
+                  ohBoy: {}
+
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        device =
+          uuid: 'for real'
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        @sut.canSeeBroadcastsSent subscriber: 'ya son', broadcaster: 'for real', (error, @canSeeBroadcastsSent) =>
+          done error
+
+      it 'should have a can broadcast sent of false', ->
+        expect(@canSeeBroadcastsSent).to.be.false
+
+    describe 'when subscriber and broadcaster are the same', ->
+      beforeEach (done) ->
+        device =
+          uuid: 'oh boy'
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        @sut.canSeeBroadcastsSent broadcaster: 'oh boy', subscriber: 'oh boy', (error, @canSeeBroadcastsSent) =>
+          done error
+
+      it 'should have a can broadcast sent of true', ->
+        expect(@canSeeBroadcastsSent).to.be.true
+
+    describe 'when called with a invalid subscriber, broadcaster', ->
+      beforeEach (done) ->
+        device =
+          uuid: 'ya son'
+          meshblu:
+            version: '2.0.0'
+            whitelists:
+              broadcast:
+                sent:
+                  'not for real': true
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        device =
+          uuid: 'for real'
+        @datastore.insert device, done
+
+      beforeEach (done) ->
+        @sut.canSeeBroadcastsSent broadcaster: 'ya son', subscriber: 'for real', (error, @canSeeBroadcastsSent) =>
+          done error
+
+      it 'should have a can broadcast sent of false', ->
+        expect(@canSeeBroadcastsSent).to.be.false


updating created_at time when adding measure snapshot to project.

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


fix spaces in memview.

fix spaces in memview.

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


Removed unused function.

Removed unused function.

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


Tweak command description

Tweak command description

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -219,7 +219,7 @@

   "LinkHints.activateMode": ["Open a link in the current tab"]
   "LinkHints.activateModeToOpenInNewTab": ["Open a link in a new tab"]
-  "LinkHints.activateModeToOpenInNewForegroundTab": ["Open a link in a new tab, switch to it"]
+  "LinkHints.activateModeToOpenInNewForegroundTab": ["Open a link in a new tab & switch to it"]
   "LinkHints.activateModeWithQueue": ["Open multiple links in a new tab"]

   "LinkHints.activateModeToOpenIncognito": ["Open a link in incognito window"]


checkpoint on bestofyourtown publishing middleware

 On branch master

	modified:   nodejs_server/middleware/boyt_publish.coffee

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


Remove whitespace.

Remove whitespace.

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


showcase: add ShowcaseAppView

showcase: add ShowcaseAppView

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

--- client/showcase/lib/appview.coffee
+++ client/showcase/lib/appview.coffee
@@ -0,0 +1,11 @@
+kd = require 'kd'
+
+module.exports = class ShowcaseAppView extends kd.CustomHTMLView
+
+  constructor: (options = {}, data) ->
+
+    options.cssClass = 'ShowcaseApp'
+
+    super options, data
+
+


Coffeescripting it up a bit

Coffeescripting it up a bit

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


Add bowercopy task

Add bowercopy task

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


change linter

change linter

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


sort answer choices

sort answer choices

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

--- app/assets/javascripts/hanuman/controllers/answer_choices.js.coffee
+++ app/assets/javascripts/hanuman/controllers/answer_choices.js.coffee
@@ -0,0 +1,3 @@
+App.AnswerChoicesController = Ember.ArrayController.extend({
+  sortProperties: ['option_text']
+})


forgot a comma

forgot a comma

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


Changed to use logger.

Changed to use logger.

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


Add package specs

Add package specs

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

--- spec/chinese-translator-spec.coffee
+++ spec/chinese-translator-spec.coffee
@@ -0,0 +1,146 @@
+describe 'Chinese Translator', ->
+  [activationPromise, editor, editorView, onDidChangeSpy] = []
+
+  hasCommand = (element, name) ->
+    commands = atom.commands.findCommands(target: element)
+    found = true for command in commands when command.name is name
+    found
+
+  translate = (command, callback) ->
+    atom.commands.dispatch(editorView, "chinese-translator:#{command}")
+    waitsForPromise ->
+      activationPromise
+    runs ->
+      waitsFor ->
+        onDidChangeSpy.callCount > 1
+      runs(callback)
+
+  beforeEach ->
+    waitsForPromise ->
+      atom.workspace.open()
+    runs ->
+      editor = atom.workspace.getActiveTextEditor()
+      editorView = atom.views.getView(editor)
+      activationPromise = atom.packages.activatePackage('chinese-translator')
+
+      onDidChangeSpy = jasmine.createSpy('onDidChange')
+      editor.onDidChange(onDidChangeSpy)
+
+  describe 'when the package activates', ->
+    it 'creates the commands', ->
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-simplified-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-taiwan-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-hong-kong-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-traditional-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard-with-phrases')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-hong-kong-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese-with-phrases')).toBeTruthy()
+      expect(hasCommand(editorView, 'chinese-translator:hong-kong-standard-to-simplified-chinese')).toBeTruthy()
+
+  describe 'when the package deactivates', ->
+    beforeEach ->
+      atom.packages.deactivatePackage('chinese-translator')
+    it 'removes all commands', ->
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-simplified-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-taiwan-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-hong-kong-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-traditional-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard-with-phrases')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-hong-kong-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese-with-phrases')).toBeFalsy()
+      expect(hasCommand(editorView, 'chinese-translator:hong-kong-standard-to-simplified-chinese')).toBeFalsy()
+
+  describe 'when no text is selected', ->
+    it 'translates all text in the editor', ->
+      editor.setText('這段文字會翻譯為簡體中文。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'traditional-chinese-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('这段文字会翻译为简体中文。')
+    it 'translates all text with line-break in the editor', ->
+      editor.setText("""
+        這段文字會翻譯為簡體中文。
+        換行之後也是一樣。
+      """)
+      editor.setCursorBufferPosition([0, 0])
+      translate 'traditional-chinese-to-simplified-chinese', ->
+        expect(editor.getText()).toBe("""
+          这段文字会翻译为简体中文。
+          换行之后也是一样。
+        """)
+
+  describe 'when some text are selected', ->
+    it 'translates the selected text', ->
+      editor.setText '這段文字「引號裡面的文字」會翻譯為簡體中文。'
+      editor.setSelectedBufferRange([[0, 5], [0, 12]])
+      translate 'traditional-chinese-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('這段文字「引号里面的文字」會翻譯為簡體中文。')
+
+  describe 'when there are multiple selection ranges', ->
+    it 'translates the text in each selection range', ->
+      editor.setText '這段文字「這個引號裡面的文字」和「這個引號裡面的文字」會翻譯為簡體中文。'
+      editor.addSelectionForBufferRange([[0, 5], [0, 14]])
+      editor.addSelectionForBufferRange([[0, 17], [0, 26]])
+      translate 'traditional-chinese-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('這段文字「这个引号里面的文字」和「这个引号里面的文字」會翻譯為簡體中文。')
+
+  describe 'when translating from traditional chinese', ->
+    it 'translates to simplified chinese', ->
+      editor.setText('曾經有一份真誠的愛情放在我面前，我沒有珍惜，等我失去的時候我才後悔莫及。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'traditional-chinese-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('曾经有一份真诚的爱情放在我面前，我没有珍惜，等我失去的时候我才后悔莫及。')
+    it 'translates to taiwan standard', ->
+      editor.setText('着裝污染虛偽發泄稜柱羣眾裏面')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'traditional-chinese-to-taiwan-standard', ->
+        expect(editor.getText()).toBe('著裝汙染虛偽發洩稜柱群眾裡面')
+    it 'translates to hong kong standard', ->
+      editor.setText('虛偽嘆息 潮溼灶臺。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'traditional-chinese-to-hong-kong-standard', ->
+        expect(editor.getText()).toBe('虛偽歎息 潮濕灶台。')
+
+  describe 'when translating from simplified chinese', ->
+    it 'translates to traditional chinese', ->
+      editor.setText('燕燕于飞，差池其羽。之子于归，远送于野。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'simplified-chinese-to-traditional-chinese', ->
+        expect(editor.getText()).toBe('燕燕于飛，差池其羽。之子于歸，遠送於野。')
+    it 'translates to taiwan standard', ->
+      editor.setText('鲶鱼和鲇鱼是一种生物。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'simplified-chinese-to-taiwan-standard', ->
+        expect(editor.getText()).toBe('鯰魚和鯰魚是一種生物。')
+    it 'translates to taiwan standard with phrases', ->
+      editor.setText('我们在老挝的服务器的硬盘需要使用互联网算法软件解决异步的问题。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'simplified-chinese-to-taiwan-standard-with-phrases', ->
+        expect(editor.getText()).toBe('我們在寮國的伺服器的硬碟需要使用網際網路演算法軟體解決非同步的問題。')
+    it 'translates to hong kong standard', ->
+      editor.setText('虚伪叹息 潮湿灶台 沙河涌汹涌的波浪。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'simplified-chinese-to-hong-kong-standard', ->
+        expect(editor.getText()).toBe('虛偽歎息 潮濕灶台 沙河涌洶湧的波浪。')
+
+  describe 'when translating from taiwan standard', ->
+    it 'translates to simplified chinese', ->
+      editor.setText('著裝著作汙染虛偽發洩稜柱群眾裡面')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'taiwan-standard-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('着装著作污染虚伪发泄棱柱群众里面')
+    it 'translates to simplified chinese with phrases', ->
+      editor.setText('滑鼠裡面的矽二極體壞了，導致游標解析度降低。')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'taiwan-standard-to-simplified-chinese-with-phrases', ->
+        expect(editor.getText()).toBe('鼠标里面的硅二极管坏了，导致光标分辨率降低。')
+
+  describe 'when translating from hong kong standard', ->
+    it 'translates to simplified chinese', ->
+      editor.setText('虛偽歎息 潮濕灶台 沙河涌洶湧的波浪')
+      editor.setCursorBufferPosition([0, 0])
+      translate 'taiwan-standard-to-simplified-chinese', ->
+        expect(editor.getText()).toBe('虚伪叹息 潮湿灶台 沙河涌汹涌的波浪')


Complete unit testing for Elyssa.Color

Complete unit testing for Elyssa.Color

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

--- test/src/tests/types/color.coffee
+++ test/src/tests/types/color.coffee
@@ -0,0 +1,1281 @@
+describe 'Elyssa', ->
+  describe 'Types', ->
+    describe 'Color', ->
+      describe 'constructor', ->
+        it 'default value r is 0', -> new Elyssa.Color().r.should.equal(0)
+        it 'default value g is 0', -> new Elyssa.Color().g.should.equal(0)
+        it 'default value b is 0', -> new Elyssa.Color().b.should.equal(0)
+        it 'default value a is 255', -> new Elyssa.Color().a.should.equal(255)
+
+        it 'value assignment works as expected', ->
+          colorObject =
+            r: ~~(Math.random() * 255)
+            g: ~~(Math.random() * 255)
+            b: ~~(Math.random() * 255)
+            a: ~~(Math.random() * 255)
+
+          color = new Elyssa.Color colorObject
+
+          color.r.should.equal colorObject.r
+          color.g.should.equal colorObject.g
+          color.b.should.equal colorObject.b
+          color.a.should.equal colorObject.a
+
+        it 'constructor with string works as expected', ->
+          color = new Elyssa.Color 'blue'
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it 'constructor with false string value returns default color', ->
+          color = new Elyssa.Color 'traaaaaainzzz'
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+      describe '#toHex()', ->
+        it 'black color is #000', -> new Elyssa.Color({r: 0, g: 0, b: 0}).toHex().should.equal('#000')
+        it 'white color is #fff', -> new Elyssa.Color({r: 255, g: 255, b: 255}).toHex().should.equal('#fff')
+
+      describe '#toString()', ->
+        it 'black color is rgb(0, 0, 0)', -> new Elyssa.Color({r: 0, g: 0, b: 0}).toString().should.equal('rgb(0, 0, 0)')
+
+      describe '#lighten()', ->
+        it 'lighten() should not change anything', ->
+          color = new Elyssa.Color().lighten()
+
+          color.r.should.equal(0)
+          color.g.should.equal(0)
+          color.b.should.equal(0)
+        it 'lighten(0) should not change anything', ->
+          color = new Elyssa.Color().lighten(0)
+
+          color.r.should.equal(0)
+          color.g.should.equal(0)
+          color.b.should.equal(0)
+        it 'lighten(1.0) converts black color to white color', ->
+          whiteColor = new Elyssa.Color().lighten(1.0)
+
+          whiteColor.r.should.equal(255)
+          whiteColor.g.should.equal(255)
+          whiteColor.b.should.equal(255)
+
+      describe '#darken()', ->
+        it 'darken() should not change anything', ->
+          color = new Elyssa.Color({r: 255, g: 255, b: 255}).darken()
+
+          color.r.should.equal(255)
+          color.g.should.equal(255)
+          color.b.should.equal(255)
+        it 'darken(0) should not change anything', ->
+          color = new Elyssa.Color({r: 255, g: 255, b: 255}).darken(0)
+
+          color.r.should.equal(255)
+          color.g.should.equal(255)
+          color.b.should.equal(255)
+        it 'darken(1.0) converts white color to black color', ->
+          blackColor = new Elyssa.Color({r: 255, g: 255, b: 255}).darken(1.0)
+
+          blackColor.r.should.equal(0)
+          blackColor.g.should.equal(0)
+          blackColor.b.should.equal(0)
+
+      describe '#fadeIn()', ->
+        it 'fadeIn() should not change anything', -> new Elyssa.Color({a: 0}).fadeIn().a.should.equal(0)
+        it 'fadeIn(0) should not change anything', -> new Elyssa.Color({a: 0}).fadeIn(0).a.should.equal(0)
+
+        it 'fadeIn(0.5) turns alpha value 0 into 128', -> new Elyssa.Color({a: 0}).fadeIn(0.5).a.should.equal(128)
+        it 'fadeIn(0.5) turns alpha value 128 into 255', -> new Elyssa.Color({a: 128}).fadeIn(0.5).a.should.equal(255)
+
+        it 'fadeIn(1.0) turns alpha value 0 into 255', -> new Elyssa.Color({a: 0}).fadeIn(1.0).a.should.equal(255)
+        it 'fadeIn(5.0) should act the same as fadeIn(1.0)', -> new Elyssa.Color({a: 0}).fadeIn(5.0).a.should.equal(255)
+
+      describe '#fadeOut()', ->
+        it 'fadeOut() should not change anything', -> new Elyssa.Color().fadeOut().a.should.equal(255)
+        it 'fadeOut(0) should not change anything', -> new Elyssa.Color().fadeOut(0).a.should.equal(255)
+
+        it 'fadeOut(0.5) turns alpha value 128 into 0', -> new Elyssa.Color({a: 128}).fadeOut(0.5).a.should.equal(0)
+        it 'fadeOut(0.5) turns alpha value 255 into 127', -> new Elyssa.Color().fadeOut(0.5).a.should.equal(127)
+
+        it 'fadeOut(1.0) turns alpha value 255 into 0', -> new Elyssa.Color().fadeOut(1.0).a.should.equal(0)
+        it 'fadeOut(5.0) should act the same as fadeOut(1.0)', -> new Elyssa.Color().fadeOut(5.0).a.should.equal(0)
+
+      describe 'Static color functions', ->
+        it '.aqua()', ->
+          color = Elyssa.Color.aqua()
+
+          color.r.should.equal 0
+          color.g.should.equal 255
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.black()', ->
+          color = Elyssa.Color.black()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.blue()', ->
+          color = Elyssa.Color.blue()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.fuchsia()', ->
+          color = Elyssa.Color.fuchsia()
+
+          color.r.should.equal 255
+          color.g.should.equal 0
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.gray()', ->
+          color = Elyssa.Color.gray()
+
+          color.r.should.equal 128
+          color.g.should.equal 128
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.grey()', ->
+          color = Elyssa.Color.grey()
+
+          color.r.should.equal 128
+          color.g.should.equal 128
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.green()', ->
+          color = Elyssa.Color.green()
+
+          color.r.should.equal 0
+          color.g.should.equal 128
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.lime()', ->
+          color = Elyssa.Color.lime()
+
+          color.r.should.equal 0
+          color.g.should.equal 255
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.maroon()', ->
+          color = Elyssa.Color.maroon()
+
+          color.r.should.equal 128
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.navy()', ->
+          color = Elyssa.Color.navy()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.olive()', ->
+          color = Elyssa.Color.olive()
+
+          color.r.should.equal 128
+          color.g.should.equal 128
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.purple()', ->
+          color = Elyssa.Color.purple()
+
+          color.r.should.equal 128
+          color.g.should.equal 0
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.gray()', ->
+          color = Elyssa.Color.red()
+
+          color.r.should.equal 255
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.silver()', ->
+          color = Elyssa.Color.silver()
+
+          color.r.should.equal 192
+          color.g.should.equal 192
+          color.b.should.equal 192
+          color.a.should.equal 255
+
+        it '.teal()', ->
+          color = Elyssa.Color.teal()
+
+          color.r.should.equal 0
+          color.g.should.equal 128
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.white()', ->
+          color = Elyssa.Color.white()
+
+          color.r.should.equal 255
+          color.g.should.equal 255
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.yellow()', ->
+          color = Elyssa.Color.yellow()
+
+          color.r.should.equal 255
+          color.g.should.equal 255
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.transparent()', ->
+          color = Elyssa.Color.transparent()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 0
+
+        it '.aliceBlue()', ->
+          color = Elyssa.Color.aliceBlue()
+
+          color.r.should.equal 240
+          color.g.should.equal 248
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.antiqueWhite()', ->
+          color = Elyssa.Color.antiqueWhite()
+
+          color.r.should.equal 250
+          color.g.should.equal 235
+          color.b.should.equal 215
+          color.a.should.equal 255
+
+        it '.azure()', ->
+          color = Elyssa.Color.azure()
+
+          color.r.should.equal 240
+          color.g.should.equal 255
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.beige()', ->
+          color = Elyssa.Color.beige()
+
+          color.r.should.equal 245
+          color.g.should.equal 245
+          color.b.should.equal 220
+          color.a.should.equal 255
+
+        it '.bisque()', ->
+          color = Elyssa.Color.bisque()
+
+          color.r.should.equal 255
+          color.g.should.equal 228
+          color.b.should.equal 196
+          color.a.should.equal 255
+
+        it '.blanchedAlmond()', ->
+          color = Elyssa.Color.blanchedAlmond()
+
+          color.r.should.equal 255
+          color.g.should.equal 235
+          color.b.should.equal 205
+          color.a.should.equal 255
+
+        it '.blueViolet()', ->
+          color = Elyssa.Color.blueViolet()
+
+          color.r.should.equal 138
+          color.g.should.equal 43
+          color.b.should.equal 226
+          color.a.should.equal 255
+
+        it '.brown()', ->
+          color = Elyssa.Color.brown()
+
+          color.r.should.equal 165
+          color.g.should.equal 42
+          color.b.should.equal 42
+          color.a.should.equal 255
+
+        it '.burlyWood()', ->
+          color = Elyssa.Color.burlyWood()
+
+          color.r.should.equal 222
+          color.g.should.equal 184
+          color.b.should.equal 135
+          color.a.should.equal 255
+
+        it '.cadetBlue()', ->
+          color = Elyssa.Color.cadetBlue()
+
+          color.r.should.equal 95
+          color.g.should.equal 158
+          color.b.should.equal 160
+          color.a.should.equal 255
+
+        it '.chartreuse()', ->
+          color = Elyssa.Color.chartreuse()
+
+          color.r.should.equal 127
+          color.g.should.equal 255
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.chocolate()', ->
+          color = Elyssa.Color.chocolate()
+
+          color.r.should.equal 210
+          color.g.should.equal 105
+          color.b.should.equal 30
+          color.a.should.equal 255
+
+        it '.coral()', ->
+          color = Elyssa.Color.coral()
+
+          color.r.should.equal 255
+          color.g.should.equal 127
+          color.b.should.equal 80
+          color.a.should.equal 255
+
+        it '.cornflowerBlue()', ->
+          color = Elyssa.Color.cornflowerBlue()
+
+          color.r.should.equal 100
+          color.g.should.equal 149
+          color.b.should.equal 237
+          color.a.should.equal 255
+
+        it '.cornsilk()', ->
+          color = Elyssa.Color.cornsilk()
+
+          color.r.should.equal 255
+          color.g.should.equal 248
+          color.b.should.equal 220
+          color.a.should.equal 255
+
+        it '.crimson()', ->
+          color = Elyssa.Color.crimson()
+
+          color.r.should.equal 220
+          color.g.should.equal 20
+          color.b.should.equal 60
+          color.a.should.equal 255
+
+        it '.cyan()', ->
+          color = Elyssa.Color.cyan()
+
+          color.r.should.equal 0
+          color.g.should.equal 255
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.darkBlue()', ->
+          color = Elyssa.Color.darkBlue()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 139
+          color.a.should.equal 255
+
+        it '.darkCyan()', ->
+          color = Elyssa.Color.darkCyan()
+
+          color.r.should.equal 0
+          color.g.should.equal 139
+          color.b.should.equal 139
+          color.a.should.equal 255
+
+        it '.darkGoldenRod()', ->
+          color = Elyssa.Color.darkGoldenRod()
+
+          color.r.should.equal 184
+          color.g.should.equal 134
+          color.b.should.equal 11
+          color.a.should.equal 255
+
+        it '.darkGray()', ->
+          color = Elyssa.Color.darkGray()
+
+          color.r.should.equal 169
+          color.g.should.equal 169
+          color.b.should.equal 169
+          color.a.should.equal 255
+
+        it '.darkGrey()', ->
+          color = Elyssa.Color.darkGrey()
+
+          color.r.should.equal 169
+          color.g.should.equal 169
+          color.b.should.equal 169
+          color.a.should.equal 255
+
+        it '.darkGreen()', ->
+          color = Elyssa.Color.darkGreen()
+
+          color.r.should.equal 0
+          color.g.should.equal 100
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.darkKhaki()', ->
+          color = Elyssa.Color.darkKhaki()
+
+          color.r.should.equal 189
+          color.g.should.equal 183
+          color.b.should.equal 107
+          color.a.should.equal 255
+
+        it '.darkMagenta()', ->
+          color = Elyssa.Color.darkMagenta()
+
+          color.r.should.equal 139
+          color.g.should.equal 0
+          color.b.should.equal 139
+          color.a.should.equal 255
+
+        it '.darkOliveGreen()', ->
+          color = Elyssa.Color.darkOliveGreen()
+
+          color.r.should.equal 85
+          color.g.should.equal 107
+          color.b.should.equal 47
+          color.a.should.equal 255
+
+        it '.darkOrange()', ->
+          color = Elyssa.Color.darkOrange()
+
+          color.r.should.equal 255
+          color.g.should.equal 140
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.darkOrchid()', ->
+          color = Elyssa.Color.darkOrchid()
+
+          color.r.should.equal 153
+          color.g.should.equal 50
+          color.b.should.equal 204
+          color.a.should.equal 255
+
+        it '.darkRed()', ->
+          color = Elyssa.Color.darkRed()
+
+          color.r.should.equal 139
+          color.g.should.equal 0
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.darkSalmon()', ->
+          color = Elyssa.Color.darkSalmon()
+
+          color.r.should.equal 233
+          color.g.should.equal 150
+          color.b.should.equal 122
+          color.a.should.equal 255
+
+        it '.darkSeaGreen()', ->
+          color = Elyssa.Color.darkSeaGreen()
+
+          color.r.should.equal 143
+          color.g.should.equal 188
+          color.b.should.equal 143
+          color.a.should.equal 255
+
+        it '.darkSlateBlue()', ->
+          color = Elyssa.Color.darkSlateBlue()
+
+          color.r.should.equal 72
+          color.g.should.equal 61
+          color.b.should.equal 139
+          color.a.should.equal 255
+
+        it '.darkSlateGray()', ->
+          color = Elyssa.Color.darkSlateGray()
+
+          color.r.should.equal 47
+          color.g.should.equal 79
+          color.b.should.equal 79
+          color.a.should.equal 255
+
+        it '.darkSlateGrey', ->
+          color = Elyssa.Color.darkSlateGrey()
+
+          color.r.should.equal 47
+          color.g.should.equal 79
+          color.b.should.equal 79
+          color.a.should.equal 255
+
+        it '.darkTurquoise()', ->
+          color = Elyssa.Color.darkTurquoise()
+
+          color.r.should.equal 0
+          color.g.should.equal 206
+          color.b.should.equal 209
+          color.a.should.equal 255
+
+        it '.darkViolet()', ->
+          color = Elyssa.Color.darkViolet()
+
+          color.r.should.equal 148
+          color.g.should.equal 0
+          color.b.should.equal 211
+          color.a.should.equal 255
+
+        it '.deepPink()', ->
+          color = Elyssa.Color.deepPink()
+
+          color.r.should.equal 255
+          color.g.should.equal 20
+          color.b.should.equal 147
+          color.a.should.equal 255
+
+        it '.deepSkyBlue()', ->
+          color = Elyssa.Color.deepSkyBlue()
+
+          color.r.should.equal 0
+          color.g.should.equal 191
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.dimGray()', ->
+          color = Elyssa.Color.dimGray()
+
+          color.r.should.equal 105
+          color.g.should.equal 105
+          color.b.should.equal 105
+          color.a.should.equal 255
+
+        it '.dimGrey()', ->
+          color = Elyssa.Color.dimGrey()
+
+          color.r.should.equal 105
+          color.g.should.equal 105
+          color.b.should.equal 105
+          color.a.should.equal 255
+
+        it '.dodgerBlue()', ->
+          color = Elyssa.Color.dodgerBlue()
+
+          color.r.should.equal 30
+          color.g.should.equal 144
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.fireBrick()', ->
+          color = Elyssa.Color.fireBrick()
+
+          color.r.should.equal 178
+          color.g.should.equal 34
+          color.b.should.equal 34
+          color.a.should.equal 255
+
+        it '.floralWhite()', ->
+          color = Elyssa.Color.floralWhite()
+
+          color.r.should.equal 255
+          color.g.should.equal 250
+          color.b.should.equal 240
+          color.a.should.equal 255
+
+        it '.forestGreen()', ->
+          color = Elyssa.Color.forestGreen()
+
+          color.r.should.equal 34
+          color.g.should.equal 139
+          color.b.should.equal 34
+          color.a.should.equal 255
+
+        it '.gainsboro()', ->
+          color = Elyssa.Color.gainsboro()
+
+          color.r.should.equal 220
+          color.g.should.equal 220
+          color.b.should.equal 220
+          color.a.should.equal 255
+
+        it '.ghostWhite()', ->
+          color = Elyssa.Color.ghostWhite()
+
+          color.r.should.equal 248
+          color.g.should.equal 248
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.gold()', ->
+          color = Elyssa.Color.gold()
+
+          color.r.should.equal 255
+          color.g.should.equal 215
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.goldenRod()', ->
+          color = Elyssa.Color.goldenRod()
+
+          color.r.should.equal 218
+          color.g.should.equal 165
+          color.b.should.equal 32
+          color.a.should.equal 255
+
+        it '.greenYellow()', ->
+          color = Elyssa.Color.greenYellow()
+
+          color.r.should.equal 173
+          color.g.should.equal 255
+          color.b.should.equal 47
+          color.a.should.equal 255
+
+        it '.honeyDew()', ->
+          color = Elyssa.Color.honeyDew()
+
+          color.r.should.equal 240
+          color.g.should.equal 255
+          color.b.should.equal 240
+          color.a.should.equal 255
+
+        it '.hotPink()', ->
+          color = Elyssa.Color.hotPink()
+
+          color.r.should.equal 255
+          color.g.should.equal 105
+          color.b.should.equal 180
+          color.a.should.equal 255
+
+        it '.indianRed()', ->
+          color = Elyssa.Color.indianRed()
+
+          color.r.should.equal 205
+          color.g.should.equal 92
+          color.b.should.equal 92
+          color.a.should.equal 255
+
+        it '.indigo()', ->
+          color = Elyssa.Color.indigo()
+
+          color.r.should.equal 75
+          color.g.should.equal 0
+          color.b.should.equal 130
+          color.a.should.equal 255
+
+        it '.ivory()', ->
+          color = Elyssa.Color.ivory()
+
+          color.r.should.equal 255
+          color.g.should.equal 255
+          color.b.should.equal 240
+          color.a.should.equal 255
+
+        it '.khaki()', ->
+          color = Elyssa.Color.khaki()
+
+          color.r.should.equal 240
+          color.g.should.equal 230
+          color.b.should.equal 140
+          color.a.should.equal 255
+
+        it '.lavender()', ->
+          color = Elyssa.Color.lavender()
+
+          color.r.should.equal 230
+          color.g.should.equal 230
+          color.b.should.equal 250
+          color.a.should.equal 255
+
+        it '.lavenderBlush()', ->
+          color = Elyssa.Color.lavenderBlush()
+
+          color.r.should.equal 255
+          color.g.should.equal 240
+          color.b.should.equal 245
+          color.a.should.equal 255
+
+        it '.lawnGreen()', ->
+          color = Elyssa.Color.lawnGreen()
+
+          color.r.should.equal 124
+          color.g.should.equal 252
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.lemonChiffon()', ->
+          color = Elyssa.Color.lemonChiffon()
+
+          color.r.should.equal 255
+          color.g.should.equal 250
+          color.b.should.equal 205
+          color.a.should.equal 255
+
+        it '.lightBlue()', ->
+          color = Elyssa.Color.lightBlue()
+
+          color.r.should.equal 173
+          color.g.should.equal 216
+          color.b.should.equal 230
+          color.a.should.equal 255
+
+        it '.lightCoral()', ->
+          color = Elyssa.Color.lightCoral()
+
+          color.r.should.equal 240
+          color.g.should.equal 128
+          color.b.should.equal 128
+          color.a.should.equal 255
+
+        it '.lightCyan()', ->
+          color = Elyssa.Color.lightCyan()
+
+          color.r.should.equal 224
+          color.g.should.equal 255
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.lightGoldenRodYellow()', ->
+          color = Elyssa.Color.lightGoldenRodYellow()
+
+          color.r.should.equal 250
+          color.g.should.equal 250
+          color.b.should.equal 210
+          color.a.should.equal 255
+
+        it '.lightGray()', ->
+          color = Elyssa.Color.lightGray()
+
+          color.r.should.equal 211
+          color.g.should.equal 211
+          color.b.should.equal 211
+          color.a.should.equal 255
+
+        it '.lightGrey', ->
+          color = Elyssa.Color.lightGrey()
+
+          color.r.should.equal 211
+          color.g.should.equal 211
+          color.b.should.equal 211
+          color.a.should.equal 255
+
+        it '.lightGreen()', ->
+          color = Elyssa.Color.lightGreen()
+
+          color.r.should.equal 144
+          color.g.should.equal 238
+          color.b.should.equal 144
+          color.a.should.equal 255
+
+        it '.lightPink()', ->
+          color = Elyssa.Color.lightPink()
+
+          color.r.should.equal 255
+          color.g.should.equal 182
+          color.b.should.equal 193
+          color.a.should.equal 255
+
+        it '.lightSalmon()', ->
+          color = Elyssa.Color.lightSalmon()
+
+          color.r.should.equal 255
+          color.g.should.equal 160
+          color.b.should.equal 122
+          color.a.should.equal 255
+
+        it '.lightSeaGreen()', ->
+          color = Elyssa.Color.lightSeaGreen()
+
+          color.r.should.equal 32
+          color.g.should.equal 178
+          color.b.should.equal 170
+          color.a.should.equal 255
+
+        it '.lightSkyBlue()', ->
+          color = Elyssa.Color.lightSkyBlue()
+
+          color.r.should.equal 135
+          color.g.should.equal 206
+          color.b.should.equal 250
+          color.a.should.equal 255
+
+        it '.lightSlateGray()', ->
+          color = Elyssa.Color.lightSlateGray()
+
+          color.r.should.equal 119
+          color.g.should.equal 136
+          color.b.should.equal 153
+          color.a.should.equal 255
+
+        it '.lightSlateGrey', ->
+          color = Elyssa.Color.lightSlateGrey()
+
+          color.r.should.equal 119
+          color.g.should.equal 136
+          color.b.should.equal 153
+          color.a.should.equal 255
+
+        it '.lightSteelBlue()', ->
+          color = Elyssa.Color.lightSteelBlue()
+
+          color.r.should.equal 176
+          color.g.should.equal 196
+          color.b.should.equal 222
+          color.a.should.equal 255
+
+        it '.lightYellow()', ->
+          color = Elyssa.Color.lightYellow()
+
+          color.r.should.equal 255
+          color.g.should.equal 255
+          color.b.should.equal 224
+          color.a.should.equal 255
+
+        it '.limeGreen()', ->
+          color = Elyssa.Color.limeGreen()
+
+          color.r.should.equal 50
+          color.g.should.equal 205
+          color.b.should.equal 50
+          color.a.should.equal 255
+
+        it '.linen()', ->
+          color = Elyssa.Color.linen()
+
+          color.r.should.equal 250
+          color.g.should.equal 240
+          color.b.should.equal 230
+          color.a.should.equal 255
+
+        it '.magenta', ->
+          color = Elyssa.Color.magenta()
+
+          color.r.should.equal 255
+          color.g.should.equal 0
+          color.b.should.equal 255
+          color.a.should.equal 255
+
+        it '.mediumAquaMarine()', ->
+          color = Elyssa.Color.mediumAquaMarine()
+
+          color.r.should.equal 102
+          color.g.should.equal 205
+          color.b.should.equal 170
+          color.a.should.equal 255
+
+        it '.mediumBlue()', ->
+          color = Elyssa.Color.mediumBlue()
+
+          color.r.should.equal 0
+          color.g.should.equal 0
+          color.b.should.equal 205
+          color.a.should.equal 255
+
+        it '.mediumOrchid()', ->
+          color = Elyssa.Color.mediumOrchid()
+
+          color.r.should.equal 186
+          color.g.should.equal 85
+          color.b.should.equal 211
+          color.a.should.equal 255
+
+        it '.mediumPurple()', ->
+          color = Elyssa.Color.mediumPurple()
+
+          color.r.should.equal 157
+          color.g.should.equal 112
+          color.b.should.equal 219
+          color.a.should.equal 255
+
+        it '.mediumSeaGreen()', ->
+          color = Elyssa.Color.mediumSeaGreen()
+
+          color.r.should.equal 60
+          color.g.should.equal 179
+          color.b.should.equal 113
+          color.a.should.equal 255
+
+        it '.mediumSlateBlue()', ->
+          color = Elyssa.Color.mediumSlateBlue()
+
+          color.r.should.equal 123
+          color.g.should.equal 104
+          color.b.should.equal 238
+          color.a.should.equal 255
+
+        it '.mediumSpringGreen()', ->
+          color = Elyssa.Color.mediumSpringGreen()
+
+          color.r.should.equal 0
+          color.g.should.equal 250
+          color.b.should.equal 154
+          color.a.should.equal 255
+
+        it '.mediumTurquoise()', ->
+          color = Elyssa.Color.mediumTurquoise()
+
+          color.r.should.equal 72
+          color.g.should.equal 209
+          color.b.should.equal 204
+          color.a.should.equal 255
+
+        it '.mediumVioletRed()', ->
+          color = Elyssa.Color.mediumVioletRed()
+
+          color.r.should.equal 199
+          color.g.should.equal 21
+          color.b.should.equal 133
+          color.a.should.equal 255
+
+        it '.midnightBlue()', ->
+          color = Elyssa.Color.midnightBlue()
+
+          color.r.should.equal 25
+          color.g.should.equal 25
+          color.b.should.equal 112
+          color.a.should.equal 255
+
+        it '.mintCream()', ->
+          color = Elyssa.Color.mintCream()
+
+          color.r.should.equal 245
+          color.g.should.equal 255
+          color.b.should.equal 250
+          color.a.should.equal 255
+
+        it '.mistyRose()', ->
+          color = Elyssa.Color.mistyRose()
+
+          color.r.should.equal 255
+          color.g.should.equal 228
+          color.b.should.equal 225
+          color.a.should.equal 255
+
+        it '.moccasin()', ->
+          color = Elyssa.Color.moccasin()
+
+          color.r.should.equal 255
+          color.g.should.equal 228
+          color.b.should.equal 181
+          color.a.should.equal 255
+
+        it '.navajoWhite()', ->
+          color = Elyssa.Color.navajoWhite()
+
+          color.r.should.equal 255
+          color.g.should.equal 222
+          color.b.should.equal 173
+          color.a.should.equal 255
+
+        it '.oldLace()', ->
+          color = Elyssa.Color.oldLace()
+
+          color.r.should.equal 253
+          color.g.should.equal 245
+          color.b.should.equal 230
+          color.a.should.equal 255
+
+        it '.oliveDrab()', ->
+          color = Elyssa.Color.oliveDrab()
+
+          color.r.should.equal 107
+          color.g.should.equal 142
+          color.b.should.equal 35
+          color.a.should.equal 255
+
+        it '.orange()', ->
+          color = Elyssa.Color.orange()
+
+          color.r.should.equal 255
+          color.g.should.equal 165
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.orangeRed()', ->
+          color = Elyssa.Color.orangeRed()
+
+          color.r.should.equal 255
+          color.g.should.equal 69
+          color.b.should.equal 0
+          color.a.should.equal 255
+
+        it '.orchid()', ->
+          color = Elyssa.Color.orchid()
+
+          color.r.should.equal 218
+          color.g.should.equal 112
+          color.b.should.equal 214
+          color.a.should.equal 255
+
+        it '.paleGoldenRod()', ->
+          color = Elyssa.Color.paleGoldenRod()
+
+          color.r.should.equal 238
+          color.g.should.equal 232
+          color.b.should.equal 170
+          color.a.should.equal 255
+
+        it '.paleGreen()', ->
+          color = Elyssa.Color.paleGreen()
+
+          color.r.should.equal 152
+          color.g.should.equal 251
+          color.b.should.equal 152
+          color.a.should.equal 255
+
+        it '.paleTurquoise()', ->
+          color = Elyssa.Color.paleTurquoise()
+
+          color.r.should.equal 175
+          color.g.should.equal 238
+          color.b.should.equal 238
+          color.a.should.equal 255
+
+        it '.paleVioletRed()', ->
+          color = Elyssa.Color.paleVioletRed()
+
+          color.r.should.equal 219
+          color.g.should.equal 112
+          color.b.should.equal 147
+          color.a.should.equal 255
+
+        it '.papayaWhip()', ->
+          color = Elyssa.Color.papayaWhip()
+
+          color.r.should.equal 255
+          color.g.should.equal 239
+          color.b.should.equal 213
+          color.a.should.equal 255
+
+        it '.peachPuff()', ->
+          color = Elyssa.Color.peachPuff()
+
+          color.r.should.equal 255
+          color.g.should.equal 218
+          color.b.should.equal 185
+          color.a.should.equal 255
+
+        it '.peru()', ->
+          color = Elyssa.Color.peru()
+
+          color.r.should.equal 205
+          color.g.should.equal 133
+          color.b.should.equal 63
+          color.a.should.equal 255
+
+        it '.pink()', ->
+          color = Elyssa.Color.pink()
+
+          color.r.should.equal 255
+          color.g.should.equal 192
+          color.b.should.equal 203
+          color.a.should.equal 255
+
+        it '.plum()', ->
+          color = Elyssa.Color.plum()
+
+          color.r.should.equal 221
+          color.g.should.equal 160
+          color.b.should.equal 221
+          color.a.should.equal 255
+
+        it '.powderBlue()', ->
+          color = Elyssa.Color.powderBlue()
+
+          color.r.should.equal 176
+          color.g.should.equal 224
+          color.b.should.equal 230
+          color.a.should.equal 255
+
+        it '.rosyBrown()', ->
+          color = Elyssa.Color.rosyBrown()
+
+          color.r.should.equal 188
+          color.g.should.equal 143
+          color.b.should.equal 143
+          color.a.should.equal 255
+
+        it '.royalBlue()', ->
+          color = Elyssa.Color.royalBlue()
+
+          color.r.should.equal 65
+          color.g.should.equal 105
+          color.b.should.equal 225
+          color.a.should.equal 255
+
+        it '.saddleBrown()', ->
+          color = Elyssa.Color.saddleBrown()
+
+          color.r.should.equal 139
+          color.g.should.equal 69
+          color.b.should.equal 19
+          color.a.should.equal 255
+
+        it '.salmon()', ->
+          color = Elyssa.Color.salmon()
+
+          color.r.should.equal 250
+          color.g.should.equal 128
+          color.b.should.equal 114
+          color.a.should.equal 255
+
+        it '.sandyBrown()', ->
+          color = Elyssa.Color.sandyBrown()
+
+          color.r.should.equal 244
+          color.g.should.equal 164
+          color.b.should.equal 96
+          color.a.should.equal 255
+
+        it '.seaGreen()', ->
+          color = Elyssa.Color.seaGreen()
+
+          color.r.should.equal 46
+          color.g.should.equal 139
+          color.b.should.equal 87
+          color.a.should.equal 255
+
+        it '.seaShell()', ->
+          color = Elyssa.Color.seaShell()
+
+          color.r.should.equal 255
+          color.g.should.equal 245
+          color.b.should.equal 238
+          color.a.should.equal 255
+
+        it '.sienna()', ->
+          color = Elyssa.Color.sienna()
+
+          color.r.should.equal 160
+          color.g.should.equal 82
+          color.b.should.equal 45
+          color.a.should.equal 255
+
+        it '.skyBlue()', ->
+          color = Elyssa.Color.skyBlue()
+
+          color.r.should.equal 135
+          color.g.should.equal 206
+          color.b.should.equal 235
+          color.a.should.equal 255
+
+        it '.slateBlue()', ->
+          color = Elyssa.Color.slateBlue()
+
+          color.r.should.equal 106
+          color.g.should.equal 90
+          color.b.should.equal 205
+          color.a.should.equal 255
+
+        it '.slateGray()', ->
+          color = Elyssa.Color.slateGray()
+
+          color.r.should.equal 112
+          color.g.should.equal 128
+          color.b.should.equal 144
+          color.a.should.equal 255
+
+        it '.slateGrey', ->
+          color = Elyssa.Color.slateGrey()
+
+          color.r.should.equal 112
+          color.g.should.equal 128
+          color.b.should.equal 144
+          color.a.should.equal 255
+
+        it '.snow()', ->
+          color = Elyssa.Color.snow()
+
+          color.r.should.equal 255
+          color.g.should.equal 250
+          color.b.should.equal 250
+          color.a.should.equal 255
+
+        it '.springGreen()', ->
+          color = Elyssa.Color.springGreen()
+
+          color.r.should.equal 0
+          color.g.should.equal 255
+          color.b.should.equal 127
+          color.a.should.equal 255
+
+        it '.steelBlue()', ->
+          color = Elyssa.Color.steelBlue()
+
+          color.r.should.equal 70
+          color.g.should.equal 130
+          color.b.should.equal 180
+          color.a.should.equal 255
+
+        it '.tan()', ->
+          color = Elyssa.Color.tan()
+
+          color.r.should.equal 210
+          color.g.should.equal 180
+          color.b.should.equal 140
+          color.a.should.equal 255
+
+        it '.thistle()', ->
+          color = Elyssa.Color.thistle()
+
+          color.r.should.equal 216
+          color.g.should.equal 191
+          color.b.should.equal 216
+          color.a.should.equal 255
+
+        it '.tomato()', ->
+          color = Elyssa.Color.tomato()
+
+          color.r.should.equal 255
+          color.g.should.equal 99
+          color.b.should.equal 71
+          color.a.should.equal 255
+
+        it '.turquoise()', ->
+          color = Elyssa.Color.turquoise()
+
+          color.r.should.equal 64
+          color.g.should.equal 224
+          color.b.should.equal 208
+          color.a.should.equal 255
+
+        it '.violet()', ->
+          color = Elyssa.Color.violet()
+
+          color.r.should.equal 238
+          color.g.should.equal 130
+          color.b.should.equal 238
+          color.a.should.equal 255
+
+        it '.wheat()', ->
+          color = Elyssa.Color.wheat()
+
+          color.r.should.equal 245
+          color.g.should.equal 222
+          color.b.should.equal 179
+          color.a.should.equal 255
+
+        it '.whiteSmoke()', ->
+          color = Elyssa.Color.whiteSmoke()
+
+          color.r.should.equal 245
+          color.g.should.equal 245
+          color.b.should.equal 245
+          color.a.should.equal 255
+
+        it '.yellowGreen()', ->
+          color = Elyssa.Color.yellowGreen()
+          color.r.should.equal 154
+          color.g.should.equal 205
+          color.b.should.equal 50
+          color.a.should.equal 255