<commit_before>'use strict';

import superagent from 'superagent';
import qs from 'qs';
import BPromise from 'bluebird';

import pick from 'lodash/pick';
import isFunction from 'lodash/isFunction';
import isEmpty from 'lodash/isEmpty';

BPromise.config({
  warnings: true,
  longStackTraces: true,
  cancellation: true
});

const API = {

  config(options = {}) {
    Object.assign(this, pick(options, [
      'onRequestError',
      'onRequestCompleted',
      'requestData',
      'requestHeaders',
      'urlRoot',
      'superagent'
    ]))
  },

	request(options = {}) {

		let { method, data, endpoint, onSuccess, onError, fileData } = options;
    let requestData, requestHeaders, doRequest;
    const request = this.superagent || superagent;

		if (!method) { method = 'get' }
		if (!data) { data = {} }
		if (!endpoint) {
			throw new Error('Please provide an endpoint for an API call');
		}

		if (!onSuccess) {
			onSuccess = (options) => { }
		}

    if (!onError) {
      onError = (options) => { }
    }

    // set headers
		doRequest = request[method](this.urlRoot+endpoint)

    if (isEmpty(fileData)) {
      doRequest.accept('json');
    }

    if (isFunction(this.requestHeaders)) {
      requestHeaders = this.requestHeaders();
    } else {
      requestHeaders = this.requestHeaders;
    }

    Object.keys(requestHeaders).forEach(header => {
      doRequest = doRequest.set(header, requestHeaders[header]);
    });

    // for now do not send any data except files if they are passed
    if (!isEmpty(fileData)) {
      // merge default requestData with object passed with this request
      if (isFunction(this.requestData)) {
  		  requestData = this.requestData();
      } else {
        requestData = this.requestData;
      }

      Object.assign(data, requestData);
    }

    // just send as POST or prepare data for GET request
    if (method === 'post' || method === 'put') {
      if (!isEmpty(fileData)) {
        let formData = new FormData();
        formData.append(fileData.attibuteName, fileData.file);
        doRequest.send(formData);
      } else {
        doRequest.send(data);
      }
    } else if (method === 'get' || method == 'del') {
      doRequest.query(
        qs.stringify(
          data,
          { arrayFormat: 'brackets' }
        )
      );
    }

    return new BPromise( (resolve, reject) => {

      // send request and act upon result
    	doRequest.end( (err, response) => {
        if (this.onRequestCompleted) this.onRequestCompleted(response);

	      if (!response.ok) {
	      	let errors = response.body ? response.body.errors : 'Something bad happened';
      		let statusCode = response.status;

      		if (this.onRequestError) this.onRequestError(response);

          onError(response);
	      } else {
	      	onSuccess(response);
        }

        /*
          we resolve promise even if request
          was not successfull to reduce boilerplat
          + because we  typically don't want ui do
          have some specific behaviour in this case
         */

        resolve(response);

      });

    });

	}
}

export default API;
<commit_msg>checking for superagent in options.<commit_after>'use strict';

import superagent from 'superagent';
import qs from 'qs';
import BPromise from 'bluebird';

import pick from 'lodash/pick';
import isFunction from 'lodash/isFunction';
import isEmpty from 'lodash/isEmpty';

BPromise.config({
  warnings: true,
  longStackTraces: true,
  cancellation: true
});

const API = {

  config(options = {}) {
    Object.assign(this, pick(options, [
      'onRequestError',
      'onRequestCompleted',
      'requestData',
      'requestHeaders',
      'urlRoot',
      'superagent'
    ]))
  },

	request(options = {}) {

		let { method, data, endpoint, onSuccess, onError, fileData } = options;
    let requestData, requestHeaders, doRequest;
    const request = options.superagent || this.superagent || superagent;

		if (!method) { method = 'get' }
		if (!data) { data = {} }
		if (!endpoint) {
			throw new Error('Please provide an endpoint for an API call');
		}

		if (!onSuccess) {
			onSuccess = (options) => { }
		}

    if (!onError) {
      onError = (options) => { }
    }

    // set headers
		doRequest = request[method](this.urlRoot+endpoint)

    if (isEmpty(fileData)) {
      doRequest.accept('json');
    }

    if (isFunction(this.requestHeaders)) {
      requestHeaders = this.requestHeaders();
    } else {
      requestHeaders = this.requestHeaders;
    }

    Object.keys(requestHeaders).forEach(header => {
      doRequest = doRequest.set(header, requestHeaders[header]);
    });

    // for now do not send any data except files if they are passed
    if (!isEmpty(fileData)) {
      // merge default requestData with object passed with this request
      if (isFunction(this.requestData)) {
  		  requestData = this.requestData();
      } else {
        requestData = this.requestData;
      }

      Object.assign(data, requestData);
    }

    // just send as POST or prepare data for GET request
    if (method === 'post' || method === 'put') {
      if (!isEmpty(fileData)) {
        let formData = new FormData();
        formData.append(fileData.attibuteName, fileData.file);
        doRequest.send(formData);
      } else {
        doRequest.send(data);
      }
    } else if (method === 'get' || method == 'del') {
      doRequest.query(
        qs.stringify(
          data,
          { arrayFormat: 'brackets' }
        )
      );
    }

    return new BPromise( (resolve, reject) => {

      // send request and act upon result
    	doRequest.end( (err, response) => {
        if (this.onRequestCompleted) this.onRequestCompleted(response);

	      if (!response.ok) {
	      	let errors = response.body ? response.body.errors : 'Something bad happened';
      		let statusCode = response.status;

      		if (this.onRequestError) this.onRequestError(response);

          onError(response);
	      } else {
	      	onSuccess(response);
        }

        /*
          we resolve promise even if request
          was not successfull to reduce boilerplat
          + because we  typically don't want ui do
          have some specific behaviour in this case
         */

        resolve(response);

      });

    });

	}
}

export default API;
<|endoftext|>


<commit_before>'use strict';

var dgram       = require('dgram')
  , Q           = require('q')
  , _           = require('underscore')
  , events      = require('events')
  , qtmrt       = require('./qtmrt')
  , writeUInt32 = require('./helpers').writeUInt32
  , mixin       = require('./helpers').mixin
  , Mangler     = require('./mangler')
  , Packet      = require('./packet')
  , Command     = require('./command')
  , Logger      = require('./logger')
;

_.str = require('underscore.string');

class Api {
	constructor(options) {
		this.net               = require('net');
		this.client            = null;
		this.response          = null;
		this.deferredResponse  = null;
		this.promiseQueue      = [];
		this.issuedCommands    = [];
		this.logger            = new Logger();
		this.mangler           = new Mangler();
		this.isStreaming       = false;
		this.currentPacketSize = false;

		events.EventEmitter.call(this);

		if (arguments.length < 1)
			options = {};

		this.options = _.defaults(options, {
			debug: false,
			frequency: 100,
			discoverPort: 22226,
			discoverTimeout: 2000,
		});

		this.frequency(this.options.frequency);
	}

	bootstrap() {
		// Disable Nagle's algorithm.
		this.client.setNoDelay(true);

		this.client.on('data', function(chunk) {
			this.mangler.read(chunk, { fun: this.receivePacket, thisArg: this });
		}.bind(this));

		this.client.on('end', function() {
			this.logger.log('Disconnected', 'white', 'bold');
			this.emit('disconnect');
		}.bind(this));
	}

	setupUdp(port) {
		var s = dgram.createSocket('udp4');

		s.on('message', function(chunk) {
			this.mangler.read(chunk, { fun: this.receivePacket, thisArg: this });
		}.bind(this));

		s.bind(port, this.host, function() { });
	}

	log(msg, color, style) {
		this.logger.logPacket(msg, color, style);
	}

	receivePacket(data) {
		var packet  = Packet.create(data)
		  , command = this.issuedCommands.pop()
		;

		if (qtmrt.COMMAND === packet.type)
			packet.type = qtmrt.COMMAND_RESPONSE;

		if (this.options.debug)
			this.logger.logPacket(packet);

		if (qtmrt.EVENT === packet.type) {
			if (command.data === 'GetState')
				this.promiseQueue.pop().resolve({ id: packet.eventId, name: packet.eventName });

			this.emit('event', packet.toJson());
		}
		else if (qtmrt.XML === packet.type) {
			this.promiseQueue.pop().resolve(packet.toJson());
		}
		else if (qtmrt.C3D_FILE === packet.type) {
			// Implement.
		}
		else if (qtmrt.COMMAND_RESPONSE === packet.type) {
			if (_.str.startsWith(command.data, 'ByteOrder'))
				this.promiseQueue.pop().resolve(/little endian/.test(packet.data) ? 'little endian' : 'big endian');

			else if (_.str.startsWith(command.data, 'QTMVersion')) {
				var human   = 'QTM ' + packet.data.replace('QTM Version is ', '').slice(0, -1)
				  , version = human.match(/QTM (\d+)\.(\d+)(?: (?:Beta)|(?:Alpha))? \(build (\d+)\)/)
				;
				this.promiseQueue.pop().resolve({ major: version[1], minor: version[2], build: version[3], human: human });
			}

			else
				this.promiseQueue.pop().resolve(packet);
		}
		else if (command && _.str.startsWith(command.data, 'GetCurrentFrame')) {
			this.promiseQueue.pop().resolve(packet.toJson());
		}
		else if (qtmrt.DATA !== packet.type) {
			if (qtmrt.NO_MORE_DATA === packet.type) {
				this.emit('end');
			}
			else
				this.promiseQueue.pop().resolve(packet);
		}
		else if (qtmrt.DATA === packet.type) {
			this.emit('frame', packet.toJson());
		}

	}

	connect(port, host, major, minor) {
		if (this.client !== null)
			return Q.reject();

		if (arguments.length < 1)
			port = 22223;

		if (arguments.length < 2)
			host = 'localhost';

		if (arguments.length < 3) {
			major = 1;
			minor = 13;
		}
		else {
			if (!_.isNumber(major))
				throw new TypeError('Major version must be a number');

			if (!_.isNumber(major))
				throw new TypeError('Minor version must be a number');
		}

		this.host = host;
		this.port = port;

		var deferredCommand  = Q.defer();
		var responsePromise = this.promiseResponse();

		if (this.options.debug)
			this.logger.log('Connecting to ' + host + ':' + port, 'white', 'bold');

		this.client = this.net.connect(port, host, function() { });
		this.issuedCommands.unshift('Connect');
		this.bootstrap();

		responsePromise
			.then((packet) => {
				if (packet.data.toString() === 'QTM RT Interface connected\0') {
					this.send(Command.version(major, minor))
						.then(function(data) {
							deferredCommand.resolve();
						})
						.catch(function(err) {
							deferredCommand.reject(new Error(err));
						})
					;
				}
				else {
					deferredCommand.reject(new Error(packet.data.toString()));
				}
			})
			.catch(function(err) {
				console.log(err);
			});

		return deferredCommand.promise;
	}

	qtmVersion() { return this.send(Command.qtmVersion()); }
	byteOrder() { return this.send(Command.byteOrder()); }
	getState() { return this.send(Command.getState()); }
	getParameters() { return this.send(Command.getParameters.apply(Command, arguments)); }
	setParameters() { return this.send(Command.setParameters.apply(Command, arguments)); }
	getCurrentFrame() { return this.send(Command.getCurrentFrame.apply(Command, arguments)); }
	releaseControl() { return this.send(Command.releaseControl()); }
	newMeasurement() { return this.send(Command.newMeasurement()); }
	close() { return this.send(Command.close()); }
	start() { return this.send(Command.start()); }
	stop() { return this.send(Command.stop()); }
	trig() { return this.send(Command.trig()); }

	// XXX: Not tested with C3D file reply.
	getCaptureC3D() { return this.send(Command.getCaptureC3D()); }
	// XXX: Not tested with QTM file reply.
	getCaptureQtm() { return this.send(Command.getCaptureQtm()); }

	streamFrames(options) {
		if (this.isStreaming)
			return Q.reject('Could not start streaming, already streaming');

		this.isStreaming = true;

		if (_.isUndefined(options.frequency))
			options.frequency = this.options.frequency;

		if (!_.isUndefined(options.udpPort) && (_.isUndefined(options.udpAddress)
				||  options.updAddress === 'localhost' ||  options.udpAddress === '127.0.0.1'))
			setupUdp.call(this, options.udpPort);

		return this.send(Command.streamFrames.apply(Command, [options]));
	}

	stopStreaming() {
		if (!this.isStreaming) {
			this.logger.log('Cannot stop streaming, not currently streaming', 'red');
			return;
		}

		this.isStreaming = false;
		this.emit('end');

		return this.send(Command.stopStreaming());
	}

	takeControl(pass) {
		if (!_.isUndefined(pass) && !_.isString(pass))
			throw new TypeError('Password must be a string');

		return this.send(Command.takeControl(pass));
	}

	load(filename) {
		if (arguments.length < 1)
			throw new TypeError('No filename specified');

		if (!_.isString(filename))
			throw new TypeError('Filename must be a string');

		return this.send(Command.load(filename));
	}

	save(filename, overwrite) {
		if (arguments.length < 1)
			throw new TypeError('No filename specified');

		if (!_.isString(filename))
			throw new TypeError('Filename must be a string');

		if (arguments.length > 1)
			overwrite = 'overwrite';

		return this.send(Command.save(filename, overwrite));
	}

	loadProject(projectPath) {
		if (arguments.length < 1)
			throw new TypeError('No project path specified');

		if (!_.isString(projectPath))
			throw new TypeError('Project path must be a string');

		return this.send(Command.loadProject(projectPath));
	}

	setQtmEvent(label) {
		if (arguments.length < 1)
			throw new TypeError('No label specified');

		if (!_.isString(label))
			throw new TypeError('Label must be a string');

		return this.send(Command.setQtmEvent(label));
	}

	send(command) {
		if (this.client === null)
			new Error('Not connected to QTM. Connect and try again.');

		var promise = Q.resolve();

		// Don't expect a reply on the StreamFrames command.
		if (!_.str.startsWith(command.data, 'StreamFrames'))
			promise = this.promiseResponse();

		this.issuedCommands.unshift(command);

		command.isResponse = false;

		this.client.write(command.buffer, 'utf8', function(data) {
			if (this.options.debug)
				this.logger.logPacket(command);
		}.bind(this));

		return promise;
	}

	promiseResponse() {
		var deferredResponse = Q.defer();

		this.promiseQueue.unshift(deferredResponse);

		return deferredResponse.promise;
	}

	disconnect() {
		if (this.client === null)
			new Error('Not connected to QTM. Connect and try again.');

		this.client.end();
	}

	discover(port) {
		if (_.isUndefined(port))
			port = this.options.discoverPort;

		var server = dgram.createSocket('udp4')
		  , receivePort = port + 1
		  , discoveredServers = []
		  , deferred = Q.defer()
		;

		server.on('error', function(err) {
			console.log('Server error:\n' + err.stack);
			server.close();
		});

		server.on('message', (msg, rinfo) => {
			// Set type to discover type.
			writeUInt32(msg, 7, 4);

			var discoverPacket = Packet.create(msg, rinfo.address, rinfo.port);

			if (this.options.debug)
				this.logger.logPacket(discoverPacket);

			discoveredServers.push({
				serverInfo: discoverPacket.serverInfo,
				serverBasePort: discoverPacket.serverBasePort,
				srcAddress: discoverPacket.srcAddress,
				srcPort: discoverPacket.srcPort,
			});
		});

		server.bind(receivePort);

		// Create discover packet.
		var buf = new Buffer(10);
		buf.writeUInt32LE(10, 0);
		buf.writeUInt32LE(7, 4);
		buf.writeUInt16BE(receivePort, 8);

		var client = dgram.createSocket('udp4')
			// , address = 'ff02::1'
		  , address = '255.255.255.255'
		;

		client.bind();
		client.on('listening', () => {
			client.setBroadcast(true);
			client.send(buf, 0, buf.length, port, address, function(err, bytes) {
				client.close();
			});

			if (this.options.debug)
				this.logger.logPacket(Packet.create(buf));

			setTimeout(function() {
				server.close();
				server.unref();
				deferred.resolve(discoveredServers);
			}, this.options.discoverTimeout);

		}.bind(this));

		return deferred.promise;
	}

	frequency(freq) {
		if (isNaN(freq) && freq !== 'AllFrames')
			throw new TypeError('Frequency must be a number or \'AllFrames\'');

		this.options.frequency = freq;
	}

	debug(val) {
		this.options.debug = val ? true : false;
	}
}

mixin(Api.prototype, events.EventEmitter.prototype);

module.exports = Api;<commit_msg>Don't pollute scope.<commit_after>'use strict';

(function() {
	var dgram       = require('dgram')
	  , Q           = require('q')
	  , _           = require('underscore')
	  , events      = require('events')
	  , qtmrt       = require('./qtmrt')
	  , writeUInt32 = require('./helpers').writeUInt32
	  , mixin       = require('./helpers').mixin
	  , Mangler     = require('./mangler')
	  , Packet      = require('./packet')
	  , Command     = require('./command')
	  , Logger      = require('./logger')
	;

	_.str = require('underscore.string');

	class Api {
		constructor(options) {
			this.net               = require('net');
			this.client            = null;
			this.response          = null;
			this.deferredResponse  = null;
			this.promiseQueue      = [];
			this.issuedCommands    = [];
			this.logger            = new Logger();
			this.mangler           = new Mangler();
			this.isStreaming       = false;
			this.currentPacketSize = false;

			events.EventEmitter.call(this);

			if (arguments.length < 1)
				options = {};

			this.options = _.defaults(options, {
				debug: false,
				frequency: 100,
				discoverPort: 22226,
				discoverTimeout: 2000,
			});

			this.frequency(this.options.frequency);
		}

		bootstrap() {
			// Disable Nagle's algorithm.
			this.client.setNoDelay(true);

			this.client.on('data', function(chunk) {
				this.mangler.read(chunk, { fun: this.receivePacket, thisArg: this });
			}.bind(this));

			this.client.on('end', function() {
				this.logger.log('Disconnected', 'white', 'bold');
				this.emit('disconnect');
			}.bind(this));
		}

		setupUdp(port) {
			var s = dgram.createSocket('udp4');

			s.on('message', function(chunk) {
				this.mangler.read(chunk, { fun: this.receivePacket, thisArg: this });
			}.bind(this));

			s.bind(port, this.host, function() { });
		}

		log(msg, color, style) {
			this.logger.logPacket(msg, color, style);
		}

		receivePacket(data) {
			var packet  = Packet.create(data)
			  , command = this.issuedCommands.pop()
			;

			if (qtmrt.COMMAND === packet.type)
				packet.type = qtmrt.COMMAND_RESPONSE;

			if (this.options.debug)
				this.logger.logPacket(packet);

			if (qtmrt.EVENT === packet.type) {
				if (command.data === 'GetState')
					this.promiseQueue.pop().resolve({ id: packet.eventId, name: packet.eventName });

				this.emit('event', packet.toJson());
			}
			else if (qtmrt.XML === packet.type) {
				this.promiseQueue.pop().resolve(packet.toJson());
			}
			else if (qtmrt.C3D_FILE === packet.type) {
				// Implement.
			}
			else if (qtmrt.COMMAND_RESPONSE === packet.type) {
				if (_.str.startsWith(command.data, 'ByteOrder'))
					this.promiseQueue.pop().resolve(/little endian/.test(packet.data) ? 'little endian' : 'big endian');

				else if (_.str.startsWith(command.data, 'QTMVersion')) {
					var human   = 'QTM ' + packet.data.replace('QTM Version is ', '').slice(0, -1)
					  , version = human.match(/QTM (\d+)\.(\d+)(?: (?:Beta)|(?:Alpha))? \(build (\d+)\)/)
					;
					this.promiseQueue.pop().resolve({ major: version[1], minor: version[2], build: version[3], human: human });
				}

				else
					this.promiseQueue.pop().resolve(packet);
			}
			else if (command && _.str.startsWith(command.data, 'GetCurrentFrame')) {
				this.promiseQueue.pop().resolve(packet.toJson());
			}
			else if (qtmrt.DATA !== packet.type) {
				if (qtmrt.NO_MORE_DATA === packet.type) {
					this.emit('end');
				}
				else
					this.promiseQueue.pop().resolve(packet);
			}
			else if (qtmrt.DATA === packet.type) {
				this.emit('frame', packet.toJson());
			}

		}

		connect(port, host, major, minor) {
			if (this.client !== null)
				return Q.reject();

			if (arguments.length < 1)
				port = 22223;

			if (arguments.length < 2)
				host = 'localhost';

			if (arguments.length < 3) {
				major = 1;
				minor = 13;
			}
			else {
				if (!_.isNumber(major))
					throw new TypeError('Major version must be a number');

				if (!_.isNumber(major))
					throw new TypeError('Minor version must be a number');
			}

			this.host = host;
			this.port = port;

			var deferredCommand  = Q.defer();

			if (this.options.debug)
				this.logger.log('Connecting to ' + host + ':' + port, 'white', 'bold');

			this.client = this.net.connect(port, host, function() { });
			this.issuedCommands.unshift('Connect');
			this.bootstrap();

			this.promiseResponse()
				.then((packet) => {
					if (packet.data.toString() === 'QTM RT Interface connected\0') {
						this.send(Command.version(major, minor))
							.then(function(data) {
								deferredCommand.resolve();
							})
							.catch(function(err) {
								deferredCommand.reject(new Error(err));
							})
						;
					}
					else {
						deferredCommand.reject(new Error(packet.data.toString()));
					}
				})
				.catch(function(err) {
					console.log(err);
				});

			return deferredCommand.promise;
		}

		qtmVersion() { return this.send(Command.qtmVersion()); }
		byteOrder() { return this.send(Command.byteOrder()); }
		getState() { return this.send(Command.getState()); }
		getParameters() { return this.send(Command.getParameters.apply(Command, arguments)); }
		setParameters() { return this.send(Command.setParameters.apply(Command, arguments)); }
		getCurrentFrame() { return this.send(Command.getCurrentFrame.apply(Command, arguments)); }
		releaseControl() { return this.send(Command.releaseControl()); }
		newMeasurement() { return this.send(Command.newMeasurement()); }
		close() { return this.send(Command.close()); }
		start() { return this.send(Command.start()); }
		stop() { return this.send(Command.stop()); }
		trig() { return this.send(Command.trig()); }

		// XXX: Not tested with C3D file reply.
		getCaptureC3D() { return this.send(Command.getCaptureC3D()); }
		// XXX: Not tested with QTM file reply.
		getCaptureQtm() { return this.send(Command.getCaptureQtm()); }

		streamFrames(options) {
			if (this.isStreaming)
				return Q.reject('Could not start streaming, already streaming');

			this.isStreaming = true;

			if (_.isUndefined(options.frequency))
				options.frequency = this.options.frequency;

			if (!_.isUndefined(options.udpPort) && (_.isUndefined(options.udpAddress)
					||  options.updAddress === 'localhost' ||  options.udpAddress === '127.0.0.1'))
				setupUdp.call(this, options.udpPort);

			return this.send(Command.streamFrames.apply(Command, [options]));
		}

		stopStreaming() {
			if (!this.isStreaming) {
				this.logger.log('Cannot stop streaming, not currently streaming', 'red');
				return;
			}

			this.isStreaming = false;
			this.emit('end');

			return this.send(Command.stopStreaming());
		}

		takeControl(pass) {
			if (!_.isUndefined(pass) && !_.isString(pass))
				throw new TypeError('Password must be a string');

			return this.send(Command.takeControl(pass));
		}

		load(filename) {
			if (arguments.length < 1)
				throw new TypeError('No filename specified');

			if (!_.isString(filename))
				throw new TypeError('Filename must be a string');

			return this.send(Command.load(filename));
		}

		save(filename, overwrite) {
			if (arguments.length < 1)
				throw new TypeError('No filename specified');

			if (!_.isString(filename))
				throw new TypeError('Filename must be a string');

			if (arguments.length > 1)
				overwrite = 'overwrite';

			return this.send(Command.save(filename, overwrite));
		}

		loadProject(projectPath) {
			if (arguments.length < 1)
				throw new TypeError('No project path specified');

			if (!_.isString(projectPath))
				throw new TypeError('Project path must be a string');

			return this.send(Command.loadProject(projectPath));
		}

		setQtmEvent(label) {
			if (arguments.length < 1)
				throw new TypeError('No label specified');

			if (!_.isString(label))
				throw new TypeError('Label must be a string');

			return this.send(Command.setQtmEvent(label));
		}

		send(command) {
			if (this.client === null)
				new Error('Not connected to QTM. Connect and try again.');

			var promise = Q.resolve();

			// Don't expect a reply on the StreamFrames command.
			if (!_.str.startsWith(command.data, 'StreamFrames'))
				promise = this.promiseResponse();

			this.issuedCommands.unshift(command);

			command.isResponse = false;

			this.client.write(command.buffer, 'utf8', function(data) {
				if (this.options.debug)
					this.logger.logPacket(command);
			}.bind(this));

			return promise;
		}

		promiseResponse() {
			var deferredResponse = Q.defer();

			this.promiseQueue.unshift(deferredResponse);

			return deferredResponse.promise;
		}

		disconnect() {
			if (this.client === null)
				new Error('Not connected to QTM. Connect and try again.');

			this.client.end();
		}

		discover(port) {
			if (_.isUndefined(port))
				port = this.options.discoverPort;

			var server = dgram.createSocket('udp4')
			  , receivePort = port + 1
			  , discoveredServers = []
			  , deferred = Q.defer()
			;

			server.on('error', function(err) {
				console.log('Server error:\n' + err.stack);
				server.close();
			});

			server.on('message', (msg, rinfo) => {
				// Set type to discover type.
				writeUInt32(msg, 7, 4);

				var discoverPacket = Packet.create(msg, rinfo.address, rinfo.port);

				if (this.options.debug)
					this.logger.logPacket(discoverPacket);

				discoveredServers.push({
					serverInfo: discoverPacket.serverInfo,
					serverBasePort: discoverPacket.serverBasePort,
					srcAddress: discoverPacket.srcAddress,
					srcPort: discoverPacket.srcPort,
				});
			});

			server.bind(receivePort);

			// Create discover packet.
			var buf = new Buffer(10);
			buf.writeUInt32LE(10, 0);
			buf.writeUInt32LE(7, 4);
			buf.writeUInt16BE(receivePort, 8);

			var client = dgram.createSocket('udp4')
				// , address = 'ff02::1'
			  , address = '255.255.255.255'
			;

			client.bind();
			client.on('listening', () => {
				client.setBroadcast(true);
				client.send(buf, 0, buf.length, port, address, function(err, bytes) {
					client.close();
				});

				if (this.options.debug)
					this.logger.logPacket(Packet.create(buf));

				setTimeout(function() {
					server.close();
					server.unref();
					deferred.resolve(discoveredServers);
				}, this.options.discoverTimeout);

			}.bind(this));

			return deferred.promise;
		}

		frequency(freq) {
			if (isNaN(freq) && freq !== 'AllFrames')
				throw new TypeError('Frequency must be a number or \'AllFrames\'');

			this.options.frequency = freq;
		}

		debug(val) {
			this.options.debug = val ? true : false;
		}
	}

	mixin(Api.prototype, events.EventEmitter.prototype);

	module.exports = Api;
})();<|endoftext|>


<commit_before>(function (root, factory) {

  if(typeof define === 'function' && define.amd) {
    define([], factory(root));
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.inlineSVG = factory(root);
  }

})(typeof global !== "undefined" ? global : this.window || this.global, function (root) {

  'use strict';

  // Variables
  var inlineSVG = {},
      supports = !!document.querySelector && !!root.addEventListener,
      settings;

  // Defaults
  var defaults = {
    initClass: 'js-inlinesvg',
    svgSelector: 'img.svg'
  };

  /**
   * Merge two objects together
   * @private
   * @param {Function} fn
   */
  var extend = function (fn) {

    // Variables
    var extended = {};
    var deep = false;
    var i = 0;
    var length = arguments.length;

    // Check if a deep merge
    if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
      deep = arguments[0];
      i++;
    }

    // Merge the object into the extended object
    var merge = function (obj) {
      for ( var prop in obj ) {
        if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
          // If deep merge and property is an object, merge properties
          if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
            extended[prop] = buoy.extend( true, extended[prop], obj[prop] );
          } else {
            extended[prop] = obj[prop];
          }
        }
      }
    };

    // Loop through each object and conduct a merge
    for ( ; i < length; i++ ) {
      var obj = arguments[i];
      merge(obj);
    }

    return extended;

  };

  // Methods

  /**
   * Grab all the SVGs that match the selector
   * @public
   */
  inlineSVG.getAll = function () {

    var svgs = document.querySelectorAll(settings.svgSelector);
    return svgs;

  };

  /**
   * Inline all the SVGs in the array
   * @public
   */
  inlineSVG.inliner = function () {

    var svgs = inlineSVG.getAll();

    Array.prototype.forEach.call(svgs, function (svg, i) {

      // Store some attributes of the image
      var src = svg.src,
          attributes = svg.attributes;

      if(!localStorage.getItem(src)) {

        // Get the contents of the SVG
        var request = new XMLHttpRequest();
        request.open('GET', src, true);

        request.onload = function () {

          if(request.status >= 200 && request.status < 400) {

            // Setup a parser to convert the response to text/xml in order for it
            // to be manipulated and changed
            var parser = new DOMParser(),
                result = parser.parseFromString(request.responseText, 'text/xml'),
                inlinedSVG = result.getElementsByTagName('svg')[0];

            // Remove some of the attributes that aren't needed
            inlinedSVG.removeAttribute('xmlns:a');
            inlinedSVG.removeAttribute('width');
            inlinedSVG.removeAttribute('height');
            inlinedSVG.removeAttribute('x');
            inlinedSVG.removeAttribute('y');
            inlinedSVG.removeAttribute('enable-background');
            inlinedSVG.removeAttribute('xmlns:xlink');
            inlinedSVG.removeAttribute('xml:space');
            inlinedSVG.removeAttribute('version');

            // Add in the attributes from the original <img> except 'src' or
            // 'alt', we don't need either
            Array.prototype.slice.call(attributes).forEach(function(attribute) {
              if(attribute.name !== 'src' && attribute.name !== 'alt') {
                inlinedSVG.setAttribute(attribute.name, attribute.value);
              }
            });

            // Add an additional class the the inlined SVG to imply it was
            // infact inlined, might be useful to know
            if (inlinedSVG.classList) {
              inlinedSVG.classList.add('inlined-svg');
            } else {
              inlinedSVG.className += ' ' + 'inlined-svg';
            }

            // Add in some accessibility quick wins
            inlinedSVG.setAttribute('role', 'img');

            if(attributes.longdesc) {
              var description = document.createElementNS('http://www.w3.org/2000/svg', 'desc'),
                  descriptionText = document.createTextNode(attributes.longdesc.value);

              description.appendChild(descriptionText);
              inlinedSVG.insertBefore(description, inlinedSVG.firstChild);
            }

            if(attributes.alt) {
              inlinedSVG.setAttribute('aria-labelledby', 'title');

              var title = document.createElementNS('http://www.w3.org/2000/svg', 'title'),
                  titleText = document.createTextNode(attributes.alt.value);

              title.appendChild(titleText);
              inlinedSVG.insertBefore(title, inlinedSVG.firstChild);
            }

            // Store the source in localStorage to avoid making requests every time
            var tempContainer = document.createElement('div');
            tempContainer.appendChild(inlinedSVG);

            localStorage.setItem(src, tempContainer.innerHTML);

            // Replace the image with the SVG
            svg.parentNode.replaceChild(inlinedSVG, svg);

          } else {
            console.error('There was an error retrieving the source of the SVG.');
          }

        };

        request.onerror = function () {
          console.error('There was an error connecting to the origin server.');
        };

        request.send();

      } else {
        var parse = new DOMParser(),
            result = parse.parseFromString(localStorage.getItem(src), 'text/xml'),
            inlinedSVG = result.getElementsByTagName('svg')[0];

        svg.parentNode.replaceChild(inlinedSVG, svg);
      }

    });

  };

  /**
   * Initialise the inliner
   * @public
   */
  inlineSVG.init = function (options) {

    // Test for support
    if (!supports) return;

    // Merge users option with defaults
    settings = extend(defaults, options || {});

    // Kick-off the inliner
    inlineSVG.inliner();

    // Once inlined and a class to the HTML
    document.documentElement.className += ' ' + settings.initClass;

  };

  return inlineSVG;

});<commit_msg>Code tidy<commit_after>(function (root, factory) {

  if(typeof define === 'function' && define.amd) {
    define([], factory(root));
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.inlineSVG = factory(root);
  }

})(typeof global !== "undefined" ? global : this.window || this.global, function (root) {

  'use strict';

  // Variables
  var inlineSVG = {},
      supports = !!document.querySelector && !!root.addEventListener,
      settings;

  // Defaults
  var defaults = {
    initClass: 'js-inlinesvg',
    svgSelector: 'img.svg'
  };

  /**
   * Merge two objects together
   * @private
   * @param {Function} fn
   */
  var extend = function () {

    // Variables
    var extended = {};
    var deep = false;
    var i = 0;
    var length = arguments.length;

    // Check if a deep merge
    if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
      deep = arguments[0];
      i++;
    }

    // Merge the object into the extended object
    var merge = function (obj) {
      for ( var prop in obj ) {
        if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
          // If deep merge and property is an object, merge properties
          if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
            extended[prop] = extend( true, extended[prop], obj[prop] );
          } else {
            extended[prop] = obj[prop];
          }
        }
      }
    };

    // Loop through each object and conduct a merge
    for ( ; i < length; i++ ) {
      var obj = arguments[i];
      merge(obj);
    }

    return extended;

  };

  // Methods

  /**
   * Grab all the SVGs that match the selector
   * @public
   */
  inlineSVG.getAll = function () {

    var svgs = document.querySelectorAll(settings.svgSelector);
    return svgs;

  };

  /**
   * Inline all the SVGs in the array
   * @public
   */
  inlineSVG.inliner = function () {

    var svgs = inlineSVG.getAll();

    Array.prototype.forEach.call(svgs, function (svg, i) {

      // Store some attributes of the image
      var src = svg.src,
          attributes = svg.attributes;

      if(!localStorage.getItem(src)) {

        // Get the contents of the SVG
        var request = new XMLHttpRequest();
        request.open('GET', src, true);

        request.onload = function () {

          if(request.status >= 200 && request.status < 400) {

            // Setup a parser to convert the response to text/xml in order for it
            // to be manipulated and changed
            var parser = new DOMParser(),
                result = parser.parseFromString(request.responseText, 'text/xml'),
                inlinedSVG = result.getElementsByTagName('svg')[0];

            // Remove some of the attributes that aren't needed
            inlinedSVG.removeAttribute('xmlns:a');
            inlinedSVG.removeAttribute('width');
            inlinedSVG.removeAttribute('height');
            inlinedSVG.removeAttribute('x');
            inlinedSVG.removeAttribute('y');
            inlinedSVG.removeAttribute('enable-background');
            inlinedSVG.removeAttribute('xmlns:xlink');
            inlinedSVG.removeAttribute('xml:space');
            inlinedSVG.removeAttribute('version');

            // Add in the attributes from the original <img> except 'src' or
            // 'alt', we don't need either
            Array.prototype.slice.call(attributes).forEach(function(attribute) {
              if(attribute.name !== 'src' && attribute.name !== 'alt') {
                inlinedSVG.setAttribute(attribute.name, attribute.value);
              }
            });

            // Add an additional class the the inlined SVG to imply it was
            // infact inlined, might be useful to know
            if (inlinedSVG.classList) {
              inlinedSVG.classList.add('inlined-svg');
            } else {
              inlinedSVG.className += ' ' + 'inlined-svg';
            }

            // Add in some accessibility quick wins
            inlinedSVG.setAttribute('role', 'img');

            if(attributes.longdesc) {
              var description = document.createElementNS('http://www.w3.org/2000/svg', 'desc'),
                  descriptionText = document.createTextNode(attributes.longdesc.value);

              description.appendChild(descriptionText);
              inlinedSVG.insertBefore(description, inlinedSVG.firstChild);
            }

            if(attributes.alt) {
              inlinedSVG.setAttribute('aria-labelledby', 'title');

              var title = document.createElementNS('http://www.w3.org/2000/svg', 'title'),
                  titleText = document.createTextNode(attributes.alt.value);

              title.appendChild(titleText);
              inlinedSVG.insertBefore(title, inlinedSVG.firstChild);
            }

            // Store the source in localStorage to avoid making requests every time
            var tempContainer = document.createElement('div');
            tempContainer.appendChild(inlinedSVG);

            localStorage.setItem(src, tempContainer.innerHTML);

            // Replace the image with the SVG
            svg.parentNode.replaceChild(inlinedSVG, svg);

          } else {
            console.error('There was an error retrieving the source of the SVG.');
          }

        };

        request.onerror = function () {
          console.error('There was an error connecting to the origin server.');
        };

        request.send();

      } else {
        var parse = new DOMParser(),
            result = parse.parseFromString(localStorage.getItem(src), 'text/xml'),
            inlinedSVG = result.getElementsByTagName('svg')[0];

        svg.parentNode.replaceChild(inlinedSVG, svg);
      }

    });

  };

  /**
   * Initialise the inliner
   * @public
   */
  inlineSVG.init = function (options) {

    // Test for support
    if (!supports) return;

    // Merge users option with defaults
    settings = extend(defaults, options || {});

    // Kick-off the inliner
    inlineSVG.inliner();

    // Once inlined and a class to the HTML
    document.documentElement.className += ' ' + settings.initClass;

  };

  return inlineSVG;

});<|endoftext|>


<commit_before>var spawn = require("cross-spawn");
var fs = require("fs");
var path = require("path");
var resolve = require("resolve");
var util = require("util");
var JSON5 = require("json5");

var EXTERNAL = /^\w[a-z\-0-9\.]+$/; // Match "react", "path", "fs", "lodash.random", etc.
var PEERS = /UNMET PEER DEPENDENCY ([a-z\-0-9\.]+)@(.+)/gm;

var defaultOptions = {
  dev: false,
  peerDependencies: true,
  quiet: false,
  npm: 'npm',
};
var erroneous = [];

function normalizeBabelPlugin(plugin, prefix) {
  // Babel plugins can be configured as [plugin, options]
  if (Array.isArray(plugin)) {
    plugin = plugin[0];
  }
  if (plugin.indexOf(prefix) === 0) {
    return plugin;
  }
  return prefix + plugin;
}

module.exports.packageExists = function packageExists() {
  var pkgPath = path.resolve("package.json");
  try {
    require.resolve(pkgPath);
    // Remove cached copy for future checks
    delete require.cache[pkgPath];
    return true;
  } catch (e) {
    return false;
  }
}

module.exports.check = function check(request) {
  if (!request) {
    return;
  }

  var namespaced = request.charAt(0) === "@";
  var dep = request.split("/")
    .slice(0, namespaced ? 2 : 1)
    .join("/")
  ;

  // Ignore relative modules, which aren't installed by NPM
  if (!dep.match(EXTERNAL) && !namespaced) {
    return;
  }

  // Ignore modules which can be resolved using require.resolve()'s algorithm
  try {
    resolve.sync(dep, {basedir: process.cwd()});
    return;
  } catch(e) {
    // Module is not resolveable
  }

  return dep;
};

module.exports.checkBabel = function checkBabel() {
  try {
    var babelrc = require.resolve(path.resolve(".babelrc"));
    var babelOpts = JSON5.parse(fs.readFileSync(babelrc, "utf8"));
  } catch (e) {
    if (babelrc) {
      console.info(".babelrc is invalid JSON5, babel deps are skipped")
    }
    // Babel isn't installed, don't install deps
    return;
  }

  // Default plugins/presets
  var options = Object.assign({
    plugins: [],
    presets: [],
  }, babelOpts);

  if (!options.env) {
    options.env = {};
  }

  if (!options.env.development) {
    options.env.development = {};
  }

  // Default env.development plugins/presets
  options.env.development = Object.assign({
    plugins: [],
    presets: [],
  }, options.env.development);

  // Accumulate babel-core (required for babel-loader)+ all dependencies
  var deps = ["@babel/core"].concat(options.plugins.map(function(plugin) {
    return normalizeBabelPlugin(plugin, "babel-plugin-");
  })).concat(options.presets.map(function(preset) {
    return normalizeBabelPlugin(preset, "@babel/preset-");
  })).concat(options.env.development.plugins.map(function(plugin) {
    return normalizeBabelPlugin(plugin, "babel-plugin-");
  })).concat(options.env.development.presets.map(function(preset) {
    return normalizeBabelPlugin(preset, "@babel/preset-");
  }));

  // Check for missing dependencies
  var missing = deps.filter(function(dep) {
    return this.check(dep);
  }.bind(this));

  // Install missing dependencies
  this.install(missing);
};

module.exports.defaultOptions = defaultOptions;

module.exports.install = function install(deps, options) {
  if (!deps) {
    return;
  }

  if (!Array.isArray(deps)) {
    deps = [deps];
  }

  options = Object.assign({}, defaultOptions, options);

  // Ignore known, erroneous modules
  deps = deps.filter(function(dep) {
    return erroneous.indexOf(dep) === -1;
  });

  if (!deps.length) {
    return;
  }

  var args;
  var client;
  var quietOptions;
  var save;
  if (options.yarn) {
    args = ['add'];
    client = 'yarn';
    save = options.dev ? "--dev" : null;
    quietOptions = ["--silent"];
  } else {
    args = ['install'];
    client = options.npm;
    save = options.dev ? "--save-dev" : "--save";
    quietOptions = ["--silent", "--no-progress"];
  }

  args = args.concat(deps).filter(Boolean);

  if (save && module.exports.packageExists()) {
    args.push(save);
  }

  if (options.quiet) {
    args = args.concat(quietOptions);
  }

  deps.forEach(function(dep) {
    console.info("Installing %s...", dep);
  });

  // Ignore input, capture output, show errors
  var output = spawn.sync(client, args, {
    stdio: ["ignore", "pipe", "inherit"]
  });

  if (output.status) {
    deps.forEach(function(dep) {
      erroneous.push(dep);
    });
  }

  var matches = null;
  var peers = [];

  // RegExps track return a single result each time
  while (matches = PEERS.exec(output.stdout)) {
    var dep = matches[1];
    var version = matches[2];

    // Ranges don't work well, so let NPM pick
    if (version.match(" ")) {
      peers.push(dep);
    } else {
      peers.push(util.format("%s@%s", dep, version));
    }
  }

  if (options.peerDependencies && peers.length) {
    console.info("Installing peerDependencies...");
    this.install(peers, options);
    console.info("");
  }

  return output;
};
<commit_msg>fix: added support for babel.config.js (#133)<commit_after>var spawn = require('cross-spawn');
var fs = require('fs');
var path = require('path');
var resolve = require('resolve');
var util = require('util');
var JSON5 = require('json5');

var EXTERNAL = /^\w[a-z\-0-9\.]+$/; // Match "react", "path", "fs", "lodash.random", etc.
var PEERS = /UNMET PEER DEPENDENCY ([a-z\-0-9\.]+)@(.+)/gm;

var defaultOptions = {
  dev: false,
  peerDependencies: true,
  quiet: false,
  npm: 'npm'
};
var erroneous = [];

function normalizeBabelPlugin(plugin, prefix) {
  // Babel plugins can be configured as [plugin, options]
  if (Array.isArray(plugin)) {
    plugin = plugin[0];
  }
  if (plugin.indexOf(prefix) === 0) {
    return plugin;
  }
  return prefix + plugin;
}

module.exports.packageExists = function packageExists() {
  var pkgPath = path.resolve('package.json');
  try {
    require.resolve(pkgPath);
    // Remove cached copy for future checks
    delete require.cache[pkgPath];
    return true;
  } catch (e) {
    return false;
  }
};

module.exports.check = function check(request) {
  if (!request) {
    return;
  }

  var namespaced = request.charAt(0) === '@';
  var dep = request
    .split('/')
    .slice(0, namespaced ? 2 : 1)
    .join('/');
  // Ignore relative modules, which aren't installed by NPM
  if (!dep.match(EXTERNAL) && !namespaced) {
    return;
  }

  // Ignore modules which can be resolved using require.resolve()'s algorithm
  try {
    resolve.sync(dep, { basedir: process.cwd() });
    return;
  } catch (e) {
    // Module is not resolveable
  }

  return dep;
};

module.exports.checkBabel = function checkBabel() {
  try {
    var babelrc = require.resolve(path.resolve('.babelrc'));
    var babelOpts = JSON5.parse(fs.readFileSync(babelrc, 'utf8'));
  } catch (e) {
    try {
      var babelConfigJs = require.resolve(path.resolve('babel.config.js'));
      var babelOpts = require(babelConfigJs);
    } catch (e2) {
      console.info("couldn't locate babel.config.js nor .babelrc");
    } finally {
    }
    if (babelrc) {
      console.info('.babelrc is invalid JSON5, babel deps are skipped');
    }
    // Babel isn't installed, don't install deps
    return;
  }

  // Default plugins/presets
  var options = Object.assign(
    {
      plugins: [],
      presets: []
    },
    babelOpts
  );

  if (!options.env) {
    options.env = {};
  }

  if (!options.env.development) {
    options.env.development = {};
  }

  // Default env.development plugins/presets
  options.env.development = Object.assign(
    {
      plugins: [],
      presets: []
    },
    options.env.development
  );

  // Accumulate babel-core (required for babel-loader)+ all dependencies
  var deps = ['@babel/core']
    .concat(
      options.plugins.map(function(plugin) {
        return normalizeBabelPlugin(plugin, 'babel-plugin-');
      })
    )
    .concat(
      options.presets.map(function(preset) {
        return normalizeBabelPlugin(preset, '@babel/preset-');
      })
    )
    .concat(
      options.env.development.plugins.map(function(plugin) {
        return normalizeBabelPlugin(plugin, 'babel-plugin-');
      })
    )
    .concat(
      options.env.development.presets.map(function(preset) {
        return normalizeBabelPlugin(preset, '@babel/preset-');
      })
    );

  // Check for missing dependencies
  var missing = deps.filter(
    function(dep) {
      return this.check(dep);
    }.bind(this)
  );

  // Install missing dependencies
  this.install(missing);
};

module.exports.defaultOptions = defaultOptions;

module.exports.install = function install(deps, options) {
  if (!deps) {
    return;
  }

  if (!Array.isArray(deps)) {
    deps = [deps];
  }

  options = Object.assign({}, defaultOptions, options);

  // Ignore known, erroneous modules
  deps = deps.filter(function(dep) {
    return erroneous.indexOf(dep) === -1;
  });

  if (!deps.length) {
    return;
  }

  var args;
  var client;
  var quietOptions;
  var save;
  if (options.yarn) {
    args = ['add'];
    client = 'yarn';
    save = options.dev ? '--dev' : null;
    quietOptions = ['--silent'];
  } else {
    args = ['install'];
    client = options.npm;
    save = options.dev ? '--save-dev' : '--save';
    quietOptions = ['--silent', '--no-progress'];
  }

  args = args.concat(deps).filter(Boolean);

  if (save && module.exports.packageExists()) {
    args.push(save);
  }

  if (options.quiet) {
    args = args.concat(quietOptions);
  }

  deps.forEach(function(dep) {
    console.info('Installing %s...', dep);
  });

  // Ignore input, capture output, show errors
  var output = spawn.sync(client, args, {
    stdio: ['ignore', 'pipe', 'inherit']
  });

  if (output.status) {
    deps.forEach(function(dep) {
      erroneous.push(dep);
    });
  }

  var matches = null;
  var peers = [];

  // RegExps track return a single result each time
  while ((matches = PEERS.exec(output.stdout))) {
    var dep = matches[1];
    var version = matches[2];

    // Ranges don't work well, so let NPM pick
    if (version.match(' ')) {
      peers.push(dep);
    } else {
      peers.push(util.format('%s@%s', dep, version));
    }
  }

  if (options.peerDependencies && peers.length) {
    console.info('Installing peerDependencies...');
    this.install(peers, options);
    console.info('');
  }

  return output;
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import './App.css';

import * as injectTapEventPlugin from 'react-tap-event-plugin';

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import TextField from 'material-ui/TextField'
import {Card, CardMedia} from 'material-ui/Card'
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();

class Logic {
    search(searchString, callback) {
        let song = {
            'titleName': 'Baba O\'Riley',
            'artist': 'The Who',
            'titleCoverUri': 'http://www.thewho.com/wp-content/uploads/2012/08/39-02-the_who_ultimate_coll-us-300x300.jpg'
        };

        console.log(searchString);

        let result = {
            'selectedSong': song,
            'otherSongs': [
                song,
                song,
                song,
                song
            ]
        };

        callback(result);
    }
}

var box_dimension=500;
var card_height=box_dimension;
var card_width=box_dimension;
var card_height_offset=-card_height / 2;
var card_width_offset=-card_width / 2;
var image_height=box_dimension;
var image_width=box_dimension;

var standard_picture_offset=box_dimension / 1.5;

class ArtistCard extends Component {
    render() {
        return (

                <Card style={{width: card_width, height: card_height, position: "relative", top: card_height_offset, left: card_width_offset}}
                      containerStyle={{width: card_width, height: card_height}}>
                    <CardMedia mediaStyle={{width: image_width, height: image_height, display: "block"}}>

                    </CardMedia>
                </Card>

)
    }
}

class ArtistCards extends Component {
    selectedCardPosition = {position: "relative", top: "0", left: "0"};

    cardPositions = [
        {position: "relative", top: -standard_picture_offset, left: -standard_picture_offset},
        {position: "relative", top: standard_picture_offset, left: -standard_picture_offset},
        {position: "relative", top: standard_picture_offset, left: standard_picture_offset},
        {position: "relative", top: -standard_picture_offset, left: standard_picture_offset}
    ];

    state = {
        previousCardPositions: this.cardPositions
    };

    randomHoverOffset() {
        return -.1 + .2 * Math.random();
    }

    randomStartOffset() {
        return -40 + 80 * Math.random();
    }

    componentDidUpdate() {
        setTimeout(()=> {
            console.log("hit");

            var cardPositions = this.state.previousCardPositions.map(position => {
                return {
                    ...position,
                    left: position.left + this.randomHoverOffset(),
                    top: position.top + this.randomHoverOffset()
                }
            });

            this.setState({
                previousCardPositions: cardPositions
            });
        }, 1);
    }

    render() {
        if(this.objectIsEmpty(this.props.artists)) {
            return
;
        }

        //console.log(this.state.previousCardPositions);

        return (

            {this.props.artists["otherSongs"].map((song, index) => {
                //var cardPosition = this.state.previousCardPositions[index];
                //cardPosition.left += this.randomHoverOffset();
                //cardPosition.top += this.randomHoverOffset();
                //this.state.previousCardPositions[index] = cardPosition;
                console.log(this.state.previousCardPositions);
                //debugger;
                return <ArtistCard key={"song" + index} artist={song} stylePosition={this.state.previousCardPositions[index]} />
            })}
            <ArtistCard artist={this.props.artists["selectedSong"]} stylePosition={this.selectedCardPosition}/>

)
    }

    objectIsEmpty(obj) {
        return Object.keys(obj).length === 0;
    }
}

class App extends Component {
    state = {
        searchString: "",
        artists: {}
    };

    l = new Logic();

    onSearchResultSuccessfulCallback = (result) => {
        //console.log(result);
        this.setState({ artists: result })
    };

    onSearchFieldKeyPress = (event) => {
        if (event.charCode === 13) {
            this.l.search(this.state.searchString, this.onSearchResultSuccessfulCallback)
        }
    };

    onSearchChange = (_, searchString) => {
        this.setState({
            searchString : searchString
        });
    };

  render() {
      return (
          <MuiThemeProvider>

                  <TextField
                      name="searchField"
                      hintText={
Link your favourite song here.
}
                      hintStyle={{color: "#FFFFFF"}}
                      style={{width: "50%", marginTop: "20px"}}
                      onChange={this.onSearchChange}
                      onKeyPress={this.onSearchFieldKeyPress}
                      underlineFocusStyle={{borderColor: "#1BA64E"}}
                      inputStyle={{color: "#FFFFFF"}}/>
                  <ArtistCards artists={this.state.artists}/>

          </MuiThemeProvider>
    );
  }
}

export default App;
<commit_msg>Add title and artist description<commit_after>import React, { Component } from 'react';
import './App.css';

import * as injectTapEventPlugin from 'react-tap-event-plugin';

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import TextField from 'material-ui/TextField'
import {Card, CardMedia, CardTitle} from 'material-ui/Card'
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();

class Logic {
    search(searchString, callback) {
        let song = {
            'titleName': 'Baba O\'Riley',
            'artist': 'The Who',
            'titleCoverUri': 'http://www.thewho.com/wp-content/uploads/2012/08/39-02-the_who_ultimate_coll-us-300x300.jpg'
        };

        console.log(searchString);

        let result = {
            'selectedSong': song,
            'otherSongs': [
                song,
                song,
                song,
                song
            ]
        };

        callback(result);
    }
}

var box_dimension=500;
var card_height=box_dimension;
var card_width=box_dimension;
var card_height_offset=-card_height / 2;
var card_width_offset=-card_width / 2;
var image_height=box_dimension;
var image_width=box_dimension;

var standard_picture_offset=box_dimension / 1.5;

class ArtistCard extends Component {
    render() {
        return (

                <Card style={{width: card_width, height: card_height, position: "relative", top: card_height_offset, left: card_width_offset}}
                      containerStyle={{width: card_width, height: card_height}}>
                    <CardMedia
                        mediaStyle={{width: image_width, height: image_height, display: "block"}}
                        overlay={<CardTitle title={this.props.artist.titleName} subtitle={this.props.artist.artist} />}>

                    </CardMedia>
                </Card>

)
    }
}

class ArtistCards extends Component {
    selectedCardPosition = {position: "relative", top: "0", left: "0"};

    cardPositions = [
        {position: "relative", top: -standard_picture_offset, left: -standard_picture_offset},
        {position: "relative", top: standard_picture_offset, left: -standard_picture_offset},
        {position: "relative", top: standard_picture_offset, left: standard_picture_offset},
        {position: "relative", top: -standard_picture_offset, left: standard_picture_offset}
    ];

    state = {
        previousCardPositions: this.cardPositions
    };

    randomHoverOffset() {
        return -.1 + .2 * Math.random();
    }

    randomStartOffset() {
        return -40 + 80 * Math.random();
    }

    componentDidUpdate() {
        setTimeout(()=> {
            console.log("hit");

            var cardPositions = this.state.previousCardPositions.map(position => {
                return {
                    ...position,
                    left: position.left + this.randomHoverOffset(),
                    top: position.top + this.randomHoverOffset()
                }
            });

            this.setState({
                previousCardPositions: cardPositions
            });
        }, 1);
    }

    render() {
        if(this.objectIsEmpty(this.props.artists)) {
            return
;
        }

        //console.log(this.state.previousCardPositions);

        return (

            {this.props.artists["otherSongs"].map((song, index) => {
                //var cardPosition = this.state.previousCardPositions[index];
                //cardPosition.left += this.randomHoverOffset();
                //cardPosition.top += this.randomHoverOffset();
                //this.state.previousCardPositions[index] = cardPosition;
                console.log(this.state.previousCardPositions);
                //debugger;
                return <ArtistCard key={"song" + index} artist={song} stylePosition={this.state.previousCardPositions[index]} />
            })}
            <ArtistCard artist={this.props.artists["selectedSong"]} stylePosition={this.selectedCardPosition}/>

)
    }

    objectIsEmpty(obj) {
        return Object.keys(obj).length === 0;
    }
}

class App extends Component {
    state = {
        searchString: "",
        artists: {}
    };

    l = new Logic();

    onSearchResultSuccessfulCallback = (result) => {
        //console.log(result);
        this.setState({ artists: result })
    };

    onSearchFieldKeyPress = (event) => {
        if (event.charCode === 13) {
            this.l.search(this.state.searchString, this.onSearchResultSuccessfulCallback)
        }
    };

    onSearchChange = (_, searchString) => {
        this.setState({
            searchString : searchString
        });
    };

  render() {
      return (
          <MuiThemeProvider>

                  <TextField
                      name="searchField"
                      hintText={
Link your favourite song here.
}
                      hintStyle={{color: "#FFFFFF"}}
                      style={{width: "50%", marginTop: "20px"}}
                      onChange={this.onSearchChange}
                      onKeyPress={this.onSearchFieldKeyPress}
                      underlineFocusStyle={{borderColor: "#1BA64E"}}
                      inputStyle={{color: "#FFFFFF"}}/>
                  <ArtistCards artists={this.state.artists}/>

          </MuiThemeProvider>
    );
  }
}

export default App;
<|endoftext|>


<commit_before>/**
 * This is an example of a basic node.js script that performs
 * the Authorization Code oAuth2 flow to authenticate against
 * the Spotify Accounts.
 *
 * For more information, read
 * https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow
 */

var express = require('express'); // Express web server framework
var request = require('request'); // "Request" library
var querystring = require('querystring');
var cookieParser = require('cookie-parser');
var settings = require('../config/settings.json');

var client_id = settings.credentials.clientId;            // Your client id
var client_secret = settings.credentials.clientSecret;    // Your secret
var scopes = 'user-read-private user-read-email playlist-modify-public playlist-modify-private';
var redirect_uri = 'http://localhost:8888/callback'; // Your redirect uri

/**
 * Generates a random string containing numbers and letters
 * @param  {number} length The length of the string
 * @return {string} The generated string
 */
var generateRandomString = function(length) {
  var text = '';
  var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
};

var stateKey = 'spotify_auth_state';

var app = express();

app.use(express.static(__dirname + '/../public'))
   .use(cookieParser());

app.get('/login', function(req, res) {

  var state = generateRandomString(16);
  res.cookie(stateKey, state);

  // your application requests authorization
  res.redirect('https://accounts.spotify.com/authorize?' +
    querystring.stringify({
      response_type: 'code',
      client_id: client_id,
      scope: scopes,
      redirect_uri: redirect_uri,
      state: state
    }));
});

app.get('/callback', function(req, res) {

  // your application requests refresh and access tokens
  // after checking the state parameter

  var code = req.query.code || null;
  var state = req.query.state || null;
  var storedState = req.cookies ? req.cookies[stateKey] : null;

  if (state === null || state !== storedState) {
    res.redirect('/#' +
      querystring.stringify({
        error: 'state_mismatch'
      }));
  } else {
    res.clearCookie(stateKey);
    var authOptions = {
      url: 'https://accounts.spotify.com/api/token',
      form: {
        code: code,
        redirect_uri: redirect_uri,
        grant_type: 'authorization_code'
      },
      headers: {
        'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
      },
      json: true
    };

    request.post(authOptions, function(error, response, body) {
      if (!error && response.statusCode === 200) {

        var access_token = body.access_token,
            refresh_token = body.refresh_token;

        var options = {
          url: 'https://api.spotify.com/v1/me',
          headers: { 'Authorization': 'Bearer ' + access_token },
          json: true
        };

        // use the access token to access the Spotify Web API
        request.get(options, function(error, response, body) {
          console.log(body);    // eslint-disable-line no-console
        });

        // we can also pass the token to the browser to make requests from there
        res.redirect('/#' +
          querystring.stringify({
            access_token: access_token,
            refresh_token: refresh_token
          }));
      } else {
        res.redirect('/#' +
          querystring.stringify({
            error: 'invalid_token'
          }));
      }
    });
  }
});

app.get('/refresh_token', function(req, res) {

  // requesting access token from refresh token
  var refresh_token = req.query.refresh_token;
  var authOptions = {
    url: 'https://accounts.spotify.com/api/token',
    headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
    form: {
      grant_type: 'refresh_token',
      refresh_token: refresh_token
    },
    json: true
  };

  request.post(authOptions, function(error, response, body) {
    if (!error && response.statusCode === 200) {
      var access_token = body.access_token;
      res.send({
        'access_token': access_token
      });
    }
  });
});

console.log('Listening on 8888');   // eslint-disable-line no-console
app.listen(8888);
<commit_msg>redirect url from settings<commit_after>/**
 * This is an example of a basic node.js script that performs
 * the Authorization Code oAuth2 flow to authenticate against
 * the Spotify Accounts.
 *
 * For more information, read
 * https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow
 */

var express = require('express'); // Express web server framework
var request = require('request'); // "Request" library
var querystring = require('querystring');
var cookieParser = require('cookie-parser');
var settings = require('../config/settings.json');

var client_id = settings.credentials.clientId;            // Your client id
var client_secret = settings.credentials.clientSecret;    // Your secret
var scopes = 'user-read-private user-read-email playlist-modify-public playlist-modify-private';
var redirect_uri = settings.redirect_url; // Your redirect uri

/**
 * Generates a random string containing numbers and letters
 * @param  {number} length The length of the string
 * @return {string} The generated string
 */
var generateRandomString = function(length) {
  var text = '';
  var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

  for (var i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }
  return text;
};

var stateKey = 'spotify_auth_state';

var app = express();

app.use(express.static(__dirname + '/../public'))
   .use(cookieParser());

app.get('/login', function(req, res) {

  var state = generateRandomString(16);
  res.cookie(stateKey, state);

  // your application requests authorization
  res.redirect('https://accounts.spotify.com/authorize?' +
    querystring.stringify({
      response_type: 'code',
      client_id: client_id,
      scope: scopes,
      redirect_uri: redirect_uri,
      state: state
    }));
});

app.get('/callback', function(req, res) {

  // your application requests refresh and access tokens
  // after checking the state parameter

  var code = req.query.code || null;
  var state = req.query.state || null;
  var storedState = req.cookies ? req.cookies[stateKey] : null;

  if (state === null || state !== storedState) {
    res.redirect('/#' +
      querystring.stringify({
        error: 'state_mismatch'
      }));
  } else {
    res.clearCookie(stateKey);
    var authOptions = {
      url: 'https://accounts.spotify.com/api/token',
      form: {
        code: code,
        redirect_uri: redirect_uri,
        grant_type: 'authorization_code'
      },
      headers: {
        'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
      },
      json: true
    };

    request.post(authOptions, function(error, response, body) {
      if (!error && response.statusCode === 200) {

        var access_token = body.access_token,
            refresh_token = body.refresh_token;

        var options = {
          url: 'https://api.spotify.com/v1/me',
          headers: { 'Authorization': 'Bearer ' + access_token },
          json: true
        };

        // use the access token to access the Spotify Web API
        request.get(options, function(error, response, body) {
          console.log(body);    // eslint-disable-line no-console
        });

        // we can also pass the token to the browser to make requests from there
        res.redirect('/#' +
          querystring.stringify({
            access_token: access_token,
            refresh_token: refresh_token
          }));
      } else {
        res.redirect('/#' +
          querystring.stringify({
            error: 'invalid_token'
          }));
      }
    });
  }
});

app.get('/refresh_token', function(req, res) {

  // requesting access token from refresh token
  var refresh_token = req.query.refresh_token;
  var authOptions = {
    url: 'https://accounts.spotify.com/api/token',
    headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
    form: {
      grant_type: 'refresh_token',
      refresh_token: refresh_token
    },
    json: true
  };

  request.post(authOptions, function(error, response, body) {
    if (!error && response.statusCode === 200) {
      var access_token = body.access_token;
      res.send({
        'access_token': access_token
      });
    }
  });
});

console.log('Listening on 8888');   // eslint-disable-line no-console
app.listen(8888);
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");
var url = require("url");
var request = require('request');
var htmlparser = require("htmlparser");
var select = require('soupselect').select;
var emptyTags = [];
for (var prop in htmlparser.DefaultHandler._emptyTags) if (htmlparser.DefaultHandler._emptyTags.hasOwnProperty(prop)) {
	emptyTags.push(prop);
}

var innerHTML = function(html, parent_elem, dom) {
	var _innerHTML = function(dom, dom2) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			if (val == parent_elem) {
				val.children = dom2
				return true
			}
			if (val.children) _innerHTML(val.children, dom2);
		}
	}
	if (emptyTags.indexOf(parent_elem.name) == -1) {
		var handler = new htmlparser.DefaultHandler(function (err, dom2) {
			if (err) {
				console.log(err);
				dom2 = [];
			}
			_innerHTML(dom, dom2);
		});
		var parser = new htmlparser.Parser(handler);
		parser.parseComplete(html);
	}
}

/* Возвращает массив true/false для соответсвующих показанных/непоказанных слоев */
var getShownLayers = function(layers) {
	var shown_layers = [];
	for (var i = layers.length; --i >= 0;) {
		shown_layers[i] = layers[i].show;
	}
	return shown_layers;
}

var appendChild = function(elem, parent_elem, dom) {
	var _appendChild = function(dom) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			if (val == parent_elem) {
				if (val.children) val.children.push(elem);
				else val.children = [elem];
				return true;
			}
			if (val.children) _appendChild(val.children);
		}
	}
	if (emptyTags.indexOf(parent_elem.name) == -1) {
		_appendChild(dom);
	}
}

/* Возвращает html сделанные из dom htmlparser'а */
var createHtml = function(dom) {
	var HTML5 = '';
	var _create = function(dom) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			switch (val.type) {
				case 'text':
					HTML5 = val.raw + HTML5;
					break;
				case "tag":
					if (emptyTags.indexOf(val.name) == -1) {
						HTML5 = '</' + val.name + '>' + HTML5;
						if (val.children) _create(val.children);
						HTML5 = '<' + val.raw + '>' + HTML5;
					} else {
						HTML5 = '<' + val.raw + '>' + HTML5;
					}
					break;
				case "script":
				case "style":
					HTML5 = '</' + val.name + '>' + HTML5;
					if (val.children) _create(val.children);
					HTML5 = '<' + val.raw + '>' + HTML5;
					break;
				case "comment":
					HTML5 = '<!--' + val.raw + '-->' + HTML5;
					break;
				case 'directive':
					HTML5 = '<' + val.raw + '>' + HTML5;
					break;
			}
		}
	}
	_create(dom);
	return HTML5;
}

var regExpStr_njs = '(node(_|-)[^/]*/.*\\.)|(\\.n\\.{0,1})js$';

module.exports = function(infra, html, state, req, root, cb) {
	var host = req.headers.host;
	infra.state = state;
	var handler = new htmlparser.DefaultHandler(function (error, dom) {
		if (error) throw error;
		infra.eqLayerNodes = function(node1, node2) {
			if (infra.existLayerNode(node1) && infra.existLayerNode(node2)) {
				var i = node1.length;
				if (i && (i == node2.length)) {
					for (; --i >= 0;) {
						if (node1[i] != node2[i]) return false;
					}
					return true
				} else if (node1 == node2) return true
			}
		}
		infra.pasteNode = function(node, htmlString) {
			if (node.length) {
				for (var n=0, ll=node.length; n<ll; n++) {
					innerHTML(htmlString, node[n], dom);
				}
			} else {
				innerHTML(htmlString, node, dom);
			}
		};
		infra.load._load = function(file, callback) {
			var writeHead = function(){};
			var end = function(data){callback(0,data)};
			var path_url = url.parse(encodeURI(file), true);
			path_url.pathname = decodeURI(path_url.pathname);
			//path_url.href = decodeURI(path_url.href);
			path_url.search = decodeURI(path_url.search);
			// var njs = new RegExp('([^/]+/node-[^/]+/[^/]+\.js)|(/[^/]+\.njs)$').test(path_url.pathname);
			//var njs = /(node(_|\-)[^\/]*\/.*\.)|(\.n\.{0,1})js$/gi.test(path_url.pathname)
			var njs = new RegExp(regExpStr_njs, 'gi').test(path_url.pathname);

			//if (path_url.host || (!njs && path_url.search)) { // загружаем через веб
				if (!path_url.host) {
					if (path_url.href[0] != '/') path_url.href = path.join(encodeURI(state), path_url.href);
					path_url.href = 'http://' + host + path_url.href
				}
				request({ url: path_url.href, timeout: 60000 }, function(error, response, body) {
					if (!error && response.statusCode == 200) {
						callback(0, body);
					} else {
						console.log('load error', error, response?response.statusCode:'', file);
						callback(0, '');
					}
				})
				/*
			} else { // читаем файл
				var filename = path.join(root, path_url.pathname);
				if (new RegExp('^'+root).test(filename)) {
					if (njs) {
						try {
							req.query = path_url.query;
							require(filename).init(req, {writeHead:writeHead, end:end}, null, root);
						} catch(e) {
							console.log('wrong njs ' + filename + ' ' + e);
							callback(0, '');
						}
					} else {
						fs.readFile(filename, 'utf-8', function(err, data) {
							callback(err, data);
						})
					}
				} else {
					console.log('wrong root path')
					callback(0, '');
				}
			}
			*/
		}
		infra.getLayerNode = function(layer, parent_element) {
			if (!parent_element) parent_element = dom;
			var tag = layer.tag;
			if (!tag) {
				infra.log.warning('error set node, where layer.state ' + layer.state);
				return
			}
			var node = false;
			var selector = tag.slice(1);
			if (tag[0] == '#') {
				if (parent_element == dom) {
					node = htmlparser.DomUtils.getElementById(selector, dom);
				} else {
					var child_elements = htmlparser.DomUtils.getElements({ tag_name: function(value) { return value; } }, parent_element);
					for (var i = child_elements.length; --i >= 0;) {
						if (child_elements[i].attribs && (selector == child_elements[i].attribs.id)) node = child_elements[i];
					}
				}
			} else if (tag[0] == '.') {
				node = select(parent_element, tag);
				//node = htmlparser.DomUtils.getElementsByClassName(selector, parent_element);
			} else {
				node = htmlparser.DomUtils.getElementsByTagName(tag, parent_element);
			}
			return node;
		};
		infra.once('end', function() {
			// вставить собранный кэш
			var server_cache = JSON.stringify(infra.load.cache).replace(/\//gim, '\\/');
			//server_cache = server_cache.replace(/\\\//gim, '/')
			var body = htmlparser.DomUtils.getElementsByTagName('body', dom);
			var script = {
				raw: 'script id="infra_server_cache" type="text/javascript"', type: 'script',
				attribs: { id: 'infra_server_cache', type: 'text/javascript' },
				children: [ {
					raw: 'if (window.Infra) { Infra.server = {}; Infra.server.showns = ' + JSON.stringify(getShownLayers(infra.layers)) + ';Infra.server.cache = '+server_cache + ' }',
					type: 'text' } ]
			}
			script.data = script.raw;
			script.name = script.type;
			script.children[0].data = script.children[0].raw;
			appendChild(script, body[0], dom);
			if (infra.title) { innerHTML(infra.title, htmlparser.DomUtils.getElementsByTagName('title', dom)[0], dom); }
			// определить status_code
			if (!infra.status_code) infra.status_code = 200;
			// передать страницу
			cb(infra.status_code, createHtml(dom));
		})
		infra.check(false, 10);
	})
	var parser = new htmlparser.Parser(handler);
	parser.parseComplete(html);
}
module.exports.regExpStr_njs = regExpStr_njs;
module.exports.createHtml = createHtml;
<commit_msg>title and meta tags<commit_after>var fs = require("fs");
var path = require("path");
var url = require("url");
var request = require('request');
var htmlparser = require("htmlparser");
var select = require('soupselect').select;
var emptyTags = [];
for (var prop in htmlparser.DefaultHandler._emptyTags) if (htmlparser.DefaultHandler._emptyTags.hasOwnProperty(prop)) {
	emptyTags.push(prop);
}

var innerHTML = function(html, parent_elem, dom) {
	var _innerHTML = function(dom, dom2) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			if (val == parent_elem) {
				val.children = dom2
				return true
			}
			if (val.children) _innerHTML(val.children, dom2);
		}
	}
	if (emptyTags.indexOf(parent_elem.name) == -1) {
		var handler = new htmlparser.DefaultHandler(function (err, dom2) {
			if (err) {
				console.log(err);
				dom2 = [];
			}
			_innerHTML(dom, dom2);
		});
		var parser = new htmlparser.Parser(handler);
		parser.parseComplete(html);
	}
}

/* Возвращает массив true/false для соответсвующих показанных/непоказанных слоев */
var getShownLayers = function(layers) {
	var shown_layers = [];
	for (var i = layers.length; --i >= 0;) {
		shown_layers[i] = layers[i].show;
	}
	return shown_layers;
}

var appendChild = function(elem, parent_elem, dom) {
	var _appendChild = function(dom) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			if (val == parent_elem) {
				if (val.children) val.children.push(elem);
				else val.children = [elem];
				return true;
			}
			if (val.children) _appendChild(val.children);
		}
	}
	if (emptyTags.indexOf(parent_elem.name) == -1) {
		_appendChild(dom);
	}
}

/* Возвращает html сделанные из dom htmlparser'а */
var createHtml = function(dom) {
	var HTML5 = '';
	var _create = function(dom) {
		for (var i = dom.length; --i >= 0;) {
			var val = dom[i];
			switch (val.type) {
				case 'text':
					HTML5 = val.raw + HTML5;
					break;
				case "tag":
					if (emptyTags.indexOf(val.name) == -1) {
						HTML5 = '</' + val.name + '>' + HTML5;
						if (val.children) _create(val.children);
						HTML5 = '<' + val.raw + '>' + HTML5;
					} else {
						HTML5 = '<' + val.raw + '>' + HTML5;
					}
					break;
				case "script":
				case "style":
					HTML5 = '</' + val.name + '>' + HTML5;
					if (val.children) _create(val.children);
					HTML5 = '<' + val.raw + '>' + HTML5;
					break;
				case "comment":
					HTML5 = '<!--' + val.raw + '-->' + HTML5;
					break;
				case 'directive':
					HTML5 = '<' + val.raw + '>' + HTML5;
					break;
			}
		}
	}
	_create(dom);
	return HTML5;
}

var regExpStr_njs = '(node(_|-)[^/]*/.*\\.)|(\\.n\\.{0,1})js$';

module.exports = function(infra, html, state, req, root, cb) {
	var host = req.headers.host;
	infra.state = state;
	var handler = new htmlparser.DefaultHandler(function (error, dom) {
		if (error) throw error;
		infra.eqLayerNodes = function(node1, node2) {
			if (infra.existLayerNode(node1) && infra.existLayerNode(node2)) {
				var i = node1.length;
				if (i && (i == node2.length)) {
					for (; --i >= 0;) {
						if (node1[i] != node2[i]) return false;
					}
					return true
				} else if (node1 == node2) return true
			}
		}
		infra.pasteNode = function(node, htmlString) {
			if (node.length) {
				for (var n=0, ll=node.length; n<ll; n++) {
					innerHTML(htmlString, node[n], dom);
				}
			} else {
				innerHTML(htmlString, node, dom);
			}
		};
		infra.load._load = function(file, callback) {
			var writeHead = function(){};
			var end = function(data){callback(0,data)};
			var path_url = url.parse(encodeURI(file), true);
			path_url.pathname = decodeURI(path_url.pathname);
			//path_url.href = decodeURI(path_url.href);
			path_url.search = decodeURI(path_url.search);
			// var njs = new RegExp('([^/]+/node-[^/]+/[^/]+\.js)|(/[^/]+\.njs)$').test(path_url.pathname);
			//var njs = /(node(_|\-)[^\/]*\/.*\.)|(\.n\.{0,1})js$/gi.test(path_url.pathname)
			var njs = new RegExp(regExpStr_njs, 'gi').test(path_url.pathname);

			//if (path_url.host || (!njs && path_url.search)) { // загружаем через веб
				if (!path_url.host) {
					if (path_url.href[0] != '/') path_url.href = path.join(encodeURI(state), path_url.href);
					path_url.href = 'http://' + host + path_url.href
				}
				request({ url: path_url.href, timeout: 60000 }, function(error, response, body) {
					if (!error && response.statusCode == 200) {
						callback(0, body);
					} else {
						console.log('load error', error, response?response.statusCode:'', file);
						callback(0, '');
					}
				})
				/*
			} else { // читаем файл
				var filename = path.join(root, path_url.pathname);
				if (new RegExp('^'+root).test(filename)) {
					if (njs) {
						try {
							req.query = path_url.query;
							require(filename).init(req, {writeHead:writeHead, end:end}, null, root);
						} catch(e) {
							console.log('wrong njs ' + filename + ' ' + e);
							callback(0, '');
						}
					} else {
						fs.readFile(filename, 'utf-8', function(err, data) {
							callback(err, data);
						})
					}
				} else {
					console.log('wrong root path')
					callback(0, '');
				}
			}
			*/
		}
		infra.getLayerNode = function(layer, parent_element) {
			if (!parent_element) parent_element = dom;
			var tag = layer.tag;
			if (!tag) {
				infra.log.warning('error set node, where layer.state ' + layer.state);
				return
			}
			var node = false;
			var selector = tag.slice(1);
			if (tag[0] == '#') {
				if (parent_element == dom) {
					node = htmlparser.DomUtils.getElementById(selector, dom);
				} else {
					var child_elements = htmlparser.DomUtils.getElements({ tag_name: function(value) { return value; } }, parent_element);
					for (var i = child_elements.length; --i >= 0;) {
						if (child_elements[i].attribs && (selector == child_elements[i].attribs.id)) node = child_elements[i];
					}
				}
			} else if (tag[0] == '.') {
				node = select(parent_element, tag);
				//node = htmlparser.DomUtils.getElementsByClassName(selector, parent_element);
			} else {
				node = htmlparser.DomUtils.getElementsByTagName(tag, parent_element);
			}
			return node;
		};
		infra.once('end', function() {
			// вставить собранный кэш
			var server_cache = JSON.stringify(infra.load.cache).replace(/\//gim, '\\/');
			//server_cache = server_cache.replace(/\\\//gim, '/')
			var body = htmlparser.DomUtils.getElementsByTagName('body', dom);
			var script = {
				raw: 'script id="infra_server_cache" type="text/javascript"', type: 'script',
				attribs: { id: 'infra_server_cache', type: 'text/javascript' },
				children: [ {
					raw: 'if (window.Infra) { Infra.server = {}; Infra.server.showns = ' + JSON.stringify(getShownLayers(infra.layers)) + ';Infra.server.cache = '+server_cache + ' }',
					type: 'text' } ]
			}
			script.data = script.raw;
			script.name = script.type;
			script.children[0].data = script.children[0].raw;
			appendChild(script, body[0], dom);
			if (infra.title) { innerHTML(infra.title, htmlparser.DomUtils.getElementsByTagName('title', dom)[0], dom); }
			if (infra.meta) {
				var updateMeta = function(metatags, attr, head) {
					var update = false;
					var cnt; for (cnt = 0; cnt < metatags.length; cnt++) {
						var name = metatags[cnt].attribs["name"];
						if (name) {
							name = name.toLowerCase();
							if (name == attr) {
								update = true;
								name.attribs["content"] = infra.meta[attr];
							}
						}
					}
					if (!update) { // создаем новый
						var meta = {
							raw: 'meta name="'+attr+'" content="'+infra.meta[attr]+'"',
							type: 'tag',
							name: 'meta',
							attribs: { name: attr, content: infra.meta[attr] }
						}
						meta.data = meta.raw;
						appendChild(meta, head[0], dom);
					}
				};
				var metatags = htmlparser.DomUtils.getElementsByTagName('meta', dom);
				var head = htmlparser.DomUtils.getElementsByTagName('head', dom);
				if (infra.meta.keywords) { updateMeta(metatags, 'keywords', head); }
				if (infra.meta.description) { updateMeta(metatags, 'description', head); }
			}
			// определить status_code
			if (!infra.status_code) infra.status_code = 200;
			// передать страницу
			cb(infra.status_code, createHtml(dom));
		})
		infra.check(false, 10);
	})
	var parser = new htmlparser.Parser(handler);
	parser.parseComplete(html);
}
module.exports.regExpStr_njs = regExpStr_njs;
module.exports.createHtml = createHtml;
<|endoftext|>


<commit_before>var React = require('react');
var ReactDOM = require('react-dom');
var reactElement = React.createElement('h1');
ReactDOM.render(reactElement, document.getElementById('react-application'));
<commit_msg>Playing with React Elements<commit_after>var React = require('react');
var ReactDOM = require('react-dom');

var h1 = React.createElement('h1', {className: 'header', key: 'header'}, 'This is React');
var p = React.createElement('p', {className: 'content', key: 'content'}, 'And this is how it works');
var reactFragment = [h1, p];
var section = React.createElement('section', {className: 'container'}, reactFragment);

ReactDOM.render(section, document.getElementById('react-application'));
<|endoftext|>