<commit_before>import config from './config';
import logger from './utils/logger';

import Queue from 'bull';
import { getStatsDClient } from './utils/statsd';

const queueSettings = {
    lockDuration: 60000,
    lockRenewTime: 15000,
    stalledInterval: 75000,
    maxStalledCount: 2,
    guardInterval: 3500,
};

export const rssQueue = new Queue('rss', config.cache.uri, {
	settings: queueSettings,
});
export const ogQueue = new Queue('og', config.cache.uri, {
	settings: queueSettings,
});
export const podcastQueue = new Queue('podcast', config.cache.uri, {
	settings: queueSettings,
});
export const streamQueue = new Queue('stream', config.cache.uri, {
	limiter: { max: 12000, duration: 3600000 }, // 12k per hour
	settings: queueSettings,
});
export const socialQueue = new Queue('social', config.cache.uri, {
	settings: queueSettings,
});

function makeMetricKey(queue, event) {
	return ['winds', 'bull', queue.name, event].join('.');
}

async function trackQueueSize(statsd, queue) {
	let queueStatus = await queue.getJobCounts();
	statsd.gauge(makeMetricKey(queue, 'waiting'), queueStatus.waiting);
	statsd.gauge(makeMetricKey(queue, 'active'), queueStatus.active);
}

function AddQueueTracking(queue) {
	var statsd = getStatsDClient();

	queue.on('error', function(err) {
		statsd.increment(makeMetricKey(queue, 'error'));
		logger.warn(`Queue ${queue.name} encountered an unexpected error: ${err.message}`);
	});

	queue.on('active', function(job, jobPromise) {
		statsd.increment(makeMetricKey(queue, 'active'));
	});

	queue.on('completed', function(job, result) {
		statsd.timing(makeMetricKey(queue, 'elapsed'), new Date() - job.timestamp);
		statsd.increment(makeMetricKey(queue, 'completed'));
	});

	queue.on('stalled', function(job) {
		statsd.increment(makeMetricKey(queue, 'stalled'));
		logger.warn(`Queue ${queue.name} job stalled: '${JSON.stringify(job)}'`);
	});

	queue.on('failed', function(job, err) {
		statsd.increment(makeMetricKey(queue, 'failed'));
		logger.warn(`Queue ${queue.name} failed to process job '${JSON.stringify(job)}': ${err.message}`);
	});

	queue.on('paused', function() {
		statsd.increment(makeMetricKey(queue, 'paused'));
	});

	queue.on('resumed', function(job) {
		statsd.increment(makeMetricKey(queue, 'resumed'));
	});

	setInterval(trackQueueSize, 30000, statsd, queue);
}

const currentEnvironment = process.env.NODE_ENV || 'development';
if (currentEnvironment !== 'test') {
	AddQueueTracking(rssQueue);
	AddQueueTracking(ogQueue);
	AddQueueTracking(podcastQueue);
	AddQueueTracking(streamQueue);
	AddQueueTracking(socialQueue);
};

export const RssQueueAdd = rssQueue.add.bind(rssQueue);
export const OgQueueAdd = ogQueue.add.bind(ogQueue);
export const PodcastQueueAdd = podcastQueue.add.bind(podcastQueue);
export const StreamQueueAdd = podcastQueue.add.bind(streamQueue);
export const SocialQueueAdd = podcastQueue.add.bind(socialQueue);

export function ProcessRssQueue() {
	getStatsDClient().increment(makeMetricKey(rssQueue, 'started'));
	return rssQueue.process(...arguments);
}

export function ProcessOgQueue() {
	getStatsDClient().increment(makeMetricKey(ogQueue, 'started'));
	return ogQueue.process(...arguments);
}

export function ProcessPodcastQueue() {
	getStatsDClient().increment(makeMetricKey(podcastQueue, 'started'));
	return podcastQueue.process(...arguments);
}

export function ProcessStreamQueue() {
	getStatsDClient().increment(makeMetricKey(streamQueue, 'started'));
	return streamQueue.process(...arguments);
}

export function ProcessSocialQueue() {
	getStatsDClient().increment(makeMetricKey(socialQueue, 'started'));
	return socialQueue.process(...arguments);
}

export function ShutDownRssQueue() {
	getStatsDClient().increment(makeMetricKey(rssQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownPodcastQueue() {
	getStatsDClient().increment(makeMetricKey(podcastQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownOgQueue() {
	getStatsDClient().increment(makeMetricKey(ogQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownSocialQueue() {
	getStatsDClient().increment(makeMetricKey(socialQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownStreamQueue() {
	getStatsDClient().increment(makeMetricKey(streamQueue, 'stopped'));
	return socialQueue.close(...arguments);
}
<commit_msg>Increase lock duration in an attempt to reduce amount of stalled jobs due to high CPU usage<commit_after>import config from './config';
import logger from './utils/logger';

import Queue from 'bull';
import { getStatsDClient } from './utils/statsd';

export const rssQueue = new Queue('rss', config.cache.uri, {
	settings: {
		lockDuration: 90000,
		stalledInterval: 75000,
		maxStalledCount: 2
	}
});
export const ogQueue = new Queue('og', config.cache.uri, {
	settings: {
		lockDuration: 90000,
		stalledInterval: 75000,
		maxStalledCount: 2
	}
});
export const podcastQueue = new Queue('podcast', config.cache.uri, {
	settings: {
		lockDuration: 90000,
		stalledInterval: 75000,
		maxStalledCount: 2
	}
});
export const streamQueue = new Queue('stream', config.cache.uri, {
	limiter: { max: 12000, duration: 3600000 } // 12k per hour
});
export const socialQueue = new Queue('social', config.cache.uri);

function makeMetricKey(queue, event) {
	return ['winds', 'bull', queue.name, event].join('.');
}

async function trackQueueSize(statsd, queue) {
	let queueStatus = await queue.getJobCounts();
	statsd.gauge(makeMetricKey(queue, 'waiting'), queueStatus.waiting);
	statsd.gauge(makeMetricKey(queue, 'active'), queueStatus.active);
}

function AddQueueTracking(queue) {
	var statsd = getStatsDClient();

	queue.on('error', function(err) {
		statsd.increment(makeMetricKey(queue, 'error'));
		logger.warn(`Queue ${queue.name} encountered an unexpected error: ${err.message}`);
	});

	queue.on('active', function(job, jobPromise) {
		statsd.increment(makeMetricKey(queue, 'active'));
	});

	queue.on('completed', function(job, result) {
		statsd.timing(makeMetricKey(queue, 'elapsed'), new Date() - job.timestamp);
		statsd.increment(makeMetricKey(queue, 'completed'));
	});

	queue.on('stalled', function(job) {
		statsd.increment(makeMetricKey(queue, 'stalled'));
		logger.warn(`Queue ${queue.name} job stalled: '${JSON.stringify(job)}'`);
	});

	queue.on('failed', function(job, err) {
		statsd.increment(makeMetricKey(queue, 'failed'));
		logger.warn(`Queue ${queue.name} failed to process job '${JSON.stringify(job)}': ${err.message}`);
	});

	queue.on('paused', function() {
		statsd.increment(makeMetricKey(queue, 'paused'));
	});

	queue.on('resumed', function(job) {
		statsd.increment(makeMetricKey(queue, 'resumed'));
	});

	setInterval(trackQueueSize, 30000, statsd, queue);
}

const currentEnvironment = process.env.NODE_ENV || 'development';
if (currentEnvironment !== 'test') {
	AddQueueTracking(rssQueue);
	AddQueueTracking(ogQueue);
	AddQueueTracking(podcastQueue);
	AddQueueTracking(streamQueue);
	AddQueueTracking(socialQueue);
};

export const RssQueueAdd = rssQueue.add.bind(rssQueue);
export const OgQueueAdd = ogQueue.add.bind(ogQueue);
export const PodcastQueueAdd = podcastQueue.add.bind(podcastQueue);
export const StreamQueueAdd = podcastQueue.add.bind(streamQueue);
export const SocialQueueAdd = podcastQueue.add.bind(socialQueue);

export function ProcessRssQueue() {
	getStatsDClient().increment(makeMetricKey(rssQueue, 'started'));
	return rssQueue.process(...arguments);
}

export function ProcessOgQueue() {
	getStatsDClient().increment(makeMetricKey(ogQueue, 'started'));
	return ogQueue.process(...arguments);
}

export function ProcessPodcastQueue() {
	getStatsDClient().increment(makeMetricKey(podcastQueue, 'started'));
	return podcastQueue.process(...arguments);
}

export function ProcessStreamQueue() {
	getStatsDClient().increment(makeMetricKey(streamQueue, 'started'));
	return streamQueue.process(...arguments);
}

export function ProcessSocialQueue() {
	getStatsDClient().increment(makeMetricKey(socialQueue, 'started'));
	return socialQueue.process(...arguments);
}

export function ShutDownRssQueue() {
	getStatsDClient().increment(makeMetricKey(rssQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownPodcastQueue() {
	getStatsDClient().increment(makeMetricKey(podcastQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownOgQueue() {
	getStatsDClient().increment(makeMetricKey(ogQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownSocialQueue() {
	getStatsDClient().increment(makeMetricKey(socialQueue, 'stopped'));
	return socialQueue.close(...arguments);
}

export function ShutDownStreamQueue() {
	getStatsDClient().increment(makeMetricKey(streamQueue, 'stopped'));
	return socialQueue.close(...arguments);
}
<|endoftext|>


<commit_before>var extend = require('lodash.assign');
var mutators = require('./mutators.js');

/**
 * Creates a `query` object which encapsulates the state of the query to be generated
 * and provides the methods to manipulate that query.
 *
 * @name queryize
 * @typedef queryize
 * @constructor
 * @param  {query|Object} [original] An existing query object to duplicate.
 * @return {query} Returns a `query` instance.
 * @example
 * var queryize = require('queryize');
 * var query = queryize();
 */
var queryize = function (original) {

	var query = Object.create(mutators);
	query._constructor = queryize;
	query._isQueryizeObject = true;
	query._attributes = {
		debugEnabled: false,
		database: false,
		tableName: false,
		tableAlias: false,
		dataBindings: {},
		useBoundParameters: queryize.useBoundParameters,
		where: [],
		whereBoolean: ' AND ',
		set: [],
		columns: ['*'],
		joins: [],
		orderBy: false,
		groupBy: false,
		distinct: false,
		limit: false,
		builder: false
	};

	if (original) {
		if (original._isQueryizeObject) {
			extend(query._attributes, original.export());
		} else if (typeof original === 'object') {
			extend(query._attributes, original);
		}
	}

	return query;

};

/**
 * Shortcut for creating a new select query
 *
 * See `query.select()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.select = function () {
	var q = queryize();
	q.select.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new update query
 *
 * See `query.update()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.update = function () {
	var q = queryize();
	q.update.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new insert query
 *
 * See `query.insert()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.insert = function () {
	var q = queryize();
	q.insert.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new delete query
 *
 * See `query.select()` for details.
 *
 * @static
 * @memberOf queryize
 * @name delete
 * @alias deleteFrom
 * @return {query} Returns a `query` instance.
 */
queryize.delete = function () {
	var q = queryize();
	q.deleteFrom.apply(q, arguments);
	return q;
};

queryize.deleteFrom = queryize.delete;

/**
 * Globally controls if new queries will use bound params by default.
 * @memberOf queryize
 * @name useBoundParameters
 * @abstract
 * @type {Boolean}
 * @example
 * //disable bound params. This is not recommended
 * queryize.useBoundParameters = false;
 */
queryize.useBoundParameters = true;

/**
 * Public access point for adding functions to query objects
 * @memberOf queryize
 * @abstract
 * @type {Object}
 * @example
 * queryize.fn.someNewFunction = function () {
 *   //`this` is the current query, use `this._attributes` to store query parameters
 * };
 */
queryize.fn = mutators;

module.exports = queryize;

<commit_msg>Incorrect attribute name in defaults.<commit_after>var extend = require('lodash.assign');
var mutators = require('./mutators.js');

/**
 * Creates a `query` object which encapsulates the state of the query to be generated
 * and provides the methods to manipulate that query.
 *
 * @name queryize
 * @typedef queryize
 * @constructor
 * @param  {query|Object} [original] An existing query object to duplicate.
 * @return {query} Returns a `query` instance.
 * @example
 * var queryize = require('queryize');
 * var query = queryize();
 */
var queryize = function (original) {

	var query = Object.create(mutators);
	query._constructor = queryize;
	query._isQueryizeObject = true;
	query._attributes = {
		debugEnabled: false,
		database: false,
		tableName: false,
		alias: false,
		dataBindings: {},
		useBoundParameters: queryize.useBoundParameters,
		where: [],
		whereBoolean: ' AND ',
		set: [],
		columns: ['*'],
		joins: [],
		orderBy: false,
		groupBy: false,
		distinct: false,
		limit: false,
		builder: false
	};

	if (original) {
		if (original._isQueryizeObject) {
			extend(query._attributes, original.export());
		} else if (typeof original === 'object') {
			extend(query._attributes, original);
		}
	}

	return query;

};

/**
 * Shortcut for creating a new select query
 *
 * See `query.select()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.select = function () {
	var q = queryize();
	q.select.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new update query
 *
 * See `query.update()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.update = function () {
	var q = queryize();
	q.update.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new insert query
 *
 * See `query.insert()` for details.
 *
 * @static
 * @memberOf queryize
 * @return {query} Returns a `query` instance.
 */
queryize.insert = function () {
	var q = queryize();
	q.insert.apply(q, arguments);
	return q;
};

/**
 * Shortcut for creating a new delete query
 *
 * See `query.select()` for details.
 *
 * @static
 * @memberOf queryize
 * @name delete
 * @alias deleteFrom
 * @return {query} Returns a `query` instance.
 */
queryize.delete = function () {
	var q = queryize();
	q.deleteFrom.apply(q, arguments);
	return q;
};

queryize.deleteFrom = queryize.delete;

/**
 * Globally controls if new queries will use bound params by default.
 * @memberOf queryize
 * @name useBoundParameters
 * @abstract
 * @type {Boolean}
 * @example
 * //disable bound params. This is not recommended
 * queryize.useBoundParameters = false;
 */
queryize.useBoundParameters = true;

/**
 * Public access point for adding functions to query objects
 * @memberOf queryize
 * @abstract
 * @type {Object}
 * @example
 * queryize.fn.someNewFunction = function () {
 *   //`this` is the current query, use `this._attributes` to store query parameters
 * };
 */
queryize.fn = mutators;

module.exports = queryize;

<|endoftext|>


<commit_before>const router = require('express').Router();
const co = require('co');
const coForEach = require('co-foreach');
const dbX = require('../../db');

router.get('/', (req, res) => {
  co(function*() {
    const db = yield dbX.dbPromise;
    const docs = yield db.collection('versions').find({}).toArray();
    res.send(docs);
  }).catch((err) => {
    return res.status(500).json(err.stack);
  })
});

router.post('/compare', (req, res) => {
  if (!req.body || !req.body.versions) {return res.status(400).json({
    message: 'No data provided.'
  })}
  const versions = req.body.versions;
  const collections = Object.keys(versions);
  const compareResult = {};
  co(function*() {
    const db = yield dbX.dbPromise;
    const serverVersions = yield db.collection('versions').find({}).toArray();

    yield coForEach(collections, function*(collection) {
      const serverVersion = serverVersions.find(sv => sv.collection === collection)['version'];
      const clientVersion = versions[collection];
      if (serverVersion === clientVersion) {
        compareResult[collection] = {
          same: true
        }
      } else {
        const newData = yield db.collection(collection).find({}).toArray();
        compareResult[collection] = {
          same: false,
          newData,
          newVersion: serverVersion
        }
      }
    })

    res.json(compareResult)

  }).catch((err) => {
    return res.status(500).json(err.stack);
  })

  // compare version and return hash like
  // {collectionName: {same: boolean, newData: any, newVersion: string}}

})

module.exports = router;
<commit_msg>minor change: renaming versions to versionHash in api/versions/compare<commit_after>const router = require('express').Router();
const co = require('co');
const coForEach = require('co-foreach');
const dbX = require('../../db');

router.get('/', (req, res) => {
  co(function*() {
    const db = yield dbX.dbPromise;
    const docs = yield db.collection('versions').find({}).toArray();
    res.send(docs);
  }).catch((err) => {
    return res.status(500).json(err.stack);
  })
});

router.post('/compare', (req, res) => {
  if (!req.body || !req.body.versionHash) {return res.status(400).json({
    message: 'No data provided.'
  })}
  const versionHash = req.body.versionHash;
  const collections = Object.keys(versionHash);
  const compareResult = {};
  co(function*() {
    const db = yield dbX.dbPromise;
    const serverVersions = yield db.collection('versions').find({}).toArray();

    yield coForEach(collections, function*(collection) {
      const serverVersion = serverVersions.find(sv => sv.collection === collection)['version'];
      const clientVersion = versionHash[collection];
      if (serverVersion === clientVersion) {
        compareResult[collection] = {
          same: true
        }
      } else {
        const newData = yield db.collection(collection).find({}).toArray();
        compareResult[collection] = {
          same: false,
          newData,
          newVersion: serverVersion
        }
      }
    })

    res.json(compareResult)

  }).catch((err) => {
    return res.status(500).json(err.stack);
  })

  // compare version and return hash like
  // {collectionName: {same: boolean, newData: any, newVersion: string}}

})

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

const fsExtra = require('fs-extra');

// lazy requires
let express;

let constructed;

module.exports = (XIBLE, EXPRESS_APP) => {
  class NodePack {
    constructor(obj = {}) {
      this.name = obj.name;
      this.path = obj.path;
      this.version = obj.version;
      this.nodes = obj.nodes || [];
      this.installedByDefault = !!obj.installedByDefault;

      if (constructed) {
        constructed[this.name] = this;
      }
    }

    static getBaseName(nodePackName) {
      nodePackName = nodePackName.toLowerCase();
      if (nodePackName.substring(0, 15) === 'xible-nodepack-') {
        nodePackName = nodePackName.substring(15);
      } else if (nodePackName.substring(0, 9) === 'xible-np-') {
        nodePackName = nodePackName.substring(9);
      }

      return nodePackName;
    }

    static get DEFAULT_NODEPACK_NAMES() {
      return [
        'xible-np-xible',
        'xible-np-core',
        'xible-np-compare',
        'xible-np-console',
        'xible-np-input',
        'xible-np-object',
        'xible-np-string',
        'xible-nodepack-math',
        'xible-nodepack-stream',
        'xible-nodepack-filesystem',
        'xible-nodepack-process',
        'xible-nodepack-timing'
      ];
    }

    /**
     * Returns a map with all nodepacks installed by default.
     * These nodepacks are within the node_modules directory of Xible,
     * And specified in the package.json.
     */
    static getDefault() {
      const nodePacks = {};
      this.DEFAULT_NODEPACK_NAMES.forEach((defaultNodePackName) => {
        const baseName = this.getBaseName(defaultNodePackName);
        nodePacks[baseName] = this.getOneByPath(`${__dirname}/../../node_modules/${defaultNodePackName}`, baseName);
        nodePacks[baseName].installedByDefault = true;
      });

      return nodePacks;
    }

    static getOneByPath(path, nodePackName) {
      if (!fsExtra.statSync(path).isDirectory()) {
        return null;
      }

      const packageJsonPath = `${path}/package.json`;
      if (!fsExtra.existsSync(packageJsonPath)) {
        return null;
      }

      let packageJson;
      try {
        packageJson = require(packageJsonPath);
      } catch (err) {
        console.error(err);
        return null;
      }

      return new NodePack({
        name: nodePackName,
        version: packageJson.version,
        path
      });
    }

    static getByPath(nodesPath) {
      const nodePacks = {};
      const nodePackDirs = fsExtra.readdirSync(nodesPath);

      for (let i = 0; i < nodePackDirs.length; i += 1) {
        const nodePack = this.getOneByPath(`${nodesPath}/${nodePackDirs[i]}`, nodePackDirs[i]);
        if (!nodePack) {
          continue;
        }

        nodePacks[nodePack.name] = nodePack;
      }

      return nodePacks;
    }

    static async getAll() {
      if (constructed) {
        return constructed;
      }

      let nodesPath = XIBLE.Config.getValue('nodes.path');
      if (!nodesPath) {
        throw new Error('need a "nodes.path" in the configuration to load the installed nodes from');
      }
      nodesPath = XIBLE.resolvePath(nodesPath);

      // Check that nodePath exists. Try to create the path if it does not exist.
      if (!fsExtra.existsSync(nodesPath)) {
        console.error(`creating "${nodesPath}"`);

        try {
          fsExtra.mkdirSync(nodesPath);
        } catch (err) {
          console.error(`creation of "${nodesPath}" failed: `, err);
        }
        return {};
      }

      const nodePacks = this.getDefault();
      Object.assign(nodePacks, this.getByPath(`${__dirname}/../../nodes`));
      Object.assign(nodePacks, this.getByPath(nodesPath));

      constructed = nodePacks;

      return nodePacks;
    }

    /**
     * Fetches a nodePack by the given name,
     * @param {String} name
     * @returns {Promise.<NodePack|null>}
     */
    static async getByName(name) {
      const nodePacks = await this.getAll();
      return nodePacks[name];
    }

    getNodeStructures() {
      return XIBLE.Node.getStructures(this.path);
    }

    /**
     * Initializes all nodes and typedefs found within the path of this nodepack, recursively.
     * Runs Node.getStructures() on that path, and hosting editor contents if applicable.
     * Throws when run from a worker.
     * @param {String} nodePath Path to the directory containting the nodes.
     * If the directory does not exist, it will be created.
     * @returns {Promise.<Object>}
     * @private
     */
    async initNodes() {
      if (XIBLE.child) {
        throw new Error('Cannot call Node.initFromPath() from worker');
      }

      if (!XIBLE.child && !express) {
        express = require('express');
      }

      const structures = await this.getNodeStructures();

      // Store the typedefs.
      for (const typeDefName in structures.typedefs) {
        structures.typedefs[typeDefName].name = typeDefName;
        XIBLE.TypeDef.add(structures.typedefs[typeDefName]);
      }

      /* Store the nodes.
       * The nodes are not constructed, only the plain object is stored here.
       * FlowInstances will construct the necessary nodes when that flowInstance is started.
       * Editor details are hosted here.
       */
      for (const nodeName in structures.nodes) {
        const structure = structures.nodes[nodeName];

        // Create default typeDefs for unknown input types.
        if (structure.inputs) {
          for (const inputName in structure.inputs) {
            const input = structure.inputs[inputName];
            if (typeof input.type === 'string' && input.type !== 'trigger' && !XIBLE.TypeDef.getByName(input.type)) {
              // nodeDebug(`creating default typedef for "${input.type}"`);
              structures.typedefs[input.type] = { name: input.type };
              XIBLE.TypeDef.add(structures.typedefs[input.type]);
              break;
            }
          }
        }

        // Create default typeDefs for unknown output types.
        if (structure.outputs) {
          for (const outputName in structure.outputs) {
            const output = structure.outputs[outputName];
            if (typeof output.type === 'string' && output.type !== 'trigger' && !XIBLE.TypeDef.getByName(output.type)) {
              // nodeDebug(`creating default typedef for "${output.type}"`);
              structures.typedefs[output.type] = { name: output.type };
              XIBLE.TypeDef.add(structures.typedefs[output.type]);
              break;
            }
          }
        }

        // Host editor contents if applicable
        if (structure.editorContentPath) {
          structure.hostsEditorContent = true;

          EXPRESS_APP.use(`/api/nodes/${nodeName}/editor`, express.static(structure.editorContentPath, {
            index: false
          }));
        }

        this.nodes.push(structure);
        XIBLE.addNode(structure);
      }
    }

    /**
     * Removes the nodePack from the XIBLE installation.
     * @returns {Promise.<NodePack>} Returns the nodePack itself.
     * The path parameter will be set to null.
     */
    async remove() {
      if (!this.path || !fsExtra.statSync(this.path).isDirectory()) {
        throw new Error(`nodepack "${this.name}" is not installed`);
      }

      fsExtra.removeSync(this.path);
      this.path = null;
      return this;
    }
  }

  if (EXPRESS_APP) {
    require('./routes.js')(NodePack, XIBLE, EXPRESS_APP);
  }

  return {
    NodePack
  };
};
<commit_msg>don't die if base nodepack isn't installed<commit_after>'use strict';

const fsExtra = require('fs-extra');

// lazy requires
let express;

let constructed;

module.exports = (XIBLE, EXPRESS_APP) => {
  class NodePack {
    constructor(obj = {}) {
      this.name = obj.name;
      this.path = obj.path;
      this.version = obj.version;
      this.nodes = obj.nodes || [];
      this.installedByDefault = !!obj.installedByDefault;

      if (constructed) {
        constructed[this.name] = this;
      }
    }

    static getBaseName(nodePackName) {
      nodePackName = nodePackName.toLowerCase();
      if (nodePackName.substring(0, 15) === 'xible-nodepack-') {
        nodePackName = nodePackName.substring(15);
      } else if (nodePackName.substring(0, 9) === 'xible-np-') {
        nodePackName = nodePackName.substring(9);
      }

      return nodePackName;
    }

    static get DEFAULT_NODEPACK_NAMES() {
      return [
        'xible-np-xible',
        'xible-np-core',
        'xible-np-compare',
        'xible-np-console',
        'xible-np-input',
        'xible-np-object',
        'xible-np-string',
        'xible-nodepack-math',
        'xible-nodepack-stream',
        'xible-nodepack-filesystem',
        'xible-nodepack-process',
        'xible-nodepack-timing'
      ];
    }

    /**
     * Returns a map with all nodepacks installed by default.
     * These nodepacks are within the node_modules directory of Xible,
     * And specified in the package.json.
     */
    static getDefault() {
      const nodePacks = {};
      this.DEFAULT_NODEPACK_NAMES.forEach((defaultNodePackName) => {
        const baseName = this.getBaseName(defaultNodePackName);
        const nodePack = this.getOneByPath(`${__dirname}/../../node_modules/${defaultNodePackName}`, baseName);
        if (nodePack) {
          nodePacks[baseName] = nodePack;
          nodePacks[baseName].installedByDefault = true;
        }
      });

      return nodePacks;
    }

    static getOneByPath(path, nodePackName) {
      if (
        !fsExtra.existsSync(path) ||
        !fsExtra.statSync(path).isDirectory()
      ) {
        return null;
      }

      const packageJsonPath = `${path}/package.json`;
      if (!fsExtra.existsSync(packageJsonPath)) {
        return null;
      }

      let packageJson;
      try {
        packageJson = require(packageJsonPath);
      } catch (err) {
        console.error(err);
        return null;
      }

      return new NodePack({
        name: nodePackName,
        version: packageJson.version,
        path
      });
    }

    static getByPath(nodesPath) {
      const nodePacks = {};
      const nodePackDirs = fsExtra.readdirSync(nodesPath);

      for (let i = 0; i < nodePackDirs.length; i += 1) {
        const nodePack = this.getOneByPath(`${nodesPath}/${nodePackDirs[i]}`, nodePackDirs[i]);
        if (!nodePack) {
          continue;
        }

        nodePacks[nodePack.name] = nodePack;
      }

      return nodePacks;
    }

    static async getAll() {
      if (constructed) {
        return constructed;
      }

      let nodesPath = XIBLE.Config.getValue('nodes.path');
      if (!nodesPath) {
        throw new Error('need a "nodes.path" in the configuration to load the installed nodes from');
      }
      nodesPath = XIBLE.resolvePath(nodesPath);

      // Check that nodePath exists. Try to create the path if it does not exist.
      if (!fsExtra.existsSync(nodesPath)) {
        console.error(`creating "${nodesPath}"`);

        try {
          fsExtra.mkdirSync(nodesPath);
        } catch (err) {
          console.error(`creation of "${nodesPath}" failed: `, err);
        }
        return {};
      }

      const nodePacks = this.getDefault();
      Object.assign(nodePacks, this.getByPath(`${__dirname}/../../nodes`));
      Object.assign(nodePacks, this.getByPath(nodesPath));

      constructed = nodePacks;

      return nodePacks;
    }

    /**
     * Fetches a nodePack by the given name,
     * @param {String} name
     * @returns {Promise.<NodePack|null>}
     */
    static async getByName(name) {
      const nodePacks = await this.getAll();
      return nodePacks[name];
    }

    getNodeStructures() {
      return XIBLE.Node.getStructures(this.path);
    }

    /**
     * Initializes all nodes and typedefs found within the path of this nodepack, recursively.
     * Runs Node.getStructures() on that path, and hosting editor contents if applicable.
     * Throws when run from a worker.
     * @param {String} nodePath Path to the directory containting the nodes.
     * If the directory does not exist, it will be created.
     * @returns {Promise.<Object>}
     * @private
     */
    async initNodes() {
      if (XIBLE.child) {
        throw new Error('Cannot call Node.initFromPath() from worker');
      }

      if (!XIBLE.child && !express) {
        express = require('express');
      }

      const structures = await this.getNodeStructures();

      // Store the typedefs.
      for (const typeDefName in structures.typedefs) {
        structures.typedefs[typeDefName].name = typeDefName;
        XIBLE.TypeDef.add(structures.typedefs[typeDefName]);
      }

      /* Store the nodes.
       * The nodes are not constructed, only the plain object is stored here.
       * FlowInstances will construct the necessary nodes when that flowInstance is started.
       * Editor details are hosted here.
       */
      for (const nodeName in structures.nodes) {
        const structure = structures.nodes[nodeName];

        // Create default typeDefs for unknown input types.
        if (structure.inputs) {
          for (const inputName in structure.inputs) {
            const input = structure.inputs[inputName];
            if (typeof input.type === 'string' && input.type !== 'trigger' && !XIBLE.TypeDef.getByName(input.type)) {
              // nodeDebug(`creating default typedef for "${input.type}"`);
              structures.typedefs[input.type] = { name: input.type };
              XIBLE.TypeDef.add(structures.typedefs[input.type]);
              break;
            }
          }
        }

        // Create default typeDefs for unknown output types.
        if (structure.outputs) {
          for (const outputName in structure.outputs) {
            const output = structure.outputs[outputName];
            if (typeof output.type === 'string' && output.type !== 'trigger' && !XIBLE.TypeDef.getByName(output.type)) {
              // nodeDebug(`creating default typedef for "${output.type}"`);
              structures.typedefs[output.type] = { name: output.type };
              XIBLE.TypeDef.add(structures.typedefs[output.type]);
              break;
            }
          }
        }

        // Host editor contents if applicable
        if (structure.editorContentPath) {
          structure.hostsEditorContent = true;

          EXPRESS_APP.use(`/api/nodes/${nodeName}/editor`, express.static(structure.editorContentPath, {
            index: false
          }));
        }

        this.nodes.push(structure);
        XIBLE.addNode(structure);
      }
    }

    /**
     * Removes the nodePack from the XIBLE installation.
     * @returns {Promise.<NodePack>} Returns the nodePack itself.
     * The path parameter will be set to null.
     */
    async remove() {
      if (!this.path || !fsExtra.statSync(this.path).isDirectory()) {
        throw new Error(`nodepack "${this.name}" is not installed`);
      }

      fsExtra.removeSync(this.path);
      this.path = null;
      return this;
    }
  }

  if (EXPRESS_APP) {
    require('./routes.js')(NodePack, XIBLE, EXPRESS_APP);
  }

  return {
    NodePack
  };
};
<|endoftext|>


<commit_before>'use strict';

module.exports = (XIBLE, EXPRESS_APP) => {
  const XibleRegistryWrapper = require('xible-registry-wrapper');
  const fsExtra = require('fs-extra');
  const os = require('os');

  const registryUrl = XIBLE.Config.getValue('registry.url');
  if (!registryUrl) {
    throw new Error('"registry.url" not found in config');
  }

  const xibleRegistry = new XibleRegistryWrapper(registryUrl);

  // the tmp path for downloading this node
  const TMP_REGISTRY_DIR = `${os.tmpdir() || '/tmp'}/xibleRegistry-`;
  console.log(os.tmpdir());

  function cleanUp(tmpRegDir) {
    if (!tmpRegDir) {
      return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
      // remove the tmp dir
      fsExtra.remove(tmpRegDir, (err) => {
        if (err) {
          reject(err);
          return;
        }

        resolve();
      });
    });
  }

  /**
  * Installs a flow from a registry.
  * @param {String} altName The name to publish the flow with. Defaults to the flow name.
  * @returns {Promise}
  */
  xibleRegistry.Flow.prototype.install = function flowInstall(altName) {
    if (!XIBLE.Config.getValue('registry.flows.allowinstall')) {
      return Promise.reject('Your config does not allow to install flows from the registry');
    }

    let flowPath = XIBLE.Config.getValue('flows.path');
    if (!flowPath) {
      return Promise.reject('no "flows.path" configured');
    }
    flowPath = XIBLE.resolvePath(flowPath);

    if (altName) {
      if (!XIBLE.Flow.validateId(altName)) {
        return Promise.reject('flow _id/name cannot contain reserved/unsave characters');
      }
      this._id = altName;
      this.name = altName;
    }

    // remove fields specifically for the registry
    delete this.publishUserName;
    delete this.publishDate;

    return new Promise((resolve, reject) => {
      // write
      const flowDestPath = `${flowPath}/${this._id}.json`;
      fsExtra.writeFile(flowDestPath, JSON.stringify(this, null, '\t'), (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  };

  /**
  * Installs a nodepack from a registry.
  * @returns {Promise}
  */
  xibleRegistry.NodePack.prototype.install = function nodePackInstall() {
    if (!XIBLE.Config.getValue('registry.nodepacks.allowinstall')) {
      return Promise.reject('Your config does not allow to install nodepacks from the registry');
    }

    let tmpRegDir;
    let nodePath = XIBLE.Config.getValue('nodes.path');
    if (!nodePath) {
      return Promise.reject('no "nodes.path" configured');
    }
    nodePath = XIBLE.resolvePath(nodePath);

    // get the registrydata
    return this.getRegistryData()
    .then((registryData) => {
      if (!registryData.name) {
        return Promise.reject(`No "name" field found in the registry data for node "${this.name}"`);
      }

      return this.getTarballUrl()
      .then(tarballUrl => new Promise((resolve, reject) => {
        // check if the tarbalUrl is safe
        if (encodeURI(tarballUrl) !== tarballUrl) {
          reject(new Error('Package URL contains potentially unsafe characters'));
          return;
        }

        // create the tmp dir
        fsExtra.mkdtemp(TMP_REGISTRY_DIR, (err, mTmpRegDir) => {
          tmpRegDir = mTmpRegDir;
          if (err) {
            reject(err);
            return;
          }

          // create a package.json so npm knows where the root lies
          // remove the dependencies from the package so npm doesn't get confused
          const packageJson = require(`${__dirname}/../../package.json`);
          delete packageJson.dependencies;
          delete packageJson.devDependencies;

          // write off package.json
          fsExtra.writeFile(`${tmpRegDir}/package.json`, JSON.stringify(packageJson), (createPackageJsonErr) => {
            if (createPackageJsonErr) {
              reject(createPackageJsonErr);
              return;
            }

            // fork npm to install the registry url
            const fork = require('child_process').spawn;
            const npm = fork('npm', ['install', '--no-save', tarballUrl], {
              cwd: tmpRegDir,
              shell: true
            });

            npm.on('error', npmErr => reject(npmErr));

            npm.on('exit', (exitCode) => {
              if (exitCode) {
                reject(`exited with code: ${exitCode}`);
                return;
              }

              // specify the dir where this node will be installed
              const nodeDestDir = `${nodePath}/${this.name}`;

              // when success, resolve
              const onSuccess = () => XIBLE.Node
              .initFromPath(nodeDestDir)
              .then(() => cleanUp(tmpRegDir))
              .then(() => {
                // see if we can/need to reinit flows that are not runnable
                const flows = XIBLE.getFlows();
                for (const flowId in flows) {
                  if (!flows[flowId].runnable) {
                    flows[flowId].initJson(flows[flowId].json);
                  }
                }
              })
              .then(resolve)
              .catch((onSuccessErr) => {
                reject(onSuccessErr);
              });

              // remove existing node directory
              fsExtra.emptyDir(nodeDestDir, (removeExistingNodeErr) => {
                if (removeExistingNodeErr) {
                  reject(removeExistingNodeErr);
                  return;
                }

                // first move the node itself
                fsExtra.move(`${tmpRegDir}/node_modules/${registryData.name}`, nodeDestDir, {
                  overwrite: true
                }, (moveNodeErr) => {
                  if (moveNodeErr) {
                    reject(moveNodeErr);
                    return;
                  }

                  // check if there's anything left in node_modules
                  fsExtra.readdir(`${tmpRegDir}/node_modules`, (remainingNodeModulesErr, files) => {
                    if (remainingNodeModulesErr) {
                      reject(remainingNodeModulesErr);
                      return;
                    }

                    if (!files.length) {
                      onSuccess();
                      return;
                    }

                    // move the rest of the node_modules
                    fsExtra.move(`${tmpRegDir}/node_modules`, `${nodeDestDir}/node_modules`, {
                      overwrite: true
                    }, (moveNodeModulesErr) => {
                      if (moveNodeModulesErr) {
                        reject(moveNodeModulesErr);
                        return;
                      }

                      onSuccess();
                    });
                  });
                });
              });
            });

            npm.stdout.on('data', (data) => {
              console.log(data.toString());
            });

            npm.stderr.on('data', (data) => {
              console.log(data.toString());
            });
          });
        });
      }));
    })
    .catch(err =>
      cleanUp(tmpRegDir)
      .then(() => Promise.reject(err))
      .catch(() => Promise.reject(err))
    );
  };

  if (EXPRESS_APP) {
    require('./routes.js')(xibleRegistry, XIBLE, EXPRESS_APP);
  }

  return {
    Registry: xibleRegistry
  };
};
<commit_msg>dashses instead of camelCase- mix<commit_after>'use strict';

module.exports = (XIBLE, EXPRESS_APP) => {
  const XibleRegistryWrapper = require('xible-registry-wrapper');
  const fsExtra = require('fs-extra');
  const os = require('os');

  const registryUrl = XIBLE.Config.getValue('registry.url');
  if (!registryUrl) {
    throw new Error('"registry.url" not found in config');
  }

  const xibleRegistry = new XibleRegistryWrapper(registryUrl);

  // the tmp path for downloading this node
  const TMP_REGISTRY_DIR = `${os.tmpdir() || '/tmp'}/xible-registry-`;
  console.log(os.tmpdir());

  function cleanUp(tmpRegDir) {
    if (!tmpRegDir) {
      return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
      // remove the tmp dir
      fsExtra.remove(tmpRegDir, (err) => {
        if (err) {
          reject(err);
          return;
        }

        resolve();
      });
    });
  }

  /**
  * Installs a flow from a registry.
  * @param {String} altName The name to publish the flow with. Defaults to the flow name.
  * @returns {Promise}
  */
  xibleRegistry.Flow.prototype.install = function flowInstall(altName) {
    if (!XIBLE.Config.getValue('registry.flows.allowinstall')) {
      return Promise.reject('Your config does not allow to install flows from the registry');
    }

    let flowPath = XIBLE.Config.getValue('flows.path');
    if (!flowPath) {
      return Promise.reject('no "flows.path" configured');
    }
    flowPath = XIBLE.resolvePath(flowPath);

    if (altName) {
      if (!XIBLE.Flow.validateId(altName)) {
        return Promise.reject('flow _id/name cannot contain reserved/unsave characters');
      }
      this._id = altName;
      this.name = altName;
    }

    // remove fields specifically for the registry
    delete this.publishUserName;
    delete this.publishDate;

    return new Promise((resolve, reject) => {
      // write
      const flowDestPath = `${flowPath}/${this._id}.json`;
      fsExtra.writeFile(flowDestPath, JSON.stringify(this, null, '\t'), (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  };

  /**
  * Installs a nodepack from a registry.
  * @returns {Promise}
  */
  xibleRegistry.NodePack.prototype.install = function nodePackInstall() {
    if (!XIBLE.Config.getValue('registry.nodepacks.allowinstall')) {
      return Promise.reject('Your config does not allow to install nodepacks from the registry');
    }

    let tmpRegDir;
    let nodePath = XIBLE.Config.getValue('nodes.path');
    if (!nodePath) {
      return Promise.reject('no "nodes.path" configured');
    }
    nodePath = XIBLE.resolvePath(nodePath);

    // get the registrydata
    return this.getRegistryData()
    .then((registryData) => {
      if (!registryData.name) {
        return Promise.reject(`No "name" field found in the registry data for node "${this.name}"`);
      }

      return this.getTarballUrl()
      .then(tarballUrl => new Promise((resolve, reject) => {
        // check if the tarbalUrl is safe
        if (encodeURI(tarballUrl) !== tarballUrl) {
          reject(new Error('Package URL contains potentially unsafe characters'));
          return;
        }

        // create the tmp dir
        fsExtra.mkdtemp(TMP_REGISTRY_DIR, (err, mTmpRegDir) => {
          tmpRegDir = mTmpRegDir;
          if (err) {
            reject(err);
            return;
          }

          // create a package.json so npm knows where the root lies
          // remove the dependencies from the package so npm doesn't get confused
          const packageJson = require(`${__dirname}/../../package.json`);
          delete packageJson.dependencies;
          delete packageJson.devDependencies;

          // write off package.json
          fsExtra.writeFile(`${tmpRegDir}/package.json`, JSON.stringify(packageJson), (createPackageJsonErr) => {
            if (createPackageJsonErr) {
              reject(createPackageJsonErr);
              return;
            }

            // fork npm to install the registry url
            const fork = require('child_process').spawn;
            const npm = fork('npm', ['install', '--no-save', tarballUrl], {
              cwd: tmpRegDir,
              shell: true
            });

            npm.on('error', npmErr => reject(npmErr));

            npm.on('exit', (exitCode) => {
              if (exitCode) {
                reject(`exited with code: ${exitCode}`);
                return;
              }

              // specify the dir where this node will be installed
              const nodeDestDir = `${nodePath}/${this.name}`;

              // when success, resolve
              const onSuccess = () => XIBLE.Node
              .initFromPath(nodeDestDir)
              .then(() => cleanUp(tmpRegDir))
              .then(() => {
                // see if we can/need to reinit flows that are not runnable
                const flows = XIBLE.getFlows();
                for (const flowId in flows) {
                  if (!flows[flowId].runnable) {
                    flows[flowId].initJson(flows[flowId].json);
                  }
                }
              })
              .then(resolve)
              .catch((onSuccessErr) => {
                reject(onSuccessErr);
              });

              // remove existing node directory
              fsExtra.emptyDir(nodeDestDir, (removeExistingNodeErr) => {
                if (removeExistingNodeErr) {
                  reject(removeExistingNodeErr);
                  return;
                }

                // first move the node itself
                fsExtra.move(`${tmpRegDir}/node_modules/${registryData.name}`, nodeDestDir, {
                  overwrite: true
                }, (moveNodeErr) => {
                  if (moveNodeErr) {
                    reject(moveNodeErr);
                    return;
                  }

                  // check if there's anything left in node_modules
                  fsExtra.readdir(`${tmpRegDir}/node_modules`, (remainingNodeModulesErr, files) => {
                    if (remainingNodeModulesErr) {
                      reject(remainingNodeModulesErr);
                      return;
                    }

                    if (!files.length) {
                      onSuccess();
                      return;
                    }

                    // move the rest of the node_modules
                    fsExtra.move(`${tmpRegDir}/node_modules`, `${nodeDestDir}/node_modules`, {
                      overwrite: true
                    }, (moveNodeModulesErr) => {
                      if (moveNodeModulesErr) {
                        reject(moveNodeModulesErr);
                        return;
                      }

                      onSuccess();
                    });
                  });
                });
              });
            });

            npm.stdout.on('data', (data) => {
              console.log(data.toString());
            });

            npm.stderr.on('data', (data) => {
              console.log(data.toString());
            });
          });
        });
      }));
    })
    .catch(err =>
      cleanUp(tmpRegDir)
      .then(() => Promise.reject(err))
      .catch(() => Promise.reject(err))
    );
  };

  if (EXPRESS_APP) {
    require('./routes.js')(xibleRegistry, XIBLE, EXPRESS_APP);
  }

  return {
    Registry: xibleRegistry
  };
};
<|endoftext|>


<commit_before>import { deviceType } from './js/utils';
import * as CONSTANT from './js/constants';
/**
 *
 * @class AppController
 */
export default class AppController {
  /**
   * Creates an instance of AppController.
   *
   * @param {any} $scope
   * @param {any} $global
   * @param {angular.IHttpService} $http
   * @param {TTSManager} TTSManager
   *
   * @memberOf AppController
   */
  constructor($scope, $global, $http, TTSManager) {
    this.$scope = $scope;
    this.$scope.global = $global;
    this.$http = $http;
    this.tts = TTSManager;
    // Initilize variables for controller.

    // Call controllerInit
    this.controllerInit();
  }

  controllerInit() {
    // Create or facilitate new functions for $scope or $global service.
    otsimo.run(() => {

      this.checkCapabilities();
      this.setSettings();
      this.runApp();
    });

    // Listen the changes on the resolution and
    // orientation from the device.
    this.resolutionListener();
  }

  /**
   * Does the inital tasks to start the app.
   */
  runApp() {
    // Get grid size X and Y from otsimo settings object.
    let otsGridSize = otsimo.settings.gridsize.split('grid-')[1];
    let otsGridXY = otsGridSize.split('x');
    let x = otsGridXY[0];
    let y = otsGridXY[1];
    // Check if the device is a phone
    // Limit the grid size to 6x4
    if (deviceType() === 'phone') {
      if (x > 6) { x = 6; }
      if (y > 4) { y = 4; }
    }
    // Set grid size and check device orientation.
    this.$scope.global.changeGridSize(x, y);

    if (otsimo.width < otsimo.height) {
      this.$scope.global.checkOrientation("portrait");
    } else {
      this.$scope.global.checkOrientation("landscape-left");
    }
    // Load symbol data to global array variable.
    this.loadSymbols();
  }

  /**
   * Sets the setting properties fron otsimo object
   *
   */
  setSettings() {

    this.$scope.global.language = otsimo.child.language;
    // Colors & styles
    this.$scope.headerColor = otsimo.kv.headerColor;
    this.$scope.generalFont = otsimo.kv.generalFont;
    document.getElementById('header')
      .style.background = this.$scope.headerColor;
    document.body.style.fontSize = this.$scope.generalFont;

    this.setUIText();

  }

  /**
   * Loads symbol package respect to language
   *
   */
  loadSymbols() {
    let global = this.$scope.global;
    let metadataPath = `${otsimo.kv.symbolPack}/metadata.json`;
    this.$http.get(metadataPath)
      .success((resp) => {
        this.metadata = resp;
        global.symbolPath = `${otsimo.kv.symbolPack}/${resp.images}`;
        this.tts.setVoiceDriver(resp.voiceId);

        let symbolDataPath = `${otsimo.kv.symbolPack}/${resp.data}`

        this.$http.get(symbolDataPath)
          .success(resp => {
            global.mainArray = resp.symbols;
            global.mainArray.forEach(obj => {
              global.mainSlugArray.push(obj.slug);
            });
            global.changeCurrentTab(CONSTANT.TAB_MAIN);
          })
          .error(console.error);
      })
      .error(console.error);
  }

  /**
   * Checks if the device or installed otsimo app is supporting TTS.
   *
   */
  checkCapabilities() {
    if (otsimo.capabilities.indexOf('tts') === -1) {
      document.getElementById('outdated')
        .style.display = 'block';
    }
  }

  /**
   * Sets UI text setting properties from otsimo kv object
   *
   */
  setUIText() {
    this.$scope.pageText1 = otsimo.kv.pageText1;
    this.$scope.pageText2 = otsimo.kv.pageText2;
    this.$scope.pageText3 = otsimo.kv.pageText3;
    this.$scope.pageText4 = otsimo.kv.pageText4;
    this.$scope.pageText5 = otsimo.kv.pageText5;
    this.$scope.timeIntervalText1 = otsimo.kv.timeIntervalText1;
    this.$scope.timeIntervalText2 = otsimo.kv.timeIntervalText2;
    this.$scope.timeIntervalText3 = otsimo.kv.timeIntervalText3;
    this.$scope.timeIntervalText4 = otsimo.kv.timeIntervalText4;
    this.$scope.previousText = otsimo.kv.previousText;
    this.$scope.nextText = otsimo.kv.nextText;
    this.$scope.backText = otsimo.kv.backText;
    this.$scope.startTyping = otsimo.kv.startTyping;
  }

  /**
   * Listens any resolution changes
   *
   */
  resolutionListener() {
    otsimo.onResolutionChanged((width, height, orientation) => {
      if (width < height) {
        this.$scope.global.checkOrientation("portrait");
      } else {
        this.$scope.global.checkOrientation("landscape-left");
      }
    });
  }

}
// Service Dependency Injection
AppController.$inject = ['$scope', '$global', '$http', 'TTSManager'];
<commit_msg>CONSTANT orientation variables<commit_after>import { deviceType } from './js/utils';
import * as CONSTANT from './js/constants';
/**
 *
 * @class AppController
 */
export default class AppController {
  /**
   * Creates an instance of AppController.
   *
   * @param {any} $scope
   * @param {any} $global
   * @param {angular.IHttpService} $http
   * @param {TTSManager} TTSManager
   *
   * @memberOf AppController
   */
  constructor($scope, $global, $http, TTSManager) {
    this.$scope = $scope;
    this.$scope.global = $global;
    this.$http = $http;
    this.tts = TTSManager;
    // Initilize variables for controller.

    // Call controllerInit
    this.controllerInit();
  }

  controllerInit() {
    // Create or facilitate new functions for $scope or $global service.
    otsimo.run(() => {

      this.checkCapabilities();
      this.setSettings();
      this.runApp();
    });

    // Listen the changes on the resolution and
    // orientation from the device.
    this.resolutionListener();
  }

  /**
   * Does the inital tasks to start the app.
   */
  runApp() {
    // Get grid size X and Y from otsimo settings object.
    let otsGridSize = otsimo.settings.gridsize.split('grid-')[1];
    let otsGridXY = otsGridSize.split('x');
    let x = otsGridXY[0];
    let y = otsGridXY[1];
    // Check if the device is a phone
    // Limit the grid size to 6x4
    if (deviceType() === 'phone') {
      if (x > 6) { x = 6; }
      if (y > 4) { y = 4; }
    }
    // Set grid size and check device orientation.
    this.$scope.global.changeGridSize(x, y);

    if (otsimo.width < otsimo.height) {
      this.$scope.global.checkOrientation("portrait");
    } else {
      this.$scope.global.checkOrientation("landscape-left");
    }
    // Load symbol data to global array variable.
    this.loadSymbols();
  }

  /**
   * Sets the setting properties fron otsimo object
   *
   */
  setSettings() {

    this.$scope.global.language = otsimo.child.language;
    // Colors & styles
    this.$scope.headerColor = otsimo.kv.headerColor;
    this.$scope.generalFont = otsimo.kv.generalFont;
    document.getElementById('header')
      .style.background = this.$scope.headerColor;
    document.body.style.fontSize = this.$scope.generalFont;

    this.setUIText();

  }

  /**
   * Loads symbol package respect to language
   *
   */
  loadSymbols() {
    let global = this.$scope.global;
    let metadataPath = `${otsimo.kv.symbolPack}/metadata.json`;
    this.$http.get(metadataPath)
      .success((resp) => {
        this.metadata = resp;
        global.symbolPath = `${otsimo.kv.symbolPack}/${resp.images}`;
        this.tts.setVoiceDriver(resp.voiceId);

        let symbolDataPath = `${otsimo.kv.symbolPack}/${resp.data}`

        this.$http.get(symbolDataPath)
          .success(resp => {
            global.mainArray = resp.symbols;
            global.mainArray.forEach(obj => {
              global.mainSlugArray.push(obj.slug);
            });
            global.changeCurrentTab(CONSTANT.TAB_MAIN);
          })
          .error(console.error);
      })
      .error(console.error);
  }

  /**
   * Checks if the device or installed otsimo app is supporting TTS.
   *
   */
  checkCapabilities() {
    if (otsimo.capabilities.indexOf('tts') === -1) {
      document.getElementById('outdated').style.display = 'block';
    }
  }

  /**
   * Sets UI text setting properties from otsimo kv object
   *
   */
  setUIText() {
    this.$scope.pageText1 = otsimo.kv.pageText1;
    this.$scope.pageText2 = otsimo.kv.pageText2;
    this.$scope.pageText3 = otsimo.kv.pageText3;
    this.$scope.pageText4 = otsimo.kv.pageText4;
    this.$scope.pageText5 = otsimo.kv.pageText5;
    this.$scope.timeIntervalText1 = otsimo.kv.timeIntervalText1;
    this.$scope.timeIntervalText2 = otsimo.kv.timeIntervalText2;
    this.$scope.timeIntervalText3 = otsimo.kv.timeIntervalText3;
    this.$scope.timeIntervalText4 = otsimo.kv.timeIntervalText4;
    this.$scope.previousText = otsimo.kv.previousText;
    this.$scope.nextText = otsimo.kv.nextText;
    this.$scope.backText = otsimo.kv.backText;
    this.$scope.startTyping = otsimo.kv.startTyping;
  }

  /**
   * Listens any resolution changes
   *
   */
  resolutionListener() {
    otsimo.onResolutionChanged((width, height, orientation) => {
      if (width < height) {
        this.$scope.global.checkOrientation(CONSTANT.PORTRAIT);
      } else {
        this.$scope.global.checkOrientation(CONSTANT.LANDSCAPE_LEFT);
      }
    });
  }

}
// Service Dependency Injection
AppController.$inject = ['$scope', '$global', '$http', 'TTSManager'];
<|endoftext|>


<commit_before>import {
  select
} from 'd3-selection'

import {
  scaleTime,
  scaleLinear,
  scaleLog
} from 'd3-scale'

import {
  axisBottom,
  axisLeft
} from 'd3-axis'

import {
  timeFormat
} from 'd3-time-format'

import {
  color
} from 'd3-color'

import {
  max
} from 'd3-array'

import 'd3-selection-multi'

export async function heatmap(el) {
  let height = 400
  let margin = {
    left: 1,
    top: 1,
    right: 1
  }

  let offset = {
    left: 60,
    bottom: 20
  }

  let $el = select(el)
  let width = $el.node().offsetWidth - margin.left - margin.right - offset.left

  console.log(width)

  let response = await fetch(el.dataset.source),
    json = await response.json(),
    data = json['values']

  let bucketWidth = width / json.x.length
  let bucketHeight = height / json.y.length

  let scaleX = scaleTime()
    .range([0, width])
    .domain(json.x.range.map((x) => Date.parse(x)))
  let scaleY = scaleLinear()
    .range([height, 0])
    .domain(json.y.range.map((x) => x / 1000))
  let scaleZ = scaleLog()
    .range(['#CFE9FF', '#0275D8'])
    .domain([1, max(data, (x) => x.v)])

  let svg = $el.append('svg')
      .attr('width', $el.node().offsetWidth)
      .attr('height', height + offset.bottom)
    .append('g')
      .attr('transform', `translate(${margin.left + offset.left}, ${margin.top})`)

  let axisX = axisBottom(scaleX)
    .tickFormat(timeFormat('%I:%M:%S'))
  let axisY = axisLeft(scaleY)
    .tickFormat((x) => `${x} ms`)
    .ticks(3)

  svg.append('g')
    .attr('transform', `translate(0,${height + 1})`)
    .call((g) => {
      g.call(axisX)
      g.selectAll('.domain').remove()
      g.selectAll('.tick text').style('text-anchor', 'middle')
    })

  svg.append('g')
    .attr('transform', 'translate(0, 0)')
    .call((g) => {
      g.call(axisY)
      g.selectAll('.domain').remove()
      g.selectAll('.tick line').remove()
    })

  let heatmap = svg.append('g')
  let group = heatmap.append('g')
  let counter = 1;

  for(let {x, y, v} of data) {
    group
      .append('rect')
      .attrs({
        x: Math.round(0 + x * bucketWidth),
        y: height - bucketHeight - y * bucketHeight,
        width: Math.round(bucketWidth),
        height: bucketHeight,
        fill: scaleZ(v),
        title: v
      })

    if(counter % 400 == 0) {
      group = heatmap.append('g')
      counter = 1
    } else {
      counter += 1
    }
  }
}
<commit_msg>Adjust heatmap time axis<commit_after>import {
  select
} from 'd3-selection'

import {
  scaleTime,
  scaleLinear,
  scaleLog
} from 'd3-scale'

import {
  axisBottom,
  axisLeft
} from 'd3-axis'

import {
  timeMinute
} from 'd3-time'

import {
  timeFormat
} from 'd3-time-format'

import {
  color
} from 'd3-color'

import {
  max
} from 'd3-array'

import 'd3-selection-multi'

export async function heatmap(el) {
  let height = 400
  let margin = {
    left: 1,
    top: 1,
    right: 1
  }

  let offset = {
    left: 60,
    bottom: 20
  }

  let $el = select(el)
  let width = $el.node().offsetWidth - margin.left - margin.right - offset.left

  console.log(width)

  let response = await fetch(el.dataset.source),
    json = await response.json(),
    data = json['values']

  let bucketWidth = width / json.x.length
  let bucketHeight = height / json.y.length

  let scaleX = scaleTime()
    .range([0, width])
    .domain(json.x.range.map((x) => Date.parse(x)))
  let scaleY = scaleLinear()
    .range([height, 0])
    .domain(json.y.range.map((x) => x / 1000))
  let scaleZ = scaleLog()
    .range(['#CFE9FF', '#0275D8'])
    .domain([1, max(data, (x) => x.v)])

  let svg = $el.append('svg')
      .attr('width', $el.node().offsetWidth)
      .attr('height', height + offset.bottom)
    .append('g')
      .attr('transform', `translate(${margin.left + offset.left}, ${margin.top})`)

  let axisX = axisBottom(scaleX)
    .tickFormat(timeFormat('%I:%M:%S'))
    .ticks(timeMinute.every(10))
  let axisY = axisLeft(scaleY)
    .tickFormat((x) => `${x} ms`)
    .ticks(3)

  svg.append('g')
    .attr('transform', `translate(0,${height + 1})`)
    .call((g) => {
      g.call(axisX)
      g.selectAll('.domain').remove()
      g.selectAll('.tick text').style('text-anchor', 'middle')
    })

  svg.append('g')
    .attr('transform', 'translate(0, 0)')
    .call((g) => {
      g.call(axisY)
      g.selectAll('.domain').remove()
      g.selectAll('.tick line').remove()
    })

  let heatmap = svg.append('g')
  let group = heatmap.append('g')
  let counter = 1;

  for(let {x, y, v} of data) {
    group
      .append('rect')
      .attrs({
        x: Math.round(0 + x * bucketWidth),
        y: height - bucketHeight - y * bucketHeight,
        width: Math.round(bucketWidth),
        height: bucketHeight,
        fill: scaleZ(v),
        title: v
      })

    if(counter % 400 == 0) {
      group = heatmap.append('g')
      counter = 1
    } else {
      counter += 1
    }
  }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { MODE_NAMES, MODES } from '../reducers/microcontrollerEnums';
import { intersection, propOr, ifElse } from 'ramda';
import styles from './Pin.sass'; // eslint-disable-line no-unused-vars

export default class Pin extends Component {
  static propTypes = {
    pin: PropTypes.object.isRequired,
    changeMode: PropTypes.func.isRequired,
    listen: PropTypes.func.isRequired
  };

  render() {
    const { changeMode, listen, pin } = this.props;
    const { id, mode, value, report } = pin;
    const supportedModes = intersection(
      pin.supportedModes,
      Object.keys(MODE_NAMES).map(k => parseInt(k, 10))
    );
    const getModeDescriptionForModeNumber = (num) => propOr('Not Set', num, MODE_NAMES);
    const modeSelector = (
      <select
        defaultValue="{defaultMode}"
        onChange={event => changeMode(id, event.target.value)}
        disabled={supportedModes.length === 0}
      >
        {supportedModes.map((supportedMode) => (
          <option key={supportedMode} value={supportedMode}>
            {getModeDescriptionForModeNumber(supportedMode)}
          </option>
          )
        )}
      </select>
    );

    const pinClass = pin.isAnalogPin ? 'pin pin--analog' : 'pin pin--digital';

    const tags = [];
    if (pin.isHWSerialPort) {
      tags.push('Hardware Serialport');
    }
    if (pin.isSWSerialPort) {
      tags.push('Software Serialport');
    }
    if (pin.isAnalogPin) {
      tags.push('Analog Pin');
    }

    return (

Pin {id}

          {tags.map((tag) =>

{tag}

          )}

          Value: {value}, Reporting: {report}, {modeSelector}

          {ifElse(() => mode === MODES.INPUT || mode === MODES.ANALOG,
            () =>
               listen(id, mode)}>
                Listen
              ,
            () =>

                {mode} {MODES.ANALOG}
              )()}

    );
  }
}
<commit_msg>Add unique key to tags<commit_after>import React, { Component, PropTypes } from 'react';
import { MODE_NAMES, MODES } from '../reducers/microcontrollerEnums';
import { intersection, propOr, ifElse } from 'ramda';
import styles from './Pin.sass'; // eslint-disable-line no-unused-vars

export default class Pin extends Component {
  static propTypes = {
    pin: PropTypes.object.isRequired,
    changeMode: PropTypes.func.isRequired,
    listen: PropTypes.func.isRequired
  };

  render() {
    const { changeMode, listen, pin } = this.props;
    const { id, mode, value, report } = pin;
    const supportedModes = intersection(
      pin.supportedModes,
      Object.keys(MODE_NAMES).map(k => parseInt(k, 10))
    );
    const getModeDescriptionForModeNumber = (num) => propOr('Not Set', num, MODE_NAMES);
    const modeSelector = (
      <select
        defaultValue="{defaultMode}"
        onChange={event => changeMode(id, event.target.value)}
        disabled={supportedModes.length === 0}
      >
        {supportedModes.map((supportedMode) => (
          <option key={supportedMode} value={supportedMode}>
            {getModeDescriptionForModeNumber(supportedMode)}
          </option>
          )
        )}
      </select>
    );

    const pinClass = pin.isAnalogPin ? 'pin pin--analog' : 'pin pin--digital';

    const tags = [];
    if (pin.isHWSerialPort) {
      tags.push('Hardware Serialport');
    }
    if (pin.isSWSerialPort) {
      tags.push('Software Serialport');
    }
    if (pin.isAnalogPin) {
      tags.push('Analog Pin');
    }

    return (

Pin {id}

          {tags.map((tag) =>

{tag}

          )}

          Value: {value}, Reporting: {report}, {modeSelector}

          {ifElse(() => mode === MODES.INPUT || mode === MODES.ANALOG,
            () =>
               listen(id, mode)}>
                Listen
              ,
            () =>

                {mode} {MODES.ANALOG}
              )()}

    );
  }
}
<|endoftext|>


<commit_before><commit_msg>Placehold deleteStock method<commit_after><|endoftext|>


<commit_before><commit_msg>defers processing of added constraints if no root is present<commit_after><|endoftext|>


<commit_before><commit_msg>Run all tests<commit_after><|endoftext|>


<commit_before>const fs = require('fs-extra');
//var UglifyJS = require("uglify-js");
const pug = require('pug');
var path = require("path");
var moment = require('moment');
var pathMain;
module.exports = {
  readInputs: function (options){
    console.log('this is what is being passed to write script', test)
  },

  getStyle: function(){

  },
  getPopup: function(){

  },
  getTool: function(){

  },
  getStuff: function(test){
    var stringfor= '';
    if (test[3].length > 0) stringfor += 'layer.bindPopup(feature.' + test[3]+');'
    if (test[4].length > 0) stringfor += 'layer.bindTooltip(feature.' + test[4]+');'
    return stringfor;
  },
  writeScript: function (optionsinit) {
    console.log('write scripts');
    console.log(optionsinit);
	//exportoptions.mapoptions.push(basemapProviderLayer1, mymap.options.maxBounds, minzoomtest, maxzoomtest , mymap.getZoom() , mymap.getCenter());
  //   var mapInit = 'var map = L.map("map").setView(['
	// + (optionsinit.mapoptions[5] ? `${optionsinit.mapoptions[5].lat}, ${optionsinit.mapoptions[5].lng}` : `51.505, -0.09`)
	// + '],' + (optionsinit.mapoptions[4] ? `${optionsinit.mapoptions[4] }`:'13')+');L.tileLayer("'
	// + (optionsinit.mapoptions[0] ? optionsinit.mapoptions[0]._url : 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
	// +'", {maxZoom:'+ ( optionsinit.mapoptions[3]? `${optionsinit.mapoptions[3]},`: '19,')
	// + 'minzoom:'+ (optionsinit.mapoptions[2]? `${optionsinit.mapoptions[2]},` : '0,')
  // + (optionsinit.mapoptions[0] && optionsinit.mapoptions[0].options.ext ? `ext: \'${optionsinit.mapoptions[0].options.ext}\',` : '')
	// + 'attribution:'+ (optionsinit.mapoptions[0] ? `\'${optionsinit.mapoptions[0].options.attribution}\'` : `\'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>\'`)
  // + `}).addTo(map);`;

  //NEW THING! ASSUMING BASEMAP ALWAY SENT WITH ITEMS

var mapInit = 'var map = L.map("map").setView(['
    +`${optionsinit.mapoptions[5].lat}, ${optionsinit.mapoptions[5].lng}]`//center point @ initiation
    + `, ${optionsinit.mapoptions[4]} );` //zoom level @ initiation
    + `L.tileLayer("${optionsinit.mapoptions[0]._url}", ${JSON.stringify(optionsinit.mapoptions[0].options)} ).addTo(map);`; //zoom level @ initiation;
if (optionsinit.mapoptions[3]){
  mapInit += ` map.setMaxZoom(${optionsinit.mapoptions[3]});`;
}
if (optionsinit.mapoptions[2]){
  mapInit += ` map.setMinZoom(${optionsinit.mapoptions[2]});`;
}
  //CHANGE TO WORK WITH TILE IN THE THING,
    var dataInit = '';
	if(optionsinit.mapoptions[1]) mapInit += `map.setMaxBounds(L.latLngBounds([[${optionsinit.mapoptions[1]._northEast.lat},${optionsinit.mapoptions[1]._northEast.lng} ],[${optionsinit.mapoptions[1]._southWest.lat} ,${optionsinit.mapoptions[1]._southWest.lng} ]]));`
    for(i in optionsinit.datanames){
      if (typeof optionsinit.datanames[i] == 'object' && optionsinit.datanames[i][0] !== null){
        console.log('has second property')
        console.log(optionsinit.datanames[i][0])
        //list the cases for different types of plugins here for second property and maybe think about sending a third for options after everything works
        switch(optionsinit.datanames[i][1]){
          case 'markercluster':
              dataInit += `var markers${i} = L.markerClusterGroup();`
              +   `var ${optionsinit.datanames[i][0]}geojson = L.geoJson(${optionsinit.datanames[i][0]}`
              +`); markers${i}.addLayer(${optionsinit.datanames[i][0]}geojson);map.addLayer(markers${i});`;
              dataInit += ( optionsinit.datanames[i][3] || optionsinit.datanames[i][4] ? `markers${i}` : '')
              + ( optionsinit.datanames[i][4]  ? '.bindPopup(function (layer) { return ' + optionsinit.datanames[i][3] +'})': '')   //').bindPopup(function (layer) { return layer.feature.properties.description;})'
              +( optionsinit.datanames[i][4]  ? '.bindTooltip(function (layer) { return '+ optionsinit.datanames[i][4] +'})': '')   //'.bindTooltip(function (layer) { return layer.feature.properties.description;})'
              +( optionsinit.datanames[i][3] || optionsinit.datanames[i][4] ? `;` : '');
            break;
          default:
            dataInit += 'var '+ optionsinit.datanames[i][0] +'geojson = L.geoJSON(' + optionsinit.datanames[i][0]
            +( optionsinit.datanames[i][2] && typeof optionsinit.datanames[i][2]=='object' ? ', {style:'+JSON.stringify(optionsinit.datanames[i][2])+'})': ')')//', {style: function (feature) {return {color: feature.properties.color};}}'
            +( optionsinit.datanames[i][3]  ? '.bindPopup(function (layer) { return ' + optionsinit.datanames[i][3] +'})': '')   //').bindPopup(function (layer) { return layer.feature.properties.description;})'
            +( optionsinit.datanames[i][4]  ? '.bindTooltip(function (layer) { return '+ optionsinit.datanames[i][4] +'})': '')   //'.bindTooltip(function (layer) { return layer.feature.properties.description;})'
            +'.addTo(map);';
        }
      }
    }
    let maptitleTest='';
    if(optionsinit.maptitle){//TAKEN FROM LEAFLET INFO EXAMPLE
      maptitleTest +=`var info = L.control();
      info.onAdd = function (map) {
          this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
          this.update();
          return this._div;
      };
      // method that we will use to update the control based on feature properties passed
      info.update = function () {
          this._div.innerHTML = '
${optionsinit.maptitle}
'
        };
      info.addTo(map);`
    }
    //if works add styling...
    fs.writeFileSync(pathMain+'/map.js', mapInit+ dataInit + maptitleTest );
    console.log('wrote the js file');
  },
  createMapDir: function(options){

    fs.ensureDirSync(pathMain);
    fs.copySync(__dirname+'/export/js', pathMain);//copies leaflet
    for(i in options.plugins){
        switch (options.plugins[i][0])
        {
          case 'leaflet.markercluster':
            fs.copySync(__dirname+'/export/markercluster', pathMain);//copies markercluster into designated folder
            break;
          default:
          console.log('default');
        }}
  },
  writeHTML: function(options){
    console.log('write html');
     var compiledFunction = pug.compileFile(__dirname+'export/test.pug');
     fs.writeFileSync(pathMain+'/map.html', compiledFunction(options) );//uncommented
     console.log('wrote html!');
  },
  writeMap: function(options){
    console.log(options)
    if(options.projectdest){
      pathMain = options.projectdest+'/'+options.projectname+ moment().format("YYYY_M_D_h_mm_ss");
    }else{
      pathMain = __dirname+options.projectname+ moment().format("YYYY_M_D_h_mm_ss");
    }
    console.log(pathMain);
    this.createMapDir(options);
    this.writeHTML(options);
    this.writeScript(options);
    return pathMain;
  }
};
<commit_msg>Add files via upload<commit_after>const fs = require('fs-extra');
//var UglifyJS = require("uglify-js");
const pug = require('pug');
var path = require("path");
var moment = require('moment');
var pathMain;
module.exports = {
  readInputs: function (options){
    console.log('this is what is being passed to write script', test)
  },

  getStyle: function(){

  },
  getPopup: function(){

  },
  getTool: function(){

  },
  getStuff: function(test){
    var stringfor= '';
    if (test[3].length > 0) stringfor += 'layer.bindPopup(feature.' + test[3]+');'
    if (test[4].length > 0) stringfor += 'layer.bindTooltip(feature.' + test[4]+');'
    return stringfor;
  },
  writeScript: function (optionsinit) {
    console.log('write scripts');
    console.log(optionsinit);
	//exportoptions.mapoptions.push(basemapProviderLayer1, mymap.options.maxBounds, minzoomtest, maxzoomtest , mymap.getZoom() , mymap.getCenter());
  //   var mapInit = 'var map = L.map("map").setView(['
	// + (optionsinit.mapoptions[5] ? `${optionsinit.mapoptions[5].lat}, ${optionsinit.mapoptions[5].lng}` : `51.505, -0.09`)
	// + '],' + (optionsinit.mapoptions[4] ? `${optionsinit.mapoptions[4] }`:'13')+');L.tileLayer("'
	// + (optionsinit.mapoptions[0] ? optionsinit.mapoptions[0]._url : 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
	// +'", {maxZoom:'+ ( optionsinit.mapoptions[3]? `${optionsinit.mapoptions[3]},`: '19,')
	// + 'minzoom:'+ (optionsinit.mapoptions[2]? `${optionsinit.mapoptions[2]},` : '0,')
  // + (optionsinit.mapoptions[0] && optionsinit.mapoptions[0].options.ext ? `ext: \'${optionsinit.mapoptions[0].options.ext}\',` : '')
	// + 'attribution:'+ (optionsinit.mapoptions[0] ? `\'${optionsinit.mapoptions[0].options.attribution}\'` : `\'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>\'`)
  // + `}).addTo(map);`;

  //NEW THING! ASSUMING BASEMAP ALWAY SENT WITH ITEMS

var mapInit = 'var map = L.map("map").setView(['
    +`${optionsinit.mapoptions[5].lat}, ${optionsinit.mapoptions[5].lng}]`//center point @ initiation
    + `, ${optionsinit.mapoptions[4]} );` //zoom level @ initiation
    + `L.tileLayer("${optionsinit.mapoptions[0]._url}", ${JSON.stringify(optionsinit.mapoptions[0].options)} ).addTo(map);`; //zoom level @ initiation;
if (optionsinit.mapoptions[3]){
  mapInit += ` map.setMaxZoom(${optionsinit.mapoptions[3]});`;
}
if (optionsinit.mapoptions[2]){
  mapInit += ` map.setMinZoom(${optionsinit.mapoptions[2]});`;
}
  //CHANGE TO WORK WITH TILE IN THE THING,
    var dataInit = '';
	if(optionsinit.mapoptions[1]) mapInit += `map.setMaxBounds(L.latLngBounds([[${optionsinit.mapoptions[1]._northEast.lat},${optionsinit.mapoptions[1]._northEast.lng} ],[${optionsinit.mapoptions[1]._southWest.lat} ,${optionsinit.mapoptions[1]._southWest.lng} ]]));`
    for(i in optionsinit.datanames){
      if (typeof optionsinit.datanames[i] == 'object' && optionsinit.datanames[i][0] !== null){
        console.log('has second property')
        console.log(optionsinit.datanames[i][0])
        //list the cases for different types of plugins here for second property and maybe think about sending a third for options after everything works
        switch(optionsinit.datanames[i][1]){
          case 'markercluster':
              dataInit += `var markers${i} = L.markerClusterGroup();`
              +   `var ${optionsinit.datanames[i][0]}geojson = L.geoJson(${optionsinit.datanames[i][0]}`
              +`); markers${i}.addLayer(${optionsinit.datanames[i][0]}geojson);map.addLayer(markers${i});`;
              dataInit += ( optionsinit.datanames[i][3] || optionsinit.datanames[i][4] ? `markers${i}` : '')
              + ( optionsinit.datanames[i][4]  ? '.bindPopup(function (layer) { return ' + optionsinit.datanames[i][3] +'})': '')   //').bindPopup(function (layer) { return layer.feature.properties.description;})'
              +( optionsinit.datanames[i][4]  ? '.bindTooltip(function (layer) { return '+ optionsinit.datanames[i][4] +'})': '')   //'.bindTooltip(function (layer) { return layer.feature.properties.description;})'
              +( optionsinit.datanames[i][3] || optionsinit.datanames[i][4] ? `;` : '');
            break;
          default:
            dataInit += 'var '+ optionsinit.datanames[i][0] +'geojson = L.geoJSON(' + optionsinit.datanames[i][0]
            +( optionsinit.datanames[i][2] && typeof optionsinit.datanames[i][2]=='object' ? ', {style:'+JSON.stringify(optionsinit.datanames[i][2])+'})': ')')//', {style: function (feature) {return {color: feature.properties.color};}}'
            +( optionsinit.datanames[i][3]  ? '.bindPopup(function (layer) { return ' + optionsinit.datanames[i][3] +'})': '')   //').bindPopup(function (layer) { return layer.feature.properties.description;})'
            +( optionsinit.datanames[i][4]  ? '.bindTooltip(function (layer) { return '+ optionsinit.datanames[i][4] +'})': '')   //'.bindTooltip(function (layer) { return layer.feature.properties.description;})'
            +'.addTo(map);';
        }
      }
    }
    let maptitleTest='';
    if(optionsinit.maptitle){//TAKEN FROM LEAFLET INFO EXAMPLE
      maptitleTest +=`var info = L.control();
      info.onAdd = function (map) {
          this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
          this.update();
          return this._div;
      };
      // method that we will use to update the control based on feature properties passed
      info.update = function () {
          this._div.innerHTML = '
${optionsinit.maptitle}
'
        };
      info.addTo(map);`
    }
    //if works add styling...
    fs.writeFileSync(pathMain+'/map.js', mapInit+ dataInit + maptitleTest );
    console.log('wrote the js file');
  },
  createMapDir: function(options){

    fs.ensureDirSync(pathMain);
    fs.copySync(__dirname+'/export/js', pathMain);//copies leaflet
    for(i in options.plugins){
        switch (options.plugins[i][0])
        {
          case 'leaflet.markercluster':
            fs.copySync(__dirname+'/export/markercluster', pathMain);//copies markercluster into designated folder
            break;
          default:
          console.log('default');
        }}
  },
  writeHTML: function(options){
    console.log('write html');
     var compiledFunction = pug.compileFile(__dirname+'/export/test.pug');
     fs.writeFileSync(pathMain+'/map.html', compiledFunction(options) );//uncommented
     console.log('wrote html!');
  },
  writeMap: function(options){
    console.log(options)
    if(options.projectdest){
      pathMain = options.projectdest+'/'+options.projectname+ moment().format("YYYY_M_D_h_mm_ss");
    }else{
      pathMain = __dirname+'/'+options.projectname+ moment().format("YYYY_M_D_h_mm_ss");
    }
    console.log(pathMain);
    this.createMapDir(options);
    this.writeHTML(options);
    this.writeScript(options);
    return pathMain;
  }
};
<|endoftext|>


<commit_before><commit_msg>not much<commit_after><|endoftext|>


<commit_before><commit_msg>added some more logging<commit_after><|endoftext|>


<commit_before>
var nodetree, cmdstack;

$(document).ready(function(){

    function init(parent) {
        cmdstack = new OCRJS.UndoStack(this);
        nodetree = new OCRJS.Nodetree.Tree(parent, cmdstack);
    }

    module("OCR Page Object Test");

    test("Initialisation test", function() {
        expect(1);

        var testdiv = $("

").attr("id", "test_div");
        $("body").append(testdiv);
        same($("#test_div").attr("id"), testdiv.attr("id"),
            "Document insertion test failed: expected " + testdiv.attr("id"),
            $("test_div").attr("id"));

    });

    test("Nodetree Initialisation", function() {
        expect(2);

        var parent = $("

")
            .attr("id", "nodetree_canvas")
            .appendTo("body");

        equal(nodetree, undefined,
            "Expected nodetree to be initially undefined");

        init(parent.get(0));

        notEqual(nodetree, undefined,
            "Expected nodetree to be defined after initialisation");
    });

    test("Nodetree Create Node", function() {
        expect(7);

        var parent = $("

")
            .attr("id", "nodetree_canvas")
            .appendTo("body");
        init(parent.get(0));

        stop();

        nodetree.addListeners({
            ready: function() {
                equal(!nodetree.hasNodes(), true,
                    "Expected nodetree to be initially empty");

                // create a test node
                var testtype = "Ocropus::GrayFileIn";
                var name = nodetree.newNodeName(testtype);
                nodetree.cmdCreateNode(name, testtype, {x: 100, y: 100});
                equal(nodetree.nodeCount(), 1,
                    "Expected one node to exist in the tree");

                // test undoing the action
                cmdstack.undo();
                equal(nodetree.nodeCount(), 0,
                    "Expected undoing action to remove created node.");

                // test redoing the action
                cmdstack.redo();
                equal(nodetree.nodeCount(), 1,
                    "Expected redoing action to place node back in tree.");

                // create a second node
                var testtype2 = "Utils::FileOut";
                var name2 = nodetree.newNodeName(testtype2);
                nodetree.cmdCreateNode(name2, testtype2, {x: 100, y: 200});
                equal(nodetree.nodeCount(), 2,
                        "Expected 2 nodes to now exist in the tree.");

                // connect them up
                nodetree.cmdConnectPlugs(
                        nodetree.getNode(name).output(),
                        nodetree.getNode(name2).input(0)
                );
                equal(nodetree.getNode(name2).input(0).isAttached(), true,
                        "Expected node 1 output to be attached.");

                // select all nodes
                nodetree.selectAll();
                equal(nodetree.selectedNodeCount(), nodetree.nodeCount(),
                        "Expected all nodes to be selected");

            },
        });

        // Initialise nodetree!
        $.getJSON("/presets/query/", function(data) {
            start();
            nodetree.init(data);
        });
    });
});
<commit_msg>Cleanup tests<commit_after>
$(document).ready(function(){

    module("OCR Page Object Test");

    test("Initialisation test", function() {
        expect(1);

        var testdiv = $("

").attr("id", "test_div");
        $("body").append(testdiv);
        same($("#test_div").attr("id"), testdiv.attr("id"),
            "Document insertion test failed: expected " + testdiv.attr("id"),
            $("test_div").attr("id"));

    });

    test("Test Nodetree", function() {
        expect(7);

        var parent = $("

")
            .attr("id", "nodetree_canvas")
            .appendTo("body");
        var cmdstack = new OCRJS.UndoStack(this);
        var nodetree = new OCRJS.Nodetree.Tree(parent, cmdstack);

        // Initialise nodetree!
        stop();
        $.getJSON("/presets/query/", function(data) {
            nodetree.init(data);
        });

        nodetree.addListeners({
            ready: function() {
                start();
                equal(!nodetree.hasNodes(), true,
                    "Expected nodetree to be initially empty");

                // create a test node
                var testtype = "Ocropus::GrayFileIn";
                var name = nodetree.newNodeName(testtype);
                nodetree.cmdCreateNode(name, testtype, {x: 100, y: 100});
                equal(nodetree.nodeCount(), 1,
                    "Expected number of nodes in the tree to be");

                // test undoing the action
                cmdstack.undo();
                equal(nodetree.nodeCount(), 0,
                    "After undo, expected number of nodes in the tree to be");

                // test redoing the action
                cmdstack.redo();
                equal(nodetree.nodeCount(), 1,
                    "After redo, expected number of nodes in the tree to be");

                // create a second node
                var testtype2 = "Utils::FileOut";
                var name2 = nodetree.newNodeName(testtype2);
                nodetree.cmdCreateNode(name2, testtype2, {x: 100, y: 200});
                equal(nodetree.nodeCount(), 2,
                        "Created another node, expected number of nodes in the tree to be");

                // connect them up
                nodetree.cmdConnectPlugs(
                        nodetree.getNode(name).output(),
                        nodetree.getNode(name2).input(0)
                );
                equal(nodetree.getNode(name2).input(0).isAttached(), true,
                        "After connecting plugs, expected input isAttached to be");

                // select all nodes
                nodetree.selectAll();
                equal(nodetree.selectedNodeCount(), nodetree.nodeCount(),
                        "SelectAll, expected number of selected nodes to be");
            },
        });
    });
});
<|endoftext|>


<commit_before><commit_msg>initialize as empty divs<commit_after><|endoftext|>


<commit_before><commit_msg>Replace let with const in isNotEq<commit_after><|endoftext|>


<commit_before>function soramame(source){
  // ソースコード
  this.source = source;

  // 文の終端記号
  var pat_CRCF = "[\n|\r|。]";
  this.CRLF = new RegExp("^" + pat_CRCF);

  //行コメント
　　var pat_comment_line = "\/\/";
  this.comment_line = new RegExp("^" + pat_comment_line);

  // 助詞
  var pat_josi = "[◎●はのにでを]";	//助詞の判定用
  var pat_josi2 = "◎●はのにでを";	//助詞以外の判定用
  this.josi = new RegExp("^" + pat_josi);

  // 文字列リテラル
  var pat_kakko = "(「.*」|『.*』)";
  var pat_kakko2 = "「」『』";
  this.string_literal = new RegExp("^" + pat_kakko);

  // 数字
  var pat_num2 = "0123456789０１２３４５６７８９";

 　// 記号
  var pat_symbol2 = "\*=\+\-\/%^\(\)\[\\]{}\.,:＝＋－×＊÷／％＾（）［］｛｝．、：";

  //単語(識別子)
  var pat_word1 = "[^" + pat_josi2 + pat_kakko2 + pat_symbol2 + pat_num2 + "]";
  var pat_word2 = "[^" + pat_josi2 + pat_kakko2 + pat_symbol2 + "]";
  this.word = new RegExp("^" + pat_word1 + pat_word2 + "*");

  // その他
  this.yylval;
  this.Escreen = document.getElementById("screen");
  this.debug_clean();
}

soramame.prototype.yylex = function(){
  var retval = WORD;

  // 文の終端を読み飛ばす
  while(this.isCRLF(this.source.charAt(0))){
    this.source = this.source.substring(1);
  }

  //スペース(全角、半角)とタブを読み飛ばす
  var p = this.source.match(/^[\s　]+/);
  if (p != null) {
	this.source = this.source.substring(p[0].length);
  }

  // 1文を取り出す
  var line = this.source;
  var p = line.match(this.CRLF);
  if (p != null) {
	line = line.substring(0, p[0].length);
  }

  //行コメント
  p = line.match(this.comment_line);
  if (p != null) {
	this.source = this.source.substr(line.length);
	this.yylval= line + "";
	return COMMENT;
  }

  // 文字列
  p = line.match(this.string_literal);
  if (p != null) {
  	var bracket = "'";
    if (p[0].substring(0,1) == "『") {
		bracket = '"';
	}
	var line = bracket + p[0].substring(1, p[0].length - 1) + bracket;

	this.source = this.source.substring(p[0].length);
    this.yylval = line + "";
	return STRING;
  }

  // 助詞
  p = line.match(this.josi);
  if (p != null) {
	var josi = p[0];
	this.source = this.source.substring(josi.length);
    this.yylval = josi + "";
	return JOSI;
  }

  // 数字
  if(this.isdigit(line.charAt(0))){
    var token = '';
    var l = line.length;
    for(var i = 0; i < l; i++){
      var c = this.isdigit(line.charAt(i));
      if(!c){
        break;
      }
      token += c;
    }
    this.source = this.source.substring(i);
    this.yylval = token - 0;
	return NUMBER;
  }

  // 記号
  var c = this.issymbol(line.charAt(0));
  if(c){
    this.source = this.source.substring(1);
    this.yylval = c;
    return c.charCodeAt(0);
  }

  // 単語
  var token = line.match(this.word);
  if(token != null){
    token = String(token[0]);
  } else {
    token = "";
  }
  if(token){
    this.source = this.source.substring(token.length);
  } else {
    token = line;
    this.source = this.source.substring(line.length);
  }
  this.yylval = token;
  if(!token){
    retval = 0;
  }
  return retval;
  /*
  this.debug("line = "+line);
  this.debug("token.length = "+token.length);
  this.debug("this.source = "+this.source);
  this.debug("this.source = "+this.source);
  */
}

soramame.prototype.isCRLF = function(c){
  var l = this.CRLF.length;
  for(var i = 0; i < l; i++){
    if(c == this.CRLF[i]){
      return true;
    }
  }
  return false;
}

soramame.prototype.isdigit = function(c){
  if('0' <= c && c <= '9'){
    return c;
  }
  if('０' <= c && c <= '９'){
    return this.zen2han(c);
  }
  if(c == '.'){
    return c;
  }
  if(c == '．'){
    return this.zen2han(c);
  }
  return false;
}

soramame.prototype.issymbol = function(c){
  switch(c){
  case "=":
  case "+":
  case "-":
  case "*":
  case "/":
  case "^":
  case "(":
  case ")":
  case "[":
  case "]":
  case "{":
  case "}":
  case ",":
  case ":":
    return c;

  case "＝":
  case "＋":
  case "－":
  case "×":
  case "＊":
  case "÷":
  case "／":
  case "％":
  case "＾":
  case "（":
  case "）":
  case "［":
  case "］":
  case "｛":
  case "｝":
  case "、":
  case "：":
    return this.zen2han(c);
  }

  switch(c.charCodeAt(0)){
  case 65288:
    return c;
    return this.zen2han(c);
  }

  return false;
}

soramame.prototype.zen2han = function(c){
  var hankaku = "0123456789+-**//%^()[]{}.,:";
  var zenkaku = "０１２３４５６７８９＋－×＊÷／％＾（）［］｛｝．、：";
  return hankaku.charAt(zenkaku.indexOf(c));
}

soramame.prototype.debug = function(str){
  this.Escreen.innerHTML += str+"
\n";
}

soramame.prototype.debug_clean = function(){
  this.Escreen.innerHTML = '';
}
<commit_msg>行コメントを切り出し：OK 行末検出を修正<commit_after>function soramame(source){
  // ソースコード
  this.source = source;

  // 文の終端記号
  var pat_CRCF = "(\n|\r|。)";
  this.CRLF = new RegExp("^" + pat_CRCF);

  //行コメント
　　var pat_comment_line = "\/\/";
  this.comment_line = new RegExp("^" + pat_comment_line);

  // 助詞
  var pat_josi = "[◎●はのにでを]";	//助詞の判定用
  var pat_josi2 = "◎●はのにでを";	//助詞以外の判定用
  this.josi = new RegExp("^" + pat_josi);

  // 文字列リテラル
  var pat_kakko = "(「.*」|『.*』)";
  var pat_kakko2 = "「」『』";
  this.string_literal = new RegExp("^" + pat_kakko);

  // 数字
  var pat_num2 = "0123456789０１２３４５６７８９";

 　// 記号
  var pat_symbol2 = "\*=\+\-\/%^\(\)\[\\]{}\.,:＝＋－×＊÷／％＾（）［］｛｝．、：";

  //単語(識別子)
  var pat_word1 = "[^" + pat_josi2 + pat_kakko2 + pat_symbol2 + pat_num2 + "]";
  var pat_word2 = "[^" + pat_josi2 + pat_kakko2 + pat_symbol2 + "]";
  this.word = new RegExp("^" + pat_word1 + pat_word2 + "*");

  // その他
  this.yylval;
  this.Escreen = document.getElementById("screen");
  this.debug_clean();
}

soramame.prototype.yylex = function(){
  var retval = WORD;

  // 文の終端を読み飛ばす
  while(this.isCRLF(this.source.charAt(0))){
    this.source = this.source.substring(1);
  }

  //スペース(全角、半角)とタブを読み飛ばす
  var p = this.source.match(/^[\s　]+/);
  if (p != null) {
	this.source = this.source.substring(p[0].length);
  }

  // 1文を取り出す
  var line = this.source;
  var p = line.match(this.CRLF);
  if (p != null) {
	line = line.substring(0, p[0].length);
  }

  //行コメント
  p = line.match(this.comment_line);
  if (p != null) {
    var index = line.indexOf("\n");
	if (index != "-1") {
		line = line.substr(0, index);
	}
	this.source = this.source.substr(line.length);
	this.yylval= line + "";
	return COMMENT;
  }

  // 文字列
  p = line.match(this.string_literal);
  if (p != null) {
  	var bracket = "'";
    if (p[0].substring(0,1) == "『") {
		bracket = '"';
	}
	var line = bracket + p[0].substring(1, p[0].length - 1) + bracket;

	this.source = this.source.substring(p[0].length);
    this.yylval = line + "";
	return STRING;
  }

  // 助詞
  p = line.match(this.josi);
  if (p != null) {
	var josi = p[0];
	this.source = this.source.substring(josi.length);
    this.yylval = josi + "";
	return JOSI;
  }

  // 数字
  if(this.isdigit(line.charAt(0))){
    var token = '';
    var l = line.length;
    for(var i = 0; i < l; i++){
      var c = this.isdigit(line.charAt(i));
      if(!c){
        break;
      }
      token += c;
    }
    this.source = this.source.substring(i);
    this.yylval = token - 0;
	return NUMBER;
  }

  // 記号
  var c = this.issymbol(line.charAt(0));
  if(c){
    this.source = this.source.substring(1);
    this.yylval = c;
    return c.charCodeAt(0);
  }

  // 単語
  var token = line.match(this.word);
  if(token != null){
    token = String(token[0]);
  } else {
    token = "";
  }
  if(token){
    this.source = this.source.substring(token.length);
  } else {
    token = line;
    this.source = this.source.substring(line.length);
  }
  this.yylval = token;
  if(!token){
    retval = 0;
  }
  return retval;
  /*
  this.debug("line = "+line);
  this.debug("token.length = "+token.length);
  this.debug("this.source = "+this.source);
  this.debug("this.source = "+this.source);
  */
}

soramame.prototype.isCRLF = function(c){
  var l = this.CRLF.length;
  for(var i = 0; i < l; i++){
    if(c == this.CRLF[i]){
      return true;
    }
  }
  return false;
}

soramame.prototype.isdigit = function(c){
  if('0' <= c && c <= '9'){
    return c;
  }
  if('０' <= c && c <= '９'){
    return this.zen2han(c);
  }
  if(c == '.'){
    return c;
  }
  if(c == '．'){
    return this.zen2han(c);
  }
  return false;
}

soramame.prototype.issymbol = function(c){
  switch(c){
  case "=":
  case "+":
  case "-":
  case "*":
  case "/":
  case "^":
  case "(":
  case ")":
  case "[":
  case "]":
  case "{":
  case "}":
  case ",":
  case ":":
    return c;

  case "＝":
  case "＋":
  case "－":
  case "×":
  case "＊":
  case "÷":
  case "／":
  case "％":
  case "＾":
  case "（":
  case "）":
  case "［":
  case "］":
  case "｛":
  case "｝":
  case "、":
  case "：":
    return this.zen2han(c);
  }

  switch(c.charCodeAt(0)){
  case 65288:
    return c;
    return this.zen2han(c);
  }

  return false;
}

soramame.prototype.zen2han = function(c){
  var hankaku = "0123456789+-**//%^()[]{}.,:";
  var zenkaku = "０１２３４５６７８９＋－×＊÷／％＾（）［］｛｝．、：";
  return hankaku.charAt(zenkaku.indexOf(c));
}

soramame.prototype.debug = function(str){
  this.Escreen.innerHTML += str+"
\n";
}

soramame.prototype.debug_clean = function(){
  this.Escreen.innerHTML = '';
}
<|endoftext|>