<commit_before>//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Handle world (aka scene+camera+renderer)
 *
 * @class youpla
 *
 * @param {THREE.Material} object an instance or an array of instance
*/
tQuery.World	= function(opts)
{
	// handle parameters
	opts	= opts	|| {};
	opts	= tQuery.extend(opts, {
		renderW		: window.innerWidth,
		renderH		: window.innerHeight,
		webGLNeeded	: true,
		autoRendering	: true,
		scene		: null,
		camera		: null,
		renderer	: null
	});
	this._opts	= opts;

	// update default world.
	// - TODO no sanity check ?
	// - not clear what to do with this...
	// - tQuery.world is the user world. like the camera controls
	console.assert( !tQuery.word );
	tQuery.world	= this;

	this._autoRendering	= true;

	// create a scene
	this._scene	= opts.scene	||(new THREE.Scene());

 	// create a camera in the scene
	if( !opts.camera ){
		this._camera	= new THREE.PerspectiveCamera(35, opts.renderW / opts.renderH, 0.01, 10000 );
		this._camera.position.set(0, 0, 3);
		this._scene.add(this._camera);
	}else{
		this._camera	= opts.camera;
	}

	// create the loop
	this._loop	= new tQuery.Loop();

	// hook the render function in this._loop
	this._loop.hookOnRender(this._$loopCb = function(){
		this.render();
	}.bind(this));

	// create a renderer
	if( opts.renderer ){
		this._renderer	= opts.renderer;
	}else if( tQuery.World.hasWebGL() ){
		this._renderer	= new THREE.WebGLRenderer({
			antialias		: true,	// to get smoother output
			preserveDrawingBuffer	: true	// to allow screenshot
		});
	}else if( !opts.webGLNeeded ){
		this._renderer	= new THREE.CanvasRenderer();
	}else{
		this._addGetWebGLMessage();
		throw new Error("WebGL required and not available")
	}
	this._renderer.setClearColorHex( 0xBBBBBB, 1 );
	this._renderer.setSize( opts.renderW, opts.renderH );
};

// make it pluginable
tQuery.pluginsInstanceOn(tQuery.World);

// make it eventable
tQuery.MicroeventMixin(tQuery.World.prototype)

tQuery.World.prototype.destroy	= function(){
	// microevent.js notification
	this.trigger('destroy');
	// unhook the render function in this._loop
	this._loop.hookOnRender(this._$loopCb);
	// destroy the loop
	this._loop.destroy();
	// remove this._cameraControls if needed
	this.removeCameraControls();
	// remove renderer element
	var parent	= this._renderer.domElement.parentElement;
	parent	&& parent.removeChild(this._renderer.domElement);

	// clear the global if needed
	if( tQuery.world === this )	tQuery.world = null;
}

//////////////////////////////////////////////////////////////////////////////////
//		WebGL Support							//
//////////////////////////////////////////////////////////////////////////////////

/**
 * true if webgl is available, false otherwise
*/
tQuery.World._hasWebGL	= (function(){
	// test from Detector.js
	try{
		return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' );
	} catch( e ){
		return false;
	}
})();

/**
 * @returns {Boolean} true if webgl is available, false otherwise
*/
tQuery.World.hasWebGL	= function(){
	return tQuery.World._hasWebGL;
};

/**
*/
tQuery.World.prototype._addGetWebGLMessage	= function(parent)
{
	parent	= parent || document.body;

	// message directly taken from Detector.js
	var domElement = document.createElement( 'div' );
	domElement.style.fontFamily = 'monospace';
	domElement.style.fontSize = '13px';
	domElement.style.textAlign = 'center';
	domElement.style.background = '#eee';
	domElement.style.color = '#000';
	domElement.style.padding = '1em';
	domElement.style.width = '475px';
	domElement.style.margin = '5em auto 0';
	domElement.innerHTML = window.WebGLRenderingContext ? [
		'Your graphics card does not seem to support WebGL.
',
		'Find out how to get it here.'
	].join( '\n' ) : [
		'Your browser does not seem to support WebGL.
',
		'Find out how to get it here.'
	].join( '\n' );

	parent.appendChild(domElement);
}

//////////////////////////////////////////////////////////////////////////////////
//		add/remove object3D						//
//////////////////////////////////////////////////////////////////////////////////

tQuery.World.prototype.setCameraControls	= function(control){
	if( this.hasCameraControls() )	this.removeCameraControls();
	this._cameraControls	= control;
	return this;	// for chained API
};

tQuery.World.prototype.removeCameraControls	= function(){
	if( this.hasCameraControls() === false )	return this;
	this._cameraControls	= undefined;
	return this;	// for chained API
};

tQuery.World.prototype.getCameraControls	= function(){
	return this._cameraControls;
};

tQuery.World.prototype.hasCameraControls	= function(){
	return this._cameraControls !== undefined ? true : false;
};

//////////////////////////////////////////////////////////////////////////////////
//		add/remove object3D						//
//////////////////////////////////////////////////////////////////////////////////

/**
 * add an object to the scene
 *
 * @param {tQuery.Object3D} object3D to add to the scene (THREE.Object3D is accepted)
*/
tQuery.World.prototype.add	= function(object3d)
{
	if( object3d instanceof tQuery.Object3D ){
		object3d.each(function(object3d){
			this._scene.add(object3d)
		}.bind(this));
	}else if( object3d instanceof THREE.Object3D ){
		this._scene.add(object3d)
	}else	console.assert(false, "invalid type");
	// for chained API
	return this;
}

/**
 * remove an object to the scene
 *
 * @param {tQuery.Object3D} object3D to add to the scene (THREE.Object3D is accepted)
*/
tQuery.World.prototype.remove	= function(object3d)
{
	if( object3d instanceof tQuery.Object3D ){
		object3d.each(function(object3d){
			this._scene.remove(object3d)
		}.bind(this));
	}else if( object3d instanceof THREE.Object3D ){
		this._scene.remove(object3d)
	}else	console.assert(false, "invalid type");
	// for chained API
	return this;
}

tQuery.World.prototype.appendTo	= function(domElement)
{
	domElement.appendChild(this._renderer.domElement)
	// for chained API
	return this;
}

/**
 * Start the loop
*/
tQuery.World.prototype.start	= function(){
	this._loop.start();
	return this;	// for chained API
}
/**
 * Stop the loop
*/
tQuery.World.prototype.stop	= function(){
	this._loop.stop();
	return this;	// for chained API
}

tQuery.World.prototype.loop	= function(){ return this._loop;	}

tQuery.World.prototype.tRenderer= function(){ return this._renderer;	}
tQuery.World.prototype.tCamera	= function(){ return this._camera;	}
tQuery.World.prototype.tScene	= function(){ return this._scene;	}

// backward compatible functions to remove
tQuery.World.prototype.renderer	= function(){  console.trace();console.warn("world.renderer() is ovbslete, use .tRenderer() instead");
						return this._renderer;	}
tQuery.World.prototype.camera	= function(){ console.trace();console.warn("world.camera() is obsolete, use .tCamerar() instead");
						return this._camera;	}
tQuery.World.prototype.scene	= function(){ console.trace();console.warn("world.scene() is obsolete, use .tScene() instead");
						return this._scene;	}
tQuery.World.prototype.get	= function(){ return this._scene;	}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

tQuery.World.prototype.autoRendering	= function(value){
	if(value === undefined)	return this._autoRendering;
	this._autoRendering	= value;
	return this;
}

tQuery.World.prototype.render	= function()
{
	// update the cameraControl
	if( this.hasCameraControls() )	this._cameraControls.update();
	// render the scene
	if( this._autoRendering )	this._renderer.render( this._scene, this._camera );
}
<commit_msg>beautifullation   js/tquery.world.js<commit_after>//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Handle world (aka scene+camera+renderer)
 *
 * @class youpla
 *
 * @param {THREE.Material} object an instance or an array of instance
*/
tQuery.World	= function(opts)
{
	// handle parameters
	opts	= opts	|| {};
	opts	= tQuery.extend(opts, {
		renderW		: window.innerWidth,
		renderH		: window.innerHeight,
		webGLNeeded	: true,
		autoRendering	: true,
		scene		: null,
		camera		: null,
		renderer	: null
	});
	this._opts	= opts;

	// update default world.
	// - TODO no sanity check ?
	// - not clear what to do with this...
	// - tQuery.world is the user world. like the camera controls
	console.assert( !tQuery.word );
	tQuery.world	= this;

	this._autoRendering	= true;

	// create a scene
	this._scene	= opts.scene	||(new THREE.Scene());

 	// create a camera in the scene
	if( !opts.camera ){
		this._camera	= new THREE.PerspectiveCamera(35, opts.renderW / opts.renderH, 0.01, 10000 );
		this._camera.position.set(0, 0, 3);
		this._scene.add(this._camera);
	}else{
		this._camera	= opts.camera;
	}

	// create the loop
	this._loop	= new tQuery.Loop();

	// hook the render function in this._loop
	this._loop.hookOnRender(this._$loopCb = function(){
		this.render();
	}.bind(this));

	// create a renderer
	if( opts.renderer ){
		this._renderer	= opts.renderer;
	}else if( tQuery.World.hasWebGL() ){
		this._renderer	= new THREE.WebGLRenderer({
			antialias		: true,	// to get smoother output
			preserveDrawingBuffer	: true	// to allow screenshot
		});
	}else if( !opts.webGLNeeded ){
		this._renderer	= new THREE.CanvasRenderer();
	}else{
		this._addGetWebGLMessage();
		throw new Error("WebGL required and not available")
	}
	this._renderer.setClearColorHex( 0xBBBBBB, 1 );
	this._renderer.setSize( opts.renderW, opts.renderH );
};

// make it pluginable
tQuery.pluginsInstanceOn(tQuery.World);

// make it eventable
tQuery.MicroeventMixin(tQuery.World.prototype)

tQuery.World.prototype.destroy	= function(){
	// microevent.js notification
	this.trigger('destroy');
	// unhook the render function in this._loop
	this._loop.hookOnRender(this._$loopCb);
	// destroy the loop
	this._loop.destroy();
	// remove this._cameraControls if needed
	this.removeCameraControls();
	// remove renderer element
	var parent	= this._renderer.domElement.parentElement;
	parent	&& parent.removeChild(this._renderer.domElement);

	// clear the global if needed
	if( tQuery.world === this )	tQuery.world = null;
}

//////////////////////////////////////////////////////////////////////////////////
//		WebGL Support							//
//////////////////////////////////////////////////////////////////////////////////

/**
 * true if webgl is available, false otherwise
*/
tQuery.World._hasWebGL	= (function(){
	// test from Detector.js
	try{
		return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' );
	} catch( e ){
		return false;
	}
})();

/**
 * @returns {Boolean} true if webgl is available, false otherwise
*/
tQuery.World.hasWebGL	= function(){
	return tQuery.World._hasWebGL;
};

/**
*/
tQuery.World.prototype._addGetWebGLMessage	= function(parent)
{
	parent	= parent || document.body;

	// message directly taken from Detector.js
	var domElement = document.createElement( 'div' );
	domElement.style.fontFamily	= 'monospace';
	domElement.style.fontSize	= '13px';
	domElement.style.textAlign	= 'center';
	domElement.style.background	= '#eee';
	domElement.style.color		= '#000';
	domElement.style.padding	= '1em';
	domElement.style.width		= '475px';
	domElement.style.margin		= '5em auto 0';
	domElement.innerHTML		= window.WebGLRenderingContext ? [
		'Your graphics card does not seem to support WebGL.
',
		'Find out how to get it here.'
	].join( '\n' ) : [
		'Your browser does not seem to support WebGL.
',
		'Find out how to get it here.'
	].join( '\n' );

	parent.appendChild(domElement);
}

//////////////////////////////////////////////////////////////////////////////////
//		add/remove object3D						//
//////////////////////////////////////////////////////////////////////////////////

tQuery.World.prototype.setCameraControls	= function(control){
	if( this.hasCameraControls() )	this.removeCameraControls();
	this._cameraControls	= control;
	return this;	// for chained API
};

tQuery.World.prototype.removeCameraControls	= function(){
	if( this.hasCameraControls() === false )	return this;
	this._cameraControls	= undefined;
	return this;	// for chained API
};

tQuery.World.prototype.getCameraControls	= function(){
	return this._cameraControls;
};

tQuery.World.prototype.hasCameraControls	= function(){
	return this._cameraControls !== undefined ? true : false;
};

//////////////////////////////////////////////////////////////////////////////////
//		add/remove object3D						//
//////////////////////////////////////////////////////////////////////////////////

/**
 * add an object to the scene
 *
 * @param {tQuery.Object3D} object3D to add to the scene (THREE.Object3D is accepted)
*/
tQuery.World.prototype.add	= function(object3d)
{
	if( object3d instanceof tQuery.Object3D ){
		object3d.each(function(object3d){
			this._scene.add(object3d)
		}.bind(this));
	}else if( object3d instanceof THREE.Object3D ){
		this._scene.add(object3d)
	}else	console.assert(false, "invalid type");
	// for chained API
	return this;
}

/**
 * remove an object to the scene
 *
 * @param {tQuery.Object3D} object3D to add to the scene (THREE.Object3D is accepted)
*/
tQuery.World.prototype.remove	= function(object3d)
{
	if( object3d instanceof tQuery.Object3D ){
		object3d.each(function(object3d){
			this._scene.remove(object3d)
		}.bind(this));
	}else if( object3d instanceof THREE.Object3D ){
		this._scene.remove(object3d)
	}else	console.assert(false, "invalid type");
	// for chained API
	return this;
}

tQuery.World.prototype.appendTo	= function(domElement)
{
	domElement.appendChild(this._renderer.domElement)
	// for chained API
	return this;
}

/**
 * Start the loop
*/
tQuery.World.prototype.start	= function(){
	this._loop.start();
	return this;	// for chained API
}
/**
 * Stop the loop
*/
tQuery.World.prototype.stop	= function(){
	this._loop.stop();
	return this;	// for chained API
}

tQuery.World.prototype.loop	= function(){ return this._loop;	}

tQuery.World.prototype.tRenderer= function(){ return this._renderer;	}
tQuery.World.prototype.tCamera	= function(){ return this._camera;	}
tQuery.World.prototype.tScene	= function(){ return this._scene;	}

// backward compatible functions to remove
tQuery.World.prototype.renderer	= function(){  console.trace();console.warn("world.renderer() is ovbslete, use .tRenderer() instead");
						return this._renderer;	}
tQuery.World.prototype.camera	= function(){ console.trace();console.warn("world.camera() is obsolete, use .tCamerar() instead");
						return this._camera;	}
tQuery.World.prototype.scene	= function(){ console.trace();console.warn("world.scene() is obsolete, use .tScene() instead");
						return this._scene;	}
tQuery.World.prototype.get	= function(){ return this._scene;	}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

tQuery.World.prototype.autoRendering	= function(value){
	if(value === undefined)	return this._autoRendering;
	this._autoRendering	= value;
	return this;
}

tQuery.World.prototype.render	= function()
{
	// update the cameraControl
	if( this.hasCameraControls() )	this._cameraControls.update();
	// render the scene
	if( this._autoRendering )	this._renderer.render( this._scene, this._camera );
}
<|endoftext|>


<commit_before>(function() {
     function config($stateProvider, $locationProvider) {
         $locationProvider
         .html5Mode({
             enabled: true,
             requireBase: false
         });
    $stateProvider
         .state('landing', {
            url: '/',
            templateUrl: '/templates/landing.html'
         });
         })
         .state('album', {
            url: '/album',
            templateUrl: '/templates/album.html'
         });
    angular
         .module('blocJams', ['ui.router'])
         .config(config);
 })();<commit_msg>fix syntax error on app.js<commit_after>(function() {
     function config($stateProvider, $locationProvider) {
         $locationProvider
         .html5Mode({
             enabled: true,
             requireBase: false
         });
    $stateProvider
         .state('landing', {
            url: '/',
            templateUrl: '/templates/landing.html'
         })
         .state('album', {
            url: '/album',
            templateUrl: '/templates/album.html'
         });
    angular
         .module('blocJams', ['ui.router'])
         .config(config);
 })();<|endoftext|>


<commit_before>var user;

/*
* start
*
* start is executed once the document is ready (equivalent to $('document').ready()), and
* the FB object is loaded. All document functions should be defined in this document,
* and functionality should start within this function.
*/
function start(FB) {
	console.log('Welcome to messaging.js!');
	console.log('start has been called with FB object: ' + FB);
	FB.api('/me', function(response) {
		user = response;
		console.log('Doing this in messaging.js, ' + response.name + '.');
		renderApp();
		var name = meta("page");
		var id = meta("page_id");

		showData(name, id);
	});
}

function showData(name, id) {
	if(name=="photos"){
		getPhotos(user.id, "photos", pic_data.photos, "/photos", "phot");
	}else if(name=="photos_tagged"){
		getPhotos(user.id, "photos_tagged", pic_data.photos_tagged, "/photos/uploaded", "photTag");
	}else if(name=="albums"){
		if(id!="undefined"){
			getAlbums(user.id,"albums", id);
		}else{
			getAlbums(user.id,"albums");
		}
	}
	console.log(id);

}

// Gets meta data by name from html page
function meta(name) {
    var tag = document.querySelector('meta[name=' + name + ']');
    if (tag != null)
        return tag.content;
    return '';
}

// Global variable to store picture info and album info
var pic_data = {"photos":{"next":null,"data":{},"num":0,"loadMore":null},"albums":{"next":null,"data":{},"num":0,"loadMore":null},"photos_tagged":{"next":null,"data":{},"num":0,"loadMore":null}};

// Global variable to store picture info albums
var album_data = {};

// Loads the preliminary info on the page when user first enters
// Function that shows folders at top bar
function renderApp() {
	console.log('renderApp was called');
	$('body').addClass('app_page');

	// var id = "/Sydney.Sprinkle";
	// var id = "/lunar.eclipse.71";
	var id =user.id;
	// var id = "/beverly.naigles";
	// var id = "/athyuttamre";
	// var id = "/arcyqwertyx";
	// var id = "/zachariah.u.medeiros";
	// var id = "/ham.hamington.5";
	$("#pic_container > div:not(#folders)").hide();
	$("#folders").empty();
	$("#folders").append("
Photos
");
	$("#folders").append("
Tagged Photos
");
	$("#folders").append("
Albums
");
}

// Displays albums
// Executed when "Albums" folder in nav bar is clicked
function showAlbum(name){
	var next = pic_data.albums.next;
	var data = pic_data.albums.data;
	$("#mainPhoto").empty();
	$("#mainPhoto").show();

	$('#mainPhoto').append(pic_data.albums.loadMore);
	for(var x in data){
		$("#mainPhoto").append("
"+data[x].name+"
");
		// onclick='goToAlbum(\""+x+"\")'
	}
}

// Displays thumbnail photos for a given folder
function showPics(name){
	var data = pic_data[name];
	var arr = pic_data[name].data;
	$("#mainPhoto").empty();
	$("#mainPhoto").show();
	$("#mainPhoto").append(data.loadMore);
	for(var x in arr){
		$("#mainPhoto").append("");
	}
}

// Gets photos from FB api
function getPhotos(id, toAppend, data, toUpload, toHide){
	FB.api(id+toUpload, function(response) {
		if(response!=undefined && response.data.length>0){
			var arr = response.data;
			var next = response.paging.next;
			data.next=next;
			data.loadMore="<button class='loadMore' onclick='loadPosts(\""+toAppend+"\")'>Load More</button>";
			// $('#'+toAppend).append("<button class='loadMore' onclick='loadPosts(\""+toAppend+"\")'>Load More</button>");
			var picPrev = null;
			for(var x in arr){
				arr[x].my_previous=picPrev;
				if(picPrev!=null){
					data.data[picPrev].my_next=arr[x].id;
				}
				picPrev=arr[x].id;

				data.data[arr[x].id]=arr[x];
			}
		}else{
			$("#"+toHide).hide();
			checkFull();
		}
		showPics(toAppend);
	});

}

// Displays albums when album page is loaded
function getAlbums(id,toAppend,albId){
	FB.api(id+'/albums', function(response) {
		if(response.data.length>0){
			var arr = response.data;
			var next = response.paging.next;
			pic_data.albums.next=next;
			if(next==undefined){
				pic_data.albums.loadMore="<button class='loadMore' onclick='loadPosts(\"albums\")'>DONENANANA</button>";
			}else{
				pic_data.albums.loadMore="<button class='loadMore' onclick='loadPosts(\"albums\")'>Load More</button>";
			}
			for(var x in arr){
				pic_data.albums.data[arr[x].id]=arr[x];
			}
		}else{
			$("#alb").hide();
			checkFull();
		}
		if(albId.length>0){
			// alert(albId);

			showAlbum(toAppend);
			goToAlbum(albId);
		}else{
			// alert("HI "+albId);

			showAlbum(toAppend);
		}
	});
}

// Checks if a given folder is empty (of the 3 at top of page)
// If empty, it takes it out, and if all of them are empty (the user had no pictures)
//	 displays a message saying the user has no photos
function checkFull(){
	var full = $("#phot").is(":visible");
	var full2 = $("#photTag").is(":visible");
	var full3 = $("#alb").is(":visible");
	if(!full&&!full2&&!full3){
		$("#container").append("
This user has no photos
");
	}
}

// Displays pictures from a specific album
function goToAlbum(dataID) {
	// alert(dataID);
	$("#mainPhoto").empty();
	$("#show").empty();
	var data = pic_data.albums.data[dataID];
	$("#mainPhoto").html("
No photos in this album
");
	if(album_data[data.id]==undefined){
		FB.api(dataID+'/photos', function(response) {
			var arr = response.data;
			var next = null;
			if(response.paging!=undefined){
				next = response.paging.next;
			}
			var obj = {"next":next,"pics":{},"button":"<button class='loadMore' onclick='loadAlbumPosts(\""+dataID+"\")'>Load More</button>"}
			$('#mainPhoto').append(obj.button);
			for(var x in arr){
				obj["pics"][arr[x].id]=arr[x];
				$("#mainPhoto").append("");
				$(".no_photos").hide();
			}
			album_data[data.id]=obj;
		});
	}else{
		$("#mainPhoto").append(album_data[dataID].button);
		for(var x in album_data[dataID]["pics"]){
			$("#mainPhoto").append("");
			$(".no_photos").hide();
		}
	}
}

// Displays photo individually with comments and like data
function goToPic(fold, id, folderID){
	var data = pic_data[fold]["data"][id];
	if(folderID!=undefined){
		data = album_data[folderID].pics[id];
	}
	$("#mainPhoto").empty();
	$("#mainPhoto").show();
	$("#mainPhoto").append("");

	// Adds comments to picture
	var comment = "
";
	if(data.comments!=undefined){
		for(var x in data.comments.data){
			comment+="
"+data.comments.data[x].from.name+" "+data.comments.data[x].message+"
";
		}
		if(data.comments.paging.next!=undefined){
			loadComments("#pictures > .comment_container",data.comments);
		}
		comment+="
";
		$("#mainPhoto").append(comment);
	}
}

// Displays individual pictures for albums
function loadAlbumPosts(dataID){
	var nextPage = album_data[dataID].next;
	if(nextPage!=undefined&&nextPage!=null){
		$.get(nextPage,function (response){
			for(var pic in response.data){
				album_data[dataID]["pics"][response.data[pic].id]=response.data[pic];
				$("#mainPhoto").append("");
			}
			if(response.paging!=undefined && response.paging.next!=undefined){
				album_data[dataID].next=response.paging.next;
			}else{
				album_data[dataID].next=null;
				$("#mainPhoto > .loadMore").html("DONENANANA");
			}

		},"json");
	}else{
		$("#mainPhoto > .loadMore").html("DONENANANA");
	}
}

// Displays comments for a given picture
function loadComments(toAppend, data){
	$.get(data.paging.next,function (response){
		for(var pic in response.data){
			data.data.push(response.data[pic]);
			$("#mainPhoto").append("
"+response.data[pic].from.name+" "+response.data[pic].message+"
");
		}
		data.paging.next=response.paging.next;
		if(response.paging.next!=undefined){
			loadComments(toAppend,data);
		}
	},"json");
}

// Displays individual pictures
function loadPosts(toAppend){
	var nextPage = pic_data[toAppend].next;
	if(toAppend!="photos"&&toAppend!="photos_tagged"){
		nextPage = album_data[dataID].next;
	}
	if(nextPage!=undefined&&nextPage!=null){
		$.get(nextPage,function (response){
			for(var pic in response.data){
				if(toAppend=="photos"||toAppend=="photos_tagged"){
					pic_data[toAppend].data[response.data[pic].id]=response.data[pic];
					$("#mainPhoto").append("");
				}else{
					album_data[dataID]["pics"][response.data[pic].id]=response.data[pic];
					$("#mainPhoto").append("");
				}
			}
			if(response.paging!=undefined&&response.paging.next!=undefined){
				if(toAppend=="photos"||toAppend=="photos_tagged"){
					pic_data[toAppend].next=response.paging.next;
				}else{
					album_data[dataID].next=response.paging.next;
				}
			}else{
				$("#mainPhoto.loadMore").html("DONENANANA");
			}
		},"json");
	}else{
		$("#mainPhoto > .loadMore").html("DONENANANA");
	}
}<commit_msg>Photos updated2<commit_after>var user;
/*
* start
*
* start is executed once the document is ready (equivalent to $('document').ready()), and
* the FB object is loaded. All document functions should be defined in this document,
* and functionality should start within this function.
*/
function start(FB) {
	console.log('Welcome to messaging.js!');
	console.log('start has been called with FB object: ' + FB);
	FB.api('/me', function(response) {
		user = response;
		console.log('Doing this in messaging.js, ' + response.name + '.');
		renderApp();
		var name = meta("page");
		var id = meta("page_id");

		showData(name, id);
	});
}

// Takes meta data and displays correct info
function showData(name, id) {
	if(name=="photos"){
		getPhotos(user.id, "photos", pic_data.photos, "/photos", "phot");
	}else if(name=="photos_tagged"){
		getPhotos(user.id, "photos_tagged", pic_data.photos_tagged, "/photos/uploaded", "photTag");
	}else if(name=="albums"){
		if(id!="undefined"){
			getAlbums(user.id,"albums", id);
		}else{
			getAlbums(user.id,"albums");
		}
	}
}

// Gets meta data by name from html page
function meta(name) {
    var tag = document.querySelector('meta[name=' + name + ']');
    if (tag != null)
        return tag.content;
    return '';
}

// Global variable to store picture info and album info
var pic_data = {"photos":{"next":null,"data":{},"num":0,"loadMore":null},"albums":{"next":null,"data":{},"num":0,"loadMore":null},"photos_tagged":{"next":null,"data":{},"num":0,"loadMore":null}};

// Global variable to store picture info albums
var album_data = {};

// Loads the preliminary info on the page when user first enters
// Function that shows folders at top bar
function renderApp() {
	console.log('renderApp was called');
	$('body').addClass('app_page');

	// var id = "/Sydney.Sprinkle";
	// var id = "/lunar.eclipse.71";
	var id =user.id;
	// var id = "/beverly.naigles";
	// var id = "/athyuttamre";
	// var id = "/arcyqwertyx";
	// var id = "/zachariah.u.medeiros";
	// var id = "/ham.hamington.5";
	$("#pic_container > div:not(#folders)").hide();
	$("#folders").empty();
	$("#folders").append("
Photos
");
	$("#folders").append("
Tagged Photos
");
	$("#folders").append("
Albums
");
}

// Displays albums
// Executed when "Albums" folder in nav bar is clicked
function showAlbum(name){
	var next = pic_data.albums.next;
	var data = pic_data.albums.data;
	$("#mainPhoto").empty();
	$("#mainPhoto").show();

	$('#mainPhoto').append(pic_data.albums.loadMore);
	for(var x in data){
		$("#mainPhoto").append("
"+data[x].name+"
");
	}
}

// Displays thumbnail photos for a given folder
function showPics(name){
	var data = pic_data[name];
	var arr = pic_data[name].data;
	$("#mainPhoto").empty();
	$("#mainPhoto").show();
	$("#mainPhoto").append(data.loadMore);
	for(var x in arr){
		$("#mainPhoto").append("");
	}
}

// Gets photos from FB api
function getPhotos(id, toAppend, data, toUpload, toHide){
	FB.api(id+toUpload, function(response) {
		if(response!=undefined && response.data.length>0){
			var arr = response.data;
			var next = response.paging.next;
			data.next=next;
			data.loadMore="<button class='loadMore' onclick='loadPosts(\""+toAppend+"\")'>Load More</button>";
			var picPrev = null;
			for(var x in arr){
				arr[x].my_previous=picPrev;
				if(picPrev!=null){
					data.data[picPrev].my_next=arr[x].id;
				}
				picPrev=arr[x].id;

				data.data[arr[x].id]=arr[x];
			}
		}else{
			$("#"+toHide).hide();
			checkFull();
		}
		showPics(toAppend);
	});

}

// Displays albums when album page is loaded
function getAlbums(id,toAppend,albId){
	FB.api(id+'/albums', function(response) {
		if(response.data.length>0){
			var arr = response.data;
			var next = response.paging.next;
			pic_data.albums.next=next;
			if(next==undefined){
				pic_data.albums.loadMore="<button class='loadMore' onclick='loadPosts(\"albums\")'>DONENANANA</button>";
			}else{
				pic_data.albums.loadMore="<button class='loadMore' onclick='loadPosts(\"albums\")'>Load More</button>";
			}
			for(var x in arr){
				pic_data.albums.data[arr[x].id]=arr[x];
			}
		}else{
			$("#alb").hide();
			checkFull();
		}
		if(albId.length>0){
			showAlbum(toAppend);
			goToAlbum(albId);
		}else{
			showAlbum(toAppend);
		}
	});
}

// Checks if a given folder is empty (of the 3 at top of page)
// If empty, it takes it out, and if all of them are empty (the user had no pictures)
//	 displays a message saying the user has no photos
function checkFull(){
	var full = $("#phot").is(":visible");
	var full2 = $("#photTag").is(":visible");
	var full3 = $("#alb").is(":visible");
	if(!full&&!full2&&!full3){
		$("#container").append("
This user has no photos
");
	}
}

// Displays pictures from a specific album
function goToAlbum(dataID) {
	$("#mainPhoto").empty();
	$("#show").empty();
	var data = pic_data.albums.data[dataID];
	$("#mainPhoto").html("
No photos in this album
");
	if(album_data[data.id]==undefined){
		FB.api(dataID+'/photos', function(response) {
			var arr = response.data;
			var next = null;
			if(response.paging!=undefined){
				next = response.paging.next;
			}
			var obj = {"next":next,"pics":{},"button":"<button class='loadMore' onclick='loadAlbumPosts(\""+dataID+"\")'>Load More</button>"}
			$('#mainPhoto').append(obj.button);
			for(var x in arr){
				obj["pics"][arr[x].id]=arr[x];
				$("#mainPhoto").append("");
				$(".no_photos").hide();
			}
			album_data[data.id]=obj;
		});
	}else{
		$("#mainPhoto").append(album_data[dataID].button);
		for(var x in album_data[dataID]["pics"]){
			$("#mainPhoto").append("");
			$(".no_photos").hide();
		}
	}
}

// Displays photo individually with comments and like data
function goToPic(fold, id, folderID){
	var data = pic_data[fold]["data"][id];
	if(folderID!=undefined){
		data = album_data[folderID].pics[id];
	}
	$("#mainPhoto").empty();
	$("#mainPhoto").show();
	$("#mainPhoto").append("");

	// Adds comments to picture
	var comment = "
";
	if(data.comments!=undefined){
		for(var x in data.comments.data){
			comment+="
"+data.comments.data[x].from.name+" "+data.comments.data[x].message+"
";
		}
		if(data.comments.paging.next!=undefined){
			loadComments("#pictures > .comment_container",data.comments);
		}
		comment+="
";
		$("#mainPhoto").append(comment);
	}
}

// Displays individual pictures for albums
function loadAlbumPosts(dataID){
	var nextPage = album_data[dataID].next;
	if(nextPage!=undefined&&nextPage!=null){
		$.get(nextPage,function (response){
			for(var pic in response.data){
				album_data[dataID]["pics"][response.data[pic].id]=response.data[pic];
				$("#mainPhoto").append("");
			}
			if(response.paging!=undefined && response.paging.next!=undefined){
				album_data[dataID].next=response.paging.next;
			}else{
				album_data[dataID].next=null;
				$("#mainPhoto > .loadMore").html("DONENANANA");
			}

		},"json");
	}else{
		$("#mainPhoto > .loadMore").html("DONENANANA");
	}
}

// Displays comments for a given picture
function loadComments(toAppend, data){
	$.get(data.paging.next,function (response){
		for(var pic in response.data){
			data.data.push(response.data[pic]);
			$("#mainPhoto").append("
"+response.data[pic].from.name+" "+response.data[pic].message+"
");
		}
		data.paging.next=response.paging.next;
		if(response.paging.next!=undefined){
			loadComments(toAppend,data);
		}
	},"json");
}

// Displays individual pictures
function loadPosts(toAppend){
	var nextPage = pic_data[toAppend].next;
	if(toAppend!="photos"&&toAppend!="photos_tagged"){
		nextPage = album_data[dataID].next;
	}
	if(nextPage!=undefined&&nextPage!=null){
		$.get(nextPage,function (response){
			for(var pic in response.data){
				if(toAppend=="photos"||toAppend=="photos_tagged"){
					pic_data[toAppend].data[response.data[pic].id]=response.data[pic];
					$("#mainPhoto").append("");
				}else{
					album_data[dataID]["pics"][response.data[pic].id]=response.data[pic];
					$("#mainPhoto").append("");
				}
			}
			if(response.paging!=undefined&&response.paging.next!=undefined){
				if(toAppend=="photos"||toAppend=="photos_tagged"){
					pic_data[toAppend].next=response.paging.next;
				}else{
					album_data[dataID].next=response.paging.next;
				}
			}else{
				$("#mainPhoto.loadMore").html("DONENANANA");
			}
		},"json");
	}else{
		$("#mainPhoto > .loadMore").html("DONENANANA");
	}
}<|endoftext|>


<commit_before>
var Map = function(parentDiv) {

    var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png');

    var osmCycle = L.tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png');
    var osmCycleTransport = L.tileLayer('http://{s}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png');
    var toner = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png');
    var watercolor = L.tileLayer('http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg');

    this.layerPokestops = new L.LayerGroup();
    this.layerCatches = new L.LayerGroup();
    this.layerPath = new L.LayerGroup();

    this.map = L.map(parentDiv, {
        layers: [osm, this.layerPath, this.layerCatches, this.layerPokestops]
    });

   var baseLayers = {
        "OpenStreetMap": osm,
        "OpenCycleMap": osmCycle,
        "OpenCycleMap Transport": osmCycleTransport,
        "Toner": toner,
        "Watercolor": watercolor,
    };
    var overlays = {
        "Path": this.layerPath,
        "Pokestops": this.layerPokestops,
        "Catches": this.layerCatches
    };

    L.control.layers(baseLayers, overlays).addTo(this.map);

    this.path = null;

    this.steps = [];
    this.catches = [];
    this.pokestops = [];
    this.availablePokestops = [];
    this.pokemonList = [];
};

Map.prototype.saveContext = function() {
    sessionStorage.setItem("available", true);
    sessionStorage.setItem("steps", JSON.stringify(this.steps));
    sessionStorage.setItem("catches", JSON.stringify(this.catches));
    sessionStorage.setItem("pokestops", JSON.stringify(this.pokestops));
}

Map.prototype.loadContext = function() {
    try {
        if (sessionStorage.getItem("available")) {
            console.log("Load data from storage to restore session");

            this.steps = JSON.parse(sessionStorage.getItem("steps")) || [];
            this.catches = JSON.parse(sessionStorage.getItem("catches")) || [];
            this.pokestops = JSON.parse(sessionStorage.getItem("pokestops")) || [];

            this.initPath();

            for (var i = 0; i < this.catches.length; i++) {
                var pt = this.catches[i];
                var icon = L.icon({ iconUrl: `./assets/pokemon/${pt.id}.png`, iconSize: [45, 45]});
                L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.map).bindPopup(`${pt.name} (lvl ${pt.lvl})`);
            }
            for (var i = 0; i < this.pokestop.length; i++) {
                var pt = this.pokestop[i];
                var icon = L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]});
                L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.map).bindPopup(pt.name);
            }
        }
    } catch(err) {}
}

Map.prototype.initPath = function() {
    if (this.path != null) return true;
    if (this.steps.length < 2) return false;

    console.log("Init path and markers.");
    $(".loading").hide();

    this.map.setView([this.steps[0].lat, this.steps[0].lng], 16);

    var pts = Array.from(this.steps, pt => L.latLng(pt.lat, pt.lng));
    this.path = L.polyline(pts, { color: 'red' }).addTo(this.layerPath);

    var last = this.steps.pop();
    this.me = L.marker([last.lat, last.lng]).addTo(this.map).bindPopup(`${last.lat},${last.lng}`);

    return true;
}

Map.prototype.addToPath = function(pt) {
    if (this.initPath()) {
        var latLng = L.latLng(pt.lat, pt.lng);
        this.path.addLatLng(latLng);
        this.me.setLatLng(latLng).getPopup().setContent(`${pt.lat},${pt.lng}`);
        if (global.config.followPlayer) {
            this.map.panTo(latLng);
        }
    }
    this.steps.push(pt);
}

Map.prototype.addCatch = function(pt) {
    if (!pt.lat) {
        if (this.steps.length > 0) {
            var pos = this.steps.pop();
            pt.lat = pos.lat;
            pt.lng = pos.lng;
        } else {
            // no position to pin to, abort
            return;
        }
    }

    var pkm = `${pt.name} (lvl ${pt.lvl})`;
    console.log("Catch " + pkm);

    this.catches.push(pt);

    var icon = L.icon({ iconUrl: `./assets/pokemon/${pt.id}.png`, iconSize: [40, 40]});
    L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.layerCatches).bindPopup(pkm);
}

Map.prototype.addVisitedPokestop = function(pt) {
    if (!pt.lat) return;

    console.log("Pokestop visited.");

    this.pokestops.push(pt);

    var ps = this.availablePokestops.find(ps => ps.id == pt.id);
    if (ps) {
        ps.marker.setIcon(L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]}));
        ps.marker.bindPopup(pt.name);
    } else {
        var icon = L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]});
        L.marker([pt.lat, pt.lng], {icon: icon}).bindPopup(pt.name).addTo(this.layerPokestops);
    }
}

Map.prototype.addPokestops = function(forts) {
    for(var i = 0; i < forts.length; i++) {
        var pt = forts[i];
        var ps = this.availablePokestops.find(ps => ps.id == pt.id);
        if (!ps) {
            var icon = L.icon({ iconUrl: `./assets/img/pokestop_available.png`, iconSize: [30, 50]});
            pt.marker = L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.layerPokestops);
            this.availablePokestops.push(pt);
        }
    }
}

Map.prototype.displayPokemonList = function(all, sortBy) {
    console.log("Pokemon list");
    this.pokemonList = all || this.pokemonList;
    if (sortBy) {
        this.pokemonList = this.pokemonList.sort((p1, p2) => p2[sortBy] - p1[sortBy]);
    }
    var div = $(".inventory .data");
    div.html(``);
    this.pokemonList.forEach(function(elt) {
        div.append(`

                CP: ${elt.cp} | IV: ${elt.iv}%

                ${elt.name}

        `);
    });
    $(".pokemonsort").show();
    $(".inventory").show();
}

Map.prototype.displayEggsList = function(eggs) {
    console.log("Eggs list");
    var div = $(".inventory .data")
    div.html("");
    eggs.forEach(function(elt) {
        div.append(`

                ${elt.doneDist.toFixed(1)} / ${elt.totalDist.toFixed(1)} km

        `);
    });
    $(".inventory").show();
}<commit_msg>try to show map earlier<commit_after>
var Map = function(parentDiv) {

    var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png');

    var osmCycle = L.tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png');
    var osmCycleTransport = L.tileLayer('http://{s}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png');
    var toner = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png');
    var watercolor = L.tileLayer('http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg');

    this.layerPokestops = new L.LayerGroup();
    this.layerCatches = new L.LayerGroup();
    this.layerPath = new L.LayerGroup();

    this.map = L.map(parentDiv, {
        layers: [osm, this.layerPath, this.layerCatches, this.layerPokestops]
    });

   var baseLayers = {
        "OpenStreetMap": osm,
        "OpenCycleMap": osmCycle,
        "OpenCycleMap Transport": osmCycleTransport,
        "Toner": toner,
        "Watercolor": watercolor,
    };
    var overlays = {
        "Path": this.layerPath,
        "Pokestops": this.layerPokestops,
        "Catches": this.layerCatches
    };

    L.control.layers(baseLayers, overlays).addTo(this.map);

    this.path = null;

    this.steps = [];
    this.catches = [];
    this.pokestops = [];
    this.availablePokestops = [];
    this.pokemonList = [];
};

Map.prototype.saveContext = function() {
    sessionStorage.setItem("available", true);
    sessionStorage.setItem("steps", JSON.stringify(this.steps));
    sessionStorage.setItem("catches", JSON.stringify(this.catches));
    sessionStorage.setItem("pokestops", JSON.stringify(this.pokestops));
}

Map.prototype.loadContext = function() {
    try {
        if (sessionStorage.getItem("available")) {
            console.log("Load data from storage to restore session");

            this.steps = JSON.parse(sessionStorage.getItem("steps")) || [];
            this.catches = JSON.parse(sessionStorage.getItem("catches")) || [];
            this.pokestops = JSON.parse(sessionStorage.getItem("pokestops")) || [];

            this.initPath();

            for (var i = 0; i < this.catches.length; i++) {
                var pt = this.catches[i];
                var icon = L.icon({ iconUrl: `./assets/pokemon/${pt.id}.png`, iconSize: [45, 45]});
                L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.map).bindPopup(`${pt.name} (lvl ${pt.lvl})`);
            }
            for (var i = 0; i < this.pokestop.length; i++) {
                var pt = this.pokestop[i];
                var icon = L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]});
                L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.map).bindPopup(pt.name);
            }
        }
    } catch(err) {}
}

Map.prototype.initPath = function() {
    if (this.path != null) return true;
    if (this.steps.length == 1) {
        this.map.setView([this.steps[0].lat, this.steps[0].lng], 16);
        $(".loading").hide();
        return false;
    }

    var pts = Array.from(this.steps, pt => L.latLng(pt.lat, pt.lng));
    this.path = L.polyline(pts, { color: 'red' }).addTo(this.layerPath);

    var last = this.steps.pop();
    this.me = L.marker([last.lat, last.lng]).addTo(this.map).bindPopup(`${last.lat},${last.lng}`);

    return true;
}

Map.prototype.addToPath = function(pt) {
    this.steps.push(pt);
    if (this.initPath()) {
        var latLng = L.latLng(pt.lat, pt.lng);
        this.path.addLatLng(latLng);
        this.me.setLatLng(latLng).getPopup().setContent(`${pt.lat},${pt.lng}`);
        if (global.config.followPlayer) {
            this.map.panTo(latLng);
        }
    }
}

Map.prototype.addCatch = function(pt) {
    if (!pt.lat) {
        if (this.steps.length > 0) {
            var pos = this.steps.pop();
            pt.lat = pos.lat;
            pt.lng = pos.lng;
        } else {
            // no position to pin to, abort
            return;
        }
    }

    var pkm = `${pt.name} (lvl ${pt.lvl})`;
    console.log("Catch " + pkm);

    this.catches.push(pt);

    var icon = L.icon({ iconUrl: `./assets/pokemon/${pt.id}.png`, iconSize: [40, 40]});
    L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.layerCatches).bindPopup(pkm);
}

Map.prototype.addVisitedPokestop = function(pt) {
    if (!pt.lat) return;

    console.log("Pokestop visited.");

    this.pokestops.push(pt);

    var ps = this.availablePokestops.find(ps => ps.id == pt.id);
    if (ps) {
        ps.marker.setIcon(L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]}));
        ps.marker.bindPopup(pt.name);
    } else {
        var icon = L.icon({ iconUrl: `./assets/img/pokestop.png`, iconSize: [30, 50]});
        L.marker([pt.lat, pt.lng], {icon: icon}).bindPopup(pt.name).addTo(this.layerPokestops);
    }
}

Map.prototype.addPokestops = function(forts) {
    for(var i = 0; i < forts.length; i++) {
        var pt = forts[i];
        var ps = this.availablePokestops.find(ps => ps.id == pt.id);
        if (!ps) {
            var icon = L.icon({ iconUrl: `./assets/img/pokestop_available.png`, iconSize: [30, 50]});
            pt.marker = L.marker([pt.lat, pt.lng], {icon: icon}).addTo(this.layerPokestops);
            this.availablePokestops.push(pt);
        }
    }
}

Map.prototype.displayPokemonList = function(all, sortBy) {
    console.log("Pokemon list");
    this.pokemonList = all || this.pokemonList;
    if (sortBy) {
        this.pokemonList = this.pokemonList.sort((p1, p2) => p2[sortBy] - p1[sortBy]);
    }
    var div = $(".inventory .data");
    div.html(``);
    this.pokemonList.forEach(function(elt) {
        div.append(`

                CP: ${elt.cp} | IV: ${elt.iv}%

                ${elt.name}

        `);
    });
    $(".pokemonsort").show();
    $(".inventory").show();
}

Map.prototype.displayEggsList = function(eggs) {
    console.log("Eggs list");
    var div = $(".inventory .data")
    div.html("");
    eggs.forEach(function(elt) {
        div.append(`

                ${elt.doneDist.toFixed(1)} / ${elt.totalDist.toFixed(1)} km

        `);
    });
    $(".inventory").show();
}<|endoftext|>


<commit_before>define(
    ["js/ui/View", "js/core/Template", "js/core/List", "js/core/Bindable", "underscore"], function (View, Template, List, Bindable, _) {
        return View.inherit({
            defaults: {
                tagName: "div",
                items: null,
                itemKey: 'item',
                indexKey: 'index',
                keyPath: null
            },

            $classAttributes: [
                'keyPath', 'itemKey', 'indexKey'
            ],

            $defaultTemplateName: 'item',

            ctor: function(){
                this.callBase();

                this.bind('items','sort', this._onSort, this);
                this.bind('items','reset', this._onReset, this);
                this.bind('items','add', this._onItemAdd, this);
                this.bind('items','remove', this._onItemRemove, this);
            },
            /***
             * Returns true if items are available
             */
            hasItems: function () {
                if (this.$.items) {
                    return this.$.items.length;
                }
                return 0;
            }.on('items'),

            render: function () {
                if (!this.isRendered()) {
                    this.$renderedItems = [];
                    this.$renderedItemsMap = {};
                }
                return this.callBase();
            },
            /***
             * Renders the given items
             * @param items
             * @private
             */
            _renderItems: function (items) {
                if(!items){
                    this._innerRenderItems([]);
                }else if (items instanceof List) {
                    this._innerRenderItems(items.$items);
                } else if (_.isArray(items)) {
                    this._innerRenderItems(items);
                }
            },
            /***
             * This method is called when the sort event is fired,
             * It reorders the items in the list
             * @param [js.core.Event] event
             * @private
             */
            _onSort: function (event) {
                if (this.isRendered()) {
                    var item, c;
                    for (var i = 0; i < event.$.items.length; i++) {
                        item = event.$.items[i];
                        c = this.getComponentForItem(item);
                        this.$el.removeChild(c.$el);
                        this.$el.appendChild(c.$el);
                    }
                }
            },
            _onReset: function (e) {
                if(this.isRendered()){
                    this._innerRenderItems(e.$.items);
                }
            },

            _onItemAdd: function (e) {
                if(this.isRendered()){
                    this._innerRenderItem(e.$.item, e.$.index);
                }
            },

            _onItemRemove: function (e) {
                if(this.isRendered()){
                    this._removeRenderedItem(e.$.item);
                }
            },
            /**
             * Inner render method for a list of items
             * All rendered items will be removed and destroyed before rendering
             * @param {Array} items[]
             * @private
             */
            _innerRenderItems: function (items) {
                var c;
                if (this.$renderedItems) {
                    for (var j = this.$renderedItems.length - 1; j >= 0; j--) {
                        c = this.$renderedItems[j];
                        this.removeChild(c.component);
                        c.component.destroy();
                    }
                }
                if(this.$renderedItemsMap){
                    for(var key in this.$renderedItemsMap){
                        if(this.$renderedItemsMap.hasOwnProperty(key)){
                            c = this.$renderedItemsMap[key];
                            this.removeChild(c);
                            c.destroy();
                        }
                    }
                }
                this.$renderedItems = [];
                this.$renderedItemsMap = {};
                for (var i = 0; i < items.length; i++) {
                    this._innerRenderItem(items[i], i);
                }

            },
            /***
             * Creates a component based on the template for a given item
             * @param {Object} item
             * @param {Number} index
             * @return {js.core.Component} component
             * @private
             */
            _createComponentForItem: function (item, index) {
                var attr = {};
                attr[this._getItemKey()] = item;
                attr[this._getIndexKey()] = index;
                var component = this.$templates['item'].createComponents(attr)[0];
                component.$classAttributes.push(this.$.itemKey, this.$.indexKey);
                return component;
            },
            /***
             * Caches the component to a given item
             * @param {Object} item
             * @param {js.core.Component} component
             * @return {js.core.Component} returns the component
             * @private
             */
            _cacheComponentForItem: function(item,component){
                var key = this._getKeyForItem(item);
                if (key) {
                    this.$renderedItemsMap[key] = component;
                } else {
                    // add to rendered item map
                    this.$renderedItems.push({
                        item: item,
                        component: component
                    });
                }
                return component;
            },
            /***
             * Calculates a cache key for a given item.
             * If a keyPath is set, it will return the value of the path
             * Otherwise if the item is a {js.core.Bindable} it will return the $cid
             * If no keyPath is set and it's an object it will return null;
             *
             * @param item
             * @return {*}
             * @private
             */
            _getKeyForItem: function(item){
                if (item instanceof Bindable) {
                    var key;
                    if (this.$.keyPath) {
                        return item.get(this.$.keyPath);
                    } else {
                        return item.$cid;
                    }
                } else {
                    if(this.$.keyPath && item instanceof Object){
                        return this.get(item, this.$.keyPath);
                    }
                }
                return null;
            },
            /***
             * Inner render method for an item
             * Creates a component, caches the component and adds the component to the list of children
             * @param {Object} item
             * @param {Number} index
             * @private
             */
            _innerRenderItem: function (item, index) {
                var component = this._createComponentForItem(item, index);
                this._cacheComponentForItem(item,component);
                this.addChild(component);
            },

            /***
             * Returns the key to access the item in the template
             * @return {String}
             * @private
             */
            _getItemKey: function () {
                return "$" + this.$.itemKey;
            },
            /***
             * Returns the key to access the index in the template
             * @return {String}
             * @private
             */
            _getIndexKey: function () {
                return "$" + this.$.indexKey;
            },
            /***
             * Removes an item from the list
             * @param {Object} item
             * @private
             */
            _removeRenderedItem: function (item) {
                var ri;
                var key = this._getKeyForItem(item);
                var comp;
                if(key){
                    comp = this.$renderedItemsMap[key];
                    this.removeChild(comp);
                    comp.destroy();
                    delete this.$renderedItemsMap[key];
                }else{
                    for (var i = 0; i < this.$renderedItems.length; i++) {
                        ri = this.$renderedItems[i];
                        if (ri.item === item) {
                            this.removeChild(ri.component);
                            this.$renderedItems.splice(i, 1);
                            ri.component.destroy();
                            return;
                        }
                    }
                }
            },
            /**
             * Returns the rendered component to a given item
             * @param item
             * @return {js/core/Component} component
             */
            getComponentForItem: function (item) {
                var key = this._getKeyForItem(item);
                if(key){
                    return this.$renderedItemsMap[key];
                }
                var ri;
                for (var i = 0; i < this.$renderedItems.length; i++) {
                    ri = this.$renderedItems[i];
                    if (ri.item === item) {
                        return ri.component;
                    }
                }
                return null;
            }
        });
    }
);<commit_msg>fixed adding of classAttributes<commit_after>define(
    ["js/ui/View", "js/core/Template", "js/core/List", "js/core/Bindable", "underscore"], function (View, Template, List, Bindable, _) {
        return View.inherit({
            defaults: {
                tagName: "div",
                items: null,
                itemKey: 'item',
                indexKey: 'index',
                keyPath: null
            },

            $classAttributes: [
                'keyPath', 'itemKey', 'indexKey'
            ],

            $defaultTemplateName: 'item',

            ctor: function(){
                this.callBase();

                this.bind('items','sort', this._onSort, this);
                this.bind('items','reset', this._onReset, this);
                this.bind('items','add', this._onItemAdd, this);
                this.bind('items','remove', this._onItemRemove, this);
            },
            /***
             * Returns true if items are available
             */
            hasItems: function () {
                if (this.$.items) {
                    return this.$.items.length;
                }
                return 0;
            }.on('items'),

            render: function () {
                if (!this.isRendered()) {
                    this.$renderedItems = [];
                    this.$renderedItemsMap = {};
                }
                return this.callBase();
            },
            /***
             * Renders the given items
             * @param items
             * @private
             */
            _renderItems: function (items) {
                if(!items){
                    this._innerRenderItems([]);
                }else if (items instanceof List) {
                    this._innerRenderItems(items.$items);
                } else if (_.isArray(items)) {
                    this._innerRenderItems(items);
                }
            },
            /***
             * This method is called when the sort event is fired,
             * It reorders the items in the list
             * @param [js.core.Event] event
             * @private
             */
            _onSort: function (event) {
                if (this.isRendered()) {
                    var item, c;
                    for (var i = 0; i < event.$.items.length; i++) {
                        item = event.$.items[i];
                        c = this.getComponentForItem(item);
                        this.$el.removeChild(c.$el);
                        this.$el.appendChild(c.$el);
                    }
                }
            },
            _onReset: function (e) {
                if(this.isRendered()){
                    this._innerRenderItems(e.$.items);
                }
            },

            _onItemAdd: function (e) {
                if(this.isRendered()){
                    this._innerRenderItem(e.$.item, e.$.index);
                }
            },

            _onItemRemove: function (e) {
                if(this.isRendered()){
                    this._removeRenderedItem(e.$.item);
                }
            },
            /**
             * Inner render method for a list of items
             * All rendered items will be removed and destroyed before rendering
             * @param {Array} items[]
             * @private
             */
            _innerRenderItems: function (items) {
                var c;
                if (this.$renderedItems) {
                    for (var j = this.$renderedItems.length - 1; j >= 0; j--) {
                        c = this.$renderedItems[j];
                        this.removeChild(c.component);
                        c.component.destroy();
                    }
                }
                if(this.$renderedItemsMap){
                    for(var key in this.$renderedItemsMap){
                        if(this.$renderedItemsMap.hasOwnProperty(key)){
                            c = this.$renderedItemsMap[key];
                            this.removeChild(c);
                            c.destroy();
                        }
                    }
                }
                this.$renderedItems = [];
                this.$renderedItemsMap = {};
                for (var i = 0; i < items.length; i++) {
                    this._innerRenderItem(items[i], i);
                }

            },
            /***
             * Creates a component based on the template for a given item
             * @param {Object} item
             * @param {Number} index
             * @return {js.core.Component} component
             * @private
             */
            _createComponentForItem: function (item, index) {
                var attr = {};
                attr[this._getItemKey()] = item;
                attr[this._getIndexKey()] = index;
                var component = this.$templates['item'].createComponents(attr)[0];
                if(component.$classAttributes){
                    component.$classAttributes.push(this.$.itemKey, this.$.indexKey);
                }
                return component;
            },
            /***
             * Caches the component to a given item
             * @param {Object} item
             * @param {js.core.Component} component
             * @return {js.core.Component} returns the component
             * @private
             */
            _cacheComponentForItem: function(item,component){
                var key = this._getKeyForItem(item);
                if (key) {
                    this.$renderedItemsMap[key] = component;
                } else {
                    // add to rendered item map
                    this.$renderedItems.push({
                        item: item,
                        component: component
                    });
                }
                return component;
            },
            /***
             * Calculates a cache key for a given item.
             * If a keyPath is set, it will return the value of the path
             * Otherwise if the item is a {js.core.Bindable} it will return the $cid
             * If no keyPath is set and it's an object it will return null;
             *
             * @param item
             * @return {*}
             * @private
             */
            _getKeyForItem: function(item){
                if (item instanceof Bindable) {
                    var key;
                    if (this.$.keyPath) {
                        return item.get(this.$.keyPath);
                    } else {
                        return item.$cid;
                    }
                } else {
                    if(this.$.keyPath && item instanceof Object){
                        return this.get(item, this.$.keyPath);
                    }
                }
                return null;
            },
            /***
             * Inner render method for an item
             * Creates a component, caches the component and adds the component to the list of children
             * @param {Object} item
             * @param {Number} index
             * @private
             */
            _innerRenderItem: function (item, index) {
                var component = this._createComponentForItem(item, index);
                this._cacheComponentForItem(item,component);
                this.addChild(component);
            },

            /***
             * Returns the key to access the item in the template
             * @return {String}
             * @private
             */
            _getItemKey: function () {
                return "$" + this.$.itemKey;
            },
            /***
             * Returns the key to access the index in the template
             * @return {String}
             * @private
             */
            _getIndexKey: function () {
                return "$" + this.$.indexKey;
            },
            /***
             * Removes an item from the list
             * @param {Object} item
             * @private
             */
            _removeRenderedItem: function (item) {
                var ri;
                var key = this._getKeyForItem(item);
                var comp;
                if(key){
                    comp = this.$renderedItemsMap[key];
                    this.removeChild(comp);
                    comp.destroy();
                    delete this.$renderedItemsMap[key];
                }else{
                    for (var i = 0; i < this.$renderedItems.length; i++) {
                        ri = this.$renderedItems[i];
                        if (ri.item === item) {
                            this.removeChild(ri.component);
                            this.$renderedItems.splice(i, 1);
                            ri.component.destroy();
                            return;
                        }
                    }
                }
            },
            /**
             * Returns the rendered component to a given item
             * @param item
             * @return {js/core/Component} component
             */
            getComponentForItem: function (item) {
                var key = this._getKeyForItem(item);
                if(key){
                    return this.$renderedItemsMap[key];
                }
                var ri;
                for (var i = 0; i < this.$renderedItems.length; i++) {
                    ri = this.$renderedItems[i];
                    if (ri.item === item) {
                        return ri.component;
                    }
                }
                return null;
            }
        });
    }
);<|endoftext|>


<commit_before>module.exports = (function () {
  'use strict';

  var DEFAULT_POWER_OF_TWO = 4;

  function makeKeysFn(shift) {
    return function (obj) {
      var startX = (obj.x - obj.width / 2) >> shift;
      var startY = (obj.y - obj.height / 2) >> shift;
      var endX = (obj.x + obj.width / 2) >> shift;
      var endY = (obj.y + obj.height / 2) >> shift;
      var x;
      var y;
      var keys = [];

      for (y = startY; y <= endY; y++) {
        for (x = startX; x <= endX; x++) {
          keys.push(x + ":" + y);
        }
      }

      return keys;
    };
  }

  function SpatialHash(power_of_two) {
    if (!power_of_two) {
      power_of_two = DEFAULT_POWER_OF_TWO;
    }

    this.getKeys = makeKeysFn(power_of_two);
    this.hash = {};
    this.list = [];
  }

  SpatialHash.prototype.clear = function () {
    var keys = _.keys(this.hash);
    var i;

    for (i = 0; i < keys.length; i++) {
      var key = keys[i];

      if (this.hash[key].length === 0) {
        delete this.hash[key];
      } else {
        this.hash[key].length = 0;
      }
    }
    this.list.length = 0;
  };

  SpatialHash.prototype.getNumBuckets = function () {
    var key, count = 0;

    for (key in this.hash) {
      if (this.hash.hasOwnProperty(key)) {
        if (this.hash[key].length > 0) {
          count++;
        }
      }
    }
    return count;

  };

  SpatialHash.prototype.insert = function (obj, rect) {
    var keys = this.getKeys(rect || obj), key, i;

    this.list.push(obj);

    for (i = 0; i < keys.length; i++) {
      key = keys[i];

      if (this.hash[key]) {
        this.hash[key].push(obj);
      }
      else {
        this.hash[key] = [obj];
      }
    }
  };

  SpatialHash.prototype.retrieve = function (obj, rect) {
    var ret = [], keys, i, key;

    if (!obj && !rect) {
      return this.list;
    }

    keys = this.getKeys(rect || obj);

    for (i = 0; i < keys.length; i++) {
      key = keys[i];

      if (this.hash[key]) {
        ret = ret.concat(this.hash[key]);
      }
    }

    return ret;
  };

  return SpatialHash;
})();<commit_msg>Adding comment for where the code is from<commit_after>//From http://zufallsgenerator.github.io/2014/01/26/visually-comparing-algorithms/
module.exports = (function () {
  'use strict';

  var DEFAULT_POWER_OF_TWO = 4;

  function makeKeysFn(shift) {
    return function (obj) {
      var startX = (obj.x - obj.width / 2) >> shift;
      var startY = (obj.y - obj.height / 2) >> shift;
      var endX = (obj.x + obj.width / 2) >> shift;
      var endY = (obj.y + obj.height / 2) >> shift;
      var x;
      var y;
      var keys = [];

      for (y = startY; y <= endY; y++) {
        for (x = startX; x <= endX; x++) {
          keys.push(x + ":" + y);
        }
      }

      return keys;
    };
  }

  function SpatialHash(power_of_two) {
    if (!power_of_two) {
      power_of_two = DEFAULT_POWER_OF_TWO;
    }

    this.getKeys = makeKeysFn(power_of_two);
    this.hash = {};
    this.list = [];
  }

  SpatialHash.prototype.clear = function () {
    var keys = _.keys(this.hash);
    var i;

    for (i = 0; i < keys.length; i++) {
      var key = keys[i];

      if (this.hash[key].length === 0) {
        delete this.hash[key];
      } else {
        this.hash[key].length = 0;
      }
    }
    this.list.length = 0;
  };

  SpatialHash.prototype.getNumBuckets = function () {
    var key, count = 0;

    for (key in this.hash) {
      if (this.hash.hasOwnProperty(key)) {
        if (this.hash[key].length > 0) {
          count++;
        }
      }
    }
    return count;

  };

  SpatialHash.prototype.insert = function (obj, rect) {
    var keys = this.getKeys(rect || obj), key, i;

    this.list.push(obj);

    for (i = 0; i < keys.length; i++) {
      key = keys[i];

      if (this.hash[key]) {
        this.hash[key].push(obj);
      }
      else {
        this.hash[key] = [obj];
      }
    }
  };

  SpatialHash.prototype.retrieve = function (obj, rect) {
    var ret = [], keys, i, key;

    if (!obj && !rect) {
      return this.list;
    }

    keys = this.getKeys(rect || obj);

    for (i = 0; i < keys.length; i++) {
      key = keys[i];

      if (this.hash[key]) {
        ret = ret.concat(this.hash[key]);
      }
    }

    return ret;
  };

  return SpatialHash;
})();<|endoftext|>


<commit_before>/*
 * CAMXES.JS POSTPROCESSOR
 * Created by Ilmen (ilmen.pokebip <at> gmail.com) on 2013-08-16.
 * Last change: 2016-09-06.
 *
 * Entry point: camxes_postprocessing(input, mode)
 * Arguments:
 *    -- input: [array] camxes' parse tree output
 *    -- mode:  [number] output mode flag
 *         If mode > 7, displaying spaces is enabled and mode's value is
 *         truncated so mode <= 7. Then, depending on the value of mode,
 *         the following options are set:
 *         0 = Raw output (no change)
 *         1 = Condensed
 *         2 = Prettified
 *         3 = Prettified + selma'o
 *         4 = Prettified + selma'o + bridi parts
 *         5 = Prettified - famyma'o
 *         6 = Prettified - famyma'o + selma'o
 *         7 = Prettified - famyma'o + selma'o + bridi parts
 *
 * Return value:
 *       [string] postprocessed version of camxes' output
 */

/*
 * Function list:
 *   -- camxes_postprocessing(text, mode)
 *   -- new_postprocessor(input, no_morpho, with_selmaho, with_terminator)
 *   -- prune_unwanted_nodes(tree, is_wanted_node)
 *   -- prefix_wordclass(tree, replacements)
 *   -- remove_morphology(pt)
 *   -- is_target_node(n)
 *   -- join_expr(n)
 *   -- among(v, s)
 *   -- is_selmaho(v)
 *   -- prettify_brackets(str)
 *   -- str_print_uint(val, charset)
 *   -- str_replace(str, pos, len, sub)
 *   -- chr_check(chr, list)
 *   -- is_string(v)
 *   -- is_array(v)
 */

if (typeof alert !== 'function')
    alert = console.log; // For Node.js

/*
 * Version of transition between the older string processing and the newer
 * parse tree processing.
 * The below function's content is temporary and allows choosing which of the
 * two postprocessor (the older, the newer or even both) to use.
 * If the new postprocessor proves satisfactory, the older postprocessor's code
 * will be entirely removed.
 */
function camxes_postprocessing(input, mode) {
    if (!is_array(input))
        return "Postprocessor error: invalid input type.";
    var with_spaces = mode & 8;
    var without_morphology = !(mode & 16);
    mode = mode % 8;
    var with_selmaho = (mode != 2 && mode != 5);
    var with_nodes_labels = (mode == 4 || mode == 7);
    var without_terminator = (mode >= 5);
    if (without_morphology)
        input = remove_morphology(input); // Deleting morphology nodes.
    var output;
    if (mode <= 1) {
        output = JSON.stringify(input, undefined, mode == 0 ? 2 : 0);
    } else {
        input = new_postprocessor(input, without_morphology, with_spaces,
                                  with_selmaho, !without_terminator);
        output = JSON.stringify(input);
        output = output.replace(/\"/gm, "");
        output = output.replace(/,/gm, " ");
    }
    // Replacing "spaces" with "_":
    output = output.replace(/([ \[\],])(initial_)?spaces(?=[ \[\],])/gm, "$1_");
    // Bracket prettification:
    output = prettify_brackets(output);
	return output;
}

// ====== NEW POSTPROCESSOR ====== //

function new_postprocessor(input, no_morpho, with_spaces, with_selmaho, with_terminator) {
    var filter;
    var wanted_nodes = with_spaces ? ["initial_spaces", "dot_star"] : ["dot_star"];
    if (no_morpho) {
        filter = function (v,b) { return (with_selmaho ?
                  among(v, wanted_nodes.concat(["cmevla", "gismu", "lujvo", "fuhivla"]))
                  || (is_selmaho(v) && (with_terminator || !b))
                  : among(v, wanted_nodes)
                  || (is_selmaho(v) && b && with_terminator)); };
    } else {
        filter = function (v,b) { return among(v, wanted_nodes) ||
                  (with_selmaho ? (is_selmaho(v) && (with_terminator || !b))
                  : is_selmaho(v) && b && with_terminator); };
    }
    input = prune_unwanted_nodes(input, filter);
    if (input === null) return [];
    if (with_selmaho && no_morpho) {
        var replacements = [["cmene", "C"], ["cmevla", "C"], ["gismu", "G"],
                            ["lujvo", "L"], ["fuhivla", "Z"]];
        input = prefix_wordclass(input, replacements);
        if (is_string(input)) input = [input];
    }
    return input;
}

function prune_unwanted_nodes(tree, is_wanted_node) {
    if (is_string(tree)) return tree;
    if (!is_array(tree)) throw "ERR";
    if (tree.length == 0) return null;
    var no_label = is_array(tree[0]);
    var k = 0;
    var i = no_label ? 0 : 1;
    while (i < tree.length) {
        tree[i] = prune_unwanted_nodes(tree[i], is_wanted_node);
        if (tree[i]) {
            k++;
            i++;
        } else tree.splice(i, 1);
    }
    if (!no_label) {
        if (!is_wanted_node(tree[0], tree.length == 1)) tree.splice(0, 1);
        else k++;
    }
    if (k == 1) return tree[0];
    else return (k > 0) ? tree : null;
}

function prefix_wordclass(tree, replacements) {
    if (tree.length == 2 && is_string(tree[0]) && is_string(tree[1])) {
        var i = 0;
        while (i < replacements.length) {
            if (tree[0] == replacements[i][0]) {
                tree[0] = replacements[i][1];
                break;
            }
            i++;
        }
        return tree[0] + ':' + tree[1];
    }
    var i = 0;
    while (i < tree.length) {
        if (is_array(tree[i]))
            tree[i] = prefix_wordclass(tree[i], replacements);
        i++;
    }
    return tree;
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function chr_check(chr, list) {
	var i = 0;
	if (!is_string(list)) return false;
	do if (chr == list[i]) return true; while (i++ < list.length);
	return false;
} // Currently unused.

function is_string(v) {
    // return $.type(v) === "string";
    return Object.prototype.toString.call(v) === '[object String]';
}

function is_array(v) {
    // return $.type(v) === "array";
    return Object.prototype.toString.call(v) === '[object Array]';
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<commit_msg>camxes_postproc.js: Adding to the error message a warning about the fact that the postprocessor doesn't allow anymore string inputs.<commit_after>/*
 * CAMXES.JS POSTPROCESSOR
 * Created by Ilmen (ilmen.pokebip <at> gmail.com) on 2013-08-16.
 * Last change: 2016-09-06.
 *
 * Entry point: camxes_postprocessing(input, mode)
 * Arguments:
 *    -- input: [array] camxes' parse tree output
 *    -- mode:  [number] output mode flag
 *         If mode > 7, displaying spaces is enabled and mode's value is
 *         truncated so mode <= 7. Then, depending on the value of mode,
 *         the following options are set:
 *         0 = Raw output (no change)
 *         1 = Condensed
 *         2 = Prettified
 *         3 = Prettified + selma'o
 *         4 = Prettified + selma'o + bridi parts
 *         5 = Prettified - famyma'o
 *         6 = Prettified - famyma'o + selma'o
 *         7 = Prettified - famyma'o + selma'o + bridi parts
 *
 * Return value:
 *       [string] postprocessed version of camxes' output
 */

/*
 * Function list:
 *   -- camxes_postprocessing(text, mode)
 *   -- new_postprocessor(input, no_morpho, with_selmaho, with_terminator)
 *   -- prune_unwanted_nodes(tree, is_wanted_node)
 *   -- prefix_wordclass(tree, replacements)
 *   -- remove_morphology(pt)
 *   -- is_target_node(n)
 *   -- join_expr(n)
 *   -- among(v, s)
 *   -- is_selmaho(v)
 *   -- prettify_brackets(str)
 *   -- str_print_uint(val, charset)
 *   -- str_replace(str, pos, len, sub)
 *   -- chr_check(chr, list)
 *   -- is_string(v)
 *   -- is_array(v)
 */

if (typeof alert !== 'function')
    alert = console.log; // For Node.js

/*
 * Version of transition between the older string processing and the newer
 * parse tree processing.
 * The below function's content is temporary and allows choosing which of the
 * two postprocessor (the older, the newer or even both) to use.
 * If the new postprocessor proves satisfactory, the older postprocessor's code
 * will be entirely removed.
 */
function camxes_postprocessing(input, mode) {
    if (!is_array(input))
        return "Postprocessor error: invalid input type for the first argument. "
             + "It should be of type 'array', but the argument given is of type '" + typeof input + "'."
             + (is_string(input) ? "\n\nThe new postprocessor doesn't allow anymore string inputs. "
             + "Please check the parse tree produced by the parser hasn't been converted to string "
             + "before being passed to the postprocessor." : "");
    var with_spaces = mode & 8;
    var without_morphology = !(mode & 16);
    mode = mode % 8;
    var with_selmaho = (mode != 2 && mode != 5);
    var with_nodes_labels = (mode == 4 || mode == 7);
    var without_terminator = (mode >= 5);
    if (without_morphology)
        input = remove_morphology(input); // Deleting morphology nodes.
    var output;
    if (mode <= 1) {
        output = JSON.stringify(input, undefined, mode == 0 ? 2 : 0);
    } else {
        input = new_postprocessor(input, without_morphology, with_spaces,
                                  with_selmaho, !without_terminator);
        output = JSON.stringify(input);
        output = output.replace(/\"/gm, "");
        output = output.replace(/,/gm, " ");
    }
    // Replacing "spaces" with "_":
    output = output.replace(/([ \[\],])(initial_)?spaces(?=[ \[\],])/gm, "$1_");
    // Bracket prettification:
    output = prettify_brackets(output);
	return output;
}

// ====== NEW POSTPROCESSOR ====== //

function new_postprocessor(input, no_morpho, with_spaces, with_selmaho, with_terminator) {
    var filter;
    var wanted_nodes = with_spaces ? ["initial_spaces", "dot_star"] : ["dot_star"];
    if (no_morpho) {
        filter = function (v,b) { return (with_selmaho ?
                  among(v, wanted_nodes.concat(["cmevla", "gismu", "lujvo", "fuhivla"]))
                  || (is_selmaho(v) && (with_terminator || !b))
                  : among(v, wanted_nodes)
                  || (is_selmaho(v) && b && with_terminator)); };
    } else {
        filter = function (v,b) { return among(v, wanted_nodes) ||
                  (with_selmaho ? (is_selmaho(v) && (with_terminator || !b))
                  : is_selmaho(v) && b && with_terminator); };
    }
    input = prune_unwanted_nodes(input, filter);
    if (input === null) return [];
    if (with_selmaho && no_morpho) {
        var replacements = [["cmene", "C"], ["cmevla", "C"], ["gismu", "G"],
                            ["lujvo", "L"], ["fuhivla", "Z"]];
        input = prefix_wordclass(input, replacements);
        if (is_string(input)) input = [input];
    }
    return input;
}

function prune_unwanted_nodes(tree, is_wanted_node) {
    if (is_string(tree)) return tree;
    if (!is_array(tree)) throw "ERR";
    if (tree.length == 0) return null;
    var no_label = is_array(tree[0]);
    var k = 0;
    var i = no_label ? 0 : 1;
    while (i < tree.length) {
        tree[i] = prune_unwanted_nodes(tree[i], is_wanted_node);
        if (tree[i]) {
            k++;
            i++;
        } else tree.splice(i, 1);
    }
    if (!no_label) {
        if (!is_wanted_node(tree[0], tree.length == 1)) tree.splice(0, 1);
        else k++;
    }
    if (k == 1) return tree[0];
    else return (k > 0) ? tree : null;
}

function prefix_wordclass(tree, replacements) {
    if (tree.length == 2 && is_string(tree[0]) && is_string(tree[1])) {
        var i = 0;
        while (i < replacements.length) {
            if (tree[0] == replacements[i][0]) {
                tree[0] = replacements[i][1];
                break;
            }
            i++;
        }
        return tree[0] + ':' + tree[1];
    }
    var i = 0;
    while (i < tree.length) {
        if (is_array(tree[i]))
            tree[i] = prefix_wordclass(tree[i], replacements);
        i++;
    }
    return tree;
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function chr_check(chr, list) {
	var i = 0;
	if (!is_string(list)) return false;
	do if (chr == list[i]) return true; while (i++ < list.length);
	return false;
} // Currently unused.

function is_string(v) {
    // return $.type(v) === "string";
    return Object.prototype.toString.call(v) === '[object String]';
}

function is_array(v) {
    // return $.type(v) === "array";
    return Object.prototype.toString.call(v) === '[object Array]';
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<|endoftext|>


<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Describes a section of continuous overlap (multiple overlapping points) between two segments.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var kite = require( 'KITE/kite' );

  /**
   * @public
   * @constructor
   *
   * Creates an overlap based on two segments with their t-values (parametric value) within the range of [0,1]
   * (inclusive). The t value from the first curve can be mapped to an equivalent t value from the second curve such
   * that first( t ) === second( a * t + b ).
   *
   * Endpoint values for the actual overlap will be computed, such that
   * - first( t0 ) === second( qt0 )
   * - first( t1 ) === second( qt1 )
   * - All of those t values are in the range [0,1]
   *
   * @param {number} a
   * @param {number} b
   */
  function Overlap( a, b ) {
    assert && assert( typeof a === 'number' && isFinite( a ) && a !== 0,
      'a should be a finite non-zero number' );
    assert && assert( typeof b === 'number' && isFinite( b ),
      'b should be a finite number' );

    // @public {number}
    this.a = a;
    this.b = b;

    var t0 = 0;
    var t1 = 1;
    var qt0 = this.apply( t0 );
    var qt1 = this.apply( t1 );

    if ( qt0 > 1 ) {
      qt0 = 1;
      t0 = this.applyInverse( qt0 );
    }
    if ( qt0 < 0 ) {
      qt0 = 0;
      t0 = this.applyInverse( qt0 );
    }
    if ( qt1 > 1 ) {
      qt1 = 1;
      t1 = this.applyInverse( qt1 );
    }
    if ( qt1 < 0 ) {
      qt1 = 0;
      t1 = this.applyInverse( qt1 );
    }

    // @public {number} - Initial and ending t-values for the first curve (t0,t1) and second curve (qt0,qt1).
    this.t0 = t0;
    this.t1 = t1;
    if ( a > 0 ) {
      this.qt0 = qt0;
      this.qt1 = qt1;
    }
    else {
      this.qt0 = qt1;
      this.qt1 = qt0;
    }

    assert && assert( this.t0 >= 0 && this.t0 <= 1, 't0 out of range: ' + this.t0 );
    assert && assert( this.t1 >= 0 && this.t1 <= 1, 't1 out of range: ' + this.t1 );
    assert && assert( this.qt0 >= 0 && this.qt0 <= 1, 'qt0 out of range: ' + this.qt0 );
    assert && assert( this.qt1 >= 0 && this.qt1 <= 1, 'qt1 out of range: ' + this.qt1 );
  }

  kite.register( 'Overlap', Overlap );

  inherit( Object, Overlap, {
    /**
     * Maps a t value from the first curve to the second curve (assuming it is within the overlap range).
     * @public
     *
     * @param {number} t
     * @returns {number}
     */
    apply: function( t ) {
      return this.a * t + this.b;
    },

    /**
     * Maps a t value from the second curve to the first curve (assuming it is within the overlap range).
     * @public
     *
     * @param {number} t
     * @returns {number}
     */
    applyInverse: function( t ) {
      return ( t - this.b ) / this.a;
    }
  }, {
    /**
     * Returns a new overlap that should map t values of a0 => b0 and a1 => b1
     * @public
     *
     * @param {number} a0
     * @param {number} b0
     * @param {number} a1
     * @param {number} b1
     * @returns {Overlap}
     */
    createLinear: function( a0, b0, a1, b1 ) {
      var factor = ( b1 - b0 ) / ( a1 - a0 );
      return new Overlap( factor, b0 - a0 * factor );
    }
  } );

  return kite.Overlap;
} );
<commit_msg>Some clamping improvements to Overlap<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Describes a section of continuous overlap (multiple overlapping points) between two segments.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var inherit = require( 'PHET_CORE/inherit' );
  var kite = require( 'KITE/kite' );

  /**
   * @public
   * @constructor
   *
   * Creates an overlap based on two segments with their t-values (parametric value) within the range of [0,1]
   * (inclusive). The t value from the first curve can be mapped to an equivalent t value from the second curve such
   * that first( t ) === second( a * t + b ).
   *
   * Endpoint values for the actual overlap will be computed, such that
   * - first( t0 ) === second( qt0 )
   * - first( t1 ) === second( qt1 )
   * - All of those t values are in the range [0,1]
   *
   * @param {number} a
   * @param {number} b
   */
  function Overlap( a, b ) {
    assert && assert( typeof a === 'number' && isFinite( a ) && a !== 0,
      'a should be a finite non-zero number' );
    assert && assert( typeof b === 'number' && isFinite( b ),
      'b should be a finite number' );

    // @public {number}
    this.a = a;
    this.b = b;

    var t0 = 0;
    var t1 = 1;
    var qt0 = this.apply( t0 );
    var qt1 = this.apply( t1 );

    if ( qt0 > 1 ) {
      qt0 = 1;
      t0 = this.applyInverse( qt0 );
    }
    if ( qt0 < 0 ) {
      qt0 = 0;
      t0 = this.applyInverse( qt0 );
    }
    if ( qt1 > 1 ) {
      qt1 = 1;
      t1 = this.applyInverse( qt1 );
    }
    if ( qt1 < 0 ) {
      qt1 = 0;
      t1 = this.applyInverse( qt1 );
    }

    // @public {number} - Initial and ending t-values for the first curve (t0,t1) and second curve (qt0,qt1).
    this.t0 = t0;
    this.t1 = t1;
    if ( a > 0 ) {
      this.qt0 = qt0;
      this.qt1 = qt1;
    }
    else {
      this.qt0 = qt1;
      this.qt1 = qt0;
    }

    if ( this.t0 < 0 && this.t0 > -1e-8 ) { this.t0 = 0; }
    if ( this.t0 > 1 && this.t0 < 1 + 1e-8 ) { this.t0 = 1; }

    if ( this.t1 < 0 && this.t1 > -1e-8 ) { this.t1 = 0; }
    if ( this.t1 > 1 && this.t1 < 1 + 1e-8 ) { this.t1 = 1; }

    if ( this.qt0 < 0 && this.qt0 > -1e-8 ) { this.qt0 = 0; }
    if ( this.qt0 > 1 && this.qt0 < 1 + 1e-8 ) { this.qt0 = 1; }

    if ( this.qt1 < 0 && this.qt1 > -1e-8 ) { this.qt1 = 0; }
    if ( this.qt1 > 1 && this.qt1 < 1 + 1e-8 ) { this.qt1 = 1; }

    assert && assert( this.t0 >= 0 && this.t0 <= 1, 't0 out of range: ' + this.t0 );
    assert && assert( this.t1 >= 0 && this.t1 <= 1, 't1 out of range: ' + this.t1 );
    assert && assert( this.qt0 >= 0 && this.qt0 <= 1, 'qt0 out of range: ' + this.qt0 );
    assert && assert( this.qt1 >= 0 && this.qt1 <= 1, 'qt1 out of range: ' + this.qt1 );
  }

  kite.register( 'Overlap', Overlap );

  inherit( Object, Overlap, {
    /**
     * Maps a t value from the first curve to the second curve (assuming it is within the overlap range).
     * @public
     *
     * @param {number} t
     * @returns {number}
     */
    apply: function( t ) {
      return this.a * t + this.b;
    },

    /**
     * Maps a t value from the second curve to the first curve (assuming it is within the overlap range).
     * @public
     *
     * @param {number} t
     * @returns {number}
     */
    applyInverse: function( t ) {
      return ( t - this.b ) / this.a;
    }
  }, {
    /**
     * Returns a new overlap that should map t values of a0 => b0 and a1 => b1
     * @public
     *
     * @param {number} a0
     * @param {number} b0
     * @param {number} a1
     * @param {number} b1
     * @returns {Overlap}
     */
    createLinear: function( a0, b0, a1, b1 ) {
      var factor = ( b1 - b0 ) / ( a1 - a0 );
      return new Overlap( factor, b0 - a0 * factor );
    }
  } );

  return kite.Overlap;
} );
<|endoftext|>