<commit_before>//wizard directive
angular.module('mgo-angular-wizard').directive('wizard', function() {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: {
            currentStep: '=',
            onFinish: '&',
            hideIndicators: '=',
            editMode: '=',
            name: '@',
            indicatorsPosition: '@?'
        },
        templateUrl: function(element, attributes) {
            return attributes.template || "wizard.html";
        },

        //controller for wizard directive, treat this just like an angular controller
        controller: ['$scope', '$element', '$log', 'WizardHandler', '$q', '$timeout', function ($scope, $element, $log, WizardHandler, $q, $timeout) {
            //setting default step position if none declared.
            if ($scope.indicatorsPosition == undefined) {
                $scope.indicatorsPosition = 'bottom';
            }
            //this variable allows directive to load without having to pass any step validation
            var firstRun = true;
            //creating instance of wizard, passing this as second argument allows access to functions attached to this via Service
            WizardHandler.addWizard($scope.name || WizardHandler.defaultName, this);

            $scope.$on('$destroy', function() {
                WizardHandler.removeWizard($scope.name || WizardHandler.defaultName);
            });

            //steps array where all the scopes of each step are added
            $scope.steps = [];

            var stepIdx = function(step) {
                var idx = 0;
                var res = -1;
                angular.forEach($scope.getEnabledSteps(), function(currStep) {
                  if (currStep === step) {
                    res = idx;
                  }
                  idx++;
                });
                return res;
            };

            var stepByTitle = function(titleToFind) {
              var foundStep = null;
              angular.forEach($scope.getEnabledSteps(), function(step) {
                if (step.wzTitle === titleToFind) {
                  foundStep = step;
                }
              });
              return foundStep;
            };

            //access to context object for step validation
            $scope.context = {};

            //watching changes to currentStep
            $scope.$watch('currentStep', function(step) {
                //checking to make sure currentStep is truthy value
                if (!step) return;
                //setting stepTitle equal to current step title or default title
                var stepTitle = $scope.selectedStep.wzTitle;
                if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
                    //invoking goTo() with step title as argument
                    $scope.goTo(stepByTitle($scope.currentStep));
                }
            });

            //watching steps array length and editMode value, if edit module is undefined or null the nothing is done
            //if edit mode is truthy, then all steps are marked as completed
            $scope.$watch('[editMode, steps.length]', function() {
                var editMode = $scope.editMode;
                if (angular.isUndefined(editMode) || (editMode === null)) return;

                if (editMode) {
                    angular.forEach($scope.getEnabledSteps(), function(step) {
                        step.completed = true;
                    });
                } else {
                    var completedStepsIndex = $scope.currentStepNumber() - 1;
                    angular.forEach($scope.getEnabledSteps(), function(step, stepIndex) {
                        if(stepIndex >= completedStepsIndex) {
                            step.completed = false;
                        }
                    });
                }
            }, true);

            //called each time step directive is loaded
            this.addStep = function(step) {
                var wzOrder = (step.wzOrder >= 0 && !$scope.steps[step.wzOrder]) ? step.wzOrder : $scope.steps.length;
                //adding the scope of directive onto step array
                $scope.steps[wzOrder] = step;
                //if this step is the new first then goTo it
                if ($scope.getEnabledSteps()[0] === step) {
                    //goTo first step
                    $scope.goTo($scope.getEnabledSteps()[0]);
                }
            };

            //called each time step directive is destroyed
            this.removeStep = function (step) {
                var index = $scope.steps.indexOf(step);
                if (index > 0) {
                    $scope.steps.splice(index, 1);
                }
            };

            this.context = $scope.context;

            $scope.getStepNumber = function(step) {
                return stepIdx(step) + 1;
            };

            $scope.goTo = function(step) {
                //if this is the first time the wizard is loading it bi-passes step validation
                if(firstRun){
                    //deselect all steps so you can set fresh below
                    unselectAll();
                    $scope.selectedStep = step;
                    //making sure current step is not undefined
                    if (!angular.isUndefined($scope.currentStep)) {
                        $scope.currentStep = step.wzTitle;
                    }
                    //setting selected step to argument passed into goTo()
                    step.selected = true;
                    //emit event upwards with data on goTo() invoktion
                    $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
                    //setting variable to false so all other step changes must pass validation
                    firstRun = false;
                } else {
                    //createing variables to capture current state that goTo() was invoked from and allow booleans
                    var thisStep;
                    //getting data for step you are transitioning out of
                    if($scope.currentStepNumber() > 0){
                        thisStep = $scope.currentStepNumber() - 1;
                    } else if ($scope.currentStepNumber() === 0){
                        thisStep = 0;
                    }
                    //$log.log('steps[thisStep] Data: ', $scope.getEnabledSteps()[thisStep].canexit);
                    $q.all([canExitStep($scope.getEnabledSteps()[thisStep], step), canEnterStep(step)]).then(function(data) {
                        if(data[0] && data[1]){
                            //deselect all steps so you can set fresh below
                            unselectAll();

                            //$log.log('value for canExit argument: ', $scope.currentStep.canexit);
                            $scope.selectedStep = step;
                            //making sure current step is not undefined
                            if(!angular.isUndefined($scope.currentStep)){
                                $scope.currentStep = step.wzTitle;
                            }
                            //setting selected step to argument passed into goTo()
                            step.selected = true;
                            //emit event upwards with data on goTo() invoktion
                            $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
                            //$log.log('current step number: ', $scope.currentStepNumber());
                        }
                    });
                }
            };

            function canEnterStep(step) {
                var defer,
                    canEnter;
                //If no validation function is provided, allow the user to enter the step
                if(step.canenter === undefined){
                    return true;
                }
                //If canenter is a boolean value instead of a function, return the value
                if(typeof step.canenter === 'boolean'){
                    return step.canenter;
                }
                //Check to see if the canenter function is a promise which needs to be returned
                canEnter = step.canenter($scope.context);
                if(angular.isFunction(canEnter.then)){
                    defer = $q.defer();
                    canEnter.then(function(response){
                        defer.resolve(response);
                    });
                    return defer.promise;
                } else {
                    return canEnter === true;
                }
            }

            function canExitStep(step, stepTo) {
                var defer,
                    canExit;
                //Exiting the step should be allowed if no validation function was provided or if the user is moving backwards
                if(typeof(step.canexit) === 'undefined' || $scope.getStepNumber(stepTo) < $scope.currentStepNumber()){
                    return true;
                }
                //If canexit is a boolean value instead of a function, return the value
                if(typeof step.canexit === 'boolean'){
                    return step.canexit;
                }
                //Check to see if the canexit function is a promise which needs to be returned
                canExit = step.canexit($scope.context);
                if(angular.isFunction(canExit.then)){
                    defer = $q.defer();
                    canExit.then(function(response){
                        defer.resolve(response);
                    });
                    return defer.promise;
                } else {
                    return canExit === true;
                }
            }

            $scope.currentStepNumber = function() {
                //retreive current step number
                return stepIdx($scope.selectedStep) + 1;
            };

            $scope.getEnabledSteps = function() {
                return $scope.steps.filter(function(step){
                    return step && step.disabled !== 'true';
                });
            };

            //unSelect All Steps
            function unselectAll() {
                //traverse steps array and set each "selected" property to false
                angular.forEach($scope.getEnabledSteps(), function (step) {
                    step.selected = false;
                });
                //set selectedStep variable to null
                $scope.selectedStep = null;
            }

            //ALL METHODS ATTACHED TO this ARE ACCESSIBLE VIA WizardHandler.wizard().methodName()

            this.currentStepTitle = function(){
                return $scope.selectedStep.wzTitle;
            };

            this.currentStepDescription = function(){
                return $scope.selectedStep.description;
            };

            this.currentStep = function(){
                return $scope.selectedStep;
            };

            this.totalStepCount = function() {
                return $scope.getEnabledSteps().length;
            };

            //Access to enabled steps from outside
            this.getEnabledSteps = function(){
                return $scope.getEnabledSteps();
            };

            //Access to current step number from outside
            this.currentStepNumber = function(){
                return $scope.currentStepNumber();
            };
            //method used for next button within step
            this.next = function(callback) {
                var enabledSteps = $scope.getEnabledSteps();
                //setting variable equal to step  you were on when next() was invoked
                var index = stepIdx($scope.selectedStep);
                //checking to see if callback is a function
                if(angular.isFunction(callback)){
                   if(callback()){
                        if (index === enabledSteps.length - 1) {
                            this.finish();
                        } else {
                            //invoking goTo() with step number next in line
                            $scope.goTo(enabledSteps[index + 1]);
                        }
                   } else {
                        return;
                   }
                }
                if (!callback) {
                    //completed property set on scope which is used to add class/remove class from progress bar
                    $scope.selectedStep.completed = true;
                }
                //checking to see if this is the last step.  If it is next behaves the same as finish()
                if (index === enabledSteps.length - 1) {
                    this.finish();
                } else {
                    //invoking goTo() with step number next in line
                    $scope.goTo(enabledSteps[index + 1]);
                }

            };

            //used to traverse to any step, step number placed as argument
            this.goTo = function(step) {
                //wrapped inside $timeout so newly enabled steps are included.
                $timeout(function() {
                    var enabledSteps = $scope.getEnabledSteps();
                    var stepTo;
                    //checking that step is a Number
                    if (angular.isNumber(step)) {
                        stepTo = enabledSteps[step];
                    } else {
                        //finding the step associated with the title entered as goTo argument
                        stepTo = stepByTitle(step);
                    }
                    //going to step
                    $scope.goTo(stepTo);
                });
            };

            //calls finish() which calls onFinish() which is declared on an attribute and linked to controller via wizard directive.
            this.finish = function() {
                if ($scope.onFinish) {
                    $scope.onFinish();
                }
            };

            this.previous = function() {
                //getting index of current step
                var index = stepIdx($scope.selectedStep);
                //ensuring you aren't trying to go back from the first step
                if (index === 0) {
                    throw new Error("Can't go back. It's already in step 0");
                } else {
                    //go back one step from current step
                    $scope.goTo($scope.getEnabledSteps()[index - 1]);
                }
            };

            //cancel is alias for previous.
            this.cancel = function() {
                //getting index of current step
                var index = stepIdx($scope.selectedStep);
                //ensuring you aren't trying to go back from the first step
                if (index === 0) {
                    throw new Error("Can't go back. It's already in step 0");
                } else {
                    //go back one step from current step
                    $scope.goTo($scope.getEnabledSteps()[0]);
                }
            };

            //reset
            this.reset = function(){
                //traverse steps array and set each "completed" property to false
                angular.forEach($scope.getEnabledSteps(), function (step) {
                    step.completed = false;
                });
                //go to first step
                this.goTo(0);
            };
        }]
    };
});<commit_msg>Fix for edit-mode true and disabled steps<commit_after>//wizard directive
angular.module('mgo-angular-wizard').directive('wizard', function() {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: {
            currentStep: '=',
            onFinish: '&',
            hideIndicators: '=',
            editMode: '=',
            name: '@',
            indicatorsPosition: '@?'
        },
        templateUrl: function(element, attributes) {
            return attributes.template || "wizard.html";
        },

        //controller for wizard directive, treat this just like an angular controller
        controller: ['$scope', '$element', '$log', 'WizardHandler', '$q', '$timeout', function ($scope, $element, $log, WizardHandler, $q, $timeout) {
            //setting default step position if none declared.
            if ($scope.indicatorsPosition == undefined) {
                $scope.indicatorsPosition = 'bottom';
            }
            //this variable allows directive to load without having to pass any step validation
            var firstRun = true;
            //creating instance of wizard, passing this as second argument allows access to functions attached to this via Service
            WizardHandler.addWizard($scope.name || WizardHandler.defaultName, this);

            $scope.$on('$destroy', function() {
                WizardHandler.removeWizard($scope.name || WizardHandler.defaultName);
            });

            //steps array where all the scopes of each step are added
            $scope.steps = [];

            var stepIdx = function(step) {
                var idx = 0;
                var res = -1;
                angular.forEach($scope.getEnabledSteps(), function(currStep) {
                  if (currStep === step) {
                    res = idx;
                  }
                  idx++;
                });
                return res;
            };

            var stepByTitle = function(titleToFind) {
              var foundStep = null;
              angular.forEach($scope.getEnabledSteps(), function(step) {
                if (step.wzTitle === titleToFind) {
                  foundStep = step;
                }
              });
              return foundStep;
            };

            //access to context object for step validation
            $scope.context = {};

            //watching changes to currentStep
            $scope.$watch('currentStep', function(step) {
                //checking to make sure currentStep is truthy value
                if (!step) return;
                //setting stepTitle equal to current step title or default title
                var stepTitle = $scope.selectedStep.wzTitle;
                if ($scope.selectedStep && stepTitle !== $scope.currentStep) {
                    //invoking goTo() with step title as argument
                    $scope.goTo(stepByTitle($scope.currentStep));
                }
            });

            //watching steps array length and editMode value, if edit module is undefined or null the nothing is done
            //if edit mode is truthy, then all steps are marked as completed
            $scope.$watch('[editMode, steps.length]', function() {
                var editMode = $scope.editMode;
                if (angular.isUndefined(editMode) || (editMode === null)) return;

                //Set completed for all steps to the value of editMode
                angular.forEach($scope.steps, function (step) {
                    step.completed = editMode;
                });

                //If editMode is false, set ONLY ENABLED steps with index lower then completedIndex to completed
                if (!editMode) {
                   var completedStepsIndex = $scope.currentStepNumber() - 1;
                    angular.forEach($scope.getEnabledSteps(), function(step, stepIndex) {
                        if(stepIndex < completedStepsIndex) {
                            step.completed = true;
                        }
                    });
                }
            }, true);

            //called each time step directive is loaded
            this.addStep = function(step) {
                var wzOrder = (step.wzOrder >= 0 && !$scope.steps[step.wzOrder]) ? step.wzOrder : $scope.steps.length;
                //adding the scope of directive onto step array
                $scope.steps[wzOrder] = step;
                //if this step is the new first then goTo it
                if ($scope.getEnabledSteps()[0] === step) {
                    //goTo first step
                    $scope.goTo($scope.getEnabledSteps()[0]);
                }
            };

            //called each time step directive is destroyed
            this.removeStep = function (step) {
                var index = $scope.steps.indexOf(step);
                if (index > 0) {
                    $scope.steps.splice(index, 1);
                }
            };

            this.context = $scope.context;

            $scope.getStepNumber = function(step) {
                return stepIdx(step) + 1;
            };

            $scope.goTo = function(step) {
                //if this is the first time the wizard is loading it bi-passes step validation
                if(firstRun){
                    //deselect all steps so you can set fresh below
                    unselectAll();
                    $scope.selectedStep = step;
                    //making sure current step is not undefined
                    if (!angular.isUndefined($scope.currentStep)) {
                        $scope.currentStep = step.wzTitle;
                    }
                    //setting selected step to argument passed into goTo()
                    step.selected = true;
                    //emit event upwards with data on goTo() invoktion
                    $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
                    //setting variable to false so all other step changes must pass validation
                    firstRun = false;
                } else {
                    //createing variables to capture current state that goTo() was invoked from and allow booleans
                    var thisStep;
                    //getting data for step you are transitioning out of
                    if($scope.currentStepNumber() > 0){
                        thisStep = $scope.currentStepNumber() - 1;
                    } else if ($scope.currentStepNumber() === 0){
                        thisStep = 0;
                    }
                    //$log.log('steps[thisStep] Data: ', $scope.getEnabledSteps()[thisStep].canexit);
                    $q.all([canExitStep($scope.getEnabledSteps()[thisStep], step), canEnterStep(step)]).then(function(data) {
                        if(data[0] && data[1]){
                            //deselect all steps so you can set fresh below
                            unselectAll();

                            //$log.log('value for canExit argument: ', $scope.currentStep.canexit);
                            $scope.selectedStep = step;
                            //making sure current step is not undefined
                            if(!angular.isUndefined($scope.currentStep)){
                                $scope.currentStep = step.wzTitle;
                            }
                            //setting selected step to argument passed into goTo()
                            step.selected = true;
                            //emit event upwards with data on goTo() invoktion
                            $scope.$emit('wizard:stepChanged', {step: step, index: stepIdx(step)});
                            //$log.log('current step number: ', $scope.currentStepNumber());
                        }
                    });
                }
            };

            function canEnterStep(step) {
                var defer,
                    canEnter;
                //If no validation function is provided, allow the user to enter the step
                if(step.canenter === undefined){
                    return true;
                }
                //If canenter is a boolean value instead of a function, return the value
                if(typeof step.canenter === 'boolean'){
                    return step.canenter;
                }
                //Check to see if the canenter function is a promise which needs to be returned
                canEnter = step.canenter($scope.context);
                if(angular.isFunction(canEnter.then)){
                    defer = $q.defer();
                    canEnter.then(function(response){
                        defer.resolve(response);
                    });
                    return defer.promise;
                } else {
                    return canEnter === true;
                }
            }

            function canExitStep(step, stepTo) {
                var defer,
                    canExit;
                //Exiting the step should be allowed if no validation function was provided or if the user is moving backwards
                if(typeof(step.canexit) === 'undefined' || $scope.getStepNumber(stepTo) < $scope.currentStepNumber()){
                    return true;
                }
                //If canexit is a boolean value instead of a function, return the value
                if(typeof step.canexit === 'boolean'){
                    return step.canexit;
                }
                //Check to see if the canexit function is a promise which needs to be returned
                canExit = step.canexit($scope.context);
                if(angular.isFunction(canExit.then)){
                    defer = $q.defer();
                    canExit.then(function(response){
                        defer.resolve(response);
                    });
                    return defer.promise;
                } else {
                    return canExit === true;
                }
            }

            $scope.currentStepNumber = function() {
                //retreive current step number
                return stepIdx($scope.selectedStep) + 1;
            };

            $scope.getEnabledSteps = function() {
                return $scope.steps.filter(function(step){
                    return step && step.disabled !== 'true';
                });
            };

            //unSelect All Steps
            function unselectAll() {
                //traverse steps array and set each "selected" property to false
                angular.forEach($scope.getEnabledSteps(), function (step) {
                    step.selected = false;
                });
                //set selectedStep variable to null
                $scope.selectedStep = null;
            }

            //ALL METHODS ATTACHED TO this ARE ACCESSIBLE VIA WizardHandler.wizard().methodName()

            this.currentStepTitle = function(){
                return $scope.selectedStep.wzTitle;
            };

            this.currentStepDescription = function(){
                return $scope.selectedStep.description;
            };

            this.currentStep = function(){
                return $scope.selectedStep;
            };

            this.totalStepCount = function() {
                return $scope.getEnabledSteps().length;
            };

            //Access to enabled steps from outside
            this.getEnabledSteps = function(){
                return $scope.getEnabledSteps();
            };

            //Access to current step number from outside
            this.currentStepNumber = function(){
                return $scope.currentStepNumber();
            };
            //method used for next button within step
            this.next = function(callback) {
                var enabledSteps = $scope.getEnabledSteps();
                //setting variable equal to step  you were on when next() was invoked
                var index = stepIdx($scope.selectedStep);
                //checking to see if callback is a function
                if(angular.isFunction(callback)){
                   if(callback()){
                        if (index === enabledSteps.length - 1) {
                            this.finish();
                        } else {
                            //invoking goTo() with step number next in line
                            $scope.goTo(enabledSteps[index + 1]);
                        }
                   } else {
                        return;
                   }
                }
                if (!callback) {
                    //completed property set on scope which is used to add class/remove class from progress bar
                    $scope.selectedStep.completed = true;
                }
                //checking to see if this is the last step.  If it is next behaves the same as finish()
                if (index === enabledSteps.length - 1) {
                    this.finish();
                } else {
                    //invoking goTo() with step number next in line
                    $scope.goTo(enabledSteps[index + 1]);
                }

            };

            //used to traverse to any step, step number placed as argument
            this.goTo = function(step) {
                //wrapped inside $timeout so newly enabled steps are included.
                $timeout(function() {
                    var enabledSteps = $scope.getEnabledSteps();
                    var stepTo;
                    //checking that step is a Number
                    if (angular.isNumber(step)) {
                        stepTo = enabledSteps[step];
                    } else {
                        //finding the step associated with the title entered as goTo argument
                        stepTo = stepByTitle(step);
                    }
                    //going to step
                    $scope.goTo(stepTo);
                });
            };

            //calls finish() which calls onFinish() which is declared on an attribute and linked to controller via wizard directive.
            this.finish = function() {
                if ($scope.onFinish) {
                    $scope.onFinish();
                }
            };

            this.previous = function() {
                //getting index of current step
                var index = stepIdx($scope.selectedStep);
                //ensuring you aren't trying to go back from the first step
                if (index === 0) {
                    throw new Error("Can't go back. It's already in step 0");
                } else {
                    //go back one step from current step
                    $scope.goTo($scope.getEnabledSteps()[index - 1]);
                }
            };

            //cancel is alias for previous.
            this.cancel = function() {
                //getting index of current step
                var index = stepIdx($scope.selectedStep);
                //ensuring you aren't trying to go back from the first step
                if (index === 0) {
                    throw new Error("Can't go back. It's already in step 0");
                } else {
                    //go back one step from current step
                    $scope.goTo($scope.getEnabledSteps()[0]);
                }
            };

            //reset
            this.reset = function(){
                //traverse steps array and set each "completed" property to false
                angular.forEach($scope.getEnabledSteps(), function (step) {
                    step.completed = false;
                });
                //go to first step
                this.goTo(0);
            };
        }]
    };
});<|endoftext|>


<commit_before>var express = require('express');
var http = require('http');
var path = require('path');
var apiExtensions = require('./apiExtensions');
var moduleLoader = require('./moduleLoader');

var server = module.exports;

server.start = function (config, cb) {
	if (typeof config == 'function') {
		cb = config;
		config = {};
	};

	var api = express();

	api.serverConfig = config;

	// Defaults
	config.loginUrl = config.loginUrl || '/signin';
	config.port = config.port || 8000;
	config.sessionProvider = config.sessionProvider || express.session();
	config.cookieSecret = config.cookieSecret || 'notasecret';
	config.errorHandler = config.errorHandler || function(error, req, res, next) {
		var status = error.status || 500;
		var msg = error.message || 'Unknown error';

		var info = error.data || {};
		info.message = msg;

		res.json(status, info);
	}

	api.configure(function(){
		api.set('port', config.port);

		api.use(express.favicon());
		api.use(express.bodyParser());
		api.use(express.cookieParser(config.cookieSecret));
		api.use(config.sessionProvider);

		if (config.authProvider) {
			api.use(function(req, res, next) {

				if (req.session.user) {
					req.user = req.session.user;
					next();
					return;
				};

				config.authProvider(req, function(err, user) {
					if (err || !user) {
						res.send(401);
						return;
					};

					req.user = user;
					req.session.user = user;
					next();
				});
			});
		};

		(config.middlewares || []).forEach(function(m) { api.use(m); });

		api.use(express.static(path.join(process.env.PWD, 'client-side')));

		// App Extensions
		apiExtensions(api);

		// Load Modules
		moduleLoader.loadModules(api);

		// Errors
		api.use(config.errorHandler);
	});

	http
	.createServer(api)
	.listen(api.get('port'), cb);
}<commit_msg>middlewaresBefore and After auth added<commit_after>var express = require('express');
var http = require('http');
var path = require('path');
var apiExtensions = require('./apiExtensions');
var moduleLoader = require('./moduleLoader');

var server = module.exports;

server.start = function (config, cb) {
	if (typeof config == 'function') {
		cb = config;
		config = {};
	};

	var api = express();

	api.serverConfig = config;

	// Defaults
	config.loginUrl = config.loginUrl || '/signin';
	config.port = config.port || 8000;
	config.sessionProvider = config.sessionProvider || express.session();
	config.cookieSecret = config.cookieSecret || 'notasecret';
	config.errorHandler = config.errorHandler || function(error, req, res, next) {
		var status = error.status || 500;
		var msg = error.message || 'Unknown error';

		var info = error.data || {};
		info.message = msg;

		res.json(status, info);
	}

	api.configure(function(){
		api.set('port', config.port);

		api.use(express.favicon());
		api.use(express.bodyParser());
		api.use(express.cookieParser(config.cookieSecret));
		api.use(config.sessionProvider);

		(config.middlewaresBeforeAuth || []).forEach(function(m) { api.use(m); });

		if (config.authProvider) {
			api.use(function(req, res, next) {

				if (req.session.user) {
					req.user = req.session.user;
					next();
					return;
				};

				config.authProvider(req, function(err, user) {
					if (err || !user) {
						res.send(401);
						return;
					};

					req.user = user;
					req.session.user = user;
					next();
				});
			});
		};

		(config.middlewaresAfterAuth || []).forEach(function(m) { api.use(m); });

		api.use(express.static(path.join(process.env.PWD, 'client-side')));

		// App Extensions
		apiExtensions(api);

		// Load Modules
		moduleLoader.loadModules(api);

		// Errors
		api.use(config.errorHandler);
	});

	http
	.createServer(api)
	.listen(api.get('port'), cb);
}<|endoftext|>


<commit_before>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * The Sprite object is the base for all textured objects that are rendered to the screen
 *
 * @class Sprite
 * @extends DisplayObjectContainer
 * @constructor
 * @param texture {Texture} The texture for this sprite
 *
 * A sprite can be created directly from an image like this :
 * var sprite = new PIXI.Sprite.fromImage('assets/image.png');
 * yourStage.addChild(sprite);
 * then obviously don't forget to add it to the stage you have already created
 */
PIXI.Sprite = function(texture)
{
    PIXI.DisplayObjectContainer.call( this );

    /**
     * The anchor sets the origin point of the texture.
     * The default is 0,0 this means the texture's origin is the top left
     * Setting than anchor to 0.5,0.5 means the textures origin is centred
     * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner
     *
     * @property anchor
     * @type Point
     */
    this.anchor = new PIXI.Point();

    /**
     * The texture that the sprite is using
     *
     * @property texture
     * @type Texture
     */
    this.texture = texture;

    /**
     * The width of the sprite (this is initially set by the texture)
     *
     * @property _width
     * @type Number
     * @private
     */
    this._width = 0;

    /**
     * The height of the sprite (this is initially set by the texture)
     *
     * @property _height
     * @type Number
     * @private
     */
    this._height = 0;

    /**
     * The tint applied to the sprite. This is a hex value
     *
     * @property tint
     * @type Number
     * @default 0xFFFFFF
     */
    this.tint = 0xFFFFFF;// * Math.random();

    /**
     * The blend mode to be applied to the sprite
     *
     * @property blendMode
     * @type Number
     * @default PIXI.blendModes.NORMAL;
     */
    this.blendMode = PIXI.blendModes.NORMAL;

    if(texture.baseTexture.hasLoaded)
    {
        this.onTextureUpdate();
    }
    else
    {
        this.onTextureUpdateBind = this.onTextureUpdate.bind(this);
        this.texture.addEventListener( 'update', this.onTextureUpdateBind );
    }

    this.renderable = true;
};

// constructor
PIXI.Sprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
PIXI.Sprite.prototype.constructor = PIXI.Sprite;

/**
 * The width of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property width
 * @type Number
 */
Object.defineProperty(PIXI.Sprite.prototype, 'width', {
    get: function() {
        return this.scale.x * this.texture.frame.width;
    },
    set: function(value) {
        this.scale.x = value / this.texture.frame.width;
        this._width = value;
    }
});

/**
 * The height of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property height
 * @type Number
 */
Object.defineProperty(PIXI.Sprite.prototype, 'height', {
    get: function() {
        return  this.scale.y * this.texture.frame.height;
    },
    set: function(value) {
        this.scale.y = value / this.texture.frame.height;
        this._height = value;
    }
});

/**
 * Sets the texture of the sprite
 *
 * @method setTexture
 * @param texture {Texture} The PIXI texture that is displayed by the sprite
 */
PIXI.Sprite.prototype.setTexture = function(texture)
{
    // stop current texture;
    if(this.texture.baseTexture !== texture.baseTexture)
    {
        this.textureChange = true;
        this.texture = texture;
    }
    else
    {
        this.texture = texture;
    }

    this.cachedTint = 0xFFFFFF;
};

/**
 * When the texture is updated, this event will fire to update the scale and frame
 *
 * @method onTextureUpdate
 * @param event
 * @private
 */
PIXI.Sprite.prototype.onTextureUpdate = function()
{
    // so if _width is 0 then width was not set..
    if(this._width)this.scale.x = this._width / this.texture.frame.width;
    if(this._height)this.scale.y = this._height / this.texture.frame.height;

    //this.updateFrame = true;
};

/**
* Returns the framing rectangle of the sprite as a PIXI.Rectangle object
*
* @method getBounds
* @param matrix {Matrix} the transformation matrix of the sprite
* @return {Rectangle} the framing rectangle
*/
PIXI.Sprite.prototype.getBounds = function(matrix)
{

    var width = this.texture.frame.width;
    var height = this.texture.frame.height;

    var w0 = width * (1-this.anchor.x);
    var w1 = width * -this.anchor.x;

    var h0 = height * (1-this.anchor.y);
    var h1 = height * -this.anchor.y;

    var worldTransform = matrix || this.worldTransform ;

    var a = worldTransform.a;
    var b = worldTransform.c;
    var c = worldTransform.b;
    var d = worldTransform.d;
    var tx = worldTransform.tx;
    var ty = worldTransform.ty;

    var x1 = a * w1 + c * h1 + tx;
    var y1 = d * h1 + b * w1 + ty;

    var x2 = a * w0 + c * h1 + tx;
    var y2 = d * h1 + b * w0 + ty;

    var x3 = a * w0 + c * h0 + tx;
    var y3 = d * h0 + b * w0 + ty;

    var x4 =  a * w1 + c * h0 + tx;
    var y4 =  d * h0 + b * w1 + ty;

    var maxX = -Infinity;
    var maxY = -Infinity;

    var minX = Infinity;
    var minY = Infinity;

    minX = x1 < minX ? x1 : minX;
    minX = x2 < minX ? x2 : minX;
    minX = x3 < minX ? x3 : minX;
    minX = x4 < minX ? x4 : minX;

    minY = y1 < minY ? y1 : minY;
    minY = y2 < minY ? y2 : minY;
    minY = y3 < minY ? y3 : minY;
    minY = y4 < minY ? y4 : minY;

    maxX = x1 > maxX ? x1 : maxX;
    maxX = x2 > maxX ? x2 : maxX;
    maxX = x3 > maxX ? x3 : maxX;
    maxX = x4 > maxX ? x4 : maxX;

    maxY = y1 > maxY ? y1 : maxY;
    maxY = y2 > maxY ? y2 : maxY;
    maxY = y3 > maxY ? y3 : maxY;
    maxY = y4 > maxY ? y4 : maxY;

    var bounds = this._bounds;

    bounds.x = minX;
    bounds.width = maxX - minX;

    bounds.y = minY;
    bounds.height = maxY - minY;

    // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
    this._currentBounds = bounds;

    return bounds;
};

/**
* Renders the object using the WebGL renderer
*
* @method _renderWebGL
* @param renderSession {RenderSession}
* @private
*/
PIXI.Sprite.prototype._renderWebGL = function(renderSession)
{
    // if the sprite is not visible or the alpha is 0 then no need to render this element
    if(!this.visible || this.alpha <= 0)return;

    var i,j;

    // do a quick check to see if this element has a mask or a filter.
    if(this._mask || this._filters)
    {
        var spriteBatch =  renderSession.spriteBatch;

        // push filter first as we need to ensure the stencil buffer is correct for any masking
        if(this._filters)
        {
            spriteBatch.flush();
            renderSession.filterManager.pushFilter(this._filterBlock);
        }

        if(this._mask)
        {
            spriteBatch.stop();
            renderSession.maskManager.pushMask(this.mask, renderSession);
            spriteBatch.start();
        }

        // add this sprite to the batch
        spriteBatch.render(this);

        // now loop through the children and make sure they get rendered
        for(i=0,j=this.children.length; i<j; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }

        // time to stop the sprite batch as either a mask element or a filter draw will happen next
        spriteBatch.stop();

        if(this._mask)renderSession.maskManager.popMask(this._mask, renderSession);
        if(this._filters)renderSession.filterManager.popFilter();

        spriteBatch.start();
    }
    else
    {
        renderSession.spriteBatch.render(this);

        // simple render children!
        for(i=0,j=this.children.length; i<j; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }
    }

    //TODO check culling
};

/**
* Renders the object using the Canvas renderer
*
* @method _renderCanvas
* @param renderSession {RenderSession}
* @private
*/
PIXI.Sprite.prototype._renderCanvas = function(renderSession)
{
    // If the sprite is not visible or the alpha is 0 then no need to render this element
    if (this.visible === false || this.alpha === 0) return;

    if (this.blendMode !== renderSession.currentBlendMode)
    {
        renderSession.currentBlendMode = this.blendMode;
        renderSession.context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
    }

    if (this._mask)
    {
        renderSession.maskManager.pushMask(this._mask, renderSession.context);
    }

    //  Ignore null sources
    if (this.texture.valid)
    {
        renderSession.context.globalAlpha = this.worldAlpha;

        //  Allow for pixel rounding
        if (renderSession.roundPixels)
        {
            renderSession.context.setTransform(
                this.worldTransform.a,
                this.worldTransform.c,
                this.worldTransform.b,
                this.worldTransform.d,
                this.worldTransform.tx | 0,
                this.worldTransform.ty | 0);
        }
        else
        {
            renderSession.context.setTransform(
                this.worldTransform.a,
                this.worldTransform.c,
                this.worldTransform.b,
                this.worldTransform.d,
                this.worldTransform.tx,
                this.worldTransform.ty);
        }

        //  If smoothingEnabled is supported and we need to change the smoothing property for this texture
        if (renderSession.smoothProperty && renderSession.scaleMode !== this.texture.baseTexture.scaleMode)
        {
            renderSession.scaleMode = this.texture.baseTexture.scaleMode;
            renderSession.context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR);
        }

        //  If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions
        var dx = (this.texture.trim) ? this.texture.trim.x - this.anchor.x * this.texture.trim.width : this.anchor.x * -this.texture.frame.width;
        var dy = (this.texture.trim) ? this.texture.trim.y - this.anchor.y * this.texture.trim.height : this.anchor.y * -this.texture.frame.height;

        if (this.tint !== 0xFFFFFF)
        {
            if (this.cachedTint !== this.tint)
            {
                this.cachedTint = this.tint;

                //  TODO clean up caching - how to clean up the caches?
                this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
            }

            renderSession.context.drawImage(
                                this.tintedTexture,
                                0,
                                0,
                                this.texture.crop.width,
                                this.texture.crop.height,
                                dx,
                                dy,
                                this.texture.crop.width,
                                this.texture.crop.height);
        }
        else
        {
            renderSession.context.drawImage(
                                this.texture.baseTexture.source,
                                this.texture.crop.x,
                                this.texture.crop.y,
                                this.texture.crop.width,
                                this.texture.crop.height,
                                dx,
                                dy,
                                this.texture.crop.width,
                                this.texture.crop.height);
        }
    }

    // OVERWRITE
    for (var i = 0, j = this.children.length; i < j; i++)
    {
        this.children[i]._renderCanvas(renderSession);
    }

    if (this._mask)
    {
        renderSession.maskManager.popMask(renderSession.context);
    }
};

// some helper functions..

/**
 *
 * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
 * The frame ids are created when a Texture packer file has been loaded
 *
 * @method fromFrame
 * @static
 * @param frameId {String} The frame Id of the texture in the cache
 * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId
 */
PIXI.Sprite.fromFrame = function(frameId)
{
    var texture = PIXI.TextureCache[frameId];
    if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this);
    return new PIXI.Sprite(texture);
};

/**
 *
 * Helper function that creates a sprite that will contain a texture based on an image url
 * If the image is not in the texture cache it will be loaded
 *
 * @method fromImage
 * @static
 * @param imageId {String} The image url of the texture
 * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id
 */
PIXI.Sprite.fromImage = function(imageId, crossorigin, scaleMode)
{
    var texture = PIXI.Texture.fromImage(imageId, crossorigin, scaleMode);
    return new PIXI.Sprite(texture);
};
<commit_msg>`this.textureChange` is no longer used in any object, anywhere within Pixi, so this check now appears to be redundant - and is changing the internal class shape of Pixi.Sprite as a result (adding a property that doesn't exist).<commit_after>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 */

/**
 * The Sprite object is the base for all textured objects that are rendered to the screen
 *
 * @class Sprite
 * @extends DisplayObjectContainer
 * @constructor
 * @param texture {Texture} The texture for this sprite
 *
 * A sprite can be created directly from an image like this :
 * var sprite = new PIXI.Sprite.fromImage('assets/image.png');
 * yourStage.addChild(sprite);
 * then obviously don't forget to add it to the stage you have already created
 */
PIXI.Sprite = function(texture)
{
    PIXI.DisplayObjectContainer.call( this );

    /**
     * The anchor sets the origin point of the texture.
     * The default is 0,0 this means the texture's origin is the top left
     * Setting than anchor to 0.5,0.5 means the textures origin is centred
     * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner
     *
     * @property anchor
     * @type Point
     */
    this.anchor = new PIXI.Point();

    /**
     * The texture that the sprite is using
     *
     * @property texture
     * @type Texture
     */
    this.texture = texture;

    /**
     * The width of the sprite (this is initially set by the texture)
     *
     * @property _width
     * @type Number
     * @private
     */
    this._width = 0;

    /**
     * The height of the sprite (this is initially set by the texture)
     *
     * @property _height
     * @type Number
     * @private
     */
    this._height = 0;

    /**
     * The tint applied to the sprite. This is a hex value
     *
     * @property tint
     * @type Number
     * @default 0xFFFFFF
     */
    this.tint = 0xFFFFFF;// * Math.random();

    /**
     * The blend mode to be applied to the sprite
     *
     * @property blendMode
     * @type Number
     * @default PIXI.blendModes.NORMAL;
     */
    this.blendMode = PIXI.blendModes.NORMAL;

    if(texture.baseTexture.hasLoaded)
    {
        this.onTextureUpdate();
    }
    else
    {
        this.onTextureUpdateBind = this.onTextureUpdate.bind(this);
        this.texture.addEventListener( 'update', this.onTextureUpdateBind );
    }

    this.renderable = true;
};

// constructor
PIXI.Sprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
PIXI.Sprite.prototype.constructor = PIXI.Sprite;

/**
 * The width of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property width
 * @type Number
 */
Object.defineProperty(PIXI.Sprite.prototype, 'width', {
    get: function() {
        return this.scale.x * this.texture.frame.width;
    },
    set: function(value) {
        this.scale.x = value / this.texture.frame.width;
        this._width = value;
    }
});

/**
 * The height of the sprite, setting this will actually modify the scale to achieve the value set
 *
 * @property height
 * @type Number
 */
Object.defineProperty(PIXI.Sprite.prototype, 'height', {
    get: function() {
        return  this.scale.y * this.texture.frame.height;
    },
    set: function(value) {
        this.scale.y = value / this.texture.frame.height;
        this._height = value;
    }
});

/**
 * Sets the texture of the sprite
 *
 * @method setTexture
 * @param texture {Texture} The PIXI texture that is displayed by the sprite
 */
PIXI.Sprite.prototype.setTexture = function(texture)
{
    this.texture = texture;
    this.cachedTint = 0xFFFFFF;
};

/**
 * When the texture is updated, this event will fire to update the scale and frame
 *
 * @method onTextureUpdate
 * @param event
 * @private
 */
PIXI.Sprite.prototype.onTextureUpdate = function()
{
    // so if _width is 0 then width was not set..
    if(this._width)this.scale.x = this._width / this.texture.frame.width;
    if(this._height)this.scale.y = this._height / this.texture.frame.height;

    //this.updateFrame = true;
};

/**
* Returns the framing rectangle of the sprite as a PIXI.Rectangle object
*
* @method getBounds
* @param matrix {Matrix} the transformation matrix of the sprite
* @return {Rectangle} the framing rectangle
*/
PIXI.Sprite.prototype.getBounds = function(matrix)
{

    var width = this.texture.frame.width;
    var height = this.texture.frame.height;

    var w0 = width * (1-this.anchor.x);
    var w1 = width * -this.anchor.x;

    var h0 = height * (1-this.anchor.y);
    var h1 = height * -this.anchor.y;

    var worldTransform = matrix || this.worldTransform ;

    var a = worldTransform.a;
    var b = worldTransform.c;
    var c = worldTransform.b;
    var d = worldTransform.d;
    var tx = worldTransform.tx;
    var ty = worldTransform.ty;

    var x1 = a * w1 + c * h1 + tx;
    var y1 = d * h1 + b * w1 + ty;

    var x2 = a * w0 + c * h1 + tx;
    var y2 = d * h1 + b * w0 + ty;

    var x3 = a * w0 + c * h0 + tx;
    var y3 = d * h0 + b * w0 + ty;

    var x4 =  a * w1 + c * h0 + tx;
    var y4 =  d * h0 + b * w1 + ty;

    var maxX = -Infinity;
    var maxY = -Infinity;

    var minX = Infinity;
    var minY = Infinity;

    minX = x1 < minX ? x1 : minX;
    minX = x2 < minX ? x2 : minX;
    minX = x3 < minX ? x3 : minX;
    minX = x4 < minX ? x4 : minX;

    minY = y1 < minY ? y1 : minY;
    minY = y2 < minY ? y2 : minY;
    minY = y3 < minY ? y3 : minY;
    minY = y4 < minY ? y4 : minY;

    maxX = x1 > maxX ? x1 : maxX;
    maxX = x2 > maxX ? x2 : maxX;
    maxX = x3 > maxX ? x3 : maxX;
    maxX = x4 > maxX ? x4 : maxX;

    maxY = y1 > maxY ? y1 : maxY;
    maxY = y2 > maxY ? y2 : maxY;
    maxY = y3 > maxY ? y3 : maxY;
    maxY = y4 > maxY ? y4 : maxY;

    var bounds = this._bounds;

    bounds.x = minX;
    bounds.width = maxX - minX;

    bounds.y = minY;
    bounds.height = maxY - minY;

    // store a reference so that if this function gets called again in the render cycle we do not have to recalculate
    this._currentBounds = bounds;

    return bounds;
};

/**
* Renders the object using the WebGL renderer
*
* @method _renderWebGL
* @param renderSession {RenderSession}
* @private
*/
PIXI.Sprite.prototype._renderWebGL = function(renderSession)
{
    // if the sprite is not visible or the alpha is 0 then no need to render this element
    if(!this.visible || this.alpha <= 0)return;

    var i,j;

    // do a quick check to see if this element has a mask or a filter.
    if(this._mask || this._filters)
    {
        var spriteBatch =  renderSession.spriteBatch;

        // push filter first as we need to ensure the stencil buffer is correct for any masking
        if(this._filters)
        {
            spriteBatch.flush();
            renderSession.filterManager.pushFilter(this._filterBlock);
        }

        if(this._mask)
        {
            spriteBatch.stop();
            renderSession.maskManager.pushMask(this.mask, renderSession);
            spriteBatch.start();
        }

        // add this sprite to the batch
        spriteBatch.render(this);

        // now loop through the children and make sure they get rendered
        for(i=0,j=this.children.length; i<j; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }

        // time to stop the sprite batch as either a mask element or a filter draw will happen next
        spriteBatch.stop();

        if(this._mask)renderSession.maskManager.popMask(this._mask, renderSession);
        if(this._filters)renderSession.filterManager.popFilter();

        spriteBatch.start();
    }
    else
    {
        renderSession.spriteBatch.render(this);

        // simple render children!
        for(i=0,j=this.children.length; i<j; i++)
        {
            this.children[i]._renderWebGL(renderSession);
        }
    }

    //TODO check culling
};

/**
* Renders the object using the Canvas renderer
*
* @method _renderCanvas
* @param renderSession {RenderSession}
* @private
*/
PIXI.Sprite.prototype._renderCanvas = function(renderSession)
{
    // If the sprite is not visible or the alpha is 0 then no need to render this element
    if (this.visible === false || this.alpha === 0) return;

    if (this.blendMode !== renderSession.currentBlendMode)
    {
        renderSession.currentBlendMode = this.blendMode;
        renderSession.context.globalCompositeOperation = PIXI.blendModesCanvas[renderSession.currentBlendMode];
    }

    if (this._mask)
    {
        renderSession.maskManager.pushMask(this._mask, renderSession.context);
    }

    //  Ignore null sources
    if (this.texture.valid)
    {
        renderSession.context.globalAlpha = this.worldAlpha;

        //  Allow for pixel rounding
        if (renderSession.roundPixels)
        {
            renderSession.context.setTransform(
                this.worldTransform.a,
                this.worldTransform.c,
                this.worldTransform.b,
                this.worldTransform.d,
                this.worldTransform.tx | 0,
                this.worldTransform.ty | 0);
        }
        else
        {
            renderSession.context.setTransform(
                this.worldTransform.a,
                this.worldTransform.c,
                this.worldTransform.b,
                this.worldTransform.d,
                this.worldTransform.tx,
                this.worldTransform.ty);
        }

        //  If smoothingEnabled is supported and we need to change the smoothing property for this texture
        if (renderSession.smoothProperty && renderSession.scaleMode !== this.texture.baseTexture.scaleMode)
        {
            renderSession.scaleMode = this.texture.baseTexture.scaleMode;
            renderSession.context[renderSession.smoothProperty] = (renderSession.scaleMode === PIXI.scaleModes.LINEAR);
        }

        //  If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions
        var dx = (this.texture.trim) ? this.texture.trim.x - this.anchor.x * this.texture.trim.width : this.anchor.x * -this.texture.frame.width;
        var dy = (this.texture.trim) ? this.texture.trim.y - this.anchor.y * this.texture.trim.height : this.anchor.y * -this.texture.frame.height;

        if (this.tint !== 0xFFFFFF)
        {
            if (this.cachedTint !== this.tint)
            {
                this.cachedTint = this.tint;

                //  TODO clean up caching - how to clean up the caches?
                this.tintedTexture = PIXI.CanvasTinter.getTintedTexture(this, this.tint);
            }

            renderSession.context.drawImage(
                                this.tintedTexture,
                                0,
                                0,
                                this.texture.crop.width,
                                this.texture.crop.height,
                                dx,
                                dy,
                                this.texture.crop.width,
                                this.texture.crop.height);
        }
        else
        {
            renderSession.context.drawImage(
                                this.texture.baseTexture.source,
                                this.texture.crop.x,
                                this.texture.crop.y,
                                this.texture.crop.width,
                                this.texture.crop.height,
                                dx,
                                dy,
                                this.texture.crop.width,
                                this.texture.crop.height);
        }
    }

    // OVERWRITE
    for (var i = 0, j = this.children.length; i < j; i++)
    {
        this.children[i]._renderCanvas(renderSession);
    }

    if (this._mask)
    {
        renderSession.maskManager.popMask(renderSession.context);
    }
};

// some helper functions..

/**
 *
 * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
 * The frame ids are created when a Texture packer file has been loaded
 *
 * @method fromFrame
 * @static
 * @param frameId {String} The frame Id of the texture in the cache
 * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId
 */
PIXI.Sprite.fromFrame = function(frameId)
{
    var texture = PIXI.TextureCache[frameId];
    if(!texture) throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this);
    return new PIXI.Sprite(texture);
};

/**
 *
 * Helper function that creates a sprite that will contain a texture based on an image url
 * If the image is not in the texture cache it will be loaded
 *
 * @method fromImage
 * @static
 * @param imageId {String} The image url of the texture
 * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id
 */
PIXI.Sprite.fromImage = function(imageId, crossorigin, scaleMode)
{
    var texture = PIXI.Texture.fromImage(imageId, crossorigin, scaleMode);
    return new PIXI.Sprite(texture);
};
<|endoftext|>


<commit_before>/** @ignore */
const {plgctor} = require("./util/promise-transform-stream");

/**
 * Scramjet main exports expose all the stream classes and a number of methods.
 *
 * All scramjet streams allow writing, reading or transform modes - currently
 * exclusively (meaning you can't have two at once). Any of the scramjet streams
 * can be constructed with the following options passed to mimic node.js standard streams:
 *
 * * `async promiseTransform(chunk)` - transform method that resolves with a single output chunk
 * * `async promiseWrite(chunk)` - write method that that resolves when chunk is written
 * * `async promiseRead(count)` - read method that resolves with an array of chunks when called
 *
 * See {@link https://nodejs.org/api/stream.html#stream_api_for_stream_implementers node.js API for stream implementers for details}
 *
 * The object exposes the following classes:
 *
 * * `DataStream` {@see DataStream} - the basic object stream of any type
 * * `StringStream` {@see StringStream} - a stream of strings
 * * `BufferStream` {@see BufferStream} - a stream of buffers
 * * `MultiStream` {@see MultiStream} - a group of streams
 * * `NumberStream` {@see NumberStream} - a stream of numbers
 * * `WindowStream` {@see WindowStream} - a stream of windows of objects
 *
 * The general concept of Scramjet streams is facilitating node's TransformStream mechanism so that you don't need
 * to create a number of streams and create the pipeline, but use the concept of chaining instead. When you call `parse`
 * method for instance, scramjet creates a new stream, pipes it to the callee and forwards errors.
 *
 * What's worth mentioning - scramjet tries to limit the number of created transform streams and pushes the transforms
 * one after another into the same stream class therefore a code `stream.map(transform1).map(transform2).filter(transform3)`
 * will only operate on a single transform stream that evaluates all three transforms one after another.
 *
 * @exports scramjet
 * @module scramjet
 */
module.exports = {
    /**
     * Creates a DataStream that's piped from the passed readable.
     *
     * @memberof module:scramjet
     * @param {Array|Iterable<any>|AsyncGeneratorFunction|GeneratorFunction|AsyncFunction|Function|string|Readable} input argument to be turned into new stream
     * @param {DataStreamOptions|Writable} [options={}] options for creation of a new stream or the target stream
     * @param {any[]} ...args additional arguments for the stream - will be passed to the function or generator
     * @return {DataStream}
     */
    from(...args) {
        return this.DataStream.from(...args);
    },

    /**
     * Creates a DataStream from an Array
     *
     * @memberof module:scramjet
     * @param  {Array} array list of chunks
     * @param {DataStreamOptions} [options={}] the read stream options
     * @return {DataStream}
     */
    fromArray(...args) {
        return this.DataStream.fromArray(...args);
    },

    get ScramjetOptions() { return require("./util/options"); },

    /**
     * Creates a safe wrapper for scramjet transform module. See [Modules documentation](modules.md) for more info.
     *
     * @param {UseCallback} transform
     * @param {CreateModuleOptions} [options={}]
     * @param  {any[]} ...initialArgs
     * @return {Function} a scramjet module function
     */
    createTransformModule(transform, {StreamClass = module.exports.DataStream} = {}, ...initialArgs) {
        return function (stream, ...extraArgs) {
            return StreamClass.from(stream)
                .use(transform, ...initialArgs, ...extraArgs);
        };
    },

    /**
     * Creates a safe wrapper for scramjet read module. See [Modules documentation](modules.md) for more info.
     *
     * @param {Array|Iterable<any>|AsyncGeneratorFunction|GeneratorFunction|AsyncFunction|Function|string|Readable} anything
     * @param {CreateModuleOptions} [options={}]
     * @param  {any[]} ...initialArgs
     * @return {Function} a scramjet module function
     */
    createReadModule(anything, {StreamClass = module.exports.DataStream} = {}, ...initialArgs) {
        StreamClass = StreamClass || this.DataStream;

        return (...extraArgs) => {
            return StreamClass.from(anything, ...initialArgs, ...extraArgs);
        };
    },

    /**
     * Options for createModule
     *
     * @typedef {object} CreateModuleOptions
     * @memberof module:scramjet~
     * @prop {DataStream} StreamClass defines what class should the module assume
     */

    get errors()  { return require("./util/stream-errors"); },

    /**
     * @ignore
     * @see {@link buffer-stream.md}
     */
    get BufferStream() { return require("./buffer-stream"); },

    /**
     * @ignore
     * @see {@link data-stream.md}
     */
    get DataStream() { return require("./data-stream"); },

    /**
     * @ignore
     * @see {@link multi-stream.md}
     */
    get MultiStream() { return require("./multi-stream"); },

    /**
     * @ignore
     * @see {@link string-stream.md}
     */
    get StringStream() { return require("./string-stream"); },

    /**
     * Provides a lazy-load accessor to PromiseTransformStream - the base class of scramjet streams
     *
     * @ignore
     */
    get PromiseTransformStream() { return require("./util/promise-transform-stream").PromiseTransformStream; },

    /**
     * Definition of a single mixin for a specific Scramjet class. Should contain any number of stream methods.
     *
     * @typedef {object} StreamMixin
     * @memberof module:scramjet~
     * @property {Function} constructor optional constructor that will be called in the stream constructor (this has to be an own property!)
     */

    /**
     * Definition of a plugin in Scramjet
     *
     * @typedef {object} ScramjetPlugin
     * @memberof module:scramjet~
     * @internal
     * @property {StreamMixin} BufferStream definition of constructor and properties for the BufferStream prototype.
     * @property {StreamMixin} DataStream definition of constructor and properties for the DataStream prototype.
     * @property {StreamMixin} MultiStream definition of constructor and properties for the MultiStream prototype.
     * @property {StreamMixin} StringStream definition of constructor and properties for the StringStream prototype.
     */

    /**
     * Plugs in methods for any of the classes
     *
     * @static
     * @memberof module:scramjet
     * @param  {ScramjetPlugin} mixin the plugin object
     * @return {ScramjetPlugin}
     *
     * @test test/methods/scramjet-plugin.js
     */
    plugin(mixins) {
        for (const key of Object.keys(mixins)) {
            if (key in this) {
                const Mixin = mixins[key];
                const Stream = this[key];
                if (Object.prototype.hasOwnProperty.call(Mixin, "constructor") && Stream[plgctor]) {
                    Stream[plgctor].ctors.push(Mixin.constructor);
                    delete Mixin.constructor;
                }
                Object.getOwnPropertyNames(Mixin).forEach(
                    (prop) => Object.defineProperty(Stream.prototype, prop, Object.getOwnPropertyDescriptor(Mixin, prop))
                );
            } else {
                this[key] = mixins[key];
            }
        }
        return this;
    },

    /**
     * Gets an API version (this may be important for future use)
     *
     * @static
     * @memberof module:scramjet
     * @param {number} version The required version (currently only: 1)
     * @return {ScramjetPlugin}
     */
    API(version) {
        if (version === 1) {
            return module.exports;
        }
    }
};

// ----- Externals documentation -----

/**
 * Asynchronous Generator.
 *
 * @ignore
 * @external AsyncGeneratorFunction
 * @see https://github.com/tc39/proposal-async-iteration#async-generator-functions
 */

/**
 * Generator function (`function* ()`).
 *
 * @ignore
 * @external GeneratorFunction
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction
 */

/**
 * Simple Node.js Passthrough stream.
 *
 * @ignore
 * @external stream.PassThrough
 * @see https://nodejs.org/api/stream.html#stream_class_stream_passthrough
 */
<commit_msg>Fix for scramjetorg/scramjet#103.<commit_after>/** @ignore */
const {plgctor} = require("./util/promise-transform-stream");

const registered_plugins = [];

/**
 * Scramjet main exports expose all the stream classes and a number of methods.
 *
 * All scramjet streams allow writing, reading or transform modes - currently
 * exclusively (meaning you can't have two at once). Any of the scramjet streams
 * can be constructed with the following options passed to mimic node.js standard streams:
 *
 * * `async promiseTransform(chunk)` - transform method that resolves with a single output chunk
 * * `async promiseWrite(chunk)` - write method that that resolves when chunk is written
 * * `async promiseRead(count)` - read method that resolves with an array of chunks when called
 *
 * See {@link https://nodejs.org/api/stream.html#stream_api_for_stream_implementers node.js API for stream implementers for details}
 *
 * The object exposes the following classes:
 *
 * * `DataStream` {@see DataStream} - the basic object stream of any type
 * * `StringStream` {@see StringStream} - a stream of strings
 * * `BufferStream` {@see BufferStream} - a stream of buffers
 * * `MultiStream` {@see MultiStream} - a group of streams
 * * `NumberStream` {@see NumberStream} - a stream of numbers
 * * `WindowStream` {@see WindowStream} - a stream of windows of objects
 *
 * The general concept of Scramjet streams is facilitating node's TransformStream mechanism so that you don't need
 * to create a number of streams and create the pipeline, but use the concept of chaining instead. When you call `parse`
 * method for instance, scramjet creates a new stream, pipes it to the callee and forwards errors.
 *
 * What's worth mentioning - scramjet tries to limit the number of created transform streams and pushes the transforms
 * one after another into the same stream class therefore a code `stream.map(transform1).map(transform2).filter(transform3)`
 * will only operate on a single transform stream that evaluates all three transforms one after another.
 *
 * @exports scramjet
 * @module scramjet
 */
module.exports = {
    /**
     * Creates a DataStream that's piped from the passed readable.
     *
     * @memberof module:scramjet
     * @param {Array|Iterable<any>|AsyncGeneratorFunction|GeneratorFunction|AsyncFunction|Function|string|Readable} input argument to be turned into new stream
     * @param {DataStreamOptions|Writable} [options={}] options for creation of a new stream or the target stream
     * @param {any[]} ...args additional arguments for the stream - will be passed to the function or generator
     * @return {DataStream}
     */
    from(...args) {
        return this.DataStream.from(...args);
    },

    /**
     * Creates a DataStream from an Array
     *
     * @memberof module:scramjet
     * @param  {Array} array list of chunks
     * @param {DataStreamOptions} [options={}] the read stream options
     * @return {DataStream}
     */
    fromArray(...args) {
        return this.DataStream.fromArray(...args);
    },

    get ScramjetOptions() { return require("./util/options"); },

    /**
     * Creates a safe wrapper for scramjet transform module. See [Modules documentation](modules.md) for more info.
     *
     * @param {UseCallback} transform
     * @param {CreateModuleOptions} [options={}]
     * @param  {any[]} ...initialArgs
     * @return {Function} a scramjet module function
     */
    createTransformModule(transform, {StreamClass = module.exports.DataStream} = {}, ...initialArgs) {
        return function (stream, ...extraArgs) {
            return StreamClass.from(stream)
                .use(transform, ...initialArgs, ...extraArgs);
        };
    },

    /**
     * Creates a safe wrapper for scramjet read module. See [Modules documentation](modules.md) for more info.
     *
     * @param {Array|Iterable<any>|AsyncGeneratorFunction|GeneratorFunction|AsyncFunction|Function|string|Readable} anything
     * @param {CreateModuleOptions} [options={}]
     * @param  {any[]} ...initialArgs
     * @return {Function} a scramjet module function
     */
    createReadModule(anything, {StreamClass = module.exports.DataStream} = {}, ...initialArgs) {
        StreamClass = StreamClass || this.DataStream;

        return (...extraArgs) => {
            return StreamClass.from(anything, ...initialArgs, ...extraArgs);
        };
    },

    /**
     * Options for createModule
     *
     * @typedef {object} CreateModuleOptions
     * @memberof module:scramjet~
     * @prop {DataStream} StreamClass defines what class should the module assume
     */

    get errors()  { return require("./util/stream-errors"); },

    /**
     * @ignore
     * @see {@link buffer-stream.md}
     */
    get BufferStream() { return require("./buffer-stream"); },

    /**
     * @ignore
     * @see {@link data-stream.md}
     */
    get DataStream() { return require("./data-stream"); },

    /**
     * @ignore
     * @see {@link multi-stream.md}
     */
    get MultiStream() { return require("./multi-stream"); },

    /**
     * @ignore
     * @see {@link string-stream.md}
     */
    get StringStream() { return require("./string-stream"); },

    /**
     * Provides a lazy-load accessor to PromiseTransformStream - the base class of scramjet streams
     *
     * @ignore
     */
    get PromiseTransformStream() { return require("./util/promise-transform-stream").PromiseTransformStream; },

    /**
     * Definition of a single mixin for a specific Scramjet class. Should contain any number of stream methods.
     *
     * @typedef {object} StreamMixin
     * @memberof module:scramjet~
     * @property {Function} constructor optional constructor that will be called in the stream constructor (this has to be an own property!)
     */

    /**
     * Definition of a plugin in Scramjet
     *
     * @typedef {object} ScramjetPlugin
     * @memberof module:scramjet~
     * @internal
     * @property {StreamMixin} BufferStream definition of constructor and properties for the BufferStream prototype.
     * @property {StreamMixin} DataStream definition of constructor and properties for the DataStream prototype.
     * @property {StreamMixin} MultiStream definition of constructor and properties for the MultiStream prototype.
     * @property {StreamMixin} StringStream definition of constructor and properties for the StringStream prototype.
     */

    /**
     * Plugs in methods for any of the classes
     *
     * @static
     * @memberof module:scramjet
     * @param  {ScramjetPlugin} mixin the plugin object
     * @return {ScramjetPlugin}
     *
     * @test test/methods/scramjet-plugin.js
     */
    plugin(mixins) {
        if (registered_plugins.includes(mixins)) {
            console.log({stack: new Error().stack});
            return this;
        }
        registered_plugins.push(mixins);

        for (const key of Object.keys(mixins)) {
            if (key in this) {
                const Mixin = mixins[key];
                if (Mixin.prototype) continue; // duplicate call

                const Stream = this[key];
                if (Object.prototype.hasOwnProperty.call(Mixin, "constructor") && Stream[plgctor]) {
                    Stream[plgctor].ctors.push(Mixin.constructor);
                    delete Mixin.constructor;
                }
                for (let prop of Object.getOwnPropertyNames(Mixin)) {
                    Object.defineProperty(Stream.prototype, prop, Object.getOwnPropertyDescriptor(Mixin, prop));
                }
            } else {
                this[key] = mixins[key];
            }
        }
        return this;
    },

    /**
     * Gets an API version (this may be important for future use)
     *
     * @static
     * @memberof module:scramjet
     * @param {number} version The required version (currently only: 1)
     * @return {ScramjetPlugin}
     */
    API(version) {
        if (version === 1) {
            return module.exports;
        }
    }
};

// ----- Externals documentation -----

/**
 * Asynchronous Generator.
 *
 * @ignore
 * @external AsyncGeneratorFunction
 * @see https://github.com/tc39/proposal-async-iteration#async-generator-functions
 */

/**
 * Generator function (`function* ()`).
 *
 * @ignore
 * @external GeneratorFunction
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction
 */

/**
 * Simple Node.js Passthrough stream.
 *
 * @ignore
 * @external stream.PassThrough
 * @see https://nodejs.org/api/stream.html#stream_class_stream_passthrough
 */
<|endoftext|>


<commit_before>
const ipc = require('electron').ipcRenderer;
const BrowserWindow = require('electron').remote.BrowserWindow;
const decompress = require('decompress');
const path = require('path');
const plist = require('simple-plist');
var callerWindow;

var tempDir = "tmp";

ipc.on('process-files', function (event, fileQueue, fromWindowId) {

    const fromWindow = BrowserWindow.fromId(fromWindowId);
    var results = [];
    var totalCount = fileQueue.length;
    var index = 0;

    var onResult = function(res) {
        results.push(res);
        doNext();
    };

    var doNext = function() {
        if(fileQueue.length > 0) {
            fromWindow.webContents.send('process-files-progress', ++index,totalCount);
            processApp(fileQueue.shift().path,onResult);
        }
        else {
            fromWindow.webContents.send('process-files-result', results);
            window.close();
        }
    };
    doNext();
});

function analyzeFiles(files) {

    // console.log('done! files.length = ' + files.length);
    var infoPlists = files.filter(function(file){
        return path.basename(file.path) === 'Info.plist';
    });

    infoPlists.sort(function(a,b){
        return a.path.length - b.path.length;
    });

    // infoPlists.forEach(function(item){
    //     console.log("item : " + item.path);
    // })

    var plistData = plist.readFileSync(path.join(tempDir,infoPlists[0].path));

    // console.log("plistData " + JSON.stringify(plistData));

    // console.log("DisplayName : " + plistData.CFBundleDisplayName);
    // console.log("BundleIdentifier : " + plistData.CFBundleIdentifier);

    var jsFiles = files.filter(function(file){
        return path.extname(file.path) === ".js";
    });

    var cordovaJsFiles = jsFiles.filter(function(file) {
        return path.basename(file.path) === 'cordova.js';
    });

    return {
        jsFileCount:jsFiles.length,
        cordovaJSCount:cordovaJsFiles.length,
        displayName:plistData.CFBundleDisplayName,
        bundleId:plistData.CFBundleIdentifier,
        icon:plistData.CFBundleIcon
    };
}

const filteredExtents = [".js",".plist",".png"];
function filterExtensions(file) {
    let ext = path.extname(file.path);
    if(filteredExtents.indexOf(ext) > -1 ) {
        return file;
    }
}

function processApp(path,cb) {

    decompress(path,tempDir,{ filter: filterExtensions })
    .then(function(res) {
        return analyzeFiles(res);
    })
    .then(function(res) {
        setTimeout(function(){ // delay so the UI can update
            cb(res);
        },0);
    },function onError(err) {
        setTimeout(function(){ // delay so the UI can update
            cb(err);
        },0);
    });
}<commit_msg>window should not close itself, the opener should manage us<commit_after>
const ipc = require('electron').ipcRenderer;
const BrowserWindow = require('electron').remote.BrowserWindow;
const decompress = require('decompress');
const path = require('path');
const plist = require('simple-plist');
var callerWindow;

var tempDir = "tmp";

ipc.on('process-files', function (event, fileQueue, fromWindowId) {

    const fromWindow = BrowserWindow.fromId(fromWindowId);
    var results = [];
    var totalCount = fileQueue.length;
    var index = 0;

    var onResult = function(res) {
        results.push(res);
        doNext();
    };

    var doNext = function() {
        if(fileQueue.length > 0) {
            fromWindow.webContents.send('process-files-progress', ++index,totalCount);
            processApp(fileQueue.shift().path,onResult);
        }
        else {
            fromWindow.webContents.send('process-files-result', results);
        }
    };
    doNext();
});

function analyzeFiles(files) {

    // console.log('done! files.length = ' + files.length);
    var infoPlists = files.filter(function(file){
        return path.basename(file.path) === 'Info.plist';
    });

    infoPlists.sort(function(a,b){
        return a.path.length - b.path.length;
    });

    // infoPlists.forEach(function(item){
    //     console.log("item : " + item.path);
    // })

    var plistData = plist.readFileSync(path.join(tempDir,infoPlists[0].path));

    // console.log("plistData " + JSON.stringify(plistData));
    // console.log("DisplayName : " + plistData.CFBundleDisplayName);
    // console.log("BundleIdentifier : " + plistData.CFBundleIdentifier);

    var jsFiles = files.filter(function(file){
        return path.extname(file.path) === ".js";
    });

    var cordovaJsFiles = jsFiles.filter(function(file) {
        return path.basename(file.path) === 'cordova.js';
    });

    return {
        jsFileCount:jsFiles.length,
        cordovaJSCount:cordovaJsFiles.length,
        displayName:plistData.CFBundleDisplayName,
        bundleId:plistData.CFBundleIdentifier,
        icon:plistData.CFBundleIcon
    };
}

const filteredExtents = [".js",".plist",".png"];
function filterExtensions(file) {
    let ext = path.extname(file.path);
    if(filteredExtents.indexOf(ext) > -1 ) {
        return file;
    }
}

function processApp(path,cb) {

    decompress(path,tempDir,{ filter: filterExtensions })
    .then(function(res) {
        return analyzeFiles(res);
    })
    .then(function(res) {
        setTimeout(function(){ // delay so the UI can update
            cb(res);
        },0);
    },function onError(err) {
        console.log("error " + err);
        setTimeout(function(){ // delay so the UI can update
            cb(err);
        },0);
    });
}<|endoftext|>