<commit_before>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
'use strict';

var Promise = global.Promise || require('bluebird'),
    debug = require('debug')('Dispatchr:dispatcher');

/**
 * @class Dispatcher
 * @param {Object} context The context to be used for store instances
 * @constructor
 */
function Dispatcher (context) {
    this.context = context || {};
    this.storeInstances = {};
    this.currentAction = null;
    this.actionQueue = [];
}

Dispatcher.stores = {};
Dispatcher.handlers = {};

/**
 * Registers a store so that it can handle actions.
 * @method registerStore
 * @static
 * @param {Object} store A store class to be registered. The store should have a static
 *      `name` property so that it can be loaded later.
 */
Dispatcher.registerStore = function (store) {
    if (Dispatcher.stores[store.name]) {
        throw new Error('Store `' + store.name + '` is already registerd.');
    }
    Dispatcher.stores[store.name] = store;
    if (store.handlers) {
        Object.keys(store.handlers).forEach(function (action) {
            var handler = store.handlers[action];
            Dispatcher.registerHandler(action, store.name, handler);
        });
    }
    return Dispatcher.stores[store.name];
};

/**
 * Adds a handler function to be called for the given action
 * @method registerHandler
 * @private
 * @static
 * @param {String} action Name of the action
 * @param {String} name Name of the store that handles the action
 * @param {String} handler Name of the function that handles the action
 * @returns {number}
 */
Dispatcher.registerHandler = function (action, name, handler) {
    Dispatcher.handlers[action] = Dispatcher.handlers[action] || [];
    Dispatcher.handlers[action].push({
        name: name,
        handler: handler
    });
    return Dispatcher.handlers.length - 1;
};

/**
 * Returns a single store instance and creates one if it doesn't already exist
 * @method getStore
 * @param {String} name The name of the instance
 * @param {Object} initialState Initial state of the store used for rehydration
 * @returns {Object} The store instance
 */
Dispatcher.prototype.getStore = function (name, initialState) {
    if (!this.storeInstances[name]) {
        var Store = Dispatcher.stores[name];
        if (!Store) {
            throw new Error('Store ' + name + ' was not registered.');
        }
        this.storeInstances[name] = new (Dispatcher.stores[name])(this.context, initialState);
        if (this.storeInstances[name].setDispatcher) {
            this.storeInstances[name].setDispatcher(this);
        }
    }
    return this.storeInstances[name];
};

/**
 * Dispatches a new action or queues it up if one is already in progress
 * @method dispatch
 * @param {String} name Name of the action to be dispatched
 * @param {Object} payload Parameters to describe the action
 * @param {Function} callback Function to be called upon completion of
 *      the action.
 */
Dispatcher.prototype.dispatch = function (name, payload, callback) {
    if (!Dispatcher.handlers[name]) {
        callback();
        return;
    }

    this.actionQueue.push({
        name: name,
        payload: payload,
        callback: callback,
        actionPromise: null,
        handlerPromises: {},
        waiting: {}
    });
    debug('action ' + name + ' added to queue');
    return this.next();
};

/**
 * Handles the next Action in the queue if another Action is not in progress
 * @method next
 * @private
 * @returns {Object}
 */
Dispatcher.prototype.next = function () {
    if (this.currentAction) {
        return this.currentAction;
    }

    var self = this,
        nextAction = self.actionQueue.shift();

    if (nextAction) {
        self.currentAction = nextAction;

        var actionPromise = self.handleAction(nextAction);
        actionPromise.then(function (err, result) {
            debug('finished ' + nextAction.name);
            self.currentAction = null;
            if (nextAction.callback) {
                nextAction.callback(null, result);
            }
            setImmediate(self.next.bind(self));
        }).catch(function (err) {
            debug('finished with error ' + nextAction.name);
            self.currentAction = null;
            if (nextAction.callback) {
                nextAction.callback(err);
            }
            setImmediate(self.next.bind(self));
        });
    }

    return self.currentAction;
};

/**
 * Calls the handler functions for all stores that have registered for
 * the given event.
 * @method handleAction
 * @private
 * @param {Object} action Action object
 * @param {String} action.name Name of the action to be handled
 * @param {Object} action.payload Parameters to describe the action
 * @returns {Promise}
 */
Dispatcher.prototype.handleAction = function (action) {
    var self = this,
        name = action.name,
        payload = action.payload,
        handlerPromises = [];

    debug('handling ' + name);
    Dispatcher.handlers[name].forEach(function (store) {
        var handlerPromise = new Promise(function(resolve, reject) {
            var storeInstance = self.getStore(store.name),
                finalHandler = function () {
                    resolve();
                    storeInstance.removeListener('error', errorHandler);
                },
                errorHandler = function (e) {
                    reject(e);
                    storeInstance.removeListener('final', finalHandler);
                };

            storeInstance.once('final', finalHandler);
            storeInstance.once('error', errorHandler);

            setImmediate(function () {
                storeInstance[store.handler](payload);
            });
        });
        handlerPromises.push(handlerPromise);
        action.handlerPromises[store.name] = handlerPromise;
    });

    return Promise.all(handlerPromises);
};

/**
 * Waits until all stores have finished handling an actionand then calls
 * the callback
 * @param {String|Array} stores An array of stores as strings to wait for
 * @param {Function} callback Called after all stores have completed handling their actions
 */
Dispatcher.prototype.waitFor = function (stores, callback) {
    var currentAction = this.currentAction,
        waitHandlers = [];

    if (!currentAction) {
        throw new Error('waitFor called even though there is no action being handled!');
    }

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

    stores.forEach(function (storeName) {
        var actionHandler = currentAction.handlerPromises[storeName];
        if (actionHandler) {
            waitHandlers.push(actionHandler);
        }
    });

    Promise.all(waitHandlers).nodeify(callback);
};

/**
 * Returns a raw data object representation of the current state of the
 * dispatcher and all store instances
 * @returns {Object} dehydrated dispatcher data
 */
Dispatcher.prototype.toJSON = function () {
    var self = this,
        stores = {};
    Object.keys(self.storeInstances).forEach(function (storeName) {
        var store = self.storeInstances[storeName];
        if (store.toJSON) {
            stores[storeName] = store.toJSON();
        } else {
            stores[storeName] = store.getState();
        }
    });
    return {
        context: self.context,
        stores: stores
    };
};

/**
 * Takes a raw data object and rehydrates the dispatcher and store instances
 * @param {Object} dispatcherState raw state typically retrieved from `toJSON`
 *      method
 */
Dispatcher.prototype.rehydrate = function (dispatcherState) {
    var self = this;
    self.context = dispatcherState.context || {};
    if (dispatcherState.stores) {
        Object.keys(dispatcherState.stores).forEach(function (storeName) {
            var state = dispatcherState.stores[storeName];
            self.getStore(storeName, state);
        });
    }
};

module.exports = Dispatcher;
<commit_msg>Fix nodeify references<commit_after>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
'use strict';

var Promise = global.Promise || require('bluebird'),
    debug = require('debug')('Dispatchr:dispatcher');

/**
 * @class Dispatcher
 * @param {Object} context The context to be used for store instances
 * @constructor
 */
function Dispatcher (context) {
    this.context = context || {};
    this.storeInstances = {};
    this.currentAction = null;
    this.actionQueue = [];
}

Dispatcher.stores = {};
Dispatcher.handlers = {};

/**
 * Registers a store so that it can handle actions.
 * @method registerStore
 * @static
 * @param {Object} store A store class to be registered. The store should have a static
 *      `name` property so that it can be loaded later.
 */
Dispatcher.registerStore = function (store) {
    if (Dispatcher.stores[store.name]) {
        throw new Error('Store `' + store.name + '` is already registerd.');
    }
    Dispatcher.stores[store.name] = store;
    if (store.handlers) {
        Object.keys(store.handlers).forEach(function (action) {
            var handler = store.handlers[action];
            Dispatcher.registerHandler(action, store.name, handler);
        });
    }
    return Dispatcher.stores[store.name];
};

/**
 * Adds a handler function to be called for the given action
 * @method registerHandler
 * @private
 * @static
 * @param {String} action Name of the action
 * @param {String} name Name of the store that handles the action
 * @param {String} handler Name of the function that handles the action
 * @returns {number}
 */
Dispatcher.registerHandler = function (action, name, handler) {
    Dispatcher.handlers[action] = Dispatcher.handlers[action] || [];
    Dispatcher.handlers[action].push({
        name: name,
        handler: handler
    });
    return Dispatcher.handlers.length - 1;
};

/**
 * Returns a single store instance and creates one if it doesn't already exist
 * @method getStore
 * @param {String} name The name of the instance
 * @param {Object} initialState Initial state of the store used for rehydration
 * @returns {Object} The store instance
 */
Dispatcher.prototype.getStore = function (name, initialState) {
    if (!this.storeInstances[name]) {
        var Store = Dispatcher.stores[name];
        if (!Store) {
            throw new Error('Store ' + name + ' was not registered.');
        }
        this.storeInstances[name] = new (Dispatcher.stores[name])(this.context, initialState);
        if (this.storeInstances[name].setDispatcher) {
            this.storeInstances[name].setDispatcher(this);
        }
    }
    return this.storeInstances[name];
};

/**
 * Dispatches a new action or queues it up if one is already in progress
 * @method dispatch
 * @param {String} name Name of the action to be dispatched
 * @param {Object} payload Parameters to describe the action
 * @param {Function} callback Function to be called upon completion of
 *      the action.
 */
Dispatcher.prototype.dispatch = function (name, payload, callback) {
    if (!Dispatcher.handlers[name]) {
        callback();
        return;
    }

    this.actionQueue.push({
        name: name,
        payload: payload,
        callback: callback,
        actionPromise: null,
        handlerPromises: {},
        waiting: {}
    });
    debug('action ' + name + ' added to queue');
    return this.next();
};

/**
 * Handles the next Action in the queue if another Action is not in progress
 * @method next
 * @private
 * @returns {Object}
 */
Dispatcher.prototype.next = function () {
    if (this.currentAction) {
        return this.currentAction;
    }

    var self = this,
        nextAction = self.actionQueue.shift();

    if (nextAction) {
        self.currentAction = nextAction;

        var actionPromise = self.handleAction(nextAction);
        actionPromise.then(function (result) {
            debug('finished ' + nextAction.name);
            self.currentAction = null;
            if (nextAction.callback) {
                nextAction.callback(null, result);
            }
            setImmediate(self.next.bind(self));
        }).catch(function (err) {
            debug('finished with error ' + nextAction.name);
            self.currentAction = null;
            if (nextAction.callback) {
                nextAction.callback(err);
            }
            setImmediate(self.next.bind(self));
        });
    }

    return self.currentAction;
};

/**
 * Calls the handler functions for all stores that have registered for
 * the given event.
 * @method handleAction
 * @private
 * @param {Object} action Action object
 * @param {String} action.name Name of the action to be handled
 * @param {Object} action.payload Parameters to describe the action
 * @returns {Promise}
 */
Dispatcher.prototype.handleAction = function (action) {
    var self = this,
        name = action.name,
        payload = action.payload,
        handlerPromises = [];

    debug('handling ' + name);
    Dispatcher.handlers[name].forEach(function (store) {
        var handlerPromise = new Promise(function(resolve, reject) {
            var storeInstance = self.getStore(store.name),
                finalHandler = function () {
                    resolve();
                    storeInstance.removeListener('error', errorHandler);
                },
                errorHandler = function (e) {
                    reject(e);
                    storeInstance.removeListener('final', finalHandler);
                };

            storeInstance.once('final', finalHandler);
            storeInstance.once('error', errorHandler);

            setImmediate(function () {
                storeInstance[store.handler](payload);
            });
        });
        handlerPromises.push(handlerPromise);
        action.handlerPromises[store.name] = handlerPromise;
    });

    return Promise.all(handlerPromises);
};

/**
 * Waits until all stores have finished handling an actionand then calls
 * the callback
 * @param {String|Array} stores An array of stores as strings to wait for
 * @param {Function} callback Called after all stores have completed handling their actions
 */
Dispatcher.prototype.waitFor = function (stores, callback) {
    var currentAction = this.currentAction,
        waitHandlers = [];

    if (!currentAction) {
        throw new Error('waitFor called even though there is no action being handled!');
    }

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

    stores.forEach(function (storeName) {
        var actionHandler = currentAction.handlerPromises[storeName];
        if (actionHandler) {
            waitHandlers.push(actionHandler);
        }
    });

    Promise.all(waitHandlers).then(function (result) {
        setImmediate(function () {
            callback(null, result);
        });
    }).catch(function (err) {
        callback(err);
    });
};

/**
 * Returns a raw data object representation of the current state of the
 * dispatcher and all store instances
 * @returns {Object} dehydrated dispatcher data
 */
Dispatcher.prototype.toJSON = function () {
    var self = this,
        stores = {};
    Object.keys(self.storeInstances).forEach(function (storeName) {
        var store = self.storeInstances[storeName];
        if (store.toJSON) {
            stores[storeName] = store.toJSON();
        } else {
            stores[storeName] = store.getState();
        }
    });
    return {
        context: self.context,
        stores: stores
    };
};

/**
 * Takes a raw data object and rehydrates the dispatcher and store instances
 * @param {Object} dispatcherState raw state typically retrieved from `toJSON`
 *      method
 */
Dispatcher.prototype.rehydrate = function (dispatcherState) {
    var self = this;
    self.context = dispatcherState.context || {};
    if (dispatcherState.stores) {
        Object.keys(dispatcherState.stores).forEach(function (storeName) {
            var state = dispatcherState.stores[storeName];
            self.getStore(storeName, state);
        });
    }
};

module.exports = Dispatcher;
<|endoftext|>


<commit_before>Rye.define('DOMEvents', function(){

    var util = Rye.require('Util')
      , EventEmitter = Rye.require('EventEmitter')
      , query = Rye.require('Query')
      , emitters = {}

    function getEmitter (element) {
        var id = util.getUid(element)
        return emitters[id] || (emitters[id] = new DOMEventEmitter(element))
    }

    function parseName (name) {
        var index = name.indexOf(' ')
        return {
            event    : index > 0 ? name.substr(0, index) : name
          , selector : index > 0 ? name.substr(index) : ''
        }
    }

    function createEvent (type, properties) {
        if (typeof type != 'string') {
            type = type.type
        }
        var isMouse = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(type) != -1
          , event = document.createEvent(isMouse ? 'MouseEvent' : 'Event')
        if (properties) {
            util.extend(event, properties)
        }
        event.initEvent(type, true, true)
        return event
    }

    var DOMEventEmitter = util.inherits(function(element){
        EventEmitter.call(this)
        this.element = element
        this.context = element
        this.proxied = {}
    }, EventEmitter)

    DOMEventEmitter.prototype.delegateProxy = function (name) {
        return function (event) {
            var selector = parseName(name).selector
              , matched = query.getClosestNode(event.target || this.element, 'parentNode', selector)
            if ((matched && matched !== document) || query.matches(event.target, selector)){
                this.context = matched
                this.emit(name, event, this.element)
            }
        }.bind(this)
    }

    DOMEventEmitter.prototype.proxy = function (name) {
        var selector = parseName(name).selector
        return this.proxied[name] || (this.proxied[name] =
            selector
              ? this.delegateProxy(name)
              : EventEmitter.prototype.proxy.call(this, name)
        )
    }

    DOMEventEmitter.prototype.addListener = function (name, handler) {
        EventEmitter.prototype.addListener.call(this, name, handler)
        if (!this.proxied[name]) {
            this.element.addEventListener(parseName(name).event, this.proxy(name), false)
        }
    }

    DOMEventEmitter.prototype.removeListener = function (name, handler) {
        var self = this
          , proxy = this.proxied[name]
        if (name === '*') {
            Object.keys(this.events).forEach(function(name){
                self.removeListener(name, handler)
            })
        } else {
            EventEmitter.prototype.removeListener.call(this, name, handler)
            if (!this.events[name] && proxy) {
                this.element.removeEventListener(parseName(name).event, proxy, false)
                delete this.proxied[name]
            }
        }
    }

    DOMEventEmitter.prototype.destroy = function () {
        this.removeListener('*')
    }

    DOMEventEmitter.prototype.trigger = function (event, data) {
        if (!(event instanceof window.Event)) {
            event = createEvent(event)
        }
        event.data = data
        this.element.dispatchEvent(event)
    }

    function listener (mode, element, name, handler) {
        getEmitter(element)[mode + 'Listener'](name, handler)
    }

    function trigger (element, event, data) {
        getEmitter(element).trigger(event, data)
    }

    var addListener    = util.curry(listener, 'add')
      , removeListener = util.curry(listener, 'remove')

    this.addEventListener    = this.iterate(addListener)
    this.removeEventListener = this.iterate(removeListener)
    this.trigger             = this.iterate(trigger)
    // Aliases
    this.on  = this.addEventListener
    this.off = this.removeEventListener

    return {
        getEmitter     : getEmitter
      , addListener    : addListener
      , removeListener : removeListener
      , trigger        : trigger
      , createEvent    : createEvent
    }

})
<commit_msg>Collapsing addListener, removeListener and trigger in function emitter<commit_after>Rye.define('DOMEvents', function(){

    var util = Rye.require('Util')
      , EventEmitter = Rye.require('EventEmitter')
      , query = Rye.require('Query')
      , emitters = {}

    function getEmitter (element) {
        var id = util.getUid(element)
        return emitters[id] || (emitters[id] = new DOMEventEmitter(element))
    }

    function parseName (name) {
        var index = name.indexOf(' ')
        return {
            event    : index > 0 ? name.substr(0, index) : name
          , selector : index > 0 ? name.substr(index) : ''
        }
    }

    function createEvent (type, properties) {
        if (typeof type != 'string') {
            type = type.type
        }
        var isMouse = ['click', 'mousedown', 'mouseup', 'mousemove'].indexOf(type) != -1
          , event = document.createEvent(isMouse ? 'MouseEvent' : 'Event')
        if (properties) {
            util.extend(event, properties)
        }
        event.initEvent(type, true, true)
        return event
    }

    var DOMEventEmitter = util.inherits(function(element){
        EventEmitter.call(this)
        this.element = element
        this.context = element
        this.proxied = {}
    }, EventEmitter)

    DOMEventEmitter.prototype.delegateProxy = function (name) {
        return function (event) {
            var selector = parseName(name).selector
              , matched = query.getClosestNode(event.target || this.element, 'parentNode', selector)
            if ((matched && matched !== document) || query.matches(event.target, selector)){
                this.context = matched
                this.emit(name, event, this.element)
            }
        }.bind(this)
    }

    DOMEventEmitter.prototype.proxy = function (name) {
        var selector = parseName(name).selector
        return this.proxied[name] || (this.proxied[name] =
            selector
              ? this.delegateProxy(name)
              : EventEmitter.prototype.proxy.call(this, name)
        )
    }

    DOMEventEmitter.prototype.addListener = function (name, handler) {
        EventEmitter.prototype.addListener.call(this, name, handler)
        if (!this.proxied[name]) {
            this.element.addEventListener(parseName(name).event, this.proxy(name), false)
        }
    }

    DOMEventEmitter.prototype.removeListener = function (name, handler) {
        var self = this
          , proxy = this.proxied[name]
        if (name === '*') {
            Object.keys(this.events).forEach(function(name){
                self.removeListener(name, handler)
            })
        } else {
            EventEmitter.prototype.removeListener.call(this, name, handler)
            if (!this.events[name] && proxy) {
                this.element.removeEventListener(parseName(name).event, proxy, false)
                delete this.proxied[name]
            }
        }
    }

    DOMEventEmitter.prototype.destroy = function () {
        this.removeListener('*')
    }

    DOMEventEmitter.prototype.trigger = function (event, data) {
        if (!(event instanceof window.Event)) {
            event = createEvent(event)
        }
        event.data = data
        this.element.dispatchEvent(event)
    }

    function emitter (mode, element, a, b) {
        getEmitter(element)[mode](a, b)
    }

    var addListener    = util.curry(emitter, 'addListener')
      , removeListener = util.curry(emitter, 'removeListener')
      , trigger        = util.curry(emitter, 'trigger')

    this.addEventListener    = this.iterate(addListener)
    this.removeEventListener = this.iterate(removeListener)
    this.trigger             = this.iterate(trigger)
    // Aliases
    this.on  = this.addEventListener
    this.off = this.removeEventListener

    return {
        getEmitter     : getEmitter
      , addListener    : addListener
      , removeListener : removeListener
      , trigger        : trigger
      , createEvent    : createEvent
    }

})
<|endoftext|>


<commit_before>/*
 * Model module
 * @lastmodifiedBy ChengFuLin(chengfulin0806@gmail.com)
 * @lastmodifiedDate 2015-08-19
 */
var namespace = require('../namespace'),
    internal = namespace();
var Scope = require('./scope'),
    DUPair = require('./dupair'),
    cfgValidator = require('./cfgvalidator');
var Map = require('core-js/es6/map'),
	Set = require('../analyses/set');

/**
 * Model
 * @constructor
 */
function Model() {
    "use strict";
    internal(this)._relatedScopes = [];
	internal(this)._mainlyRelatedScope = null;
    internal(this)._graph = null;
    internal(this)._dupairs = new Map(); /// (Var, Set)
	/// TODO: should contain dataflow artifacts (ReachIn, ReachOut, KILL, GEN, USE) or not

    /* start-test-block */
    this._testonly_ = internal(this);
    /* end-test-block */
}

/* start-static-methods */
/**
 * Check for the object is an Model
 * @param {Object} obj An object to be checked
 * @returns {boolean} True, if it is; false, otherwise
 */
Model.isModel = function (obj) {
    "use strict";
    return obj instanceof Model;
};
/* end-static-methods */

/* start-public-methods */
/**
 * Check for the scope is related
 * @param {Scope} scope A Scope to be checked
 * @returns {boolean}
 */
Model.prototype.isRelatedToTheScope = function (scope) {
    "use strict";
    return internal(this)._relatedScopes.indexOf(scope) !== -1;
};

/**
 * Check the scope is mainly related, which means this model is derive from the scope's intra-procedural model
 * @param {Scope} scope A Scope to be checked
 * @returns {boolean} True, if it is; false, otherwise
 */
Model.prototype.isMainlyRelatedToTheScope = function (scope) {
    "use strict";
    return internal(this)._mainlyRelatedScope === scope;
};

/**
 * Add a related scope
 * @param {Scope} scope Related scope
 */
Model.prototype.addRelatedScope = function (scope) {
    "use strict";
    if (Scope.isScope(scope) && !this.isRelatedToTheScope(scope)) {
	    if (internal(this)._relatedScopes.length === 0) {
		    internal(this)._mainlyRelatedScope = scope;
	    }
        internal(this)._relatedScopes.push(scope);
    }
};

/**
 * Check for DUPair has found
 * @param {DUPair} dupair
 * @returns {boolean} True, if found; false, otherwise
 */
Model.prototype.hasDUPair = function (dupair) {
    "use strict";
    var found = false;
    if (DUPair.isDUPair(dupair)) {
        internal(this)._dupairs.forEach(function (pairs) {
            pairs.forEach(function (pair) {
                if (pair.def === dupair.def && pair.use === dupair.use) {
                    found = true;
                }
            });
        });
    }
    return found;
};
/* end-public-methods */

/* start-public-data-members */
Object.defineProperties(Model.prototype, {
	/**
	 * Graph of the model
	 * @type {Array}
	 * @memberof Model.prototype
	 */
	graph: {
	    get: function () {
	        "use strict";
	        return [].concat(internal(this)._graph);
	    },
	    set: function (graph) {
	        "use strict";
	        if (cfgValidator.isValidCFG(graph)) {
	            internal(this)._graph = [graph[0], graph[1], [].concat(graph[2])];
	        }
	    }
	},
	/**
	 * Related scopes
	 * @type {Array}
	 * @memberof Model.prototype
	 */
	relatedScopes: {
		get: function () {
			"use strict";
			return [].concat(internal(this)._relatedScopes);
		},
		set: function (scopes) {
			"use strict";
			if (scopes instanceof Array) {
				internal(this)._relatedScopes = [].concat(scopes);
			}
		}
	},
	/**
	 * DUPairs found in this model
	 * @type {Map}
	 * @memberof Model.prototype
	 */
	dupairs: {
		get: function () {
			"use strict";
			var map = new Map();
			internal(this)._dupairs.forEach(function (val, key) {
				map.set(key, val);
			});
			return map;
		},
		set: function (dupairs) {
			"use strict";
			if (dupairs instanceof Map) {
				var currentAnalysisItem = this;
				dupairs.forEach(function (pairs, variable) {
					internal(currentAnalysisItem)._dupairs.set(variable, pairs);
				});
			}
		}
	},
	/**
	 * Mainly related scope
	 * @type {Scope}
	 * @memberof Model.prototype
	 */
	mainlyRelatedScope: {
		get: function () {
			"use strict";
			return internal(this)._mainlyRelatedScope;
		}
	}
});
/* end-public-data-members */

module.exports = Model;<commit_msg>Refactor the getter of property "graph"<commit_after>/*
 * Model module
 * @lastmodifiedBy ChengFuLin(chengfulin0806@gmail.com)
 * @lastmodifiedDate 2015-08-19
 */
var namespace = require('../namespace'),
    internal = namespace();
var Scope = require('./scope'),
    DUPair = require('./dupair'),
    cfgValidator = require('./cfgvalidator');
var Map = require('core-js/es6/map'),
	Set = require('../analyses/set');

/**
 * Model
 * @constructor
 */
function Model() {
    "use strict";
    internal(this)._relatedScopes = [];
	internal(this)._mainlyRelatedScope = null;
    internal(this)._graph = null;
    internal(this)._dupairs = new Map(); /// (Var, Set)
	/// TODO: should contain dataflow artifacts (ReachIn, ReachOut, KILL, GEN, USE) or not

    /* start-test-block */
    this._testonly_ = internal(this);
    /* end-test-block */
}

/* start-static-methods */
/**
 * Check for the object is an Model
 * @param {Object} obj An object to be checked
 * @returns {boolean} True, if it is; false, otherwise
 */
Model.isModel = function (obj) {
    "use strict";
    return obj instanceof Model;
};
/* end-static-methods */

/* start-public-methods */
/**
 * Check for the scope is related
 * @param {Scope} scope A Scope to be checked
 * @returns {boolean}
 */
Model.prototype.isRelatedToTheScope = function (scope) {
    "use strict";
    return internal(this)._relatedScopes.indexOf(scope) !== -1;
};

/**
 * Check the scope is mainly related, which means this model is derive from the scope's intra-procedural model
 * @param {Scope} scope A Scope to be checked
 * @returns {boolean} True, if it is; false, otherwise
 */
Model.prototype.isMainlyRelatedToTheScope = function (scope) {
    "use strict";
    return internal(this)._mainlyRelatedScope === scope;
};

/**
 * Add a related scope
 * @param {Scope} scope Related scope
 */
Model.prototype.addRelatedScope = function (scope) {
    "use strict";
    if (Scope.isScope(scope) && !this.isRelatedToTheScope(scope)) {
	    if (internal(this)._relatedScopes.length === 0) {
		    internal(this)._mainlyRelatedScope = scope;
	    }
        internal(this)._relatedScopes.push(scope);
    }
};

/**
 * Check for DUPair has found
 * @param {DUPair} dupair
 * @returns {boolean} True, if found; false, otherwise
 */
Model.prototype.hasDUPair = function (dupair) {
    "use strict";
    var found = false;
    if (DUPair.isDUPair(dupair)) {
        internal(this)._dupairs.forEach(function (pairs) {
            pairs.forEach(function (pair) {
                if (pair.def === dupair.def && pair.use === dupair.use) {
                    found = true;
                }
            });
        });
    }
    return found;
};
/* end-public-methods */

/* start-public-data-members */
Object.defineProperties(Model.prototype, {
	/**
	 * Graph of the model
	 * @type {Array}
	 * @memberof Model.prototype
	 */
	graph: {
	    get: function () {
	        "use strict";
	        return [internal(this)._graph[0], internal(this)._graph[1], [].concat(internal(this)._graph[2])];
	    },
	    set: function (graph) {
	        "use strict";
	        if (cfgValidator.isValidCFG(graph)) {
	            internal(this)._graph = [graph[0], graph[1], [].concat(graph[2])];
	        }
	    }
	},
	/**
	 * Related scopes
	 * @type {Array}
	 * @memberof Model.prototype
	 */
	relatedScopes: {
		get: function () {
			"use strict";
			return [].concat(internal(this)._relatedScopes);
		},
		set: function (scopes) {
			"use strict";
			if (scopes instanceof Array) {
				internal(this)._relatedScopes = [].concat(scopes);
			}
		}
	},
	/**
	 * DUPairs found in this model
	 * @type {Map}
	 * @memberof Model.prototype
	 */
	dupairs: {
		get: function () {
			"use strict";
			var map = new Map();
			internal(this)._dupairs.forEach(function (val, key) {
				map.set(key, val);
			});
			return map;
		},
		set: function (dupairs) {
			"use strict";
			if (dupairs instanceof Map) {
				var currentAnalysisItem = this;
				dupairs.forEach(function (pairs, variable) {
					internal(currentAnalysisItem)._dupairs.set(variable, pairs);
				});
			}
		}
	},
	/**
	 * Mainly related scope
	 * @type {Scope}
	 * @memberof Model.prototype
	 */
	mainlyRelatedScope: {
		get: function () {
			"use strict";
			return internal(this)._mainlyRelatedScope;
		}
	}
});
/* end-public-data-members */

module.exports = Model;<|endoftext|>


<commit_before>const crypto = require('crypto');
const MD5    = (s, encoding) => crypto.createHash('md5').update(s).digest(encoding);

// Magic numbers
const MAGIC = {
  chat  : new Buffer('58f18d70f667c9c79ef7de435bf0f9b1553bbb6e61816212ab80e5b0d351fbb1', 'hex'),
  email : new Buffer('52eafb7a84e95c1dbdb0ffef1aa5c8d1aab8158b5232934f154a7cffee29b923', 'hex'),
  alarm : new Buffer('b7691867799c11d5b837f8a5e86e81c8e6d2bbcc624f157ac4f03d5d3701e11e', 'hex'),
};

function generateKey(magicKey, id_key_uuid, privatePassword) {
  return Buffer.concat([
    MD5( Buffer.concat([ new Buffer(id_key_uuid, 'utf8'), magicKey ]) ),
    MD5( Buffer.concat([ magicKey, new Buffer(privatePassword, 'utf8') ]) )
  ]);
}

var Encryption = module.exports = function Encryption(serialNumber, accessKey, password) {
  if (! (this instanceof Encryption)) return new Encryption(serialNumber, accessKey, password);
  this.keys = {
    chat  : generateKey(MAGIC.chat,  accessKey,    password),
    email : generateKey(MAGIC.email, serialNumber, 'gservice_smtp'),
    alarm : generateKey(MAGIC.alarm, serialNumber, 'gservice_alarm'),
  }
};

Encryption.prototype.encrypt = function(data, type) {
  var key    = this.keys[ type || 'chat' ];
  var cipher = crypto.createCipheriv('aes-256-ecb', key, new Buffer(0));

  cipher.setAutoPadding(false);

  // Apply manual padding.
  var buffer = new Buffer(data, 'utf8');
  if (buffer.length % 16 !== 0) {
    buffer = Buffer.concat([
      buffer,
      new Buffer(16 - (buffer.length % 16)).fill(0),
    ]);
  }
  return cipher.update(buffer, null, 'base64') + cipher.final('base64');
};

Encryption.prototype.decrypt = function(data, type) {
  var key       = this.keys[ type || 'chat' ];
  var encrypted = new Buffer(data, 'base64');
  var decipher  = crypto.createDecipheriv('aes-256-ecb', key, new Buffer(0));

  decipher.setAutoPadding(false);

  // Add zero-padding?
  var paddingLength = encrypted.length % 8;
  if (paddingLength !== 0) {
    var padding = new Buffer(paddingLength).fill(0);
    encrypted = Buffer.concat([ encrypted, padding ]);
  }
  return decipher.update(encrypted).toString() + decipher.final().toString();
};
<commit_msg>Cleanups<commit_after>const crypto = require('crypto');
const MD5    = (s, encoding) => crypto.createHash('md5').update(s).digest(encoding);

// Magic number.
const MAGIC = new Buffer('58f18d70f667c9c79ef7de435bf0f9b1553bbb6e61816212ab80e5b0d351fbb1', 'hex');

function generateKey(magicKey, id_key_uuid, privatePassword) {
  return Buffer.concat([
    MD5( Buffer.concat([ new Buffer(id_key_uuid, 'utf8'), magicKey ]) ),
    MD5( Buffer.concat([ magicKey, new Buffer(privatePassword, 'utf8') ]) )
  ]);
}

var Encryption = module.exports = function Encryption(serialNumber, accessKey, password) {
  if (! (this instanceof Encryption)) return new Encryption(serialNumber, accessKey, password);
  this.key = generateKey(MAGIC,  accessKey, password);
};

Encryption.prototype.encrypt = function(data, type) {
  var cipher = crypto.createCipheriv('aes-256-ecb', this.key, new Buffer(0));

  cipher.setAutoPadding(false);

  // Apply manual padding.
  var buffer = new Buffer(data, 'utf8');
  if (buffer.length % 16 !== 0) {
    buffer = Buffer.concat([
      buffer,
      new Buffer(16 - (buffer.length % 16)).fill(0),
    ]);
  }
  return cipher.update(buffer, null, 'base64') + cipher.final('base64');
};

Encryption.prototype.decrypt = function(data, type) {
  var encrypted = new Buffer(data, 'base64');
  var decipher  = crypto.createDecipheriv('aes-256-ecb', this.key, new Buffer(0));

  decipher.setAutoPadding(false);

  // Add zero-padding?
  var paddingLength = encrypted.length % 8;
  if (paddingLength !== 0) {
    var padding = new Buffer(paddingLength).fill(0);
    encrypted = Buffer.concat([ encrypted, padding ]);
  }
  return decipher.update(encrypted).toString() + decipher.final().toString();
};
<|endoftext|>


<commit_before>var util = require("ethereumjs-util");
var nacl = require('tweetnacl');

function nacl_encodeHex(msgUInt8Arr) {
  var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr);
  return (new Buffer(msgBase64, 'base64')).toString('hex');
}

function nacl_decodeHex(msgHex) {
  var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64');
  return nacl.util.decodeBase64(msgBase64);
}

function addressToPublicEncKey (keystore, pwDerivedKey, address) {
  var privKey = keystore.exportPrivateKey(address, pwDerivedKey)
  var privKeyUInt8Array = nacl_decodeHex(privKey)
  var pubKeyUInt8Array = nacl.box.keyPair.fromSecretKey(privKeyUInt8Array).publicKey
  return nacl_encodeHex(pubKeyUInt8Array)
}

function _asymEncryptRaw (keystore, pwDerivedKey, msgUint8Array, myAddress, theirPubKey) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  if (keystore.encPrivKeys[myAddress] === undefined) {
    throw new Error('encryption._asymEncryptRaw: address not found in KeyStore');
  }

  var privKey = keystore.exportPrivateKey(myAddress, pwDerivedKey);
  var privKeyUInt8Array = nacl_decodeHex(privKey);
  var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);
  var nonce = nacl.randomBytes(nacl.box.nonceLength);
  var encryptedMessage = nacl.box(msgUint8Array, nonce, pubKeyUInt8Array, privKeyUInt8Array);

  var output = {
    alg: 'curve25519-xsalsa20-poly1305',
    nonce: nacl.util.encodeBase64(nonce),
    ciphertext: nacl.util.encodeBase64(encryptedMessage)
  };

  return output;
}

function _asymDecryptRaw (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  if (keystore.encPrivKeys[myAddress] === undefined) {
    throw new Error('encryption._asymDecryptRaw: address not found in KeyStore');
  }

  var privKey = keystore.exportPrivateKey(myAddress, pwDerivedKey);
  var privKeyUInt8Array = nacl_decodeHex(privKey);
  var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);

  var nonce = nacl.util.decodeBase64(encMsg.nonce);
  var ciphertext = nacl.util.decodeBase64(encMsg.ciphertext);
  var cleartext = nacl.box.open(ciphertext, nonce, pubKeyUInt8Array, privKeyUInt8Array);

  return cleartext;

}

var asymEncryptString = function (keystore, pwDerivedKey, msg, myAddress, theirPubKey) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var messageUInt8Array = nacl.util.decodeUTF8(msg);

  return _asymEncryptRaw(keystore, pwDerivedKey, messageUInt8Array, myAddress, theirPubKey);

}

var asymDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var cleartext = _asymDecryptRaw(keystore, pwDerivedKey, encMsg, theirPubKey, myAddress);

  if (cleartext === false) {
    return false;
  }
  else {
    return nacl.util.encodeUTF8(cleartext);
  }

}

var multiEncryptString = function (keystore, pwDerivedKey, msg, myAddress, theirPubKeyArray) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var messageUInt8Array = nacl.util.decodeUTF8(msg);
  var symEncryptionKey = nacl.randomBytes(nacl.secretbox.keyLength);
  var symNonce = nacl.randomBytes(nacl.secretbox.nonceLength);

  var symEncMessage = nacl.secretbox(messageUInt8Array, symNonce, symEncryptionKey);

  if (theirPubKeyArray.length < 1) {
    throw new Error('Found no pubkeys to encrypt to.');
  }

  var encryptedSymKey = {};
  encryptedSymKey = []
  for (var i=0; i<theirPubKeyArray.length; i++) {

    var encSymKey = _asymEncryptRaw(keystore, pwDerivedKey, symEncryptionKey, myAddress, theirPubKeyArray[i]);

    delete encSymKey['alg'];
    encryptedSymKey.push(encSymKey);
  }

  var output = {};
  output.version = 1;
  output.asymAlg = 'curve25519-xsalsa20-poly1305';
  output.symAlg = 'xsalsa20-poly1305';
  output.symNonce = nacl.util.encodeBase64(symNonce);
  output.symEncMessage = nacl.util.encodeBase64(symEncMessage);
  output.encryptedSymKey = encryptedSymKey;

  return output;
}

var multiDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var symKey = false;
  for (var i=0; i < encMsg.encryptedSymKey.length; i++) {
    var result = _asymDecryptRaw(keystore, pwDerivedKey, encMsg.encryptedSymKey[i], theirPubKey, myAddress)
    if (result !== false) {
      symKey = result;
      break;
    }
  }

  if (symKey === false) {
    return false;
  }
  else {
    var symNonce = nacl.util.decodeBase64(encMsg.symNonce);
    var symEncMessage = nacl.util.decodeBase64(encMsg.symEncMessage);
    var msg = nacl.secretbox.open(symEncMessage, symNonce, symKey);

    if (msg === false) {
      return false;
    }
    else {
      return nacl.util.encodeUTF8(msg);
    }
  }

}

module.exports = {
  asymEncryptString: asymEncryptString,
  asymDecryptString: asymDecryptString,
  multiEncryptString: multiEncryptString,
  multiDecryptString: multiDecryptString,
  addressToPublicEncKey: addressToPublicEncKey
};
<commit_msg>Remove superflous checks<commit_after>var util = require("ethereumjs-util");
var nacl = require('tweetnacl');

function nacl_encodeHex(msgUInt8Arr) {
  var msgBase64 = nacl.util.encodeBase64(msgUInt8Arr);
  return (new Buffer(msgBase64, 'base64')).toString('hex');
}

function nacl_decodeHex(msgHex) {
  var msgBase64 = (new Buffer(msgHex, 'hex')).toString('base64');
  return nacl.util.decodeBase64(msgBase64);
}

function addressToPublicEncKey (keystore, pwDerivedKey, address) {
  var privKey = keystore.exportPrivateKey(address, pwDerivedKey)
  var privKeyUInt8Array = nacl_decodeHex(privKey)
  var pubKeyUInt8Array = nacl.box.keyPair.fromSecretKey(privKeyUInt8Array).publicKey
  return nacl_encodeHex(pubKeyUInt8Array)
}

function _asymEncryptRaw (keystore, pwDerivedKey, msgUint8Array, myAddress, theirPubKey) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var privKey = keystore.exportPrivateKey(myAddress, pwDerivedKey);
  var privKeyUInt8Array = nacl_decodeHex(privKey);
  var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);
  var nonce = nacl.randomBytes(nacl.box.nonceLength);
  var encryptedMessage = nacl.box(msgUint8Array, nonce, pubKeyUInt8Array, privKeyUInt8Array);

  var output = {
    alg: 'curve25519-xsalsa20-poly1305',
    nonce: nacl.util.encodeBase64(nonce),
    ciphertext: nacl.util.encodeBase64(encryptedMessage)
  };

  return output;
}

function _asymDecryptRaw (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var privKey = keystore.exportPrivateKey(myAddress, pwDerivedKey);
  var privKeyUInt8Array = nacl_decodeHex(privKey);
  var pubKeyUInt8Array = nacl_decodeHex(theirPubKey);

  var nonce = nacl.util.decodeBase64(encMsg.nonce);
  var ciphertext = nacl.util.decodeBase64(encMsg.ciphertext);
  var cleartext = nacl.box.open(ciphertext, nonce, pubKeyUInt8Array, privKeyUInt8Array);

  return cleartext;

}

var asymEncryptString = function (keystore, pwDerivedKey, msg, myAddress, theirPubKey) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var messageUInt8Array = nacl.util.decodeUTF8(msg);

  return _asymEncryptRaw(keystore, pwDerivedKey, messageUInt8Array, myAddress, theirPubKey);

}

var asymDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var cleartext = _asymDecryptRaw(keystore, pwDerivedKey, encMsg, theirPubKey, myAddress);

  if (cleartext === false) {
    return false;
  }
  else {
    return nacl.util.encodeUTF8(cleartext);
  }

}

var multiEncryptString = function (keystore, pwDerivedKey, msg, myAddress, theirPubKeyArray) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var messageUInt8Array = nacl.util.decodeUTF8(msg);
  var symEncryptionKey = nacl.randomBytes(nacl.secretbox.keyLength);
  var symNonce = nacl.randomBytes(nacl.secretbox.nonceLength);

  var symEncMessage = nacl.secretbox(messageUInt8Array, symNonce, symEncryptionKey);

  if (theirPubKeyArray.length < 1) {
    throw new Error('Found no pubkeys to encrypt to.');
  }

  var encryptedSymKey = {};
  encryptedSymKey = []
  for (var i=0; i<theirPubKeyArray.length; i++) {

    var encSymKey = _asymEncryptRaw(keystore, pwDerivedKey, symEncryptionKey, myAddress, theirPubKeyArray[i]);

    delete encSymKey['alg'];
    encryptedSymKey.push(encSymKey);
  }

  var output = {};
  output.version = 1;
  output.asymAlg = 'curve25519-xsalsa20-poly1305';
  output.symAlg = 'xsalsa20-poly1305';
  output.symNonce = nacl.util.encodeBase64(symNonce);
  output.symEncMessage = nacl.util.encodeBase64(symEncMessage);
  output.encryptedSymKey = encryptedSymKey;

  return output;
}

var multiDecryptString = function (keystore, pwDerivedKey, encMsg, theirPubKey, myAddress) {

  if(!keystore.isDerivedKeyCorrect(pwDerivedKey)) {
    throw new Error("Incorrect derived key!");
  }

  var symKey = false;
  for (var i=0; i < encMsg.encryptedSymKey.length; i++) {
    var result = _asymDecryptRaw(keystore, pwDerivedKey, encMsg.encryptedSymKey[i], theirPubKey, myAddress)
    if (result !== false) {
      symKey = result;
      break;
    }
  }

  if (symKey === false) {
    return false;
  }
  else {
    var symNonce = nacl.util.decodeBase64(encMsg.symNonce);
    var symEncMessage = nacl.util.decodeBase64(encMsg.symEncMessage);
    var msg = nacl.secretbox.open(symEncMessage, symNonce, symKey);

    if (msg === false) {
      return false;
    }
    else {
      return nacl.util.encodeUTF8(msg);
    }
  }

}

module.exports = {
  asymEncryptString: asymEncryptString,
  asymDecryptString: asymDecryptString,
  multiEncryptString: multiEncryptString,
  multiDecryptString: multiDecryptString,
  addressToPublicEncKey: addressToPublicEncKey
};
<|endoftext|>


<commit_before>/**
 * prototype for an action that can run on the scheduler. It can emit 'frame' events, which will
 * be picked up by the scheduler and sent to the driver. Or it can participate in the animation loop, returning
 * a list of light values in the `step` function.
 */
'use strict';

var EventEmitter = require('events').EventEmitter,
    inherits     = require('inherits'),
    _            = require('lodash');

module.exports = Action;
inherits(Action, EventEmitter);
Action.prototype.step = step;

function Action(options){
    options = options || {};
    this.scheduler = options.scheduler;

    // auto-add the action to the scheduler if it's given
    if(this.scheduler) this.scheduler.add(this);
};

function step() {
    console.warn('Default action step, please override');
};<commit_msg>observable functionality ideas<commit_after>/**
 * prototype for an action that can run on the scheduler. It can emit 'frame' events, which will
 * be picked up by the scheduler and sent to the driver. Or it can participate in the animation loop, returning
 * a list of light values in the `step` function.
 */
'use strict';

var EventEmitter = require('events').EventEmitter,
    inherits     = require('inherits'),
    _            = require('lodash');

module.exports = Action;

inherits(Action, EventEmitter);

Action.prototype.step = step;
Action.prototype.observable = observable;

function Action(options){
    options = options || {};
    this.scheduler = options.scheduler;

    // auto-add the action to the scheduler if it's given
    if(this.scheduler) this.scheduler.add(this);
}

function step() {
    console.warn('Default action step, please override');
}

/**
 * get an observable that responds to the action
 *
 * fires an onNext when step is executed and when the 'frame' event is emitted
 * onCompleted when the 'end' event is emitted
 */
function observable() {

}<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

let getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function(obj) {
    return Object.getOwnPropertyNames(obj).reduce(function (descriptors, name) {
        descriptors[name] = Object.getOwnPropertyDescriptor(obj, name);
        return descriptors;
    }, {});
};

function setConstructorOnPrototype(klass) {
    if (klass.prototype.constructor !== klass) {
        Object.defineProperty(klass.prototype, 'constructor', { value: klass, configurable: true, writable: true });
    }
}

module.exports = function(realmConstructor) {
    // Add the specified Array methods to the Collection prototype.
    Object.defineProperties(realmConstructor.Collection.prototype, require('./collection-methods'));

    setConstructorOnPrototype(realmConstructor.Collection);
    setConstructorOnPrototype(realmConstructor.List);
    setConstructorOnPrototype(realmConstructor.Results);
    setConstructorOnPrototype(realmConstructor.Object);

    //Add async open API
    Object.defineProperties(realmConstructor, getOwnPropertyDescriptors({
        open(config) {
            return new Promise((resolve, reject) => {
                realmConstructor._waitForDownload(config, (error) => {
                    if (error) {
                        reject(error);
                    }

                    let syncedRealm = new realmConstructor(config);
                    //FIXME: RN hangs here. Remove when node's makeCallback alternative is implemented
                    setTimeout(() => { resolve(syncedRealm); }, 1);
                });
            });
        },

        openAsync(config, callback) {
                realmConstructor._waitForDownload(config, (error) => {
                    if (error) {
                        callback(error);
                    }

                    let syncedRealm = new realmConstructor(config);
                    //FIXME: RN hangs here. Remove when node's makeCallback alternative is implemented
                    setTimeout(() => { callback(null, syncedRealm); }, 1);
                });
        },
    }));

    // Add sync methods
    if (realmConstructor.Sync) {
        let userMethods = require('./user-methods');
        Object.defineProperties(realmConstructor.Sync.User, getOwnPropertyDescriptors(userMethods.static));
        Object.defineProperties(realmConstructor.Sync.User.prototype, getOwnPropertyDescriptors(userMethods.instance));
        Object.defineProperty(realmConstructor.Sync.User, '_realmConstructor', { value: realmConstructor });

        realmConstructor.Sync.AuthError = require('./errors').AuthError;

        if (realmConstructor.Sync.cleanup) {
            // FIXME: DOES THIS WORK ON BOTH NODE AND REACT NATIVE?
            process.on('exit', realmConstructor.Sync.cleanup);
            process.on('SIGINT', function () {
                realmConstructor.Sync.cleanup();
                process.exit(2);
            });
            process.on('uncaughtException', function(e) {
                realmConstructor.Sync.cleanup();
                /* eslint-disable no-console */
                console.log(e.stack);
                process.exit(99);
            });
        }

        setConstructorOnPrototype(realmConstructor.Sync.User);
        setConstructorOnPrototype(realmConstructor.Sync.Session);
    } else {
        Object.defineProperty(realmConstructor, 'Sync', {
            get: function () {
                throw new Error("Realm.Sync is not available. Note that the developer edition of the Node.JS SDK for Realm does not include sync on Linux.");
            }
        })
    }

    // TODO: Remove this now useless object.
    var types = Object.freeze({
        'BOOL': 'bool',
        'INT': 'int',
        'FLOAT': 'float',
        'DOUBLE': 'double',
        'STRING': 'string',
        'DATE': 'date',
        'DATA': 'data',
        'OBJECT': 'object',
        'LIST': 'list',
    });
    Object.defineProperty(realmConstructor, 'Types', {
        get: function() {
            if (typeof console != 'undefined') {
                /* global console */
                /* eslint-disable no-console */
                var stack = new Error().stack.split("\n").slice(2).join("\n");
                var msg = '`Realm.Types` is deprecated! Please specify the type name as lowercase string instead!\n'+stack;
                if (console.warn != undefined) {
                    console.warn(msg);
                }
                else {
                    console.log(msg);
                }
                /* eslint-enable no-console */
            }
            return types;
        },
        configurable: true
    });
}
<commit_msg>Replace calls to sync.cleanup with sync.removealllisteners (#1066)<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

let getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function(obj) {
    return Object.getOwnPropertyNames(obj).reduce(function (descriptors, name) {
        descriptors[name] = Object.getOwnPropertyDescriptor(obj, name);
        return descriptors;
    }, {});
};

function setConstructorOnPrototype(klass) {
    if (klass.prototype.constructor !== klass) {
        Object.defineProperty(klass.prototype, 'constructor', { value: klass, configurable: true, writable: true });
    }
}

module.exports = function(realmConstructor) {
    // Add the specified Array methods to the Collection prototype.
    Object.defineProperties(realmConstructor.Collection.prototype, require('./collection-methods'));

    setConstructorOnPrototype(realmConstructor.Collection);
    setConstructorOnPrototype(realmConstructor.List);
    setConstructorOnPrototype(realmConstructor.Results);
    setConstructorOnPrototype(realmConstructor.Object);

    //Add async open API
    Object.defineProperties(realmConstructor, getOwnPropertyDescriptors({
        open(config) {
            return new Promise((resolve, reject) => {
                realmConstructor._waitForDownload(config, (error) => {
                    if (error) {
                        reject(error);
                    }

                    let syncedRealm = new realmConstructor(config);
                    //FIXME: RN hangs here. Remove when node's makeCallback alternative is implemented
                    setTimeout(() => { resolve(syncedRealm); }, 1);
                });
            });
        },

        openAsync(config, callback) {
                realmConstructor._waitForDownload(config, (error) => {
                    if (error) {
                        callback(error);
                    }

                    let syncedRealm = new realmConstructor(config);
                    //FIXME: RN hangs here. Remove when node's makeCallback alternative is implemented
                    setTimeout(() => { callback(null, syncedRealm); }, 1);
                });
        },
    }));

    // Add sync methods
    if (realmConstructor.Sync) {
        let userMethods = require('./user-methods');
        Object.defineProperties(realmConstructor.Sync.User, getOwnPropertyDescriptors(userMethods.static));
        Object.defineProperties(realmConstructor.Sync.User.prototype, getOwnPropertyDescriptors(userMethods.instance));
        Object.defineProperty(realmConstructor.Sync.User, '_realmConstructor', { value: realmConstructor });

        realmConstructor.Sync.AuthError = require('./errors').AuthError;

        if (realmConstructor.Sync.removeAllListeners) {
            process.on('exit', realmConstructor.Sync.removeAllListeners);
            process.on('SIGINT', function () {
                realmConstructor.Sync.removeAllListeners();
                process.exit(2);
            });
            process.on('uncaughtException', function(e) {
                realmConstructor.Sync.removeAllListeners();
                /* eslint-disable no-console */
                console.log(e.stack);
                process.exit(99);
            });
        }

        setConstructorOnPrototype(realmConstructor.Sync.User);
        setConstructorOnPrototype(realmConstructor.Sync.Session);
    } else {
        Object.defineProperty(realmConstructor, 'Sync', {
            get: function () {
                throw new Error("Realm.Sync is not available. Note that the developer edition of the Node.JS SDK for Realm does not include sync on Linux.");
            }
        })
    }

    // TODO: Remove this now useless object.
    var types = Object.freeze({
        'BOOL': 'bool',
        'INT': 'int',
        'FLOAT': 'float',
        'DOUBLE': 'double',
        'STRING': 'string',
        'DATE': 'date',
        'DATA': 'data',
        'OBJECT': 'object',
        'LIST': 'list',
    });
    Object.defineProperty(realmConstructor, 'Types', {
        get: function() {
            if (typeof console != 'undefined') {
                /* global console */
                /* eslint-disable no-console */
                var stack = new Error().stack.split("\n").slice(2).join("\n");
                var msg = '`Realm.Types` is deprecated! Please specify the type name as lowercase string instead!\n'+stack;
                if (console.warn != undefined) {
                    console.warn(msg);
                }
                else {
                    console.log(msg);
                }
                /* eslint-enable no-console */
            }
            return types;
        },
        configurable: true
    });
}
<|endoftext|>


<commit_before>/* eslint-disable no-undef */
const chai = require('chai');
const assert = chai.assert;
chai.should();

describe('Testing Hierarchy', () => {

  it('Should render hierarchy', () => {
    browser.url('/');
    browser.pause(5000);
    browser.url('/#!/hierarchy/40-49');
    browser.pause(1000);

    const text = browser.getText('.selected .dk5')[0];
    assert.equal(text, '40-49', 'title is present');

    const level = browser.getText('.selected .hierarchy-level')[0];
    assert.include(level, 'Geografi og rejser i alm.', 'sublevel is present');
  });

  it('Click on sublevel', () => {
    browser.url('/#!/hierarchy/40-49');
    browser.pause(5000);
    browser.click('[href="#!/hierarchy/40"]');
    browser.pause(5000);

    const sel = browser.getText('.selected');
    console.log('sel', sel);
    const dk5 = browser.getText('.dk5');
    console.log('dk5', dk5);
    const text2 = browser.getText('.selected .dk5');
    console.log('text2', text2);
    const h2 = browser.getText('.h2');
    console.log('h2', h2);
    const text = browser.getText('.selected h2 .dk5')[0];
    console.log('text', text);
    assert.equal(text, '40', 'title is present');

    const topics = browser.getText('.selected .hierarchy-topics');
    assert.include(topics[0], 'Flyveulykker', 'first topic is present');
  });

  it('Click between levels', () => {
    browser.url('/#!/hierarchy/40-49');
    browser.pause(1000);
    assert.equal(browser.getText('.selected .dk5')[0], '40-49', 'toplevel is selected');

    browser.click('[href="#!/hierarchy/40"]');
    browser.pause(1000);
    assert.equal(browser.getText('.selected .dk5')[0], '40', '2. level is selected');

    browser.click('[href="#!/hierarchy/40.6"]');
    browser.pause(1000);
    assert.equal(browser.getText('.selected .dk5'), '40.6', '3. level is selected');

    browser.click('[href="#!/hierarchy/40-49"]');
    browser.pause(1000);
    assert.equal(browser.getText('.selected .dk5')[0], '40-49', 'toplevel is selected');
  });

  it('Should display the first five aspects only', () => {
    browser.url('/#!/hierarchy/40');

    const topics = browser.getText('.selected .hierarchy-topics');

    assert.include(topics[0], 'Atlanterhavet\nBjerge\nFlyveulykker\nGeografi\nHave');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.notInclude(topics[0], 'Lande');
  });

  it('Should display all aspects when "Vis Flere" is clicked', () => {
    browser.url('/#!/hierarchy/40');

    let topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(browser.getText('.selected .hidden .hierarchy-topics'), 0);

    browser.click('.toggle-button');

    topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(topics[1].split('\n'), 12);
    assert.isTrue(browser.isExisting('.selected .show .hierarchy-topics'));
  });

  it('Should hide all but 5 aspects when "Vis Flere" is clicked twice', () => {
    browser.url('/#!/hierarchy/40');

    browser.click('.toggle-button');

    let topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(topics[1].split('\n'), 12);
    assert.isTrue(browser.isExisting('.selected .show .hierarchy-topics'));

    browser.click('.toggle-button');

    topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(browser.getText('.selected .hidden .hierarchy-topics'), 0);
  });
});
<commit_msg>Drop mixed getext<commit_after>/* eslint-disable no-undef */
const chai = require('chai');
const assert = chai.assert;
chai.should();

describe('Testing Hierarchy', () => {

  it('Should render hierarchy', () => {
    browser.url('/');
    browser.pause(500);
    browser.url('/#!/hierarchy/40-49');
    browser.pause(500);

    const text = browser.getText('.selected .dk5')[0];
    assert.equal(text, '40-49', 'title is present');

    const level = browser.getText('.selected .hierarchy-level')[0];
    assert.include(level, 'Geografi og rejser i alm.', 'sublevel is present');
  });

  it('Click on sublevel', () => {
    browser.url('/#!/hierarchy/40-49');
    browser.pause(500);
    browser.click('[href="#!/hierarchy/40"]');
    browser.pause(500);

    browser.pause(300);
    const text = browser.getText('.selected .hierarchy-level--header .dk5');
    assert.equal(text, '40', 'title is present');

    const topics = browser.getText('.selected .hierarchy-topics');
    assert.include(topics[0], 'Flyveulykker', 'first topic is present');
  });

  it('Click between levels', () => {
    browser.url('/#!/hierarchy/40-49');
    browser.pause(500);
    assert.equal(browser.getText('.selected .dk5')[0], '40-49', 'toplevel is selected');

    browser.click('[href="#!/hierarchy/40"]');
    browser.pause(500);
    assert.equal(browser.getText('.selected .dk5')[0], '40', '2. level is selected');

    browser.click('[href="#!/hierarchy/40.6"]');
    browser.pause(500);
    assert.equal(browser.getText('.selected .dk5'), '40.6', '3. level is selected');

    browser.click('[href="#!/hierarchy/40-49"]');
    browser.pause(500);
    assert.equal(browser.getText('.selected .dk5')[0], '40-49', 'toplevel is selected');
  });

  it('Should display the first five aspects only', () => {
    browser.url('/#!/hierarchy/40');

    const topics = browser.getText('.selected .hierarchy-topics');

    assert.include(topics[0], 'Atlanterhavet\nBjerge\nFlyveulykker\nGeografi\nHave');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.notInclude(topics[0], 'Lande');
  });

  it('Should display all aspects when "Vis Flere" is clicked', () => {
    browser.url('/#!/hierarchy/40');

    let topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(browser.getText('.selected .hidden .hierarchy-topics'), 0);

    browser.click('.toggle-button');

    topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(topics[1].split('\n'), 12);
    assert.isTrue(browser.isExisting('.selected .show .hierarchy-topics'));
  });

  it('Should hide all but 5 aspects when "Vis Flere" is clicked twice', () => {
    browser.url('/#!/hierarchy/40');

    browser.click('.toggle-button');

    let topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(topics[1].split('\n'), 12);
    assert.isTrue(browser.isExisting('.selected .show .hierarchy-topics'));

    browser.click('.toggle-button');

    topics = browser.getText('.selected .hierarchy-topics');
    assert.lengthOf(topics[0].split('\n'), 5);
    assert.lengthOf(browser.getText('.selected .hidden .hierarchy-topics'), 0);
  });
});
<|endoftext|>


<commit_before>'use strict';

/**
 * Provides functions to interact with the file system as an extension to the Node.js filesystem module.
 *
 * @module fileSystem
 * @class fileSystem
 * @main fileSystem
 */

var fs = require('fs');
var path = require('path');
var tar = require('tar');

/**
 * Creates a directory recursively and asynchronously.
 *
 * If parent directories do not exist, they will be automatically created.
 *
 * @method mkdirRecursive
 * @private
 * @async
 * @param {String} directoryPath The directory system path to create
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function mkdirRecursive(directoryPath, callback) {
  directoryPath = path.resolve(directoryPath);

  // Try to create directory
  fs.mkdir(directoryPath, function(error) {

    if (error && error.code === 'EEXIST') {

      // Can't create directory it already exists
      // It may have been created by another loop
      callback();

    } else if (error && error.code === 'ENOENT') {

      // Can't create directory, parent directory does not exist

      // Create parent directory
      mkdirRecursive(path.dirname(directoryPath), function(error) {
        if (!error) {

          // Now that parent directory is created, create requested directory
          fs.mkdir(directoryPath, function(error) {
            if (error && error.code === 'EEXIST') {

              // Can't create directory it already exists
              // It may have been created by another loop
              callback();

            } else
              callback(error);
          });

        } else
          callback(error);
      });
    } else
      callback(error);
  });
}

/**
 * Removes a directory and all its content recursively and asynchronously.
 *
 * It is assumed that the directory exists.
 *
 * @method rmdirRecursive
 * @private
 * @async
 * @param {String} directoryPath Path of the directory to remove
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function rmdirRecursive(directoryPath, callback) {

  // Open directory
  fs.readdir(directoryPath, function(error, resources) {

    // Failed reading directory
    if (error)
      return callback(error);

    var pendingResourceNumber = resources.length;

    // No more pending resources, done for this directory
    if (!pendingResourceNumber) {

      // Remove directory
      fs.rmdir(directoryPath, callback);

    }

    // Iterate through the list of resources in the directory
    resources.forEach(function(resource) {

      var resourcePath = path.join(directoryPath, resource);

      // Get resource stats
      fs.stat(resourcePath, function(error, stats) {
        if (error)
          return callback(error);

        // Resource correspond to a directory
        if (stats.isDirectory()) {

          resources = rmdirRecursive(path.join(directoryPath, resource), function(error) {
            if (error)
              return callback(error);

            pendingResourceNumber--;

            if (!pendingResourceNumber)
              fs.rmdir(directoryPath, callback);

          });

        } else {

          // Resource does not correspond to a directory
          // Mark resource as treated

          // Remove file
          fs.unlink(resourcePath, function(error) {
            if (error)
              return callback(error);
            else {
              pendingResourceNumber--;

              if (!pendingResourceNumber)
                fs.rmdir(directoryPath, callback);

            }
          });

        }

      });

    });

  });

}

/**
 * Copies a file.
 *
 * If directory does not exist it will be automatically created.
 *
 * @method copyFile
 * @private
 * @async
 * @param {String} sourceFilePath Path of the file
 * @param {String} destinationFilePath Final path of the file
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function copyFile(sourceFilePath, destinationFilePath, callback) {
  var onError = function(error) {
    callback(error);
  };

  var safecopy = function(sourceFilePath, destinationFilePath, callback) {
    if (sourceFilePath && destinationFilePath && callback) {
      try {
        var is = fs.createReadStream(sourceFilePath);
        var os = fs.createWriteStream(destinationFilePath);

        is.on('error', onError);
        os.on('error', onError);

        is.on('end', function() {
          os.end();
          callback();
        });

        is.pipe(os);
      } catch (e) {
        callback(new Error(e.message));
      }
    } else callback(new Error('File path not defined'));
  };

  var pathDir = path.dirname(destinationFilePath);

  this.mkdir(pathDir,
    function(error) {
      if (error) callback(error);
      else safecopy(sourceFilePath, destinationFilePath, callback);
    }
  );
}

/**
 * Extracts a tar file to the given directory.
 *
 * @method extract
 * @async
 * @param {String} filePath Path of the file to extract
 * @param {String} destinationPath Path of the directory where to
 * extract files
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.extract = function(filePath, destinationPath, callback) {
  var extractTimeout;
  var streamError;

  callback = callback || function(error) {
    if (error)
      process.logger.error('Extract error', {error: error});
    else
      process.logger.silly(filePath + ' extracted into ' + destinationPath);
  };

  if (filePath && destinationPath) {

    // Prepare the extractor with destination path
    var extractor = tar.Extract(
      {
        path: path.normalize(destinationPath)
      }
    );

    var onError = function(error) {
      if (extractTimeout)
        clearTimeout(extractTimeout);

      streamError = error;
      extractor.end();
    };

    // Handle extraction end
    extractor.on('end', function() {
      if (extractTimeout)
        clearTimeout(extractTimeout);

      callback(streamError);
    });

    var tarFileReadableStream = fs.createReadStream(path.normalize(filePath));

    // Handle errors
    tarFileReadableStream.on('error', onError);
    extractor.on('error', onError);

    // Listen to readable stream close event
    tarFileReadableStream.on('close', function(chunk) {

      // In case of a broken archive, the readable stream close event is dispatched but not the close event of the
      // writable stream, wait for 10 seconds and dispatch an error if writable stream is still not closed
      extractTimeout = setTimeout(onError, 10000, new Error('Unexpected end of archive'));

    });

    // Extract file
    tarFileReadableStream.pipe(extractor);

  } else
    callback(new TypeError('Invalid filePath and / or destinationPath, expected strings'));
};

/**
 * Copies a file or a directory.
 *
 * @method copy
 * @async
 * @param {String} sourcePath Path of the source to copy
 * @param {String} destinationSourcePath Final path of the source
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.copy = function(sourcePath, destinationSourcePath, callback) {
  var self = this;

  // Get source stats to test if this is a directory or a file
  fs.stat(sourcePath, function(error, stats) {
    if (error)
      return callback(error);

    if (stats.isDirectory()) {

      // Resource is a directory

      // Open directory
      fs.readdir(sourcePath, function(error, resources) {

        // Failed reading directory
        if (error)
          return callback(error);

        var pendingResourceNumber = resources.length;

        // Directory is empty, create it and leave
        if (!pendingResourceNumber) {
          self.mkdir(destinationSourcePath, callback);
          return;
        }

        // Iterate through the list of resources in the directory
        resources.forEach(function(resource) {
          var resourcePath = path.join(sourcePath, resource);
          var resourceDestinationPath = path.join(destinationSourcePath, resource);

          // Copy resource
          self.copy(resourcePath, resourceDestinationPath, function(error) {
            if (error)
              return callback(error);

            pendingResourceNumber--;

            if (!pendingResourceNumber)
              callback();
          });
        });

      });

    } else {

      // Resource is a file
      copyFile.call(self, sourcePath, destinationSourcePath, callback);

    }

  });

};

/**
 * Gets a JSON file content.
 *
 * This will verify that the file exists first.
 *
 * @method getJSONFileContent
 * @async
 * @param {String} filePath The path of the file to read
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **String** The file content or null if an error occurred
 * @throws {TypeError} An error if callback is not speficied
 */
module.exports.getJSONFileContent = function(filePath, callback) {
  if (!filePath)
    return callback(new TypeError('Invalid file path, expected a string'));

  // Check if file exists
  fs.exists(filePath, function(exists) {

    if (exists) {

      // Read file content
      fs.readFile(filePath, {
        encoding: 'utf8'
      },
      function(error, data) {
        if (error) {
          callback(error);
        } else {
          var dataAsJson;
          try {

            // Try to parse file data as JSON content
            dataAsJson = JSON.parse(data);

          } catch (e) {
            callback(new Error(e.message));
          }

          callback(null, dataAsJson);
        }
      });
    } else
      callback(new Error('Missing file ' + filePath));

  });
};

/**
 * Creates a directory.
 *
 * If parent directory does not exist, it will be automatically created.
 * If directory already exists, it won't do anything.
 *
 * @method mkdir
 * @async
 * @param {String} directoryPath The directory system path to create
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.mkdir = function(directoryPath, callback) {
  callback = callback || function(error) {
    if (error)
      process.logger.error('mkdir error', {error: error});
    else
      process.logger.silly(directoryPath + ' directory created');
  };

  if (!directoryPath)
    return callback(new TypeError('Invalid directory path, expected a string'));

  fs.exists(directoryPath, function(exists) {
    if (exists)
      callback();
    else
      mkdirRecursive(directoryPath, callback);
  });
};

/**
 * Removes a directory and all its content recursively and asynchronously.
 *
 * @method rmdir
 * @async
 * @param {String} directoryPath Path of the directory to remove
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.rmdir = function(directoryPath, callback) {
  callback = callback || function(error) {
    if (error)
      process.logger.error('rmdir error', {error: error});
    else
      process.logger.silly(directoryPath + ' directory removed');
  };

  if (!directoryPath)
    return callback(new TypeError('Invalid directory path, expected a string'));

  fs.exists(directoryPath, function(exists) {
    if (!exists)
      callback();
    else
      rmdirRecursive(directoryPath, callback);
  });
};

/**
 * Gets OpenVeo configuration directory path.
 *
 * OpenVeo configuration is stored in user home directory.
 *
 * @method getConfDir
 * @return {String} OpenVeo configuration directory path
 */
module.exports.getConfDir = function() {
  var env = process.env;
  var home = env.HOME;

  if (process.platform === 'win32')
    home = env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || '';

  return path.join(home, '.openveo');
};
<commit_msg>Correct bug on fileSystem.copyFile<commit_after>'use strict';

/**
 * Provides functions to interact with the file system as an extension to the Node.js filesystem module.
 *
 * @module fileSystem
 * @class fileSystem
 * @main fileSystem
 */

var fs = require('fs');
var path = require('path');
var tar = require('tar');

/**
 * Creates a directory recursively and asynchronously.
 *
 * If parent directories do not exist, they will be automatically created.
 *
 * @method mkdirRecursive
 * @private
 * @async
 * @param {String} directoryPath The directory system path to create
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function mkdirRecursive(directoryPath, callback) {
  directoryPath = path.resolve(directoryPath);

  // Try to create directory
  fs.mkdir(directoryPath, function(error) {

    if (error && error.code === 'EEXIST') {

      // Can't create directory it already exists
      // It may have been created by another loop
      callback();

    } else if (error && error.code === 'ENOENT') {

      // Can't create directory, parent directory does not exist

      // Create parent directory
      mkdirRecursive(path.dirname(directoryPath), function(error) {
        if (!error) {

          // Now that parent directory is created, create requested directory
          fs.mkdir(directoryPath, function(error) {
            if (error && error.code === 'EEXIST') {

              // Can't create directory it already exists
              // It may have been created by another loop
              callback();

            } else
              callback(error);
          });

        } else
          callback(error);
      });
    } else
      callback(error);
  });
}

/**
 * Removes a directory and all its content recursively and asynchronously.
 *
 * It is assumed that the directory exists.
 *
 * @method rmdirRecursive
 * @private
 * @async
 * @param {String} directoryPath Path of the directory to remove
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function rmdirRecursive(directoryPath, callback) {

  // Open directory
  fs.readdir(directoryPath, function(error, resources) {

    // Failed reading directory
    if (error)
      return callback(error);

    var pendingResourceNumber = resources.length;

    // No more pending resources, done for this directory
    if (!pendingResourceNumber) {

      // Remove directory
      fs.rmdir(directoryPath, callback);

    }

    // Iterate through the list of resources in the directory
    resources.forEach(function(resource) {

      var resourcePath = path.join(directoryPath, resource);

      // Get resource stats
      fs.stat(resourcePath, function(error, stats) {
        if (error)
          return callback(error);

        // Resource correspond to a directory
        if (stats.isDirectory()) {

          resources = rmdirRecursive(path.join(directoryPath, resource), function(error) {
            if (error)
              return callback(error);

            pendingResourceNumber--;

            if (!pendingResourceNumber)
              fs.rmdir(directoryPath, callback);

          });

        } else {

          // Resource does not correspond to a directory
          // Mark resource as treated

          // Remove file
          fs.unlink(resourcePath, function(error) {
            if (error)
              return callback(error);
            else {
              pendingResourceNumber--;

              if (!pendingResourceNumber)
                fs.rmdir(directoryPath, callback);

            }
          });

        }

      });

    });

  });

}

/**
 * Copies a file.
 *
 * If directory does not exist it will be automatically created.
 *
 * @method copyFile
 * @private
 * @async
 * @param {String} sourceFilePath Path of the file
 * @param {String} destinationFilePath Final path of the file
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
function copyFile(sourceFilePath, destinationFilePath, callback) {
  var onError = function(error) {
    callback(error);
  };

  var safecopy = function(sourceFilePath, destinationFilePath, callback) {
    if (sourceFilePath && destinationFilePath && callback) {
      try {
        var is = fs.createReadStream(sourceFilePath);
        var os = fs.createWriteStream(destinationFilePath);

        is.on('error', onError);
        os.on('error', onError);

        is.on('end', function() {
          os.end();
        });

        os.on('finish', function() {
          callback();
        });

        is.pipe(os);
      } catch (e) {
        callback(new Error(e.message));
      }
    } else callback(new Error('File path not defined'));
  };

  var pathDir = path.dirname(destinationFilePath);

  this.mkdir(pathDir,
    function(error) {
      if (error) callback(error);
      else safecopy(sourceFilePath, destinationFilePath, callback);
    }
  );
}

/**
 * Extracts a tar file to the given directory.
 *
 * @method extract
 * @async
 * @param {String} filePath Path of the file to extract
 * @param {String} destinationPath Path of the directory where to
 * extract files
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.extract = function(filePath, destinationPath, callback) {
  var extractTimeout;
  var streamError;

  callback = callback || function(error) {
    if (error)
      process.logger.error('Extract error', {error: error});
    else
      process.logger.silly(filePath + ' extracted into ' + destinationPath);
  };

  if (filePath && destinationPath) {

    // Prepare the extractor with destination path
    var extractor = tar.Extract(
      {
        path: path.normalize(destinationPath)
      }
    );

    var onError = function(error) {
      if (extractTimeout)
        clearTimeout(extractTimeout);

      streamError = error;
      extractor.end();
    };

    // Handle extraction end
    extractor.on('end', function() {
      if (extractTimeout)
        clearTimeout(extractTimeout);

      callback(streamError);
    });

    var tarFileReadableStream = fs.createReadStream(path.normalize(filePath));

    // Handle errors
    tarFileReadableStream.on('error', onError);
    extractor.on('error', onError);

    // Listen to readable stream close event
    tarFileReadableStream.on('close', function(chunk) {

      // In case of a broken archive, the readable stream close event is dispatched but not the close event of the
      // writable stream, wait for 10 seconds and dispatch an error if writable stream is still not closed
      extractTimeout = setTimeout(onError, 10000, new Error('Unexpected end of archive'));

    });

    // Extract file
    tarFileReadableStream.pipe(extractor);

  } else
    callback(new TypeError('Invalid filePath and / or destinationPath, expected strings'));
};

/**
 * Copies a file or a directory.
 *
 * @method copy
 * @async
 * @param {String} sourcePath Path of the source to copy
 * @param {String} destinationSourcePath Final path of the source
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.copy = function(sourcePath, destinationSourcePath, callback) {
  var self = this;

  // Get source stats to test if this is a directory or a file
  fs.stat(sourcePath, function(error, stats) {
    if (error)
      return callback(error);

    if (stats.isDirectory()) {

      // Resource is a directory

      // Open directory
      fs.readdir(sourcePath, function(error, resources) {

        // Failed reading directory
        if (error)
          return callback(error);

        var pendingResourceNumber = resources.length;

        // Directory is empty, create it and leave
        if (!pendingResourceNumber) {
          self.mkdir(destinationSourcePath, callback);
          return;
        }

        // Iterate through the list of resources in the directory
        resources.forEach(function(resource) {
          var resourcePath = path.join(sourcePath, resource);
          var resourceDestinationPath = path.join(destinationSourcePath, resource);

          // Copy resource
          self.copy(resourcePath, resourceDestinationPath, function(error) {
            if (error)
              return callback(error);

            pendingResourceNumber--;

            if (!pendingResourceNumber)
              callback();
          });
        });

      });

    } else {

      // Resource is a file
      copyFile.call(self, sourcePath, destinationSourcePath, callback);

    }

  });

};

/**
 * Gets a JSON file content.
 *
 * This will verify that the file exists first.
 *
 * @method getJSONFileContent
 * @async
 * @param {String} filePath The path of the file to read
 * @param {Function} callback The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **String** The file content or null if an error occurred
 * @throws {TypeError} An error if callback is not speficied
 */
module.exports.getJSONFileContent = function(filePath, callback) {
  if (!filePath)
    return callback(new TypeError('Invalid file path, expected a string'));

  // Check if file exists
  fs.exists(filePath, function(exists) {

    if (exists) {

      // Read file content
      fs.readFile(filePath, {
        encoding: 'utf8'
      },
      function(error, data) {
        if (error) {
          callback(error);
        } else {
          var dataAsJson;
          try {

            // Try to parse file data as JSON content
            dataAsJson = JSON.parse(data);

          } catch (e) {
            callback(new Error(e.message));
          }

          callback(null, dataAsJson);
        }
      });
    } else
      callback(new Error('Missing file ' + filePath));

  });
};

/**
 * Creates a directory.
 *
 * If parent directory does not exist, it will be automatically created.
 * If directory already exists, it won't do anything.
 *
 * @method mkdir
 * @async
 * @param {String} directoryPath The directory system path to create
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.mkdir = function(directoryPath, callback) {
  callback = callback || function(error) {
    if (error)
      process.logger.error('mkdir error', {error: error});
    else
      process.logger.silly(directoryPath + ' directory created');
  };

  if (!directoryPath)
    return callback(new TypeError('Invalid directory path, expected a string'));

  fs.exists(directoryPath, function(exists) {
    if (exists)
      callback();
    else
      mkdirRecursive(directoryPath, callback);
  });
};

/**
 * Removes a directory and all its content recursively and asynchronously.
 *
 * @method rmdir
 * @async
 * @param {String} directoryPath Path of the directory to remove
 * @param {Function} [callback] The function to call when done
 *   - **Error** The error if an error occurred, null otherwise
 */
module.exports.rmdir = function(directoryPath, callback) {
  callback = callback || function(error) {
    if (error)
      process.logger.error('rmdir error', {error: error});
    else
      process.logger.silly(directoryPath + ' directory removed');
  };

  if (!directoryPath)
    return callback(new TypeError('Invalid directory path, expected a string'));

  fs.exists(directoryPath, function(exists) {
    if (!exists)
      callback();
    else
      rmdirRecursive(directoryPath, callback);
  });
};

/**
 * Gets OpenVeo configuration directory path.
 *
 * OpenVeo configuration is stored in user home directory.
 *
 * @method getConfDir
 * @return {String} OpenVeo configuration directory path
 */
module.exports.getConfDir = function() {
  var env = process.env;
  var home = env.HOME;

  if (process.platform === 'win32')
    home = env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || '';

  return path.join(home, '.openveo');
};
<|endoftext|>