<commit_before>/* Le namespace "iJS"(pour "inside JS") initié ici est une mini bibliothèque pour le développement en JavaScript des projets associés.
 * En effet s'il est une chose que JQuery ne fais pas c'est le respect de la syntaxe JavaScript; ce qui constitue un problème lorsque après avoir appris le JavaScript,
 *il ne suffit plus seulement de connaître les fonctionnalités qu'apporte JQuery (ce qui se doit normalement d'être suffisant) mais aussi sa syntaxe à elle.
 * "iJS" tout comme "Dojo" s'oriente avant tout dans le respect de la syntaxe; sauf que seules sont récrites les fonctionnalités JS trop verbeux ou difficile d'utilisation.
 *
 * Ce namespace constitue un ensemble de petites fonctionnalités permettant de faciliter le développement en JavaScript.
 *
 * @license: GPL v3.0
 * @author : Tindo Ngoufo Arsel
 * @version: 0.0_(15.04)
 */

var iJS = {

    isNumber: function (arg) {

        if ((typeof arg).toLowerCase() === "number" || arg instanceof Number)
            return true;
        else
            return false;
    },

    isBoolean: function (arg) {

        if ((typeof arg).toLowerCase() === "boolean" || arg instanceof Boolean)
            return true;
        else
            return false;
    },

    isString: function (arg) {

        if ((typeof arg).toLowerCase() === "string" || arg instanceof String)
            return true;
        else
            return false;
    },

    isArray: function (arg) {

        if (arg instanceof Array)
            return true;
        else
            return false;
    },

    isHTMLElement: function (arg) {

        if (arg instanceof HTMLElement)
            return true;
        else
            return false;
    },

    isHTMLImageElement: function (arg) {

        if (arg instanceof HTMLImageElement)
            return true;
        else
            return false;
    },

    isObject: function (arg) {

        if ((typeof arg).toLowerCase() === "object")
            return true;
        else
            return false;
    },

    /* permet de changer les images pour l'animations des chargements (simuler un "loader")
	 *
	 *"imgContainer" représente soit l'id d'un élément "img", soit un élément "img" proprement dit.
	 *"imgDir" représente le chemin du répertoire contenant les images à animer
	 *"imgLength" représente le nombre d'image à animer
	 *"imgGlobalName" représente le nom global des images à animer. En effet les images à animer
	 doivent être de la forme 'imglaod0.png', 'imglaod1.png', ... où 'imgload' est ici le nom globlal
	*"imgFormat" est le format des images à animer. Par défaut (ou s'il n'est pas renseigner) c'est 'png'.
	*/
    mi_loader: function (imgContainer, imgDir, imgLength, imgGlobalName, imgFormat) {

        if (iJS.isString(imgDir))
            this.imgDir = imgDir;
        if (iJS.isNumber(imgLength))
            this.imgLength = imgLength;
        if (iJS.isString(imgGlobalName))
            this.imgGlobalName = imgGlobalName;

        this.imgFormat = (iJS.isString(imgFormat)) ? imgFormat : "png";

        if (iJS.isString(imgContainer))
            if (iJS.isHTMLImageElement(document.getElementById(imgContainer)))
                this.imgContainer = document.getElementById(imgContainer);
            else if (iJS.isHTMLImageElement(imgContainer))
            this.imgContainer = imgContainer;

        this.imgIndex = 0; //représente le numéro de l'image à afficher
        this.imgPath = ""; //représente le chemin vers l'image à afficher
        this.loaderID = 0; //puisque clearInterval pourra être utilisées

        /*la fonction ci-dessous permet de changer ou remplacer l'image affichée par la suivante.
         *le paramètre "loader" n'est nécessaire lorsque la fonction est passer en paramètre à une autre.
         *en effet il fera le plus souvent référence à l'objet lui même (au "this").
         *sauf que cela ne marche plus pour une utilisation dans une fonction externe à l'objet
         *puis que, en prenant l'exemple de "setInterval" rattachée à l'objet "window"
         *le "this" fera référence à l'objet "window" et non à l'objet voulu.
         *en ce moment là faudra faire setIinterval( obj.changeIMGLoader, time, obj).
         */
        this.changeIMGLoader = function (loader) {

            //ld = loader ou this ( l'objet lui même)
            var ld = (loader instanceof iJS.mi_loader) ? loader : this;

            if (ld.imgDir && ld.imgLength && ld.imgGlobalName)
                if (ld.imgIndex < ld.imgLength) {
                    ld.imgPath = ld.imgDir + "/" + ld.imgGlobalName + ld.imgIndex + "." + ld.imgFormat;
                    ld.imgIndex++;
                } else {
                    ld.imgIndex = 0;
                }

            if (ld.imgContainer)
                ld.imgContainer.src = ld.imgPath;
        }

        /*permet de lancer l'animation ( par remplacement successif d'image
         *suivant une intervalle de temps défini par "timeInterval"
         *par défaut l'intervalle de temps est de 150ms
         */
        this.startLoading = function (timeInterval) {

            if (this.loaderID) //alors faut d'abord stopper l'animation encours
                this.stopLoading();

            if (iJS.isNumber(timeInterval))
                this.loaderID = setInterval(this.changeIMGLoader, timeInterval, this)
            else {
                this.loaderID = setInterval(this.changeIMGLoader, 150, this);
            }

        }

        /*permet de stopper l'animation; soit immédiatement, soit après un un certain temps défini ici par "time"*/
        this.stopLoading = function (time) {

            if (iJS.isNumber(time)) {
                setTimeout(function (loader) {
                    if (loader instanceof iJS.mi_loader) {
                        clearInterval(loader.loaderID);
                        loader.imgIndex = 0;
                        loader.loaderID = 0;
                        loader.changeIMGLoader();
                    }
                }, time, this);
            } else {
                clearInterval(this.loaderID);
                this.imgIndex = 0;
                this.loaderID = 0;
                this.changeIMGLoader();
            }

        }
    }

}<commit_msg>set GPL to LGPL where is @license<commit_after>/* Le namespace "iJS"(pour "inside JS") initié ici est une mini bibliothèque pour le développement en JavaScript des projets associés.
 * En effet s'il est une chose que JQuery ne fais pas c'est le respect de la syntaxe JavaScript; ce qui constitue un problème lorsque après avoir appris le JavaScript,
 *il ne suffit plus seulement de connaître les fonctionnalités qu'apporte JQuery (ce qui se doit normalement d'être suffisant) mais aussi sa syntaxe à elle.
 * "iJS" tout comme "Dojo" s'oriente avant tout dans le respect de la syntaxe; sauf que seules sont récrites les fonctionnalités JS trop verbeux ou difficile d'utilisation.
 *
 * Ce namespace constitue un ensemble de petites fonctionnalités permettant de faciliter le développement en JavaScript.
 *
 * @license: GPL v3.0
 * @author : Tindo Ngoufo Arsel
 * @version: 0.0_(15.04)
 */

var iJS = {

    isNumber: function (arg) {

        if ((typeof arg).toLowerCase() === "number" || arg instanceof Number)
            return true;
        else
            return false;
    },

    isBoolean: function (arg) {

        if ((typeof arg).toLowerCase() === "boolean" || arg instanceof Boolean)
            return true;
        else
            return false;
    },

    isString: function (arg) {

        if ((typeof arg).toLowerCase() === "string" || arg instanceof String)
            return true;
        else
            return false;
    },

    isArray: function (arg) {

        if (arg instanceof Array)
            return true;
        else
            return false;
    },

    isHTMLElement: function (arg) {

        if (arg instanceof HTMLElement)
            return true;
        else
            return false;
    },

    isHTMLImageElement: function (arg) {

        if (arg instanceof HTMLImageElement)
            return true;
        else
            return false;
    },

    isObject: function (arg) {

        if ((typeof arg).toLowerCase() === "object")
            return true;
        else
            return false;
    },

    /* permet de changer les images pour l'animations des chargements (simuler un "loader")
	 *
	 *"imgContainer" représente soit l'id d'un élément "img", soit un élément "img" proprement dit.
	 *"imgDir" représente le chemin du répertoire contenant les images à animer
	 *"imgLength" représente le nombre d'image à animer
	 *"imgGlobalName" représente le nom global des images à animer. En effet les images à animer
	  doivent être de la forme 'imglaod0.png', 'imglaod1.png', ... où 'imgload' est ici le nom globlal
	 *"imgFormat" est le format des images à animer. Par défaut (ou s'il n'est pas renseigner) c'est 'png'.
	*/
    mi_loader: function (imgContainer, imgDir, imgLength, imgGlobalName, imgFormat) {

        if (iJS.isString(imgDir))
            this.imgDir = imgDir;
        if (iJS.isNumber(imgLength))
            this.imgLength = imgLength;
        if (iJS.isString(imgGlobalName))
            this.imgGlobalName = imgGlobalName;

        this.imgFormat = (iJS.isString(imgFormat)) ? imgFormat : "png";

        if (iJS.isString(imgContainer))
            if (iJS.isHTMLImageElement(document.getElementById(imgContainer)))
                this.imgContainer = document.getElementById(imgContainer);
            else if (iJS.isHTMLImageElement(imgContainer))
                this.imgContainer = imgContainer;

        this.imgIndex = 0; //représente le numéro de l'image à afficher
        this.imgPath = ""; //représente le chemin vers l'image à afficher
        this.loaderID = 0; //pour contenir le numéro d’identification des événements programés via des fonctions telle que "setTimeout()"

        /* La fonction ci-dessous permet de changer ou remplacer l'image affichée par la suivante.
         * Le paramètre "loader" n'est nécessaire lorsque la fonction est passer en paramètre à une autre.
         * En effet il fera le plus souvent référence à l'objet lui même (au "this").
         * Sauf que cela ne marche plus pour une utilisation dans une fonction appelée de manière externe à l'objet
         *puis que, en prenant l'exemple de "setInterval" rattachée à l'objet "window"
         *le "this" fera référence à l'objet "window" et non à l'objet voulu.
         *en ce moment là faudra faire setIinterval( obj.changeIMGLoader, time, obj ); au lieu de setIinterval( obj.changeIMGLoader, time );
         *car la déclaration est externe à l’objet "obj" de type "iJS.mi_loager".
         */
        this.changeIMGLoader = function (loader) {

            //ld = loader ou this ( l'objet lui même)
            var ld = (loader instanceof iJS.mi_loader) ? loader : this;

            if (ld.imgDir && ld.imgLength && ld.imgGlobalName)
                if (ld.imgIndex < ld.imgLength) {
                    ld.imgPath = ld.imgDir + "/" + ld.imgGlobalName + ld.imgIndex + "." + ld.imgFormat;
                    ld.imgIndex++;
                } else {
                    ld.imgIndex = 0;
                }

            if (ld.imgContainer)
                ld.imgContainer.src = ld.imgPath;
        }

        /*permet de lancer l'animation ( par remplacement successif d'image
         *suivant une intervalle de temps défini par "timeInterval"
         *par défaut l'intervalle de temps est de 150ms
         */
        this.startLoading = function (timeInterval) {

            if (this.loaderID) //alors faut d'abord stopper l'animation encours
                this.stopLoading();

            if (iJS.isNumber(timeInterval))
                this.loaderID = setInterval(this.changeIMGLoader, timeInterval, this)
            else {
                this.loaderID = setInterval(this.changeIMGLoader, 150, this);
            }

        }

        /*permet de stopper l'animation; soit immédiatement, soit après un un certain temps défini ici par "time"*/
        this.stopLoading = function (time) {

            /* @TODO: supprimer le paramètre "loader" et remplacer la variable associée par "this"
             *dans le bloc d’instruction contenu dans la fonction "setTimeout",
             *de ce fait enlever le "this" comme paramètre à cette fonction.
            */
            if (iJS.isNumber(time)) {
                setTimeout(function (loader) {
                    if (loader instanceof iJS.mi_loader) {
                        clearInterval(loader.loaderID);
                        loader.imgIndex = 0;
                        loader.loaderID = 0;
                        loader.changeIMGLoader();
                    }
                }, time, this);
            } else {
                clearInterval(this.loaderID);
                this.imgIndex = 0;
                this.loaderID = 0;
                this.changeIMGLoader();
            }

        }
    }

}<|endoftext|>


<commit_before>/*
 * Feedback arrows UX extension.
 * Shows two independent webgl models that should immitate spacenav movement.
 * Object should fade in and fade out on spacenav use.
 */
/*
 * Feedback arrows UX extension.
 * Shows two independent webgl models that should immitate spacenav movement.
 * Object should fade in and fade out on spacenav use.
 */

console.log('Loading Feedback arrows Extension: creating WS socket');

//Let's connect directly to websocket<->ROS bridge
var spacenavROS = new ROSLIB.Ros({
	url : 'ws://master:9090'
});

console.log('Loading Feedback arrows Extension: initializing ROS');

// Define topic object
var feedbackArrowsSpacenavListener = new ROSLIB.Topic({
	ros : spacenavROS,
	name : 'spacenav/twist',
	messageType : 'geometry_msgs/Twist',
	throttle_rate : 20
});

var arrowObjPosition = [ 0, 0, 0, 0, 0, 0 ];
var ringObjPosition = [ 0, 0, 0, 0, 0, 0 ];

// Subscribe to spacenav topic + ROS messages rate limiting
console.log('Loading Feedback arrows Extension: subscribing to spacenav topic');

feedbackArrowsSpacenavListener.subscribe(function(msg) {
	this.msg = msg;
	if (this.msg.linear.x == 0 && this.msg.linear.y == 0
			&& this.msg.linear.z == 0 && this.msg.angular.x == 0
			&& this.msg.angular.y == 0 && this.msg.angular.z == 0) {
		return;
	}

	arrowObjPosition[4] += 0.1;
	ringObjPosition[3] += 0.1;
});

// Three.js part
var container, stats;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

console.log("Arrows: before init");
init();
console.log("Arrows: after init");
console.log("Arrows: before animate");
animate();
console.log("Arrows: after animate");

function init() {
	container = document.createElement('div');
	container.id = 'feedback_arrows';
	document.body.appendChild(container);

	camera = new THREE.PerspectiveCamera(45, window.innerWidth
			/ window.innerHeight, 1, 2000);
	camera.position.x = 33;
	camera.position.y = 33;
	camera.position.z = 33;

	// scene

	scene = new THREE.Scene();

	var ambient = new THREE.AmbientLight(0x101030);
	scene.add(ambient);

	var directionalLight = new THREE.DirectionalLight(0xffeedd);
	directionalLight.position.set(0, 0, 1);
	scene.add(directionalLight);

	// texture

	var manager = new THREE.LoadingManager();
	manager.onProgress = function(item, loaded, total) {

		console.log(item, loaded, total);

	};

	var texture = new THREE.Texture();
	var imaginator = new Image();
	imaginator.src = "data:image/jpeg;base64,"
			+ "R0lGODlhkAGQAfAAAP///wAAACH5BAAAAAAAIf4Kc2NyaThlLmNvbQAsAAAAAJABkAEAAv6Ej6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/4PDAqHxKLxiEwql8ym8wmNSqfUqvWKzWq33K73Cw6Lx+Sy+YxOq9fstvsNj8vn9Lr9js/r9/y+/w8YKDhIWGh4iJiouMjY6PgIGSk5SVlpeYmZqbnJ2en5CRoqOkpaanqKmqq6ytrq+gobKztLW2t7i5uru8vb6/sLHCw8TFxsfIycrLzM3Oz8DB0tPU1dbX2Nna29zd3t/Q0eLj5OXm5+jp6uvs7e7v4OHy8/T19vf4+fr7/P3+//DzCgwIEECxo8iDChwoUMGzp8CDGixIkUK1q8iDGjxv6NHDt6/AgypMiRJEuaPIkypcqVLFu6fAkzpsyZNGvavIkzp86dPHv6/Ak0qNChRIsaPYo0qdKlTJs6fQo1qtSpVKtavYo1q9atXLt6/Qo2rNixZMuaPYs2rdq1bNu6fQs3rty5dOvavYs3r969fPv6/Qs4sODBhAsbPow4seLFjBs7fgw5suTJlCtbvow5s+bNnDt7/gw6tOjRpEubPo06terVrFu7fg07tuzZtGvbvo07t+7dvHv7/g08uPDhxIsbP448ufLlzJs7fw49uvTp1Ktbv449u/bt3Lt7/w4+vPjx5MubP48+vfr17Nu7fw8/vvz59Ovbv48/v/79/E/7+/8PYIACDkhggQYeiGCCCi7IYIMOPghhhBJOSGGFFl6IYYYabshhhx5+CGKIIo5IYokmnohiiiquyGKLLr4IY4wyzkhjjTbeiGOObRQAADs="
	texture.image = imaginator;
	texture.needsUpdate = true;
	// EOFD

	var arrows_loader = new THREE.OBJLoader(manager);
	arrows_loader.load(chrome.extension.getURL('models/arrow.obj'), function(
			object) {
		this.arrowObj = object;
		object.traverse(function(child) {
			if (child instanceof THREE.Mesh) {
				child.material.map = texture;
			}
		});
		scene.add(object);
	});

	var ring_loader = new THREE.OBJLoader(manager);
	ring_loader.load(chrome.extension.getURL('models/ring.obj'), function(
			object) {
		this.ringObj = object;
		object.traverse(function(child) {
			if (child instanceof THREE.Mesh) {
				child.material.map = texture;
			}
		});
		scene.add(object);
	});

	//

	// let's make transparent background
	renderer = new THREE.WebGLRenderer({
		alpha : true
	});
	renderer.setSize(window.innerWidth, window.innerHeight);
	container.appendChild(renderer.domElement);
	renderer.setClearColor(0x000000, 0);
	window.addEventListener('resize', onWindowResize, false);

}

// we need this for debug purposes
function onWindowResize() {
	windowHalfX = window.innerWidth / 2;
	windowHalfY = window.innerHeight / 2;
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}

//

function animate() {
	requestAnimationFrame(animate);
	render();
}

function render() {
	if (arrowObj) {
		arrowObj.position.x = arrowObjPosition[0];
		arrowObj.position.y = arrowObjPosition[1];
		arrowObj.position.z = arrowObjPosition[2];
		arrowObj.rotation.x = arrowObjPosition[3];
		arrowObj.rotation.y = arrowObjPosition[4];
		arrowObj.rotation.z = arrowObjPosition[5];
	}
	if (ringObj) {
		arrowObj.position.x = ringObjPosition[0];
		arrowObj.position.y = ringObjPosition[1];
		arrowObj.position.z = ringObjPosition[2];
		arrowObj.rotation.x = ringObjPosition[3];
		arrowObj.rotation.y = ringObjPosition[4];
		arrowObj.rotation.z = ringObjPosition[5];
	}
	camera.lookAt(scene.position);
	renderer.render(scene, camera);
}
<commit_msg>Experiment with axes<commit_after>/*
 * Feedback arrows UX extension.
 * Shows two independent webgl models that should immitate spacenav movement.
 * Object should fade in and fade out on spacenav use.
 */
/*
 * Feedback arrows UX extension.
 * Shows two independent webgl models that should immitate spacenav movement.
 * Object should fade in and fade out on spacenav use.
 */

console.log('Loading Feedback arrows Extension: creating WS socket');

//Let's connect directly to websocket<->ROS bridge
var spacenavROS = new ROSLIB.Ros({
	url : 'ws://master:9090'
});

console.log('Loading Feedback arrows Extension: initializing ROS');

// Define topic object
var feedbackArrowsSpacenavListener = new ROSLIB.Topic({
	ros : spacenavROS,
	name : 'spacenav/twist',
	messageType : 'geometry_msgs/Twist',
	throttle_rate : 20
});

var arrowObjPosition = [ 0, 0, 0, 0, 0, 0 ];
var ringObjPosition = [ 0, 0, 0, 0, 0, 0 ];

// Subscribe to spacenav topic + ROS messages rate limiting
console.log('Loading Feedback arrows Extension: subscribing to spacenav topic');

feedbackArrowsSpacenavListener.subscribe(function(msg) {
	this.msg = msg;
	if (this.msg.linear.x == 0 && this.msg.linear.y == 0
			&& this.msg.linear.z == 0 && this.msg.angular.x == 0
			&& this.msg.angular.y == 0 && this.msg.angular.z == 0) {
		return;
	}

	arrowObjPosition[1] += 0.1;
	ringObjPosition[0] += 0.1;
});

// Three.js part
var container, stats;
var camera, scene, renderer;
var mouseX = 0, mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

console.log("Arrows: before init");
init();
console.log("Arrows: after init");
console.log("Arrows: before animate");
animate();
console.log("Arrows: after animate");

function init() {
	container = document.createElement('div');
	container.id = 'feedback_arrows';
	document.body.appendChild(container);

	camera = new THREE.PerspectiveCamera(45, window.innerWidth
			/ window.innerHeight, 1, 2000);
	camera.position.x = 33;
	camera.position.y = 33;
	camera.position.z = 33;

	// scene

	scene = new THREE.Scene();

	var ambient = new THREE.AmbientLight(0x101030);
	scene.add(ambient);

	var directionalLight = new THREE.DirectionalLight(0xffeedd);
	directionalLight.position.set(0, 0, 1);
	scene.add(directionalLight);

	// texture

	var manager = new THREE.LoadingManager();
	manager.onProgress = function(item, loaded, total) {

		console.log(item, loaded, total);

	};

	var texture = new THREE.Texture();
	var imaginator = new Image();
	imaginator.src = "data:image/jpeg;base64,"
			+ "R0lGODlhkAGQAfAAAP///wAAACH5BAAAAAAAIf4Kc2NyaThlLmNvbQAsAAAAAJABkAEAAv6Ej6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/4PDAqHxKLxiEwql8ym8wmNSqfUqvWKzWq33K73Cw6Lx+Sy+YxOq9fstvsNj8vn9Lr9js/r9/y+/w8YKDhIWGh4iJiouMjY6PgIGSk5SVlpeYmZqbnJ2en5CRoqOkpaanqKmqq6ytrq+gobKztLW2t7i5uru8vb6/sLHCw8TFxsfIycrLzM3Oz8DB0tPU1dbX2Nna29zd3t/Q0eLj5OXm5+jp6uvs7e7v4OHy8/T19vf4+fr7/P3+//DzCgwIEECxo8iDChwoUMGzp8CDGixIkUK1q8iDGjxv6NHDt6/AgypMiRJEuaPIkypcqVLFu6fAkzpsyZNGvavIkzp86dPHv6/Ak0qNChRIsaPYo0qdKlTJs6fQo1qtSpVKtavYo1q9atXLt6/Qo2rNixZMuaPYs2rdq1bNu6fQs3rty5dOvavYs3r969fPv6/Qs4sODBhAsbPow4seLFjBs7fgw5suTJlCtbvow5s+bNnDt7/gw6tOjRpEubPo06terVrFu7fg07tuzZtGvbvo07t+7dvHv7/g08uPDhxIsbP448ufLlzJs7fw49uvTp1Ktbv449u/bt3Lt7/w4+vPjx5MubP48+vfr17Nu7fw8/vvz59Ovbv48/v/79/E/7+/8PYIACDkhggQYeiGCCCi7IYIMOPghhhBJOSGGFFl6IYYYabshhhx5+CGKIIo5IYokmnohiiiquyGKLLr4IY4wyzkhjjTbeiGOObRQAADs="
	texture.image = imaginator;
	texture.needsUpdate = true;
	// EOFD

	var arrows_loader = new THREE.OBJLoader(manager);
	arrows_loader.load(chrome.extension.getURL('models/arrow.obj'), function(
			arrow_object) {
		this.arrowObj = arrow_object;
		arrow_object.traverse(function(child) {
			if (child instanceof THREE.Mesh) {
				child.material.map = texture;
			}
		});
		scene.add(arrow_object);
	});

	var ring_loader = new THREE.OBJLoader(manager);
	ring_loader.load(chrome.extension.getURL('models/ring.obj'), function(
			ring_object) {
		this.ringObj = ring_object;
		ring_object.traverse(function(child) {
			if (child instanceof THREE.Mesh) {
				child.material.map = texture;
			}
		});
		scene.add(ring_object);
	});

	//

	// let's make transparent background
	renderer = new THREE.WebGLRenderer({
		alpha : true
	});
	renderer.setSize(window.innerWidth, window.innerHeight);
	container.appendChild(renderer.domElement);
	renderer.setClearColor(0x000000, 0);
	window.addEventListener('resize', onWindowResize, false);

}

// we need this for debug purposes
function onWindowResize() {
	windowHalfX = window.innerWidth / 2;
	windowHalfY = window.innerHeight / 2;
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}

//

function animate() {
	requestAnimationFrame(animate);
	render();
}

function render() {
	if (arrowObj) {
		arrowObj.position.x = arrowObjPosition[0];
		arrowObj.position.y = arrowObjPosition[1];
		arrowObj.position.z = arrowObjPosition[2];
		arrowObj.rotation.x = arrowObjPosition[3];
		arrowObj.rotation.y = arrowObjPosition[4];
		arrowObj.rotation.z = arrowObjPosition[5];
	}
	if (ringObj) {
		arrowObj.position.x = ringObjPosition[0];
		arrowObj.position.y = ringObjPosition[1];
		arrowObj.position.z = ringObjPosition[2];
		arrowObj.rotation.x = ringObjPosition[3];
		arrowObj.rotation.y = ringObjPosition[4];
		arrowObj.rotation.z = ringObjPosition[5];
	}
	camera.lookAt(scene.position);
	renderer.render(scene, camera);
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 */

'use strict';

/**
 *
 * @type {*|exports|module.exports}
 */
var utils;

var backboneEvents;

var jquery = require('jquery');
require('snackbarjs');

var exId = "session";

/**
 *
 * @type {{set: module.exports.set, init: module.exports.init}}
 */
module.exports = {
    set: function (o) {
        utils = o.utils;
        backboneEvents = o.backboneEvents;
        return this;
    },
    init: function () {

        var parent = this;

        /**
         *
         */
        var React = require('react');

        /**
         *
         */
        var ReactDOM = require('react-dom');

        $('

').appendTo('#main-navbar');

        // Check if signed in
        //===================

        $.ajax({
            dataType: 'json',
            url: "/api/session/status",
            type: "GET",
            success: function (data) {
                if (data.status.authenticated) {
                    $(".gc2-session-lock").show();
                    $(".gc2-session-unlock").hide();
                } else {
                    $(".gc2-session-lock").hide();
                    $(".gc2-session-unlock").show();
                }

            },
            error: function (error) {
                console.error(error.responseJSON);
            }
        });

        $("#" + exId).on("click", function () {
            $("#info-modal.slide-right").animate({
                right: "0"
            }, 200, function () {

                // Render
                //=======

                ReactDOM.render(
                    <Session/>,
                    document.getElementById("info-modal-body-wrapper")
                );

            });
        });

        class Status extends React.Component {
            render() {
                return

                    {this.props.statusText}

            }
        }

        class Session extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    sessionEmail: "",
                    sessionPassword: "",
                    statusText: "Type your user name and password",
                    alertClass: "alert-info",
                    btnText: "Sign in",
                    auth: false
                };

                this.validateForm = this.validateForm.bind(this);
                this.handleChange = this.handleChange.bind(this);
                this.handleSubmit = this.handleSubmit.bind(this);

                this.padding = {
                    padding: "12px"
                };
                this.sessionLoginBtn = {
                    width: "100%"
                };

            }

            validateForm() {
                return this.state.sessionEmail.length > 0 && this.state.sessionPassword.length > 0 || this.state.auth;
            }

            handleChange(event) {
                this.setState({
                    [event.target.id]: event.target.value
                });
            }

            handleSubmit(event) {

                let me = this;

                event.preventDefault();

                if (!me.state.auth) {
                    $.ajax({
                        dataType: 'json',
                        url: "/api/session/start",
                        type: "POST",
                        data: "u=" + me.state.sessionEmail + "&p=" + me.state.sessionPassword + "&s=public",
                        success: function (data) {
                            me.setState({statusText: "Signed in as " + me.state.sessionEmail});
                            me.setState({alertClass: "alert-success"});
                            me.setState({btnText: "Log out"});
                            me.setState({auth: true});
                            setTimeout(function () {
                                $("#info-modal button.close").trigger("click");
                            }, 1000);
                            $(".gc2-session-lock").show();
                            $(".gc2-session-unlock").hide();
                            parent.update();
                        },
                        error: function (error) {
                            me.setState({statusText: "Wrong user name or password"});
                            me.setState({alertClass: "alert-danger"});
                        }
                    });
                }

                else {
                    $.ajax({
                        dataType: 'json',
                        url: "/api/session/stop",
                        type: "GET",
                        success: function (data) {
                            me.setState({statusText: "Not signed in"});
                            me.setState({alertClass: "alert-info"});
                            me.setState({btnText: "Sign in"});
                            me.setState({auth: false});
                            setTimeout(function () {
                                $("#info-modal button.close").trigger("click");
                            }, 1000);
                            $(".gc2-session-lock").hide();
                            $(".gc2-session-unlock").show();
                            parent.update();
                        },
                        error: function (error) {
                            console.error(error.responseJSON);
                        }
                    });
                }
            }

            componentDidMount() {
                var me = this;

                $.ajax({
                    dataType: 'json',
                    url: "/api/session/status",
                    type: "GET",
                    success: function (data) {
                        if (data.status.authenticated) {
                            me.setState({sessionEmail: data.status.userName});
                            me.setState({statusText: "Signed in as " + me.state.sessionEmail});
                            me.setState({alertClass: "alert-success"});
                            me.setState({btnText: "Sign out"});
                            me.setState({auth: true});
                            $(".gc2-session-lock").show();
                            $(".gc2-session-unlock").hide();
                        } else {
                            $(".gc2-session-lock").hide();
                            $(".gc2-session-unlock").show();
                        }

                    },
                    error: function (error) {
                        console.error(error.responseJSON);
                    }
                });
            }

            render() {

                return (

                        <Status statusText={this.state.statusText} alertClass={this.state.alertClass}/>

                            <form onSubmit={this.handleSubmit}>

                                        User name
                                        <input
                                            id="sessionEmail"
                                            className="form-control"
                                            defaultValue={this.state.sessionEmail}
                                            onChange={this.handleChange}
                                        />

                                        Password
                                        <input
                                            id="sessionPassword"
                                            className="form-control"
                                            defaultValue={this.state.sessionPassword}
                                            onChange={this.handleChange}
                                            type="password"
                                        />

                                <button
                                    type="submit"
                                    disabled={!this.validateForm()}
                                    className="btn btn-raised"
                                    style={this.sessionLoginBtn}
                                >
                                    {this.state.btnText}
                                </button>

                            </form>

                );
            }
        }

    },

    update: function () {
        backboneEvents.get().trigger("refresh:meta");

    }
};

<commit_msg>Delete is working<commit_after>/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 */

'use strict';

/**
 *
 * @type {*|exports|module.exports}
 */
var utils;

var backboneEvents;

var jquery = require('jquery');
require('snackbarjs');

var exId = "session";

/**
 *
 * @type {{set: module.exports.set, init: module.exports.init}}
 */
module.exports = {
    set: function (o) {
        utils = o.utils;
        backboneEvents = o.backboneEvents;
        return this;
    },
    init: function () {

        var parent = this;

        /**
         *
         */
        var React = require('react');

        /**
         *
         */
        var ReactDOM = require('react-dom');

        $('

').appendTo('#main-navbar');

        // Check if signed in
        //===================

        $.ajax({
            dataType: 'json',
            url: "/api/session/status",
            type: "GET",
            success: function (data) {
                if (data.status.authenticated) {
                    $(".gc2-session-lock").show();
                    $(".gc2-session-unlock").hide();
                } else {
                    $(".gc2-session-lock").hide();
                    $(".gc2-session-unlock").show();
                }

            },
            error: function (error) {
                console.error(error.responseJSON);
            }
        });

        $("#" + exId).on("click", function () {
            $("#info-modal.slide-right").animate({
                right: "0"
            }, 200, function () {

                // Render
                //=======

                ReactDOM.render(
                    <Session/>,
                    document.getElementById("info-modal-body")
                );

            });
        });

        class Status extends React.Component {
            render() {
                return

                    {this.props.statusText}

            }
        }

        class Session extends React.Component {
            constructor(props) {
                super(props);

                this.state = {
                    sessionEmail: "",
                    sessionPassword: "",
                    statusText: "Type your user name and password",
                    alertClass: "alert-info",
                    btnText: "Sign in",
                    auth: false
                };

                this.validateForm = this.validateForm.bind(this);
                this.handleChange = this.handleChange.bind(this);
                this.handleSubmit = this.handleSubmit.bind(this);

                this.padding = {
                    padding: "12px"
                };
                this.sessionLoginBtn = {
                    width: "100%"
                };

            }

            validateForm() {
                return this.state.sessionEmail.length > 0 && this.state.sessionPassword.length > 0 || this.state.auth;
            }

            handleChange(event) {
                this.setState({
                    [event.target.id]: event.target.value
                });
            }

            handleSubmit(event) {

                let me = this;

                event.preventDefault();

                if (!me.state.auth) {
                    $.ajax({
                        dataType: 'json',
                        url: "/api/session/start",
                        type: "POST",
                        data: "u=" + me.state.sessionEmail + "&p=" + me.state.sessionPassword + "&s=public",
                        success: function (data) {
                            me.setState({statusText: "Signed in as " + me.state.sessionEmail});
                            me.setState({alertClass: "alert-success"});
                            me.setState({btnText: "Log out"});
                            me.setState({auth: true});
                            setTimeout(function () {
                                $("#info-modal button.close").trigger("click");
                            }, 1000);
                            $(".gc2-session-lock").show();
                            $(".gc2-session-unlock").hide();
                            parent.update();
                        },
                        error: function (error) {
                            me.setState({statusText: "Wrong user name or password"});
                            me.setState({alertClass: "alert-danger"});
                        }
                    });
                }

                else {
                    $.ajax({
                        dataType: 'json',
                        url: "/api/session/stop",
                        type: "GET",
                        success: function (data) {
                            me.setState({statusText: "Not signed in"});
                            me.setState({alertClass: "alert-info"});
                            me.setState({btnText: "Sign in"});
                            me.setState({auth: false});
                            setTimeout(function () {
                                $("#info-modal button.close").trigger("click");
                            }, 1000);
                            $(".gc2-session-lock").hide();
                            $(".gc2-session-unlock").show();
                            parent.update();
                        },
                        error: function (error) {
                            console.error(error.responseJSON);
                        }
                    });
                }
            }

            componentDidMount() {
                var me = this;

                $.ajax({
                    dataType: 'json',
                    url: "/api/session/status",
                    type: "GET",
                    success: function (data) {
                        if (data.status.authenticated) {
                            me.setState({sessionEmail: data.status.userName});
                            me.setState({statusText: "Signed in as " + me.state.sessionEmail});
                            me.setState({alertClass: "alert-success"});
                            me.setState({btnText: "Sign out"});
                            me.setState({auth: true});
                            $(".gc2-session-lock").show();
                            $(".gc2-session-unlock").hide();
                        } else {
                            $(".gc2-session-lock").hide();
                            $(".gc2-session-unlock").show();
                        }

                    },
                    error: function (error) {
                        console.error(error.responseJSON);
                    }
                });
            }

            render() {

                return (

                        <Status statusText={this.state.statusText} alertClass={this.state.alertClass}/>

                            <form onSubmit={this.handleSubmit}>

                                        User name
                                        <input
                                            id="sessionEmail"
                                            className="form-control"
                                            defaultValue={this.state.sessionEmail}
                                            onChange={this.handleChange}
                                        />

                                        Password
                                        <input
                                            id="sessionPassword"
                                            className="form-control"
                                            defaultValue={this.state.sessionPassword}
                                            onChange={this.handleChange}
                                            type="password"
                                        />

                                <button
                                    type="submit"
                                    disabled={!this.validateForm()}
                                    className="btn btn-raised"
                                    style={this.sessionLoginBtn}
                                >
                                    {this.state.btnText}
                                </button>

                            </form>

                );
            }
        }

    },

    update: function () {
        backboneEvents.get().trigger("refresh:meta");

    }
};

<|endoftext|>


<commit_before>// Polyfills
import './polyfills/objectAssign';
import './polyfills/requestAnimationFrame';

// Utils
import Utils from './utils/index';
import debounce from './utils/debounce';
import setStyle from './utils/setStyle';
import isTransformed from './utils/isTransformed';
import getSupportedPropertyName from './utils/getSupportedPropertyName';
import getPosition from './utils/getPosition';
import getOffsets from './utils/getOffsets';
import isFunction from './utils/isFunction';
import setupEventListeners from './utils/setupEventListeners';
import removeEventListeners from './utils/removeEventListeners';
import runModifiers from './utils/runModifiers';
import sortModifiers from './utils/sortModifiers';
import isModifierEnabled from './utils/isModifierEnabled';

// Modifiers
import modifiersFunctions from './modifiers/index';
import { modifiersOnLoad as modifiersOnLoadFunctions } from './modifiers/index';

// default options
var DEFAULTS = {
    // placement of the popper
    placement: 'bottom',

    // if true, it uses the CSS 3d transformation to position the popper
    gpuAcceleration: true,

    // list of functions used to modify the offsets before they are applied to the popper
    modifiers: {
        shift: {
            order: 100,
            enabled: true,
            function: modifiersFunctions.shift,
        },
        offset: {
            order: 200,
            enabled: true,
            function: modifiersFunctions.offset,
            // nudges popper from its origin by the given amount of pixels (can be negative)
            offset: 0,
        },
        preventOverflow: {
            order: 300,
            enabled: true,
            function: modifiersFunctions.preventOverflow,
            // popper will try to prevent overflow following these priorities
            //  by default, then, it could overflow on the left and on top of the boundariesElement
            priority: ['left', 'right', 'top', 'bottom'],
            // amount of pixel used to define a minimum distance between the boundaries and the popper
            // this makes sure the popper has always a little padding between the edges of its container
            padding: 5,
            boundariesElement: 'scrollParent',
        },
        keepTogether: {
            order: 400,
            enabled: true,
            function: modifiersFunctions.keepTogether
        },
        arrow: {
            order: 500,
            enabled: true,
            function: modifiersFunctions.arrow,
            // selector or node used as arrow
            element: '[x-arrow]'
        },
        flip: {
            order: 600,
            enabled: true,
            function: modifiersFunctions.flip,
            // the behavior used to change the popper's placement
            behavior: 'flip',
            // the popper will flip if it hits the edges of the boundariesElement - padding
            padding: 5,
            boundariesElement: 'viewport'
        },
        hide: {
            order: 700,
            enabled: true,
            function: modifiersFunctions.hide
        },
        applyStyle: {
            order: 800,
            enabled: true,
            function: modifiersFunctions.applyStyle,
            onLoad: modifiersOnLoadFunctions.applyStyleOnLoad
        }
    },
};

/**
 * Create a new Popper.js instance
 * @class Popper
 * @param {HTMLElement} reference - The reference element used to position the popper
 * @param {HTMLElement} popper - The HTML element used as popper.
 * @param {Object} options
 * @param {String} options.placement=bottom
 *      Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -right),
 *      left(-start, -end)`
 *
 * @param {Boolean} options.gpuAcceleration=true
 *      When this property is set to true, the popper position will be applied using CSS3 translate3d, allowing the
 *      browser to use the GPU to accelerate the rendering.
 *      If set to false, the popper will be placed using `top` and `left` properties, not using the GPU.
 *
 * @param {Number} options.boundariesPadding=5
 *      Additional padding for the boundaries
 *
 * @param {Boolean} options.removeOnDestroy=false
 *      Set to true if you want to automatically remove the popper when you call the `destroy` method.
 *
 * @param {Object} options.modifiers
 *      List of functions used to modify the data before they are applied to the popper (see source code for default values)
 *
 * @param {Object} options.modifiers.arrow - Arrow modifier configuration
 * @param {HTMLElement|String} options.modifiers.arrow.element='[x-arrow]'
 *      The DOM Node used as arrow for the popper, or a CSS selector used to get the DOM node. It must be child of
 *      its parent Popper. Popper.js will apply to the given element the style required to align the arrow with its
 *      reference element.
 *      By default, it will look for a child node of the popper with the `x-arrow` attribute.
 *
 * @param {Object} options.modifiers.offset - Offset modifier configuration
 * @param {Number} options.modifiers.offset.offset=0
 *      Amount of pixels the popper will be shifted (can be negative).
 *
 * @param {Object} options.modifiers.preventOverflow - PreventOverflow modifier configuration
 * @param {Array} [options.modifiers.preventOverflow.priority=['left', 'right', 'top', 'bottom']]
 *      Priority used when Popper.js tries to avoid overflows from the boundaries, they will be checked in order,
 *      this means that the last one will never overflow
 * @param {Number} options.modifiers.preventOverflow.padding=5
 *      Amount of pixel used to define a minimum distance between the boundaries and the popper
 *      this makes sure the popper has always a little padding between the edges of its container.
 *
 * @param {Object} options.modifiers.flip - Flip modifier configuration
 * @param {String|Array} options.modifiers.flip.behavior='flip'
 *      The behavior used by the `flip` modifier to change the placement of the popper when the latter is trying to
 *      overlap its reference element. Defining `flip` as value, the placement will be flipped on
 *      its axis (`right - left`, `top - bottom`).
 *      You can even pass an array of placements (eg: `['right', 'left', 'top']` ) to manually specify
 *      how alter the placement when a flip is needed. (eg. in the above example, it would first flip from right to left,
 *      then, if even in its new placement, the popper is overlapping its reference element, it will be moved to top)
 * @param {String|Element} options.modifiers.flip.boundariesElement='viewport'
 *      The element which will define the boundaries of the popper position, the popper will never be placed outside
 *      of the defined boundaries (except if `keepTogether` is enabled)
 *
 * @param {Number} options.modifiers.flip.padding=5
 *      Amount of pixel used to define a minimum distance between the boundaries and the popper
 *      this makes sure the popper has always a little padding between the edges of its container.
 *
 * @return {Object} instance - The generated Popper.js instance
 */
export default class Popper {
    constructor(reference, popper, options = {}) {
        // make update() debounced, so that it only runs at most once-per-tick
        this.update = debounce(this.update.bind(this));
        // create a throttled version of update() that is scheduled based on UI updates
        this.scheduleUpdate = () => requestAnimationFrame(this.update);

        // init state
        this.state = {
            isDestroyed: false,
            isCreated: false,
        };

        // get reference and popper elements (allow jQuery wrappers)
        this.reference = reference.jquery ? reference[0] : reference;
        this.popper = popper.jquery ? popper[0] : popper;

        // with {} we create a new object with the options inside it
        this.options = Object.assign({}, DEFAULTS, options);

        // refactoring modifiers' list (Object => Array)
        this.modifiers = Object.keys(DEFAULTS.modifiers)
                               .map((name) => Object.assign({ name }, DEFAULTS.modifiers[name]));

        // assign default values to modifiers, making sure to override them with
        // the ones defined by user
        this.modifiers = this.modifiers.map((defaultConfig) => {
            const userConfig = (options.modifiers && options.modifiers[defaultConfig.name]) || {};
            const finalConfig = Object.assign({}, defaultConfig, userConfig);
            return finalConfig;
        });

        // add custom modifiers to the modifiers list
        if (options.modifiers) {
            this.options.modifiers = Object.assign({}, DEFAULTS.modifiers, options.modifiers);
            Object.keys(options.modifiers).forEach((name) => {
                // take in account only custom modifiers
                if (DEFAULTS.modifiers[name] === undefined) {
                    const modifier = options.modifiers[name];
                    modifier.name = name;
                    this.modifiers.push(modifier);
                }
            });
        }

        // sort the modifiers by order
        this.modifiers = this.modifiers.sort(sortModifiers)

        // modifiers have the ability to execute arbitrary code when Popper.js get inited
        // such code is executed in the same order of its modifier
        // they could add new properties to their options configuration
        // BE AWAARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
        this.modifiers.forEach((modifier) => {
            if (modifier.enabled && isFunction(modifier.onLoad)) {
                //              reference       popper       options       modifierOptions
                modifier.onLoad(this.reference, this.popper, this.options, modifier);
            }
        });

        // get the popper position type
        this.state.position = getPosition(this.reference);

        // determine how we should set the origin of offsets
        this.state.isParentTransformed = isTransformed(this.popper.parentNode);

        // fire the first update to position the popper in the right place
        this.update();

        // setup event listeners, they will take care of update the position in specific situations
        setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);

        // make it chainable
        return this;
    }

    //
    // Methods
    //

    /**
     * Updates the position of the popper, computing the new offsets and applying the new style
     * @method
     * @memberof Popper
     */
    update() {
        var data = {
            instance: this,
            styles: {},
            flipped: false,
        };

        // make sure to apply the popper position before any computation
        this.state.position = getPosition(this.reference);
        setStyle(this.popper, { position: this.state.position});

        // if popper is destroyed, don't perform any further update
        if (this.state.isDestroyed) { return; }

        // store placement inside the data object, modifiers will be able to edit `placement` if needed
        // and refer to originalPlacement to know the original value
        data.placement = this.options.placement;
        data.originalPlacement = this.options.placement;

        // compute the popper and reference offsets and put them inside data.offsets
        data.offsets = getOffsets(this.state, this.popper, this.reference, data.placement);

        // run the modifiers
        data = runModifiers(this.modifiers, data);

        // the first `update` will call `onCreate` callback
        // the other ones will call `onUpdate` callback
        if (!this.state.isCreated) {
            this.state.isCreated = true;
            if (isFunction(this.state.createCallback)) {
                this.state.createCallback(data);
            }
        } else if (isFunction(this.state.updateCallback)) {
            this.state.updateCallback(data);
        }
    }

    /**
     * If a function is passed, it will be executed after the initialization of popper with as first argument the Popper instance.
     * @method
     * @memberof Popper
     * @param {createCallback} callback
     */
    onCreate(callback) {
        // the createCallbacks return as first argument the popper instance
        this.state.createCallback = callback;
        return this;
    }

    /**
     * Callback called when the popper is created.
     * Access Popper.js instance with `data.instance`.
     * @callback createCallback
     * @static
     * @param {dataObject} data
     */

    /**
     * If a function is passed, it will be executed after each update of popper with as first argument the set of coordinates and informations
     * used to style popper and its arrow.
     * NOTE: it doesn't get fired on the first call of the `Popper.update()` method inside the `Popper` constructor!
     * @method
     * @memberof Popper
     * @param {updateCallback} callback
     */
    onUpdate(callback) {
        this.state.updateCallback = callback;
        return this;
    }

    /**
     * Callback called when the popper is updated, this callback is not called
     * on the initialization/creation of the popper, but only on subsequent
     * updates.
     * Access Popper.js instance with `data.instance`.
     * @callback updateCallback
     * @static
     * @param {dataObject} data
     */

    /**
     * Destroy the popper
     * @method
     * @memberof Popper
     */
    destroy() {
        this.state.isDestroyed = true;

        // touch DOM only if `applyStyle` modifier is enabled
        if (isModifierEnabled(this.modifiers, 'applyStyle')) {
            this.popper.removeAttribute('x-placement');
            this.popper.style.left = '';
            this.popper.style.position = '';
            this.popper.style.top = '';
            this.popper.style[getSupportedPropertyName('transform')] = '';
        }

        this.state = removeEventListeners(this.reference, this.state);

        // remove the popper if user explicity asked for the deletion on destroy
        // do not use `remove` because IE11 doesn't support it
        if (this.options.removeOnDestroy) {
            this.popper.parentNode.removeChild(this.popper);
        }
        return this;
    }

    /**
     * Collection of utilities useful when writing custom modifiers
     * @memberof Popper
     */
    static Utils = Utils;

    /**
     * Default Popper.js options
     * @memberof Popper
     */
    Defaults = DEFAULTS;
}
<commit_msg>close #94<commit_after>// Polyfills
import './polyfills/objectAssign';
import './polyfills/requestAnimationFrame';

// Utils
import Utils from './utils/index';
import debounce from './utils/debounce';
import setStyle from './utils/setStyle';
import isTransformed from './utils/isTransformed';
import getSupportedPropertyName from './utils/getSupportedPropertyName';
import getPosition from './utils/getPosition';
import getOffsets from './utils/getOffsets';
import isFunction from './utils/isFunction';
import setupEventListeners from './utils/setupEventListeners';
import removeEventListeners from './utils/removeEventListeners';
import runModifiers from './utils/runModifiers';
import sortModifiers from './utils/sortModifiers';
import isModifierEnabled from './utils/isModifierEnabled';

// Modifiers
import modifiersFunctions from './modifiers/index';
import { modifiersOnLoad as modifiersOnLoadFunctions } from './modifiers/index';

// default options
var DEFAULTS = {
    // placement of the popper
    placement: 'bottom',

    // if true, it uses the CSS 3d transformation to position the popper
    gpuAcceleration: true,

    // list of functions used to modify the offsets before they are applied to the popper
    modifiers: {
        shift: {
            order: 100,
            enabled: true,
            function: modifiersFunctions.shift,
        },
        offset: {
            order: 200,
            enabled: true,
            function: modifiersFunctions.offset,
            // nudges popper from its origin by the given amount of pixels (can be negative)
            offset: 0,
        },
        preventOverflow: {
            order: 300,
            enabled: true,
            function: modifiersFunctions.preventOverflow,
            // popper will try to prevent overflow following these priorities
            //  by default, then, it could overflow on the left and on top of the boundariesElement
            priority: ['left', 'right', 'top', 'bottom'],
            // amount of pixel used to define a minimum distance between the boundaries and the popper
            // this makes sure the popper has always a little padding between the edges of its container
            padding: 5,
            boundariesElement: 'scrollParent',
        },
        keepTogether: {
            order: 400,
            enabled: true,
            function: modifiersFunctions.keepTogether
        },
        arrow: {
            order: 500,
            enabled: true,
            function: modifiersFunctions.arrow,
            // selector or node used as arrow
            element: '[x-arrow]'
        },
        flip: {
            order: 600,
            enabled: true,
            function: modifiersFunctions.flip,
            // the behavior used to change the popper's placement
            behavior: 'flip',
            // the popper will flip if it hits the edges of the boundariesElement - padding
            padding: 5,
            boundariesElement: 'viewport'
        },
        hide: {
            order: 700,
            enabled: true,
            function: modifiersFunctions.hide
        },
        applyStyle: {
            order: 800,
            enabled: true,
            function: modifiersFunctions.applyStyle,
            onLoad: modifiersOnLoadFunctions.applyStyleOnLoad
        }
    },
};

/**
 * Create a new Popper.js instance
 * @class Popper
 * @param {HTMLElement} reference - The reference element used to position the popper
 * @param {HTMLElement} popper - The HTML element used as popper.
 * @param {Object} options
 * @param {String} options.placement=bottom
 *      Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -right),
 *      left(-start, -end)`
 *
 * @param {Boolean} options.gpuAcceleration=true
 *      When this property is set to true, the popper position will be applied using CSS3 translate3d, allowing the
 *      browser to use the GPU to accelerate the rendering.
 *      If set to false, the popper will be placed using `top` and `left` properties, not using the GPU.
 *
 * @param {Number} options.boundariesPadding=5
 *      Additional padding for the boundaries
 *
 * @param {Boolean} options.removeOnDestroy=false
 *      Set to true if you want to automatically remove the popper when you call the `destroy` method.
 *
 * @param {Object} options.modifiers
 *      List of functions used to modify the data before they are applied to the popper (see source code for default values)
 *
 * @param {Object} options.modifiers.arrow - Arrow modifier configuration
 * @param {HTMLElement|String} options.modifiers.arrow.element='[x-arrow]'
 *      The DOM Node used as arrow for the popper, or a CSS selector used to get the DOM node. It must be child of
 *      its parent Popper. Popper.js will apply to the given element the style required to align the arrow with its
 *      reference element.
 *      By default, it will look for a child node of the popper with the `x-arrow` attribute.
 *
 * @param {Object} options.modifiers.offset - Offset modifier configuration
 * @param {Number} options.modifiers.offset.offset=0
 *      Amount of pixels the popper will be shifted (can be negative).
 *
 * @param {Object} options.modifiers.preventOverflow - PreventOverflow modifier configuration
 * @param {Array} [options.modifiers.preventOverflow.priority=['left', 'right', 'top', 'bottom']]
 *      Priority used when Popper.js tries to avoid overflows from the boundaries, they will be checked in order,
 *      this means that the last one will never overflow
 * @param {Number} options.modifiers.preventOverflow.padding=5
 *      Amount of pixel used to define a minimum distance between the boundaries and the popper
 *      this makes sure the popper has always a little padding between the edges of its container.
 *
 * @param {Object} options.modifiers.flip - Flip modifier configuration
 * @param {String|Array} options.modifiers.flip.behavior='flip'
 *      The behavior used by the `flip` modifier to change the placement of the popper when the latter is trying to
 *      overlap its reference element. Defining `flip` as value, the placement will be flipped on
 *      its axis (`right - left`, `top - bottom`).
 *      You can even pass an array of placements (eg: `['right', 'left', 'top']` ) to manually specify
 *      how alter the placement when a flip is needed. (eg. in the above example, it would first flip from right to left,
 *      then, if even in its new placement, the popper is overlapping its reference element, it will be moved to top)
 * @param {String|Element} options.modifiers.flip.boundariesElement='viewport'
 *      The element which will define the boundaries of the popper position, the popper will never be placed outside
 *      of the defined boundaries (except if `keepTogether` is enabled)
 *
 * @param {Number} options.modifiers.flip.padding=5
 *      Amount of pixel used to define a minimum distance between the boundaries and the popper
 *      this makes sure the popper has always a little padding between the edges of its container.
 *
 * @return {Object} instance - The generated Popper.js instance
 */
export default class Popper {
    constructor(reference, popper, options = {}) {
        // make update() debounced, so that it only runs at most once-per-tick
        this.update = debounce(this.update.bind(this));
        // create a throttled version of update() that is scheduled based on UI updates
        this.scheduleUpdate = () => requestAnimationFrame(this.update);

        // init state
        this.state = {
            isDestroyed: false,
            isCreated: false,
        };

        // get reference and popper elements (allow jQuery wrappers)
        this.reference = reference.jquery ? reference[0] : reference;
        this.popper = popper.jquery ? popper[0] : popper;

        // with {} we create a new object with the options inside it
        this.options = Object.assign({}, DEFAULTS, options);

        // refactoring modifiers' list (Object => Array)
        this.modifiers = Object.keys(DEFAULTS.modifiers)
                               .map((name) => Object.assign({ name }, DEFAULTS.modifiers[name]));

        // assign default values to modifiers, making sure to override them with
        // the ones defined by user
        this.modifiers = this.modifiers.map((defaultConfig) => {
            const userConfig = (options.modifiers && options.modifiers[defaultConfig.name]) || {};
            const finalConfig = Object.assign({}, defaultConfig, userConfig);
            return finalConfig;
        });

        // add custom modifiers to the modifiers list
        if (options.modifiers) {
            this.options.modifiers = Object.assign({}, DEFAULTS.modifiers, options.modifiers);
            Object.keys(options.modifiers).forEach((name) => {
                // take in account only custom modifiers
                if (DEFAULTS.modifiers[name] === undefined) {
                    const modifier = options.modifiers[name];
                    modifier.name = name;
                    this.modifiers.push(modifier);
                }
            });
        }

        // sort the modifiers by order
        this.modifiers = this.modifiers.sort(sortModifiers)

        // modifiers have the ability to execute arbitrary code when Popper.js get inited
        // such code is executed in the same order of its modifier
        // they could add new properties to their options configuration
        // BE AWAARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
        this.modifiers.forEach((modifier) => {
            if (modifier.enabled && isFunction(modifier.onLoad)) {
                //              reference       popper       options       modifierOptions
                modifier.onLoad(this.reference, this.popper, this.options, modifier);
            }
        });

        // get the popper position type
        this.state.position = getPosition(this.reference);

        // determine how we should set the origin of offsets
        this.state.isParentTransformed = isTransformed(this.popper.parentNode);

        // fire the first update to position the popper in the right place
        this.update();

        // setup event listeners, they will take care of update the position in specific situations
        setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);

        // make it chainable
        return this;
    }

    //
    // Methods
    //

    /**
     * Updates the position of the popper, computing the new offsets and applying the new style
     * @method
     * @memberof Popper
     */
    update() {
        var data = {
            instance: this,
            styles: {},
            flipped: false,
        };

        // make sure to apply the popper position before any computation
        this.state.position = getPosition(this.reference);
        setStyle(this.popper, { position: this.state.position});

        // if popper is destroyed, don't perform any further update
        if (this.state.isDestroyed) { return; }

        // store placement inside the data object, modifiers will be able to edit `placement` if needed
        // and refer to originalPlacement to know the original value
        data.placement = this.options.placement;
        data.originalPlacement = this.options.placement;

        // compute the popper and reference offsets and put them inside data.offsets
        data.offsets = getOffsets(this.state, this.popper, this.reference, data.placement);

        // run the modifiers
        data = runModifiers(this.modifiers, data);

        // the first `update` will call `onCreate` callback
        // the other ones will call `onUpdate` callback
        if (!this.state.isCreated) {
            this.state.isCreated = true;
            if (isFunction(this.state.createCallback)) {
                this.state.createCallback(data);
            }
        } else if (isFunction(this.state.updateCallback)) {
            this.state.updateCallback(data);
        }
    }

    /**
     * If a function is passed, it will be executed after the initialization of popper with as first argument the Popper instance.
     * @method
     * @memberof Popper
     * @param {createCallback} callback
     */
    onCreate(callback) {
        // the createCallbacks return as first argument the popper instance
        this.state.createCallback = callback;
        return this;
    }

    /**
     * Callback called when the popper is created.
     * Access Popper.js instance with `data.instance`.
     * @callback createCallback
     * @static
     * @param {dataObject} data
     */

    /**
     * If a function is passed, it will be executed after each update of popper with as first argument the set of coordinates and informations
     * used to style popper and its arrow.
     * NOTE: it doesn't get fired on the first call of the `Popper.update()` method inside the `Popper` constructor!
     * @method
     * @memberof Popper
     * @param {updateCallback} callback
     */
    onUpdate(callback) {
        this.state.updateCallback = callback;
        return this;
    }

    /**
     * Callback called when the popper is updated, this callback is not called
     * on the initialization/creation of the popper, but only on subsequent
     * updates.
     * Access Popper.js instance with `data.instance`.
     * @callback updateCallback
     * @static
     * @param {dataObject} data
     */

    /**
     * Destroy the popper
     * @method
     * @memberof Popper
     */
    destroy() {
        this.state.isDestroyed = true;

        // touch DOM only if `applyStyle` modifier is enabled
        if (isModifierEnabled(this.modifiers, 'applyStyle')) {
            this.popper.removeAttribute('x-placement');
            this.popper.style.left = '';
            this.popper.style.position = '';
            this.popper.style.top = '';
            this.popper.style[getSupportedPropertyName('transform')] = '';
        }

        this.state = removeEventListeners(this.reference, this.state);

        // remove the popper if user explicity asked for the deletion on destroy
        // do not use `remove` because IE11 doesn't support it
        if (this.options.removeOnDestroy) {
            this.popper.parentNode.removeChild(this.popper);
        }
        return this;
    }

    /**
     * Collection of utilities useful when writing custom modifiers
     * @memberof Popper
     */
    static Utils = Utils;

    /**
     * List of accepted placements to use as values of the `placement` option
     * @memberof Popper
     */
     static placements = [
         'top',
         'top-start',
         'top-end',
         'right',
         'right-start',
         'right-end',
         'bottom',
         'bottom-start',
         'bottom-end',
         'left',
         'left-start',
         'left-end',
     ];

    /**
     * Default Popper.js options
     * @memberof Popper
     */
    Defaults = DEFAULTS;
}
<|endoftext|>


<commit_before>import wrap from './wrap.js';

const statementsWithBlocks = {
	IfStatement: 'consequent',
	ForStatement: 'body',
	ForInStatement: 'body',
	ForOfStatement: 'body',
	WhileStatement: 'body',
	DoWhileStatement: 'body',
	ArrowFunctionExpression: 'body'
};

export default class Node {
	constructor ( raw, parent ) {
		Object.defineProperties( this, {
			parent: { value: parent },
			program: { value: parent.program || parent },
			depth: { value: parent.depth + 1 },
			keys: { value: Object.keys( raw ) }
		});

		// special case – body-less if/for/while statements. TODO others?
		const type = statementsWithBlocks[ raw.type ];
		if ( type && raw[ type ].type !== 'BlockStatement' ) {
			const nonBlock = raw[ type ];

			// create a synthetic block statement, otherwise all hell
			// breaks loose when it comes to block scoping
			raw[ type ] = {
				start: nonBlock.start,
				end: nonBlock.end,
				type: 'BlockStatement',
				body: [ nonBlock ],
				synthetic: true
			};
		}

		for ( const key of this.keys ) {
			this[ key ] = wrap( raw[ key ], this );
		}

		this.program.magicString.addSourcemapLocation( this.start );
		this.program.magicString.addSourcemapLocation( this.end );
	}

	ancestor ( level ) {
		let node = this;
		while ( level-- ) {
			node = node.parent;
			if ( !node ) return null;
		}

		return node;
	}

	contains ( node ) {
		while ( node ) {
			if ( node === this ) return true;
			node = node.parent;
		}

		return false;
	}

	findLexicalBoundary () {
		return this.parent.findLexicalBoundary();
	}

	findNearest ( type ) {
		if ( typeof type === 'string' ) type = new RegExp( `^${type}$` );
		if ( type.test( this.type ) ) return this;
		return this.parent.findNearest( type );
	}

	findScope ( functionScope ) {
		return this.parent.findScope( functionScope );
	}

	getIndentation () {
		const lastLine = /\n(.+)$/.exec( this.program.magicString.original.slice( 0, this.start ) );
		return lastLine ? /^[ \t]*/.exec( lastLine[1] )[0] : '';
	}

	initialise ( transforms ) {
		for ( var key of this.keys ) {
			const value = this[ key ];

			if ( Array.isArray( value ) ) {
				value.forEach( node => node && node.initialise( transforms ) );
			} else if ( value && typeof value === 'object' ) {
				value.initialise( transforms );
			}
		}
	}

	toString () {
		return this.program.magicString.slice( this.start, this.end );
	}

	transpile ( code, transforms ) {
		for ( const key of this.keys ) {
			const value = this[ key ];

			if ( Array.isArray( value ) ) {
				value.forEach( node => node && node.transpile( code, transforms ) );
			} else if ( value && typeof value === 'object' ) {
				value.transpile( code, transforms );
			}
		}
	}
}
<commit_msg>much, much faster getIndentation<commit_after>import wrap from './wrap.js';

const statementsWithBlocks = {
	IfStatement: 'consequent',
	ForStatement: 'body',
	ForInStatement: 'body',
	ForOfStatement: 'body',
	WhileStatement: 'body',
	DoWhileStatement: 'body',
	ArrowFunctionExpression: 'body'
};

export default class Node {
	constructor ( raw, parent ) {
		Object.defineProperties( this, {
			parent: { value: parent },
			program: { value: parent.program || parent },
			depth: { value: parent.depth + 1 },
			keys: { value: Object.keys( raw ) },
			indentation: { value: undefined, writable: true }
		});

		// special case – body-less if/for/while statements. TODO others?
		const type = statementsWithBlocks[ raw.type ];
		if ( type && raw[ type ].type !== 'BlockStatement' ) {
			const nonBlock = raw[ type ];

			// create a synthetic block statement, otherwise all hell
			// breaks loose when it comes to block scoping
			raw[ type ] = {
				start: nonBlock.start,
				end: nonBlock.end,
				type: 'BlockStatement',
				body: [ nonBlock ],
				synthetic: true
			};
		}

		for ( const key of this.keys ) {
			this[ key ] = wrap( raw[ key ], this );
		}

		this.program.magicString.addSourcemapLocation( this.start );
		this.program.magicString.addSourcemapLocation( this.end );
	}

	ancestor ( level ) {
		let node = this;
		while ( level-- ) {
			node = node.parent;
			if ( !node ) return null;
		}

		return node;
	}

	contains ( node ) {
		while ( node ) {
			if ( node === this ) return true;
			node = node.parent;
		}

		return false;
	}

	findLexicalBoundary () {
		return this.parent.findLexicalBoundary();
	}

	findNearest ( type ) {
		if ( typeof type === 'string' ) type = new RegExp( `^${type}$` );
		if ( type.test( this.type ) ) return this;
		return this.parent.findNearest( type );
	}

	findScope ( functionScope ) {
		return this.parent.findScope( functionScope );
	}

	getIndentation () {
		if ( this.indentation === undefined ) {
			const source = this.program.magicString.original;
			let c = this.start;
			while ( c && source[c] !== '\n' ) c -= 1;

			this.indentation = '';

			while ( true ) {
				c += 1;
				const char = source[c];

				if ( char !== ' ' && char !== '\t' ) break;

				this.indentation += char;
			}
		}

		return this.indentation;
	}

	initialise ( transforms ) {
		for ( var key of this.keys ) {
			const value = this[ key ];

			if ( Array.isArray( value ) ) {
				value.forEach( node => node && node.initialise( transforms ) );
			} else if ( value && typeof value === 'object' ) {
				value.initialise( transforms );
			}
		}
	}

	toString () {
		return this.program.magicString.slice( this.start, this.end );
	}

	transpile ( code, transforms ) {
		for ( const key of this.keys ) {
			const value = this[ key ];

			if ( Array.isArray( value ) ) {
				value.forEach( node => node && node.transpile( code, transforms ) );
			} else if ( value && typeof value === 'object' ) {
				value.transpile( code, transforms );
			}
		}
	}
}
<|endoftext|>


<commit_before>;(function( factory ){
	if ( typeof module !== "undefined" && module && module.exports ) {
		module.exports = factory();

	} else if ( typeof define !== "function" ) {
		define( factory );

	} else {
		P = factory();
	}
})(function() {
	"use strict";

	var
		// linked list with head node - used as a queue of tasks
		// f: task, w: needed a tick, n: next node
		head = { f: null, w: false, n: null }, tail = head,

		// vars for tick re-usage
		nextNeedsTick = true, pendingTicks = 0, neededTicks = 0,

		channel, // MessageChannel
		requestTick, // requestTick( onTick, 0 ) is the only valid usage!

		// window or worker
		wow = ot(typeof window) && window || ot(typeof worker) && worker,

		toStr = head.toString,
		isArray;

	function onTick() {
		--pendingTicks;
		while ( head.n ) {
			head = head.n;
			if ( head.w ) {
				--neededTicks;
			}
			var f = head.f;
			head.f = null;
			f();
		}
		nextNeedsTick = true;
	}

	function runLater( f, couldThrow ) {
		if ( nextNeedsTick && ++neededTicks > pendingTicks ) {
			++pendingTicks;
			requestTick( onTick, 0 );
		};
		tail = tail.n = { f: f, w: nextNeedsTick, n: null };
		nextNeedsTick = couldThrow === true;
	}

	function ot( type ) {
		return type === "object" || type === "function";
	}

	function ft( type ) {
		return type === "function";
	}

	if ( ot(typeof process) && process && ft(typeof process.nextTick) ) {
		requestTick = process.nextTick;

	} else if ( wow && ft(typeof wow.setImmediate) ) {
		requestTick = function( cb ) {
			wow.setImmediate( cb );
		};

	} else if ( ft(typeof MessageChannel) ) {
		channel = new MessageChannel();
		channel.port1.onmessage = onTick;
		requestTick = function() {
			channel.port2.postMessage(0);
		};

	} else {
		requestTick = setTimeout;

		if ( wow && ot(typeof Image) && Image ) {
			(function(){
				var c = 0;

				var requestTickViaImage = function( cb ) {
					var img = new Image();
					img.onerror = cb;
					img.src = 'data:image/png,';
				};

				try {
					requestTickViaImage(function() {
						if ( --c === 0 ) {
							requestTick = requestTickViaImage;
						}
					});
					++c;
				} catch (e) {}

				c && setTimeout(function() {
					c = 0;
				}, 0);
			})();
		}
	}

	//__________________________________________________________________________

	isArray = Array.isArray || function( val ) {
		return !!val && toStr.call( val ) === "[object Array]";
	};

	function forEach( arr, cb ) {
		for ( var i = 0, l = arr.length; i < l; ++i ) {
			if ( i in arr ) {
				cb( arr[i], i );
			}
		}
	}

	function each( obj, cb ) {
		if ( isArray(obj) ) {
			forEach( obj, cb );
			return;
		}

		for ( var prop in obj ) {
			cb( obj[prop], prop );
		}
	}

	function P( val ) {
		if ( val instanceof Promise ) {
			return val;
		}

		var def = defer();
		def.resolve( val );
		return def.promise;
	}

	P.defer = defer;
	function defer() {
		var pending = [],
			rejected = false,
			promise = new Promise( then ),
			value;

		function then( onFulfilled, onRejected ) {
			var def = defer();

			function onReslved() {
				var func = rejected ? onRejected : onFulfilled;

				if ( typeof func === "function" ) {
					try {
						def.resolve( func( value ) );
					} catch ( ex ) {
						def.reject( ex );
					}

				} else if ( rejected ) {
					def.reject( value );

				} else {
					def.fulfill( value );
				}
			}

			if ( pending ) {
				pending.push( onReslved );

			} else {
				runLater( onReslved );
			}

			return def.promise;
		}

		function resolve( val ) {
			if ( pending ) {
				if ( val && typeof val.then === "function" ) {
					val.then( fulfill, reject );

				} else {
					fulfill( val );
				}
			}
		}

		function fulfill( val ) {
			if ( pending ) {
				promise.state = rejected ? "rejected" : "fulfilled";
				promise.value = value = val;
				forEach( pending, runLater );
				pending = null;
			}
		}

		function reject( error ) {
			if ( pending ) {
				rejected = true;
				fulfill( error );
			}
		}

		return {
			promise: promise,
			resolve: resolve,
			fulfill: fulfill,
			reject: reject
		};
	}

	function Promise( then ) {
		this.then = then;
		this.state = "pending";
		this.value = void 0;
	}

	Promise.prototype.done = function( cb, eb ) {
		var p = this;
		if ( cb || eb ) {
			p = p.then( cb, eb );
		}
		p.then(null, function( error ) {
			runLater(function() {
				if ( P.onerror ) {
					P.onerror( error );
				} else {
					throw error;
				}
			}, true);
		});
	};

	Promise.prototype.spread = function( cb, eb ) {
		return this.then(cb && function( values ) {
			return cb.apply( void 0, values );
		}, eb);
	};

	P.all = all;
	function all( promises ) {
		var waiting = 0;
		var def = defer();
		each(promises, function( promise, index ) {
			++waiting;
			P( promise ).then(function( value ) {
				promises[ index ] = value;
				if ( --waiting === 0 ) {
					def.fulfill( promises );
				}
			}, def.reject );
		});
		if ( waiting === 0 ) {
			def.fulfill( promises );
		}
		return def.promise;
	}

	P.allResolved = allResolved;
	function allResolved( promises ) {
		var waiting = 1;
		var def = defer();
		function callback() {
			if ( --waiting === 0 ) {
				def.fulfill( promise );
			}
		}
		each(promises, function( promise, index ) {
			++waiting;
			promises[ index ] = promise = P( promise );
			promise.then( callback, callback );
		});
		callback();
		return def.promise;
	}

	P.onerror = null;

	P.prototype = Promise.prototype;

	P.nextTick = function( f ) {
		runLater( f, true );
	};

	//P.runLater = runLater;

	return P;
});
<commit_msg>Make deferred.resolve always safe.<commit_after>;(function( factory ){
	if ( typeof module !== "undefined" && module && module.exports ) {
		module.exports = factory();

	} else if ( typeof define !== "function" ) {
		define( factory );

	} else {
		P = factory();
	}
})(function() {
	"use strict";

	var
		// linked list with head node - used as a queue of tasks
		// f: task, w: needed a tick, n: next node
		head = { f: null, w: false, n: null }, tail = head,

		// vars for tick re-usage
		nextNeedsTick = true, pendingTicks = 0, neededTicks = 0,

		channel, // MessageChannel
		requestTick, // requestTick( onTick, 0 ) is the only valid usage!

		// window or worker
		wow = ot(typeof window) && window || ot(typeof worker) && worker,

		toStr = head.toString,
		isArray;

	function onTick() {
		--pendingTicks;
		while ( head.n ) {
			head = head.n;
			if ( head.w ) {
				--neededTicks;
			}
			var f = head.f;
			head.f = null;
			f();
		}
		nextNeedsTick = true;
	}

	function runLater( f, couldThrow ) {
		if ( nextNeedsTick && ++neededTicks > pendingTicks ) {
			++pendingTicks;
			requestTick( onTick, 0 );
		};
		tail = tail.n = { f: f, w: nextNeedsTick, n: null };
		nextNeedsTick = couldThrow === true;
	}

	function ot( type ) {
		return type === "object" || type === "function";
	}

	function ft( type ) {
		return type === "function";
	}

	if ( ot(typeof process) && process && ft(typeof process.nextTick) ) {
		requestTick = process.nextTick;

	} else if ( wow && ft(typeof wow.setImmediate) ) {
		requestTick = function( cb ) {
			wow.setImmediate( cb );
		};

	} else if ( ft(typeof MessageChannel) ) {
		channel = new MessageChannel();
		channel.port1.onmessage = onTick;
		requestTick = function() {
			channel.port2.postMessage(0);
		};

	} else {
		requestTick = setTimeout;

		if ( wow && ot(typeof Image) && Image ) {
			(function(){
				var c = 0;

				var requestTickViaImage = function( cb ) {
					var img = new Image();
					img.onerror = cb;
					img.src = 'data:image/png,';
				};

				try {
					requestTickViaImage(function() {
						if ( --c === 0 ) {
							requestTick = requestTickViaImage;
						}
					});
					++c;
				} catch (e) {}

				c && setTimeout(function() {
					c = 0;
				}, 0);
			})();
		}
	}

	//__________________________________________________________________________

	isArray = Array.isArray || function( val ) {
		return !!val && toStr.call( val ) === "[object Array]";
	};

	function forEach( arr, cb ) {
		for ( var i = 0, l = arr.length; i < l; ++i ) {
			if ( i in arr ) {
				cb( arr[i], i );
			}
		}
	}

	function each( obj, cb ) {
		if ( isArray(obj) ) {
			forEach( obj, cb );
			return;
		}

		for ( var prop in obj ) {
			cb( obj[prop], prop );
		}
	}

	function P( val ) {
		if ( val instanceof Promise ) {
			return val;
		}

		var def = defer();
		def.resolve( val );
		return def.promise;
	}

	P.defer = defer;
	function defer() {
		var pending = [],
			rejected = false,
			promise = new Promise( then ),
			value;

		function then( onFulfilled, onRejected ) {
			var def = defer();

			function onReslved() {
				var func = rejected ? onRejected : onFulfilled;

				if ( typeof func === "function" ) {
					try {
						var val = func( value );
					} catch ( ex ) {
						def.reject( ex );
					}

					def.resolve( val );

				} else if ( rejected ) {
					def.reject( value );

				} else {
					def.fulfill( value );
				}
			}

			if ( pending ) {
				pending.push( onReslved );

			} else {
				runLater( onReslved );
			}

			return def.promise;
		}

		function resolve( val ) {
			if ( pending ) {
				if ( val && typeof val.then === "function" ) {
					try {
						val.then( fulfill, reject );
					} catch ( ex ) {
						reject( ex );
					}

				} else {
					fulfill( val );
				}
			}
		}

		function fulfill( val ) {
			if ( pending ) {
				promise.state = rejected ? "rejected" : "fulfilled";
				promise.value = value = val;
				forEach( pending, runLater );
				pending = null;
			}
		}

		function reject( error ) {
			if ( pending ) {
				rejected = true;
				fulfill( error );
			}
		}

		return {
			promise: promise,
			resolve: resolve,
			fulfill: fulfill,
			reject: reject
		};
	}

	function Promise( then ) {
		this.then = then;
		this.state = "pending";
		this.value = void 0;
	}

	Promise.prototype.done = function( cb, eb ) {
		var p = this;
		if ( cb || eb ) {
			p = p.then( cb, eb );
		}
		p.then(null, function( error ) {
			runLater(function() {
				if ( P.onerror ) {
					P.onerror( error );
				} else {
					throw error;
				}
			}, true);
		});
	};

	Promise.prototype.spread = function( cb, eb ) {
		return this.then(cb && function( values ) {
			return cb.apply( void 0, values );
		}, eb);
	};

	P.all = all;
	function all( promises ) {
		var waiting = 0;
		var def = defer();
		each(promises, function( promise, index ) {
			++waiting;
			P( promise ).then(function( value ) {
				promises[ index ] = value;
				if ( --waiting === 0 ) {
					def.fulfill( promises );
				}
			}, def.reject );
		});
		if ( waiting === 0 ) {
			def.fulfill( promises );
		}
		return def.promise;
	}

	P.allResolved = allResolved;
	function allResolved( promises ) {
		var waiting = 1;
		var def = defer();
		function callback() {
			if ( --waiting === 0 ) {
				def.fulfill( promise );
			}
		}
		each(promises, function( promise, index ) {
			++waiting;
			promises[ index ] = promise = P( promise );
			promise.then( callback, callback );
		});
		callback();
		return def.promise;
	}

	P.onerror = null;

	P.prototype = Promise.prototype;

	P.nextTick = function( f ) {
		runLater( f, true );
	};

	//P.runLater = runLater;

	return P;
});
<|endoftext|>