diff --git a/js/amount.js b/js/amount.js index 36d57889b5..ea8d24095a 100644 --- a/js/amount.js +++ b/js/amount.js @@ -4,14 +4,11 @@ var utils = require('./utils.js'); var jsbn = require('./jsbn.js'); +// Don't include in browser context. +var config = require('../test/config.js'); + var BigInteger = jsbn.BigInteger; -var accounts = {}; - -var setAccounts = function (accounts_new) { - accounts = accounts_new; -}; - var UInt160 = function () { // Internal form: // 0, 1, 'iXXXXX', 20 byte string, or NaN. @@ -44,8 +41,8 @@ UInt160.prototype.copyTo = function(d) { // value = NaN on error. UInt160.prototype.parse_json = function (j) { // Canonicalize and validate - if (j in accounts) - j = accounts[j].account; + if (config.accounts && j in config.accounts) + j = config.accounts[j].account; switch (j) { case undefined: @@ -445,7 +442,6 @@ Amount.prototype.parse_issuer = function (issuer) { return this; }; -exports.setAccounts = setAccounts; exports.Amount = Amount; exports.Currency = Currency; exports.UInt160 = UInt160; diff --git a/js/remote.js b/js/remote.js index ff5532717e..ee23fc2e8f 100644 --- a/js/remote.js +++ b/js/remote.js @@ -16,6 +16,9 @@ var WebSocket = require('ws'); var Amount = require('./amount.js').Amount; var UInt160 = require('./amount.js').UInt160; +// Don't include in browser context. +var config = require('../test/config.js'); + // Request events emmitted: // 'success' : Request successful. // 'error' : Request failed. @@ -140,12 +143,11 @@ Request.prototype.ripple_state = function (account, issuer, currency) { // // --> trusted: truthy, if remote is trusted -var Remote = function (trusted, websocket_ip, websocket_port, config, trace) { +var Remote = function (trusted, websocket_ip, websocket_port, trace) { this.trusted = trusted; this.websocket_ip = websocket_ip; this.websocket_port = websocket_port; this.id = 0; - this.config = config; this.trace = trace; this.ledger_closed = undefined; this.ledger_current_index = undefined; @@ -155,6 +157,7 @@ var Remote = function (trusted, websocket_ip, websocket_port, config, trace) { this.state = 'offline'; // 'online', 'offline' this.retry_timer = undefined; this.retry = undefined; + this.config = config || { 'accounts' : {}}; // Cache information for accounts. this.accounts = { @@ -176,10 +179,10 @@ var Remote = function (trusted, websocket_ip, websocket_port, config, trace) { Remote.prototype = new EventEmitter; -var remoteConfig = function (config, server, trace) { - var serverConfig = config.servers[server]; +Remote.from_config = function (name, trace) { + var serverConfig = config.servers[name]; - return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, config, trace); + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace); }; var isTemMalformed = function (engine_result_code) { @@ -190,7 +193,7 @@ var isTefFailure = function (engine_result_code) { return (engine_result_code >= -299 && engine_result_code < 199); }; -var flags = { +Remote.flags = { 'OfferCreate' : { 'Passive' : 0x00010000, }, @@ -204,7 +207,7 @@ var flags = { }; // XXX This needs to be determined from the network. -var fees = { +Remote.fees = { 'default' : Amount.from_json("100"), 'account_create' : Amount.from_json("1000"), 'nickname_create' : Amount.from_json("1000"), @@ -233,6 +236,12 @@ Remote.prototype._set_state = function (state) { } }; +Remote.prototype.trace = function () { + this.trace = true; + + return this; +}; + // Set the target online state. Defaults to false. Remote.prototype.connect = function (online) { var target = undefined === online || online; @@ -751,7 +760,7 @@ Remote.prototype.transaction = function () { // Construction: // remote.transaction() // Build a transaction object. // .offer_create(...) // Set major parameters. -// .flags() // Set optional parameters. +// .set_flags() // Set optional parameters. // .on() // Register for events. // .submit(); // Send to network. // @@ -895,12 +904,12 @@ Transaction.prototype.submit = function () { if (undefined === transaction.Fee) { if ('Payment' === transaction.TransactionType - && transaction.Flags & exports.flags.Payment.CreateAccount) { + && transaction.Flags & Remote.flags.Payment.CreateAccount) { - transaction.Fee = fees.account_create.to_json(); + transaction.Fee = Remote.fees.account_create.to_json(); } else { - transaction.Fee = fees['default'].to_json(); + transaction.Fee = Remote.fees['default'].to_json(); } } @@ -973,9 +982,9 @@ Transaction.prototype.send_max = function (send_max) { // Add flags to a transaction. // --> flags: undefined, _flag_, or [ _flags_ ] -Transaction.prototype.flags = function (flags) { +Transaction.prototype.set_flags = function (flags) { if (flags) { - var transaction_flags = exports.flags[this.transaction.TransactionType]; + var transaction_flags = Remote.flags[this.transaction.TransactionType]; if (undefined == this.transaction.Flags) // We plan to not define this field on new Transaction. this.transaction.Flags = 0; @@ -994,8 +1003,8 @@ Transaction.prototype.flags = function (flags) { } } - if (this.transaction.Flags & exports.flags.Payment.CreateAccount) - this.transaction.Fee = fees.account_create.to_json(); + if (this.transaction.Flags & Remote.flags.Payment.CreateAccount) + this.transaction.Fee = Remote.fees.account_create.to_json(); } return this; @@ -1029,7 +1038,7 @@ Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expi this.secret = this.account_secret(src); this.transaction.TransactionType = 'OfferCreate'; this.transaction.Account = UInt160.from_json(src).to_json(); - this.transaction.Fee = fees.offer.to_json(); + this.transaction.Fee = Remote.fees.offer.to_json(); this.transaction.TakerPays = Amount.json_rewrite(taker_pays); this.transaction.TakerGets = Amount.json_rewrite(taker_gets); @@ -1077,8 +1086,5 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit }; exports.Remote = Remote; -exports.remoteConfig = remoteConfig; -exports.fees = fees; -exports.flags = flags; // vim:sw=2:sts=2:ts=8 diff --git a/test/offer-test.js b/test/offer-test.js index eeca2404bb..df67d07598 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -1,15 +1,10 @@ var async = require("async"); var buster = require("buster"); -var fs = require("fs"); - -var server = require("./server.js"); -var remote = require("../js/remote.js"); -var config = require("./config.js"); var Amount = require("../js/amount.js").Amount; - -require("../js/amount.js").setAccounts(config.accounts); +var Remote = require("../js/remote.js").Remote; +var Server = require("./server.js").Server; buster.testRunner.timeout = 5000; @@ -18,28 +13,16 @@ var alpha; buster.testCase("Offer tests", { 'setUp' : function (done) { - server.start("alpha", - function (e) { - buster.refute(e); - - alpha = remote.remoteConfig(config, "alpha", 'TRACE'); - - alpha - .once('ledger_closed', done) - .connect(); - } -// , 'MOCK' - ); + server = Server.from_config("alpha").on('started', function () { + alpha = Remote.from_config("alpha").once('ledger_closed', done) .connect(); + }).start(); }, 'tearDown' : - function (done) { + function (done) { alpha .on('disconnected', function () { - server.stop("alpha", function (e) { - buster.refute(e); - done(); - }); + server.on('stopped', done).stop(); }) .connect(false); }, @@ -190,7 +173,7 @@ buster.testCase("Offer tests", { function (callback) { alpha.transaction() .payment('root', 'alice', "1000") - .flags('CreateAccount') + .set_flags('CreateAccount') .on('proposed', function (m) { console.log("proposed: %s", JSON.stringify(m)); buster.assert.equals(m.result, 'tesSUCCESS'); @@ -283,7 +266,7 @@ buster.testCase("Offer tests", { function (callback) { alpha.transaction() .payment('root', 'alice', Amount.from_json("10000")) - .flags('CreateAccount') + .set_flags('CreateAccount') .on("proposed", function (m) { console.log("PROPOSED: CreateAccount: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS', m); diff --git a/test/remote-test.js b/test/remote-test.js index 86f31554eb..4ebf857db9 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -1,12 +1,8 @@ var buster = require("buster"); -var config = require("./config.js"); -var server = require("./server.js"); -var remote = require("../js/remote.js"); - var Amount = require("../js/amount.js").Amount; - -require("../js/amount.js").setAccounts(config.accounts); +var Remote = require("../js/remote.js").Remote; +var Server = require("./server.js").Server; var fastTearDown = true; @@ -18,26 +14,16 @@ buster.testRunner.timeout = 5000; buster.testCase("Remote functions", { 'setUp' : function (done) { - server.start("alpha", - function (e) { - buster.refute(e); - - alpha = remote.remoteConfig(config, "alpha"); - - alpha - .once('ledger_closed', done) - .connect(); - }); + server = Server.from_config("alpha").on('started', function () { + alpha = Remote.from_config("alpha").once('ledger_closed', done) .connect(); + }).start(); }, 'tearDown' : - function (done) { + function (done) { alpha .on('disconnected', function () { - server.stop("alpha", function (e) { - buster.refute(e); - done(); - }); + server.on('stopped', done).stop(); }) .connect(false); }, @@ -45,13 +31,13 @@ buster.testCase("Remote functions", { 'request_ledger_current' : function (done) { alpha.request_ledger_current().on('success', function (m) { - console.log(m); + // console.log(m); buster.assert.equals(m.ledger_current_index, 3); done(); }) .on('error', function(m) { - console.log(m); + // console.log(m); buster.assert(false); }) @@ -61,13 +47,13 @@ buster.testCase("Remote functions", { 'request_ledger_closed' : function (done) { alpha.request_ledger_closed().on('success', function (m) { - console.log("result: %s", JSON.stringify(m)); + // console.log("result: %s", JSON.stringify(m)); buster.assert.equals(m.ledger_closed_index, 2); done(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) @@ -90,14 +76,14 @@ buster.testCase("Remote functions", { done(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) .request(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) @@ -108,7 +94,7 @@ buster.testCase("Remote functions", { 'account_root remote malformedAddress' : function (done) { alpha.request_ledger_closed().on('success', function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); alpha .request_ledger_entry('account_root') @@ -120,7 +106,7 @@ buster.testCase("Remote functions", { buster.assert(false); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert.equals(m.error, 'remoteError'); buster.assert.equals(m.remote.error, 'malformedAddress'); @@ -129,7 +115,7 @@ buster.testCase("Remote functions", { .request(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) @@ -139,19 +125,19 @@ buster.testCase("Remote functions", { 'account_root entryNotFound' : function (done) { alpha.request_ledger_closed().on('success', function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); alpha .request_ledger_entry('account_root') .ledger_closed(r.ledger_closed) - .account_root(config.accounts.alice.account) + .account_root("alice") .on('success', function (r) { // console.log("account_root: %s", JSON.stringify(r)); buster.assert(false); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert.equals(m.error, 'remoteError'); buster.assert.equals(m.remote.error, 'entryNotFound'); @@ -160,7 +146,7 @@ buster.testCase("Remote functions", { .request(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }).request(); @@ -169,12 +155,12 @@ buster.testCase("Remote functions", { 'ledger_entry index' : function (done) { alpha.request_ledger_closed().on('success', function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); alpha .request_ledger_entry('index') .ledger_closed(r.ledger_closed) - .account_root(config.accounts.alice.account) + .account_root("alice") .index("2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8") .on('success', function (r) { // console.log("account_root: %s", JSON.stringify(r)); @@ -183,14 +169,14 @@ buster.testCase("Remote functions", { done(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }). request(); }) .on('error', function(m) { - console.log(m); + // console.log(m); buster.assert(false); }) @@ -201,7 +187,7 @@ buster.testCase("Remote functions", { function (done) { alpha.transaction() .payment('root', 'alice', Amount.from_json("10000")) - .flags('CreateAccount') + .set_flags('CreateAccount') .on('success', function (r) { // console.log("account_root: %s", JSON.stringify(r)); @@ -209,7 +195,7 @@ buster.testCase("Remote functions", { done(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) @@ -223,25 +209,25 @@ buster.testCase("Remote functions", { alpha.transaction() .payment('root', 'alice', Amount.from_json("10000")) - .flags('CreateAccount') + .set_flags('CreateAccount') .on('success', function (r) { - console.log("create_account: %s", JSON.stringify(r)); + // console.log("create_account: %s", JSON.stringify(r)); got_success = true; }) .on('error', function (m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) .on('final', function (m) { - console.log("final: %s", JSON.stringify(m)); + // console.log("final: %s", JSON.stringify(m)); buster.assert(got_success && got_proposed); done(); }) .on('proposed', function (m) { - console.log("proposed: %s", JSON.stringify(m)); + // console.log("proposed: %s", JSON.stringify(m)); // buster.assert.equals(m.result, 'terNO_DST'); buster.assert.equals(m.result, 'tesSUCCESS'); @@ -251,7 +237,7 @@ buster.testCase("Remote functions", { alpha.ledger_accept(); }) .on('status', function (s) { - console.log("status: %s", JSON.stringify(s)); + // console.log("status: %s", JSON.stringify(s)); }) .submit(); }, diff --git a/test/send-test.js b/test/send-test.js index 145ce34105..fa41aa8d47 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -1,40 +1,29 @@ var buster = require("buster"); -var config = require("./config.js"); -var server = require("./server.js"); -var amount = require("../js/amount.js"); -var remote = require("../js/remote.js"); - -var Amount = amount.Amount; +var Amount = require("../js/amount.js").Amount; +var Remote = require("../js/remote.js").Remote; +var Server = require("./server.js").Server; // How long to wait for server to start. var serverDelay = 1500; buster.testRunner.timeout = 5000; +var alpha; + buster.testCase("Sending", { 'setUp' : function (done) { - server.start("alpha", - function (e) { - buster.refute(e); - - alpha = remote.remoteConfig(config, "alpha"); - - alpha - .once('ledger_closed', done) - .connect(); - }); + server = Server.from_config("alpha").on('started', function () { + alpha = Remote.from_config("alpha").once('ledger_closed', done) .connect(); + }).start(); }, 'tearDown' : - function (done) { + function (done) { alpha .on('disconnected', function () { - server.stop("alpha", function (e) { - buster.refute(e); - done(); - }); + server.on('stopped', done).stop(); }) .connect(false); }, @@ -49,11 +38,11 @@ buster.testCase("Sending", { .on('success', function (r) { // Transaction sent. - console.log("success: %s", JSON.stringify(r)); + // console.log("success: %s", JSON.stringify(r)); }) .on('pending', function() { // Moving ledgers along. - console.log("missing: %d", ledgers); + // console.log("missing: %d", ledgers); ledgers -= 1; if (ledgers) { @@ -66,14 +55,14 @@ buster.testCase("Sending", { }) .on('lost', function () { // Transaction did not make it in. - console.log("lost"); + // console.log("lost"); buster.assert(true); done(); }) .on('proposed', function (m) { // Transaction got an error. - console.log("proposed: %s", JSON.stringify(m)); + // console.log("proposed: %s", JSON.stringify(m)); buster.assert.equals(m.result, 'terNO_DST'); @@ -82,13 +71,13 @@ buster.testCase("Sending", { alpha.ledger_accept(); // Move it along. }) .on('final', function (m) { - console.log("final: %s", JSON.stringify(m)); + // console.log("final: %s", JSON.stringify(m)); buster.assert(false, "Should not have got a final."); done(); }) .on('error', function(m) { - console.log("error: %s", m); + // console.log("error: %s", m); buster.assert(false); }) diff --git a/test/server-test.js b/test/server-test.js index 817b5f9fd6..24496537ef 100644 --- a/test/server-test.js +++ b/test/server-test.js @@ -1,22 +1,27 @@ var buster = require("buster"); -var server = require("./server.js"); +var Server = require("./server.js").Server; // How long to wait for server to start. -var serverDelay = 1500; +// var serverDelay = 1500; -buster.testRunner.timeout = 5000; +var alpha; buster.testCase("Standalone server startup", { "server start and stop" : function (done) { - server.start("alpha", - function (e) { - buster.refute(e); - server.stop("alpha", function (e) { - buster.refute(e); - done(); - }); - }); + alpha = Server.from_config("alpha"); + + alpha + .on('started', function () { + alpha + .on('stopped', function () { + buster.assert(true); + + done(); + }) + .stop(); + }) + .start(); } }); diff --git a/test/server.js b/test/server.js index 85efe695b9..aca9b3984b 100644 --- a/test/server.js +++ b/test/server.js @@ -1,6 +1,13 @@ -// Manage test servers +// Create and stop test servers. // -// YYY Would be nice to be able to hide server output. +// Usage: +// s = new Server(name, config) +// s.verbose() : optional +// .start() +// 'started' +// +// s.stop() : stops server is started. +// 'stopped' // // Provide servers @@ -8,29 +15,40 @@ // Servers are created in tmp/server/$server // -var config = require("./config.js"); -var nodeutils = require("../js/nodeutils.js"); +var buster = require("buster"); +var child = require("child_process"); +var fs = require("fs"); +var path = require("path"); +var util = require("util"); +var EventEmitter = require('events').EventEmitter; -var fs = require("fs"); -var path = require("path"); -var util = require("util"); -var child = require("child_process"); - -var servers = {}; +var config = require("./config.js"); +var nodeutils = require("../js/nodeutils.js"); // Create a server object -var Server = function (name, mock) { - this.name = name; - this.mock = mock; +var Server = function (name, config, verbose) { + this.name = name; + this.config = config; + this.started = false; + this.quiet = !verbose; }; -// Return a server's rippled.cfg as string. -Server.prototype.configContent = function() { - var cfg = config.servers[this.name]; +Server.prototype = new EventEmitter; - return Object.keys(cfg).map(function(o) { - return util.format("[%s]\n%s\n", o, cfg[o]); - }).join(""); +Server.from_config = function (name, verbose) { + return new Server(name, config.servers[name], verbose); +}; + +Server.prototype.on = function (e, c) { + EventEmitter.prototype.on.call(this, e, c); + + return this; +}; + +Server.prototype.once = function (e, c) { + EventEmitter.prototype.once.call(this, e, c); + + return this; }; Server.prototype.serverPath = function() { @@ -42,38 +60,51 @@ Server.prototype.configPath = function() { }; // Write a server's rippled.cfg. -Server.prototype.writeConfig = function(done) { - fs.writeFile(this.configPath(), this.configContent(), 'utf8', done); +Server.prototype._writeConfig = function(done) { + var self = this; + + fs.writeFile( + this.configPath(), + Object.keys(this.config).map(function(o) { + return util.format("[%s]\n%s\n", o, self.config[o]); + }).join(""), + 'utf8', done); }; // Spawn the server. -Server.prototype.serverSpawnSync = function() { - // Spawn in standalone mode for now. - this.child = child.spawn( - config.rippled, - [ +Server.prototype._serverSpawnSync = function() { + var self = this; + + var args = [ "-a", "-v", "--conf=rippled.cfg" - ], + ]; + + // Spawn in standalone mode for now. + this.child = child.spawn( + config.rippled, + args, { cwd: this.serverPath(), env: process.env, - stdio: 'inherit' + stdio: this.quiet ? 'ignore' : 'inherit' }); - console.log("server: start %s: %s -a --conf=%s", this.child.pid, config.rippled, this.configPath()); + if (!this.quiet) + console.log("server: start %s: %s --conf=%s", + this.child.pid, config.rippled, args.join(" "), this.configPath()); // By default, just log exits. this.child.on('exit', function(code, signal) { // If could not exec: code=127, signal=null // If regular exit: code=0, signal=null - console.log("server: spawn: server exited code=%s: signal=%s", code, signal); + if (!self.quiet) console.log("server: spawn: server exited code=%s: signal=%s", code, signal); }); }; // Prepare server's working directory. -Server.prototype.makeBase = function (done) { +Server.prototype._makeBase = function (done) { var path = this.serverPath(); var self = this; @@ -83,80 +114,59 @@ Server.prototype.makeBase = function (done) { throw e; } else { - self.writeConfig(done); + self._writeConfig(done); } }); }; +Server.prototype.verbose = function () { + this.quiet = false; + + return this; +}; + // Create a standalone server. // Prepare the working directory and spawn the server. -Server.prototype.start = function (done) { +Server.prototype.start = function () { var self = this; - if (this.mock) { - done(); - } - else { - this.makeBase(function (e) { - if (e) { - throw e; - } - else { - self.serverSpawnSync(); - done(); - } - }); - } + if (!this.quiet) console.log("server: start: %s: %s", this.name, JSON.stringify(this.config)); + + this._makeBase(function (e) { + if (e) { + throw e; + } + else { + self._serverSpawnSync(); + self.emit('started'); + } + }); + + return this; }; // Stop a standalone server. -Server.prototype.stop = function (done) { - if (this.mock) { - console.log("server: stop: mock"); - done(); - } - else if (this.child) { +Server.prototype.stop = function () { + var self = this; + + if (this.child) { // Update the on exit to invoke done. this.child.on('exit', function (code, signal) { - console.log("server: stop: server exited"); - done(); + + if (!self.quiet) console.log("server: stop: server exited"); + + self.emit('stopped'); + delete this.child; }); + this.child.kill(); } else { - console.log("server: stop: no such server"); - done('noSuchServer'); + buster.log("server: stop: can't stop"); } -}; -// Start the named server. -exports.start = function (name, done, mock) { - if (servers[name]) - { - console.log("server: start: server already started."); - } - else - { - var server = new Server(name, mock); - - servers[name] = server; - - console.log("server: start: %s", JSON.stringify(server)); - - server.start(done); - } -}; - -// Delete the named server. -exports.stop = function (name, done) { - console.log("server: stop: %s of %s", name, Object.keys(servers).toString()); - - var server = servers[name]; - if (server) { - server.stop(done); - delete servers[name]; - } + return this; }; exports.Server = Server; diff --git a/test/websocket-test.js b/test/websocket-test.js index 055a0aab23..dcfc25d5b5 100644 --- a/test/websocket-test.js +++ b/test/websocket-test.js @@ -1,8 +1,7 @@ var buster = require("buster"); -var config = require("./config.js"); -var server = require("./server.js"); -var remote = require("../js/remote.js"); +var Server = require("./server.js").Server; +var Remote = require("../js/remote.js").Remote; // How long to wait for server to start. var serverDelay = 1500; @@ -11,26 +10,14 @@ buster.testRunner.timeout = 5000; buster.testCase("WebSocket connection", { 'setUp' : - function (done) { - server.start("alpha", - function (e) { - buster.refute(e); - done(); - } - ); - }, + function (done) { server = Server.from_config("alpha").on('started', done).start(); }, 'tearDown' : - function (done) { - server.stop("alpha", function (e) { - buster.refute(e); - done(); - }); - }, + function (done) { server.on('stopped', done).stop(); }, "websocket connect and disconnect" : function (done) { - var alpha = remote.remoteConfig(config, "alpha", 'TRACE'); + var alpha = Remote.from_config("alpha"); alpha .on('connected', function () {