<commit_before>var net = require('net');
var fifo = require('fifo');
var once = require('once');
var speedometer = require('speedometer');
var peerWireProtocol = require('peer-wire-protocol');
var EventEmitter = require('events').EventEmitter;
var util = require('util');

var HANDSHAKE_TIMEOUT = 25000;
var RECONNECT_WAIT = [1000, 5000, 15000, 30000, 60000, 120000, 300000, 600000];
var DEFAULT_SIZE = 100;

var toBuffer = function(str, encoding) {
	return Buffer.isBuffer(str) ? str : new Buffer(str, encoding);
};

var toAddress = function(wire) {
	if (typeof wire === 'string') return wire;
	return wire.peerAddress;
};

var onwire = function(swarm, connection, onhandshake) {
	var wire = peerWireProtocol();

	connection.on('end', function() {
		connection.destroy();
	});
	connection.on('error', function() {
		connection.destroy();
	});
	connection.on('close', function() {
		wire.destroy();
	});

	var destroy = function() {
		connection.destroy();
	};
	var timeout = setTimeout(destroy, swarm.timeout);
	if (timeout.unref) timeout.unref();

	wire.once('handshake', function(infoHash, peerId) {
		clearTimeout(timeout);
		onhandshake(infoHash, peerId);
	});

	connection.pipe(wire).pipe(connection);
	return wire;
};

var pools = {};

var leave = function(port, swarm) {
	if (!pools[port]) return;
	delete pools[port].swarms[swarm.infoHash.toString('hex')];

	if (Object.keys(pools[port].swarms).length) return;
	pools[port].server.close();
	delete pools[port];
};

var join = function(port, swarm) {
	var pool = pools[port];

	if (!pool) {
		var swarms = {};
		var server = net.createServer(function(connection) {
			var wire = onwire(swarm, connection, function(infoHash, peerId) {
				var swarm = swarms[infoHash.toString('hex')];
				if (!swarm) return connection.destroy();
				swarm._onincoming(connection, wire);
			});
		});

		server.listen(port, function() {
			pool.listening = true;
			Object.keys(swarms).forEach(function(infoHash) {
				swarms[infoHash].emit('listening');
			});
		});

		pool = pools[port] = {
			server: server,
			swarms: swarms,
			listening: false
		};
	}

	var infoHash = swarm.infoHash.toString('hex');

	if (pool.listening) {
		process.nextTick(function() {
			swarm.emit('listening');
		});
	}
	if (pool.swarms[infoHash]) {
		process.nextTick(function() {
			swarm.emit('error', new Error('port and info hash already in use'));
		});
		return;
	}

	pool.swarms[infoHash] = swarm;
};

var Swarm = function(infoHash, peerId, options) {
	if (!(this instanceof Swarm)) return new Swarm(infoHash, peerId, options);
	EventEmitter.call(this);

	options = options || {};
	this.handshake = options.handshake;

	this.port = 0;
	this.size = options.size || DEFAULT_SIZE;
	this.timeout = options.timeout || HANDSHAKE_TIMEOUT;

	this.infoHash = toBuffer(infoHash, 'hex');
	this.peerId = toBuffer(peerId, 'utf-8');

	this.downloaded = 0;
	this.uploaded = 0;
	this.connections = [];
	this.wires = [];
	this.paused = false;

	this.uploaded = 0;
	this.downloaded = 0;

	this.downloadSpeed = speedometer();
	this.uploadSpeed = speedometer();

	this._destroyed = false;
	this._queues = [fifo()];
	this._peers = {};
};

util.inherits(Swarm, EventEmitter);

Swarm.prototype.__defineGetter__('queued', function() {
	return this._queues.reduce(function(prev, queue) {
		return prev + queue.length;
	}, 0);
});

Swarm.prototype.pause = function() {
	this.paused = true;
};

Swarm.prototype.resume = function() {
	this.paused = false;
	this._drain();
};

Swarm.prototype.priority = function(addr, level) {
	addr = toAddress(addr);
	var peer = this._peers[addr];

	if (!peer) return 0;
	if (typeof level !== 'number' || peer.priority === level) return level;

	if (!this._queues[level]) this._queues[level] = fifo();

	if (peer.node) {
		this._queues[peer.priority].remove(peer.node);
		peer.node = this._queues[level].push(addr);
	}

	return peer.priority = level;
};

Swarm.prototype.add = function(addr) {
	if (this._destroyed || this._peers[addr]) return;

	var port = Number(addr.split(':')[1]);
	if (!(port > 0 && port < 65535)) return;

	this._peers[addr] = {
		node: this._queues[0].push(addr),
		wire: null,
		timeout: null,
		reconnect: false,
		priority: 0,
		retries: 0,
	};

	this._drain();
};

Swarm.prototype.remove = function(addr) {
	this._remove(toAddress(addr));
	this._drain();
};

Swarm.prototype.listen = function(port, onlistening) {
	if (onlistening) this.once('listening', onlistening);
	this.port = port;
	join(this.port, this);
};

Swarm.prototype.destroy = function() {
	this._destroyed = true;

	var self = this;
	Object.keys(this._peers).forEach(function(addr) {
		self._remove(addr);
	});

	leave(this.port, this);
	process.nextTick(function() {
		self.emit('close');
	});
};

Swarm.prototype._remove = function(addr) {
	var peer = this._peers[addr];
	if (!peer) return;
	delete this._peers[addr];
	if (peer.node) this._queues[peer.priority].remove(peer.node);
	if (peer.timeout) clearTimeout(peer.timeout);
	if (peer.wire) peer.wire.destroy();
};

Swarm.prototype._drain = function() {
	if (this.connections.length >= this.size || this.paused) return;

	var self = this;
	var addr = this._shift();
	if (!addr) return;

	var peer = this._peers[addr];
	if (!peer) return;

	var parts = addr.split(':');
	var connection = net.connect(parts[1], parts[0]);
	if (peer.timeout) clearTimeout(peer.timeout);

	peer.node = null;
	peer.timeout = null;

	var wire = onwire(swarm, connection, function(infoHash) {
		if (infoHash.toString('hex') !== self.infoHash.toString('hex')) return connection.destroy();
		peer.reconnect = true;
		peer.retries = 0;
		self._onwire(connection, wire);
	});

	var repush = function() {
		peer.node = self._queues[peer.priority].push(addr);
		self._drain();
	};

	wire.on('end', function() {
		peer.wire = null;
		if (!peer.reconnect || self._destroyed || peer.retries >= RECONNECT_WAIT.length) return self._remove(addr);
		peer.timeout = setTimeout(repush, RECONNECT_WAIT[peer.retries++]);
	});

	peer.wire = wire;
	self._onconnection(connection);

	wire.peerAddress = addr;
	wire.handshake(this.infoHash, this.peerId, this.handshake);
};

Swarm.prototype._shift = function() {
	for (var i = this._queues.length-1; i >= 0; i--) {
		if (this._queues[i] && this._queues[i].length) return this._queues[i].shift();
	}
	return null;
};

Swarm.prototype._onincoming = function(connection, wire) {
	wire.peerAddress = connection.address().address + ':' + connection.address().port;
	wire.handshake(this.infoHash, this.peerId, this.handshake);

	this._onconnection(connection);
	this._onwire(connection, wire);
};

Swarm.prototype._onconnection = function(connection) {
	var self = this;

	connection.once('close', function() {
		self.connections.splice(self.connections.indexOf(connection), 1);
		self._drain();
	});

	this.connections.push(connection);
};

Swarm.prototype._onwire = function(connection, wire) {
	var self = this;

	wire.on('download', function(downloaded) {
		self.downloaded += downloaded;
		self.downloadSpeed(downloaded);
		self.emit('download', downloaded);
	});

	wire.on('upload', function(uploaded) {
		self.uploaded += uploaded;
		self.uploadSpeed(uploaded);
		self.emit('upload', uploaded);
	});

	var cleanup = once(function() {
		self.wires.splice(self.wires.indexOf(wire), 1);
		connection.destroy();
	});

	connection.on('close', cleanup);
	connection.on('error', cleanup);
	connection.on('end', cleanup);
	wire.on('end', cleanup);
	wire.on('close', cleanup);
	wire.on('finish', cleanup);

	this.wires.push(wire);
	this.emit('wire', wire, connection);
};

module.exports = Swarm;
<commit_msg>fixed ref error<commit_after>var net = require('net');
var fifo = require('fifo');
var once = require('once');
var speedometer = require('speedometer');
var peerWireProtocol = require('peer-wire-protocol');
var EventEmitter = require('events').EventEmitter;
var util = require('util');

var HANDSHAKE_TIMEOUT = 25000;
var RECONNECT_WAIT = [1000, 5000, 15000, 30000, 60000, 120000, 300000, 600000];
var DEFAULT_SIZE = 100;

var toBuffer = function(str, encoding) {
	return Buffer.isBuffer(str) ? str : new Buffer(str, encoding);
};

var toAddress = function(wire) {
	if (typeof wire === 'string') return wire;
	return wire.peerAddress;
};

var onwire = function(swarm, connection, onhandshake) {
	var wire = peerWireProtocol();

	connection.on('end', function() {
		connection.destroy();
	});
	connection.on('error', function() {
		connection.destroy();
	});
	connection.on('close', function() {
		wire.destroy();
	});

	var destroy = function() {
		connection.destroy();
	};
	var timeout = setTimeout(destroy, swarm.timeout);
	if (timeout.unref) timeout.unref();

	wire.once('handshake', function(infoHash, peerId) {
		clearTimeout(timeout);
		onhandshake(infoHash, peerId);
	});

	connection.pipe(wire).pipe(connection);
	return wire;
};

var pools = {};

var leave = function(port, swarm) {
	if (!pools[port]) return;
	delete pools[port].swarms[swarm.infoHash.toString('hex')];

	if (Object.keys(pools[port].swarms).length) return;
	pools[port].server.close();
	delete pools[port];
};

var join = function(port, swarm) {
	var pool = pools[port];

	if (!pool) {
		var swarms = {};
		var server = net.createServer(function(connection) {
			var wire = onwire(swarm, connection, function(infoHash, peerId) {
				var swarm = swarms[infoHash.toString('hex')];
				if (!swarm) return connection.destroy();
				swarm._onincoming(connection, wire);
			});
		});

		server.listen(port, function() {
			pool.listening = true;
			Object.keys(swarms).forEach(function(infoHash) {
				swarms[infoHash].emit('listening');
			});
		});

		pool = pools[port] = {
			server: server,
			swarms: swarms,
			listening: false
		};
	}

	var infoHash = swarm.infoHash.toString('hex');

	if (pool.listening) {
		process.nextTick(function() {
			swarm.emit('listening');
		});
	}
	if (pool.swarms[infoHash]) {
		process.nextTick(function() {
			swarm.emit('error', new Error('port and info hash already in use'));
		});
		return;
	}

	pool.swarms[infoHash] = swarm;
};

var Swarm = function(infoHash, peerId, options) {
	if (!(this instanceof Swarm)) return new Swarm(infoHash, peerId, options);
	EventEmitter.call(this);

	options = options || {};
	this.handshake = options.handshake;

	this.port = 0;
	this.size = options.size || DEFAULT_SIZE;
	this.timeout = options.timeout || HANDSHAKE_TIMEOUT;

	this.infoHash = toBuffer(infoHash, 'hex');
	this.peerId = toBuffer(peerId, 'utf-8');

	this.downloaded = 0;
	this.uploaded = 0;
	this.connections = [];
	this.wires = [];
	this.paused = false;

	this.uploaded = 0;
	this.downloaded = 0;

	this.downloadSpeed = speedometer();
	this.uploadSpeed = speedometer();

	this._destroyed = false;
	this._queues = [fifo()];
	this._peers = {};
};

util.inherits(Swarm, EventEmitter);

Swarm.prototype.__defineGetter__('queued', function() {
	return this._queues.reduce(function(prev, queue) {
		return prev + queue.length;
	}, 0);
});

Swarm.prototype.pause = function() {
	this.paused = true;
};

Swarm.prototype.resume = function() {
	this.paused = false;
	this._drain();
};

Swarm.prototype.priority = function(addr, level) {
	addr = toAddress(addr);
	var peer = this._peers[addr];

	if (!peer) return 0;
	if (typeof level !== 'number' || peer.priority === level) return level;

	if (!this._queues[level]) this._queues[level] = fifo();

	if (peer.node) {
		this._queues[peer.priority].remove(peer.node);
		peer.node = this._queues[level].push(addr);
	}

	return peer.priority = level;
};

Swarm.prototype.add = function(addr) {
	if (this._destroyed || this._peers[addr]) return;

	var port = Number(addr.split(':')[1]);
	if (!(port > 0 && port < 65535)) return;

	this._peers[addr] = {
		node: this._queues[0].push(addr),
		wire: null,
		timeout: null,
		reconnect: false,
		priority: 0,
		retries: 0,
	};

	this._drain();
};

Swarm.prototype.remove = function(addr) {
	this._remove(toAddress(addr));
	this._drain();
};

Swarm.prototype.listen = function(port, onlistening) {
	if (onlistening) this.once('listening', onlistening);
	this.port = port;
	join(this.port, this);
};

Swarm.prototype.destroy = function() {
	this._destroyed = true;

	var self = this;
	Object.keys(this._peers).forEach(function(addr) {
		self._remove(addr);
	});

	leave(this.port, this);
	process.nextTick(function() {
		self.emit('close');
	});
};

Swarm.prototype._remove = function(addr) {
	var peer = this._peers[addr];
	if (!peer) return;
	delete this._peers[addr];
	if (peer.node) this._queues[peer.priority].remove(peer.node);
	if (peer.timeout) clearTimeout(peer.timeout);
	if (peer.wire) peer.wire.destroy();
};

Swarm.prototype._drain = function() {
	if (this.connections.length >= this.size || this.paused) return;

	var self = this;
	var addr = this._shift();
	if (!addr) return;

	var peer = this._peers[addr];
	if (!peer) return;

	var parts = addr.split(':');
	var connection = net.connect(parts[1], parts[0]);
	if (peer.timeout) clearTimeout(peer.timeout);

	peer.node = null;
	peer.timeout = null;

	var wire = onwire(this, connection, function(infoHash) {
		if (infoHash.toString('hex') !== self.infoHash.toString('hex')) return connection.destroy();
		peer.reconnect = true;
		peer.retries = 0;
		self._onwire(connection, wire);
	});

	var repush = function() {
		peer.node = self._queues[peer.priority].push(addr);
		self._drain();
	};

	wire.on('end', function() {
		peer.wire = null;
		if (!peer.reconnect || self._destroyed || peer.retries >= RECONNECT_WAIT.length) return self._remove(addr);
		peer.timeout = setTimeout(repush, RECONNECT_WAIT[peer.retries++]);
	});

	peer.wire = wire;
	self._onconnection(connection);

	wire.peerAddress = addr;
	wire.handshake(this.infoHash, this.peerId, this.handshake);
};

Swarm.prototype._shift = function() {
	for (var i = this._queues.length-1; i >= 0; i--) {
		if (this._queues[i] && this._queues[i].length) return this._queues[i].shift();
	}
	return null;
};

Swarm.prototype._onincoming = function(connection, wire) {
	wire.peerAddress = connection.address().address + ':' + connection.address().port;
	wire.handshake(this.infoHash, this.peerId, this.handshake);

	this._onconnection(connection);
	this._onwire(connection, wire);
};

Swarm.prototype._onconnection = function(connection) {
	var self = this;

	connection.once('close', function() {
		self.connections.splice(self.connections.indexOf(connection), 1);
		self._drain();
	});

	this.connections.push(connection);
};

Swarm.prototype._onwire = function(connection, wire) {
	var self = this;

	wire.on('download', function(downloaded) {
		self.downloaded += downloaded;
		self.downloadSpeed(downloaded);
		self.emit('download', downloaded);
	});

	wire.on('upload', function(uploaded) {
		self.uploaded += uploaded;
		self.uploadSpeed(uploaded);
		self.emit('upload', uploaded);
	});

	var cleanup = once(function() {
		self.wires.splice(self.wires.indexOf(wire), 1);
		connection.destroy();
	});

	connection.on('close', cleanup);
	connection.on('error', cleanup);
	connection.on('end', cleanup);
	wire.on('end', cleanup);
	wire.on('close', cleanup);
	wire.on('finish', cleanup);

	this.wires.push(wire);
	this.emit('wire', wire, connection);
};

module.exports = Swarm;
<|endoftext|>


<commit_before>const express = require('express')
const path = require('path')
const app = express()

app.use(
  express.static(
    path.join(__dirname, '/public/build/')
  )
)

app.get(
  '*', (req, res) => {
    res.sendFile(
      path.join(__dirname, '/public/build/index.html')
    )
  }
)

app.listen(
  process.env.PORT || 8080, () => {
    return console.log('🌐 Server running on port ', process.env.PORT || 8080)
  }
)
<commit_msg>Remove the meridians from the index.js file.<commit_after>const express = require('express')
const path = require('path')
const app = express()

app.use(
  express.static(
    path.join(__dirname, '/public/build/')
  )
)

app.get(
  '*', (req, res) => {
    res.sendFile(
      path.join(__dirname, '/public/build/index.html')
    )
  }
)

app.listen(
  process.env.PORT || 8080, () => {
    return console.log('Server running on port ', process.env.PORT || 8080)
  }
)
<|endoftext|>


<commit_before>const _ = require('lodash');
const co = require('co');

const MAX_TIMEOUT_VALUE = 2147483647;

module.exports = function(underlying, interval = 0, {
    leading = false,
    trailing = true,
    maxWait = null,
    delayBetweenExecutions = null,
    waitForNextExecution = true,
    allowConcurrentExecutions = false
}) {
    leading = !!leading;
    trailing = !!trailing;

    // function must either execute on leading side or on trailing side, not neither
    if (!leading && !trailing) {
        trailing = true;
    }

    waitForNextExecution = !!waitForNextExecution;

    // if function executes on leading side only, waiting for next execution makes no sense
    // same applies for trailing side only and previous execution
    if (!leading || !trailing) {
        waitForNextExecution = trailing;
    }

    allowConcurrentExecutions = !!allowConcurrentExecutions;

    interval = _.clamp(interval, 0, MAX_TIMEOUT_VALUE);

    let applyMaxWait = _.isNil(maxWait);
    maxWait = _.clamp(maxWait, interval, MAX_TIMEOUT_VALUE);

    let applyDelayBetweenExecutions = _.isNil(delayBetweenExecutions);
    delayBetweenExecutions = _.clamp(delayBetweenExecutions, 0, MAX_TIMEOUT_VALUE);

    // if a delay between executions is set, no consecutive executions can occur
    if (allowConcurrentExecutions && applyDelayBetweenExecutions) {
        allowConcurrentExecutions = false;
    }

    let currentlyExecuting = false;

    let callsWaiting = false;
    let firstWaitingCall = null;
    let lastProcessedCall = null;
    let lastCall = null;
    let lastCallArgs = null;
    let lastCallThis = null;
    let lastExecution = null;

    let nextRunTimer = null;
    let nextRunIsImmediate = false;

    let currentPromise = null;

    let nextPromise = null;
    let nextResolver = null;
    let nextRejecter = null;

    function cancelWaitingRun() {
        // properly cancel either immediate or timeout
        if (nextRunTimer) {
            if (nextRunIsImmediate) {
                clearImmediate(nextRunTimer);
            }
            else {
                clearTimeout(nextRunTimer);
            }
        }

        nextRunTimer = null;
    }

    function scheduleRun(func, time) {
        cancelWaitingRun();

        // clamp to acceptable timeout values
        time = _.clamp(time, 0, MAX_TIMEOUT_VALUE);

        // use either immediates or timeouts
        if (time === 0) {
            nextRunTimer = setImmediate(func);
            nextRunIsImmediate = true;
        }
        else {
            nextRunTimer = setTimeout(func, time);
            nextRunIsImmediate = false;
        }
    }

    function setNextPromise() {
        nextPromise = new Promise(function(resolve, reject) {
            // make sure to keep the resolver and rejecter
            nextResolver = resolve;
            nextRejecter = reject;
        });
    }

    function scheduleNextRun() {
        let currentTime = Date.now();

        if (callsWaiting) {
            // calls are waiting, schedule a run

            let times = [lastCall + interval];

            // apply max wait(s)
            if (applyMaxWait) {
                if (leading && lastProcessedCall) {
                    times.push(lastProcessedCall + maxWait);
                }

                if (trailing && firstWaitingCall) {
                    times.push(firstWaitingCall + maxWait);
                }
            }

            let nextTime = _.min(times);

            // apply delay between executions
            if (applyDelayBetweenExecutions && lastExecution) {
                let nextAllowedTime = lastExecution + delayBetweenExecutions;

                if (nextAllowedTime > nextTime) {
                    nextTime = nextAllowedTime;
                }
            }

            // schedule actual run
            let wait = nextTime - currentTime;
            scheduleRun(executeUnderlying, wait);
        }
    }

    function executeUnderlying() {
        let promise = nextPromise;
        let resolve = nextResolver;
        let reject = nextRejecter;

        let funcArgs = lastCallArgs;
        let funcThis = lastCallThis;

        return co(function*() {
            currentlyExecuting = true;
            callsWaiting = false;
            firstWaitingCall = null;
            lastProcessedCall = lastCall;
            currentPromise = promise;
            cancelWaitingRun();
            setNextPromise();

            try {
                let result = yield underlying.apply(funcThis, funcArgs);

                resolve(result);
            }
            catch (err) {
                reject(err);
            }

            let finishTime = Date.now();

            // clean up if appropriate
            if (currentPromise === promise) {
                currentlyExecuting = false;
                lastExecution = finishTime;

                // schedule any delayed calls
                if (callsWaiting) {
                    scheduleNextRun();
                }
            }
        });
    }

    let debounced = function debouncer() {
        let currentTime = Date.now();
        let withinDebounceInterval = lastCall && lastCall + interval > currentTime;
        lastCall = currentTime;
        lastCallArgs = arguments;
        lastCallThis = this;

        if (leading) {
            if (!withinDebounceInterval) {
                // just run now
                executeUnderlying();
                return currentPromise;
            }
            else {
                // even if not the leading call, max wait may apply forcing a run
                if (applyMaxWait) {
                    let waitTime = currentTime - lastProcessedCall;

                    if (waitTime >= maxWait) {
                        callsWaiting = true;
                    }
                }
            }
        }

        if (trailing) {
            // calls are always waiting on the trailing edge
            callsWaiting = true;

            if (!firstWaitingCall) {
                firstWaitingCall = currentTime;
            }
        }

        if (callsWaiting) {
            // don't schedule runs during an execution unless allowed to
            if (!currentlyExecuting || allowConcurrentExecutions) {
                scheduleNextRun();
            }
        }

        // provide proper promise
        return waitForNextExecution ? nextPromise : currentPromise;
    }

    debounced.flush = function flush() {
        executeUnderlying();
    }

    debounced.cancel = function cancel() {
        nextRejecter(new Error('call canceled'));
        callsWaiting = false;
        firstWaitingCall = null;
        lastCall = null;
        cancelWaitingRun();
        setNextPromise();
    }

    setNextPromise();

    return debounced;
}
<commit_msg>Overhaul debounce code again.<commit_after>const _ = require('lodash');
const co = require('co');

const MAX_TIMEOUT_VALUE = 2147483647;

module.exports = function(underlying, interval = 0, {
    leading = null,
    trailing = null,
    maxWait = null,
    delayBetweenExecutions = null,
    condenseExecutions = false,
    allowConcurrentExecutions = false
} = {}) {
    leading = !!leading;
    trailing = !!trailing;

    // function must either execute on leading side or on trailing side, not neither
    if (!leading && !trailing) {
        trailing = true;
    }

    condenseExecutions = !!condenseExecutions;
    allowConcurrentExecutions = !!allowConcurrentExecutions;

    interval = _.clamp(interval, 0, MAX_TIMEOUT_VALUE);

    let applyMaxWait = !_.isNil(maxWait);
    maxWait = _.clamp(maxWait, interval, MAX_TIMEOUT_VALUE);

    let applyDelayBetweenExecutions = !_.isNil(delayBetweenExecutions);
    delayBetweenExecutions = _.clamp(delayBetweenExecutions, 0, MAX_TIMEOUT_VALUE);

    let executions = [];

    let waitTimer = null;
    let waitTimerIsImmediate = false;

    function cancelWait() {
        // properly cancel either immediate or timeout
        if (waitTimer) {
            if (waitTimerIsImmediate) {
                clearImmediate(waitTimer);
            }
            else {
                clearTimeout(waitTimer);
            }
        }

        waitTimer = null;
    }

    function scheduleWait(func, time) {
        cancelWait();

        // clamp to acceptable timeout values
        time = _.clamp(time, 0, MAX_TIMEOUT_VALUE);

        // use either immediates or timeouts
        if (time === 0) {
            waitTimer = setImmediate(func);
            waitTimerIsImmediate = true;
        }
        else {
            waitTimer = setTimeout(func, time);
            waitTimerIsImmediate = false;
        }
    }

    function dispatchExecution(execution) {
        return co(function*() {
            execution.startTime = Date.now();

            try {
                let result = yield underlying.apply(execution.this, execution.arguments);

                execution.resolve(result);
            }
            catch (err) {
                execution.reject(err);
            }

            execution.finishTime = Date.now();

            maintainExecutions(); // eslint-disable-line no-use-before-define
        })
    }

    function maintainExecutions() {
        let currentTime = Date.now();

        cancelWait();

        let nextCheckWait;

        for (let i = 0; i < executions.length; i++) {
            let execution = executions[i];

            if (execution.startTime) {
                // execution started

                if (execution.finishTime) {
                    // execution finished

                    if (applyDelayBetweenExecutions && execution.finishTime + delayBetweenExecutions > currentTime) {
                        // keep execution in array to constrain next execution
                        continue;
                    }
                    else if (execution.lastCallTime + interval > currentTime) {
                        // still within debounce interval, allow calls to continue being attached
                        continue;
                    }
                    else {
                        // remove execution from array and move on
                        executions.splice(i, 1);
                        i--;
                        continue;
                    }
                }
                else {
                    // no need to operate on an unfinished execution
                    continue;
                }
            }

            let expectedExecutionTime = execution.isLeading ? execution.firstCallTime : execution.lastCallTime + interval;

            if (i > 0) {
                // execution before this, check if wait required

                let lastExecution = executions[i - 1];

                if (!allowConcurrentExecutions) {
                    // no concurrent executions allowed

                    if (!lastExecution.startTime || !lastExecution.finishTime) {
                        // last execution is running or hasn't even started, so can't start this one
                        expectedExecutionTime = null;
                    }
                    else {
                        if (applyDelayBetweenExecutions) {
                            // need to make sure execution is sufficiently delayed
                            expectedExecutionTime = Math.max(lastExecution.finishTime + delayBetweenExecutions, expectedExecutionTime);
                        }
                    }
                }
                else {
                    if (applyDelayBetweenExecutions) {
                        // need to make sure execution is sufficiently delayed

                        if (!lastExecution.startTime) {
                            // last execution hasn't even started, so can't start this one
                            expectedExecutionTime = null;
                        }
                        else {
                            // need to make sure execution is sufficiently delayed
                            expectedExecutionTime = Math.max(lastExecution.startTime + delayBetweenExecutions, expectedExecutionTime);
                        }
                    }
                }
            }

            if (expectedExecutionTime) {
                if (expectedExecutionTime <= currentTime) {
                    // need to run the execution now, dispatch and continue operating on executions
                    dispatchExecution(execution);
                    continue;
                }
                else {
                    // defined amount of time before execution can begin
                    nextCheckWait = expectedExecutionTime - currentTime;
                }
            }

            break;
        }

        if (nextCheckWait) {
            scheduleWait(maintainExecutions, nextCheckWait);
        }
    }

    function createNewExecution({
        firstCallTime,
        isLeading,
        executionArguments,
        executionThis
    }) {
        let execution = {
            firstCallTime,
            lastCallTime: firstCallTime,
            isLeading,
            arguments: executionArguments,
            this: executionThis,
            startTime: null,
            finishTime: null
        };
        execution.promise = new Promise(function(resolve, reject) {
            execution.resolve = resolve;
            execution.reject = reject;
        });

        executions.push(execution);

        return execution;
    }

    function getApplicableExecution(currentTime, callArguments, callThis) {
        let lastExecution = _.last(executions);

        if (!lastExecution) {
            // there are no active executions, create a new one
            return createNewExecution({
                firstCallTime: currentTime,
                isLeading: leading,
                executionArguments: callArguments,
                executionThis: callThis
            });
        }

        if (condenseExecutions && !lastExecution.startTime) {
            // condense into non-executed execution
            return lastExecution;
        }

        if (lastExecution.lastCallTime + interval > currentTime) {
            // call falls within debounce interval of last execution

            if (lastExecution.isLeading && trailing) {
                // need to create a trailing execution
                return createNewExecution({
                    firstCallTime: lastExecution.firstCallTime,
                    isLeading: false,
                    executionArguments: callArguments,
                    executionThis: callThis
                });
            }

            if (applyMaxWait && lastExecution.firstCallTime + maxWait <= currentTime) {
                // max wait has been exceeded, create new execution
                return createNewExecution({
                    firstCallTime: currentTime,
                    isLeading: leading,
                    executionArguments: callArguments,
                    executionThis: callThis
                });
            }

            // attach to last execution
            return lastExecution;
        }

        // need to create a new execution
        return createNewExecution({
            firstCallTime: currentTime,
            isLeading: leading,
            executionArguments: callArguments,
            executionThis: callThis
        });
    }

    let debounced = function debouncer() {
        let currentTime = Date.now();
        let execution = getApplicableExecution(currentTime, arguments, this);

        // update last call time
        execution.lastCallTime = currentTime;

        if (!execution.isLeading) {
            // update arguments and this for trailing execution
            execution.arguments = arguments;
            execution.this = this;
        }

        maintainExecutions();

        return execution.promise;
    }

    debounced.flush = function flush() {
        _.forEach(executions, function(execution) { // eslint-disable-line lodash/prefer-filter
            if (!execution.startTime) {
                // execution hasn't started, dispatch
                dispatchExecution(execution);
            }
        });

        maintainExecutions();
    }

    debounced.cancel = function cancel() {
        executions = _.reject(executions, function(execution) {
            if (execution.startTime) {
                // execution has started, leave alone
                return false;
            }
            else {
                // execution hasn't started, cancel
                execution.reject(new Error('canceled'));
                return true;
            }
        });

        maintainExecutions();
    }

    return debounced;
}
<|endoftext|>


<commit_before>'use strict'

var EventEmitter = require('events').EventEmitter;
var util = require('util');

function CircularQueue (maxSize) {

  if (typeof maxSize !== 'number' || maxSize < 1) {
    throw new Error('please specify maxSize');
  }

  Object.defineProperties(this, {
    'maxSize': {
      get: function () {
        return maxSize;
      }
    },
    'size': {
      get: function () {
        return this._size;
      }
    }
  });

  this._items = [];
  this._head = 0;
  this._size = 0;
};

util.inherits(CircularQueue, EventEmitter);

CircularQueue.prototype._rotate = function () {

  var removedItem = this._items[this._head];

  if ((this._head + 1) === this.maxSize) {
    this._head = 0;
  }
  else {
    this._head++;
  }

  return removedItem;
};

CircularQueue.prototype.isFull = function () {
  return this.size === this.maxSize;
};

CircularQueue.prototype.isEmpty = function () {
  return this.size === 0;
};

CircularQueue.prototype.offer = function (item) {
  var tailIndex;

  if (this.isFull()) {
    this.emit('evict', this._rotate());
  }
  else {
    this._size++;
  }

  tailIndex = (this._head + (this.size - 1)) % this.maxSize;

  this._items[tailIndex] = item;
};

CircularQueue.prototype.peek = function () {
  return this._items[this._head];
};

CircularQueue.prototype.poll = function () {
  if (!this.isEmpty()) {
    this._size--;
    return this._rotate();
  }
};

module.exports = CircularQueue;

<commit_msg>Rotates with ... math.<commit_after>'use strict'

var EventEmitter = require('events').EventEmitter;
var util = require('util');

function CircularQueue (maxSize) {

  if (typeof maxSize !== 'number' || maxSize < 1) {
    throw new Error('please specify maxSize');
  }

  Object.defineProperties(this, {
    'maxSize': {
      get: function () {
        return maxSize;
      }
    },
    'size': {
      get: function () {
        return this._size;
      }
    }
  });

  this._items = [];
  this._head = 0;
  this._size = 0;
};

util.inherits(CircularQueue, EventEmitter);

CircularQueue.prototype._rotate = function () {
  var removedItem = this.peek();
  this._head = (this._head + 1) % this.maxSize;
  return removedItem;
};

CircularQueue.prototype.isFull = function () {
  return this.size === this.maxSize;
};

CircularQueue.prototype.isEmpty = function () {
  return this.size === 0;
};

CircularQueue.prototype.offer = function (item) {
  var tailIndex;

  if (this.isFull()) {
    this.emit('evict', this._rotate());
  }
  else {
    this._size++;
  }

  tailIndex = (this._head + (this.size - 1)) % this.maxSize;

  this._items[tailIndex] = item;
};

CircularQueue.prototype.peek = function () {
  return this._items[this._head];
};

CircularQueue.prototype.poll = function () {
  if (!this.isEmpty()) {
    this._size--;
    return this._rotate();
  }
};

module.exports = CircularQueue;

<|endoftext|>


<commit_before>var placeholder = "Search, drag and drop video, or paste its URL...";

var playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";
var removeImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/x-4x.png";

var videoUrl;
var videoName;
var videoTime = null;

var videos = [];
var videoCounter = 0;
var videoIteration = 0;
var bufferTime = 2000;

var videoPaused;
var stayPaused;
var backRestart;

var loopTimer;
var progressTimer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function addVideoToList(name, time) {
  name = decodeURIComponent(name);
  $("#videosTable").append("
" + name + "<button class=\"tableButton removeButton\" onclick=\"actionRemoveVideo(this);\"></button>" +
  "<button class=\"tableButton playButton\" onclick=\"actionPlayVideo(this);\"></button>	" + time + "
");
}

function resetTimer(which) {
  if (which != 0) {
      which.pause();
    }
    which = 0;
}

var ActionTimers = function() {
  this.pause = function() {
    loopTimer.pause();
    progressTimer.pause();
  }
  this.resume = function() {
    loopTimer.resume();
    progressTimer.resume();
  }
  this.clear = function() {
    resetTimer(loopTimer);
    resetTimer(progressTimer);
    $("#progress").css("width", "0%");
    $("#currentTime").text("0:00");
  }
}
var actionTimers = new ActionTimers();

function videoProgress() {
  $("#videoTime").text(msConversion(videos[videoIteration]["time"] * 1000));
  var iteration = 0;
  var percentChange = 1 / videos[videoIteration]["time"] * 100;
  var currentPercent = 0;
  var interval = bufferTime;
  function progressLoop() {
    iteration++;
    currentPercent = currentPercent + percentChange;
    progressTimer = new Timer(function() {
      $("#progress").css("width", currentPercent + "%");
      $("#currentTime").text(msConversion(iteration * 1000));
      progressLoop();
    }, interval);
    interval = 1000;
  }
  progressLoop();
}

function playVideo() {
  highlight(videoIteration);
  document.title = "Streamly - " + decodeURIComponent(videos[videoIteration]["name"]);
  var embedUrl = videos[videoIteration]["url"];

  var autoplay = "";
  if (!stayPaused) {
    autoplay = "?autoplay=1";
  }

  if (embedUrl.search(/file:\/\//i) == -1) {
    embedUrl = "https://www.youtube.com/embed/" + videos[videoIteration]["url"] + autoplay;
  }
  $("#youtube").attr("src", embedUrl);

  backRestart = false;
  window.setTimeout(function() {
    backRestart = true;
  }, 3000);

  videoProgress();
}

function loopVideo() {
  videoIteration++;
  playVideo();
  loopTimer = new Timer(function() {
    if (videoIteration < videoCounter) {
      loopVideo();
    }
    else {
      actionTimers.clear();
      $("#youtube").attr("src", "");
      document.title = "Streamly";
    }
  }, (videos[videoIteration]["time"] * 1000) + bufferTime);
  if (stayPaused) {
    actionTimers.pause();
  }
}

function pauseVideo() {
  if (!videoPaused) {
    actionTimers.pause();
    videoPaused = true;
    if (videos[0] !== null && videos[0] !== undefined) {
      document.title = "Streamly - " + decodeURIComponent(videos[0]);
    }
  }
  else {
    actionTimers.resume();
    videoPaused = false;
    stayPaused = false;
    document.title = "Streamly - " + decodeURIComponent(videos[videoIteration]["name"]);
  }
  $("#pauseOverlay").css("display", "none");
  setTimeout(function(){
    $("#pauseOverlay").css("display", "block");
    $("#youtube").blur();
  }, 500);
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    actionTimers.clear();

    if (videoPaused) {
      stayPaused = true;
    }
    loopVideo();
  }
}

function backVideo() {
  if (videoPaused) {
    stayPaused = true;
  }
  if (!backRestart) {
    if (videoIteration - 2 > -1) {
      videoIteration = videoIteration - 2;
      actionTimers.clear();
      loopVideo();
    }
  }
  else {
    videoIteration = videoIteration - 1;
    actionTimers.clear();
    loopVideo();
  }
}

function setPlaylist() {
  if (videos.length > 1) {
    var playlist = JSON.stringify(videos);
    playlist = window.btoa(playlist);
    playlist = encodeURIComponent(playlist);
    window.location.hash = playlist;
  }
  else {
    window.location.hash = "";
  }
}

function getPlaylist() {
  if (window.location.hash.substr(1) !== "") {
    var playlist = window.location.hash.substr(1);
    playlist = decodeURIComponent(playlist);
    playlist = window.atob(playlist);
    playlist = JSON.parse(playlist);
    videos = playlist;

    if (videos[0] != undefined) {
      $("#playlistNameBox").val(decodeURIComponent(videos[0]));
    }

    for (i = 1; i < videos.length; i++) {
      videoCounter = i;
      var printTime = msConversion(videos[videoCounter]["time"] * 1000);
      addVideoToList(videos[videoCounter]["name"], printTime);
    }
    loopVideo();
  }
}

function getVideoData() {
  $.ajax({
    url: videoUrl,
    type: 'GET',
    success: function(res) {
      var data = $(res.responseText);
      try {
        videoName = data.find("span#eow-title");
        videoName = videoName[0].textContent;
        videoName = $("
").html(videoName).text();
        videoName = videoName.trim();
      } catch(err) {
        videoName = prompt("Please enter the name of the video", "");
      }
      videoName = encodeURIComponent(videoName).replace(/%20/g, " ");
      try {
        videoTime = null;
        for (iteration in data) {
          var str = data[iteration].innerHTML;
          if (videoTime == null && typeof str != "undefined") {
            videoTime = str.match(/,"length_seconds":"\d+",/g);
          }
        }
        videoTime = videoTime[0];
        videoTime = videoTime.replace(/,"length_seconds":"/g, "").replace(/",/g, "");
        videoTime = +videoTime * 1000;
      } catch(err) {
        videoTime = prompt("Please enter the length of the video", "3:00");
        videoTime = videoTime.split(":");
        videoTime = (+videoTime[0]) * 60 + (+videoTime[1]);
        videoTime = videoTime * 1000;
      }
    },
    complete: function(jqXHR, textStatus) {
      $("#inputBox").val("").attr("placeholder", placeholder);
      addVideo();
    },
    error: function(jqXHR, textStatus, errorThrown) {
      videoName = prompt("Please enter the name of the video", "");

      videoTime = prompt("Please enter the length of the video", "3:00");
      videoTime = videoTime.split(":");
      videoTime = (+videoTime[0]) * 60 + (+videoTime[1]);
      videoTime = videoTime * 1000;
    }
  });
}

function addVideo() {
  videoCounter++;
  var video = {};
  video["name"] = videoName;
  video["time"] = videoTime / 1000;
  video["url"] = videoUrl.replace(/^htt(p|ps):\/\/www\.youtube\.com\/watch\?v=/i, "");
  videos[videoCounter] = video;

  var printTime = msConversion(videoTime);

  addVideoToList(videoName, printTime);

  setPlaylist();

  if (videoCounter == 1 || loopTimer == 0) {
    loopVideo();
  }
}

function actionPlayVideo(element) {
  var index = $(".playButton").index(element);
  videoIteration = index;
  actionTimers.clear();
  loopVideo();
}

function actionRemoveVideo(element) {
  var index = $(".removeButton").index(element) + 1;
  if (index == videoIteration) {
    if (videoIteration + 1 <= videoCounter) {
      forwardVideo();
      videoIteration--;
    }
    else {
      actionTimers.clear();
      $("#youtube").attr("src", "");
      document.title = "Streamly";
      videoIteration--;
    }
  }
  else if (index < videoIteration) {
    videoIteration--;
  }
  videoCounter--;
  videos.splice(index, 1);
  $("tr:nth-child(" + index + ")").remove();
  setPlaylist();
}

function urlValidate(url) {
  var isValidYouTube = /^htt(p|ps):\/\/www\.youtube\.com\/watch\?v=.+$/i;
  var isValidFile = /^file:\/\/.+$/i;

  url = url.trim();
  url = url.replace(/&list=.+/g, "");

  if (url.search(isValidYouTube) > -1 || url.search(isValidFile) > -1) {
    return url;
  }
  else {
    return false;
  }
}

function input(type) {
  var inputBox = $("#inputBox").val();
  var playlistNameBox = $("#playlistNameBox").val();
  switch (type) {
    case 0:
      if (inputBox != "") {
        window.open("https://www.youtube.com/results?search_query=" + inputBox.replace(/ /g, "+"));
        $("#inputBox").val("").attr("placeholder", placeholder);
      }
      break;
    case 1:
      if (inputBox != "") {
        inputBox = urlValidate(inputBox);
        if (inputBox) {
          videoUrl = inputBox;
          $("#inputBox").val("").attr("placeholder", "Loading video data from YouTube...");
          getVideoData();
        }
        else {
          alert("That video's URL seems broken\n\nTry copying it again, or drag and drop the video directly");
        }
      }
      break;
    case 2:
      if (playlistNameBox != "") {
        videos[0] = encodeURIComponent(playlistNameBox).replace(/%20/g, " ");
        setPlaylist();
      }
      else {
        videos[0] = undefined;
      }
      break;
  }
}

document.addEventListener("drop", function(event) {
  event.preventDefault();
  var data = event.dataTransfer.getData("URL");

  $("#inputBox").val(data);
  input(1);
});

document.addEventListener("dragover", function(event) {
  event.preventDefault();
});
<commit_msg>need to clear all timers before moving on<commit_after>var placeholder = "Search, drag and drop video, or paste its URL...";

var playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";
var removeImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/x-4x.png";

var videoUrl;
var videoName;
var videoTime = null;

var videos = [];
var videoCounter = 0;
var videoIteration = 0;
var bufferTime = 2000;

var videoPaused;
var stayPaused;
var backRestart;

var loopTimer;
var progressTimer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function addVideoToList(name, time) {
  name = decodeURIComponent(name);
  $("#videosTable").append("
" + name + "<button class=\"tableButton removeButton\" onclick=\"actionRemoveVideo(this);\"></button>" +
  "<button class=\"tableButton playButton\" onclick=\"actionPlayVideo(this);\"></button>	" + time + "
");
}

function resetTimer(which) {
  if (which != 0) {
      which.pause();
    }
    which = 0;
}

var ActionTimers = function() {
  this.pause = function() {
    loopTimer.pause();
    progressTimer.pause();
  }
  this.resume = function() {
    loopTimer.resume();
    progressTimer.resume();
  }
  this.clear = function() {
    resetTimer(loopTimer);
    resetTimer(progressTimer);
    $("#progress").css("width", "0%");
    $("#currentTime").text("0:00");
  }
}
var actionTimers = new ActionTimers();

function videoProgress() {
  $("#videoTime").text(msConversion(videos[videoIteration]["time"] * 1000));
  var iteration = 0;
  var percentChange = 1 / videos[videoIteration]["time"] * 100;
  var currentPercent = 0;
  var interval = bufferTime;
  function progressLoop() {
    iteration++;
    currentPercent = currentPercent + percentChange;
    progressTimer = new Timer(function() {
      $("#progress").css("width", currentPercent + "%");
      $("#currentTime").text(msConversion(iteration * 1000));
      progressLoop();
    }, interval);
    interval = 1000;
  }
  progressLoop();
}

function playVideo() {
  highlight(videoIteration);
  document.title = "Streamly - " + decodeURIComponent(videos[videoIteration]["name"]);
  var embedUrl = videos[videoIteration]["url"];

  var autoplay = "";
  if (!stayPaused) {
    autoplay = "?autoplay=1";
  }

  if (embedUrl.search(/file:\/\//i) == -1) {
    embedUrl = "https://www.youtube.com/embed/" + videos[videoIteration]["url"] + autoplay;
  }
  $("#youtube").attr("src", embedUrl);

  backRestart = false;
  window.setTimeout(function() {
    backRestart = true;
  }, 3000);

  videoProgress();
}

function loopVideo() {
  videoIteration++;
  playVideo();
  loopTimer = new Timer(function() {
    if (videoIteration < videoCounter) {
      actionTimers.clear();
      loopVideo();
    }
    else {
      actionTimers.clear();
      $("#youtube").attr("src", "");
      document.title = "Streamly";
    }
  }, (videos[videoIteration]["time"] * 1000) + bufferTime);
  if (stayPaused) {
    actionTimers.pause();
  }
}

function pauseVideo() {
  if (!videoPaused) {
    actionTimers.pause();
    videoPaused = true;
    if (videos[0] !== null && videos[0] !== undefined) {
      document.title = "Streamly - " + decodeURIComponent(videos[0]);
    }
  }
  else {
    actionTimers.resume();
    videoPaused = false;
    stayPaused = false;
    document.title = "Streamly - " + decodeURIComponent(videos[videoIteration]["name"]);
  }
  $("#pauseOverlay").css("display", "none");
  setTimeout(function(){
    $("#pauseOverlay").css("display", "block");
    $("#youtube").blur();
  }, 500);
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    actionTimers.clear();

    if (videoPaused) {
      stayPaused = true;
    }
    loopVideo();
  }
}

function backVideo() {
  if (videoPaused) {
    stayPaused = true;
  }
  if (!backRestart) {
    if (videoIteration - 2 > -1) {
      videoIteration = videoIteration - 2;
      actionTimers.clear();
      loopVideo();
    }
  }
  else {
    videoIteration = videoIteration - 1;
    actionTimers.clear();
    loopVideo();
  }
}

function setPlaylist() {
  if (videos.length > 1) {
    var playlist = JSON.stringify(videos);
    playlist = window.btoa(playlist);
    playlist = encodeURIComponent(playlist);
    window.location.hash = playlist;
  }
  else {
    window.location.hash = "";
  }
}

function getPlaylist() {
  if (window.location.hash.substr(1) !== "") {
    var playlist = window.location.hash.substr(1);
    playlist = decodeURIComponent(playlist);
    playlist = window.atob(playlist);
    playlist = JSON.parse(playlist);
    videos = playlist;

    if (videos[0] != undefined) {
      $("#playlistNameBox").val(decodeURIComponent(videos[0]));
    }

    for (i = 1; i < videos.length; i++) {
      videoCounter = i;
      var printTime = msConversion(videos[videoCounter]["time"] * 1000);
      addVideoToList(videos[videoCounter]["name"], printTime);
    }
    loopVideo();
  }
}

function getVideoData() {
  $.ajax({
    url: videoUrl,
    type: 'GET',
    success: function(res) {
      var data = $(res.responseText);
      try {
        videoName = data.find("span#eow-title");
        videoName = videoName[0].textContent;
        videoName = $("
").html(videoName).text();
        videoName = videoName.trim();
      } catch(err) {
        videoName = prompt("Please enter the name of the video", "");
      }
      videoName = encodeURIComponent(videoName).replace(/%20/g, " ");
      try {
        videoTime = null;
        for (iteration in data) {
          var str = data[iteration].innerHTML;
          if (videoTime == null && typeof str != "undefined") {
            videoTime = str.match(/,"length_seconds":"\d+",/g);
          }
        }
        videoTime = videoTime[0];
        videoTime = videoTime.replace(/,"length_seconds":"/g, "").replace(/",/g, "");
        videoTime = +videoTime * 1000;
      } catch(err) {
        videoTime = prompt("Please enter the length of the video", "3:00");
        videoTime = videoTime.split(":");
        videoTime = (+videoTime[0]) * 60 + (+videoTime[1]);
        videoTime = videoTime * 1000;
      }
    },
    complete: function(jqXHR, textStatus) {
      $("#inputBox").val("").attr("placeholder", placeholder);
      addVideo();
    },
    error: function(jqXHR, textStatus, errorThrown) {
      videoName = prompt("Please enter the name of the video", "");

      videoTime = prompt("Please enter the length of the video", "3:00");
      videoTime = videoTime.split(":");
      videoTime = (+videoTime[0]) * 60 + (+videoTime[1]);
      videoTime = videoTime * 1000;
    }
  });
}

function addVideo() {
  videoCounter++;
  var video = {};
  video["name"] = videoName;
  video["time"] = videoTime / 1000;
  video["url"] = videoUrl.replace(/^htt(p|ps):\/\/www\.youtube\.com\/watch\?v=/i, "");
  videos[videoCounter] = video;

  var printTime = msConversion(videoTime);

  addVideoToList(videoName, printTime);

  setPlaylist();

  if (videoCounter == 1 || loopTimer == 0) {
    loopVideo();
  }
}

function actionPlayVideo(element) {
  var index = $(".playButton").index(element);
  videoIteration = index;
  actionTimers.clear();
  loopVideo();
}

function actionRemoveVideo(element) {
  var index = $(".removeButton").index(element) + 1;
  if (index == videoIteration) {
    if (videoIteration + 1 <= videoCounter) {
      forwardVideo();
      videoIteration--;
    }
    else {
      actionTimers.clear();
      $("#youtube").attr("src", "");
      document.title = "Streamly";
      videoIteration--;
    }
  }
  else if (index < videoIteration) {
    videoIteration--;
  }
  videoCounter--;
  videos.splice(index, 1);
  $("tr:nth-child(" + index + ")").remove();
  setPlaylist();
}

function urlValidate(url) {
  var isValidYouTube = /^htt(p|ps):\/\/www\.youtube\.com\/watch\?v=.+$/i;
  var isValidFile = /^file:\/\/.+$/i;

  url = url.trim();
  url = url.replace(/&list=.+/g, "");

  if (url.search(isValidYouTube) > -1 || url.search(isValidFile) > -1) {
    return url;
  }
  else {
    return false;
  }
}

function input(type) {
  var inputBox = $("#inputBox").val();
  var playlistNameBox = $("#playlistNameBox").val();
  switch (type) {
    case 0:
      if (inputBox != "") {
        window.open("https://www.youtube.com/results?search_query=" + inputBox.replace(/ /g, "+"));
        $("#inputBox").val("").attr("placeholder", placeholder);
      }
      break;
    case 1:
      if (inputBox != "") {
        inputBox = urlValidate(inputBox);
        if (inputBox) {
          videoUrl = inputBox;
          $("#inputBox").val("").attr("placeholder", "Loading video data from YouTube...");
          getVideoData();
        }
        else {
          alert("That video's URL seems broken\n\nTry copying it again, or drag and drop the video directly");
        }
      }
      break;
    case 2:
      if (playlistNameBox != "") {
        videos[0] = encodeURIComponent(playlistNameBox).replace(/%20/g, " ");
        setPlaylist();
      }
      else {
        videos[0] = undefined;
      }
      break;
  }
}

document.addEventListener("drop", function(event) {
  event.preventDefault();
  var data = event.dataTransfer.getData("URL");

  $("#inputBox").val(data);
  input(1);
});

document.addEventListener("dragover", function(event) {
  event.preventDefault();
});
<|endoftext|>


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

"use strict";

// This tool supports CSV as defined in RFC 4180 (plus some extensions)

var program = require('commander');
var fs = require('fs');
var os = require('os');

var util = {
  // Output is truncated to length of shortest array
  createObj: function(keys, values) {
    var obj = {};
    for (var i = 0; i < keys.length && i < values.length; i++) {
      obj[keys[i]] = values[i];
    }
    return obj;
  },
  isNumeric: function(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
  }
};

program
  .arguments('<file>')
  .option('-t, --tab', 'Switches the separator from comma to tab')
  .option('-d, --delimiter <text delimiter>', 'Sets the symbol used to delimit text [default "]')
  .option('-h, --header', 'CSV file includes a header')
  .action(function(file) {

    var csv2json = {
      i: 0,
      csv: '',
      json: [],
      header: [],
      hasHeader: false,
      curVal: '',
      curVals: [],
      withinDelimiter: false,
      separator: program.tab ? '\t' : ',',
      delimiter: program.delimiter || '"',
      eol: os.EOL,
      setCSV: function(csv) {
        this.csv = csv;
        return this;
      },
      munch: function(n) {
        var n = n || 1;
        this.i += n;
      },
      peek: function(n) {
        var n = n || 1;
        return this.csv[this.i + n];
      },
      wind: function() {
        while (this.csv[this.i] == ' ') {
          this.munch();
        }
      },
      toJSON: function() {
        while (this.i < this.csv.length) {
          var c = this.csv[this.i];

          if (typeof c == 'undefined') {  // end of string
            break;
          }
          else if (this.withinDelimiter) {
            switch (c) {
              case this.delimiter:
                if (this.peek() == this.delimiter) {  // escaped delimiter
                  this.munch(2);
                  this.curVal += this.delimiter;
                }
                else {
                  this.munch();
                  this.wind();
                  this.withinDelimiter = false;
                }
                break;
              case this.separator:
              case this.eol:
              default:
                this.curVal += c;
                this.munch();
            }
          }
          else {
            switch (c) {
              case this.separator:
                if (util.isNumeric(this.curVal)) {
                  this.curVal = parseFloat(this.curVal);
                }
                this.curVals.push(this.curVal);
                this.curVal = '';
                this.munch();
                break;
              case this.delimiter:
                this.curVal = '';  // Discard any white space up to this point
                this.munch();
                this.withinDelimiter = true;
                break;
              case this.eol:
                if (util.isNumeric(this.curVal)) {
                  this.curVal = parseFloat(this.curVal);
                }
                this.curVals.push(this.curVal);
                this.curVal = '';
                if (program.header) {
                  if (this.hasHeader) {
                    var obj = util.createObj(this.header, this.curVals);
                    this.json.push(obj);
                  }
                  else {
                    this.header = this.curVals;
                    this.hasHeader = true;
                  }
                }
                else {
                  this.json.push(this.curVals);
                }
                this.curVals = [];
                this.munch();
                this.wind();
                break;
              default:
                this.curVal += c;
                this.munch();
            }
          }
        }
        return JSON.stringify(this.json);
      }
    };

    fs.readFile(file, 'utf8', function(err, csv) {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      var json = csv2json.setCSV(csv).toJSON();
      process.stdout.write(json);
    });
  })
  .parse(process.argv);
<commit_msg>Gut old parser code<commit_after>#!/usr/bin/env node

"use strict";

// This tool supports CSV as defined in RFC 4180 (plus some extensions)

var program = require('commander');
var fs = require('fs');
var os = require('os');

program
  .arguments('<file>')
  .option('-t, --tab', 'Switches the separator from comma to tab')
  .option('-d, --delimiter <text delimiter>', 'Sets the symbol used to delimit text [default "]')
  .option('-h, --header', 'CSV file includes a header')
  .action(function(file) {

    fs.readFile(file, 'utf8', function(err, csv) {
      if (err) {
        console.error(err);
        process.exit(1);
      }

    });
  })
  .parse(process.argv);
<|endoftext|>


<commit_before>var pull = require('pull-stream')

module.exports = pull.pipeable(function (read, writer, ender) {
  var queue = [], ended

  function enqueue (data) {
    queue.push(data)
  }

  writer = writer || function (data) {
    this.queue(data)
  }

  ender = ender || function () {
    this.queue(null)
  }

  var emitter = {
    emit: function (event, data) {
      if(event == 'data') enqueue(data)
      if(event == 'end')  enqueue(null)
    },
    queue: enqueue
  }

  return function (end, cb) {
    ;(function pull () {
      if(queue.length) {
        var data = queue.shift()
        cb(data === null, data)
      } else (!ended)  {
        read(null, function (end, data) {
          if(data) writer.call(emitter, data)
          if(ended = end)  ender.call(emitter)
          process.nextTick(pull)
        })
      }
    })()
  }
})

<commit_msg>pass end to source<commit_after>var pull = require('pull-stream')

module.exports = pull.pipeable(function (read, writer, ender) {
  var queue = [], ended

  function enqueue (data) {
    queue.push(data)
  }

  writer = writer || function (data) {
    this.queue(data)
  }

  ender = ender || function () {
    this.queue(null)
  }

  var emitter = {
    emit: function (event, data) {
      if(event == 'data') enqueue(data)
      if(event == 'end')  enqueue(null)
    },
    queue: enqueue
  }

  return function (end, cb) {
    ended = ended || end
    ;(function pull () {
      if(queue.length) {
        var data = queue.shift()
        cb(data === null, data)
      } else {
        read(ended, function (end, data) {
          if(data) writer.call(emitter, data)
          if(ended = end)  ender.call(emitter)
          process.nextTick(pull)
        })
      }
    })()
  }
})

<|endoftext|>


<commit_before>var regexLong  = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/gi
var regexShort = /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?(...)?/gi

module.exports = transform

function transform(filename, src, opts, done) {
  src = src.replace(regexLong, function(whole, r, g, b, a) {
    return makeVec(r, g, b, a)
  }).replace(regexShort, function(whole, r, g, b, a, remaining) {
    var str = makeVec(r + r, g + g, b + b, a + a)
    if (remaining === 'ine') return whole
    if (remaining) str += remaining
    return str
  })

  done(null, src)
}

function makeVec(r, g, b, a) {
  r = parseInt(r, 16) / 255
  g = parseInt(g, 16) / 255
  b = parseInt(b, 16) / 255
  a = parseInt(a, 16) / 255

  return isNaN(a)
    ? 'vec3('+[r,g,b].map(makeFloat).join(',')+')'
    : 'vec4('+[r,g,b,a].map(makeFloat).join(',')+')'
}

function makeFloat(n) {
  return String(n).indexOf('.') === -1
    ? n + '.'
    : n
}
<commit_msg>support new glslify sync interface<commit_after>var regexLong  = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/gi
var regexShort = /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?(...)?/gi

module.exports = transform
module.exports.sync = transform

function transform(filename, src, opts, done) {
  src = src.replace(regexLong, function(whole, r, g, b, a) {
    return makeVec(r, g, b, a)
  }).replace(regexShort, function(whole, r, g, b, a, remaining) {
    var str = makeVec(r + r, g + g, b + b, a + a)
    if (remaining === 'ine') return whole
    if (remaining) str += remaining
    return str
  })

  if (typeof done === 'function') done(null, src)
  return src
}

function makeVec(r, g, b, a) {
  r = parseInt(r, 16) / 255
  g = parseInt(g, 16) / 255
  b = parseInt(b, 16) / 255
  a = parseInt(a, 16) / 255

  return isNaN(a)
    ? 'vec3('+[r,g,b].map(makeFloat).join(',')+')'
    : 'vec4('+[r,g,b,a].map(makeFloat).join(',')+')'
}

function makeFloat(n) {
  return String(n).indexOf('.') === -1
    ? n + '.'
    : n
}
<|endoftext|>


<commit_before>var AVALON_NANO_VENDOR_ID = 10737; //0x29f1;
var AVALON_NANO_PRODUCT_ID = 13297; //0x33f1;
var FILTERS = {
	filters: [{
		vendorId: AVALON_NANO_VENDOR_ID,
		productId: AVALON_NANO_PRODUCT_ID
	}]};

var P_DETECT = 0x0a;
var P_REQUIRE = 0x12;
var P_WORK = 0x1e;
var P_ACKDETECT = 0x19;

var CANAAN_HEAD1 = 0x41;
var CANAAN_HEAD2 = 0x56;

var CRC16_TABLE = [
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
	];

var Nano = function(device, connection) {
	this.device = device;
	this.connection = connection;
};

Nano.prototype.init = function() {
};

Nano.prototype.detect = function() {
	var nano = this;
	this._send(this._mm_encode(P_DETECT, 0x01, 0x01, null, [0, 0, 0, 0, 0, 0, 0, 0]));
	this._receive(function(data) {
		if (data.type === P_ACKDETECT && nano._check_version(data.version))
			nano.valid = true;
		console.log(nano);
	});
};

Nano.prototype._check_version = function(version) {
	return version.slice(0, 15) === '3U1410-82418d6+';
};

Nano.prototype._send = function(data) {
	chrome.hid.send(this.connection.connectionId, 0, data, function() {
		if (chrome.runtime.lastError) {
			console.log(chrome.runtime.lastError);
			return;
		}
		console.log("Send");
	});
};

Nano.prototype._receive = function(callback) {
	var nano = this;
	chrome.hid.receive(this.connection.connectionId, function(reportId, data) {
		if (chrome.runtime.lastError) {
			console.log(chrome.runtime.lastError);
			return;
		}
		console.log("Receive:");
		console.log(new Uint8Array(data));
		callback(nano._mm_decode(data));
	});
};

Nano.prototype._crc16 = function(arraybuffer) {
	var data = new Uint8Array(arraybuffer);
	var crc = 0;
	var i = 0;
	var len = data.length;
	while (len-- > 0)
		crc = CRC16_TABLE[((crc >> 8) ^ data[i++]) & 0xff] ^ (crc << 8);
	return crc;
};

Nano.prototype._mm_encode = function(type, idx, cnt, id, data) {
	var buffer = new ArrayBuffer(64);
	var dv = new DataView(buffer);
	dv.setUint8(0, CANAAN_HEAD1);
	dv.setUint8(1, CANAAN_HEAD2);
	dv.setUint8(2, type);
	dv.setUint8(3, idx);
	dv.setUint8(4, cnt);
	for (var i = 0; i < 8; i++)
		dv.setUint32(i * 4 + 5, data[i]);
	var crc = this._crc16(buffer.slice(5, 37));
	dv.setUint8(37, (crc & 0xff00) >> 8);
	dv.setUint8(38, crc & 0x00ff);
	return buffer;
};

Nano.prototype._mm_decode = function(pkg) {
	var dv = new DataView(pkg);
	var head1 = dv.getUint8(0);
	var head2 = dv.getUint8(1);
	if (head1 !== CANAAN_HEAD1 || head2 !== CANAAN_HEAD2) {
		console.log("Wrong head.");
		return false;
	}
	var cmd = dv.getUint8(2);
	var idx = dv.getUint8(3);
	var cnt = dv.getUint8(4);
	var data = pkg.slice(5, 37);
	var crc_l = dv.getUint8(37);
	var crc_h = dv.getUint8(38);
	var crc = this._crc16(data);
	if (crc_l !== ((crc & 0xff00) >> 8) || crc_h !== (crc & 0x00ff)) {
		console.log("Wrong CRC.");
		return false;
	}
	switch (cmd) {
		case P_ACKDETECT:
			var version = '';
			for (c of new Uint8Array(data))
				version += String.fromCharCode(c);
			return {type: P_ACKDETECT, version: version};
		default:
			return data;
	}
};
<commit_msg>Use unsigned right shift when handling CRC<commit_after>var AVALON_NANO_VENDOR_ID = 10737; //0x29f1;
var AVALON_NANO_PRODUCT_ID = 13297; //0x33f1;
var FILTERS = {
	filters: [{
		vendorId: AVALON_NANO_VENDOR_ID,
		productId: AVALON_NANO_PRODUCT_ID
	}]};

var P_DETECT = 0x0a;
var P_REQUIRE = 0x12;
var P_WORK = 0x1e;
var P_ACKDETECT = 0x19;

var CANAAN_HEAD1 = 0x41;
var CANAAN_HEAD2 = 0x56;

var CRC16_TABLE = [
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
];

var Nano = function(device, connection) {
	this.device = device;
	this.connection = connection;
};

Nano.prototype.init = function() {
};

Nano.prototype.detect = function() {
	var nano = this;
	this._send(this._mm_encode(P_DETECT, 0x01, 0x01, null, [0, 0, 0, 0, 0, 0, 0, 0]));
	this._receive(function(data) {
		if (data.type === P_ACKDETECT && nano._check_version(data.version))
			nano.valid = true;
		console.log(nano);
	});
};

Nano.prototype._check_version = function(version) {
	return version.slice(0, 15) === '3U1410-82418d6+';
};

Nano.prototype._send = function(data) {
	chrome.hid.send(this.connection.connectionId, 0, data, function() {
		if (chrome.runtime.lastError) {
			console.log(chrome.runtime.lastError);
			return;
		}
		console.log("Send");
	});
};

Nano.prototype._receive = function(callback) {
	var nano = this;
	chrome.hid.receive(this.connection.connectionId, function(reportId, data) {
		if (chrome.runtime.lastError) {
			console.log(chrome.runtime.lastError);
			return;
		}
		console.log("Receive:");
		console.log(new Uint8Array(data));
		callback(nano._mm_decode(data));
	});
};

Nano.prototype._crc16 = function(arraybuffer) {
	var data = new Uint8Array(arraybuffer);
	var crc = 0;
	var i = 0;
	var len = data.length;
	while (len-- > 0)
		crc = CRC16_TABLE[((crc >>> 8) ^ data[i++]) & 0xff] ^ (crc << 8);
	return crc;
};

Nano.prototype._mm_encode = function(type, idx, cnt, id, data) {
	var buffer = new ArrayBuffer(64);
	var dv = new DataView(buffer);
	dv.setUint8(0, CANAAN_HEAD1);
	dv.setUint8(1, CANAAN_HEAD2);
	dv.setUint8(2, type);
	dv.setUint8(3, idx);
	dv.setUint8(4, cnt);
	for (var i = 0; i < 8; i++)
		dv.setUint32(i * 4 + 5, data[i]);
	var crc = this._crc16(buffer.slice(5, 37));
	dv.setUint8(37, (crc & 0xff00) >>> 8);
	dv.setUint8(38, crc & 0x00ff);
	return buffer;
};

Nano.prototype._mm_decode = function(pkg) {
	var dv = new DataView(pkg);
	var head1 = dv.getUint8(0);
	var head2 = dv.getUint8(1);
	if (head1 !== CANAAN_HEAD1 || head2 !== CANAAN_HEAD2) {
		console.log("Wrong head.");
		return false;
	}
	var cmd = dv.getUint8(2);
	var idx = dv.getUint8(3);
	var cnt = dv.getUint8(4);
	var data = pkg.slice(5, 37);
	var crc_l = dv.getUint8(37);
	var crc_h = dv.getUint8(38);
	var crc = this._crc16(data);
	if (crc_l !== ((crc & 0xff00) >>> 8) || crc_h !== (crc & 0x00ff)) {
		console.log("Wrong CRC.");
		return false;
	}
	switch (cmd) {
		case P_ACKDETECT:
			var version = '';
			for (c of new Uint8Array(data))
				version += String.fromCharCode(c);
			return {type: P_ACKDETECT, version: version};
		default:
			return data;
	}
};
<|endoftext|>


<commit_before>/* global math */
// Variables
var buttons = ['7','8','9','+',
               '4','5','6','-',
               '1','2','3','*',
               '0','.','=','/',
               'sin','cos','^','√',
               'tan','cot','(',')',
               'clr','<-'];

var lastNum = 'new';
var answer;

function renderContent() {
  // Create base elements for the page
  var container = createElement('div', '', {id: 'container'});
  var header = createElement('div', '', {id: 'header'});
  var nav = createElement('div', '', {id: 'nav'});
  var main = createElement('div', '', {id: 'main'});
  var aside = createElement('div', '', {id: 'aside'});
  var footer = createElement('div', '', {id: 'footer'});

  // Append main elements to container
  container.appendChild(header);
  container.appendChild(nav);
  container.appendChild(main);
  container.appendChild(aside);
  container.appendChild(footer);

  // Insert content
  header.appendChild(createElement('h1', 'Calculator', {className: 'title'}));
  main.appendChild(calculator());
  footer.appendChild(themeButton());
  footer.appendChild(about());

  // Add container to page
  document.body.appendChild(container);
  //document.getElementById('cal-box').focus();
}

function createElement(type, textContent, options) {
  var elem = document.createElement(type);
  elem.textContent = textContent;
  if(options){
    for(var option in options){
      elem[option] = options[option];
    }
  }
  return elem;
}

function calculator() {
  var calculatorWrap = createElement('div', '', {id: 'calculator'}); // Add calculator wrapper div
  calculatorWrap.appendChild(createElement('input', '', {className: 'cal-box', id: 'cal-box'})); // Add input box
  buttons.forEach(function(buttonContent){
    var button = createElement('button', buttonContent, {className: 'cal-button', id: buttonContent});
    button.addEventListener('click', handleButton, false);
    calculatorWrap.appendChild(button);
  }); // Add calculator buttons
  return calculatorWrap;
}

function themeButton() {
  var themeWrapper = createElement('div', '');
  var toggle = createElement('button', 'Toggle Theme', {className: 'toggle', id: 'toggle'});
  toggle.addEventListener('click', switchTheme, false);
  themeWrapper.appendChild(toggle);
  return themeWrapper;
}

function switchTheme() {
  theme = document.body.className;
  if(theme == 'theme-light') {
    document.body.className = 'theme-dark';
  } else {
    document.body.className = 'theme-light';
  }
}

function about(){
  var about = createElement('p', 'Created by ');
  about.appendChild(createElement('a', '@keawade', {href: 'https://github.com/keawade'}));
  return about;
}

// Need to rewrite keypress to be more efficient

// If Enter/Return is pressed, click '=' to evaluate
document.addEventListener('keypress', function(key){
  console.log(key.keyCode);
  var keyString = String.fromCharCode(key.charCode);
  if(key.keyCode == 13){
    document.getElementById('=').click();
  } else if (/[0-9]|[-/*+=.^()]/.test(keyString)) {
    document.getElementById(keyString).click();
  } else if (key.keyCode == 8){
    var box = document.getElementById('cal-box')
    if(box === document.activeElement){
      //
    } else {
      if(box.value == ''){
        // Do nothing
      } else {
        document.getElementById('<-').click();
      }
    }
  } // keyCode 46 is Delete
}, false);

function handleButton(event) {
  // If clicked button is a number
  var box = document.getElementById('cal-box');
  if(!(box === document.activeElement)){
    if(event.target.id == '='){
      answer = math.eval(box.value);
      if(!isNaN(answer)){
        box.value = answer;
        lastNum = answer;
      }
    } else if (event.target.id == 'clr'){
      box.value = '';
      lastNum = 'new';
    } else if (event.target.id == '<-') {
      box.value = box.value.substring(0, box.value.length - 1);
      lastNum = box.value.charAt(box.value.length-1);
    } else if(/[0-9]/.test(event.target.id)){
      if(!(/[)]/.test(lastNum))){
        box.value = box.value + event.target.id;
        lastNum = event.target.id;
      }
    } else if(/[-/*+.^()]/.test(event.target.id)){
      box.value = box.value + event.target.id;
      lastNum = event.target.id;
    } else if (/[sin]|[cos]|[tan]|[cot]/.test(event.target.id)){
      if(lastNum == answer){
        box.value = event.target.id + '(';
      } else if(isNaN(lastNum)){
        box.value = box.value + event.target.id + '('
        lastNum = '(';
      }
    }
    this.blur();
  }
}
/*

if(!isNaN(event.target.id)) {
  // If last operation was math.eval then start new string
  if(lastNum == 'new') {
    box.value = '';
  }
  // Append new value
  box.value = box.value + event.target.id;
  lastNum = event.target.id;
// If clicked button is not a number
} else {
  // If clicked button is '='
  if(event.target.id == '=') {
    // Evaluate current string
    answer = math.eval(box.value)
    if(isNaN(answer)){
      //
    } else {
      box.value = answer;
    }
    // Note that the last operation was an eval
    lastNum = 'new';
  // If clicked button is an operation
  } else {
    // If the last button clicked was a number, allow the operator to be appended
    if(!isNaN(lastNum)) {
      box.value = box.value + event.target.id;
      lastNum = event.target.id;
    }
  }
}
// Remove keyboard focus on button
this.blur();
} if(event.target.id == '=') {
// Evaluate current string
answer = math.eval(box.value)
if(isNaN(answer)){
  //
} else {
  box.value = answer;
}
// Note that the last operation was an eval
lastNum = 'new';
*/

renderContent();
<commit_msg>Beautified<commit_after>/* global math */
// Variables
var buttons = ['7', '8', '9', '+',
  '4', '5', '6', '-',
  '1', '2', '3', '*',
  '0', '.', '=', '/',
  'sin', 'cos', '^', '√',
  'tan', 'cot', '(', ')',
  'clr', '<-'
];

var lastNum = 'new';
var answer;

function renderContent() {
  // Create base elements for the page
  var container = createElement('div', '', {
    id: 'container'
  });
  var header = createElement('div', '', {
    id: 'header'
  });
  var nav = createElement('div', '', {
    id: 'nav'
  });
  var main = createElement('div', '', {
    id: 'main'
  });
  var aside = createElement('div', '', {
    id: 'aside'
  });
  var footer = createElement('div', '', {
    id: 'footer'
  });

  // Append main elements to container
  container.appendChild(header);
  container.appendChild(nav);
  container.appendChild(main);
  container.appendChild(aside);
  container.appendChild(footer);

  // Insert content
  header.appendChild(createElement('h1', 'Calculator', {
    className: 'title'
  }));
  main.appendChild(calculator());
  footer.appendChild(themeButton());
  footer.appendChild(about());

  // Add container to page
  document.body.appendChild(container);
  //document.getElementById('cal-box').focus();
}

function createElement(type, textContent, options) {
  var elem = document.createElement(type);
  elem.textContent = textContent;
  if (options) {
    for (var option in options) {
      elem[option] = options[option];
    }
  }
  return elem;
}

function calculator() {
  var calculatorWrap = createElement('div', '', {
    id: 'calculator'
  }); // Add calculator wrapper div
  calculatorWrap.appendChild(createElement('input', '', {
    className: 'cal-box',
    id: 'cal-box'
  })); // Add input box
  buttons.forEach(function(buttonContent) {
    var button = createElement('button', buttonContent, {
      className: 'cal-button',
      id: buttonContent
    });
    button.addEventListener('click', handleButton, false);
    calculatorWrap.appendChild(button);
  }); // Add calculator buttons
  return calculatorWrap;
}

function themeButton() {
  var themeWrapper = createElement('div', '');
  var toggle = createElement('button', 'Toggle Theme', {
    className: 'toggle',
    id: 'toggle'
  });
  toggle.addEventListener('click', switchTheme, false);
  themeWrapper.appendChild(toggle);
  return themeWrapper;
}

function switchTheme() {
  theme = document.body.className;
  if (theme == 'theme-light') {
    document.body.className = 'theme-dark';
  } else {
    document.body.className = 'theme-light';
  }
}

function about() {
  var about = createElement('p', 'Created by ');
  about.appendChild(createElement('a', '@keawade', {
    href: 'https://github.com/keawade'
  }));
  return about;
}

// Need to rewrite keypress to be more efficient

// If Enter/Return is pressed, click '=' to evaluate
document.addEventListener('keypress', function(key) {
  console.log(key.keyCode);
  var keyString = String.fromCharCode(key.charCode);
  if (key.keyCode == 13) {
    document.getElementById('=').click();
  } else if (/[0-9]|[-/*+=.^()]/.test(keyString)) {
    document.getElementById(keyString).click();
  } else if (key.keyCode == 8) {
    var box = document.getElementById('cal-box')
    if (box === document.activeElement) {
      //
    } else {
      if (box.value == '') {
        // Do nothing
      } else {
        document.getElementById('<-').click();
      }
    }
  } // keyCode 46 is Delete
}, false);

function handleButton(event) {
  // If clicked button is a number
  var box = document.getElementById('cal-box');
  if (!(box === document.activeElement)) {
    if (event.target.id == '=') {
      answer = math.eval(box.value);
      if (!isNaN(answer)) {
        box.value = answer;
        lastNum = answer;
      }
    } else if (event.target.id == 'clr') {
      box.value = '';
      lastNum = 'new';
    } else if (event.target.id == '<-') {
      box.value = box.value.substring(0, box.value.length - 1);
      lastNum = box.value.charAt(box.value.length - 1);
    } else if (/[0-9]/.test(event.target.id)) {
      if (!(/[)]/.test(lastNum))) {
        box.value = box.value + event.target.id;
        lastNum = event.target.id;
      }
    } else if (/[-/*+.^()]/.test(event.target.id)) {
      box.value = box.value + event.target.id;
      lastNum = event.target.id;
    } else if (/[sin]|[cos]|[tan]|[cot]/.test(event.target.id)) {
      if (lastNum == answer) {
        box.value = event.target.id + '(';
      } else if (isNaN(lastNum)) {
        box.value = box.value + event.target.id + '('
        lastNum = '(';
      }
    }
    this.blur();
  }
}
/*

if(!isNaN(event.target.id)) {
  // If last operation was math.eval then start new string
  if(lastNum == 'new') {
    box.value = '';
  }
  // Append new value
  box.value = box.value + event.target.id;
  lastNum = event.target.id;
// If clicked button is not a number
} else {
  // If clicked button is '='
  if(event.target.id == '=') {
    // Evaluate current string
    answer = math.eval(box.value)
    if(isNaN(answer)){
      //
    } else {
      box.value = answer;
    }
    // Note that the last operation was an eval
    lastNum = 'new';
  // If clicked button is an operation
  } else {
    // If the last button clicked was a number, allow the operator to be appended
    if(!isNaN(lastNum)) {
      box.value = box.value + event.target.id;
      lastNum = event.target.id;
    }
  }
}
// Remove keyboard focus on button
this.blur();
} if(event.target.id == '=') {
// Evaluate current string
answer = math.eval(box.value)
if(isNaN(answer)){
  //
} else {
  box.value = answer;
}
// Note that the last operation was an eval
lastNum = 'new';
*/

renderContent();
<|endoftext|>


<commit_before>var jsonBody = require('body/json')
var sendPlain = require('send-data/plain')

module.exports = function (accessKey) {
  return function webhook (req, res, next) {
    function makeError (statusCode, message) {
      var error = new Error(message)
      error.statusCode = statusCode || 500
      return error
    }
    function handleError (err) {
      sendPlain(req, res, {
        body: err.toString(),
        statusCode: err.statusCode
      })
    }

    function handlePost (err, body) {
      if (err) return next(err)
      next(null, body)
    }

    function processWebhook (name) {
      var accepted = [
        'ticket.created',
        'ticket.updated',
        'ticket.voided',
        'ticket.unsnoozed',
        'ticket.reassigned'
      ]
      if (~accepted.indexOf(name)) jsonBody(req, res, handlePost)
      else handleError(makeError(400, 'Unknown webhook name: ' + name))
    }

    if (req.url === accessKey) {
      if (req.method === 'POST') {
        if (req.headers['x-webhook-name']) return processWebhook(req.headers['x-webhook-name'])

        handleError(makeError(400, 'Missing header'))
      } else {
        handleError(makeError(405, 'Method not supported: ' + req.method))
      }
    } else {
      next()
    }
  }
}
<commit_msg>Update makeError arguments<commit_after>var jsonBody = require('body/json')
var sendPlain = require('send-data/plain')

module.exports = function (accessKey) {
  return function webhook (req, res, next) {
    function makeError (message, statusCode) {
      var error = new Error(message)
      error.statusCode = statusCode || 500
      return error
    }

    function handleError (err) {
      sendPlain(req, res, {
        body: err.toString(),
        statusCode: err.statusCode
      })
    }

    function handlePost (err, body) {
      if (err) return next(err)
      next(null, body)
    }

    function processWebhook (name) {
      var accepted = [
        'ticket.created',
        'ticket.updated',
        'ticket.voided',
        'ticket.unsnoozed',
        'ticket.reassigned'
      ]
      if (~accepted.indexOf(name)) jsonBody(req, res, handlePost)
      else handleError(makeError('Unknown webhook name: ' + name, 400))
    }

    if (req.url === accessKey) {
      if (req.method === 'POST') {
        if (req.headers['x-webhook-name']) return processWebhook(req.headers['x-webhook-name'])

        handleError(makeError('Missing header', 400))
      } else {
        handleError(makeError('Method not supported: ' + req.method, 405))
      }
    } else {
      next()
    }
  }
}
<|endoftext|>


<commit_before>var Ending = function(game) {
	this.onStasisStart = function(event, channel) {
		console.log('Channel %s is trying to enter after the game has ended', channel.id);
		channel.hangup();
	}
	this.onDtmfReceived = function(event, participant) {
		// Just ignore
		return;
	}

	this.game.end();
}

module.exports = Ending;
<commit_msg>Remove unnecessary 'this'<commit_after>var Ending = function(game) {
	this.onStasisStart = function(event, channel) {
		console.log('Channel %s is trying to enter after the game has ended', channel.id);
		channel.hangup();
	}
	this.onDtmfReceived = function(event, participant) {
		// Just ignore
		return;
	}

	game.end();
}

module.exports = Ending;
<|endoftext|>


<commit_before>/* global math */
// Variables
var buttons = ['7','8','9','+','4','5','6','-','1','2','3','*','0','.','=','/'];
var lastNum = '=';

function prep() {
  // Create base elements for the page
  var container = document.createElement('div');
  var header = document.createElement('div');
  var nav = document.createElement('div');
  var main = document.createElement('div');
  var aside = document.createElement('div');
  var footer = document.createElement('div');

  // Apply IDs to the base elements
  container.id = 'container';
  header.id = 'header';
  nav.id = 'nav';
  main.id = 'main';
  aside.id = 'aside';
  footer.id = 'footer';

  // Append main elements to container
  container.appendChild(header);
  container.appendChild(nav);
  container.appendChild(main);
  container.appendChild(aside);
  container.appendChild(footer);

  // Insert content
  header.appendChild(heading());
  main.appendChild(calculator());
  footer.appendChild(themeButton());
  footer.appendChild(about());

  // Add container to page
  document.body.appendChild(container);
  document.getElementById('cal-box').focus();
}

function heading(headContent) {
  // Add heading to header
  var title = document.createElement('h1');
  title.className = 'title';
  title.textContent = 'Calculon';
  return title;
}

function calculator() {
  // Add calculator wrapper div
  var calculatorWrap = document.createElement('div');
  calculatorWrap.id = 'calculator';

  // Add input box
  var box = document.createElement('input');
  box.className = 'cal-box';
  box.id = 'cal-box';
  calculatorWrap.appendChild(box);

  // Add calculator buttons
  buttons.forEach(function(buttonContent){
    var button = document.createElement('button');
    button.className = 'cal-button';
    button.id = buttonContent;
    button.appendChild(document.createTextNode(buttonContent));
    button.addEventListener('click', handleButton, false);
    calculatorWrap.appendChild(button);
  })
  return calculatorWrap;
}

function about(){
  var about = document.createElement('p');
  var a = document.createElement('a');
  a.href = 'https://github.com/keawade';
  a.textContent = '@keawade';
  about.textContent = 'Created by ';
  about.appendChild(a);
  return about;
}

// If Enter/Return is pressed, click '=' to evaluate
document.addEventListener('keypress', function(key){
  var keyString = String.fromCharCode(key.charCode);
  if(key.keyCode == 13){
    document.getElementById('=').click();
  } else if (/[0-9]|[/*-+=.]/.test(keyString)) {
    document.getElementById(keyString).click();
  } else if (key.keyCode == 8){
    var box = document.getElementById('cal-box')
    if(box === document.activeElement){
      //
    } else {
      box.value = box.value.substring(0, box.value.length - 1);
    }
  }
}, false);

function handleButton(event) {
  var answer;
  // If clicked button is a number
  var box = document.getElementById('cal-box');
  var clickedElem = event.target.id;
  if(box === document.activeElement){
    //
  } else {
    if(!isNaN(clickedElem)) {
      // If last operation was math.eval then start new string
      if(lastNum == 'new') {
        box.value = '';
      }
      // Append new value
      box.value = box.value + clickedElem;
      lastNum = clickedElem;
    // If clicked button is not a number
    } else {
      // If clicked button is '='
      if(clickedElem == '=') {
        // Evaluate current string
        if(box.value.toUpperCase() == 'CALCULON'){
          var p = document.createElement('p');
          p.textContent = 'Funny story. The script called for me to say "Yes", but I gave it a little twist.';
          document.getElementById('footer').appendChild(p);
          box.value = 'Nooooo!';
        } else {
          answer = math.eval(box.value)
          if(isNaN(answer)){
            //
          } else {
            box.value = answer;
          }
        }
        // Note that the last operation was an eval
        lastNum = 'new';
      // If clicked button is an operation
      } else {
        // If the last button clicked was a number, allow the operator to be appended
        if(!isNaN(lastNum)) {
          box.value = box.value + clickedElem;
          lastNum = clickedElem;
        }
      }
    }
    // Remove keyboard focus on button
    this.blur();
  } if(clickedElem == '=') {
    // Evaluate current string
    answer = math.eval(box.value)
    if(isNaN(answer)){
      //
    } else {
      box.value = answer;
    }
    // Note that the last operation was an eval
    lastNum = 'new';
  }
}

function themeButton() {
  var themeWrapper = document.createElement('div');
  themeWrapper.id = 'theme-changer';

  var toggle = document.createElement('button');
  toggle.id = 'toggle';
  toggle.className = 'toggle';
  toggle.appendChild(document.createTextNode('Toggle Theme'));
  toggle.addEventListener('click', switchTheme, false);
  themeWrapper.appendChild(toggle);
  return themeWrapper;
}

function switchTheme() {
  theme = document.body.className;
  if(theme == 'theme-light') {
    document.body.className = 'theme-dark';
  } else {
    document.body.className = 'theme-light';
  }
}

prep();
<commit_msg>Turned off focus to help mobile<commit_after>/* global math */
// Variables
var buttons = ['7','8','9','+','4','5','6','-','1','2','3','*','0','.','=','/'];
var lastNum = '=';

function prep() {
  // Create base elements for the page
  var container = document.createElement('div');
  var header = document.createElement('div');
  var nav = document.createElement('div');
  var main = document.createElement('div');
  var aside = document.createElement('div');
  var footer = document.createElement('div');

  // Apply IDs to the base elements
  container.id = 'container';
  header.id = 'header';
  nav.id = 'nav';
  main.id = 'main';
  aside.id = 'aside';
  footer.id = 'footer';

  // Append main elements to container
  container.appendChild(header);
  container.appendChild(nav);
  container.appendChild(main);
  container.appendChild(aside);
  container.appendChild(footer);

  // Insert content
  header.appendChild(heading());
  main.appendChild(calculator());
  footer.appendChild(themeButton());
  footer.appendChild(about());

  // Add container to page
  document.body.appendChild(container);
  //document.getElementById('cal-box').focus();
}

function heading(headContent) {
  // Add heading to header
  var title = document.createElement('h1');
  title.className = 'title';
  title.textContent = 'Calculon';
  return title;
}

function calculator() {
  // Add calculator wrapper div
  var calculatorWrap = document.createElement('div');
  calculatorWrap.id = 'calculator';

  // Add input box
  var box = document.createElement('input');
  box.className = 'cal-box';
  box.id = 'cal-box';
  calculatorWrap.appendChild(box);

  // Add calculator buttons
  buttons.forEach(function(buttonContent){
    var button = document.createElement('button');
    button.className = 'cal-button';
    button.id = buttonContent;
    button.appendChild(document.createTextNode(buttonContent));
    button.addEventListener('click', handleButton, false);
    calculatorWrap.appendChild(button);
  })
  return calculatorWrap;
}

function about(){
  var about = document.createElement('p');
  var a = document.createElement('a');
  a.href = 'https://github.com/keawade';
  a.textContent = '@keawade';
  about.textContent = 'Created by ';
  about.appendChild(a);
  return about;
}

// If Enter/Return is pressed, click '=' to evaluate
document.addEventListener('keypress', function(key){
  var keyString = String.fromCharCode(key.charCode);
  if(key.keyCode == 13){
    document.getElementById('=').click();
  } else if (/[0-9]|[/*-+=.]/.test(keyString)) {
    document.getElementById(keyString).click();
  } else if (key.keyCode == 8){
    var box = document.getElementById('cal-box')
    if(box === document.activeElement){
      //
    } else {
      box.value = box.value.substring(0, box.value.length - 1);
    }
  }
}, false);

function handleButton(event) {
  var answer;
  // If clicked button is a number
  var box = document.getElementById('cal-box');
  var clickedElem = event.target.id;
  if(box === document.activeElement){
    //
  } else {
    if(!isNaN(clickedElem)) {
      // If last operation was math.eval then start new string
      if(lastNum == 'new') {
        box.value = '';
      }
      // Append new value
      box.value = box.value + clickedElem;
      lastNum = clickedElem;
    // If clicked button is not a number
    } else {
      // If clicked button is '='
      if(clickedElem == '=') {
        // Evaluate current string
        if(box.value.toUpperCase() == 'CALCULON'){
          var p = document.createElement('p');
          p.textContent = 'Funny story. The script called for me to say "Yes", but I gave it a little twist.';
          document.getElementById('footer').appendChild(p);
          box.value = 'Nooooo!';
        } else {
          answer = math.eval(box.value)
          if(isNaN(answer)){
            //
          } else {
            box.value = answer;
          }
        }
        // Note that the last operation was an eval
        lastNum = 'new';
      // If clicked button is an operation
      } else {
        // If the last button clicked was a number, allow the operator to be appended
        if(!isNaN(lastNum)) {
          box.value = box.value + clickedElem;
          lastNum = clickedElem;
        }
      }
    }
    // Remove keyboard focus on button
    this.blur();
  } if(clickedElem == '=') {
    // Evaluate current string
    answer = math.eval(box.value)
    if(isNaN(answer)){
      //
    } else {
      box.value = answer;
    }
    // Note that the last operation was an eval
    lastNum = 'new';
  }
}

function themeButton() {
  var themeWrapper = document.createElement('div');
  themeWrapper.id = 'theme-changer';

  var toggle = document.createElement('button');
  toggle.id = 'toggle';
  toggle.className = 'toggle';
  toggle.appendChild(document.createTextNode('Toggle Theme'));
  toggle.addEventListener('click', switchTheme, false);
  themeWrapper.appendChild(toggle);
  return themeWrapper;
}

function switchTheme() {
  theme = document.body.className;
  if(theme == 'theme-light') {
    document.body.className = 'theme-dark';
  } else {
    document.body.className = 'theme-light';
  }
}

prep();
<|endoftext|>