<commit_before>'use strict';

/**
 * A simple library for making microservice message bus
 * calls using RabbitMQ.
 *
 * @module postmaster-general
 */
const EventEmitter = require('events');
const rabbit = require('rabbot');
const Promise = require('bluebird');
const uuid = require('uuid');
const bunyan = require('bunyan');
const defaults = require('./defaults');

class PostmasterGeneral extends EventEmitter {
	/**
	 * Constructor function for the PostmasterGeneral object.
	 * @param {string} queueName
	 * @param {object} [options]
	 */
	constructor(queueName, options) {
		super();

		options = options || {};
		this.settings = defaults;

		// Set uri, or default to localhost.
		if (typeof options.uri !== 'undefined') {
			this.settings.connection.uri = options.uri;
		}

		// Set options for listening.
		const listenerQueue = this.settings.queues[0];
		listenerQueue.name = queueName;

		if (typeof options.durable !== 'undefined') {
			listenerQueue.durable = options.durable;
		}
		if (typeof options.autoDelete !== 'undefined') {
			listenerQueue.autoDelete = options.autoDelete;
		}
		if (typeof options.exclusive !== 'undefined') {
			listenerQueue.exclusive = options.exclusive;
		}
		if (typeof options.limit !== 'undefined') {
			listenerQueue.limit = options.limit;
		}
		if (typeof options.messageTtl !== 'undefined') {
			listenerQueue.messageTtl = options.messageTtl;
		}

		// Only allow listening on two exchanges: postmaster.topic and postmaster.dlx.
		if (options.exchange === 'postmaster.dlx') {
			this.listenExchangeName = this.settings.exchanges[1].name;
		} else {
			this.listenExchangeName = this.settings.exchanges[0].name;
		}

		// Set options for publishing.
		this.settings.connection.replyTimeout = listenerQueue.messageTtl;

		const replyQueueName = options.replyQueue || 'queue';
		this.settings.connection.replyQueue = `postmaster.reply.${replyQueueName}.${uuid.v4()}`;

		// Postmaster expects loggers to be syntactially-compatible with the excellent Bunyan library.
		this.logger = options.logger;
		if (!this.logger) {
			this.logger = bunyan.createLogger({
				name: 'postmaster-general',
				serializers: {err: bunyan.stdSerializers.err}
			});

			// Default log level to info.
			this.logger.level(options.logLevel || 'info');
		}

		// Store a reference to rabbot.
		this.rabbit = rabbit;

		// We want to automatically send all unhandled messages and errors to the dead letter queue.
		this.rabbit.rejectUnhandled();

		// Add event listeners to log events from rabbot.
		this.rabbit.on('failed', () => {
			this.logger.warn('postmaster-general failed to connect to RabbitMQ! Retrying...');
		});
		this.rabbit.on('unreachable', () => {
			this.logger.error('postmaster-general is unable to reach RabbitMQ!');
			this.emit('unreachable');
		});

		// Store a list of message handlers.
		this.listeners = {};

		// If set, this will cause postmaster-general to log a warning when a message takes too long to ack.
		this.settings.ackWarnTimeout = options.ackWarnTimeout;
	}

	/**
	 * Called to start the PostmasterGeneral instance.
	 */
	start() {
		this.logger.info('Starting postmaster-general...');
		return this.rabbit.configure(this.settings)
			.then(() => {
				const promises = [];
				for (let topic of Object.keys(this.listeners)) {
					promises.push(this.rabbit.bindQueue(this.listenExchangeName, this.settings.queues[0].name, topic));
				}
				return Promise.all(promises);
			})
			.then(() => {
				this.logger.info('postmaster-general started.');
			})
			.catch((err) => {
				this.logger.error({err: err}, 'postmaster-general failed to start!');
				throw err;
			});
	}

	/**
	 * Called to stop the PostmasterGeneral instance.
	 */
	stop() {
		this.logger.info('Shutting down postmaster-general...');
		return this.rabbit.shutdown().then(() => {
			this.logger.info('postmaster-general shutdown successfully.');
		})
			.catch((err) => {
				this.logger.warn({err: err}, 'postmaster-general encountered error when trying to shutdown!');
			});
	}

	/**
	 * Called to resolve the AMQP topic key corresponding to an address.
	 * @param {string} address
	 */
	resolveTopic(address) {
		return address.replace(/:/g, '.');
	}

	/**
	 * Publishes a message to the specified address.
	 * @param {string} address - The message address.
	 * @param {object} message - The message data.
	 * @param {object} [args] - Optional arguments, including "requestId", and "trace".
	 * @returns {Promise} - Promise returning the message response.
	 */
	publish(address, message, args) {
		args = args || {};

		const exchange = this.settings.exchanges[0].name;
		const options = {
			type: this.resolveTopic(address),
			body: message,
			headers: {
				requestId: args.requestId || uuid.v4(),
				trace: args.trace
			}
		};

		this.logger.trace({address: address, message: message}, `Sent fire-and-forget message.`);
		return this.rabbit.publish(exchange, options).catch((err) => {
			this.logger.error({err: err, address: address, message: message}, `postmaster-general failed to send fire-and-forget message!`);
			throw err;
		});
	}

	/**
	 * Publishes a message to the specified address, returning a promise that resolves on reply.
	 * @param {string} address - The message address.
	 * @param {object} message - The message data.
	 * @param {object} [args] - Optional arguments, including "requestId", and "trace".
	 * @returns {Promise} - Promise returning the message response.
	 */
	request(address, message, args) {
		args = args || {};

		const exchange = this.settings.exchanges[0].name;
		const options = {
			type: this.resolveTopic(address),
			body: message,
			headers: {
				requestId: args.requestId || uuid.v4(),
				trace: args.trace
			},
			correlationId: args.correlationId || uuid.v4()
		};

		// If we have the ack timer enabled, start it up.
		let ackTimeout = this.settings.ackWarnTimeout ? setTimeout(() => {
			this.logger.warn({address: address, message: message}, 'postmaster-general hit the ACK timeout for a publisher request!');
		}, this.settings.ackWarnTimeout) : null;

		// If we want a reply, call request.
		this.logger.trace({address: address, message: message}, `postmaster-general sent RPC call.`);
		return this.rabbit.request(exchange, options)
			.then((reply) => {
				reply.ack();

				reply.properties = reply.properties || {};
				reply.properties.headers = reply.properties.headers || {};

				const body = reply.body;
				body.$requestId = reply.properties.headers.requestId;
				body.$trace = reply.properties.headers.trace;
				return body;
			})
			.catch((err) => {
				this.logger.error({err: err, address: address, message: message}, `postmaster-general failed to send RPC call!`);
				throw err;
			})
			.then((body) => {
				if (ackTimeout) {
					clearTimeout(ackTimeout);
				}
				return body;
			});
	}

	/**
	 * Called to bind a new listener to the queue.
	 * @param {string} address - The message address.
	 * @param {function} callback - The callback function that handles the message.
	 * @param {object} [context] - The object to use as the "this" context during execution of the callback function.
	 */
	addListener(address, callback, context) {
		const topic = this.resolveTopic(address);

		return new Promise((resolve, reject) => {
			try {
				this.listeners[topic] = this.rabbit.handle({
					type: topic,
					context: this,
					handler: function (message) {
						if (!message.body) {
							throw new Error('Missing field "body" for message!');
						}

						message.properties = message.properties || {};
						message.properties.headers = message.properties.headers || {};

						const replyTo = message.properties.replyTo;
						const requestId = message.properties.headers.requestId;
						const trace = message.properties.headers.trace;
						const correlationId = message.properties.correlationId;
						const messageId = message.properties.messageId;

						// To make things easier on ourselves, convert the callback to a promise.
						const promiseCallback = Promise.promisify(callback, {context: context});
						const body = message.body;
						body.$requestId = requestId;
						body.$trace = trace;

						// If we have the ack timer enabled, start it up.
						let ackTimeout = this.settings.ackWarnTimeout ? setTimeout(() => {
							this.logger.warn({address: address, message: message}, 'postmaster-general hit the ACK timeout for a listener!');
						}, this.settings.ackWarnTimeout) : null;

						return promiseCallback(body)
							.then((reply) => {
								this.logger.trace({address: address, message: message}, 'postmaster-general processed callback for message.');

								// If we have an error that should be returned to the caller, log it and convert the error to a string.
								if (reply.err) {
									this.logger.error({err: reply.err, address: address, message: message}, 'postmaster-general callback returned an error!');
									reply.err = reply.err.message || reply.err.name;
								}

								if (replyTo && correlationId) {
									// Make sure messsageId and correlationId match, for backwards-compatibility.
									if (!messageId) {
										message.properties.messageId = correlationId;
									}

									message.reply(reply, {headers: {requestId: requestId, trace: trace}});
								} else {
									message.ack();
								}
							})
							.catch((err) => {
								this.logger.error({err: err, address: address, message: message}, 'postmaster-general encountered error processing callback!');
								message.reject();
							})
							.then(() => {
								if (ackTimeout) {
									clearTimeout(ackTimeout);
								}
							});
					}
				});

				// Add a sanity-check error handler for the listener, in case an exception is thrown that's not caught in the promise.
				this.listeners[topic].catch((err, message) => {
					this.logger.error({err: err, address: address, message: message}, 'postmaster-general encountered error processing callback!');
					message.reject();
				});

				resolve();
			} catch (err) {
				this.logger.error({err: err, address: address}, 'postmaster-general encountered error while registering a listener!');
				reject(err);
			}
		});
	}

	/**
	 * Called to unbind a new listener from the queue.
	 * @param {string} address - The message address.
	 */
	removeListener(address) {
		const topic = this.resolveTopic(address);

		return new Promise((resolve, reject) => {
			try {
				const handler = this.listeners[topic];
				if (handler) {
					handler.remove();
					delete this.listeners[topic];
					this.logger.info({address: address}, 'postmaster-general removed listener callback.');
				}
				resolve();
			} catch (err) {
				this.logger.error({err: err, address: address}, 'postmaster-general encountered error while removing a listener!');
				reject(err);
			}
		});
	}
}

module.exports = PostmasterGeneral;

// Start up postmaster if this module is run as a script.
if (require.main === module) {
	const postmaster = new PostmasterGeneral();
	postmaster.start();
}
<commit_msg>Fix bug with missing replies.<commit_after>'use strict';

/**
 * A simple library for making microservice message bus
 * calls using RabbitMQ.
 *
 * @module postmaster-general
 */
const EventEmitter = require('events');
const rabbit = require('rabbot');
const Promise = require('bluebird');
const uuid = require('uuid');
const bunyan = require('bunyan');
const defaults = require('./defaults');

class PostmasterGeneral extends EventEmitter {
	/**
	 * Constructor function for the PostmasterGeneral object.
	 * @param {string} queueName
	 * @param {object} [options]
	 */
	constructor(queueName, options) {
		super();

		options = options || {};
		this.settings = defaults;

		// Set uri, or default to localhost.
		if (typeof options.uri !== 'undefined') {
			this.settings.connection.uri = options.uri;
		}

		// Set options for listening.
		const listenerQueue = this.settings.queues[0];
		listenerQueue.name = queueName;

		if (typeof options.durable !== 'undefined') {
			listenerQueue.durable = options.durable;
		}
		if (typeof options.autoDelete !== 'undefined') {
			listenerQueue.autoDelete = options.autoDelete;
		}
		if (typeof options.exclusive !== 'undefined') {
			listenerQueue.exclusive = options.exclusive;
		}
		if (typeof options.limit !== 'undefined') {
			listenerQueue.limit = options.limit;
		}
		if (typeof options.messageTtl !== 'undefined') {
			listenerQueue.messageTtl = options.messageTtl;
		}

		// Only allow listening on two exchanges: postmaster.topic and postmaster.dlx.
		if (options.exchange === 'postmaster.dlx') {
			this.listenExchangeName = this.settings.exchanges[1].name;
		} else {
			this.listenExchangeName = this.settings.exchanges[0].name;
		}

		// Set options for publishing.
		this.settings.connection.replyTimeout = listenerQueue.messageTtl;

		const replyQueueName = options.replyQueue || 'queue';
		this.settings.connection.replyQueue = `postmaster.reply.${replyQueueName}.${uuid.v4()}`;

		// Postmaster expects loggers to be syntactially-compatible with the excellent Bunyan library.
		this.logger = options.logger;
		if (!this.logger) {
			this.logger = bunyan.createLogger({
				name: 'postmaster-general',
				serializers: {err: bunyan.stdSerializers.err}
			});

			// Default log level to info.
			this.logger.level(options.logLevel || 'info');
		}

		// Store a reference to rabbot.
		this.rabbit = rabbit;

		// We want to automatically send all unhandled messages and errors to the dead letter queue.
		this.rabbit.rejectUnhandled();

		// Add event listeners to log events from rabbot.
		this.rabbit.on('failed', () => {
			this.logger.warn('postmaster-general failed to connect to RabbitMQ! Retrying...');
		});
		this.rabbit.on('unreachable', () => {
			this.logger.error('postmaster-general is unable to reach RabbitMQ!');
			this.emit('unreachable');
		});

		// Store a list of message handlers.
		this.listeners = {};

		// If set, this will cause postmaster-general to log a warning when a message takes too long to ack.
		this.settings.ackWarnTimeout = options.ackWarnTimeout;
	}

	/**
	 * Called to start the PostmasterGeneral instance.
	 */
	start() {
		this.logger.info('Starting postmaster-general...');
		return this.rabbit.configure(this.settings)
			.then(() => {
				const promises = [];
				for (let topic of Object.keys(this.listeners)) {
					promises.push(this.rabbit.bindQueue(this.listenExchangeName, this.settings.queues[0].name, topic));
				}
				return Promise.all(promises);
			})
			.then(() => {
				this.logger.info('postmaster-general started.');
			})
			.catch((err) => {
				this.logger.error({err: err}, 'postmaster-general failed to start!');
				throw err;
			});
	}

	/**
	 * Called to stop the PostmasterGeneral instance.
	 */
	stop() {
		this.logger.info('Shutting down postmaster-general...');
		return this.rabbit.shutdown().then(() => {
			this.logger.info('postmaster-general shutdown successfully.');
		})
			.catch((err) => {
				this.logger.warn({err: err}, 'postmaster-general encountered error when trying to shutdown!');
			});
	}

	/**
	 * Called to resolve the AMQP topic key corresponding to an address.
	 * @param {string} address
	 */
	resolveTopic(address) {
		return address.replace(/:/g, '.');
	}

	/**
	 * Publishes a message to the specified address.
	 * @param {string} address - The message address.
	 * @param {object} message - The message data.
	 * @param {object} [args] - Optional arguments, including "requestId", and "trace".
	 * @returns {Promise} - Promise returning the message response.
	 */
	publish(address, message, args) {
		args = args || {};

		const exchange = this.settings.exchanges[0].name;
		const options = {
			type: this.resolveTopic(address),
			body: message,
			headers: {
				requestId: args.requestId || uuid.v4(),
				trace: args.trace
			}
		};

		this.logger.trace({address: address, message: message}, `Sent fire-and-forget message.`);
		return this.rabbit.publish(exchange, options).catch((err) => {
			this.logger.error({err: err, address: address, message: message}, `postmaster-general failed to send fire-and-forget message!`);
			throw err;
		});
	}

	/**
	 * Publishes a message to the specified address, returning a promise that resolves on reply.
	 * @param {string} address - The message address.
	 * @param {object} message - The message data.
	 * @param {object} [args] - Optional arguments, including "requestId", and "trace".
	 * @returns {Promise} - Promise returning the message response.
	 */
	request(address, message, args) {
		args = args || {};

		const exchange = this.settings.exchanges[0].name;
		const options = {
			type: this.resolveTopic(address),
			body: message,
			headers: {
				requestId: args.requestId || uuid.v4(),
				trace: args.trace
			},
			correlationId: args.correlationId || uuid.v4()
		};

		// If we have the ack timer enabled, start it up.
		let ackTimeout = this.settings.ackWarnTimeout ? setTimeout(() => {
			this.logger.warn({address: address, message: message}, 'postmaster-general hit the ACK timeout for a publisher request!');
		}, this.settings.ackWarnTimeout) : null;

		// If we want a reply, call request.
		this.logger.trace({address: address, message: message}, `postmaster-general sent RPC call.`);
		return this.rabbit.request(exchange, options)
			.then((reply) => {
				reply.ack();

				reply.properties = reply.properties || {};
				reply.properties.headers = reply.properties.headers || {};

				const body = reply.body;
				body.$requestId = reply.properties.headers.requestId;
				body.$trace = reply.properties.headers.trace;
				return body;
			})
			.catch((err) => {
				this.logger.error({err: err, address: address, message: message}, `postmaster-general failed to send RPC call!`);
				throw err;
			})
			.then((body) => {
				if (ackTimeout) {
					clearTimeout(ackTimeout);
				}
				return body;
			});
	}

	/**
	 * Called to bind a new listener to the queue.
	 * @param {string} address - The message address.
	 * @param {function} callback - The callback function that handles the message.
	 * @param {object} [context] - The object to use as the "this" context during execution of the callback function.
	 */
	addListener(address, callback, context) {
		const topic = this.resolveTopic(address);

		return new Promise((resolve, reject) => {
			try {
				this.listeners[topic] = this.rabbit.handle({
					type: topic,
					context: this,
					handler: function (message) {
						if (!message.body) {
							throw new Error('Missing field "body" for message!');
						}

						message.properties = message.properties || {};
						message.properties.headers = message.properties.headers || {};

						const replyTo = message.properties.replyTo;
						const requestId = message.properties.headers.requestId;
						const trace = message.properties.headers.trace;
						const correlationId = message.properties.correlationId;
						const messageId = message.properties.messageId;

						// To make things easier on ourselves, convert the callback to a promise.
						const promiseCallback = Promise.promisify(callback, {context: context});
						const body = message.body;
						body.$requestId = requestId;
						body.$trace = trace;

						// If we have the ack timer enabled, start it up.
						let ackTimeout = this.settings.ackWarnTimeout ? setTimeout(() => {
							this.logger.warn({address: address, message: message}, 'postmaster-general hit the ACK timeout for a listener!');
						}, this.settings.ackWarnTimeout) : null;

						return promiseCallback(body)
							.then((reply) => {
								this.logger.trace({address: address, message: message}, 'postmaster-general processed callback for message.');

								// If we have an error that should be returned to the caller, log it and convert the error to a string.
								if (reply && reply.err) {
									this.logger.error({err: reply.err, address: address, message: message}, 'postmaster-general callback returned an error!');
									reply.err = reply.err.message || reply.err.name;
								}

								if (replyTo && correlationId) {
									// Make sure messsageId and correlationId match, for backwards-compatibility.
									if (!messageId) {
										message.properties.messageId = correlationId;
									}

									message.reply(reply, {headers: {requestId: requestId, trace: trace}});
								} else {
									message.ack();
								}
							})
							.catch((err) => {
								this.logger.error({err: err, address: address, message: message}, 'postmaster-general encountered error processing callback!');
								message.reject();
							})
							.then(() => {
								if (ackTimeout) {
									clearTimeout(ackTimeout);
								}
							});
					}
				});

				// Add a sanity-check error handler for the listener, in case an exception is thrown that's not caught in the promise.
				this.listeners[topic].catch((err, message) => {
					this.logger.error({err: err, address: address, message: message}, 'postmaster-general encountered error processing callback!');
					message.reject();
				});

				resolve();
			} catch (err) {
				this.logger.error({err: err, address: address}, 'postmaster-general encountered error while registering a listener!');
				reject(err);
			}
		});
	}

	/**
	 * Called to unbind a new listener from the queue.
	 * @param {string} address - The message address.
	 */
	removeListener(address) {
		const topic = this.resolveTopic(address);

		return new Promise((resolve, reject) => {
			try {
				const handler = this.listeners[topic];
				if (handler) {
					handler.remove();
					delete this.listeners[topic];
					this.logger.info({address: address}, 'postmaster-general removed listener callback.');
				}
				resolve();
			} catch (err) {
				this.logger.error({err: err, address: address}, 'postmaster-general encountered error while removing a listener!');
				reject(err);
			}
		});
	}
}

module.exports = PostmasterGeneral;

// Start up postmaster if this module is run as a script.
if (require.main === module) {
	const postmaster = new PostmasterGeneral();
	postmaster.start();
}
<|endoftext|>


<commit_before>import { Mongo } from 'meteor/mongo';

const Items = new Mongo.Collection('items');

Meteor.methods({
  'items.addOne': ({ name }) => {
    return Items.insert({ name });
  },
});

Meteor.publish('items', () => {
  return Items.find();
});

export default Items;
<commit_msg>Remove unused items<commit_after><|endoftext|>


<commit_before>/*eslint-env node */
/*eslint no-sync: "off", global-require: "off"*/
'use strict';

var path = require('path')
  , basename = path.basename(__filename, '.js')
  , debug = require('debug')('ezmaster:' + basename)
  , bodyParser = require('body-parser')
  , fs = require('fs')
  , getSize = require('get-folder-size')
  , filesize = require('filesize')
  , Docker = require('dockerode')
  , docker = new Docker({ socketPath: '/var/run/docker.sock'})
  , exec = require('child_process').exec
  , jsonfile = require('jsonfile')
  , mkdirp = require('mkdirp')
  , rimraf = require('rimraf')
  , fileExists = require('file-exists')
  , instances = require('../helpers/instances')
  , app = require('../helpers/app')
  //, util = require('utile')
  , instancesArray
  , containers
  , portMax
  , freePortSplitted
  ;

// The bool to check if the instances cache is up to date.
var instancesChangesBool = true;

jsonfile.spaces = 2;

module.exports = function (router, core) {

  router.route('/').get(function (req, res, next) {

    return res.render('template.html');

  });

  router.route('/-/v1/app').get(function (req, res, next) {

    app.getApps(function (err, data) {

      if (err) { return next(err); }
      return res.status(200).send(data);

    });

  });

  router.route('/-/v1/instances').get(function (req, res, next) {

    instances.getInstances(instancesChangesBool, function (err, data) {

      if (err) { return next(err); }

      return res.status(200).send(data);

    });

    // instancesChangesBool set to false because the cache is up to date.
    instancesChangesBool = false;

  });

  router.route('/-/v1/instances/:containerId').put(bodyParser(), function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      if (req.body.action == 'start' && data.State.Running == false) {
        container.start(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is started, we call refreshInstances() to update
          // the instances list cache and socket emit the updated list to all users.
          // The 'core' parameter allows to get the socket object inside refreshInstances().
          instances.refreshInstances(core);

          res.status(200).send('Starting done');
        });
      }
      else if (req.body.action == 'stop' && data.State.Running == true) {
        container.stop(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is stopped, we call refreshInstances() to update the
          // instances list cache and socket emit the updated list to all users.
          // The 'core' parameter allows to get the socket object inside refreshInstances().
          instances.refreshInstances(core);

          res.status(200).send('Stoping done');
        });
      }
      else if (req.body.action == 'updateConfig') {
        var splittedName = data.Name.split('/');

        jsonfile.writeFile(
          path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
          req.body.newConfig, function (err) {

            if (err) { return next(err); }

            if (data.State.Running == true) {
              container.restart(function (err) {
                if (err) { return next(err); }
                res.status(200).send('Update done');
              });
            }
            else {
              res.status(200).send('Update done');
            }
          });

        // When a new config is given to an instance, we call refreshInstances() to update the
        // instances list cache and socket emit the updated list to all users.
        // The 'core' parameter allows to get the socket object inside refreshInstances().
        instances.refreshInstances(core);
      }

    });
  });

  router.route('/-/v1/instances/verif/:technicalName').get(bodyParser(), function (req, res, next) {

    if (fileExists(path.join(__dirname, '../manifests/'+req.params.technicalName+'.json')) == false) {
      res.status(200).send('OK');
    }
    else {
      res.status(200).send('KO');
    }

  });

  router.route('/-/v1/instances/:containerId').get(bodyParser(), function (req, res, next) {

    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {

      if (err) { return next(err); }

      var splittedName = data.Name.split('/');

      // Delete information.
      var directoryDatas = path.join(__dirname, '../instances/', splittedName[1], '/data/')
        , result = {};

      getSize(directoryDatas, function (err, size) {

        if (err) { return next(err); }

        result.technicalName = splittedName[1];
        result.size = filesize(size);

        // Configuration information.
        jsonfile.readFile(
        path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
        function (err, obj) {

          if (err) { return next(err); }

          result.config = obj;

          return res.status(200).send(result);

        });

      });

    });

  });

  router.route('/-/v1/instances/:containerId').delete(function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      if (data.State.Running == true) {
        container.stop(function (err, datas, cont) {
          if (err) { return next(err); }

          container.remove(function (err, datas, cont) {
            if (err) { return next(err); }

          });
        });
      }
      else if (data.State.Running == false) {
        container.remove(function (err, datas, cont) {
          if (err) { return next(err); }
        });
      }

      var splittedName = data.Name.split('/');
      rimraf(path.join(__dirname, '../instances/', splittedName[1]), function (err) {
        if (err) { return next(err); }

        rimraf(path.join(__dirname, '../manifests/', splittedName[1] + '.json'), function (err) {
          if (err) { return next(err); }

          // When an instance is deleted, we call refreshInstances() to update the
          // instances list cache and socket emit the updated list to all users.
          // The 'core' parameter allows to get the socket object inside refreshInstances().
          instances.refreshInstances(core);

          res.status(200).send('Removing done');
        });
      });
    });

  });

  router.route('/-/v1/instances').post(bodyParser(), function (req, res, next) {

    var technicalName = req.body.technicalName
      , longName = req.body.longName
      , image = req.body.app
      , project = req.body.project
      , study = req.body.study
      ;

    if (/^[a-z0-9]+$/.test(project) == false && project != '' && project != null) {

      return res.status(400).send('Enter a valid project name');

    }

    if (/^[a-z0-9]+$/.test(study) == false && study != '' && study != null) {

      return res.status(400).send('Enter a valid study name');

    }

    if (fileExists(path.join(__dirname, '../manifests/'+req.query.technicalName+'.json')) == true) {

      res.status(409).send('Technical name already exists');

    }
    else {

      docker.pull(image, follow);

    }

    function follow(err, stream) {
      if (err) { return res.status(400).send(err); }

      docker.modem.followProgress(stream, onFinished);

    }

    function onFinished(err, output) {
      if (err) { return res.status(400).send(err); }

      mkdirp(path.join(__dirname, '../instances/'+technicalName+'/config/'), makeDataDirectory);
    }

    function makeDataDirectory(err) {
      if (err) { return next(err); }

      mkdirp(path.join(__dirname, '../instances/'+technicalName+'/data/'), createConfigFile);
    }

    function createConfigFile(err) {
      if (err) { return next(err); }

      fs.appendFile(
        path.join(
          __dirname, '../instances/'+technicalName+'/config/config.json'
        )
        , '{}'
        , readInstances
      );
    }

    function readInstances(err) {
      if (err) { return next(err); }

      instancesArray = fs.readdirSync(path.join(__dirname, '../instances/'));

      docker.listContainers({all : true}, createInstance);
    }

    function createInstance(err, containersList) {
      if (err) { return next(err); }

      containers = containersList;

      portMax = 0;
      freePortSplitted = process.env.EZMASTER_FREE_PORT_RANGE.split('-');

      checkContainer();
    }

    function checkContainer() {
      var element = containers.pop();

      if (element) {
        var splittedName = element.Names[0].split('/');
        if (instancesArray.indexOf(splittedName[1]) === -1) {
          return checkContainer();
        }

        var container = docker.getContainer(element.Id);

        container.inspect(checkPort);
      }
      else {
        if (!Number.isInteger(portMax) || portMax == 0) {
          portMax = freePortSplitted[0];
        }

        var cmd = 'docker run -d -p '+portMax+':3000 ' +
        '-e http_proxy -e https_proxy -e EZMASTER_MONGODB_HOST_PORT '+
        '--net=ezmaster_default --link ezmaster_db '+
        '-v '+process.env.EZMASTER_PATH+'/instances/'+
        technicalName+'/config/config.json:'+'/opt/ezmaster/config/config.json '+
        '-v '+process.env.EZMASTER_PATH+'/instances/'
        +technicalName+'/data/:/opt/ezmaster/data/ '+
        '--name '+technicalName+' '+image;

        var newlongName = {
          'longName' : longName
        };

        jsonfile.writeFile(
          path.join(__dirname, '../manifests/'+technicalName+'.json')
          , newlongName, function (err) {
            if (err) {
              return next(err);
            }
          });

        exec(cmd, refreshAndReturn);
      }
    }

    function checkPort(err, data) {
      if (err) { return next(err); }

      var keys =  Object.keys(data.HostConfig.PortBindings);
      var currentPort = data.HostConfig.PortBindings[keys[0]][0].HostPort;

      if (currentPort >= portMax) {
        portMax = parseInt(currentPort) + 1;
      }

      return checkContainer();
    }

    function refreshAndReturn(err, stdout, stderr) {
      if (err) { return next(err); }

      // When an instance is created, we call refreshInstances() to update the
      // instances list cache and socket emit the updated list to all users.
      // The 'core' parameter allows to get the socket object inside
      // refreshInstances().
      instances.refreshInstances(core);

      return res.status(200).send('Instance created');
    }

  }); // End of the route.

// APPLICATION MANAGEMENT

 router.route('/-/v1/app').post(bodyParser(), function (req, res, next) {

   var image = req.body.imageName;

     docker.pull(image, function(err, stream) {

  docker.modem.followProgress(stream, onFinished, onProgress);

  function onFinished(err, output) {
    if (err) { return res.status(400).send(err); }

     return res.status(200);
  }
  function onProgress(event) {
    //...
  }
});

 });

 router.route('/-/v1/app/:imageId/delete').get(function (req, res, next) {

   var container = docker.getImage(req.params.imageId);

   container.inspect(function (err, data) {

   var result = {};

   result['imageName'] = data.RepoTags;

   return res.status(200).send(result);

 });

 });

 router.route('/-/v1/app/:imageId').delete(function (req, res, next) {

   var image = docker.getImage(req.params.imageId);

   image.remove(function (err, datas, cont) {
     if (err.statusCode == '409') { return next(err); }
   });
 });

}; // End of module.exports = function (router, core) {<commit_msg>Minor changes.<commit_after>/*eslint-env node */
/*eslint no-sync: "off", global-require: "off"*/
'use strict';

var path = require('path')
  , basename = path.basename(__filename, '.js')
  , debug = require('debug')('ezmaster:' + basename)
  , bodyParser = require('body-parser')
  , fs = require('fs')
  , getSize = require('get-folder-size')
  , filesize = require('filesize')
  , Docker = require('dockerode')
  , docker = new Docker({ socketPath: '/var/run/docker.sock'})
  , exec = require('child_process').exec
  , jsonfile = require('jsonfile')
  , mkdirp = require('mkdirp')
  , rimraf = require('rimraf')
  , fileExists = require('file-exists')
  , instances = require('../helpers/instances')
  , app = require('../helpers/app')
  //, util = require('utile')
  , instancesArray
  , containers
  , portMax
  , freePortSplitted
  ;

// The bool to check if the instances cache is up to date.
var instancesChangesBool = true;

jsonfile.spaces = 2;

module.exports = function (router, core) {

  router.route('/').get(function (req, res, next) {

    return res.render('template.html');

  });

  router.route('/-/v1/app').get(function (req, res, next) {

    app.getApps(function (err, data) {

      if (err) { return next(err); }
      return res.status(200).send(data);

    });

  });

  router.route('/-/v1/instances').get(function (req, res, next) {

    instances.getInstances(instancesChangesBool, function (err, data) {

      if (err) { return next(err); }

      return res.status(200).send(data);

    });

    // instancesChangesBool set to false because the cache is up to date.
    instancesChangesBool = false;

  });

  router.route('/-/v1/instances/start/:containerId').put(bodyParser(), function (req, res, next) {

    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {

      if (err) { return next(err); }

      container.start(function (err, datas, container) {
        if (err) { return next(err); }

        // When an instance is started, we call refreshInstances() to update
        // the instances list cache and socket emit the updated list to all users.
        // The 'core' parameter allows to get the socket object inside refreshInstances().
        instances.refreshInstances(core);

        res.status(200).send('Starting done');

      });

    });
  });

  router.route('/-/v1/instances/stop/:containerId').put(bodyParser(), function (req, res, next) {

    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {

      if (err) { return next(err); }

      container.stop(function (err, datas, container) {
        if (err) { return next(err); }

        // When an instance is stopped, we call refreshInstances() to update the
        // instances list cache and socket emit the updated list to all users.
        // The 'core' parameter allows to get the socket object inside refreshInstances().
        instances.refreshInstances(core);

        res.status(200).send('Stoping done');
      });

    });
  });

  router.route('/-/v1/instances/config/:containerId').put(bodyParser(), function (req, res, next) {

    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {

      if (err) { return next(err); }

      var splittedName = data.Name.split('/');

      jsonfile.writeFile(
        path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
        req.body.newConfig, function (err) {

          if (err) { return next(err); }

          if (data.State.Running == true) {
            container.restart(function (err) {
              if (err) { return next(err); }
              res.status(200).send('Update done');
            });
          }
          else {
            res.status(200).send('Update done');
          }
        });

      // When a new config is given to an instance, we call refreshInstances() to update the
      // instances list cache and socket emit the updated list to all users.
      // The 'core' parameter allows to get the socket object inside refreshInstances().
      instances.refreshInstances(core);

    });
  });

  router.route('/-/v1/instances/verif/:technicalName').get(bodyParser(), function (req, res, next) {

    if (fileExists(path.join(__dirname, '../manifests/'+req.params.technicalName+'.json'))
    ==false) {
      res.status(200).send('OK');
    }
    else {
      res.status(200).send('KO');
    }

  });

  router.route('/-/v1/instances/:containerId').get(bodyParser(), function (req, res, next) {

    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {

      if (err) { return next(err); }

      var splittedName = data.Name.split('/');

      // Get Delete Information.
      var directoryDatas = path.join(__dirname, '../instances/', splittedName[1], '/data/')
        , result = {};

      getSize(directoryDatas, function (err, size) {

        if (err) { return next(err); }

        result.technicalName = splittedName[1];
        result.size = filesize(size);

        // Get Configuration Information.
        jsonfile.readFile(
        path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
        function (err, obj) {

          if (err) { return next(err); }

          result.config = obj;

          return res.status(200).send(result);

        });

      });

    });

  });

  router.route('/-/v1/instances/:containerId').delete(function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      if (data.State.Running == true) {
        container.stop(function (err, datas, cont) {
          if (err) { return next(err); }

          container.remove(function (err, datas, cont) {
            if (err) { return next(err); }

          });
        });
      }
      else if (data.State.Running == false) {
        container.remove(function (err, datas, cont) {
          if (err) { return next(err); }
        });
      }

      var splittedName = data.Name.split('/');
      rimraf(path.join(__dirname, '../instances/', splittedName[1]), function (err) {
        if (err) { return next(err); }

        rimraf(path.join(__dirname, '../manifests/', splittedName[1] + '.json'), function (err) {
          if (err) { return next(err); }

          // When an instance is deleted, we call refreshInstances() to update the
          // instances list cache and socket emit the updated list to all users.
          // The 'core' parameter allows to get the socket object inside refreshInstances().
          instances.refreshInstances(core);

          res.status(200).send('Removing done');
        });
      });
    });

  });

  router.route('/-/v1/instances').post(bodyParser(), function (req, res, next) {

    var technicalName = req.body.technicalName
      , longName = req.body.longName
      , image = req.body.app
      , project = req.body.project
      , study = req.body.study
      ;

    if (/^[a-z0-9]+$/.test(project) == false && project != '' && project != null) {

      return res.status(400).send('Enter a valid project name');

    }

    if (/^[a-z0-9]+$/.test(study) == false && study != '' && study != null) {

      return res.status(400).send('Enter a valid study name');

    }

    if (fileExists(path.join(__dirname, '../manifests/'+req.query.technicalName+'.json')) == true) {

      res.status(409).send('Technical name already exists');

    }
    else {

      docker.pull(image, follow);

    }

    function follow(err, stream) {
      if (err) { return res.status(400).send(err); }

      docker.modem.followProgress(stream, onFinished);

    }

    function onFinished(err, output) {
      if (err) { return res.status(400).send(err); }

      mkdirp(path.join(__dirname, '../instances/'+technicalName+'/config/'), makeDataDirectory);
    }

    function makeDataDirectory(err) {
      if (err) { return next(err); }

      mkdirp(path.join(__dirname, '../instances/'+technicalName+'/data/'), createConfigFile);
    }

    function createConfigFile(err) {
      if (err) { return next(err); }

      fs.appendFile(
        path.join(
          __dirname, '../instances/'+technicalName+'/config/config.json'
        )
        , '{}'
        , readInstances
      );
    }

    function readInstances(err) {
      if (err) { return next(err); }

      instancesArray = fs.readdirSync(path.join(__dirname, '../instances/'));

      docker.listContainers({all : true}, createInstance);
    }

    function createInstance(err, containersList) {
      if (err) { return next(err); }

      containers = containersList;

      portMax = 0;
      freePortSplitted = process.env.EZMASTER_FREE_PORT_RANGE.split('-');

      checkContainer();
    }

    function checkContainer() {
      var element = containers.pop();

      if (element) {
        var splittedName = element.Names[0].split('/');
        if (instancesArray.indexOf(splittedName[1]) === -1) {
          return checkContainer();
        }

        var container = docker.getContainer(element.Id);

        container.inspect(checkPort);
      }
      else {
        if (!Number.isInteger(portMax) || portMax == 0) {
          portMax = freePortSplitted[0];
        }

        var cmd = 'docker run -d -p '+portMax+':3000 ' +
        '-e http_proxy -e https_proxy -e EZMASTER_MONGODB_HOST_PORT '+
        '--net=ezmaster_default --link ezmaster_db '+
        '-v '+process.env.EZMASTER_PATH+'/instances/'+
        technicalName+'/config/config.json:'+'/opt/ezmaster/config/config.json '+
        '-v '+process.env.EZMASTER_PATH+'/instances/'
        +technicalName+'/data/:/opt/ezmaster/data/ '+
        '--name '+technicalName+' '+image;

        var newlongName = {
          'longName' : longName
        };

        jsonfile.writeFile(
          path.join(__dirname, '../manifests/'+technicalName+'.json')
          , newlongName, function (err) {
            if (err) {
              return next(err);
            }
          });

        exec(cmd, refreshAndReturn);
      }
    }

    function checkPort(err, data) {
      if (err) { return next(err); }

      var keys =  Object.keys(data.HostConfig.PortBindings);
      var currentPort = data.HostConfig.PortBindings[keys[0]][0].HostPort;

      if (currentPort >= portMax) {
        portMax = parseInt(currentPort) + 1;
      }

      return checkContainer();
    }

    function refreshAndReturn(err, stdout, stderr) {
      if (err) { return next(err); }

      // When an instance is created, we call refreshInstances() to update the
      // instances list cache and socket emit the updated list to all users.
      // The 'core' parameter allows to get the socket object inside
      // refreshInstances().
      instances.refreshInstances(core);

      return res.status(200).send('Instance created');
    }

  }); // End of the route.

// APPLICATION MANAGEMENT

 router.route('/-/v1/app').post(function (req, res, next) {

   var image = req.body.imageName;

   docker.pull(image, function (err, data) {

     console.log(data);

     if (err) { return res.status(400).send(err); }

     return res.status(200).send(data);

   });

 });

 router.route('/-/v1/app/:imageId/delete').get(function (req, res, next) {

   var container = docker.getImage(req.params.imageId);

   container.inspect(function (err, data) {

   var result = {};

   result['imageName'] = data.RepoTags;

   return res.status(200).send(result);

 });

 });

 router.route('/-/v1/app/:imageId').delete(function (req, res, next) {

   var image = docker.getImage(req.params.imageId);

   image.remove(function (err, datas, cont) {
     if (err) { return next(err); }
   });
 });

}; // End of module.exports = function (router, core) {<|endoftext|>


<commit_before>if (typeof(angular) !== 'undefined') {
  angular
    .module('xml', [])
    .config(['$provide', function ($provide) {

      $provide.factory('xmlHttpInterceptor', ['$q', 'xmlFilter', function ($q, xmlFilter) {
        return {
          response: function (response) {
            if (response) {
              response.xml = xmlFilter(response.data);
              return response;
            } else {
              return $q.when(response);
            }
          }
        };
      }]);

    }])
    .factory('xmlParser', ['$window', function ($window) {

      function MicrosoftXMLDOMParser() {
        this.parser = new $window.ActiveXObject('Microsoft.XMLDOM');
      }

      MicrosoftXMLDOMParser.prototype.parse = function (input) {
        this.parser.async = false;
        return this.parser.loadXml(input);
      };

      function XMLDOMParser() {
        this.parser = new $window.DOMParser();
      }

      XMLDOMParser.prototype.parse = function (input) {
        return this.parser.parseFromString(input, 'text/xml');
      };

      if ($window.DOMParser) {
        return new XMLDOMParser();
      } else if ($window.ActiveXObject) {
        return new MicrosoftXMLDOMParser();
      } else {
        throw new Error('Cannot parser XML in this environment.');
      }

    }])
    .filter('xml', ['xmlParser', function (xmlParser) {
      return function (input) {
        var xmlDoc = xmlParser.parse(input);
        return angular.element(xmlDoc);
      };
    }]);
}

<commit_msg>loadXml should be loadXML<commit_after>if (typeof(angular) !== 'undefined') {
  angular
    .module('xml', [])
    .config(['$provide', function ($provide) {

      $provide.factory('xmlHttpInterceptor', ['$q', 'xmlFilter', function ($q, xmlFilter) {
        return {
          response: function (response) {
            if (response) {
              response.xml = xmlFilter(response.data);
              return response;
            } else {
              return $q.when(response);
            }
          }
        };
      }]);

    }])
    .factory('xmlParser', ['$window', function ($window) {

      function MicrosoftXMLDOMParser() {
        this.parser = new $window.ActiveXObject('Microsoft.XMLDOM');
      }

      MicrosoftXMLDOMParser.prototype.parse = function (input) {
        this.parser.async = false;
        return this.parser.loadXML(input);
      };

      function XMLDOMParser() {
        this.parser = new $window.DOMParser();
      }

      XMLDOMParser.prototype.parse = function (input) {
        return this.parser.parseFromString(input, 'text/xml');
      };

      if ($window.DOMParser) {
        return new XMLDOMParser();
      } else if ($window.ActiveXObject) {
        return new MicrosoftXMLDOMParser();
      } else {
        throw new Error('Cannot parser XML in this environment.');
      }

    }])
    .filter('xml', ['xmlParser', function (xmlParser) {
      return function (input) {
        var xmlDoc = xmlParser.parse(input);
        return angular.element(xmlDoc);
      };
    }]);
}

<|endoftext|>


<commit_before>import React from 'react'
import DuckImage from '../assets/Duck.jpg'
import classes from './HomeView.scss'

export const HomeView = () => (

Objetivo

Criar o carrinho de compras de uma loja que vende desenvolvedores baseado no exemplo fornecido.

Queremos descobrir seu nível de habilidade em todas as áreas envolvidas na construção de um aplicativo web: back end, front end e usabilidade.

Sinta-se confortável para focar nas áreas que você tem mais habilidade.

Tarefas e priorização

Priorize a lista de tarefas abaixo explicando os motivos da priorização de cada uma delas. Então, escolha de três a seis tarefas para implementar.

Determinar o preço do desenvolvedor a partir de informações do seu perfil do GitHub, como por exemplo: followers, repos, stars, commits, etc.

Substituir os inputs de texto por uma lista de desenvolvedores com nome, foto, preço e um botão de “Adicionar ao carrinho”.

Criar paginação para a lista de desenvolvedores.

Popular a lista de desenvolvedores a partir de uma organização do GitHub.

Permitir a escolha de quantidade de horas contratadas de cada desenvolvedor.

Permitir a adição de um cupom de desconto que altera o preço total da compra. Utilize o código “SHIPIT”.

Melhorar a visualização do desenvolvedor no carrinho mostrando mais informações.

Adicionar um botão de “comprar” que leva o usuário a uma página de pedido confirmado.

Server side

Crie uma API REST simples que, no mínimo, utiliza uma lista em memória para guardar o estado do carrinho.

As tarefas mais avançadas exigem integração com API do GitHub. Além disso, você pode utilizar uma persistência mais robusta.

Testes automatizados são extremamente bem vindos.

Adoraríamos que você utilizasse Go, .NET ou Node para construir sua API. Caso contrário, justifique sua escolha de tecnologia.

Client side

Você pode implementar toda a interface com HTML renderizado server-side e formulários.

Uma opção melhor é criar uma single page application que utilize a API REST por AJAX.

De preferência, utilize React. Caso deseje utilizar outras tecnologias, justifique sua escolha.

Entrega e observações

Seu código deve estar disponível em um repositório git, preferencialmente hospedado no Github.

Você pode utilizar plataformas como Heroku ou Google Cloud Plataform para nos mostrar a aplicação funcionando em produção.

Não se preocupe se você não tem experiência em Go, Node ou React. Grande parte do nosso trabalho é lidar com novas tecnologias. Vamos levar isso em consideração.

Boa sorte!

)

export default HomeView
<commit_msg>add id to header<commit_after>import React from 'react'
import DuckImage from '../assets/Duck.jpg'
import classes from './HomeView.scss'

export const HomeView = () => (

Objetivo

Criar o carrinho de compras de uma loja que vende desenvolvedores baseado no exemplo fornecido.

Queremos descobrir seu nível de habilidade em todas as áreas envolvidas na construção de um aplicativo web: back end, front end e usabilidade.

Sinta-se confortável para focar nas áreas que você tem mais habilidade.

Tarefas e priorização

Priorize a lista de tarefas abaixo explicando os motivos da priorização de cada uma delas. Então, escolha de três a seis tarefas para implementar.

Determinar o preço do desenvolvedor a partir de informações do seu perfil do GitHub, como por exemplo: followers, repos, stars, commits, etc.

Substituir os inputs de texto por uma lista de desenvolvedores com nome, foto, preço e um botão de “Adicionar ao carrinho”.

Popular a lista de desenvolvedores a partir de uma organização do GitHub.

Permitir a escolha de quantidade de horas contratadas de cada desenvolvedor.

Permitir a adição de um cupom de desconto que altera o preço total da compra. Utilize o código “SHIPIT”.

Adicionar um botão de “comprar” que leva o usuário a uma página de pedido confirmado.

Melhorar a visualização do desenvolvedor no carrinho mostrando mais informações.

Criar paginação para a lista de desenvolvedores.

Server side

Crie uma API REST simples que, no mínimo, utiliza uma lista em memória para guardar o estado do carrinho.

As tarefas mais avançadas exigem integração com API do GitHub. Além disso, você pode utilizar uma persistência mais robusta.

Testes automatizados são extremamente bem vindos.

Adoraríamos que você utilizasse Go, .NET ou Node para construir sua API. Caso contrário, justifique sua escolha de tecnologia.

Client side

Você pode implementar toda a interface com HTML renderizado server-side e formulários.

Uma opção melhor é criar uma single page application que utilize a API REST por AJAX.

De preferência, utilize React. Caso deseje utilizar outras tecnologias, justifique sua escolha.

Entrega e observações

Seu código deve estar disponível em um repositório git, preferencialmente hospedado no Github.

Você pode utilizar plataformas como Heroku ou Google Cloud Plataform para nos mostrar a aplicação funcionando em produção.

Não se preocupe se você não tem experiência em Go, Node ou React. Grande parte do nosso trabalho é lidar com novas tecnologias. Vamos levar isso em consideração.

Boa sorte!

)

export default HomeView
<|endoftext|>


<commit_before>(function () { /* Begin of privacy scope */
    "use strict";
    /*global esprima, escodegen*/

    var
        gpfX = gpf.xml,
        versions = {
            debug: {
                UMD: true,
                DEBUG: true,
                keepComments: true,
                reduce: false,
                rewriteOptions: {
                    format: {
                        indent: {
                            style: "    ",
                            base: 0,
                            adjustMultilineComment: false
                        },
                        newline: "\n",
                        space: " ",
                        json: false,
                        renumber: false,
                        hexadecimal: false,
                        quotes: "double",
                        escapeless: false,
                        reduce: false,
                        parentheses: true,
                        semicolons: true,
                        safeConcatenation: false
                    },
                    comment: true
                }
            },
            release: {
                UMD: true,
                DEBUG: false,
                keepComments: false,
                reduce: true,
                rewriteOptions: {
                    format: {
                        indent: {
                            style: "",
                            base: 0,
                            adjustMultilineComment: false
                        },
                        newline: "",
                        space: "",
                        json: false,
                        renumber: false,
                        hexadecimal: false,
                        quotes: "double",
                        escapeless: false,
                        reduce: true,
                        parentheses: false,
                        semicolons: true,
                        safeConcatenation: true
                    },
                    comment: false
                }
            }
        },
        // body/item[@type="ExpressionStatement" and expression/@name="__gpf__"]
        xpathToGpfPlaceHolder = new gpfX.XPath({
            type: gpfX.NODE_ELEMENT,
            name: "body",
            relative: false,
            then: {
                type: gpfX.NODE_ELEMENT,
                name: "item",
                filter: {
                    and: [ {
                        type: gpfX.NODE_ATTRIBUTE,
                        name: "type",
                        text: "ExpressionStatement"
                    }, {
                        type: gpfX.NODE_ELEMENT,
                        name: "expression",
                        then: {
                            type: gpfX.NODE_ATTRIBUTE,
                            name: "name",
                            text: "__gpf__"
                        }
                    }]
                }
            }
        }),
        identifierCharacters = "abcdefghijklmnopqrstuvwxyz"
                             + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    ;

    //region Preprocessor (#ifdef)

    function preProcess(src, version) {
        var
            lines = src.split("\n"),
            len = lines.length,
            idx,
            line,
            ignoreStack = [false],
            ignore;
        for (idx = 0; idx < len; ++idx) {
            line = lines[idx];
            ignore = ignoreStack[ignoreStack.length - 1];
            if (-1 < line.indexOf("/*#if")) {
                // console.log("#" + line);
                // In the end, we use an "ignore" flag
                // so we invert the condition
                ignore = -1 === line.indexOf("/*#ifndef(");
                line = line.split("(")[1].split(")")[0];
                // console.log("\t" + line);
                ignore = gpf.xor(version[line], ignore);
                // console.log("\t" + ignore);
                ignoreStack.push(ignore);
                ignore = true; // Ignore this line
                // console.log(">>" + ignoreStack);
                /*
                 * TODO handle imbricated when the parent is false
                 */

            } else if (-1 < line.indexOf("/*#else")) {
                ignoreStack[ignoreStack.length - 1] = !ignore;
                ignore = true; // Ignore this line

            } else if (-1 < line.indexOf("/*#endif")) {
                // console.log("#" + line);
                ignoreStack.pop();
                ignore = true; // Ignore this line
                // console.log(">>" + ignoreStack);
            }
            // console.log((ignore ? "-" : "+")  + line);
            if (ignore) {
                lines.splice(idx, 1);
                --len;
                --idx;
            }
        }
        return lines.join("\n");
    }

    //endregion

    function toAST(parsed, src, version) {
        // https://github.com/Constellation/escodegen/issues/85
        try {
            var
                keepComments = version.keepComments,
                ast = esprima.parse(parsed[src], {
                    range: keepComments,
                    tokens: keepComments,
                    comment: keepComments
                });
            if (keepComments) {
                ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
                delete ast.tokens;
                delete ast.comments;
            }
            return ast;
        } catch(e) {
            console.error("Error in \"" + src + "\": " + e.message);
            throw e;
        }
    }

    //region AST compactor

    /**
     * AST Reducer
     *
     * @class ASTreducer
     * @private
     */
    var ASTreducer = gpf.define("ASTreducer", {

        public: {

            constructor: function() {

                this._identifiers = {};
                this._identifiersStack = [];

            },

            /**
             * Process the AST to reduce the generated source
             *
             * @param {Object} ast
             */
            reduce: function (ast) {
                this._walk(ast);
            },

            //region AST processing APIs

            beginIdentifierMapping: function (names, forVariables) {
//                if (START_TRACES) {
//                    console.log(">> beginIdentifierMapping");
//                    if (forVariables) {
//                        console.log("\t+[VAR] " + names.join(","));
//                    } else {
//                        console.log("\t+[FUN] " + names.join(","));
//                    }
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        var stackedNames = this._identifiersStack[idx];
//                        if (stackedNames.isVariables) {
//                            console.log("\t[VAR] " + stackedNames.join(","));
//                        } else {
//                            console.log("\t[FUN] " + stackedNames.join(","));
//                        }
//                    }
//                }
                var
                    len = names.length,
                    idx,
                    name;
                if (forVariables) {
                    names.isVariables = true;
                }
                names.identifierCount = this._identifierCount;
                this._identifiersStack.push(names);
                for (idx = 0; idx < len; ++idx) {
                    name = names[idx];
                    this._identifiers[name] = this._newName();
//                    if (name === "gpf") {
//                        console.log("!!! gpf = " + this._identifiers[name]);
//                        START_TRACES = 5;
//                    }
                }
            },

            endIdentifierMapping: function () {
//                if (START_TRACES) {
//                    console.log(">> endIdentifierMapping");
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        names = this._identifiersStack[idx];
//                        if (names.isVariables) {
//                            console.log("\t[VAR] " + names.join(","));
//                        } else {
//                            console.log("\t[FUN] " + names.join(","));
//                        }
//                    }
//                }
                /*
                 * Undo identifiers stack until a non 'isVariables' one is found
                 */
                var
                    stack = this._identifiersStack,
                    names,
                    len,
                    idx,
                    name;
                do {
                    names = stack.pop();
                    len = names.length;
                    for (idx = 0; idx < len; ++idx) {
                        name = names[idx];
                        delete this._identifiers[name];
                    }
                    this._identifierCount = names.identifierCount;
                } while (names.isVariables);
//                if (START_TRACES) {
//                    console.log("<< endIdentifierMapping");
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        names = this._identifiersStack[idx];
//                        if (names.isVariables) {
//                            console.log("\t[VAR] " + names.join(","));
//                        } else {
//                            console.log("\t[FUN] " + names.join(","));
//                        }
//                    }
//                    START_TRACES--;
//                }
            },

            isIdentifierMapped: function (name) {
                if (this._identifiers.hasOwnProperty(name)) {
                    return this._identifiers[name];
                }
                return undefined;
            }

            //endregion

        },

        private: {

            _identifiers: {},
            _identifiersStack: [],
            _identifierCount: 0,

            _walkArray: function (astArray) {
                var
                    idx,
                    subItem,
                    names;
                // First pass to see if any FunctionDeclaration names
                for (idx = 0; idx < astArray.length; ++idx) {
                    subItem = astArray[idx];
                    if (subItem.type === "FunctionDeclaration") {
                        if (undefined === names) {
                            names = [];
                        }
                        names.push(subItem.id.name);
                    }
                }
                if (undefined !== names) {
                    this.beginIdentifierMapping(names, true);
                }
                // Second pass to reduce
                for (idx = 0; idx < astArray.length; ++idx) {
                    this._walk(astArray[idx]);
                }
            },

            _walk: function (ast) {
                var
                    myStatics = this.constructor,
                    member,
                    subItem,
                    processor;
                if (ast instanceof Array) {
                    this._walkArray(ast);
                } else {
                    if (ast.type) {
                        processor = myStatics[ast.type];
                    }
                    if (undefined !== processor && processor.pre) {
                        processor.pre(ast, this);
                    }
                    if (undefined !== processor && processor.walk) {
                        processor.walk(ast, this);
                    } else {
                        for (member in ast) {
                            if (ast.hasOwnProperty(member)) {
                                subItem = ast[member];
                                if ("object" === typeof subItem && subItem) {
                                    this._walk(subItem);
                                }
                            }
                        }
                    }
                    if (undefined !== processor && processor.post) {
                        processor.post(ast, this);
                    }
                }
            },

            _newName: function () {
                var
                    id,
                    newName,
                    mod = identifierCharacters.length;
                do {
                    id = this._identifierCount++;
                    newName = [];
                    while (id >= identifierCharacters.length) {
                        newName.push(identifierCharacters.charAt(id % mod));
                        id = id / mod;
                    }
                    newName.push(identifierCharacters.charAt(id));
                    newName = newName.join("");
                } while (undefined !== gpf.test(gpf.js.keywords(), newName));
                return newName;
            }

        },

        static: {

            VariableDeclaration: {

                pre: function (ast, reducer) {
                    var
                        names = [],
                        len = ast.declarations.length,
                        idx;
                    for (idx = 0; idx < len; ++idx) {
                        names.push(ast.declarations[idx].id.name);
                    }
                    // TODO distinguish 'globals' from inner variables
                    reducer.beginIdentifierMapping(names, true);
                }

            },

            FunctionDeclaration: {

                pre: function (ast, reducer) {
                    // Name is reduced at an higher level
                    var
                        names = [],
                        idx,
                        len;
                    // Process parameters
                    if (ast.params && ast.params.length) {
                        len = ast.params.length;
                        for (idx = 0; idx < len; ++idx) {
                            names.push(ast.params[idx].name);
                        }
                    }
                    reducer.beginIdentifierMapping(names, false);
                },

                post: function (ast, reducer) {
                    gpf.interfaces.ignoreParameter(ast);
                    // Clean parameters (and inner variables) substitutions
                    reducer.endIdentifierMapping();
                }

            },

            FunctionExpression: {

                pre: function (ast, reducer) {
                    var
                        names = [],
                        idx,
                        len;
                    // Process parameters
                    if (ast.params && ast.params.length) {
                        len = ast.params.length;
                        for (idx = 0; idx < len; ++idx) {
                            names.push(ast.params[idx].name);
                        }
                    }
                    reducer.beginIdentifierMapping(names, false);
                },

                post: function (ast, reducer) {
                    gpf.interfaces.ignoreParameter(ast);
                    // Clean parameters (and inner variables) substitutions
                    reducer.endIdentifierMapping();
                }
            },

            Identifier: {

                pre: function (astItem, reducer) {
                    // TODO Check the astParent avoid !MemberExpression.property
                    var newName = reducer.isIdentifierMapped(astItem.name);
                    if (undefined !== newName) {
                        astItem.name = newName;
                    }
                }

            },

            MemberExpression: {

                walk: function (astItem, reducer) {
                    reducer.reduce(astItem.object);
                    // Reduce property only if computed
                    if (astItem.computed) {
                        reducer.reduce(astItem.property);
                    }
                }

            },

            ObjectExpression: {

                walk: function (astItem, reducer) {
                    var len, idx;
                    len = astItem.properties.length;
                    for (idx = 0; idx < len; ++idx) {
                        reducer.reduce(astItem.properties[idx].value);
                    }
                }
            }

        }

    });

    //endregion

    function pushCloneOf(idx, item) {
        /*jslint -W040*/
        gpf.interfaces.ignoreParameter(idx);
        this.push(gpf.clone(item));
        /*jslint +W040*/
    }

    function process (parsed, source, version, placeholder, reducer) {
        var body;
        try {
            body = parsed[source].body;
        } catch(e) {
            console.error("Error while processing source: " + source
                + "\r\n" + e.message);
        }
        if (version.reduce) {
            reducer.reduce(body);
            try {
                parsed[source + ".compact.js"] =
                    escodegen.generate(parsed[source],
                        versions.debug.rewriteOptions);
            } catch (e) {
                console.error("Failed to generate compact source for "
                    + source + ": " + e.message);
            }
        }
        if (body instanceof Array) {
// console.log("Adding " + body.length + " items from " + source);
            gpf.each.apply(placeholder, [body, pushCloneOf]);
        } else {
// console.log("Adding item from " + source + "\r\n" + body.item);
            placeholder.push(gpf.clone(body));
        }
    }

    gpf.context().make = function (sources, version) {
        var
            parsed,
            __gpf__,
            placeholder,
            idx,
            source,
            reducer = null;
        if (undefined === versions[version]) {
            throw {
                message: "Unknown version"
            };
        }
        parsed = sources[version];
        if (undefined !== parsed) {
            return parsed.gpf;
        }
        parsed = sources[version] = {};
        version = versions[version];
        // First, parse everything
        parsed["UMD.js"] = preProcess(sources.UMD, version);
        parsed.UMD = toAST(parsed, "UMD.js", version);
        if (version.reduce) {
            reducer = new ASTreducer();
            reducer.reduce(parsed.UMD.body);
            try {
                parsed["UMD.compact.js"] =
                    escodegen.generate(parsed.UMD,
                        versions.debug.rewriteOptions);
            } catch (e) {
                console.error("Failed to generate compact source for UMD: "
                    + e.message);
            }
        }
        parsed.result = gpf.clone(parsed.UMD);
        parsed["boot.js"] = preProcess(sources.boot, version);
        parsed.boot = toAST(parsed, "boot.js", version);
        for (idx = 0; idx < sources._list.length; ++idx) {
            source = sources._list[idx];
            parsed[source + ".js"] = preProcess(sources[source], version);
            parsed[source] = toAST(parsed, source + ".js", version);
        }
        // Then, locate the use of __gpf__ to replace it with our content
        __gpf__ = xpathToGpfPlaceHolder
            .selectNodes(new gpfX.ConstNode(parsed.result))[0];
        // Parent is the placeholder (an array ending with __gpf__)
        placeholder = __gpf__.parentNode().nodeValue();
        placeholder.pop(); // remove __gpf__
        // Add all sources
        for (idx = -1; idx < sources._list.length; ++idx) {
            if (-1 === idx) {
                source = "boot";
            } else {
                source = sources._list[idx];
            }
            process(parsed, source, version, placeholder, reducer);
        }
        // And generate the result
        parsed["result.js"] = escodegen.generate(parsed.result,
            version.rewriteOptions);

        return parsed["result.js"];
    };

}()); /* End of privacy scope */
<commit_msg>Support of gpf:no-replace tag<commit_after>(function () { /* Begin of privacy scope */
    "use strict";
    /*global esprima, escodegen*/

    var
        gpfX = gpf.xml,
        versions = {
            debug: {
                UMD: true,
                DEBUG: true,
                keepComments: true,
                reduce: false,
                rewriteOptions: {
                    format: {
                        indent: {
                            style: "    ",
                            base: 0,
                            adjustMultilineComment: false
                        },
                        newline: "\n",
                        space: " ",
                        json: false,
                        renumber: false,
                        hexadecimal: false,
                        quotes: "double",
                        escapeless: false,
                        reduce: false,
                        parentheses: true,
                        semicolons: true,
                        safeConcatenation: false
                    },
                    comment: true
                }
            },
            release: {
                UMD: true,
                DEBUG: false,
                keepComments: true, // Needed for gpf: tags
                reduce: true,
                rewriteOptions: {
                    format: {
                        indent: {
                            style: "",
                            base: 0,
                            adjustMultilineComment: false
                        },
                        newline: "",
                        space: "",
                        json: false,
                        renumber: false,
                        hexadecimal: false,
                        quotes: "double",
                        escapeless: false,
                        reduce: true,
                        parentheses: false,
                        semicolons: true,
                        safeConcatenation: true
                    },
                    comment: false
                }
            }
        },
        // body/item[@type="ExpressionStatement" and expression/@name="__gpf__"]
        xpathToGpfPlaceHolder = new gpfX.XPath({
            type: gpfX.NODE_ELEMENT,
            name: "body",
            relative: false,
            then: {
                type: gpfX.NODE_ELEMENT,
                name: "item",
                filter: {
                    and: [ {
                        type: gpfX.NODE_ATTRIBUTE,
                        name: "type",
                        text: "ExpressionStatement"
                    }, {
                        type: gpfX.NODE_ELEMENT,
                        name: "expression",
                        then: {
                            type: gpfX.NODE_ATTRIBUTE,
                            name: "name",
                            text: "__gpf__"
                        }
                    }]
                }
            }
        }),
        identifierCharacters = "abcdefghijklmnopqrstuvwxyz"
                             + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    ;

    //region Preprocessor (#ifdef)

    function preProcess(src, version) {
        var
            lines = src.split("\n"),
            len = lines.length,
            idx,
            line,
            ignoreStack = [false],
            ignore;
        for (idx = 0; idx < len; ++idx) {
            line = lines[idx];
            ignore = ignoreStack[ignoreStack.length - 1];
            if (-1 < line.indexOf("/*#if")) {
                // console.log("#" + line);
                // In the end, we use an "ignore" flag
                // so we invert the condition
                ignore = -1 === line.indexOf("/*#ifndef(");
                line = line.split("(")[1].split(")")[0];
                // console.log("\t" + line);
                ignore = gpf.xor(version[line], ignore);
                // console.log("\t" + ignore);
                ignoreStack.push(ignore);
                ignore = true; // Ignore this line
                // console.log(">>" + ignoreStack);
                /*
                 * TODO handle imbricated when the parent is false
                 */

            } else if (-1 < line.indexOf("/*#else")) {
                ignoreStack[ignoreStack.length - 1] = !ignore;
                ignore = true; // Ignore this line

            } else if (-1 < line.indexOf("/*#endif")) {
                // console.log("#" + line);
                ignoreStack.pop();
                ignore = true; // Ignore this line
                // console.log(">>" + ignoreStack);
            }
            // console.log((ignore ? "-" : "+")  + line);
            if (ignore) {
                lines.splice(idx, 1);
                --len;
                --idx;
            }
        }
        return lines.join("\n");
    }

    //endregion

    function toAST(parsed, src, version) {
        // https://github.com/Constellation/escodegen/issues/85
        try {
            var
                keepComments = version.keepComments,
                ast = esprima.parse(parsed[src], {
                    range: keepComments,
                    tokens: keepComments,
                    comment: keepComments
                });
            if (keepComments) {
                ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
                delete ast.tokens;
                delete ast.comments;
            }
            return ast;
        } catch(e) {
            console.error("Error in \"" + src + "\": " + e.message);
            throw e;
        }
    }

    //region AST compactor

    /**
     * AST Reducer
     *
     * @class ASTreducer
     * @private
     */
    var ASTreducer = gpf.define("ASTreducer", {

        public: {

            constructor: function() {

                this._identifiers = {};
                this._identifiersStack = [];

            },

            /**
             * Process the AST to reduce the generated source
             *
             * @param {Object} ast
             */
            reduce: function (ast) {
                this._walk(ast);
            },

            //region AST processing APIs

            beginIdentifierMapping: function (names, forVariables) {
//                if (START_TRACES) {
//                    console.log(">> beginIdentifierMapping");
//                    if (forVariables) {
//                        console.log("\t+[VAR] " + names.join(","));
//                    } else {
//                        console.log("\t+[FUN] " + names.join(","));
//                    }
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        var stackedNames = this._identifiersStack[idx];
//                        if (stackedNames.isVariables) {
//                            console.log("\t[VAR] " + stackedNames.join(","));
//                        } else {
//                            console.log("\t[FUN] " + stackedNames.join(","));
//                        }
//                    }
//                }
                var
                    len = names.length,
                    idx,
                    name;
                if (forVariables) {
                    names.isVariables = true;
                }
                names.identifierCount = this._identifierCount;
                this._identifiersStack.push(names);
                for (idx = 0; idx < len; ++idx) {
                    name = names[idx];
                    this._identifiers[name] = this._newName();
//                    if (name === "gpf") {
//                        console.log("!!! gpf = " + this._identifiers[name]);
//                        START_TRACES = 5;
//                    }
                }
            },

            endIdentifierMapping: function () {
//                if (START_TRACES) {
//                    console.log(">> endIdentifierMapping");
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        names = this._identifiersStack[idx];
//                        if (names.isVariables) {
//                            console.log("\t[VAR] " + names.join(","));
//                        } else {
//                            console.log("\t[FUN] " + names.join(","));
//                        }
//                    }
//                }
                /*
                 * Undo identifiers stack until a non 'isVariables' one is found
                 */
                var
                    stack = this._identifiersStack,
                    names,
                    len,
                    idx,
                    name;
                do {
                    names = stack.pop();
                    len = names.length;
                    for (idx = 0; idx < len; ++idx) {
                        name = names[idx];
                        delete this._identifiers[name];
                    }
                    this._identifierCount = names.identifierCount;
                } while (names.isVariables);
//                if (START_TRACES) {
//                    console.log("<< endIdentifierMapping");
//                    for (idx = this._identifiersStack.length - 1;
//                         idx > 0; --idx) {
//                        names = this._identifiersStack[idx];
//                        if (names.isVariables) {
//                            console.log("\t[VAR] " + names.join(","));
//                        } else {
//                            console.log("\t[FUN] " + names.join(","));
//                        }
//                    }
//                    START_TRACES--;
//                }
            },

            isIdentifierMapped: function (name) {
                if (this._identifiers.hasOwnProperty(name)) {
                    return this._identifiers[name];
                }
                return undefined;
            }

            //endregion

        },

        private: {

            _identifiers: {},
            _identifiersStack: [],
            _identifierCount: 0,

            _walkArray: function (astArray) {
                var
                    idx,
                    subItem,
                    names;
                // First pass to see if any FunctionDeclaration names
                for (idx = 0; idx < astArray.length; ++idx) {
                    subItem = astArray[idx];
                    if (subItem.type === "FunctionDeclaration") {
                        if (undefined === names) {
                            names = [];
                        }
                        names.push(subItem.id.name);
                    }
                }
                if (undefined !== names) {
                    this.beginIdentifierMapping(names, true);
                }
                // Second pass to reduce
                for (idx = 0; idx < astArray.length; ++idx) {
                    this._walk(astArray[idx]);
                }
            },

            _walk: function (ast) {
                var
                    myStatics = this.constructor,
                    member,
                    subItem,
                    processor;
                if (ast instanceof Array) {
                    this._walkArray(ast);
                } else {
                    if (ast.type) {
                        processor = myStatics[ast.type];
                    }
                    if (undefined !== processor && processor.pre) {
                        processor.pre(ast, this);
                    }
                    if (undefined !== processor && processor.walk) {
                        processor.walk(ast, this);
                    } else {
                        for (member in ast) {
                            if (ast.hasOwnProperty(member)) {
                                subItem = ast[member];
                                if ("object" === typeof subItem && subItem) {
                                    this._walk(subItem);
                                }
                            }
                        }
                    }
                    if (undefined !== processor && processor.post) {
                        processor.post(ast, this);
                    }
                }
            },

            _newName: function () {
                var
                    id,
                    newName,
                    mod = identifierCharacters.length;
                do {
                    id = this._identifierCount++;
                    newName = [];
                    while (id >= identifierCharacters.length) {
                        newName.push(identifierCharacters.charAt(id % mod));
                        id = id / mod;
                    }
                    newName.push(identifierCharacters.charAt(id));
                    newName = newName.join("");
                } while (undefined !== gpf.test(gpf.js.keywords(), newName));
                return newName;
            }

        },

        static: {

            isTaggedWith: function (ast, tag) {
                var array,
                    len,
                    idx;
                if (!ast.leadingComments) {
                    return false;
                }
                tag = "gpf:" + tag;
                array = ast.leadingComments;
                len = array.length;
                for (idx = 0; idx < len; ++idx) {
                    if (array[idx].value === tag) {
                        return true;
                    }
                }
                return false;
            },

            VariableDeclaration: {

                pre: function (ast, reducer) {
                    var
                        names = [],
                        len = ast.declarations.length,
                        idx,
                        decl;
                    for (idx = 0; idx < len; ++idx) {
                        decl = ast.declarations[idx];
                        if (!ASTreducer.isTaggedWith(decl, "no-reduce")) {
                            names.push(decl.id.name);
                        }
                    }
                    // TODO distinguish 'globals' from inner variables
                    reducer.beginIdentifierMapping(names, true);
                }

            },

            FunctionDeclaration: {

                pre: function (ast, reducer) {
                    // Name is reduced at an higher level
                    var
                        names = [],
                        idx,
                        len;
                    // Process parameters
                    if (ast.params && ast.params.length) {
                        len = ast.params.length;
                        for (idx = 0; idx < len; ++idx) {
                            names.push(ast.params[idx].name);
                        }
                    }
                    reducer.beginIdentifierMapping(names, false);
                },

                post: function (ast, reducer) {
                    gpf.interfaces.ignoreParameter(ast);
                    // Clean parameters (and inner variables) substitutions
                    reducer.endIdentifierMapping();
                }

            },

            FunctionExpression: {

                pre: function (ast, reducer) {
                    var
                        names = [],
                        len,
                        idx,
                        param;
                    // Process parameters
                    if (ast.params && ast.params.length) {
                        len = ast.params.length;
                        for (idx = 0; idx < len; ++idx) {
                            param = ast.params[idx];
                            if (!ASTreducer.isTaggedWith(param, "no-reduce")) {
                                names.push(ast.params[idx].name);
                            }
                        }
                    }
                    reducer.beginIdentifierMapping(names, false);
                },

                post: function (ast, reducer) {
                    gpf.interfaces.ignoreParameter(ast);
                    // Clean parameters (and inner variables) substitutions
                    reducer.endIdentifierMapping();
                }
            },

            Identifier: {

                pre: function (astItem, reducer) {
                    // TODO Check the astParent avoid !MemberExpression.property
                    var newName = reducer.isIdentifierMapped(astItem.name);
                    if (undefined !== newName) {
                        astItem.name = newName;
                    }
                }

            },

            MemberExpression: {

                walk: function (astItem, reducer) {
                    reducer.reduce(astItem.object);
                    // Reduce property only if computed
                    if (astItem.computed) {
                        reducer.reduce(astItem.property);
                    }
                }

            },

            ObjectExpression: {

                walk: function (astItem, reducer) {
                    var len, idx;
                    len = astItem.properties.length;
                    for (idx = 0; idx < len; ++idx) {
                        reducer.reduce(astItem.properties[idx].value);
                    }
                }
            }

        }

    });

    //endregion

    function pushCloneOf(idx, item) {
        /*jslint -W040*/
        gpf.interfaces.ignoreParameter(idx);
        this.push(gpf.clone(item));
        /*jslint +W040*/
    }

    function process (parsed, source, version, placeholder, reducer) {
        var body;
        try {
            body = parsed[source].body;
        } catch(e) {
            console.error("Error while processing source: " + source
                + "\r\n" + e.message);
        }
        if (version.reduce) {
            reducer.reduce(body);
            try {
                parsed[source + ".compact.js"] =
                    escodegen.generate(parsed[source],
                        versions.debug.rewriteOptions);
            } catch (e) {
                console.error("Failed to generate compact source for "
                    + source + ": " + e.message);
            }
        }
        if (body instanceof Array) {
// console.log("Adding " + body.length + " items from " + source);
            gpf.each.apply(placeholder, [body, pushCloneOf]);
        } else {
// console.log("Adding item from " + source + "\r\n" + body.item);
            placeholder.push(gpf.clone(body));
        }
    }

    gpf.context().make = function (sources, version) {
        var
            parsed,
            __gpf__,
            placeholder,
            idx,
            source,
            reducer = null;
        if (undefined === versions[version]) {
            throw {
                message: "Unknown version"
            };
        }
        parsed = sources[version];
        if (undefined !== parsed) {
            return parsed.gpf;
        }
        parsed = sources[version] = {};
        version = versions[version];
        // First, parse everything
        parsed["UMD.js"] = preProcess(sources.UMD, version);
        parsed.UMD = toAST(parsed, "UMD.js", version);
        if (version.reduce) {
            reducer = new ASTreducer();
            reducer.reduce(parsed.UMD.body);
            try {
                parsed["UMD.compact.js"] =
                    escodegen.generate(parsed.UMD,
                        versions.debug.rewriteOptions);
            } catch (e) {
                console.error("Failed to generate compact source for UMD: "
                    + e.message);
            }
        }
        parsed.result = gpf.clone(parsed.UMD);
        parsed["boot.js"] = preProcess(sources.boot, version);
        parsed.boot = toAST(parsed, "boot.js", version);
        for (idx = 0; idx < sources._list.length; ++idx) {
            source = sources._list[idx];
            parsed[source + ".js"] = preProcess(sources[source], version);
            parsed[source] = toAST(parsed, source + ".js", version);
        }
        // Then, locate the use of __gpf__ to replace it with our content
        __gpf__ = xpathToGpfPlaceHolder
            .selectNodes(new gpfX.ConstNode(parsed.result))[0];
        // Parent is the placeholder (an array ending with __gpf__)
        placeholder = __gpf__.parentNode().nodeValue();
        placeholder.pop(); // remove __gpf__
        // Add all sources
        for (idx = -1; idx < sources._list.length; ++idx) {
            if (-1 === idx) {
                source = "boot";
            } else {
                source = sources._list[idx];
            }
            process(parsed, source, version, placeholder, reducer);
        }
        // And generate the result
        parsed["result.js"] = escodegen.generate(parsed.result,
            version.rewriteOptions);

        return parsed["result.js"];
    };

}()); /* End of privacy scope */
<|endoftext|>