<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var fs = require('fs');
var TypedError = require('error/typed');
var WrappedError = require('error/wrapped');
var timers = require('timers');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var safeJsonParse = require('safe-json-parse/tuple');

var Reporter = require('../tcollector/reporter.js');
var TChannelJSON = require('../as/json.js');

var AdvertisementTimeoutError = WrappedError({
    type: 'hyperbahn-client.advertisement-timeout',
    message: 'Hyperbahn advertisement timed out after {time} ms!.\n' +
        '{origMessage}.\n'
});

var AlreadyDestroyed = TypedError({
    type: 'hyperbahn-client.already-destroyed',
    message: 'HyperbahnClient was already destroyed.\n' +
        'Cannot invoke {method}.',
    method: null
});

var States = {
    UNADVERTISED: 'UNADVERTISED',
    ADVERTISED: 'ADVERTISED'
};
var DEFAULT_TTL = 60 * 1000;
var DEFAULT_ERROR_RETRY_TIMES = [
    200, // One fast retry

    1000, // Fibonacci backoff
    1000,
    2000,
    3000,
    5000,
    8000,

    10000 // Max out at 10 seconds
];
var DEFAULT_TIMEOUT = 500;

module.exports = HyperbahnClient;

// # HyperbahnClient
// options.
//   * (required) tchannel: tchannel instance
//   * (required) serviceName: string service name
//   * (required) hostPortList: array of initial hyperbahn nodes
//   * callerName: the caller name
//   * logger: logtron instance
//   * reportTracing: Whether to report tracing
//   * hardFail: boolean; default false; whether or not to fail hard when we
//     can't advertise or on unexpected hyperbahn errors
//   * registrationTimeout: deprecated
//   * advertisementTimeout: integer. In hardFail mode we default to 5000. If
//     not in hardFail mode we don't time out advertisements.
function HyperbahnClient(options) {
    /*eslint max-statements: [2, 25] complexity: [2, 20] */
    if (!(this instanceof HyperbahnClient)) {
        return new HyperbahnClient(options);
    }

    var self = this;

    EventEmitter.call(this);

    assert(options && options.tchannel && !options.tchannel.topChannel,
        'Must pass in top level tchannel');
    assert(options.tchannel.tracer, 'Top channel must have trace enabled');
    assert(options.serviceName, 'must pass in serviceName');
    if (Array.isArray(options.hostPortList)) {
        self.hostPortList = options.hostPortList;
    } else if (typeof options.hostPortFile === 'string') {
        var tuple = safeSyncRead(options.hostPortFile);
        assert(!tuple[0], 'Failed to read the hostPortFile');
        tuple = safeJsonParse(tuple[1]);
        assert(!tuple[0], 'Failed to parse the hostPortFile');
        assert(Array.isArray(tuple[1]), 'The hostPortFile must contain a hostPortList');
        self.hostPortList = tuple[1];
    } else {
        assert(false, 'Must pass in hostPortList or hostPortFile');
    }

    self.serviceName = options.serviceName;
    self.callerName = options.callerName || options.serviceName;
    self.tchannel = options.tchannel;
    self.reportTracing = 'reportTracing' in options ?
        options.reportTracing : true;
    self.hardFail = !!options.hardFail;
    self.advertiseInterval = options.advertiseInterval || DEFAULT_TTL;
    self.timeoutFuzz = self.advertiseInterval;
    self.errorRetryTimes = options.errorRetryTimes || DEFAULT_ERROR_RETRY_TIMES;

    self.logger = options.logger || self.tchannel.logger;
    self.statsd = options.statsd;

    self.reporter = Reporter({
        channel: self.getClientChannel({
            serviceName: 'tcollector',
            trace: false
        }),
        logger: self.logger,
        callerName: self.callerName,
        logWarnings: options.logTraceWarnings
    });
    self.tchannel.tracer.reporter = function report(span) {
        if (self.reportTracing) {
            self.reporter.report(span);
        }
    };

    if (!self.reportTracing) {
        self.logger.warn('HyperbahnClient tcollector tracing is OFF', {
            service: self.serviceName
        });
    }

    self.hyperbahnChannel = self.tchannel.subChannels.hyperbahn ||
        self.tchannel.makeSubChannel({
            serviceName: 'hyperbahn',
            peers: self.hostPortList
        });
    self.tchannelJSON = TChannelJSON();

    self.lastError = null;
    self.latestAdvertisementResult = null;
    self.attemptCounter = 0;
    self.state = States.UNADVERTISED;
    self._destroyed = false;
    self.defaultTimeout = options.defaultTimeout || DEFAULT_TIMEOUT;

    var advertisementTimeout = options.advertisementTimeout ||
        options.registrationTimeout;
    if (self.hardFail) {
        self.advertisementTimeoutTime = advertisementTimeout || 5000;
    } else {
        self.advertisementTimeoutTime = 0;
    }
}

util.inherits(HyperbahnClient, EventEmitter);

HyperbahnClient.prototype.setReportTracing = function setReportTracing(bool) {
    var self = this;

    self.reportTracing = bool;
};

// Gets the subchannel for hitting a particular service.
HyperbahnClient.prototype.getClientChannel =
function getClientChannel(options) {
    var self = this;

    assert(options && options.serviceName, 'must pass serviceName');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'getClientChannel'
        }));
        return null;
    }

    if (self.tchannel.subChannels[options.serviceName]) {
        return self.tchannel.subChannels[options.serviceName];
    }

    var channelOptions = {
        peers: self.hostPortList,
        serviceName: options.serviceName,
        requestDefaults: {
            serviceName: options.serviceName,
            headers: {
                cn: self.callerName
            }
        }
    };
    if ('trace' in options) {
        channelOptions.trace = options.trace;
    }
    if ('timeout' in options) {
        channelOptions.requestDefaults.timeout = options.timeout;
    }
    if ('retryLimit' in options) {
        channelOptions.requestDefaults.retryLimit = options.retryLimit;
    }

    return self.tchannel.makeSubChannel(channelOptions);
};

// ## advertisementTimeout
// Called after a certain amount of time to have a fatal error when reg fails.
// Will not be called if options.advertisementTimeout isn't passed in
HyperbahnClient.prototype.advertisementTimeout =
function advertisementTimeout() {
    var self = this;

    if (self.state === States.UNADVERTISED) {
        var lastError = self.lastError ||
            new Error('advertisement timeout!');
        var err = AdvertisementTimeoutError(lastError, {
            time: self.advertisementTimeoutTime
        });

        self.logger.fatal('HyperbahnClient: advertisement timed out', {
            timeout: self.advertisementTimeout,
            error: err
        });

        self.advertisementFailure(err);
    }
    // TODO else warn
};

HyperbahnClient.prototype.advertisementFailure =
function advertisementFailure(err) {
    var self = this;

    self.destroy();
    self.emit('error', err);

    if (self.statsd) {
        self.statsd.increment(
            'hyperbahn-client.' + self.serviceName + '.advertisement.failure'
        );
    }
};

HyperbahnClient.prototype.sendRequest =
function sendRequest(opts, endpoint, cb) {
    var self = this;

    var req = self.hyperbahnChannel.request({
        serviceName: 'hyperbahn',
        timeout: (opts && opts.timeout) || self.defaultTimeout,
        hasNoParent: true,
        trace: false,
        retryLimit: 1,
        headers: {
            cn: self.callerName
        }
    });
    self.tchannelJSON.send(req, endpoint, null, {
        services: [{
            cost: 0,
            serviceName: self.serviceName
        }]
    }, cb);
};

// ## advertise
// Advertise with Hyperbahn. If called with a callback, the callback will not be
// called until there has been a successful advertisement. This function
// attempts a advertise and retries until there are no healthy servers left; it
// will then repeatedly choose random servers to try until it finds one that
// works.
// register is **deprecated**
HyperbahnClient.prototype.register =
HyperbahnClient.prototype.advertise =
function advertise(opts) {
    var self = this;
    // Attempt a advertisement. If it succeeds, setTimeout to re-advertise with
    // the same server after the TTL.

    assert(self.tchannel.hostPort,
        'must call tchannel.listen() before advertise()');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'advertise'
        }));
        return;
    }

    if (self.advertisementTimeoutTime) {
        // Start the timeout timer
        self.advertisementTimeoutTimer = timers.setTimeout(
            function advertisementTimeoutTimer() {
                self.advertisementTimeout();
            },
            self.advertisementTimeoutTime
        );
    }

    self.attemptCounter++;
    self.sendRequest(opts, 'ad', advertiseInternalCb);
    self.emit('advertise-attempt');

    function advertiseInternalCb(err, result) {
        /*eslint max-statements: [2, 40] */
        if (err) {
            self.logger[self.hardFail ? 'error' : 'warn'](
                'HyperbahnClient: advertisement failure, ' +
                'marking server as sick', {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            self.lastError = err;

            self.advertiseAgain(self.getErrorRetryTime());
            return;
        }

        if (result.ok === false) {
            err = result.body;
            var errInfo2 = {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            };

            self.logger[self.hardFail ? 'fatal' : 'warn'](
                'HyperbahnClient: unexpected failure (from Hyperbahn)',
                errInfo2
            );

            if (self.hardFail) {
                self.advertisementFailure(err);
            } else {
                self.advertiseAgain(self.getErrorRetryTime());
            }

            return;
        }

        if (self.statsd) {
            self.statsd.increment(
                'hyperbahn-client.' + self.serviceName +
                    '.advertisement.success'
            );
        }

        self.latestAdvertisementResult = result;
        self.attemptCounter = 0;
        self.state = States.ADVERTISED;
        timers.clearTimeout(self.advertisementTimeoutTimer);

        self.advertiseAgain(self.getHealthyRetryTime());

        // registered event is deprecated
        self.emit('registered');
        self.emit('advertised');
    }
};

HyperbahnClient.prototype.unadvertise =
function unadvertise(opts) {
    var self = this;
    self.sendRequest(opts, 'unad', unadvertiseInternalCb);
    timers.clearTimeout(self._advertisementTimer);
    timers.clearTimeout(self.advertisementTimeoutTimer);
    self.latestAdvertisementResult = null;
    self.state = States.UNADVERTISED;
    self.emit('unadvertised');
    function unadvertiseInternalCb(error, result) {
        if (error) {
            self.logger.warn('HyperbahnClient: unadvertisement failure', {
                error: error,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            return;
        }
    }
};

HyperbahnClient.prototype.getErrorRetryTime = function getErrorRetryTime() {
    var self = this;

    return self.errorRetryTimes[self.attemptCounter - 1] ||
        self.errorRetryTimes[self.errorRetryTimes.length - 1];
};

HyperbahnClient.prototype.getHealthyRetryTime = function getHealthyRetryTime() {
    var self = this;

    var fuzz = self.timeoutFuzz;
    var delay = Math.round(Math.floor(Math.random() * fuzz)) - (fuzz / 2);

    return self.advertiseInterval + delay;
};

HyperbahnClient.prototype.advertiseAgain =
function advertiseAgain(delay) {
    var self = this;

    if (self._destroyed) {
        return;
    }

    self._advertisementTimer = timers.setTimeout(
        function advertiseTimeout() {
            self.advertise();
        },
        delay
    );
};

// ## destroy
HyperbahnClient.prototype.destroy = function destroy() {
    var self = this;
    if (self._destroyed) {
        return;
    }

    self._destroyed = true;
    timers.clearTimeout(self._advertisementTimer);
    timers.clearTimeout(self.advertisementTimeoutTimer);
};

function safeSyncRead(filePath) {
    var fileContents = null;
    var error;

    try {
        fileContents = fs.readFileSync(filePath, 'utf8');
    } catch (err) {
        error = err;
    }

    return [error, fileContents];
}
<commit_msg>Put log entry back but only log once<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var fs = require('fs');
var TypedError = require('error/typed');
var WrappedError = require('error/wrapped');
var timers = require('timers');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var safeJsonParse = require('safe-json-parse/tuple');

var Reporter = require('../tcollector/reporter.js');
var TChannelJSON = require('../as/json.js');

var AdvertisementTimeoutError = WrappedError({
    type: 'hyperbahn-client.advertisement-timeout',
    message: 'Hyperbahn advertisement timed out after {time} ms!.\n' +
        '{origMessage}.\n'
});

var AlreadyDestroyed = TypedError({
    type: 'hyperbahn-client.already-destroyed',
    message: 'HyperbahnClient was already destroyed.\n' +
        'Cannot invoke {method}.',
    method: null
});

var States = {
    UNADVERTISED: 'UNADVERTISED',
    ADVERTISED: 'ADVERTISED'
};
var DEFAULT_TTL = 60 * 1000;
var DEFAULT_ERROR_RETRY_TIMES = [
    200, // One fast retry

    1000, // Fibonacci backoff
    1000,
    2000,
    3000,
    5000,
    8000,

    10000 // Max out at 10 seconds
];
var DEFAULT_TIMEOUT = 500;

module.exports = HyperbahnClient;

// # HyperbahnClient
// options.
//   * (required) tchannel: tchannel instance
//   * (required) serviceName: string service name
//   * (required) hostPortList: array of initial hyperbahn nodes
//   * callerName: the caller name
//   * logger: logtron instance
//   * reportTracing: Whether to report tracing
//   * hardFail: boolean; default false; whether or not to fail hard when we
//     can't advertise or on unexpected hyperbahn errors
//   * registrationTimeout: deprecated
//   * advertisementTimeout: integer. In hardFail mode we default to 5000. If
//     not in hardFail mode we don't time out advertisements.
function HyperbahnClient(options) {
    /*eslint max-statements: [2, 25] complexity: [2, 20] */
    if (!(this instanceof HyperbahnClient)) {
        return new HyperbahnClient(options);
    }

    var self = this;

    EventEmitter.call(this);

    assert(options && options.tchannel && !options.tchannel.topChannel,
        'Must pass in top level tchannel');
    assert(options.tchannel.tracer, 'Top channel must have trace enabled');
    assert(options.serviceName, 'must pass in serviceName');
    if (Array.isArray(options.hostPortList)) {
        self.hostPortList = options.hostPortList;
    } else if (typeof options.hostPortFile === 'string') {
        var tuple = safeSyncRead(options.hostPortFile);
        assert(!tuple[0], 'Failed to read the hostPortFile');
        tuple = safeJsonParse(tuple[1]);
        assert(!tuple[0], 'Failed to parse the hostPortFile');
        assert(Array.isArray(tuple[1]), 'The hostPortFile must contain a hostPortList');
        self.hostPortList = tuple[1];
    } else {
        assert(false, 'Must pass in hostPortList or hostPortFile');
    }

    self.serviceName = options.serviceName;
    self.callerName = options.callerName || options.serviceName;
    self.tchannel = options.tchannel;
    self.reportTracing = 'reportTracing' in options ?
        options.reportTracing : true;
    self.hardFail = !!options.hardFail;
    self.advertiseInterval = options.advertiseInterval || DEFAULT_TTL;
    self.timeoutFuzz = self.advertiseInterval;
    self.errorRetryTimes = options.errorRetryTimes || DEFAULT_ERROR_RETRY_TIMES;

    self.logger = options.logger || self.tchannel.logger;
    self.statsd = options.statsd;

    self.reporter = Reporter({
        channel: self.getClientChannel({
            serviceName: 'tcollector',
            trace: false
        }),
        logger: self.logger,
        callerName: self.callerName,
        logWarnings: options.logTraceWarnings
    });
    self.tchannel.tracer.reporter = function report(span) {
        if (self.reportTracing) {
            self.reporter.report(span);
        }
    };

    if (!self.reportTracing) {
        self.logger.warn('HyperbahnClient tcollector tracing is OFF', {
            service: self.serviceName
        });
    }

    self.hyperbahnChannel = self.tchannel.subChannels.hyperbahn ||
        self.tchannel.makeSubChannel({
            serviceName: 'hyperbahn',
            peers: self.hostPortList
        });
    self.tchannelJSON = TChannelJSON();

    self.lastError = null;
    self.latestAdvertisementResult = null;
    self.attemptCounter = 0;
    self.state = States.UNADVERTISED;
    self._destroyed = false;
    self.defaultTimeout = options.defaultTimeout || DEFAULT_TIMEOUT;

    var advertisementTimeout = options.advertisementTimeout ||
        options.registrationTimeout;
    if (self.hardFail) {
        self.advertisementTimeoutTime = advertisementTimeout || 5000;
    } else {
        self.advertisementTimeoutTime = 0;
        self.logger.info('HyperbahnClient advertisement timeout disabled', {
            service: self.serviceName
        });
    }
}

util.inherits(HyperbahnClient, EventEmitter);

HyperbahnClient.prototype.setReportTracing = function setReportTracing(bool) {
    var self = this;

    self.reportTracing = bool;
};

// Gets the subchannel for hitting a particular service.
HyperbahnClient.prototype.getClientChannel =
function getClientChannel(options) {
    var self = this;

    assert(options && options.serviceName, 'must pass serviceName');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'getClientChannel'
        }));
        return null;
    }

    if (self.tchannel.subChannels[options.serviceName]) {
        return self.tchannel.subChannels[options.serviceName];
    }

    var channelOptions = {
        peers: self.hostPortList,
        serviceName: options.serviceName,
        requestDefaults: {
            serviceName: options.serviceName,
            headers: {
                cn: self.callerName
            }
        }
    };
    if ('trace' in options) {
        channelOptions.trace = options.trace;
    }
    if ('timeout' in options) {
        channelOptions.requestDefaults.timeout = options.timeout;
    }
    if ('retryLimit' in options) {
        channelOptions.requestDefaults.retryLimit = options.retryLimit;
    }

    return self.tchannel.makeSubChannel(channelOptions);
};

// ## advertisementTimeout
// Called after a certain amount of time to have a fatal error when reg fails.
// Will not be called if options.advertisementTimeout isn't passed in
HyperbahnClient.prototype.advertisementTimeout =
function advertisementTimeout() {
    var self = this;

    if (self.state === States.UNADVERTISED) {
        var lastError = self.lastError ||
            new Error('advertisement timeout!');
        var err = AdvertisementTimeoutError(lastError, {
            time: self.advertisementTimeoutTime
        });

        self.logger.fatal('HyperbahnClient: advertisement timed out', {
            timeout: self.advertisementTimeout,
            error: err
        });

        self.advertisementFailure(err);
    }
    // TODO else warn
};

HyperbahnClient.prototype.advertisementFailure =
function advertisementFailure(err) {
    var self = this;

    self.destroy();
    self.emit('error', err);

    if (self.statsd) {
        self.statsd.increment(
            'hyperbahn-client.' + self.serviceName + '.advertisement.failure'
        );
    }
};

HyperbahnClient.prototype.sendRequest =
function sendRequest(opts, endpoint, cb) {
    var self = this;

    var req = self.hyperbahnChannel.request({
        serviceName: 'hyperbahn',
        timeout: (opts && opts.timeout) || self.defaultTimeout,
        hasNoParent: true,
        trace: false,
        retryLimit: 1,
        headers: {
            cn: self.callerName
        }
    });
    self.tchannelJSON.send(req, endpoint, null, {
        services: [{
            cost: 0,
            serviceName: self.serviceName
        }]
    }, cb);
};

// ## advertise
// Advertise with Hyperbahn. If called with a callback, the callback will not be
// called until there has been a successful advertisement. This function
// attempts a advertise and retries until there are no healthy servers left; it
// will then repeatedly choose random servers to try until it finds one that
// works.
// register is **deprecated**
HyperbahnClient.prototype.register =
HyperbahnClient.prototype.advertise =
function advertise(opts) {
    var self = this;
    // Attempt a advertisement. If it succeeds, setTimeout to re-advertise with
    // the same server after the TTL.

    assert(self.tchannel.hostPort,
        'must call tchannel.listen() before advertise()');

    if (self._destroyed) {
        self.emit('error', AlreadyDestroyed({
            method: 'advertise'
        }));
        return;
    }

    if (self.advertisementTimeoutTime) {
        // Start the timeout timer
        self.advertisementTimeoutTimer = timers.setTimeout(
            function advertisementTimeoutTimer() {
                self.advertisementTimeout();
            },
            self.advertisementTimeoutTime
        );
    }

    self.attemptCounter++;
    self.sendRequest(opts, 'ad', advertiseInternalCb);
    self.emit('advertise-attempt');

    function advertiseInternalCb(err, result) {
        /*eslint max-statements: [2, 40] */
        if (err) {
            self.logger[self.hardFail ? 'error' : 'warn'](
                'HyperbahnClient: advertisement failure, ' +
                'marking server as sick', {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            self.lastError = err;

            self.advertiseAgain(self.getErrorRetryTime());
            return;
        }

        if (result.ok === false) {
            err = result.body;
            var errInfo2 = {
                error: err,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            };

            self.logger[self.hardFail ? 'fatal' : 'warn'](
                'HyperbahnClient: unexpected failure (from Hyperbahn)',
                errInfo2
            );

            if (self.hardFail) {
                self.advertisementFailure(err);
            } else {
                self.advertiseAgain(self.getErrorRetryTime());
            }

            return;
        }

        if (self.statsd) {
            self.statsd.increment(
                'hyperbahn-client.' + self.serviceName +
                    '.advertisement.success'
            );
        }

        self.latestAdvertisementResult = result;
        self.attemptCounter = 0;
        self.state = States.ADVERTISED;
        timers.clearTimeout(self.advertisementTimeoutTimer);

        self.advertiseAgain(self.getHealthyRetryTime());

        // registered event is deprecated
        self.emit('registered');
        self.emit('advertised');
    }
};

HyperbahnClient.prototype.unadvertise =
function unadvertise(opts) {
    var self = this;
    self.sendRequest(opts, 'unad', unadvertiseInternalCb);
    timers.clearTimeout(self._advertisementTimer);
    timers.clearTimeout(self.advertisementTimeoutTimer);
    self.latestAdvertisementResult = null;
    self.state = States.UNADVERTISED;
    self.emit('unadvertised');
    function unadvertiseInternalCb(error, result) {
        if (error) {
            self.logger.warn('HyperbahnClient: unadvertisement failure', {
                error: error,
                serviceName: self.serviceName,
                hostPort: self.hostPort
            });
            return;
        }
    }
};

HyperbahnClient.prototype.getErrorRetryTime = function getErrorRetryTime() {
    var self = this;

    return self.errorRetryTimes[self.attemptCounter - 1] ||
        self.errorRetryTimes[self.errorRetryTimes.length - 1];
};

HyperbahnClient.prototype.getHealthyRetryTime = function getHealthyRetryTime() {
    var self = this;

    var fuzz = self.timeoutFuzz;
    var delay = Math.round(Math.floor(Math.random() * fuzz)) - (fuzz / 2);

    return self.advertiseInterval + delay;
};

HyperbahnClient.prototype.advertiseAgain =
function advertiseAgain(delay) {
    var self = this;

    if (self._destroyed) {
        return;
    }

    self._advertisementTimer = timers.setTimeout(
        function advertiseTimeout() {
            self.advertise();
        },
        delay
    );
};

// ## destroy
HyperbahnClient.prototype.destroy = function destroy() {
    var self = this;
    if (self._destroyed) {
        return;
    }

    self._destroyed = true;
    timers.clearTimeout(self._advertisementTimer);
    timers.clearTimeout(self.advertisementTimeoutTimer);
};

function safeSyncRead(filePath) {
    var fileContents = null;
    var error;

    try {
        fileContents = fs.readFileSync(filePath, 'utf8');
    } catch (err) {
        error = err;
    }

    return [error, fileContents];
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name        imgur_show_user_stats_light
// @namespace   someName
// @include     http://imgur.com/user/*
// @include     https://imgur.com/user/*
// @version     0.1c
// @grant       none
// ==/UserScript==

$( window ).load(function() {
	var CLIENT_ID = "cd0695f1226536b";

	if(window.location.pathname.indexOf('/user/') === 0 && $('.button').filter('.comments').length > 0){
		var newBox = $('

');
		var tble = $('
' +
								 '
Account creation	 -
'+
								 '
Comments	 -
'+
								 '
Submissions	 -
'+
								 '
Albums	 -
'+
								 '
Images	 -
'+
								 '
Favorites	 -
'+
								 '
 -
'+
								 '
 -
'+
								 '
');
		newBox.append(tble);
		newBox.insertBefore( $('.icons').filter('.textbox') );
		var username = window.location.pathname.split("/", 3)[2];

		// get coments / submission stats
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username+'/gallery_profile',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log(request.getAllResponseHeaders());
				//console.log(result);
				$('#stats_comments').html(result.data.total_gallery_comments.toLocaleString());
				$('#stats_submissions').html(result.data.total_gallery_submissions.toLocaleString());
				$('#stats_favorites').html(result.data.total_gallery_favorites.toLocaleString());
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
			}
		});

		// get the excat join date. TODO: I bet i messed up the time(zones) here.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username,
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log(request.getAllResponseHeaders());
				$('#stats_created').html( new Date(result.data.created * 1000).toLocaleDateString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
			}
		});

		// album count (inklusive not submitted to gallery), if album settings are set to public.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username + '/albums/count',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				$('#stats_albums').html( result.data.toLocaleString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_albums').html( "private" );
			}
		});

		// image count (inklusive not submitted to gallery), if image settings are set to public.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username + '/images/count',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				$('#stats_images').html( result.data.toLocaleString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_images').html( "private" );
			}
		});

		// creadits remaining
		$.ajax({
			url: 'https://api.imgur.com/3/credits',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log( result.data );
				$('#stats_credits_user').html( "User Credits: " + result.data.UserRemaining + " / " + result.data.UserLimit);
				$('#stats_credits_script').html( "Script Credits: : " +  result.data.ClientRemaining + " / " + result.data.ClientLimit);
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_images').html( "private" );
			}
		});
	}
});
<commit_msg>Ignore me<commit_after>// ==UserScript==
// @name        imgur_show_user_stats_light
// @namespace   someName
// @include     http://imgur.com/user/*
// @include     https://imgur.com/user/*
// @version     0.1c
// @grant       none
// ==/UserScript==

alert("test");

$( window ).load(function() {
	var CLIENT_ID = "cd0695f1226536b";

	if(window.location.pathname.indexOf('/user/') === 0 && $('.button').filter('.comments').length > 0){
		var newBox = $('

');
		var tble = $('
' +
								 '
Account creation	 -
'+
								 '
Comments	 -
'+
								 '
Submissions	 -
'+
								 '
Albums	 -
'+
								 '
Images	 -
'+
								 '
Favorites	 -
'+
								 '
 -
'+
								 '
 -
'+
								 '
');
		newBox.append(tble);
		newBox.insertBefore( $('.icons').filter('.textbox') );
		var username = window.location.pathname.split("/", 3)[2];

		// get coments / submission stats
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username+'/gallery_profile',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log(request.getAllResponseHeaders());
				//console.log(result);
				$('#stats_comments').html(result.data.total_gallery_comments.toLocaleString());
				$('#stats_submissions').html(result.data.total_gallery_submissions.toLocaleString());
				$('#stats_favorites').html(result.data.total_gallery_favorites.toLocaleString());
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
			}
		});

		// get the excat join date. TODO: I bet i messed up the time(zones) here.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username,
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log(request.getAllResponseHeaders());
				$('#stats_created').html( new Date(result.data.created * 1000).toLocaleDateString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
			}
		});

		// album count (inklusive not submitted to gallery), if album settings are set to public.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username + '/albums/count',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				$('#stats_albums').html( result.data.toLocaleString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_albums').html( "private" );
			}
		});

		// image count (inklusive not submitted to gallery), if image settings are set to public.
		$.ajax({
			url: 'https://api.imgur.com/3/account/'+username + '/images/count',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				$('#stats_images').html( result.data.toLocaleString() );
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_images').html( "private" );
			}
		});

		// creadits remaining
		$.ajax({
			url: 'https://api.imgur.com/3/credits',
			method: 'GET',
			headers: {
				Authorization: 'Client-ID ' + CLIENT_ID,
				Accept: 'application/json'
			},
			success: function(result, status, request) {
				console.log( result.data );
				$('#stats_credits_user').html( "User Credits: " + result.data.UserRemaining + " / " + result.data.UserLimit);
				$('#stats_credits_script').html( "Script Credits: : " +  result.data.ClientRemaining + " / " + result.data.ClientLimit);
			},
			error: function(a, b, c){
				console.log('Failed to load', a, b, c);
				$('#stats_images').html( "private" );
			}
		});
	}
});
<|endoftext|>


<commit_before>/*
The HTML language is assigned to english and the class should be assigned to Javascript.
The bulk of the document is an unordered list with `<h3>` tags for each heading.
The unordered list has an id of "cpb-ntaccordion" and a class of "cbp-ntaccordion"
The `h3` element has a class set to "cpb-nttrigger"
Each heading accordions open to a description and sub-accordions.
When accordion is opened, list has a class of 'cbp-ntopen'
Inside of a
 element, a description is written inside a paragraph tag.
The div element has a class set to "cbp-ntcontent"
Also inside of the div element is another unordered list with the class of "cbp-ntsubaccordion"
Each item in the sub-list has a header with the class "cbp-nttrigger" and div element with the class "cbp-ntcontent"

In order to use JavaScript with our HTML file, link to our .js file within a `<script>` tag on the .html page with the source set to the file path
Need to create an array to hold the accordion items???
Create function to initiate JavaScript???
  * use getElementsByTagName() to call array
  * create for loop with if statements that trigger different items either onload or ontoggle
Need to write a `toggleItem()` onclick function that is assigned to the
 element.
  // toggleItem() hides or shows all the items in the list when it is clicked on (onclick)
    // aka will expand and collapse accordion
Need to call the id "cpb-ntaccordion" using the `Document` prototype document.getElementById()
**/

/*
//OPENING & CLOSING ACCORDION
var heading = document.querySelector('.cbp-nttrigger'); //d
  heading.addEventListener('click', function(){ // the `addEventListener` listens to the Event type `click`
  if (document.querySelector('li').className !== "cbp-ntopen"){ // method `querySelector` selects the element

                                                                // if the class attribute is not equal to "cbp-ntopen" then..
    document.querySelector('li').className = "cbp-ntopen"; //..the event type `click` changes the class attribute to "cbp-ntopen"
    return true;
  }
  if (document.querySelector('li').className === "cbp-ntopen"){ // if the class attribute is strictly equal to "cbp-ntopen"..
    document.querySelector('li').className = ""; //..the event type `click` changes the class attribute to empty string
    return true;
  }
});
**/

//OPENING ALL HEADINGS

//my code
var openAll = document.querySelectorAll('h3.cbp-nttrigger'); //Stores node list in array
for (var i = 0; i < openAll.length; i++) { //will loop through each item in array and adds event listener of `click`
  openAll[i].addEventListener('click', function(){
    for (var i = 0; i < openAll.length; i++){ // once clicked, goes through each item in array and...
      var parent = openAll[i].parentElement; //`...returns parent element (
) for each
      if (parent.className !== "cbp-ntopen"){
        parent.className = "cbp-ntopen";
        return true;
      }
      if (parent.className === "cbp-ntopen"){
        parent.className = "";
        return true;
      }
    }
  });
}

// if (heading.length > 0) { //aka if it contains items..

//ORIG FUNC 4 REF
/*
heading.addEventListener('click', function(){
if (document.querySelector('li').className !== "cbp-ntopen"){
  document.querySelector('li').className = "cbp-ntopen";
  return true;
}
if (document.querySelector('li').className === "cbp-ntopen"){
  document.querySelector('li').className = null;
  return true;
}
});
**/

//group code- idk what is happening
// var heading = document.querySelectorAll("h3.cbp-nttrigger"); //Store nodelist in array / `h3.cbp-nttrigger` bc I want to target all h3 tags
// heading.addEventListener('click', function(){
// if (heading.length > 0) { // if it contains items then..
//   for (var i = 0; i < heading.length; i++){ //will loop through nodelist for class cbp-nttrigger
//     heading[i].addEventListener("click", function(){ //putting in to array. Change value of the class attribute
// //
//       var openAcc = document.querySelectorAll("li.cbp-ntopen");
//       if (openAcc.length > 0){
//         for (var i = 0; i < openAcc.length; i++){
//           openAcc[i].className = "";
//         };
//
//       } else {
//           document.querySelectorAll("li").className = "cbp-ntopen";
//         }
//       }
//   }
//   }
// }
// }
// } ^^^???????

/*
var collapse = document.querySelector("li").className = "cbp-ntopen" ;// `.` = class
  collapse.addEventListener('click', function(){ //trying to remove class of "cbp-ntopen"
    document.querySelector('li').removeClass("cbp-ntopen");
  }
**/
<commit_msg>all headings opening! Now to close...<commit_after>/*
The HTML language is assigned to english and the class should be assigned to Javascript.
The bulk of the document is an unordered list with `<h3>` tags for each heading.
The unordered list has an id of "cpb-ntaccordion" and a class of "cbp-ntaccordion"
The `h3` element has a class set to "cpb-nttrigger"
Each heading accordions open to a description and sub-accordions.
When accordion is opened, list has a class of 'cbp-ntopen'
Inside of a
 element, a description is written inside a paragraph tag.
The div element has a class set to "cbp-ntcontent"
Also inside of the div element is another unordered list with the class of "cbp-ntsubaccordion"
Each item in the sub-list has a header with the class "cbp-nttrigger" and div element with the class "cbp-ntcontent"

In order to use JavaScript with our HTML file, link to our .js file within a `<script>` tag on the .html page with the source set to the file path
Need to create an array to hold the accordion items???
Create function to initiate JavaScript???
  * use getElementsByTagName() to call array
  * create for loop with if statements that trigger different items either onload or ontoggle
Need to write a `toggleItem()` onclick function that is assigned to the
 element.
  // toggleItem() hides or shows all the items in the list when it is clicked on (onclick)
    // aka will expand and collapse accordion
Need to call the id "cpb-ntaccordion" using the `Document` prototype document.getElementById()
**/

/*
//OPENING & CLOSING ACCORDION
var heading = document.querySelector('.cbp-nttrigger'); //d
  heading.addEventListener('click', function(){ // the `addEventListener` listens to the Event type `click`
  if (document.querySelector('li').className !== "cbp-ntopen"){ // method `querySelector` selects the element

                                                                // if the class attribute is not equal to "cbp-ntopen" then..
    document.querySelector('li').className = "cbp-ntopen"; //..the event type `click` changes the class attribute to "cbp-ntopen"
    return true;
  }
  if (document.querySelector('li').className === "cbp-ntopen"){ // if the class attribute is strictly equal to "cbp-ntopen"..
    document.querySelector('li').className = ""; //..the event type `click` changes the class attribute to empty string
    return true;
  }
});
**/

//OPENING ALL HEADINGS

//my code
var openAll = document.querySelectorAll('h3.cbp-nttrigger'); //Stores node list in array
for (var i = 0; i < openAll.length; i++) { //will loop through each item in array and adds event listener of `click`
  openAll[i].addEventListener('click', function(){
    for (var i = 0; i < openAll.length; i++){ // once clicked, goes through each item in array and...
      var parent = openAll[i].parentElement; //`...returns parent element (
) for each
      if (parent.className !== "cbp-ntopen"){
        parent.className = "cbp-ntopen"; // just opens all
        //return true;
      }
      // if (parent.className === "cbp-ntopen"){
      //   parent.className = "";
      //   return true;
      // }
    }
  });
}

// if (heading.length > 0) { //aka if it contains items..

//ORIG FUNC 4 REF
/*
heading.addEventListener('click', function(){
if (document.querySelector('li').className !== "cbp-ntopen"){
  document.querySelector('li').className = "cbp-ntopen";
  return true;
}
if (document.querySelector('li').className === "cbp-ntopen"){
  document.querySelector('li').className = null;
  return true;
}
});
**/

//group code- idk what is happening
// var heading = document.querySelectorAll("h3.cbp-nttrigger"); //Store nodelist in array / `h3.cbp-nttrigger` bc I want to target all h3 tags
// heading.addEventListener('click', function(){
// if (heading.length > 0) { // if it contains items then..
//   for (var i = 0; i < heading.length; i++){ //will loop through nodelist for class cbp-nttrigger
//     heading[i].addEventListener("click", function(){ //putting in to array. Change value of the class attribute
// //
//       var openAcc = document.querySelectorAll("li.cbp-ntopen");
//       if (openAcc.length > 0){
//         for (var i = 0; i < openAcc.length; i++){
//           openAcc[i].className = "";
//         };
//
//       } else {
//           document.querySelectorAll("li").className = "cbp-ntopen";
//         }
//       }
//   }
//   }
// }
// }
// } ^^^???????

/*
var collapse = document.querySelector("li").className = "cbp-ntopen" ;// `.` = class
  collapse.addEventListener('click', function(){ //trying to remove class of "cbp-ntopen"
    document.querySelector('li').removeClass("cbp-ntopen");
  }
**/
<|endoftext|>


<commit_before>import React from 'react'
import events from '../events'
import { Calendar, Views } from 'react-big-calendar'
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop'

import 'react-big-calendar/lib/addons/dragAndDrop/styles.scss'

const DragAndDropCalendar = withDragAndDrop(Calendar)

class Dnd extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      events: events,
      displayDragItemInCell: true,
    }

    this.moveEvent = this.moveEvent.bind(this)
    this.newEvent = this.newEvent.bind(this)
  }

  handleDragStart = event => {
    this.setState({ draggedEvent: event })
  }

  dragFromOutsideItem = () => {
    return this.state.draggedEvent
  }

  onDropFromOutside = ({ start, end, allDay }) => {
    const { draggedEvent } = this.state

    const event = {
      id: draggedEvent.id,
      title: draggedEvent.title,
      start,
      end,
      allDay: allDay,
    }

    this.setState({ draggedEvent: null })
    this.moveEvent({ event, start, end })
  }

  moveEvent = ({ event, start, end, isAllDay: droppedOnAllDaySlot }) => {
    const { events } = this.state

    let allDay = event.allDay

    if (!event.allDay && droppedOnAllDaySlot) {
      allDay = true
    } else if (event.allDay && !droppedOnAllDaySlot) {
      allDay = false
    }

    const nextEvents = events.map(existingEvent => {
      return existingEvent.id == event.id
        ? { ...existingEvent, start, end }
        : existingEvent
    })

    this.setState({
      events: nextEvents,
    })

    // alert(`${event.title} was dropped onto ${updatedEvent.start}`)
  }

  resizeEvent = ({ event, start, end }) => {
    const { events } = this.state

    const nextEvents = events.map(existingEvent => {
      return existingEvent.id == event.id
        ? { ...existingEvent, start, end }
        : existingEvent
    })

    this.setState({
      events: nextEvents,
    })

    //alert(`${event.title} was resized to ${start}-${end}`)
  }

  newEvent(event) {
    // let idList = this.state.events.map(a => a.id)
    // let newId = Math.max(...idList) + 1
    // let hour = {
    //   id: newId,
    //   title: 'New Event',
    //   allDay: event.slots.length == 1,
    //   start: event.start,
    //   end: event.end,
    // }
    // this.setState({
    //   events: this.state.events.concat([hour]),
    // })
  }

  render() {
    return (
      <DragAndDropCalendar
        selectable
        localizer={this.props.localizer}
        events={this.state.events}
        onEventDrop={this.moveEvent}
        resizable
        onEventResize={this.resizeEvent}
        onSelectSlot={this.newEvent}
        onDragStart={console.log}
        defaultView={Views.MONTH}
        defaultDate={new Date(2015, 3, 12)}
        popup={true}
        dragFromOutsideItem={
          this.state.displayDragItemInCell ? this.dragFromOutsideItem : null
        }
        onDropFromOutside={this.onDropFromOutside}
        handleDragStart={this.handleDragStart}
      />
    )
  }
}

export default Dnd
<commit_msg>feat(DnD): support to/from allDay events in demos<commit_after>import React from 'react'
import events from '../events'
import { Calendar, Views } from 'react-big-calendar'
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop'

import 'react-big-calendar/lib/addons/dragAndDrop/styles.scss'

const DragAndDropCalendar = withDragAndDrop(Calendar)

class Dnd extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      events: events,
      displayDragItemInCell: true,
    }

    this.moveEvent = this.moveEvent.bind(this)
    this.newEvent = this.newEvent.bind(this)
  }

  handleDragStart = event => {
    this.setState({ draggedEvent: event })
  }

  dragFromOutsideItem = () => {
    return this.state.draggedEvent
  }

  onDropFromOutside = ({ start, end, allDay }) => {
    const { draggedEvent } = this.state

    const event = {
      id: draggedEvent.id,
      title: draggedEvent.title,
      start,
      end,
      allDay: allDay,
    }

    this.setState({ draggedEvent: null })
    this.moveEvent({ event, start, end })
  }

  moveEvent = ({ event, start, end, isAllDay: droppedOnAllDaySlot }) => {
    const { events } = this.state

    let allDay = event.allDay

    if (!event.allDay && droppedOnAllDaySlot) {
      allDay = true
    } else if (event.allDay && !droppedOnAllDaySlot) {
      allDay = false
    }

    const nextEvents = events.map(existingEvent => {
      return existingEvent.id == event.id
        ? { ...existingEvent, start, end, allDay }
        : existingEvent
    })

    this.setState({
      events: nextEvents,
    })

    // alert(`${event.title} was dropped onto ${updatedEvent.start}`)
  }

  resizeEvent = ({ event, start, end }) => {
    const { events } = this.state

    const nextEvents = events.map(existingEvent => {
      return existingEvent.id == event.id
        ? { ...existingEvent, start, end }
        : existingEvent
    })

    this.setState({
      events: nextEvents,
    })

    //alert(`${event.title} was resized to ${start}-${end}`)
  }

  newEvent(_event) {
    // let idList = this.state.events.map(a => a.id)
    // let newId = Math.max(...idList) + 1
    // let hour = {
    //   id: newId,
    //   title: 'New Event',
    //   allDay: event.slots.length == 1,
    //   start: event.start,
    //   end: event.end,
    // }
    // this.setState({
    //   events: this.state.events.concat([hour]),
    // })
  }

  render() {
    return (
      <DragAndDropCalendar
        selectable
        localizer={this.props.localizer}
        events={this.state.events}
        onEventDrop={this.moveEvent}
        resizable
        onEventResize={this.resizeEvent}
        onSelectSlot={this.newEvent}
        onDragStart={console.log}
        defaultView={Views.MONTH}
        defaultDate={new Date(2015, 3, 12)}
        popup={true}
        dragFromOutsideItem={
          this.state.displayDragItemInCell ? this.dragFromOutsideItem : null
        }
        onDropFromOutside={this.onDropFromOutside}
        handleDragStart={this.handleDragStart}
      />
    )
  }
}

export default Dnd
<|endoftext|>


<commit_before>'use strict';

/* global Connector, Util */

if ($('.cnt-song-lst').length > 0) {
	Connector.playerSelector = '.cnt-song-lst';

	Connector.getArtistTrack = function() {
		var text = $('.playing .song').clone().children('.like-count').remove().end().text();
		return Util.splitArtistTrack(text);
	};

	Connector.isPlaying = function () {
		return $('.playing .pause').length > 0;
	};

	Connector.getCurrentTime = function() {
		return $('.playing .p-btn').attr('sec');
	};

	Connector.getDuration = function() {
		return $('.playing .p-btn').attr('data-to_sec');
	};
} else if ($('.cur-blk').length > 0) {
	Connector.playerSelector = '.cur-blk';

	Connector.artistTrackSelector = '.cur-blk .name';

	Connector.isPlaying = function () {
		return $('.cur-blk #play').hasClass('pause');
	};

	Connector.durationSelector = '.cur-blk .total-time';
}
<commit_msg>Radio Obozrevatel: reorganize code<commit_after>'use strict';

/* global Connector, Util */

setupConnector();

function setupConnector() {
	if (isRadioPlayer()) {
		setupRadioPlayer();
	} else if (isMusicPlayer()) {
		setupMusicPlayer();
	}
}

function isRadioPlayer() {
	return $('.cur-blk').length > 0;
}

function isMusicPlayer() {
	$('.cnt-song-lst').length > 0;
}

function setupMusicPlayer() {
	Connector.playerSelector = '.cnt-song-lst';

	Connector.getArtistTrack = function() {
		let text = $('.playing .song').clone().children('.like-count').remove().end().text();
		return Util.splitArtistTrack(text);
	};

	Connector.isPlaying = () => $('.playing .pause').length > 0;

	Connector.getCurrentTime = () => $('.playing .p-btn').attr('sec');

	Connector.getDuration = () => $('.playing .p-btn').attr('data-to_sec');
}

function setupRadioPlayer() {
	Connector.playerSelector = '.cur-blk';

	Connector.artistTrackSelector = '.cur-blk .name';

	Connector.isPlaying = () => $('.cur-blk #play').hasClass('pause');

	Connector.durationSelector = '.cur-blk .total-time';
}
<|endoftext|>


<commit_before>// 作业 7
//
// var appendHtml = function(element, html) { }
//
// element 是一个标签
// html 是一段 html 字符串
// 把 html 作为子元素插入到 element 的末尾
// 上课一直在用这个函数
//
// 用法如下:
// var b = document.querySelector('body')
// appendHtml(b, '
hello
')
//

// 以下是提交作业代码
/* ------------------------------------------------------------------------- */
var appendHtml = function(element, html) {
    element.insertAdjacentHTML('beforeEnd', html)
}
<commit_msg>DOM方法封装：把insertAdjacentHTML-beforeEnd封装为appendHtml(element, html)<commit_after>// 作业 7
//
// var appendHtml = function(element, html) { }
//
// element 是一个标签
// html 是一段 html 字符串
// 把 html 作为子元素插入到 element 的末尾
// 上课一直在用这个函数
//
// 用法如下:
// var b = document.querySelector('body')
// appendHtml(b, '
hello
')
//

// 以下是提交作业代码
/* ------------------------------------------------------------------------- */
var appendHtml = function(element, html) {
    element.insertAdjacentHTML('beforeend', html)
}
<|endoftext|>


<commit_before>import Map from '../src/ol/Map.js';
import TileLayer from '../src/ol/layer/WebGLTile.js';
import View from '../src/ol/View.js';

import DataTileSource from '../src/ol/source/DataTile.js';
import {fromLonLat} from '../src/ol/proj.js';

// 16-bit COG
// Which will be served as NumpyTiles.
const COG =
  'https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif';

function numpyTileLoader(z, x, y) {
  const url = `https://api.cogeo.xyz/cog/tiles/WebMercatorQuad/${z}/${x}/${y}@1x?format=npy&url=${encodeURIComponent(
    COG
  )}`;

  return fetch(url)
    .then((r) => r.arrayBuffer())
    .then((buffer) => NumpyLoader.fromArrayBuffer(buffer)) // eslint-disable-line no-undef
    .then((numpyData) => {
      // flatten the numpy data
      const dataTile = new Float32Array(256 * 256 * 5);
      const bandSize = 256 * 256;
      for (let x = 0; x < 256; x++) {
        for (let y = 0; y < 256; y++) {
          const px = x + y * 256;
          dataTile[px * 5 + 0] = numpyData.data[y * 256 + x];
          dataTile[px * 5 + 1] = numpyData.data[bandSize + y * 256 + x];
          dataTile[px * 5 + 2] = numpyData.data[bandSize * 2 + y * 256 + x];
          dataTile[px * 5 + 3] = numpyData.data[bandSize * 3 + y * 256 + x];
          dataTile[px * 5 + 4] =
            numpyData.data[bandSize * 4 + y * 256 + x] > 0 ? 1.0 : 0;
        }
      }
      return dataTile;
    });
}

const interpolateBand = (bandIdx) => [
  'interpolate',
  ['linear'],
  ['band', bandIdx],
  ['var', 'bMin'],
  0,
  ['var', 'bMax'],
  1,
];

const initialMin = 3000;
const initialMax = 18000;

const numpyLayer = new TileLayer({
  style: {
    color: [
      'array',
      interpolateBand(3),
      interpolateBand(2),
      interpolateBand(1),
      ['band', 5],
    ],
    variables: {
      'bMin': initialMin,
      'bMax': initialMax,
    },
  },
  source: new DataTileSource({
    loader: numpyTileLoader,
    bandCount: 5,
  }),
});

const map = new Map({
  target: 'map',
  layers: [numpyLayer],
  view: new View({
    center: fromLonLat([172.933, 1.3567]),
    zoom: 15,
  }),
});

const inputMin = document.getElementById('input-min');
const inputMax = document.getElementById('input-max');
const outputMin = document.getElementById('output-min');
const outputMax = document.getElementById('output-max');

inputMin.addEventListener('input', (evt) => {
  numpyLayer.updateStyleVariables({
    'bMin': parseFloat(evt.target.value),
    'bMax': parseFloat(inputMax.value),
  });
  outputMin.innerText = evt.target.value;
});

inputMax.addEventListener('input', (evt) => {
  numpyLayer.updateStyleVariables({
    'bMin': parseFloat(inputMin.value),
    'bMax': parseFloat(evt.target.value),
  });
  outputMax.innerText = evt.target.value;
});

inputMin.value = initialMin;
inputMax.value = initialMax;
outputMin.innerText = initialMin;
outputMax.innerText = initialMax;
<commit_msg>Fix range slider for better browser support<commit_after>import DataTileSource from '../src/ol/source/DataTile.js';
import Map from '../src/ol/Map.js';
import TileLayer from '../src/ol/layer/WebGLTile.js';
import View from '../src/ol/View.js';
import {fromLonLat} from '../src/ol/proj.js';

// 16-bit COG
// Which will be served as NumpyTiles.
const COG =
  'https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif';

function numpyTileLoader(z, x, y) {
  const url = `https://api.cogeo.xyz/cog/tiles/WebMercatorQuad/${z}/${x}/${y}@1x?format=npy&url=${encodeURIComponent(
    COG
  )}`;

  return fetch(url)
    .then((r) => r.arrayBuffer())
    .then((buffer) => NumpyLoader.fromArrayBuffer(buffer))
    .then((numpyData) => {
      // flatten the numpy data
      const dataTile = new Float32Array(256 * 256 * 5);
      const bandSize = 256 * 256;
      for (let x = 0; x < 256; x++) {
        for (let y = 0; y < 256; y++) {
          const px = x + y * 256;
          dataTile[px * 5 + 0] = numpyData.data[y * 256 + x];
          dataTile[px * 5 + 1] = numpyData.data[bandSize + y * 256 + x];
          dataTile[px * 5 + 2] = numpyData.data[bandSize * 2 + y * 256 + x];
          dataTile[px * 5 + 3] = numpyData.data[bandSize * 3 + y * 256 + x];
          dataTile[px * 5 + 4] =
            numpyData.data[bandSize * 4 + y * 256 + x] > 0 ? 1.0 : 0;
        }
      }
      return dataTile;
    });
}

const interpolateBand = (bandIdx) => [
  'interpolate',
  ['linear'],
  ['band', bandIdx],
  ['var', 'bMin'],
  0,
  ['var', 'bMax'],
  1,
];

const initialMin = 3000;
const initialMax = 18000;

const numpyLayer = new TileLayer({
  style: {
    color: [
      'array',
      interpolateBand(3),
      interpolateBand(2),
      interpolateBand(1),
      ['band', 5],
    ],
    variables: {
      'bMin': initialMin,
      'bMax': initialMax,
    },
  },
  source: new DataTileSource({
    loader: numpyTileLoader,
    bandCount: 5,
  }),
});

const map = new Map({
  target: 'map',
  layers: [numpyLayer],
  view: new View({
    center: fromLonLat([172.933, 1.3567]),
    zoom: 15,
  }),
});

const inputMin = document.getElementById('input-min');
const inputMax = document.getElementById('input-max');
const outputMin = document.getElementById('output-min');
const outputMax = document.getElementById('output-max');

const handleMin = (evt) => {
  numpyLayer.updateStyleVariables({
    'bMin': parseFloat(evt.target.value),
    'bMax': parseFloat(inputMax.value),
  });
  outputMin.innerText = evt.target.value;
};
inputMin.addEventListener('input', handleMin);
inputMin.addEventListener('change', handleMin);

const handleMax = (evt) => {
  numpyLayer.updateStyleVariables({
    'bMin': parseFloat(inputMin.value),
    'bMax': parseFloat(evt.target.value),
  });
  outputMax.innerText = evt.target.value;
};
inputMax.addEventListener('input', handleMax);
inputMax.addEventListener('change', handleMax);

inputMin.value = initialMin;
inputMax.value = initialMax;
outputMin.innerText = initialMin;
outputMax.innerText = initialMax;
<|endoftext|>


<commit_before>"use strict";
console.log("Loading content script...");

var s = document.createElement('script');
s.src = chrome.extension.getURL('js/override.js');
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);

var gzipHeader = [0x1F, 0x8B];

function download(url) {
	console.time("Download");
	var xhr = new XMLHttpRequest();
	xhr.responseType = "arraybuffer";
	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			console.timeEnd("Download");
			if (xhr.status !== 200) {
				return failed('Got wrong response ' + xhr.status);
			}
			var contentType = xhr.getResponseHeader('content-type');
			decrypt(xhr.response, contentType);
		}
	};
	xhr.open("GET", url, true);
	xhr.send();
}

function decrypt(data, contentType) {
	console.time("Decrypt");
	chrome.runtime.sendMessage({
		to:"background",
		message: "decrypt",
		data: forge.util.binary.base64.encode(new Uint8Array(data))
	}, function(response) {
		console.timeEnd("Decrypt");
		if (response.error) {
			return emit('decryption-failed', { error: response.error });
		}
		handleDecrypted(stringToUint8Array(response.data), contentType);
	});
}

function handleDecrypted(decrypted, contentType) {
	var data = decompress(decrypted);
	if (contentType.indexOf('html') > 0) {
		data = sanitize_html(data);
	}
	var blobUrl = createBlob(data, contentType);

	emit('decrypted', {
		url: blobUrl,
		contentType: contentType
	});
}

function emit(event, data) {
	document.dispatchEvent(new CustomEvent(event, { detail : data }));
}

function decompress(data) {
	if (data[0] === gzipHeader[0] && data[1] === gzipHeader[1]) {
		try {
			return gzip.unzip(data);
		} catch(e) {
			console.error("Unzipping av brev feilet", e);
		}
	}
	return data;
}

function sanitize_html(data) {
	var bom = [0xef, 0xbb, 0xbf];
	if (data[0] !== bom[0] || data[1] !== bom[1] || data[2] !== bom[2]) {
		data = bom.concat(data);
	}
	var html = String.fromCharCode.apply(this, data);
	var purified = DOMPurify.sanitize(html, {WHOLE_DOCUMENT: true});
	return stringToUint8Array(purified);
}

function createBlob(decrypted, contentType) {
	var blob = new Blob( [ new Uint8Array(decrypted) ], { type: contentType } );
	return (window.URL || window.webkitURL).createObjectURL(blob);
}

function stringToUint8Array(str) {
	var arr = new Uint8Array(str.length);
	var j = str.length;
	for(var i = 0; i < j ; ++i){
	  arr[i] = str.charCodeAt(i);
	}
	return arr;
}

function failed(message) {
	document.dispatchEvent(new CustomEvent('failed', { detail : message } ));
}

document.addEventListener('start', function(e, x){
	download(e.detail);
});

function perfLog(fun, context) {
	var context = context || this;
	var realFun = context[fun.name];
	context[fun.name] = function() {
		console.time(fun.name);
		var result = realFun.apply(context, arguments);
		console.timeEnd(fun.name);
		return result;
	}
}

perfLog(createBlob);
perfLog(sanitize_html);
perfLog(createBlob);
perfLog(decompress);

<commit_msg>Removed clever perf logging because replacing it in context didn't work. Will look at it later when needed<commit_after>"use strict";
console.log("Loading content script...");

var s = document.createElement('script');
s.src = chrome.extension.getURL('js/override.js');
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);

var gzipHeader = [0x1F, 0x8B];

function download(url) {
	console.time("Download");
	var xhr = new XMLHttpRequest();
	xhr.responseType = "arraybuffer";
	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			console.timeEnd("Download");
			if (xhr.status !== 200) {
				return failed('Got wrong response ' + xhr.status);
			}
			var contentType = xhr.getResponseHeader('content-type');
			decrypt(xhr.response, contentType);
		}
	};
	xhr.open("GET", url, true);
	xhr.send();
}

function decrypt(data, contentType) {
	console.time("Decrypt");
	chrome.runtime.sendMessage({
		to:"background",
		message: "decrypt",
		data: forge.util.binary.base64.encode(new Uint8Array(data))
	}, function(response) {
		console.timeEnd("Decrypt");
		if (response.error) {
			return emit('decryption-failed', { error: response.error });
		}
		handleDecrypted(stringToUint8Array(response.data), contentType);
	});
}

function handleDecrypted(decrypted, contentType) {
	var data = decompress(decrypted);
	if (contentType.indexOf('html') > 0) {
		data = sanitize_html(data);
	}
	var blobUrl = createBlob(data, contentType);

	emit('decrypted', {
		url: blobUrl,
		contentType: contentType
	});
}

function emit(event, data) {
	document.dispatchEvent(new CustomEvent(event, { detail : data }));
}

function decompress(data) {
	if (data[0] === gzipHeader[0] && data[1] === gzipHeader[1]) {
		try {
			return gzip.unzip(data);
		} catch(e) {
			console.error("Unzipping av brev feilet", e);
		}
	}
	return data;
}

function sanitize_html(data) {
	var bom = [0xef, 0xbb, 0xbf];
	if (data[0] !== bom[0] || data[1] !== bom[1] || data[2] !== bom[2]) {
		data = bom.concat(data);
	}
	var html = String.fromCharCode.apply(this, data);
	var purified = DOMPurify.sanitize(html, {WHOLE_DOCUMENT: true});
	return stringToUint8Array(purified);
}

function createBlob(decrypted, contentType) {
	var blob = new Blob( [ new Uint8Array(decrypted) ], { type: contentType } );
	return (window.URL || window.webkitURL).createObjectURL(blob);
}

function stringToUint8Array(str) {
	var arr = new Uint8Array(str.length);
	var j = str.length;
	for(var i = 0; i < j ; ++i){
	  arr[i] = str.charCodeAt(i);
	}
	return arr;
}

function failed(message) {
	document.dispatchEvent(new CustomEvent('failed', { detail : message } ));
}

document.addEventListener('start', function(e, x){
	download(e.detail);
});
<|endoftext|>


<commit_before>var fs = require('fs');
var colors = require('colors');
var _ = require('lodash');
var utils = require('../utils');

exports.run = function (args) {
  if (!args.subcommand) {
    utils.argShift(args, 'subcommand');
  }

  var moduleName;
  if (args.command === 'help' && args.subcommand) {
    moduleName = args.subcommand;
  } else if (args.command !== 'help') {
    moduleName = args.command;
  }

  if (moduleName) {
    if (fs.existsSync(__dirname + '/' + moduleName + '.js')) {
      var module = require('./' + moduleName);
      if (module && module.help) {
        return module.help();
      }
    } else {
      utils.unknownCommand();
    }
  }

  exports.help();
};

exports.help = function () {
  var signatures = [];
  _.each(utils.getCommands(), function (command, name) {
    if (name !== 'help' && command.signatures) {
      signatures = signatures.concat(command.signatures());
    }
  });

  utils.printArray([
    ('Overcast v' + utils.VERSION).grey,
    '',
    'Source code, issues, pull requests:'.grey,
    '  https://github.com/andrewchilds/overcast',
    '',
    'Usage:'.grey,
    '  overcast [command] [options...]',
    '',
    'Help:'.grey,
    '  overcast help',
    '  overcast help [command]',
    '  overcast [command] help',
    '',
    'Commands:'.grey
  ]);
  utils.printArray(signatures);
  utils.printArray([
    '',
    'Config directory:'.grey,
    '  ' + utils.CONFIG_DIR.cyan
  ]);
};
<commit_msg>AC: Condense help command output to only show command names.<commit_after>var fs = require('fs');
var colors = require('colors');
var _ = require('lodash');
var utils = require('../utils');

exports.run = function (args) {
  if (!args.subcommand) {
    utils.argShift(args, 'subcommand');
  }

  var moduleName;
  if (args.command === 'help' && args.subcommand) {
    moduleName = args.subcommand;
  } else if (args.command !== 'help') {
    moduleName = args.command;
  }

  if (moduleName) {
    if (fs.existsSync(__dirname + '/' + moduleName + '.js')) {
      var module = require('./' + moduleName);
      if (module && module.help) {
        return module.help();
      }
    } else {
      utils.unknownCommand();
    }
  }

  exports.help();
};

exports.help = function () {
  var signatures = [];
  var row = ' ';
  _.each(utils.getCommands(), function (command, name) {
    if (name !== 'help' && command.signatures) {
      if (row.length > 65) {
        signatures.push(row);
        row = ' ';
      }
      row += ' ' + name;
    }
  });
  signatures.push(row);

  utils.printArray([
    ('Overcast v' + utils.VERSION).grey,
    '',
    'Source code, issues, pull requests:'.grey,
    '  https://github.com/andrewchilds/overcast',
    '',
    'Usage:'.grey,
    '  overcast [command] [options...]',
    '',
    'Help:'.grey,
    '  overcast help',
    '  overcast help [command]',
    '  overcast [command] help',
    '',
    'Commands:'.grey
  ]);
  utils.printArray(signatures);
  utils.printArray([
    '',
    'Config directory:'.grey,
    '  ' + utils.CONFIG_DIR.cyan
  ]);
};
<|endoftext|>


<commit_before><commit_msg>实现：点击按钮切换图片（有bug）<commit_after><|endoftext|>


<commit_before>const TournamentInscription = require('../models/TournamentInscription');
const mongoose = require('mongoose');

/**
 * Create inscription
 */
exports.newTournamentInscription = async (req, res) => {
    try {
        let inscription = new TournamentInscription(req.body);
        await inscription.save();
        await res.json({msg: "Inscipcion exitosa."});
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
};

/**
 * Find a inscription by id
 */
exports.getInscription = async (req, res) => {
    try {
        let inscription = await TournamentInscription.findById(req.params._id);
        await res.json({inscription})
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
}

/**
 * Find all inscription of a tournament
 */
exports.getTournamentInscriptions = async (req, res) => {
    try {
        let inscriptions = await TournamentInscription.find({
            tournamentId: mongoose.Types.ObjectId(req.params.tournamentId)
        });
        await res.json({inscriptions});
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
}

// TODO: validations for endpoints
<commit_msg>Verificacion inicial sin finalizar en inscripcion. Para que pablo pueda seguir trabajo<commit_after>const TournamentInscription = require('../models/TournamentInscription');
const mongoose = require('mongoose');

/**
 * Create inscription
 */
exports.newTournamentInscription = async (req, res) => {
    try {
        let inscription = new TournamentInscription(req.body);
        await inscription.save();
        await res.json({msg: "Inscipcion exitosa."});
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
};

/**
 * Find a inscription by id
 */
exports.getInscription = async (req, res) => {
    try {
        let inscription = await TournamentInscription.findById(req.params._id);
        await res.json({inscription})
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
}

/**
 * Find all inscription of a tournament
 */
exports.getTournamentInscriptions = async (req, res) => {
    try {
        let inscriptions = await TournamentInscription.find({
            tournamentId: mongoose.Types.ObjectId(req.params.tournamentId)
        });
        await res.json({inscriptions});
    } catch (e) {
        res.status(500).send("Ocurrio un error imprevisto :(");
    }
}

/**
 * Utility - checks:
 *      - with quota for inscription?
 *      - inscriptions are close?
 * @return true if can effectuate the inscription
 */
canEffectuateInscription = async (tournamentId) => {
    try {
        //verify quota
        let actualInscriptions = await TournamentInscription.countDocuments({tournamentId: tournamentId})
        // let quota =
    } catch (error) {
        return false;
    }
}

// TODO: validations for endpoints
<|endoftext|>


<commit_before>$(document).ready(function (doc) {
    $("input").live("focus", function (e) {
        var $this = $(this);
        if ($this.val() == $this.attr('default')) {
            $this.val('');
        }
    }).live("blur", function (e) {
        var $this = $(this);
        if ($this.val() == "") {
            $this.val($this.attr('default'));
        }
    });

    var languages = [
        ['.cc', '.cpp;CppLexer'],
        ['.cxx', '.cpp;CppLexer'],
        ['.C', '.cpp;CppLexer'],
        ['.C', '.c;CLexer'],
        ['.h', '.c;CLexer'],
        ['.hpp', '.cpp;CppLexer'],
        ['.hxx', '.cpp;CppLexer'],
        ['.java', '.java;JavaLexer']
    ];

    var $options = $('div.language:first select > option')
    for (var i = 0; i < $options.length; i++) {
        languages.push([$options[i].value.split(';')[0], $options[i].value]);
    }

    $("input").blur();

    $('input.filename').live('keyup', function (e) {
        var $this = $(this);
        var $parent = $this.parents('div.entry');
        var $lang = $('div.language select', $parent);
        var val = $this.val();
        var ext = val.split('.')
        ext = '.' + ext[ext.length - 1];

        for (var i = 0; i < languages.length; i++) {
            if (languages[i][0] == ext) {
                $lang.val(languages[i][1]);
                return;
            }
        }
        $lang.val('.txt');
    });

    $('#paste-form > div.entry').formset({
        'addText': 'add another file to this paste',
        'deleteText': 'delete this file',
        'added': function () {
            $('textarea').tabby();
            $('div.entry:last input').val('');
            $('div.entry:last select').val('');
            $('div.entry:last textarea').html('');
            $('input').blur();
        }
    })

    $('textarea').tabby();
});
<commit_msg>Uses 4-space instead of hard-tab<commit_after>$(document).ready(function (doc) {
    $("input").live("focus", function (e) {
        var $this = $(this);
        if ($this.val() == $this.attr('default')) {
            $this.val('');
        }
    }).live("blur", function (e) {
        var $this = $(this);
        if ($this.val() == "") {
            $this.val($this.attr('default'));
        }
    });

    var languages = [
        ['.cc', '.cpp;CppLexer'],
        ['.cxx', '.cpp;CppLexer'],
        ['.C', '.cpp;CppLexer'],
        ['.C', '.c;CLexer'],
        ['.h', '.c;CLexer'],
        ['.hpp', '.cpp;CppLexer'],
        ['.hxx', '.cpp;CppLexer'],
        ['.java', '.java;JavaLexer']
    ];

    var $options = $('div.language:first select > option')
    for (var i = 0; i < $options.length; i++) {
        languages.push([$options[i].value.split(';')[0], $options[i].value]);
    }

    $("input").blur();

    $('input.filename').live('keyup', function (e) {
        var $this = $(this);
        var $parent = $this.parents('div.entry');
        var $lang = $('div.language select', $parent);
        var val = $this.val();
        var ext = val.split('.')
        ext = '.' + ext[ext.length - 1];

        for (var i = 0; i < languages.length; i++) {
            if (languages[i][0] == ext) {
                $lang.val(languages[i][1]);
                return;
            }
        }
        $lang.val('.txt');
    });

    $('#paste-form > div.entry').formset({
        'addText': 'add another file to this paste',
        'deleteText': 'delete this file',
        'added': function () {
            $('textarea').tabby({'tabString': '    '});
            $('div.entry:last input').val('');
            $('div.entry:last select').val('');
            $('div.entry:last textarea').html('');
            $('input').blur();
        }
    })

    $('textarea').tabby({'tabString': '    '});
});
<|endoftext|>


<commit_before>
function episodesReleasedToday() {

    var today = new Date()
    var dd = today.getDate()
    var mm = today.getMonth()+1

    current_date = dd + '.' + mm + '.'

    console.log("Current date: " + current_date)

    let elements = document.getElementsByTagName("td")

    let element
    let elementRegex = /(\d){0,2}\.(\d){0,2}\./g;

    // for some reason we have to reverse the loop, otherwise every 2nd "td" element will be skipped.. wtf?
    for (var i = elements.length - 1 ; i >= 0; i--) {
        element = elements[i].innerHTML
        var match = elementRegex.exec(element)

        if (match != null ) {

            var episode_date = match[0]

            if (episode_date == current_date) {

                todays_episode_element = elements[i].parentNode.innerHTML
                todays_episode_node = elements[i].parentNode

                // Hotfix for duplicate elemenets to be skipped.
                // kinda hacky way, but hey.. it works :-)
                if (todays_episode_node.parentNode.id == 'snippet--episodes tvshows_today') {
                    continue;
                }

                var title = todays_episode_node.parentNode.parentNode.parentElement.getElementsByTagName('h2')[0].textContent //.getElementsByTagName('h2')[0].innerHTML

                var h2_element = document.createElement('h2')
                var h2_title_node = document.createTextNode(title)
                h2_element.appendChild(h2_title_node)
                var div_tvshows_today = document.getElementById('tvshows_today')
                div_tvshows_today.appendChild(h2_element)

                var table_element = document.createElement('table')
                table_element.className = 'episodes'
                var tbody_element = table_element.createTBody()
                tbody_element.id = 'snippet--episodes tvshows_today'

                tbody_element.insertAdjacentHTML('afterbegin', todays_episode_element)
                div_tvshows_today.appendChild(table_element)
            }

        }
    }

}

episodesReleasedToday()

<commit_msg>correctly display episodes released for current day<commit_after>
// Extending string fucntion
// E.g. '{}'.format(string)
String.prototype.format = function () {
    var args = [].slice.call(arguments);
    return this.replace(/(\{\d+\})/g, function (a){
        return args[+(a.substr(1,a.length-2))||0];
    });
};

function episodesReleasedToday() {

    var today = new Date()
    var dd = today.getDate()
    var mm = today.getMonth()+1

    current_date = dd + '.' + mm + '.'

    console.log("Current date: " + current_date)

    let elements = document.getElementsByTagName("td")

    let element
    let elementRegex = /(\d){0,2}\.(\d){0,2}\./g;
    //let elementRegex = /16\.10\./g

    // for some reason we have to reverse the loop, otherwise every 2nd "td" element will be skipped.. wtf?
    for (var i = elements.length - 1 ; i >= 0; i--) {
        element = elements[i].innerHTML

        //console.log(element)

        var match = elementRegex.exec(element)

        console.log(match)

        if (match != null ) {

            var episode_date = match[0]

            //console.log(match)

            if (episode_date == current_date) {

                todays_episode_element = elements[i].parentNode.innerHTML
                todays_episode_node = elements[i].parentNode

                //console.log(todays_episode_element)
                //console.log(todays_episode_node)

                var tvshow_name = todays_episode_node.getElementsByTagName('a').title

                //var tvshow_name = "test"

                // Hotfix for duplicate elemenets to be skipped.
                // kinda hacky way, but hey.. it works :-)
                var td_id = 'snippet--episodes {0}'.format(tvshow_name)

                //console.log("td_id: ", td_id)
                //console.log("parentNode.id: ", todays_episode_node.parentNode.id)

                if (todays_episode_node.parentNode.id == td_id) { // check comment on line 48
                    continue;
                }

                var title = todays_episode_node.parentNode.parentNode.parentElement.getElementsByTagName('h2')[0].textContent //.getElementsByTagName('h2')[0].innerHTML

                var h2_element = document.createElement('h2')
                var h2_title_node = document.createTextNode(title)
                h2_element.appendChild(h2_title_node)
                var div_tvshows_today = document.getElementById('tvshows_today')
                div_tvshows_today.appendChild(h2_element)

                var table_element = document.createElement('table')
                table_element.className = 'episodes'
                var tbody_element = table_element.createTBody()
                tbody_element.id = 'snippet--episodes {0}'.format(tvshow_name) // should contain name of the episode as ID

                tbody_element.insertAdjacentHTML('afterbegin', todays_episode_element)
                div_tvshows_today.appendChild(table_element)
            }

        }
    }

}

episodesReleasedToday()

<|endoftext|>


<commit_before>import { WidthSpriteSheetHero, HeightSpriteSheetHero, Width, Height, BabyRatio, HeroRatio } from '../Constants.js';
import { Tileset, Levels, HeroSprite } from '../ConstantsKey.js';
import MapManager from "objects/MapManager";
import Character from 'objects/Character';

class Introduction extends Phaser.State {

  constructor() {
    super();
  }

  create() {
      this.game.physics.startSystem(Phaser.Physics.ARCADE);

      this.map = this.game.add.tilemap(Levels[`Level1`].key);
      this.map.addTilesetImage(Levels[`Level1`].key, Tileset.key);

      this.map.createLayer('thirdLayer');
      this.map.createLayer('secondLayer');
      this.map.createLayer('firstLayer');
      // This resizes the game world to match the layer dimensions
      this.collisionLayer = this.map.createLayer('colissionLayer');
      this.map.setCollisionByExclusion([], true, this.collisionLayer);

      this.collisionLayer.resizeWorld();

      this.mapManager = new MapManager(this.map, Levels[`Level1`].lastLayer);
      this.mapManager.setUpCollisionLayer(this.collisionLayer);

      let baby = this.game.add.sprite(400, 395, 'baby');
      let baby2 = this.game.add.sprite(350, 395, 'baby2');
      let badGuy = this.game.add.sprite(950, 370, 'baby3');
      baby.scale.setTo(BabyRatio, BabyRatio);
      baby2.scale.setTo(BabyRatio, BabyRatio);
      badGuy.scale.setTo(HeroRatio, HeroRatio);

      let tweenA = this.game.add.tween(badGuy).to( { y: 320 }, 2000, "Quart.easeOut");
      let tweenB = this.game.add.tween(badGuy).to( { x: 370 }, 5000, "Quart.easeOut");
      this.tweenC = this.game.add.tween(badGuy).to( { x: -320 }, 5000, "Quart.easeOut");
      this.tweenD = this.game.add.tween(baby).to( { x: -350 + 50 }, 5000, "Quart.easeOut");
      this.tweenE = this.game.add.tween(baby2).to( { x: -350 }, 5000, "Quart.easeOut");
      tweenA.chain(tweenB);
      tweenB.chain(this.tweenC);
      tweenB.onComplete.add(this.catched, this);

      tweenA.start();
  }

  catched() {
    this.tweenC.start();
    this.tweenD.start();
    this.tweenE.start();
  }

  preload() {
    this.game.load.spritesheet(HeroSprite.key, `res/${HeroSprite.path}`, WidthSpriteSheetHero, HeightSpriteSheetHero);
    this.game.load.image(Tileset.key, `res/${Tileset.path}`);
    this.game.load.tilemap(Levels[`Level1`].key, `res/${Levels[`Level1`].path}` , null, Phaser.Tilemap.TILED_JSON);
    this.game.load.image("baby", "res/baby.png");
    this.game.load.image("baby2", "res/baby2.png");
    this.game.load.image("baby3", "res/baby3.png");
  }

  render() {
    //this.game.debug.text(this.game.time.fps, 2, 16, "#00ff00");
  }

}

export default Introduction;
<commit_msg>finish cut scene<commit_after>import { WidthSpriteSheetHero, HeightSpriteSheetHero, Width, Height, BabyRatio, HeroRatio } from '../Constants.js';
import { Tileset, Levels, HeroSprite } from '../ConstantsKey.js';
import MapManager from "objects/MapManager";
import Character from 'objects/Character';

class Introduction extends Phaser.State {

  constructor() {
    super();
  }

  create() {
      this.game.physics.startSystem(Phaser.Physics.ARCADE);

      this.map = this.game.add.tilemap(Levels[`Level6`].key);
      this.map.addTilesetImage(Levels[`Level6`].key, Tileset.key);

      this.map.createLayer('thirdLayer');
      this.map.createLayer('secondLayer');
      this.map.createLayer('firstLayer');
      // This resizes the game world to match the layer dimensions
      this.collisionLayer = this.map.createLayer('colissionLayer');
      this.map.setCollisionByExclusion([], true, this.collisionLayer);

      this.collisionLayer.resizeWorld();

      this.mapManager = new MapManager(this.map, Levels[`Level6`].lastLayer);
      this.mapManager.setUpCollisionLayer(this.collisionLayer);

      this.baby = this.game.add.sprite(400, 395, 'baby');
      this.baby2 = this.game.add.sprite(350, 395, 'baby2');
      this.badGuy = this.game.add.sprite(950, 370, 'baby3');
      this.baby.scale.setTo(BabyRatio, BabyRatio);
      this.baby2.scale.setTo(BabyRatio, BabyRatio);
      this.badGuy.scale.setTo(HeroRatio, HeroRatio);

      let tweenA = this.game.add.tween(this.badGuy).to( { y: 320 }, 2000, "Quart.easeOut");
      let tweenB = this.game.add.tween(this.badGuy).to( { x: 370 }, 1000, "Quart.easeOut");
      this.tweenC = this.game.add.tween(this.badGuy).to( { x: -320 }, 1000, "Quart.easeOut");
      this.tweenD = this.game.add.tween(this.baby).to( { x: -350 + 50 }, 1000, "Quart.easeOut");
      this.tweenE = this.game.add.tween(this.baby2).to( { x: -350 }, 1000, "Quart.easeOut");

      this.tweenF = this.game.add.tween(this.badGuy).to( { x: -350 }, 1000, "Quart.easeOut");
      this.tweenG = this.game.add.tween(this.baby).to( { x: -350 }, 1000, "Quart.easeOut");
      this.tweenH = this.game.add.tween(this.baby2).to( { x: 400 }, 1000, "Quart.easeOut");
      this.tweenI = this.game.add.tween(this.baby).to( { x: 400 }, 1000, "Quart.easeOut");

      tweenA.chain(tweenB);
      tweenB.chain(this.tweenC);
      tweenB.onComplete.add(this.catched, this);

      tweenA.start();
  }

  catched() {
    this.tweenC.start();
    this.tweenD.start();
    this.tweenE.start();

    this.tweenE.onComplete.add(() => {
      this.mapManager.removeLayer();
      this.badGuy.x = 970;
      this.baby.x = 990;
      this.baby2.x = 950;

      this.tweenF.start();
      this.tweenG.start();
      this.tweenH.start();
    }, this);

    this.tweenH.onComplete.add(() => {
      this.mapManager.removeLayer();
      this.badGuy.x = 970;
      this.baby.x = 990;

      this.baby2.kill();

      this.tweenF.start();
      this.tweenI.start();
    }, this);
  }

  preload() {
    this.game.load.spritesheet(HeroSprite.key, `res/${HeroSprite.path}`, WidthSpriteSheetHero, HeightSpriteSheetHero);
    this.game.load.image(Tileset.key, `res/${Tileset.path}`);
    this.game.load.tilemap(Levels[`Level6`].key, `res/${Levels[`Level6`].path}` , null, Phaser.Tilemap.TILED_JSON);
    this.game.load.image("baby", "res/baby.png");
    this.game.load.image("baby2", "res/baby2.png");
    this.game.load.image("baby3", "res/baby3.png");
  }

  render() {
    //this.game.debug.text(this.game.time.fps, 2, 16, "#00ff00");
  }

}

export default Introduction;
<|endoftext|>


<commit_before>/**
 * COMMON STRUCTOR WEBPACK CONFIGURATION
 */

var path = require('path');
var webpack = require('webpack');

module.exports = (options) => ({
	// Add hot reloading in development
	entry: [
		'react-hot-loader/patch',
		'eventsource-polyfill', // Necessary for hot reloading with IE
		'webpack-hot-middleware/client?path=/structor-dev/a&timeout=2000&overlay=false&noInfo=true',
		path.join(process.cwd(), '.structor/src/default.js'), // Start
	],

	output: {
		path: path.join(process.cwd(), '.structor/desk/__build__'),
		filename: 'bundle.js',
		publicPath: '/structor-dev/__build__',
	},

	module: {
		loaders: [{
			test: /\.js$/, // Transform all .js files required somewhere with Babel
			loader: 'babel-loader',
			exclude: /node_modules/,
			query: {
				plugins: ['react-hot-loader/babel'],
				presets: [
					[
						'es2015',
						{
							modules: false
						}
					],
					'react',
					'stage-0',
				]
			},
		}, {
			// Do not transform vendor's CSS with CSS-modules
			// The point is that they remain in global scope.
			// Since we require these CSS files in our JS or CSS files,
			// they will be a part of our compilation either way.
			// So, no need for ExtractTextPlugin here.
			test: /\.css$/,
			include: [/node_modules/], // eslint-disable-line
			loaders: ['style-loader', 'css-loader'],
		}, {
			test: /\.(eot|svg|ttf|woff|woff2)$/,
			loader: 'file-loader',
		}, {
			test: /\.(jpg|png|gif)$/,
			loader: 'file-loader',
		}, {
			test: /\.html$/,
			loader: 'html-loader',
		}, {
			test: /\.json$/,
			loader: 'json-loader',
		}, {
			test: /\.mp4$/,
			loader: 'url?limit=10000&mimetype=video/mp4',
		}, {
			test: /\.webm$/,
			loader: 'url?limit=10000&mimetype=video/webm',
		}],
	},

	plugins: [

		new webpack.optimize.OccurrenceOrderPlugin(),
		new webpack.HotModuleReplacementPlugin(), // Tell webpack we want hot reloading
		new webpack.NoEmitOnErrorsPlugin(),
		new webpack.ProvidePlugin({
			// make fetch available
			fetch: 'exports?self.fetch!whatwg-fetch',
		}),

		// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
		// inside your code for any environment checks; UglifyJS will automatically
		// drop any unreachable code.
		new webpack.DefinePlugin({
			'process.env': {
				NODE_ENV: JSON.stringify(process.env.NODE_ENV),
			},
		}),

	],

	resolve: {
		modules: [path.resolve(__dirname, '../' + options.srcPath), 'node_modules'],
		extensions: [
			'.js',
			'.jsx',
			'.react.js',
		],
		mainFields: [
			'browser',
			'jsnext:main',
			'main',
		],
	},

	// Emit a source map for easier debugging
	devtool: 'cheap-module-eval-source-map',
	target: 'web', // Make web variables accessible to webpack, e.g. window
	stats: false, // Don't show stats in the console
	performance: {
		hints: false
	},
});
<commit_msg>Fix Webpack base config<commit_after>/**
 * COMMON STRUCTOR WEBPACK CONFIGURATION
 */

var path = require('path');
var webpack = require('webpack');

module.exports = (options) => ({
	// Add hot reloading in development
	entry: [
		'react-hot-loader/patch',
		'eventsource-polyfill', // Necessary for hot reloading with IE
		'webpack-hot-middleware/client?path=/structor-dev/a&timeout=2000&overlay=false&noInfo=true',
		path.join(process.cwd(), '.structor/src/default.js'), // Start
	],

	output: {
		path: path.join(process.cwd(), '.structor/desk/__build__'),
		filename: 'bundle.js',
		publicPath: '/structor-dev/__build__',
	},

	module: {
		loaders: [{
			test: /\.js$/, // Transform all .js files required somewhere with Babel
			loader: 'babel-loader',
			exclude: /node_modules/,
			query: {
				plugins: ['react-hot-loader/babel'],
				presets: [
					[
						'es2015',
						{
							modules: false
						}
					],
					'react',
					'stage-0',
				]
			},
		}, {
			test: /\.css$/,
			loaders: ['style-loader', 'css-loader'],
		}, {
			test: /\.(eot|svg|ttf|woff|woff2)$/,
			loader: 'file-loader',
		}, {
			test: /\.(jpg|png|gif)$/,
			loader: 'file-loader',
		}, {
			test: /\.html$/,
			loader: 'html-loader',
		}, {
			test: /\.json$/,
			loader: 'json-loader',
		}, {
			test: /\.mp4$/,
			loader: 'url?limit=10000&mimetype=video/mp4',
		}, {
			test: /\.webm$/,
			loader: 'url?limit=10000&mimetype=video/webm',
		}],
	},

	plugins: [

		new webpack.optimize.OccurrenceOrderPlugin(),
		new webpack.HotModuleReplacementPlugin(), // Tell webpack we want hot reloading
		new webpack.NoEmitOnErrorsPlugin(),
		new webpack.ProvidePlugin({
			// make fetch available
			fetch: 'exports?self.fetch!whatwg-fetch',
		}),

		// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
		// inside your code for any environment checks; UglifyJS will automatically
		// drop any unreachable code.
		new webpack.DefinePlugin({
			'process.env': {
				NODE_ENV: JSON.stringify(process.env.NODE_ENV),
			},
		}),

	],

	resolve: {
		modules: [path.resolve(__dirname, '../' + options.srcPath), 'node_modules'],
		extensions: [
			'.js',
			'.jsx',
			'.react.js',
		],
		mainFields: [
			'browser',
			'jsnext:main',
			'main',
		],
	},

	// Emit a source map for easier debugging
	devtool: 'cheap-module-eval-source-map',
	target: 'web', // Make web variables accessible to webpack, e.g. window
	stats: false, // Don't show stats in the console
	performance: {
		hints: false
	},
});
<|endoftext|>