<commit_before>'use strict';

/**
 * Pterodactyl Daemon
 * Copyright (c) 2015 Dane Everitt <dane@daneeveritt.com>
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
const rfr = require('rfr');
const Async = require('async');
const moment = require('moment');
const _ = require('underscore');
const EventEmitter = require('events').EventEmitter;
const Querystring = require('querystring');
const Path = require('path');

const Log = rfr('src/helpers/logger.js');
const Docker = rfr('src/controllers/docker.js');
const Service = rfr('src/services/minecraft/index.js');
const Status = rfr('src/helpers/status.js');
const ConfigHelper = rfr('src/helpers/config.js');
const Websocket = rfr('src/http/socket.js');
const UploadServer = rfr('src/http/upload.js');

const Config = new ConfigHelper();

class Server extends EventEmitter {

    constructor(json, next) {
        super();
        const self = this;
        this.status = Status.OFF;
        this.json = json;
        this.uuid = this.json.uuid;
        this.processData = {
            query: {},
            process: {},
        };

        this.intervals = {
            process: undefined,
            query: undefined,
        };

        this.log = Log.child({ server: this.uuid });
        this.lastCrash = undefined;

        this.docker = new Docker(this, function constructorServer(err, status) {
            if (status === true) {
                self.log.info('Daemon detected that the server container is currently running, re-attaching to it now!');
            }
            return next(err);
        });

        this.service = new Service(this);

        this.socketIO = new Websocket(this).init();
        this.uploadSocket = new UploadServer(this).init();
    }

    hasPermission(perm, token) {
        if (typeof perm !== 'undefined' && typeof token !== 'undefined') {
            if (typeof this.json.keys !== 'undefined' && token in this.json.keys) {
                if (this.json.keys[token].indexOf(perm) > -1) {
                    return true;
                }
            }
        }
        return false;
    }

    setStatus(status) {
        if (status === this.status) return;
        const inverted = _.invert(Status);

        // If a user starts their server and then tries to stop it before the server is done
        // it triggers a crash condition. This logic determines if the server status is set to
        // stopping, and if so, we prevent changing the status to starting or on. This allows the
        // server to not crash when we press stop before it is compeltely started.
        if (this.status === Status.STOPPING && (status === Status.ON || status === Status.STARTING)) {
            this.log.debug('Recieved request to mark server as ' + inverted[status] + ' but the server is currently marked as STOPPING.');
            return;
        }

        // Handle Internal Tracking
        if (status !== Status.OFF) {
            // If an interval has not been started, start one now.
            if (typeof this.intervals.process === 'undefined') {
                this.intervals.process = setInterval(this.process, 2000, this);
            }
        } else {
            // Server has been stopped, lets clear the interval as well as any stored
            // information about the process or query. Lets also detach the stats stream.
            clearInterval(this.intervals.process);
            this.processData.process = undefined;
            this.processData.query = undefined;
        }

        this.log.info('Server status has been changed to ' + inverted[status]);
        this.status = status;
        this.emit('status', status);
    }

    preflight(next) {
        // Return immediately if server is currently powered on.
        if (this.status !== Status.OFF) {
            return next(new Error('Server is already running.'));
        }
        // @TODO: plugin specific preflights
        return next();
    }

    start(next) {
        const self = this;
        if (this.status !== Status.OFF) {
            return next(new Error('Server is already running.'));
        }

        Async.series([
            function startAsyncPreflight(callback) {
                self.log.debug('Initializing for boot sequence, running preflight checks.');
                self.preflight(callback);
            },
            function startAsyncStart(callback) {
                self.docker.start(callback);
            },
            function startAsyncAttach(callback) {
                self.docker.attach(callback);
            },
        ], function startAsyncDone(err, reboot) {
            if (err) {
                self.log.error(err);
                return next(err);
            }

            if (typeof reboot !== 'undefined') {
                // @TODO: Handle the need for a reboot here.
            }
            return next();
        });
    }

    stop(next) {
        if (this.status === Status.OFF) {
            return next(new Error('Server is already stopped.'));
        }

        this.setStatus(Status.STOPPING);
        // So, technically docker sends a SIGTERM to the process when this is run.
        // This works out fine normally, however, there are times when a container might take
        // more than 10 seconds to gracefully stop, at which point docker resorts to sending
        // a SIGKILL, which, as you can imagine, isn't ideal for stopping a server.
        //
        // So, what we will do is send a stop command, and then sit there and wait
        // until the container stops because the process stopped, at which point the crash
        // detection will not fire since we set the status to STOPPING.
        this.command(this.service.object.stop, function (err) {
            return next(err);
        });
    }

    kill(next) {
        const self = this;
        if (this.status === Status.OFF) {
            return next(new Error('Server is already stopped.'));
        }

        this.setStatus(Status.STOPPING);
        this.docker.kill(function killDockerKill(err) {
            self.log.info('Process SIGINT request for server. Server will be forciably stopped.');
            self.setStatus(Status.OFF);
            return next(err);
        });
    }

    restart(next) {
        const self = this;
        Async.series([
            function restartAsyncStop(callback) {
                if (self.status !== Status.OFF) {
                    self.stop(callback);
                } else {
                    // Already off, lets move on.
                    return callback();
                }
            },
            function restartAsyncStart(callback) {
                self.start(callback);
            },
        ], function restartAsycDone(err) {
            return next(err);
        });
    }

    /**
     * Send output from server container to websocket.
     */
    output(output) {
        if (output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === null || output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === '' || output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === ' ') {
            return;
        }
        // For now, log to console, and strip control characters from output.
        this.service.onConsole(output);
    }

    /**
     * Send command to server.
     */
    command(command, next) {
        this.docker.write(command, next);
    }

    /**
     * Determines if the container stream should have ended yet, if not, mark server crashed.
     */
    streamClosed() {
        const self = this;

        if (this.status === Status.OFF || this.status === Status.STOPPING) {
            this.setStatus(Status.OFF);
            return;
        }

        this.setStatus(Status.OFF);
        if (moment.isMoment(this.lastCrash)) {
            if (moment(this.lastCrash).add(60, 'seconds').isAfter(moment())) {
                this.setCrashTime();
                this.log.debug('Server detected as crashed but has crashed within the last 60 seconds, aborting reboot.');
                return;
            }
        }

        this.log.debug('Server detected as crashed... attempting reboot.');
        this.setCrashTime();

        this.start(function streamClosedStart(err) {
            if (err) self.log.fatal(err);
        });
    }

    setCrashTime() {
        this.lastCrash = moment();
    }

    path(location) {
        const dataPath = Path.join(Config.get('sftp.path', '/srv/data'), this.json.user, '/data');
        const cleanLocation = location.replace(/\s+/g, '');
        let returnPath;

        if (typeof location !== 'undefined' && cleanLocation.length > 0) {
            returnPath = Path.join(dataPath, Path.normalize(Querystring.unescape(cleanLocation)));
        }

        // Path is good, return it.
        if (returnPath.indexOf(dataPath) === 0) {
            return returnPath;
        }

        this.log.debug({ attemted_path: returnPath }, 'Attempted to access file outside of SFTP path, defaulted to SFTP data directory.');
        return dataPath;
    }

    process(self) {
        if (self.status === Status.OFF) return;

        // When the server is started a stream of process data is begun
        // which is stored in Docker.procData. We wilol now access that
        // and process it.
        if (typeof self.docker.procData === 'undefined') return;

        // We need previous cycle information as well.
        if (typeof self.docker.procData.precpu_stats.cpu_usage === 'undefined') return;

        const perCoreUsage = [];
        const priorCycle = self.docker.procData.precpu_stats;
        const cycle = self.docker.procData.cpu_stats;

        const deltaTotal = cycle.cpu_usage.total_usage - priorCycle.cpu_usage.total_usage;
        const deltaSystem = cycle.system_cpu_usage - priorCycle.system_cpu_usage;
        const totalUsage = (deltaTotal / deltaSystem) * cycle.cpu_usage.percpu_usage.length * 100;

        Async.forEachOf(cycle.cpu_usage.percpu_usage, function (cpu, index, callback) {
            if (index in priorCycle.cpu_usage.percpu_usage) {
                const priorCycleCpu = priorCycle.cpu_usage.percpu_usage[index];
                const deltaCore = cpu - priorCycleCpu;
                perCoreUsage.push(parseFloat(((deltaCore / deltaSystem) * 100).toFixed(6).toString()));
            }
            callback();
        }, function () {
            self.processData.process = {
                memory: {
                    total: self.docker.procData.memory_stats.usage,
                    max: self.docker.procData.memory_stats.max_usage,
                },
                cpu: {
                    cores: perCoreUsage,
                    total: parseFloat(totalUsage.toFixed(6).toString()),
                },
            };
            self.emit('proc', self.processData.process);
        });
    }

}

module.exports = Server;
<commit_msg>use startswith not indexof<commit_after>'use strict';

/**
 * Pterodactyl Daemon
 * Copyright (c) 2015 Dane Everitt <dane@daneeveritt.com>
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
const rfr = require('rfr');
const Async = require('async');
const moment = require('moment');
const _ = require('underscore');
const EventEmitter = require('events').EventEmitter;
const Querystring = require('querystring');
const Path = require('path');

const Log = rfr('src/helpers/logger.js');
const Docker = rfr('src/controllers/docker.js');
const Service = rfr('src/services/minecraft/index.js');
const Status = rfr('src/helpers/status.js');
const ConfigHelper = rfr('src/helpers/config.js');
const Websocket = rfr('src/http/socket.js');
const UploadServer = rfr('src/http/upload.js');

const Config = new ConfigHelper();

class Server extends EventEmitter {

    constructor(json, next) {
        super();
        const self = this;
        this.status = Status.OFF;
        this.json = json;
        this.uuid = this.json.uuid;
        this.processData = {
            query: {},
            process: {},
        };

        this.intervals = {
            process: undefined,
            query: undefined,
        };

        this.log = Log.child({ server: this.uuid });
        this.lastCrash = undefined;

        this.docker = new Docker(this, function constructorServer(err, status) {
            if (status === true) {
                self.log.info('Daemon detected that the server container is currently running, re-attaching to it now!');
            }
            return next(err);
        });

        this.service = new Service(this);

        this.socketIO = new Websocket(this).init();
        this.uploadSocket = new UploadServer(this).init();
    }

    hasPermission(perm, token) {
        if (typeof perm !== 'undefined' && typeof token !== 'undefined') {
            if (typeof this.json.keys !== 'undefined' && token in this.json.keys) {
                if (this.json.keys[token].indexOf(perm) > -1) {
                    return true;
                }
            }
        }
        return false;
    }

    setStatus(status) {
        if (status === this.status) return;
        const inverted = _.invert(Status);

        // If a user starts their server and then tries to stop it before the server is done
        // it triggers a crash condition. This logic determines if the server status is set to
        // stopping, and if so, we prevent changing the status to starting or on. This allows the
        // server to not crash when we press stop before it is compeltely started.
        if (this.status === Status.STOPPING && (status === Status.ON || status === Status.STARTING)) {
            this.log.debug('Recieved request to mark server as ' + inverted[status] + ' but the server is currently marked as STOPPING.');
            return;
        }

        // Handle Internal Tracking
        if (status !== Status.OFF) {
            // If an interval has not been started, start one now.
            if (typeof this.intervals.process === 'undefined') {
                this.intervals.process = setInterval(this.process, 2000, this);
            }
        } else {
            // Server has been stopped, lets clear the interval as well as any stored
            // information about the process or query. Lets also detach the stats stream.
            clearInterval(this.intervals.process);
            this.processData.process = undefined;
            this.processData.query = undefined;
        }

        this.log.info('Server status has been changed to ' + inverted[status]);
        this.status = status;
        this.emit('status', status);
    }

    preflight(next) {
        // Return immediately if server is currently powered on.
        if (this.status !== Status.OFF) {
            return next(new Error('Server is already running.'));
        }
        // @TODO: plugin specific preflights
        return next();
    }

    start(next) {
        const self = this;
        if (this.status !== Status.OFF) {
            return next(new Error('Server is already running.'));
        }

        Async.series([
            function startAsyncPreflight(callback) {
                self.log.debug('Initializing for boot sequence, running preflight checks.');
                self.preflight(callback);
            },
            function startAsyncStart(callback) {
                self.docker.start(callback);
            },
            function startAsyncAttach(callback) {
                self.docker.attach(callback);
            },
        ], function startAsyncDone(err, reboot) {
            if (err) {
                self.log.error(err);
                return next(err);
            }

            if (typeof reboot !== 'undefined') {
                // @TODO: Handle the need for a reboot here.
            }
            return next();
        });
    }

    stop(next) {
        if (this.status === Status.OFF) {
            return next(new Error('Server is already stopped.'));
        }

        this.setStatus(Status.STOPPING);
        // So, technically docker sends a SIGTERM to the process when this is run.
        // This works out fine normally, however, there are times when a container might take
        // more than 10 seconds to gracefully stop, at which point docker resorts to sending
        // a SIGKILL, which, as you can imagine, isn't ideal for stopping a server.
        //
        // So, what we will do is send a stop command, and then sit there and wait
        // until the container stops because the process stopped, at which point the crash
        // detection will not fire since we set the status to STOPPING.
        this.command(this.service.object.stop, function (err) {
            return next(err);
        });
    }

    kill(next) {
        const self = this;
        if (this.status === Status.OFF) {
            return next(new Error('Server is already stopped.'));
        }

        this.setStatus(Status.STOPPING);
        this.docker.kill(function killDockerKill(err) {
            self.log.info('Process SIGINT request for server. Server will be forciably stopped.');
            self.setStatus(Status.OFF);
            return next(err);
        });
    }

    restart(next) {
        const self = this;
        Async.series([
            function restartAsyncStop(callback) {
                if (self.status !== Status.OFF) {
                    self.stop(callback);
                } else {
                    // Already off, lets move on.
                    return callback();
                }
            },
            function restartAsyncStart(callback) {
                self.start(callback);
            },
        ], function restartAsycDone(err) {
            return next(err);
        });
    }

    /**
     * Send output from server container to websocket.
     */
    output(output) {
        if (output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === null || output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === '' || output.replace(/[\x00-\x1F\x7F-\x9F]/g, '') === ' ') {
            return;
        }
        // For now, log to console, and strip control characters from output.
        this.service.onConsole(output);
    }

    /**
     * Send command to server.
     */
    command(command, next) {
        this.docker.write(command, next);
    }

    /**
     * Determines if the container stream should have ended yet, if not, mark server crashed.
     */
    streamClosed() {
        const self = this;

        if (this.status === Status.OFF || this.status === Status.STOPPING) {
            this.setStatus(Status.OFF);
            return;
        }

        this.setStatus(Status.OFF);
        if (moment.isMoment(this.lastCrash)) {
            if (moment(this.lastCrash).add(60, 'seconds').isAfter(moment())) {
                this.setCrashTime();
                this.log.debug('Server detected as crashed but has crashed within the last 60 seconds, aborting reboot.');
                return;
            }
        }

        this.log.debug('Server detected as crashed... attempting reboot.');
        this.setCrashTime();

        this.start(function streamClosedStart(err) {
            if (err) self.log.fatal(err);
        });
    }

    setCrashTime() {
        this.lastCrash = moment();
    }

    path(location) {
        const dataPath = Path.join(Config.get('sftp.path', '/srv/data'), this.json.user, '/data');
        const cleanLocation = location.replace(/\s+/g, '');
        let returnPath;

        if (typeof location !== 'undefined' && cleanLocation.length > 0) {
            returnPath = Path.join(dataPath, Path.normalize(Querystring.unescape(cleanLocation)));
        }

        // Path is good, return it.
        if (returnPath.startsWith(dataPath)) {
            return returnPath;
        }

        this.log.debug({ attemted_path: returnPath }, 'Attempted to access file outside of SFTP path, defaulted to SFTP data directory.');
        return dataPath;
    }

    process(self) {
        if (self.status === Status.OFF) return;

        // When the server is started a stream of process data is begun
        // which is stored in Docker.procData. We wilol now access that
        // and process it.
        if (typeof self.docker.procData === 'undefined') return;

        // We need previous cycle information as well.
        if (typeof self.docker.procData.precpu_stats.cpu_usage === 'undefined') return;

        const perCoreUsage = [];
        const priorCycle = self.docker.procData.precpu_stats;
        const cycle = self.docker.procData.cpu_stats;

        const deltaTotal = cycle.cpu_usage.total_usage - priorCycle.cpu_usage.total_usage;
        const deltaSystem = cycle.system_cpu_usage - priorCycle.system_cpu_usage;
        const totalUsage = (deltaTotal / deltaSystem) * cycle.cpu_usage.percpu_usage.length * 100;

        Async.forEachOf(cycle.cpu_usage.percpu_usage, function (cpu, index, callback) {
            if (index in priorCycle.cpu_usage.percpu_usage) {
                const priorCycleCpu = priorCycle.cpu_usage.percpu_usage[index];
                const deltaCore = cpu - priorCycleCpu;
                perCoreUsage.push(parseFloat(((deltaCore / deltaSystem) * 100).toFixed(6).toString()));
            }
            callback();
        }, function () {
            self.processData.process = {
                memory: {
                    total: self.docker.procData.memory_stats.usage,
                    max: self.docker.procData.memory_stats.max_usage,
                },
                cpu: {
                    cores: perCoreUsage,
                    total: parseFloat(totalUsage.toFixed(6).toString()),
                },
            };
            self.emit('proc', self.processData.process);
        });
    }

}

module.exports = Server;
<|endoftext|>


<commit_before>var ProductStore = require('../product-store');
var assert = require('chai').assert;
var sinon = require('sinon');

describe('ProductStore', function() {

  describe('internals.initProducts', function() {
    before(function() {
      this.products = ProductStore.__get__('products');
      this.user = ProductStore.__get__('user');
      ProductStore.__set__('products', {
        fetch: () => true,
        trigger: sinon.stub()
      });
      ProductStore.__set__('user', {
        fetch: () => true
      })
    });

    after(function() {
      ProductStore.__set__('products', this.products);
      ProductStore.__set__('user', this.user);
    });

    it('should return a promise', function() {
      var internals = ProductStore.internals;
      return internals.initProducts();
    });
  });

  describe('getItemsForProduct', function() {
    it('returns an items collection', function() {

    });

    it('updates the items collection filter config', function() {

    });
  });
});
<commit_msg>add tests on internals.loadMoreItems<commit_after>var $ = require('jquery');
var _ = require('lodash');
var ProductStore = require('../product-store');
var Backbone = require('backdash');
var assert = require('chai').assert;
var sinon = require('sinon');

describe('ProductStore', function() {

  describe('internals.initProducts', function() {
    before(function() {
      this.products = ProductStore.__get__('products');
      this.user = ProductStore.__get__('user');
      ProductStore.__set__('products', {
        fetch: () => true,
        trigger: sinon.stub()
      });
      ProductStore.__set__('user', {
        fetch: () => true
      })
    });

    after(function() {
      ProductStore.__set__('products', this.products);
      ProductStore.__set__('user', this.user);
    });

    it('should return a promise', function() {
      var internals = ProductStore.internals;
      return internals.initProducts();
    });
  });

  describe('internals.loadMoreItems', function() {
    beforeEach(function() {
      this.collection = new Backbone.Collection();
      this.collection.config = new Backbone.Model({
        status: 'backlog',
        offset: 0
      });
    });

    it('should return a promise', function() {
      var spy = sinon.spy(this.collection, 'trigger');

      this.collection.fetch = () => {
        return $.Deferred().resolve({length: 0});
      };

      ProductStore.internals.loadMoreItems(this.collection);
      sinon.assert.calledOnce(spy);
    });

    it('should emit a change event and pass an object containing the response item count', function() {
      var spy = sinon.spy(this.collection, 'trigger');

      this.collection.fetch = () => {
        return $.Deferred().resolve({length: 16});
      };

      ProductStore.internals.loadMoreItems(this.collection);
      sinon.assert.calledWith(spy, 'change', {count: 16});
    });
  });

  describe('getItemsForProduct', function() {
    it('returns an items collection', function() {

    });

    it('updates the items collection filter config', function() {

    });
  });
});<|endoftext|>


<commit_before>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Flows the text into tspans
//------------------------------------------------------------------------------
d3plus.textwrap.tspan = function( vars ) {

  var xPosition  = vars.container.value.attr("x") || "0px"
    , words      = vars.text.words.slice(0)
    , tspans     = false
    , fontSize   = vars.resize.value ? vars.size.value[1] : vars.container.fontSize || vars.size.value[0]
    , textBox    = vars.container.value.append("tspan").text( words[0] )
                     .attr( "dy" , fontSize + "px" )
    , textHeight = textBox.node().offsetHeight
    , line       = 1
    , newLine    = function( ) {
      return vars.container.value.append("tspan")
              .attr( "x" , xPosition )
              .attr( "dy" , fontSize + "px" )
    }
    , truncate   = function( ) {

      if ( !textBox.empty() ) {

        words = textBox.text().match(/[^\s-]+-?/g)

        ellipsis()

      }

    }
    , ellipsis   = function( ) {

      if ( words && words.length ) {

        var lastWord = words.pop()
          , lastChar = lastWord.charAt( lastWord.length-1 )

        if ( lastWord.length === 1
        && vars.text.split.indexOf( lastWord ) >= 0 ) {
          ellipsis()
        }
        else {

          if ( vars.text.split.indexOf( lastChar ) >= 0 ) {
            lastWord = lastWord.substr( 0 , lastWord.length - 1 )
          }

          textBox.text( words.join(" ") + " " + lastWord + " ..." )

          var baseline = (line-1) * textHeight
            , lineWidth = vars.shape.value === "circle"
                        ? 2*Math.sqrt( baseline*( (2*(vars.width.value/2))-baseline ) )
                        : vars.width.value

          if ( textBox.node().getComputedTextLength() > lineWidth ) {
            ellipsis()
          }

        }

      }
      else {

        textBox.remove()
        textBox = d3.select( vars.container.value.node().lastChild )
        if ( !textBox.empty() ) {
          line--
          truncate()
        }

      }

    }

  if ( vars.shape.value === "circle" ) {
    vars.container.value.attr( "text-anchor" , "middle" )
  }

  for ( var i = 1 ; i < words.length ; i++ ) {

    if ( line * textHeight > vars.height.value ) {
      textBox.remove()
      if ( i !== 1 ) {
        textBox = d3.select( vars.container.value.node().lastChild )
        if ( !textBox.empty() ) truncate()
      }
      break

    }

    var current   = textBox.text()
      , lastChar = current.slice(-1)
      , next_char = vars.text.current.charAt( vars.text.current.indexOf(current) + current.length )
      , joiner    = next_char == " " ? " " : ""

    textBox.text( current + joiner + words[i] )

    var baseline = (line-1) * textHeight
      , lineWidth = vars.shape.value === "circle"
                  ? 2*Math.sqrt( baseline*( (2*(vars.width.value/2))-baseline ) )
                  : vars.width.value

    if ( textBox.node().getComputedTextLength() > lineWidth ) {

      if ( !tspans ) {
        textBox.text("")
        textBox = newLine()
      }

      textBox.text( current )

      textBox = newLine()
      textBox.text( words[i] )

      line++

    }

  }

}
<commit_msg>fixed circle textwrapping in Firefox<commit_after>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Flows the text into tspans
//------------------------------------------------------------------------------
d3plus.textwrap.tspan = function( vars ) {

  var xPosition  = vars.container.value.attr("x") || "0px"
    , words      = vars.text.words.slice(0)
    , tspans     = false
    , fontSize   = vars.resize.value ? vars.size.value[1] : vars.container.fontSize || vars.size.value[0]
    , textBox    = vars.container.value.append("tspan").text( words[0] )
                     .attr( "dy" , fontSize + "px" )
    , textHeight = textBox.node().offsetHeight || textBox.node().getBoundingClientRect().height
    , line       = 1
    , newLine    = function( ) {
      return vars.container.value.append("tspan")
              .attr( "x" , xPosition )
              .attr( "dy" , fontSize + "px" )
    }
    , truncate   = function( ) {

      if ( !textBox.empty() ) {

        words = textBox.text().match(/[^\s-]+-?/g)

        ellipsis()

      }

    }
    , ellipsis   = function( ) {

      if ( words && words.length ) {

        var lastWord = words.pop()
          , lastChar = lastWord.charAt( lastWord.length-1 )

        if ( lastWord.length === 1
        && vars.text.split.indexOf( lastWord ) >= 0 ) {
          ellipsis()
        }
        else {

          if ( vars.text.split.indexOf( lastChar ) >= 0 ) {
            lastWord = lastWord.substr( 0 , lastWord.length - 1 )
          }

          textBox.text( words.join(" ") + " " + lastWord + " ..." )

          var baseline = (line-1) * textHeight
            , lineWidth = vars.shape.value === "circle"
                        ? 2*Math.sqrt( baseline*( (2*(vars.width.value/2))-baseline ) )
                        : vars.width.value

          if ( textBox.node().getComputedTextLength() > lineWidth ) {
            ellipsis()
          }

        }

      }
      else {

        textBox.remove()
        textBox = d3.select( vars.container.value.node().lastChild )
        if ( !textBox.empty() ) {
          line--
          truncate()
        }

      }

    }

  if ( vars.shape.value === "circle" ) {
    vars.container.value.attr( "text-anchor" , "middle" )
  }

  for ( var i = 1 ; i < words.length ; i++ ) {

    if ( line * textHeight > vars.height.value ) {
      textBox.remove()
      if ( i !== 1 ) {
        textBox = d3.select( vars.container.value.node().lastChild )
        if ( !textBox.empty() ) truncate()
      }
      break

    }

    var current   = textBox.text()
      , lastChar = current.slice(-1)
      , next_char = vars.text.current.charAt( vars.text.current.indexOf(current) + current.length )
      , joiner    = next_char == " " ? " " : ""

    textBox.text( current + joiner + words[i] )

    var baseline = (line-1) * textHeight
      , lineWidth = vars.shape.value === "circle"
                  ? 2*Math.sqrt( baseline*( (2*(vars.width.value/2))-baseline ) )
                  : vars.width.value

    if ( textBox.node().getComputedTextLength() > lineWidth ) {

      if ( !tspans ) {
        textBox.text("")
        textBox = newLine()
      }

      textBox.text( current )

      textBox = newLine()
      textBox.text( words[i] )

      line++

    }

  }

}
<|endoftext|>


<commit_before>const os = require('os');

/**
 * The maximum number of concurrent tasks we want to have on some CLI and CI tasks.
 * The amount of CPUS minus one.
 * @type {number}
 */
const maxConcurrentTasks = Math.max(1, os.cpus().length - 1);

/**
 * Use a simple round robin to filter input data according to the CI node currently running the script
 * @param {Array} arrayOfData An array of anything you want
 * @returns {Array} An array containing only the data that shoud be used by current CI node.
 */
function filterDataForCurrentCircleCINode(arrayOfData) {
  const nodeIndex = +process.env.CIRCLE_NODE_INDEX || 0;
  const numberOfNodes = +process.env.CIRCLE_NODE_TOTAL || 1;

  return arrayOfData.filter((_, index) => {
    return index % numberOfNodes === nodeIndex;
  });
}

module.exports = {
  maxConcurrentTasks,
  filterDataForCurrentCircleCINode,
};
<commit_msg>ci: try to fix `publish` job by limiting the number of concurrent tasks<commit_after>const os = require('os');

/**
 * The maximum number of concurrent tasks we want to have on some CLI and CI tasks.
 * The amount of CPUS minus one, arbitrary limited to 15 to not overload CI executors.
 * @type {number}
 */
const maxConcurrentTasks = Math.min(Math.max(1, os.cpus().length - 1), 15);

/**
 * Use a simple round robin to filter input data according to the CI node currently running the script
 * @param {Array} arrayOfData An array of anything you want
 * @returns {Array} An array containing only the data that shoud be used by current CI node.
 */
function filterDataForCurrentCircleCINode(arrayOfData) {
  const nodeIndex = +process.env.CIRCLE_NODE_INDEX || 0;
  const numberOfNodes = +process.env.CIRCLE_NODE_TOTAL || 1;

  return arrayOfData.filter((_, index) => {
    return index % numberOfNodes === nodeIndex;
  });
}

module.exports = {
  maxConcurrentTasks,
  filterDataForCurrentCircleCINode,
};
<|endoftext|>


<commit_before>(function(){
	'use strict';

	angular.module('<%= moduleName %>').config(RouterConfig);

	RouterConfig.$inject = ['$stateProvider', '$urlRouterProvider', '$locationProvider', '$compileProvider'];
	function RouterConfig($stateProvider, $urlRouterProvider, $locationProvider, $compileProvider) {
			$locationProvider.html5Mode({
				enabled: true
			});
			$compileProvider.debugInfoEnabled(false);
			$urlRouterProvider.otherwise('/');
			$stateProvider
				.state('home', {
					url: '/',
					templateUrl: 'template/View/home.html',
					controller: 'HomeController',
					controllerAs: 'home'
				})
				.state('404', {
					url: '/404',
					templateUrl: 'template/View/404.html'
				});
	}
})();
<commit_msg>Issue #32 Manage redirection for AngularUI Router stateChangeError event<commit_after>(function(){
	'use strict';

	angular.module('<%= moduleName %>')
		.config(RouterConfig)
		.run(AppRun);

	RouterConfig.$inject = ['$stateProvider', '$urlRouterProvider', '$locationProvider', '$compileProvider'];
	function RouterConfig($stateProvider, $urlRouterProvider, $locationProvider, $compileProvider) {
			$locationProvider.html5Mode({
				enabled: true
			});
			$compileProvider.debugInfoEnabled(false);
			$urlRouterProvider.otherwise('/');
			$stateProvider
				.state('home', {
					url: '/',
					templateUrl: 'template/View/home.html',
					controller: 'HomeController',
					controllerAs: 'home'
				})
				.state('404', {
					url: '/404',
					templateUrl: 'template/View/404.html'
				});
	}

	AppRun.$inject = ['$rootScope','$state'];
	function AppRun($rootScope, $state){
		$rootScope.$on('$stateChangeError', function(){
			$state.go('404');
		});
	}
})();
<|endoftext|>


<commit_before>#! /usr/bin/env node

/**
 * @author Adam Meadows [@job13er](https://github.com/job13er)
 * @copyright 2015 Ciena Corporation. All rights reserved
 */

'use strict'

/**
 * @typedef Result
 * @property {Number} code - the exit code of the command
 * @property {String} stdout - the standard output from command
 */

const _ = require('lodash')
const Q = require('q')
const path = require('path')
const fs = require('fs')
const exec = require('child_process').exec
const sleep = require('sleep')
const argv = require('minimist')(process.argv.slice(2), {
  'boolean': 'app'
})
const TOKEN_REVOKED = '~'
const TRAVIS_USERNAME = 'travis'
const WEB_FLOW_USERNAME = 'web-flow'

const GitHubAPI = require('github')

/**
 * Helper for creating a promise (so I don't need to disable new-cap everywhere)
 * @param {*} resolution - what to resolve the promise with
 * @returns {Promise} the promise
 */
function makePromise (resolution) {
  return Q(resolution) // eslint-disable-line new-cap
}

/** @alias tester */
const ns = {
  /**
   * Initialize the module
   * @returns {tester} the tester instance
   */
  init () {
    // this is on the object for eaiser mocking
    this.exec = Q.denodeify(exec)
    this.github = new GitHubAPI({
      debug: false,
      protocol: 'https',
      host: 'api.github.com',
      timeout: 5000
    })
    return this
  },

  /**
   * obvious
   * @param {String} filename - the filename to remove
   * @returns {Promise} resolved with result of exec
   */
  remove (filename) {
    return this.exec('rm -rf ' + filename)
  },

  /**
   * obvious
   * @param {String[]} extras - extra files/directories to include in tarball
   * @returns {Promise} resolved when done
   */
  tarUpAppAndTestsDirectory (extras) {
    let cmd = ['tar', '--exclude="*.map"', '-czf', 'test.tar.gz',
               process.env['E2E_TESTS_DIR'], process.env['BUILD_OUTPUT_DIR']]
    cmd = cmd.concat(extras)

    return this.exec(cmd.join(' '))
  },

  /**
   * Create a tarball of the resources to submit
   * @param {Boolean} isApp - true if we need to fake the demo directory
   * @param {String[]} extras - optional extra files/directories to include in tarball
   * @returns {Promise} resolved when done
   */
  createTarball (isApp, extras) {
    return this.tarUpAppAndTestsDirectory(extras)
  },

  /**
   * Finds the username of developer using the Travis commit number and the GitHub API
   * @param {Object} configFile - Contains the username and token of the developer
   * @returns {Promise} Either resolves with an updated version of the config file or rejects with an error
   */
  findUsername (configFile) {
    return new Promise((resolve, reject) => {
      console.log(`Your config.json file must contain a valid username and token.
      Please visit http://wdio.bp.cyaninc.com to sign up to become an authorized third party developer for Ciena. \n\n`)
      let repo = process.env['TRAVIS_REPO_SLUG'].split('/')
      let user = repo[0]
      let sha = process.env['TRAVIS_COMMIT']
      repo = repo[1]
      this.github.authenticate({
        type: 'oauth',
        token: process.env['RO_GH_TOKEN']
      })
      this.github.repos.getCommit({
        user,
        repo,
        sha
      }, (err, res) => {
        if (err) {
          console.log('Error 4: ' + err)
          reject(err)
        } else {
          let author = res.committer.login
          if (author === WEB_FLOW_USERNAME && res.author.login) {
            author = res.author.login
          }
          configFile.username = author
          console.log('Author ' + configFile)
          resolve(configFile)
        }
      })
    })
  },

  /**
   * Extracts the config.json file from the tests/e2e directory. If it does not exist, it assumes it on TravisCI, and it attempts
   * to extract the appropriate environment variables
   * @returns {Promise} It will either resolve with the configFile or reject with an error
   */
  extractConfig () {
    return new Promise((resolve, reject) => {
      const configDir = path.join(__dirname, '../../..', process.env['E2E_TESTS_DIR'], 'config.json')
      let configFile = {}
      try {
        configFile = JSON.parse(fs.readFileSync(configDir))
      } catch (e) {
        console.log(`Since a config.json file does not exist, we are assuming you are on Travis\n\n`)
      }
      _.defaults(configFile, {username: TRAVIS_USERNAME, token: TOKEN_REVOKED})
      if (configFile.username === TRAVIS_USERNAME) {
        this.findUsername(configFile).then((result) => {
          resolve(result)
        })
        .catch((err) => {
          reject(err)
        })
      } else {
        resolve(configFile)
      }
    })
  },

  /**
   * Submit the tarball for test
   * @param {String} server - the protocol/host/port of the server
   * @returns {Promise} resolved when done
   */
  submitTarball (server) {
    console.log('Submitting bundle to ' + server + ' for test...')
    return this.extractConfig()
    .then((configFile) => {
      const cmd = [
        'curl',
        '-s',
        '-H',
        '"username: ' + configFile.username + '"',
        '-H',
        '"token: ' + configFile.token + '"',
        '-F',
        '"tarball=@test.tar.gz"',
        '-F',
        '"entry-point=' + process.env['BUILD_OUTPUT_DIR'] + '/"',
        '-F',
        '"tests-folder=' + process.env['E2E_TESTS_DIR'] + '"',
        server + '/'
      ]
      console.log('Running command: ' + cmd.join(' '))

      return this.exec(cmd.join(' '))
      .then((res) => {
        const timestamp = res[0]
        this.exec()
        if (isNaN(timestamp)) {
          throw new Error('The server responded with: ' + timestamp)
        }
        console.log('Server Response/Timestamp: ' + timestamp)
        return timestamp
      })
      .catch((err) => {
        throw new Error('The server responded with: Exec failed ' + err)
      })
    })
    .catch((err) => {
      throw new Error('The server responded with: ' + err)
    })
  },

  /**
   * Wait till the server is done with our tests
   * @param {String} cmd - the command to execute to check for results
   * @param {Number} pollInterval - the poll interval in seconds
   * @returns {Promise} resolved when done
   */
  checkForResults (cmd, pollInterval) {
    console.log('Checking for results...')
    return this.exec(cmd).then((res) => {
      const stdout = res[0]
      if (stdout.toString().toLowerCase() === 'not found') {
        sleep.sleep(pollInterval)
        return this.checkForResults(cmd, pollInterval)
      } else {
        return makePromise()
      }
    })
  },

  /**
   * Wait till the server is done with our tests
   * @param {Object} params - object for named parameters
   * @param {String} params.timestamp - the timestamp of the results we're waiting for
   * @param {String} params.server - the protocol/host/port of the server
   * @param {Number} params.initialSleep - the initial sleep time in seconds
   * @param {Number} params.pollInterval - the poll interval in seconds
   * @returns {Promise} resolved when done
   */
  waitForResults (params) {
    console.log('Waiting ' + params.initialSleep + 's before checking')
    sleep.sleep(params.initialSleep)

    const cmd = 'curl -s ' + params.server + '/status/' + params.timestamp
    return this.checkForResults(cmd, params.pollInterval)
  },

  /**
   * Fetch the results from the server
   * @param {String} url - the url to fetch results from
   * @returns {Promise} resolved when done
   */
  getResults (url) {
    return this.exec('curl -s ' + url).then((res) => {
      const stdout = res[0]
      console.log('Parsing results...')
      const obj = JSON.parse(stdout.toString())
      return obj
    })
  },

  /**
   * obvious
   * @param {String} url - the URL to get the tarball from
   * @returns {Promise} resolved when done
   */
  getTarball (url) {
    return this.exec('curl -s -O ' + url)
  },

  /**
   * Obvious
   * @param {WebdriverioServerTestResults} results - details of the test results
   * @returns {Promise} resolved when done
   */
  extractTarball (results) {
    const filename = path.basename(results.output)
    return this.exec('tar -xf ' + filename).then(() => {
      return {
        filename: filename,
        results: results
      }
    })
  },

  /**
   * Parse and output the results
   * @param {String} timestamp - the timestamp of the results we're processing
   * @param {String} server - the protocol/host/port of the server
   * @returns {Promise} resolved when done
   */
  processResults (timestamp, server) {
    const url = server + '/screenshots/output-' + timestamp + '.json'

    return this.getResults(url)
      .then((results) => {
        const url = server + '/' + results.output
        return this.getTarball(url).then(() => {
          return results
        })
      })
      .then((results) => {
        return this.extractTarball(results)
      })
      .then((params) => {
        return this.remove(params.filename).then(() => {
          return params.results
        })
      })
      .then((results) => {
        console.log(results.info)

        console.log('----------------------------------------------------------------------')
        console.log('Screenshots directory updated with results from server.')

        if (results.exitCode === 0) {
          console.log('Tests Pass.')
        } else {
          console.log('Tests FAILED')
          process.exit(1)
        }
      })
      .catch((err) => {
        throw new Error('Error processing results ' + err)
      })
  },

  /**
   * Actual functionality of the 'webdriverio-test' command
   * @param {MinimistArgv} argv - the minimist arguments object
   * @throws CliError
   */
  command (argv) {
    _.defaults(argv, {
      initialSleep: 10,
      pollInterval: 3,
      server: 'http://localhost:3000'
    })

    const extras = argv._.slice(1)
    console.log('isApp is :' + argv.app)

    this.createTarball(argv.app, extras)
      .then(() => {
        return this.submitTarball(argv.server)
      })
      .then((timestamp) => {
        return this.remove('test.tar.gz').then(() => {
          return timestamp
        })
      })
      .then((timestamp) => {
        const params = {
          timestamp: timestamp,
          server: argv.server,
          pollInterval: argv.pollInterval,
          initialSleep: argv.initialSleep
        }

        return this.waitForResults(params).then(() => {
          return timestamp
        })
      })
      .then((timestamp) => {
        return this.processResults(timestamp, argv.server)
      })
      .done()
  }
}

function factory () {
  return Object.create(ns).init()
}

factory.proto = ns

factory().command(argv)
<commit_msg>Added correct headers for localhost testing<commit_after>#! /usr/bin/env node

/**
 * @author Adam Meadows [@job13er](https://github.com/job13er)
 * @copyright 2015 Ciena Corporation. All rights reserved
 */

'use strict'

/**
 * @typedef Result
 * @property {Number} code - the exit code of the command
 * @property {String} stdout - the standard output from command
 */

const _ = require('lodash')
const Q = require('q')
const path = require('path')
const fs = require('fs')
const exec = require('child_process').exec
const sleep = require('sleep')
const argv = require('minimist')(process.argv.slice(2), {
  'boolean': 'app'
})
const TOKEN_REVOKED = '~'
const TRAVIS_USERNAME = 'travis'
const WEB_FLOW_USERNAME = 'web-flow'

const GitHubAPI = require('github')

/**
 * Helper for creating a promise (so I don't need to disable new-cap everywhere)
 * @param {*} resolution - what to resolve the promise with
 * @returns {Promise} the promise
 */
function makePromise (resolution) {
  return Q(resolution) // eslint-disable-line new-cap
}

/** @alias tester */
const ns = {
  /**
   * Initialize the module
   * @returns {tester} the tester instance
   */
  init () {
    // this is on the object for eaiser mocking
    this.exec = Q.denodeify(exec)
    this.github = new GitHubAPI({
      debug: false,
      protocol: 'https',
      host: 'api.github.com',
      timeout: 5000
    })
    return this
  },

  /**
   * obvious
   * @param {String} filename - the filename to remove
   * @returns {Promise} resolved with result of exec
   */
  remove (filename) {
    return this.exec('rm -rf ' + filename)
  },

  /**
   * obvious
   * @param {String[]} extras - extra files/directories to include in tarball
   * @returns {Promise} resolved when done
   */
  tarUpAppAndTestsDirectory (extras) {
    let cmd = ['tar', '--exclude="*.map"', '-czf', 'test.tar.gz',
               process.env['E2E_TESTS_DIR'], process.env['BUILD_OUTPUT_DIR']]
    cmd = cmd.concat(extras)

    return this.exec(cmd.join(' '))
  },

  /**
   * Create a tarball of the resources to submit
   * @param {Boolean} isApp - true if we need to fake the demo directory
   * @param {String[]} extras - optional extra files/directories to include in tarball
   * @returns {Promise} resolved when done
   */
  createTarball (isApp, extras) {
    return this.tarUpAppAndTestsDirectory(extras)
  },

  /**
   * Finds the username of developer using the Travis commit number and the GitHub API
   * @param {Object} configFile - Contains the username and token of the developer
   * @returns {Promise} Either resolves with an updated version of the config file or rejects with an error
   */
  findUsername (configFile) {
    return new Promise((resolve, reject) => {
      console.log(`Your config.json file must contain a valid username and token.
      Please visit http://wdio.bp.cyaninc.com to sign up to become an authorized third party developer for Ciena. \n\n`)
      let repo = process.env['TRAVIS_REPO_SLUG'].split('/')
      let user = repo[0]
      let sha = process.env['TRAVIS_COMMIT']
      repo = repo[1]
      this.github.authenticate({
        type: 'oauth',
        token: process.env['RO_GH_TOKEN']
      })
      this.github.repos.getCommit({
        user,
        repo,
        sha
      }, (err, res) => {
        if (err) {
          console.log('Error 4: ' + err)
          reject(err)
        } else {
          let author = res.committer.login
          if (author === WEB_FLOW_USERNAME && res.author.login) {
            author = res.author.login
          }
          configFile.username = author
          console.log('Author ' + configFile)
          resolve(configFile)
        }
      })
    })
  },

  /**
   * Extracts the config.json file from the tests/e2e directory. If it does not exist, it assumes it on TravisCI, and it attempts
   * to extract the appropriate environment variables
   * @returns {Promise} It will either resolve with the configFile or reject with an error
   */
  extractConfig () {
    return new Promise((resolve, reject) => {
      const configDir = path.join(__dirname, '../../..', process.env['E2E_TESTS_DIR'], 'config.json')
      let configFile = {}
      try {
        configFile = JSON.parse(fs.readFileSync(configDir))
      } catch (e) {
        console.log(`Since a config.json file does not exist, we are assuming you are on Travis\n\n`)
      }
      _.defaults(configFile, {username: TRAVIS_USERNAME, token: TOKEN_REVOKED})
      if (configFile.username === TRAVIS_USERNAME) {
        this.findUsername(configFile).then((result) => {
          resolve(result)
        })
        .catch((err) => {
          reject(err)
        })
      } else {
        resolve(configFile)
      }
    })
  },

  /**
   * Submit the tarball for test
   * @param {String} server - the protocol/host/port of the server
   * @returns {Promise} resolved when done
   */
  submitTarball (server) {
    console.log('Submitting bundle to ' + server + ' for test...')
    return this.extractConfig()
    .then((configFile) => {
      const cmd = [
        'curl',
        '-s',
        '-H',
        '"username: ' + configFile.username + '"',
        '-H',
        '"token: ' + configFile.token + '"',
        '-F',
        '"tarball=@test.tar.gz"',
        '-F',
        '"entry-point=' + process.env['BUILD_OUTPUT_DIR'] + '/"',
        '-F',
        '"tests-folder=' + process.env['E2E_TESTS_DIR'] + '"',
        server + '/'
      ]
      if (server.toString() === 'localhost:3000') {
        cmd.splice(2, 0, '-H "x-forwarded-for: 127.0.0.1"')
      }
      console.log('Running command: ' + cmd.join(' '))

      return this.exec(cmd.join(' '))
      .then((res) => {
        const timestamp = res[0]
        this.exec()
        if (isNaN(timestamp)) {
          throw timestamp
        }
        console.log('Server Response/Timestamp: ' + timestamp)
        return timestamp
      })
      .catch((err) => {
        throw err
      })
    })
    .catch((err) => {
      throw new Error(err)
    })
  },

  /**
   * Wait till the server is done with our tests
   * @param {String} cmd - the command to execute to check for results
   * @param {Number} pollInterval - the poll interval in seconds
   * @returns {Promise} resolved when done
   */
  checkForResults (cmd, pollInterval) {
    console.log('Checking for results...')
    return this.exec(cmd).then((res) => {
      const stdout = res[0]
      if (stdout.toString().toLowerCase() === 'not found') {
        sleep.sleep(pollInterval)
        return this.checkForResults(cmd, pollInterval)
      } else {
        return makePromise()
      }
    })
  },

  /**
   * Wait till the server is done with our tests
   * @param {Object} params - object for named parameters
   * @param {String} params.timestamp - the timestamp of the results we're waiting for
   * @param {String} params.server - the protocol/host/port of the server
   * @param {Number} params.initialSleep - the initial sleep time in seconds
   * @param {Number} params.pollInterval - the poll interval in seconds
   * @returns {Promise} resolved when done
   */
  waitForResults (params) {
    console.log('Waiting ' + params.initialSleep + 's before checking')
    sleep.sleep(params.initialSleep)

    const cmd = 'curl -s ' + params.server + '/status/' + params.timestamp
    return this.checkForResults(cmd, params.pollInterval)
  },

  /**
   * Fetch the results from the server
   * @param {String} url - the url to fetch results from
   * @returns {Promise} resolved when done
   */
  getResults (url) {
    return this.exec('curl -s ' + url).then((res) => {
      const stdout = res[0]
      console.log('Parsing results...')
      const obj = JSON.parse(stdout.toString())
      return obj
    })
  },

  /**
   * obvious
   * @param {String} url - the URL to get the tarball from
   * @returns {Promise} resolved when done
   */
  getTarball (url) {
    return this.exec('curl -s -O ' + url)
  },

  /**
   * Obvious
   * @param {WebdriverioServerTestResults} results - details of the test results
   * @returns {Promise} resolved when done
   */
  extractTarball (results) {
    const filename = path.basename(results.output)
    return this.exec('tar -xf ' + filename).then(() => {
      return {
        filename: filename,
        results: results
      }
    })
  },

  /**
   * Parse and output the results
   * @param {String} timestamp - the timestamp of the results we're processing
   * @param {String} server - the protocol/host/port of the server
   * @returns {Promise} resolved when done
   */
  processResults (timestamp, server) {
    const url = server + '/screenshots/output-' + timestamp + '.json'

    return this.getResults(url)
      .then((results) => {
        const url = server + '/' + results.output
        return this.getTarball(url).then(() => {
          return results
        })
      })
      .then((results) => {
        return this.extractTarball(results)
      })
      .then((params) => {
        return this.remove(params.filename).then(() => {
          return params.results
        })
      })
      .then((results) => {
        console.log(results.info)

        console.log('----------------------------------------------------------------------')
        console.log('Screenshots directory updated with results from server.')

        if (results.exitCode === 0) {
          console.log('Tests Pass.')
        } else {
          console.log('Tests FAILED')
          process.exit(1)
        }
      })
      .catch((err) => {
        throw new Error(err)
      })
  },

  /**
   * Actual functionality of the 'webdriverio-test' command
   * @param {MinimistArgv} argv - the minimist arguments object
   * @throws CliError
   */
  command (argv) {
    _.defaults(argv, {
      initialSleep: 10,
      pollInterval: 3,
      server: 'http://localhost:3000'
    })

    const extras = argv._.slice(1)
    console.log('isApp is :' + argv.app)

    this.createTarball(argv.app, extras)
      .then(() => {
        return this.submitTarball(argv.server)
      })
      .then((timestamp) => {
        return this.remove('test.tar.gz').then(() => {
          return timestamp
        })
      })
      .then((timestamp) => {
        const params = {
          timestamp: timestamp,
          server: argv.server,
          pollInterval: argv.pollInterval,
          initialSleep: argv.initialSleep
        }

        return this.waitForResults(params).then(() => {
          return timestamp
        })
      })
      .then((timestamp) => {
        return this.processResults(timestamp, argv.server)
      })
      .done()
  }
}

function factory () {
  return Object.create(ns).init()
}

factory.proto = ns

factory().command(argv)
<|endoftext|>


<commit_before>/*
 * Stately.js: A JavaScript based finite-state machine (FSM) engine.
 *
 * Copyright (c) 2012 Florian Schäfer (florian.schaefer@gmail.com)
 * Released under MIT license.
 *
 * Version: 0.9.8
 *
 */
(function (root, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        root.Stately = factory();
    }
})(this, function () {

    var
        //helper to identify options type
        toString = Object.prototype.toString,

        //custom exception for invalid states
        InvalidStateError = (function () {

            //custom event constructor
            function InvalidStateError(message) {

                //the error message
                this.message = message;
            }

            //inherit from error object
            InvalidStateError.prototype = new Error();

            //return custom event
            return InvalidStateError;
        })(),

        //the state machine engine
        Stately = (function () {

            //constructor
            function Stately(statesObject) {

                //if statesObject is a function
                if (typeof statesObject === 'function') {

                    //avaluate it
                    statesObject = statesObject();
                }

                //if no valid statesObject provided
                if (toString.call(statesObject) !== '[object Object]') {

                    //bail out
                    throw new InvalidStateError('Stately.js: Invalid states object: `' + statesObject + '`.');
                }

                var
                    //current state of the machine
                    currentState,

                    //storage for notification callbacks
                    notificationStore = [],

                    //notify callbacks about a transition
                    notify = function () {

                        //make copy of notification storage
                        var notifications = notificationStore.slice();

                        //walk over stored callbacks
                        for (var i = 0, l = notifications.length; i < l; i++) {

                            //and notify them
                            notifications[i].apply(this, arguments);
                        }
                    },

                    //storage for machine states
                    stateStore = {

                        //evaluates the current state
                        getMachineState: function getMachineState() {

                            //return current state as string
                            return currentState.name;
                        },

                        //function to transition into another state
                        setMachineState: function setMachineState(nextState /*, eventName */) {

                            var
                                //event that triggered the transition
                                eventName = arguments[1],

                                //before state hook
                                onBeforeState,

                                //enter state hook
                                onEnterState,

                                //leave state hook
                                onLeaveState,

                                //store last machine state
                                lastState = currentState;

                            //if state machine cannot handle returned state
                            if (!nextState || !nextState.name || !stateStore[nextState.name]) {

                                //throw invalid state exception
                                throw new InvalidStateError('Stately.js: Transitioned into invalid state: `' + setMachineState.caller + '`.');
                            }

                            //transition into next state
                            currentState = nextState;

                            //retrieve enter state hook
                            onBeforeState = stateMachine['onbefore' + currentState.name];

                            //if a hook is attached
                            if (onBeforeState && typeof onBeforeState === 'function') {

                                //apply it
                                onBeforeState.call(stateStore, eventName, lastState.name, nextState.name);
                            }

                            //retrieve enter state hook
                            onEnterState = stateMachine['onenter' + currentState.name] || stateMachine['on' + currentState.name];

                            //if a hook is attached
                            if (onEnterState && typeof onEnterState === 'function') {

                                //apply it
                                onEnterState.call(stateStore, eventName, lastState.name, nextState.name);
                            }

                            //retrieve leave state hook
                            onLeaveState = stateMachine['onleave' + currentState.name];

                            //if a hook is attached
                            if (onLeaveState && typeof onLeaveState === 'function') {

                                //apply it
                                onLeaveState.call(stateStore, eventName, lastState.name, nextState.name);
                            }

                            //notify notification callbacks about transition
                            notify.call(stateStore, eventName, lastState.name, nextState.name);

                            //return the state store
                            return this;
                        },

                        //function returns the possible events in current state
                        getMachineEvents: function getMachineEvents() {

                            //storage for the events in current state
                            var events = [];

                            //walk over the events of the current state
                            for (property in currentState) {

                                //ensure to only walk over own properties
                                if (currentState.hasOwnProperty(property)) {

                                    //if it is an event function
                                    if (typeof currentState[property] === 'function') {

                                        //store it in events storage
                                        events.push(property);
                                    }
                                }
                            }

                            //return the possible events
                            return events;
                        }

                    },

                    //the state machine
                    stateMachine = {

                        //copy function to public state machine object
                        getMachineState: stateStore.getMachineState,

                        //copy function to public state machine object
                        getMachineEvents: stateStore.getMachineEvents,

                        //store a new notification callback
                        bind: function bind(callback) {

                            //if we have a new notification callback
                            if (callback) {

                                //store it in notification storage
                                notificationStore.push(callback);
                            }

                            //return the state machine
                            return this;
                        },

                        //remove a notification callback from storage
                        unbind: function unbind(callback) {

                            //if no callback is given
                            if (!callback) {

                                //reset notification storage
                                notificationStore = [];

                            } else {

                                //walk over stored callbacks
                                for (var i = 0, l = notificationStore.length; i < l; i++) {

                                    //if callback is found in notification storage
                                    if (notificationStore[i] === callback) {

                                        //remove it
                                        notificationStore.splice(i, 1);
                                    }
                                }
                            }

                            //return the state machine
                            return this;
                        }
                    },

                    //event decorator factory function
                    transition = function transition(stateName, eventName, nextEvent) {

                        //the decorator
                        return function event() {

                            var
                                //before event hook
                                onBeforeEvent,

                                //after event hook
                                onAfterEvent,

                                //new state machine changed into
                                nextState,

                                //return the state machine if no event returns something
                                eventValue = stateMachine;

                            //if attached event handler doesn't handle this event
                            if (stateStore[stateName] !== currentState) {

                                //try other events in chain
                                if (nextEvent) {

                                    //let next event function handle this event
                                    eventValue = nextEvent.apply(stateStore, arguments);
                                }

                                //or return value of action
                                return eventValue;
                            }

                            //retrieve before event hook
                            onBeforeEvent = stateMachine['onbefore' + eventName];

                            //if a hook is attached
                            if (onBeforeEvent && typeof onBeforeEvent === 'function') {

                                //apply it
                                onBeforeEvent.call(stateStore, eventName, currentState.name, currentState.name);
                            }

                            //run action
                            eventValue = stateStore[stateName][eventName].apply(stateStore, arguments);

                            //check return value of action
                            if (typeof eventValue === 'undefined') {

                                //nothing returned, stay in current state
                                nextState = currentState;

                                //return state machine
                                eventValue = stateMachine;

                            } else if (toString.call(eventValue) === '[object Object]') {

                                //if state store object is returned ('this' in action function) stay in current state
                                nextState = (eventValue === stateStore ? currentState : eventValue);

                                //return state machine
                                eventValue = stateMachine;

                            } else if (toString.call(eventValue) === '[object Array]' && eventValue.length >= 1) {

                                //else first element is next state
                                nextState = eventValue[0];

                                //second element is return value
                                eventValue = eventValue[1];
                            }

                            //retrieve after event hook
                            onAfterEvent = stateMachine['onafter' + eventName] || stateMachine['on' + eventName];

                            //if a hook is attached
                            if (onAfterEvent && typeof onAfterEvent === 'function') {

                                //apply it
                                onAfterEvent.call(stateStore, eventName, currentState.name, nextState.name);
                            }

                            //transition into next state
                            stateStore.setMachineState(nextState, eventName);

                            //return desired value
                            return eventValue;
                        };
                    };

                //walk over states object
                for (var stateName in statesObject) {

                    //check own properties
                    if (statesObject.hasOwnProperty(stateName)) {

                        //store states in storage
                        stateStore[stateName] = statesObject[stateName];

                        //walk over events
                        for (var eventName in stateStore[stateName]) {

                            //check for own property
                            if (stateStore[stateName].hasOwnProperty(eventName)) {

                                //if type is a string, assume it is a state
                                if (typeof stateStore[stateName][eventName] === 'string') {

                                    //decorate it
                                    stateStore[stateName][eventName] = (function (stateName) {

                                        //with a function
                                        return function event() {

                                            //returning the given state
                                            return this[stateName];
                                        };

                                    })(stateStore[stateName][eventName]);
                                }

                                //if type function
                                if (typeof stateStore[stateName][eventName] === 'function') {

                                    //assign decorated events to state machine
                                    stateMachine[eventName] = transition(stateName, eventName, stateMachine[eventName]);
                                }
                            }
                        }

                        //attach states name to object in storage
                        stateStore[stateName].name = stateName;

                        //initial state is the first passed in state
                        if (!currentState) {

                            //make initial state the current state
                            currentState = stateStore[stateName];
                        }
                    }
                }

                //if there is no initial state
                if (!currentState) {

                    //throw invalid state exception
                    throw new InvalidStateError('Stately.js: Invalid initial state.');
                }

                //return the new state machine
                return stateMachine;
            }

            //a factory for new machines
            Stately.machine = function machine(statesObject) {
                return new Stately(statesObject);
            };

            //InvalidStateError exception
            Stately.InvalidStateError = InvalidStateError;

            //return the constructor
            return Stately;
        })();

    //export Stately object
    return Stately;

});
<commit_msg>Remove the unnecessary scope function.<commit_after>/*
 * Stately.js: A JavaScript based finite-state machine (FSM) engine.
 *
 * Copyright (c) 2012 Florian Schäfer (florian.schaefer@gmail.com)
 * Released under MIT license.
 *
 * Version: 0.9.8
 *
 */
(function (root, factory) {
    if (typeof exports === 'object') {
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        root.Stately = factory();
    }
})(this, function () {

    var
        //helper to identify options type
        toString = Object.prototype.toString,

        //custom exception for invalid states
        InvalidStateError = (function () {

            //custom event constructor
            function InvalidStateError(message) {

                //the error message
                this.message = message;
            }

            //inherit from error object
            InvalidStateError.prototype = new Error();

            //return custom event
            return InvalidStateError;
        })();

    //constructor
    function Stately(statesObject) {

        //if statesObject is a function
        if (typeof statesObject === 'function') {

            //avaluate it
            statesObject = statesObject();
        }

        //if no valid statesObject provided
        if (toString.call(statesObject) !== '[object Object]') {

            //bail out
            throw new InvalidStateError('Stately.js: Invalid states object: `' + statesObject + '`.');
        }

        var
            //current state of the machine
            currentState,

            //storage for notification callbacks
            notificationStore = [],

            //notify callbacks about a transition
            notify = function () {

                //make copy of notification storage
                var notifications = notificationStore.slice();

                //walk over stored callbacks
                for (var i = 0, l = notifications.length; i < l; i++) {

                    //and notify them
                    notifications[i].apply(this, arguments);
                }
            },

            //storage for machine states
            stateStore = {

                //evaluates the current state
                getMachineState: function getMachineState() {

                    //return current state as string
                    return currentState.name;
                },

                //function to transition into another state
                setMachineState: function setMachineState(nextState /*, eventName */) {

                    var
                        //event that triggered the transition
                        eventName = arguments[1],

                        //before state hook
                        onBeforeState,

                        //enter state hook
                        onEnterState,

                        //leave state hook
                        onLeaveState,

                        //store last machine state
                        lastState = currentState;

                    //if state machine cannot handle returned state
                    if (!nextState || !nextState.name || !stateStore[nextState.name]) {

                        //throw invalid state exception
                        throw new InvalidStateError('Stately.js: Transitioned into invalid state: `' + setMachineState.caller + '`.');
                    }

                    //transition into next state
                    currentState = nextState;

                    //retrieve enter state hook
                    onBeforeState = stateMachine['onbefore' + currentState.name];

                    //if a hook is attached
                    if (onBeforeState && typeof onBeforeState === 'function') {

                        //apply it
                        onBeforeState.call(stateStore, eventName, lastState.name, nextState.name);
                    }

                    //retrieve enter state hook
                    onEnterState = stateMachine['onenter' + currentState.name] || stateMachine['on' + currentState.name];

                    //if a hook is attached
                    if (onEnterState && typeof onEnterState === 'function') {

                        //apply it
                        onEnterState.call(stateStore, eventName, lastState.name, nextState.name);
                    }

                    //retrieve leave state hook
                    onLeaveState = stateMachine['onleave' + currentState.name];

                    //if a hook is attached
                    if (onLeaveState && typeof onLeaveState === 'function') {

                        //apply it
                        onLeaveState.call(stateStore, eventName, lastState.name, nextState.name);
                    }

                    //notify notification callbacks about transition
                    notify.call(stateStore, eventName, lastState.name, nextState.name);

                    //return the state store
                    return this;
                },

                //function returns the possible events in current state
                getMachineEvents: function getMachineEvents() {

                    //storage for the events in current state
                    var events = [];

                    //walk over the events of the current state
                    for (property in currentState) {

                        //ensure to only walk over own properties
                        if (currentState.hasOwnProperty(property)) {

                            //if it is an event function
                            if (typeof currentState[property] === 'function') {

                                //store it in events storage
                                events.push(property);
                            }
                        }
                    }

                    //return the possible events
                    return events;
                }

            },

            //the state machine
            stateMachine = {

                //copy function to public state machine object
                getMachineState: stateStore.getMachineState,

                //copy function to public state machine object
                getMachineEvents: stateStore.getMachineEvents,

                //store a new notification callback
                bind: function bind(callback) {

                    //if we have a new notification callback
                    if (callback) {

                        //store it in notification storage
                        notificationStore.push(callback);
                    }

                    //return the state machine
                    return this;
                },

                //remove a notification callback from storage
                unbind: function unbind(callback) {

                    //if no callback is given
                    if (!callback) {

                        //reset notification storage
                        notificationStore = [];

                    } else {

                        //walk over stored callbacks
                        for (var i = 0, l = notificationStore.length; i < l; i++) {

                            //if callback is found in notification storage
                            if (notificationStore[i] === callback) {

                                //remove it
                                notificationStore.splice(i, 1);
                            }
                        }
                    }

                    //return the state machine
                    return this;
                }
            },

            //event decorator factory function
            transition = function transition(stateName, eventName, nextEvent) {

                //the decorator
                return function event() {

                    var
                        //before event hook
                        onBeforeEvent,

                        //after event hook
                        onAfterEvent,

                        //new state machine changed into
                        nextState,

                        //return the state machine if no event returns something
                        eventValue = stateMachine;

                    //if attached event handler doesn't handle this event
                    if (stateStore[stateName] !== currentState) {

                        //try other events in chain
                        if (nextEvent) {

                            //let next event function handle this event
                            eventValue = nextEvent.apply(stateStore, arguments);
                        }

                        //or return value of action
                        return eventValue;
                    }

                    //retrieve before event hook
                    onBeforeEvent = stateMachine['onbefore' + eventName];

                    //if a hook is attached
                    if (onBeforeEvent && typeof onBeforeEvent === 'function') {

                        //apply it
                        onBeforeEvent.call(stateStore, eventName, currentState.name, currentState.name);
                    }

                    //run action
                    eventValue = stateStore[stateName][eventName].apply(stateStore, arguments);

                    //check return value of action
                    if (typeof eventValue === 'undefined') {

                        //nothing returned, stay in current state
                        nextState = currentState;

                        //return state machine
                        eventValue = stateMachine;

                    } else if (toString.call(eventValue) === '[object Object]') {

                        //if state store object is returned ('this' in action function) stay in current state
                        nextState = (eventValue === stateStore ? currentState : eventValue);

                        //return state machine
                        eventValue = stateMachine;

                    } else if (toString.call(eventValue) === '[object Array]' && eventValue.length >= 1) {

                        //else first element is next state
                        nextState = eventValue[0];

                        //second element is return value
                        eventValue = eventValue[1];
                    }

                    //retrieve after event hook
                    onAfterEvent = stateMachine['onafter' + eventName] || stateMachine['on' + eventName];

                    //if a hook is attached
                    if (onAfterEvent && typeof onAfterEvent === 'function') {

                        //apply it
                        onAfterEvent.call(stateStore, eventName, currentState.name, nextState.name);
                    }

                    //transition into next state
                    stateStore.setMachineState(nextState, eventName);

                    //return desired value
                    return eventValue;
                };
            };

        //walk over states object
        for (var stateName in statesObject) {

            //check own properties
            if (statesObject.hasOwnProperty(stateName)) {

                //store states in storage
                stateStore[stateName] = statesObject[stateName];

                //walk over events
                for (var eventName in stateStore[stateName]) {

                    //check for own property
                    if (stateStore[stateName].hasOwnProperty(eventName)) {

                        //if type is a string, assume it is a state
                        if (typeof stateStore[stateName][eventName] === 'string') {

                            //decorate it
                            stateStore[stateName][eventName] = (function (stateName) {

                                //with a function
                                return function event() {

                                    //returning the given state
                                    return this[stateName];
                                };

                            })(stateStore[stateName][eventName]);
                        }

                        //if type function
                        if (typeof stateStore[stateName][eventName] === 'function') {

                            //assign decorated events to state machine
                            stateMachine[eventName] = transition(stateName, eventName, stateMachine[eventName]);
                        }
                    }
                }

                //attach states name to object in storage
                stateStore[stateName].name = stateName;

                //initial state is the first passed in state
                if (!currentState) {

                    //make initial state the current state
                    currentState = stateStore[stateName];
                }
            }
        }

        //if there is no initial state
        if (!currentState) {

            //throw invalid state exception
            throw new InvalidStateError('Stately.js: Invalid initial state.');
        }

        //return the new state machine
        return stateMachine;
    }

    //a factory for new machines
    Stately.machine = function machine(statesObject) {
        return new Stately(statesObject);
    };

    //InvalidStateError exception
    Stately.InvalidStateError = InvalidStateError;

    //export Stately object
    return Stately;

});
<|endoftext|>


<commit_before>/**
 * 更新比赛状态
 * */
var query = require("../../service/common/connection").query;

var request = require("request");
var cheerio = require("cheerio");

var log;
module.exports = function (runner) {
    log = runner && runner.log || console.log;
    var today = new Date();
    today.setHours(0);
    today.setMinutes(0);
    today.setSeconds(0);
    today.setMilliseconds(0);

    var tomorrow = new Date(today);
    tomorrow.setDate(tomorrow.getDate() + 1);

    query("select * from playball.Game where Time between ? and ? and Status<2", [today, tomorrow], function (error, results) {
        if (!error && results && results.length) {

            results.forEach(function (game) {
                if (game.Status == 0 && new Date(game.Time) < new Date()) {
                    //已经开始
                    updateStatus(game.GameID, 1);
                }
                if (game.Status == 1) {
                    findScore("http://g.hupu.com/nba/daily/boxscore_" + game.ThirdID + ".html", game.GameID, game);
//                    findScore("http://g.hupu.com/nba/homepage/getMatchBasicInfo?matchId="+game.ThirdID, game.GameID, game);
                }

            });
        }
    });
};

function findScore(liveUrl, id, game) {
    log("request hupu game page " + liveUrl + " to get score.. ");

    request(liveUrl, function (errors, response, body) {
        if (!errors && response && response.statusCode == 200) {
            var $ = cheerio.load(body);

            var list = $(".table_list_c li");
            list.each(function (i, li) {
                var link = $(li).find("a").attr("href");
                if (~link.indexOf(game.ThirdID)) {
                    //命中同一场比赛
                    var hs = "0" , vs = "0";
                    var status;
                    $(li).find(".name").each(function (j, name) {
                        var score = $(name).parent().text().match(/(\d+)/)[0];
                        if (j == 0) {
                            hs = score
                        } else {
                            vs = score;
                        }
                    });
                    updateScore(id, hs, vs);

                    if ($(li).find("p").text() == "已结束") {
                        status = 2;
                    }
                    if (status) {
                        updateStatus(id, status, +hs > +vs ? game.HostID : game.VisitID, game);
                    }
                }
            });
        }
    });
}

function updateScore(id, hs, vs) {
    log("update game " + id + " " + hs + "-" + vs);
    query("update playball.Game set ? where GameID=" + id, {
        HostScore: hs,
        VisitScore: vs
    }, function (err) {
        if (err) {
            log(err);
        }
    });
}

function updateStatus(id, status, winnerID, game) {
    if (status != 2) {
        winnerID = 0;
    }
    query("update playball.Game set ? where GameID=" + id, {
        Status: status,
        WinnerID: winnerID || 0
    }, function (err) {
        if (err) {
            log(err);
        } else {
            if (status == 2 && game && game.IsPlayOff == 1 && game.RoundID) {
                query('select * from playball.PlayOff where RoundID = ?', [game.RoundID], function (err, round) {
                    if (!err && round && round.length) {
                        round = round[0];
                        var key = winnerID == round.HostID ? 'HostWin' : 'VisitWin';
                        query('update playball.PlayOff set ' + key + '= ' + key + '+1 where RoundID= ?', [game.RoundID], function (e) {
                            if (e) {
                                log(e);
                            }
                        });
                    }
                });

            }
        }
    });
}

<commit_msg>bug fix<commit_after>/**
 * 更新比赛状态
 * */
var query = require("../../service/common/connection").query;

var request = require("request");
var cheerio = require("cheerio");

var log;
module.exports = function (runner) {
    log = runner && runner.log || console.log;
    var today = new Date();
    today.setHours(0);
    today.setMinutes(0);
    today.setSeconds(0);
    today.setMilliseconds(0);

    var tomorrow = new Date(today);
    tomorrow.setDate(tomorrow.getDate() + 1);

    query("select * from playball.Game where Time between ? and ? and Status<2", [today, tomorrow], function (error, results) {
        if (!error && results && results.length) {

            results.forEach(function (game) {
                if (game.Status == 0 && new Date(game.Time) < new Date()) {
                    //已经开始
                    updateStatus(game.GameID, 1);
                }
                if (game.Status == 1) {
                    findScore("http://g.hupu.com/nba/daily/boxscore_" + game.ThirdID + ".html", game.GameID, game);
//                    findScore("http://g.hupu.com/nba/homepage/getMatchBasicInfo?matchId="+game.ThirdID, game.GameID, game);
                }

            });
        }
    });
};

function findScore(liveUrl, id, game) {
    log("request hupu game page " + liveUrl + " to get score.. ");

    request(liveUrl, function (errors, response, body) {
        if (!errors && response && response.statusCode == 200) {
            var $ = cheerio.load(body);

            var list = $(".table_list_c li");
            list.each(function (i, li) {
                var link = $(li).find("a").attr("href");
                if (~link.indexOf(game.ThirdID)) {
                    //命中同一场比赛
                    var hs = "0" , vs = "0";
                    var status;
                    $(li).find(".name").each(function (j, name) {
                        var score = $(name).parent().text().match(/(\d+)/)[0];
                        if (j == 0) {
                            hs = score
                        } else {
                            vs = score;
                        }
                    });
                    updateScore(id, hs, vs);

                    if ($(li).find("p").text() == "已结束") {
                        status = 2;
                    }
                    if (status) {
                        updateStatus(id, status, +hs > +vs ? game.HostID : game.VisitID, game);
                    }
                }
            });
        }
    });
}

function updateScore(id, hs, vs) {
    log("update game " + id + " " + hs + "-" + vs);
    query("update playball.Game set ? where GameID=" + id, {
        HostScore: hs,
        VisitScore: vs
    }, function (err) {
        if (err) {
            log(err);
        }
    });
}

function updateStatus(id, status, winnerID, game) {
    if (status != 2) {
        winnerID = 0;
    }
    query("update playball.Game set ? where GameID=" + id, {
        Status: status,
        WinnerID: winnerID || 0
    }, function (err) {
        if (err) {
            log(err);
        } else {
            if (status == 2 && game && game.IsPlayOff == 1 && game.RoundID) {
                query('select * from playball.PlayOff where RoundID = ?', [game.RoundID], function (err, round) {
                    if (!err && round && round.length) {
                        round = round[0];
                        var key = winnerID == round.HostID ? 'HostWin' : 'VisitWin';
                        query('update playball.PlayOff set ' + key + '= ' + key + '+1 where RoundID= ? and '+key+' < 4', [game.RoundID], function (e) {
                            if (e) {
                                log(e);
                            }
                        });
                    }
                });

            }
        }
    });
}

<|endoftext|>


<commit_before>module.exports = class ObjectUtil {

  // Retrieves key for given value (if any) in object
  static keyByValue(object, target) {
    if(!'lookup' in object) {
      lookup = {}
      for(var key in object) {
        if(object.hasOwnProperty(key)) {
          lookup[value] = object[key]
        }
      }
      object.lookup = lookup
    }

    return object.lookup[target]
  }

}
<commit_msg>Fix ObjectUtil.keyByValue<commit_after>module.exports = class ObjectUtil {

  // Retrieves key for given value (if any) in object
  static keyByValue(object, target) {
    if(!('lookup' in object)) {
      const lookup = {}
      for(var key in object) {
        if(object.hasOwnProperty(key)) {
          var value = object[key]
          lookup[value] = key
        }
      }
      object.lookup = lookup
    }

    return object.lookup[target]
  }

}
<|endoftext|>