<commit_before>ajax_url = 'https://kmu43f0xqb.execute-api.us-east-1.amazonaws.com/prod/posts/';

if (window.location.protocol == 'file:'){
	// Testing mode
	ajax_url = 'http://localhost:3001/';
}

posting_delay = 10;
button_delay = 3;
auto_refresh_delay = 30000;

postIds = [];
highest_id = null;
lowest_id = null;

function getPosts(){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url, true);
	xmlhttp.send();
}

function getExactPost(postId){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url + postId, true);
	xmlhttp.send();
}

function getNewerPosts(){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url + highest_id + '/up', true);
	xmlhttp.send();
}

function getOlderPosts(){
	loading();
	if (lowest_id > 1){
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.onreadystatechange = function(){
			handleGetPosts(xmlhttp, true);
		};
		xmlhttp.open("GET", ajax_url + lowest_id + '/down', true);
		xmlhttp.send();
	}
}

function handleGetPosts(xmlhttp, reverse){
	if (xmlhttp.readyState == XMLHttpRequest.DONE) {
		if (xmlhttp.status == 200) {
			var resp = JSON.parse(xmlhttp.responseText);
			if (reverse !== 'undefined' && reverse){
				reverse(resp);
			}
			for (var i = 0; i < resp.length; i++){
				post = resp[i];
				addPost(post);
			}
		} else if (xmlhttp.status == 400) {
			//TODO alert('There was an error 400');
		} else {
			//TODO alert('something else other than 200 was returned');
		}
		unloading();
	}
}

function addPost(postObj){
	// Check post not already exists
	var exist = document.getElementById('post'+postObj.postId);
	if (exist === null){
		// Create post
		var post = document.createElement('div');
		post.className = 'panel transparent';
		post.id = 'post'+postObj.postId;
		// Top info
		var postTop = document.createElement('div');
		post.appendChild(postTop);
		post.appendChild(document.createElement('hr'));
		// Post postId
		if (postObj.postId){
			var postId = document.createElement('a');
			postId.href = '#';
			postId.innerText = '>>' + postObj.postId;
			postId.onclick = function(){
				quote(postObj.postId);
			};
			postTop.appendChild(postId);
		}
		// Date
		if (postObj.time){
			t = new Date(postObj.time);
			var postTime = document.createElement('span');
			postTime.innerText = t.toLocaleString();
			postTime.className = 'right';
			postTop.appendChild(postTime);
		}
		// Image
		if (postObj.img){
			var postImg = document.createElement('img');
			postImg.src = postObj.img;
			postImg.onerror = imageError;
			post.appendChild(postImg);
		}
		// Text
		if (postObj.msg){
			var postTextP = document.createElement('p');
			// Linkify
			var re = />>\d+/g
			postText = postObj.msg;
			var i = postText.indexOf(postText.match(re));
			while (i != -1){
				var temp;
				var s;
				if (i != 0){
					// Splice string
					temp = postText.split('');
					s = temp.splice(0, i).join('');
					postText = temp.join('');
					postTextP.appendChild(document.createTextNode(s));
				}
				var el = document.createElement('a');
				// Splice string
				temp = postText.split('');
				s = temp.splice(0, postText.match(re)[0].length).join('');
				postText = temp.join('');
				el.innerText = s;
				el.href = '#post'+s.slice(2, s.length);
				postTextP.appendChild(el);
				i = postText.indexOf(postText.match(re));
			}
			if (postText.length > 0){
				postTextP.appendChild(document.createTextNode(postText));
			}
			re = /\n/g;
			postTextP.innerHTML = postTextP.innerHTML.replace(re, '
');
			post.appendChild(postTextP);
		}
		// Add post
		var postContainer = document.getElementById('postcontainer');
		if (postObj.postId < lowest_id){
			postContainer.appendChild(post);
		} else {
			postContainer.insertBefore(post, postContainer.firstChild);
		}
		// Mark added
		postIds.push(postObj.postId);
		if (highest_id == null || postObj.postId > highest_id){
			highest_id = postObj.postId;
		}
		if (lowest_id == null || postObj.postId < lowest_id){
			lowest_id = postObj.postId;
			if (lowest_id <= 1){
				document.getElementById('ancient').className = 'transparent';
			}
		}
		// Transition
		setTimeout(function(){
			post.className = 'panel';
			// Auto-scroll to prevent jumping if not at top
			if (window.scrollY != 0){
				window.scrollTo(window.scrollX, window.scrollY + post.scrollHeight);
			}
		}, 50);
	}
}

function imageError(){
	this.onerror = null;
	this.src = 'img/broken.png';
}

// Quote a post
function quote(postId){
	var postMsg = document.getElementById('postMsg');
	pos = postMsg.selectionStart;
	postMsg.value = postMsg.value.substr(0, pos) + '>>' + postId + '\n' + postMsg.value.substr(pos);
	postMsg.focus();
	return false;
}

function makePost(){
	var makePostButton = document.getElementById('makePost');
	makePostButton.disabled = true;

	var post = {};
	var postMsg = document.getElementById('postMsg');
	post.msg = postMsg.value;
	postMsg.value = '';
	var postImg = document.getElementById('postImg');
	post.img = postImg.value;
	postImg.value = '';
	previewImage();

	if (post.msg != '' || post.img != ''){
		var xmlhttp = new XMLHttpRequest();

		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == XMLHttpRequest.DONE) {
				if (xmlhttp.status == 200) {
					// Success
				} else if (xmlhttp.status == 400) {
					//TODO alert('There was an error 400');
				} else {
					//TODO alert('something else other than 200 was returned');
				}
				impatientClick();
			}
			buttonTimedDisable(makePostButton, posting_delay);
		};

		xmlhttp.open("POST", ajax_url, true);
		xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
		xmlhttp.send(JSON.stringify(post));
	} else {
		makePostButton.disabled = false;
	}
}

// Load newer posts
function impatientClick(){
	var impatient = document.getElementById('impatient');
	impatient.disabled = true;
	if (highest_id == null){
		getPosts();
	} else {
		getNewerPosts();
	}
	buttonTimedDisable(impatient, button_delay);
}

// Load older posts
function ancientClick(){
	var ancient = document.getElementById('ancient');
	ancient.disabled = true;
	getOlderPosts();
	buttonTimedDisable(ancient, button_delay);
}

function buttonTimedDisable(butt, seconds, repeat){
	butt.disabled = true;
	if (repeat == true){
		//butt.innerText = butt.innerText.slice(0, butt.innerText.lastIndexOf(" "));
	}
	if (seconds <= 0){
		butt.disabled = false;
	} else {
		//butt.innerText += ' '+seconds+'...';
		setTimeout(function(){
			buttonTimedDisable(butt, seconds-1, true);
		}, 1000);
	}
}

function loading(){
	document.getElementById('loading').className = '';
	if (document.getElementById('postcontainer').firstElementChild != null &&
			document.getElementById('ancient').className != 'transparent'){
		document.getElementById('loadingLower').className = '';
	}
}

function unloading(){
	document.getElementById('loading').className = 'transparent';
	document.getElementById('loadingLower').className = 'transparent';
}

// Preview post images
function previewImage(){
	var postImgSrc = document.getElementById('postImg').value;
	var previewImg = document.getElementById('postImgPreview');
	console.log(postImgSrc);
	if (postImgSrc == ''){
		previewImg.className = 'hidden';
	} else {
		previewImg.className = 'preview';
		previewImg.src = postImgSrc;
		previewImg.onerror = imageError;
	}
}

function init(){
	// Set up buttons
	document.getElementById('toggleTheme').onclick = toggleTheme;
	document.getElementById('impatient').onclick = impatientClick;
	document.getElementById('ancient').onclick = ancientClick;
	document.getElementById('makePost').onclick = makePost;
	document.getElementById('postImg').onchange = previewImage;

	impatientClick();
	setInterval(impatientClick, auto_refresh_delay);
}
init();

/* Themes */
var currentTheme = 0;
var themes = ['native', 'amber'];

function toggleTheme(){
	currentTheme++;
	// Intentional out of bounds to include no theme
	if (currentTheme > themes.length){
		currentTheme = 0;
	}
	document.documentElement.className = themes[currentTheme];
}

/* Ads */
function adBlockDetected() {
	document.getElementById('adBlockPlea').className = '';
}

if (typeof blockAdBlock === 'undefined') {
	adBlockDetected();
} else {
	blockAdBlock.onDetected(adBlockDetected);
}<commit_msg>Added post ordering for insertion<commit_after>ajax_url = 'https://kmu43f0xqb.execute-api.us-east-1.amazonaws.com/prod/posts/';

if (window.location.protocol == 'file:'){
	// Testing mode
	ajax_url = 'http://localhost:3001/';
}

posting_delay = 10;
button_delay = 3;
auto_refresh_delay = 30000;

postIds = [];
highest_id = null;
lowest_id = null;

function getPosts(){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url, true);
	xmlhttp.send();
}

function getExactPost(postId){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url + postId, true);
	xmlhttp.send();
}

function getNewerPosts(){
	loading();
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.onreadystatechange = function(){
		handleGetPosts(xmlhttp, false);
	};
	xmlhttp.open("GET", ajax_url + highest_id + '/up', true);
	xmlhttp.send();
}

function getOlderPosts(){
	loading();
	if (lowest_id > 1){
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.onreadystatechange = function(){
			handleGetPosts(xmlhttp, true);
		};
		xmlhttp.open("GET", ajax_url + lowest_id + '/down', true);
		xmlhttp.send();
	}
}

function handleGetPosts(xmlhttp, reverse){
	if (xmlhttp.readyState == XMLHttpRequest.DONE) {
		if (xmlhttp.status == 200) {
			var resp = JSON.parse(xmlhttp.responseText);
			if (reverse !== 'undefined' && reverse){
				reverse(resp);
			}
			for (var i = 0; i < resp.length; i++){
				post = resp[i];
				addPost(post);
			}
		} else if (xmlhttp.status == 400) {
			//TODO alert('There was an error 400');
		} else {
			//TODO alert('something else other than 200 was returned');
		}
		unloading();
	}
}

function addPost(postObj){
	// Check post not already exists
	var exist = document.getElementById('post'+postObj.postId);
	if (exist === null){
		// Create post
		var post = document.createElement('div');
		post.className = 'panel transparent';
		post.id = 'post'+postObj.postId;
		// Top info
		var postTop = document.createElement('div');
		post.appendChild(postTop);
		post.appendChild(document.createElement('hr'));
		// Post postId
		if (postObj.postId){
			var postId = document.createElement('a');
			postId.href = '#';
			postId.innerText = '>>' + postObj.postId;
			postId.onclick = function(){
				quote(postObj.postId);
			};
			postTop.appendChild(postId);
		}
		// Date
		if (postObj.time){
			t = new Date(postObj.time);
			var postTime = document.createElement('span');
			postTime.innerText = t.toLocaleString();
			postTime.className = 'right';
			postTop.appendChild(postTime);
		}
		// Image
		if (postObj.img){
			var postImg = document.createElement('img');
			postImg.src = postObj.img;
			postImg.onerror = imageError;
			post.appendChild(postImg);
		}
		// Text
		if (postObj.msg){
			var postTextP = document.createElement('p');
			// Linkify
			var re = />>\d+/g
			postText = postObj.msg;
			var i = postText.indexOf(postText.match(re));
			while (i != -1){
				var temp;
				var s;
				if (i != 0){
					// Splice string
					temp = postText.split('');
					s = temp.splice(0, i).join('');
					postText = temp.join('');
					postTextP.appendChild(document.createTextNode(s));
				}
				var el = document.createElement('a');
				// Splice string
				temp = postText.split('');
				s = temp.splice(0, postText.match(re)[0].length).join('');
				postText = temp.join('');
				el.innerText = s;
				el.href = '#post'+s.slice(2, s.length);
				postTextP.appendChild(el);
				i = postText.indexOf(postText.match(re));
			}
			if (postText.length > 0){
				postTextP.appendChild(document.createTextNode(postText));
			}
			re = /\n/g;
			postTextP.innerHTML = postTextP.innerHTML.replace(re, '
');
			post.appendChild(postTextP);
		}
		// Add post
		var before = 0;
		for (var i = 0; i < postIds.length; i++){
			if (postIds[i] > before && postObj.postId > postIds[i]){
				before = postIds[i];
			}
		}
		var postContainer = document.getElementById('postcontainer');
		if (before <= 0){
			postContainer.appendChild(post);
		} else {
			postContainer.insertBefore(post, document.getElementById('post'+before));
		}
		// Mark added
		postIds.push(postObj.postId);
		if (highest_id == null || postObj.postId > highest_id){
			highest_id = postObj.postId;
		}
		if (lowest_id == null || postObj.postId < lowest_id){
			lowest_id = postObj.postId;
			if (lowest_id <= 1){
				document.getElementById('ancient').className = 'transparent';
			}
		}
		// Transition
		setTimeout(function(){
			post.className = 'panel';
			// Auto-scroll to prevent jumping if not at top
			if (window.scrollY != 0){
				window.scrollTo(window.scrollX, window.scrollY + post.scrollHeight);
			}
		}, 50);
	}
}

function imageError(){
	this.onerror = null;
	this.src = 'img/broken.png';
}

// Quote a post
function quote(postId){
	var postMsg = document.getElementById('postMsg');
	pos = postMsg.selectionStart;
	postMsg.value = postMsg.value.substr(0, pos) + '>>' + postId + '\n' + postMsg.value.substr(pos);
	postMsg.focus();
	return false;
}

function makePost(){
	var makePostButton = document.getElementById('makePost');
	makePostButton.disabled = true;

	var post = {};
	var postMsg = document.getElementById('postMsg');
	post.msg = postMsg.value;
	postMsg.value = '';
	var postImg = document.getElementById('postImg');
	post.img = postImg.value;
	postImg.value = '';
	previewImage();

	if (post.msg != '' || post.img != ''){
		var xmlhttp = new XMLHttpRequest();

		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == XMLHttpRequest.DONE) {
				if (xmlhttp.status == 200) {
					// Success
				} else if (xmlhttp.status == 400) {
					//TODO alert('There was an error 400');
				} else {
					//TODO alert('something else other than 200 was returned');
				}
				impatientClick();
			}
			buttonTimedDisable(makePostButton, posting_delay);
		};

		xmlhttp.open("POST", ajax_url, true);
		xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
		xmlhttp.send(JSON.stringify(post));
	} else {
		makePostButton.disabled = false;
	}
}

// Load newer posts
function impatientClick(){
	var impatient = document.getElementById('impatient');
	impatient.disabled = true;
	if (highest_id == null){
		getPosts();
	} else {
		getNewerPosts();
	}
	buttonTimedDisable(impatient, button_delay);
}

// Load older posts
function ancientClick(){
	var ancient = document.getElementById('ancient');
	ancient.disabled = true;
	getOlderPosts();
	buttonTimedDisable(ancient, button_delay);
}

function buttonTimedDisable(butt, seconds, repeat){
	butt.disabled = true;
	if (repeat == true){
		//butt.innerText = butt.innerText.slice(0, butt.innerText.lastIndexOf(" "));
	}
	if (seconds <= 0){
		butt.disabled = false;
	} else {
		//butt.innerText += ' '+seconds+'...';
		setTimeout(function(){
			buttonTimedDisable(butt, seconds-1, true);
		}, 1000);
	}
}

function loading(){
	document.getElementById('loading').className = '';
	if (document.getElementById('postcontainer').firstElementChild != null &&
			document.getElementById('ancient').className != 'transparent'){
		document.getElementById('loadingLower').className = '';
	}
}

function unloading(){
	document.getElementById('loading').className = 'transparent';
	document.getElementById('loadingLower').className = 'transparent';
}

// Preview post images
function previewImage(){
	var postImgSrc = document.getElementById('postImg').value;
	var previewImg = document.getElementById('postImgPreview');
	console.log(postImgSrc);
	if (postImgSrc == ''){
		previewImg.className = 'hidden';
	} else {
		previewImg.className = 'preview';
		previewImg.src = postImgSrc;
		previewImg.onerror = imageError;
	}
}

function init(){
	// Set up buttons
	document.getElementById('toggleTheme').onclick = toggleTheme;
	document.getElementById('impatient').onclick = impatientClick;
	document.getElementById('ancient').onclick = ancientClick;
	document.getElementById('makePost').onclick = makePost;
	document.getElementById('postImg').onchange = previewImage;

	impatientClick();
	setInterval(impatientClick, auto_refresh_delay);
}
init();

/* Themes */
var currentTheme = 0;
var themes = ['native', 'amber'];

function toggleTheme(){
	currentTheme++;
	// Intentional out of bounds to include no theme
	if (currentTheme > themes.length){
		currentTheme = 0;
	}
	document.documentElement.className = themes[currentTheme];
}

/* Ads */
function adBlockDetected() {
	document.getElementById('adBlockPlea').className = '';
}

if (typeof blockAdBlock === 'undefined') {
	adBlockDetected();
} else {
	blockAdBlock.onDetected(adBlockDetected);
}<|endoftext|>


<commit_before>/// <reference path="../libraries/Simplate.js"/>
/// <reference path="../libraries/reui/reui.js"/>
/// <reference path="../libraries/ext/ext-core-debug.js"/>
/// <reference path="../libraries/sdata/sdata-client-dependencies-debug.js"/>
/// <reference path="../libraries/sdata/sdata-client-debug.js"/>
/// <reference path="View.js"/>

Ext.namespace('Sage.Platform.Mobile');
Ext.namespace('Sage.Platform.Mobile.Controls');

(function() {
    Sage.Platform.Mobile.Edit = Ext.extend(Sage.Platform.Mobile.View, {
        attachmentPoints: {
            contentEl: '.panel-content',
            validationContentEl: '.panel-validation-summary > ul'
        },
        viewTemplate: new Simplate([
            '
',
            '{%! $.loadingTemplate %}',
            '{%! $.validationSummaryTemplate %}',
            '

',
            '
'
        ]),
        loadingTemplate: new Simplate([
            '<fieldset class="panel-loading-indicator">',
            '

{%: $.loadingText %}

',
            '</fieldset>'
        ]),
        validationSummaryTemplate: new Simplate([
            '
',
            '
{%: $.validationSummaryText %}
',
            '
',
            '
',
            '
'
        ]),
        validationSummaryItemTemplate: new Simplate([
            '
',
            '',
            '
{%: $.message %}
',
            '
{%: $$.label %}
',
            '',
            '
'
        ]),
        sectionBeginTemplate: new Simplate([
            '
{%: $.title %}
',
            '{% if ($.list) { %}
{% } else { %}<fieldset>{% } %}'
        ]),
        sectionEndTemplate: new Simplate([
            '{% if ($.list) { %}
{% } else { %}</fieldset>{% } %}'
        ]),
        propertyTemplate: new Simplate([
            '',
            '
',
            '
'
        ]),
        transitionEffect: 'flip',
        id: 'generic_edit',
        expose: false,
        saveText: 'Save',
        titleText: 'Edit',
        validationSummaryText: 'Validation Summary',
        detailsText: 'Details',
        loadingText: 'loading...',
        constructor: function(o) {
            this.fields = {};

            Sage.Platform.Mobile.Edit.superclass.constructor.apply(this, arguments);
        },
        render: function() {
            Sage.Platform.Mobile.Edit.superclass.render.apply(this, arguments);

            this.processLayout(this.createLayout(), {title: this.detailsText});

            this.el
                .select('div[data-field]')
                .each(function(value) {
                    var el = Ext.get(value.dom),
                        name = el.getAttribute('data-field'),
                        field = this.fields[name];
                    if (field)
                        field.renderTo(el);
                }, this);
        },
        init: function() {
            Sage.Platform.Mobile.Edit.superclass.init.apply(this, arguments);

            for (var name in this.fields) this.fields[name].init();

            this.tools.tbar = [{
                name: 'save',
                title: this.saveText,
                cls: 'button',
                fn: this.save,
                scope: this
            }];
        },
        createRequest: function() {
            var request = new Sage.SData.Client.SDataSingleResourceRequest(this.getService());

            if (this.entry && this.entry['$key'])
                request.setResourceSelector(String.format("'{0}'", this.entry['$key']));

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            if (this.queryOrderBy)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.OrderBy, this.queryOrderBy);

            return request;
        },
        createTemplateRequest: function() {
            var request = new Sage.SData.Client.SDataTemplateResourceRequest(this.getService());

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            return request;
        },
        createLayout: function() {
            return this.layout || [];
        },
        processLayout: function(layout, options)
        {
            var sections = [];
            var content = [];

            content.push(this.sectionBeginTemplate.apply(options));

            for (var i = 0; i < layout.length; i++)
            {
                var current = layout[i];

                if (current['as'])
                {
                    sections.push(current);
                    continue;
                }
                else
                {
                    var ctor = Sage.Platform.Mobile.Controls.FieldManager.get(current['type']),
                        field = this.fields[current['name']] = new ctor(Ext.apply({
                            owner: this
                        }, current)),
                        template = field.propertyTemplate || this.propertyTemplate;

                    content.push(template.apply(field));
                }
            }

            content.push(this.sectionEndTemplate.apply(options));

            Ext.DomHelper.append(this.contentEl, content.join(''));

            for (var i = 0; i < sections.length; i++)
            {
                var current = sections[i];

                this.processLayout(current['as'], current['options']);
            }
        },
        requestFailure: function(response, o) {

        },
        requestData: function() {
            var request = this.createRequest();
            if (request)
                request.read({
                    success: this.processEntry,
                    failure: this.requestFailure,
                    scope: this
                });
        },
        requestTemplateFailure: function() {

        },
        requestTemplateData: function() {
            var request = this.createTemplateRequest();
            if (request)
                request.read({
                    success: this.processTemplateEntry,
                    failure: this.requestTemplateFailure,
                    scope: this
                });
        },
        processEntry: function(entry) {
            // not currently used
        },
        processTemplateEntry: function(entry) {
            this.setValues(entry || {});
            this.el.removeClass('panel-loading');
        },
        clearValues: function() {
            for (var name in this.fields)
            {
                this.fields[name].clearValue();
            }
        },
        setValues: function(o) {
            for (var name in this.fields)
            {
                var value = Sage.Platform.Mobile.Utility.getValue(o, name);

                this.fields[name].setValue(value);
            }
        },
        getValues: function(ignoreDirtyFlag) {
            var o = {};
            var empty = true;

            for (var name in this.fields)
            {
                if (ignoreDirtyFlag || this.fields[name].alwaysUseValue || this.fields[name].isDirty())
                {
                    var value = this.fields[name].getValue();

                    Sage.Platform.Mobile.Utility.setValue(o, name, value);

                    empty = false;
                }
            }
            return empty ? false : o;
        },
        validate: function() {
            this.errors = [];

            for (var name in this.fields)
            {
                var result;
                if (false !== (result = this.fields[name].validate()))
                {
                    this.fields[name].el.addClass('panel-field-error');

                    this.errors.push({
                        name: name,
                        message: result
                    });
                }
                else
                {
                    this.fields[name].el.removeClass('panel-field-error');
                }
            }

            return this.errors.length > 0
                ? this.errors
                : false;
        },
        createEntryForUpdate: function(values) {
            return Ext.apply(values, {
                '$key': this.entry['$key'],
                '$etag': this.entry['$etag'],
                '$name': this.entry['$name']
            });
        },
        createEntryForInsert: function(values) {
            return Ext.apply(values, {
                '$name': this.entityName
            });
        },
        isFormDisabled: function() {
            return this.busy;
        },
        disableForm: function() {
            this.busy = true;
            this.el.addClass('view-busy');
            if (App.bars.tbar && App.bars.tbar.el)
                App.bars.tbar.el.addClass('toolbar-busy');
        },
        enableForm: function() {
            this.busy = false;
            this.el.removeClass('view-busy');
            if (App.bars.tbar && App.bars.tbar.el)
                App.bars.tbar.el.removeClass('toolbar-busy');
        },
        insert: function() {
            this.disableForm();

            var values = this.getValues();
            if (values)
            {
                var entry = this.createEntryForInsert(values);

                var request = this.createRequest();
                if (request)
                    request.create(entry, {
                        success: function(created) {
                            this.enableForm();

                            App.fireEvent('refresh', {
                                resourceKind: this.resourceKind
                            });

                            ReUI.back();
                        },
                        failure: function(response, o) {
                            this.enableForm();
                        },
                        scope: this
                    });
            }
            else
            {
                ReUI.back();
            }
        },
        update: function() {
            var values = this.getValues();
            if (values)
            {
                this.disableForm();

                var entry = this.createEntryForUpdate(values);

                var request = this.createRequest();
                if (request)
                    request.update(entry, {
                        success: function(modified) {
                            this.enableForm();

                            App.fireEvent('refresh', {
                                resourceKind: this.resourceKind,
                                key: modified['$key'],
                                data: {
                                    '$descriptor': modified['$descriptor']
                                }
                            });

                            ReUI.back();
                        },
                        failure: function(response, o) {
                            this.enableForm();
                        },
                        scope: this
                    });
            }
            else
            {
                ReUI.back();
            }
        },
        showValidationSummary: function() {
            var content = [];

            for (var i = 0; i < this.errors.length; i++)
                content.push(this.validationSummaryItemTemplate.apply(this.errors[i], this.fields[this.errors[i].name]));

            this.validationContentEl.update(content.join(''));

            ReUI.DomHelper.wait(scrollTo, 0, 0, 1)
        },
        save: function() {
            if (this.isFormDisabled())  return;

            if (this.validate() !== false)
            {
                this.el.addClass('panel-form-error');

                this.showValidationSummary();

                return;
            }
            else
            {
                this.el.removeClass('panel-form-error');
            }

            if (this.inserting)
                this.insert();
            else
                this.update();
        },
        getContext: function() {
            return Ext.apply(Sage.Platform.Mobile.Edit.superclass.getContext.call(this), {
                resourceKind: this.resourceKind,
                insert: this.options.insert,
                key: this.options.insert ? false : this.options.entry && this.options.entry['$key']
            });
        },
        beforeTransitionTo: function() {
            Sage.Platform.Mobile.Edit.superclass.beforeTransitionTo.call(this);

            if (this.refreshRequired)
            {
                if (this.options.insert === true)
                    this.el.addClass('panel-loading');
                else
                    this.el.removeClass('panel-loading');
            }
        },
        refresh: function() {
            this.entry = false;
            this.inserting = (this.options.insert === true);

            this.clearValues();

            if (this.inserting)
            {
                this.requestTemplateData();
            }
            else
            {
                this.entry = this.options.entry;
                this.setValues(this.options.entry || {});
            }
        },
        transitionTo: function() {
            Sage.Platform.Mobile.Edit.superclass.transitionTo.call(this);
        }
    });
})();
<commit_msg>fixed address insert/update issue.<commit_after>/// <reference path="../libraries/Simplate.js"/>
/// <reference path="../libraries/reui/reui.js"/>
/// <reference path="../libraries/ext/ext-core-debug.js"/>
/// <reference path="../libraries/sdata/sdata-client-dependencies-debug.js"/>
/// <reference path="../libraries/sdata/sdata-client-debug.js"/>
/// <reference path="View.js"/>

Ext.namespace('Sage.Platform.Mobile');
Ext.namespace('Sage.Platform.Mobile.Controls');

(function() {
    Sage.Platform.Mobile.Edit = Ext.extend(Sage.Platform.Mobile.View, {
        attachmentPoints: {
            contentEl: '.panel-content',
            validationContentEl: '.panel-validation-summary > ul'
        },
        viewTemplate: new Simplate([
            '
',
            '{%! $.loadingTemplate %}',
            '{%! $.validationSummaryTemplate %}',
            '

',
            '
'
        ]),
        loadingTemplate: new Simplate([
            '<fieldset class="panel-loading-indicator">',
            '

{%: $.loadingText %}

',
            '</fieldset>'
        ]),
        validationSummaryTemplate: new Simplate([
            '
',
            '
{%: $.validationSummaryText %}
',
            '
',
            '
',
            '
'
        ]),
        validationSummaryItemTemplate: new Simplate([
            '
',
            '',
            '
{%: $.message %}
',
            '
{%: $$.label %}
',
            '',
            '
'
        ]),
        sectionBeginTemplate: new Simplate([
            '
{%: $.title %}
',
            '{% if ($.list) { %}
{% } else { %}<fieldset>{% } %}'
        ]),
        sectionEndTemplate: new Simplate([
            '{% if ($.list) { %}
{% } else { %}</fieldset>{% } %}'
        ]),
        propertyTemplate: new Simplate([
            '',
            '
',
            '
'
        ]),
        transitionEffect: 'flip',
        id: 'generic_edit',
        expose: false,
        saveText: 'Save',
        titleText: 'Edit',
        validationSummaryText: 'Validation Summary',
        detailsText: 'Details',
        loadingText: 'loading...',
        requestErrorText: 'A server error occured while requesting data.',
        constructor: function(o) {
            this.fields = {};

            Sage.Platform.Mobile.Edit.superclass.constructor.apply(this, arguments);
        },
        render: function() {
            Sage.Platform.Mobile.Edit.superclass.render.apply(this, arguments);

            this.processLayout(this.createLayout(), {title: this.detailsText});

            this.el
                .select('div[data-field]')
                .each(function(value) {
                    var el = Ext.get(value.dom),
                        name = el.getAttribute('data-field'),
                        field = this.fields[name];
                    if (field)
                        field.renderTo(el);
                }, this);
        },
        init: function() {
            Sage.Platform.Mobile.Edit.superclass.init.apply(this, arguments);

            for (var name in this.fields) this.fields[name].init();

            this.tools.tbar = [{
                name: 'save',
                title: this.saveText,
                cls: 'button',
                fn: this.save,
                scope: this
            }];
        },
        createRequest: function() {
            var request = new Sage.SData.Client.SDataSingleResourceRequest(this.getService());

            if (this.entry && this.entry['$key'])
                request.setResourceSelector(String.format("'{0}'", this.entry['$key']));

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            if (this.queryOrderBy)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.OrderBy, this.queryOrderBy);

            return request;
        },
        createTemplateRequest: function() {
            var request = new Sage.SData.Client.SDataTemplateResourceRequest(this.getService());

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            return request;
        },
        createLayout: function() {
            return this.layout || [];
        },
        processLayout: function(layout, options)
        {
            var sections = [];
            var content = [];

            content.push(this.sectionBeginTemplate.apply(options));

            for (var i = 0; i < layout.length; i++)
            {
                var current = layout[i];

                if (current['as'])
                {
                    sections.push(current);
                    continue;
                }
                else
                {
                    var ctor = Sage.Platform.Mobile.Controls.FieldManager.get(current['type']),
                        field = this.fields[current['name']] = new ctor(Ext.apply({
                            owner: this
                        }, current)),
                        template = field.propertyTemplate || this.propertyTemplate;

                    content.push(template.apply(field));
                }
            }

            content.push(this.sectionEndTemplate.apply(options));

            Ext.DomHelper.append(this.contentEl, content.join(''));

            for (var i = 0; i < sections.length; i++)
            {
                var current = sections[i];

                this.processLayout(current['as'], current['options']);
            }
        },
        requestFailure: function(response, o) {
            alert(String.format(this.requestErrorText, response, o));
        },
        requestData: function() {
            var request = this.createRequest();
            if (request)
                request.read({
                    success: this.processEntry,
                    failure: this.requestFailure,
                    scope: this
                });
        },
        requestTemplateFailure: function() {
            alert(String.format(this.requestErrorText, response, o));
        },
        requestTemplateData: function() {
            var request = this.createTemplateRequest();
            if (request)
                request.read({
                    success: this.processTemplateEntry,
                    failure: this.requestTemplateFailure,
                    scope: this
                });
        },
        processEntry: function(entry) {
            // not currently used
        },
        processTemplateEntry: function(entry) {
            this.setValues(entry || {});
            this.el.removeClass('panel-loading');
        },
        clearValues: function() {
            for (var name in this.fields)
            {
                this.fields[name].clearValue();
            }
        },
        setValues: function(o) {
            for (var name in this.fields)
            {
                var value = Sage.Platform.Mobile.Utility.getValue(o, name);

                this.fields[name].setValue(value);
            }
        },
        getValues: function(ignoreDirtyFlag) {
            var o = {};
            var empty = true;

            for (var name in this.fields)
            {
                if (ignoreDirtyFlag || this.fields[name].alwaysUseValue || this.fields[name].isDirty())
                {
                    var value = this.fields[name].getValue();

                    Sage.Platform.Mobile.Utility.setValue(o, name, value);

                    empty = false;
                }
            }
            return empty ? false : o;
        },
        validate: function() {
            this.errors = [];

            for (var name in this.fields)
            {
                var result;
                if (false !== (result = this.fields[name].validate()))
                {
                    this.fields[name].el.addClass('panel-field-error');

                    this.errors.push({
                        name: name,
                        message: result
                    });
                }
                else
                {
                    this.fields[name].el.removeClass('panel-field-error');
                }
            }

            return this.errors.length > 0
                ? this.errors
                : false;
        },
        createEntryForUpdate: function(values) {
            return Ext.apply(values, {
                '$key': this.entry['$key'],
                '$etag': this.entry['$etag'],
                '$name': this.entry['$name']
            });
        },
        createEntryForInsert: function(values) {
            return Ext.apply(values, {
                '$name': this.entityName
            });
        },
        isFormDisabled: function() {
            return this.busy;
        },
        disableForm: function() {
            this.busy = true;
            this.el.addClass('view-busy');
            if (App.bars.tbar && App.bars.tbar.el)
                App.bars.tbar.el.addClass('toolbar-busy');
        },
        enableForm: function() {
            this.busy = false;
            this.el.removeClass('view-busy');
            if (App.bars.tbar && App.bars.tbar.el)
                App.bars.tbar.el.removeClass('toolbar-busy');
        },
        insert: function() {
            this.disableForm();

            var values = this.getValues();
            if (values)
            {
                var entry = this.createEntryForInsert(values);

                var request = this.createRequest();
                if (request)
                    request.create(entry, {
                        success: function(created) {
                            this.enableForm();

                            App.fireEvent('refresh', {
                                resourceKind: this.resourceKind
                            });

                            ReUI.back();
                        },
                        failure: function(response, o) {
                            this.enableForm();
                        },
                        scope: this
                    });
            }
            else
            {
                ReUI.back();
            }
        },
        update: function() {
            var values = this.getValues();
            if (values)
            {
                this.disableForm();

                var entry = this.createEntryForUpdate(values);

                var request = this.createRequest();
                if (request)
                    request.update(entry, {
                        success: function(modified) {
                            this.enableForm();

                            App.fireEvent('refresh', {
                                resourceKind: this.resourceKind,
                                key: modified['$key'],
                                data: {
                                    '$descriptor': modified['$descriptor']
                                }
                            });

                            ReUI.back();
                        },
                        failure: function(response, o) {
                            this.enableForm();
                        },
                        scope: this
                    });
            }
            else
            {
                ReUI.back();
            }
        },
        showValidationSummary: function() {
            var content = [];

            for (var i = 0; i < this.errors.length; i++)
                content.push(this.validationSummaryItemTemplate.apply(this.errors[i], this.fields[this.errors[i].name]));

            this.validationContentEl.update(content.join(''));

            ReUI.DomHelper.wait(scrollTo, 0, 0, 1)
        },
        save: function() {
            if (this.isFormDisabled())  return;

            if (this.validate() !== false)
            {
                this.el.addClass('panel-form-error');

                this.showValidationSummary();

                return;
            }
            else
            {
                this.el.removeClass('panel-form-error');
            }

            if (this.inserting)
                this.insert();
            else
                this.update();
        },
        getContext: function() {
            return Ext.apply(Sage.Platform.Mobile.Edit.superclass.getContext.call(this), {
                resourceKind: this.resourceKind,
                insert: this.options.insert,
                key: this.options.insert ? false : this.options.entry && this.options.entry['$key']
            });
        },
        beforeTransitionTo: function() {
            Sage.Platform.Mobile.Edit.superclass.beforeTransitionTo.call(this);

            if (this.refreshRequired)
            {
                if (this.options.insert === true)
                    this.el.addClass('panel-loading');
                else
                    this.el.removeClass('panel-loading');
            }
        },
        refresh: function() {
            this.entry = false;
            this.inserting = (this.options.insert === true);

            this.clearValues();

            if (this.inserting)
            {
                this.requestTemplateData();
            }
            else
            {
                this.entry = this.options.entry;
                this.setValues(this.options.entry || {});
            }
        },
        transitionTo: function() {
            Sage.Platform.Mobile.Edit.superclass.transitionTo.call(this);
        }
    });
})();
<|endoftext|>


<commit_before>const _ = require('lodash');
const pc = require('../../pathway-commons');
const logger = require('./../../logger');
const LRUCache = require('lru-cache');
const cache = require('../../cache');
const { PC_CACHE_MAX_SIZE } = require('../../../config');
const cytoscape = require('cytoscape');

function edgeType(type) {
  switch(type){
    case 'in-complex-with':
    case 'interacts-with':
      return 'Binding';
    case 'controls-phosphorylation-of':
      return 'Phosphorylation';
    case 'controls-expression-of':
      return 'Expression';
    default:
      return '';
  }
}

function rawGetInteractionGraphFromPC(interactionIDs){
  const geneIds = _.uniq(_.concat([], interactionIDs)); //convert sources to array

  const params = {
    cmd : 'graph',
    source : geneIds,
    pattern : ['controls-phosphorylation-of','in-complex-with','controls-expression-of', 'interacts-with'],
    kind : geneIds.length > 1 ? 'pathsbetween' : 'neighborhood',
    format : 'txt'
  };

  //Fetch graph from PC
  return pc.query(params).then(res => {

    console.time('parse');
    let parsedNetwork = parse(res,geneIds);
    console.timeEnd('parse');

    console.time('total');
    let filteredNetwork = addMetricandFilter(parsedNetwork.network, parsedNetwork.nodeDegrees);
    console.timeEnd('total');

    return {network: filteredNetwork};
  }).catch((e)=>{
    logger.error(e);
    return 'ERROR : could not retrieve graph from PC';
  });
}

const pcCache = LRUCache({ max: PC_CACHE_MAX_SIZE, length: () => 1 });

const getInteractionGraphFromPC = cache(rawGetInteractionGraphFromPC, pcCache);

/**
 * Parse txt format to Json
 * @param {string} data graph in txt format
 * @param {String[]} Array of query Ids
 * @return {json} JSON of graph
 */
function parse(data, queryIds){
  let network = {
    edges:[],
    nodes:[],
  };
  let nodeDegreeMap =new Map(); //keeps track of nodes that have already been added, also calculates node degree
  if(data){
    const dataSplit=data.split('\n\n');
    const nodeMetadata= new Map(dataSplit[1].split('\n').slice(1).map(line =>line.split('\t')).map(line => [line[0], line.slice(1) ]));
    dataSplit[0].split('\n').slice(1).forEach(line => {
      const splitLine=line.split('\t');
      const edgeMetadata = interactionMetadata(splitLine[6],splitLine[4]);
      addInteraction([splitLine[0], splitLine[2]], splitLine[1], edgeMetadata, network, nodeDegreeMap, nodeMetadata, queryIds);
    });
    return {network: network, nodeDegrees:nodeDegreeMap};
  }
  return {};
}

/**
 *
 * @param {*} network JSON containing nodes and edges that represent a network
 * @returns A network JSON with 50 nodes, sorted based on centrality & degree
 * @description Each node in the network is assigned a `degree` metric, and the network is filtered down to the 100 nodes with largest degree.
 * The remaining 100 nodes are assigned a `betweenness centrality (BC)` metric, and the network is filtered down to the 50 nodes with largest BC.
 */
function addMetricandFilter(network,nodeDegrees){
  const nodes = network.nodes;
  const edges = network.edges;

  console.time("Sort/Filter Nodes");
  //sort nodes by degree
  let sortedNodes = nodes.sort( (a,b) => {
    return nodeDegrees.get(b.data.id).length - nodeDegrees.get(a.data.id).length;
  });

  //keep the 100 nodes with the largest degree
  let filteredNodes = sortedNodes.slice(0,50);
  filteredNodes.forEach( node => {
    node.data['metric'] = nodeDegrees.get(node.data.id);
  });
  console.timeEnd("Sort/Filter Nodes");

  console.time('cy');
  const cy = cytoscape( { headless:true, container:undefined, elements:{nodes:filteredNodes} } );
  console.timeEnd('cy');

  console.time('Filter Edges');
  const filteredEdges = [];
  edges.forEach( edge => {
    const source = edge.data.source;
    const target = edge.data.target;
    let sourceFound = false;
    let targetFound = false;
    filteredNodes.forEach( node => {
      if(node.data.id === source)
        sourceFound = true;
      if(node.data.id === target)
        targetFound = true;
    });
    if(sourceFound && targetFound)
      filteredEdges.push(edge);
  });
  console.timeEnd('Filter Edges');

  console.log(filteredEdges.length);

  console.time('Add Edges');
  filteredEdges.forEach( edge => {
    try{
      cy.add({
        group: 'edges',
        data: edge.data,
        classes: edge.classes,
      });
    }catch(err){ return; }
  });
  console.timeEnd('Add Edges');

  return cy.json().elements;
}

function interactionMetadata(mediatorIds, pubmedIds){
  let metadata = [['List',[]],['Detailed Views',[]]];//Format expected by format-content
  mediatorIds.split(';').forEach( link => {
    const id=link.split('/')[4];
    metadata[1][1].push(link.includes('reactome') ? ['Reactome',id]:['Pathway Commons',id]);
  });
  if(pubmedIds){
   pubmedIds.split(';').forEach(id=>metadata[0][1].push(['PubMed',id]));
  }
 return metadata;
}

function addInteraction(nodes, edge, sources, network, nodeDegreeMap, nodeMetadata, interactionIDs){
  const interaction= edgeType(edge);
  const networkEdgeData = {data: {
    id: nodes[0]+'\t'+edge+'\t'+nodes[1] ,
    label: nodes[0]+' '+edge.replace(/-/g,' ')+' '+nodes[1] ,
    source: nodes[0],
    target: nodes[1],
    class: interaction,
    parsedMetadata:sources
  },classes:interaction};

  nodes.forEach((node)=>{
    if(!nodeDegreeMap.has(node)){
      const metadata=nodeMetadata.get(node);
      const links=_.uniqWith(_.flatten(metadata.slice(-2).map(entry => entry.split(';').map(entry=>entry.split(':')))),_.isEqual).filter(entry=>entry[0]!='intact');
      nodeDegreeMap.set(node,1);
      network.nodes.push({data:{
        class: "ball",
        id: node,
        label: node,
        queried: interactionIDs.indexOf(node) != -1,
        parsedMetadata:[
          ['Type',
          'bp:'+metadata[0].split(' ')[0].replace(/Reference/g,'').replace(/;/g,',')],
          ['Database IDs', links]
        ]
      }});
    }
    else {
      let degree = nodeDegreeMap.get(node);
      nodeDegreeMap.set(node, degree+1);
    }
  });

  network.edges.push(networkEdgeData);

}

module.exports = {getInteractionGraphFromPC};<commit_msg>updated with max's suggestions WITH CONSOLE TIMING<commit_after>const _ = require('lodash');
const pc = require('../../pathway-commons');
const logger = require('./../../logger');
const LRUCache = require('lru-cache');
const cache = require('../../cache');
const { PC_CACHE_MAX_SIZE } = require('../../../config');
const cytoscape = require('cytoscape');

function edgeType(type) {
  switch(type){
    case 'in-complex-with':
    case 'interacts-with':
      return 'Binding';
    case 'controls-phosphorylation-of':
      return 'Phosphorylation';
    case 'controls-expression-of':
      return 'Expression';
    default:
      return '';
  }
}

function rawGetInteractionGraphFromPC(interactionIDs){
  const geneIds = _.uniq(_.concat([], interactionIDs)); //convert sources to array

  const params = {
    cmd : 'graph',
    source : geneIds,
    pattern : ['controls-phosphorylation-of','in-complex-with','controls-expression-of', 'interacts-with'],
    kind : geneIds.length > 1 ? 'pathsbetween' : 'neighborhood',
    format : 'txt'
  };

  //Fetch graph from PC
  return pc.query(params).then(res => {

    console.time('Total');

    console.time('Parse');
    let parsedNetwork = parse(res,geneIds);
    console.timeEnd('Parse');

    console.time('Filter');
    let filteredNetwork = addMetricandFilter(parsedNetwork.nodes, parsedNetwork.edges);
    console.timeEnd('Filter');

    console.timeEnd('Total');

    return {network: filteredNetwork};
  }).catch((e)=>{
    logger.error(e);
    return 'ERROR : could not retrieve graph from PC';
  });
}

const pcCache = LRUCache({ max: PC_CACHE_MAX_SIZE, length: () => 1 });

const getInteractionGraphFromPC = cache(rawGetInteractionGraphFromPC, pcCache);

/**
 * Parse txt format to Json
 * @param {string} data graph in txt format
 * @param {String[]} Array of query Ids
 * @return {json} JSON of graph
 */
function parse(data, queryIDs){
  let edgeList = [];
  let nodeList =new Map(); //maps node id to node (to avoid duplicate entries)

  if(data){

    const dataSplit=data.split('\n\n');
    const nodeMetadata= new Map(dataSplit[1].split('\n').slice(1).map(line =>line.split('\t')).map(line => [line[0], line.slice(1) ]));
    dataSplit[0].split('\n').slice(1).forEach(line => {
      const splitLine=line.split('\t');
      const edgeMetadata = interactionMetadata(splitLine[6],splitLine[4]);
      addInteraction([splitLine[0], splitLine[2]], splitLine[1], nodeList, edgeList, nodeMetadata, edgeMetadata, queryIDs);
    });

    //return network
    return {nodes: nodeList, edges: edgeList};
  }
  return {};
}

/**
 *
 * @param {*} network JSON containing nodes and edges that represent a network
 * @returns A network JSON with 50 nodes, sorted based on centrality & degree
 * @description Each node in the network is assigned a `degree` metric, and the network is filtered down to the 100 nodes with largest degree.
 * The remaining 100 nodes are assigned a `betweenness centrality (BC)` metric, and the network is filtered down to the 50 nodes with largest BC.
 */
function addMetricandFilter(nodes,edges){

  console.time('Filter Nodes');
  const filteredNodes = new Map(
    [...nodes.entries()].sort( (a, b) => {
      return b[1].data.metric - a[1].data.metric;
    }).slice(0,50)
  );
  console.timeEnd('Filter Nodes');

  console.time('Filter Edges');
  const filteredEdges = [];
  edges.forEach( edge => {
    const source = edge.data.source;
    const target = edge.data.target;
    if(filteredNodes.has(source) && filteredNodes.has(target))
      filteredEdges.push(edge);
  });
  console.timeEnd('Filter Edges');

  return { nodes:[...filteredNodes.values()], edges:filteredEdges };
}

function interactionMetadata(mediatorIds, pubmedIds){
  let metadata = [['List',[]],['Detailed Views',[]]];//Format expected by format-content
  mediatorIds.split(';').forEach( link => {
    const id=link.split('/')[4];
    metadata[1][1].push(link.includes('reactome') ? ['Reactome',id]:['Pathway Commons',id]);
  });
  if(pubmedIds){
   pubmedIds.split(';').forEach(id=>metadata[0][1].push(['PubMed',id]));
  }
 return metadata;
}

function addInteraction(nodes, edge, nodeList, edgeList, nodeMetadata, edgeMetadata, queryIDs){
  const interaction= edgeType(edge);
  const networkEdgeData = {data: {
    id: nodes[0]+'\t'+edge+'\t'+nodes[1] ,
    label: nodes[0]+' '+edge.replace(/-/g,' ')+' '+nodes[1] ,
    source: nodes[0],
    target: nodes[1],
    class: interaction,
    parsedMetadata:edgeMetadata
  },classes:interaction};
  edgeList.push(networkEdgeData);

  nodes.forEach((node)=>{
    if(!nodeList.has(node)){
      const metadata=nodeMetadata.get(node);
      const links=_.uniqWith(_.flatten(metadata.slice(-2).map(entry => entry.split(';').map(entry=>entry.split(':')))),_.isEqual).filter(entry=>entry[0]!='intact');
      const networkNodeData = {data:{
        class: "ball",
        id: node,
        label: node,
        queried: queryIDs.indexOf(node) != -1,
        metric: 1,
        parsedMetadata:[
          ['Type',
          'bp:'+metadata[0].split(' ')[0].replace(/Reference/g,'').replace(/;/g,',')],
          ['Database IDs', links]
        ]
      }};
      nodeList.set(node,networkNodeData);
    }
    else {
      //metric is degree
      let nodeUpdate = nodeList.get(node);
      nodeUpdate.data['metric'] = nodeUpdate.data.metric + 1;
      nodeList.set(node, nodeUpdate);
    }
  });
}

module.exports = {getInteractionGraphFromPC};<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Mixin.create({

    /// <param name="error">
    ///     DS.InvalidError
    ///     jqXHR
    ///     string
    ///     array of strings
    /// </param>
    /// <returns type="array" />
    getErrorMessages: function(error) {

        // When rejected after calling record.save().then(resolve, reject), it's easiest
        // to pass in the reason parameter as the error object for this function.
        // if server returns 422, then the reason parameter will be DS.InvalidError, otherwise, it will be jqXHR

        // When substate goes into error, easiest just to pass in the error substate model.
        // if server returns 422, then the model will be DS.InvalidError, otherwise, it will be jqXHR

        if (Ember.typeOf(error) === 'string')
            return [ error ];

        if (Ember.typeOf(error) === 'array')
            return error;

        // interestingly, DS.InvalidError contains all of the error messages, even for the attributes (e.g. base) that don't exist in the model.
        // DS.Errors, which is attached to the model as record.get('errors'), only contains the errors for the attributes that are on the model. http://stackoverflow.com/a/24031233/188740
        if (error instanceof DS.InvalidError)
            return this._messagesFromObject(error.errors);

        if (Ember.typeOf(error.responseJSON) === 'object' && Ember.typeOf(error.responseJSON.errors) === 'object')
            return this._messagesFromObject(error.responseJSON.errors);

        return ['There was an unexpected error.'];
    },

    _messagesFromObject: function(object) {

        /*jshint loopfunc: true */

        var messages = [];
        for (var key in object) {
            var value = object[key];
            if(Ember.typeOf(value) === 'array')
                value.forEach(
                    function(message) {
                        messages.push(this._concatenateMessage(key, message));
                    }.bind(this)
                );
            else
                messages.push(this._concatenateMessage(key, value));
        }

        return messages;
    },

    _concatenateMessage: function(key, value) {
        if (key === 'base')
            return value;
        else
            return this._titleize(key) + ' ' + value;
    },

    _titleize: function(s) {
        return s.underscore().replace(/_/g, ' ').capitalize();
    }

});
<commit_msg>Improved error message extraction.<commit_after>import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Mixin.create({

    /// <param name="error">
    ///     DS.InvalidError
    ///     jqXHR
    ///     string
    ///     array of strings
    /// </param>
    /// <returns type="array" />
    getErrorMessages: function(error) {

        // When rejected after calling record.save().then(resolve, reject), it's easiest
        // to pass in the reason parameter as the error object for this function.
        // if server returns 422, then the reason parameter will be DS.InvalidError, otherwise, it will be jqXHR

        // When substate goes into error, easiest just to pass in the error substate model.
        // if server returns 422, then the model will be DS.InvalidError, otherwise, it will be jqXHR

        if (Ember.typeOf(error) === 'string')
            return [ error ];

        if (Ember.typeOf(error) === 'array')
            return error;

        // interestingly, DS.InvalidError contains all of the error messages, even for the attributes (e.g. base) that don't exist in the model.
        // DS.Errors, which is attached to the model as record.get('errors'), only contains the errors for the attributes that are on the model. http://stackoverflow.com/a/24031233/188740
        if (error instanceof DS.InvalidError)
            return this._messagesFromObject(error.errors);

        if (Ember.typeOf(error.responseJSON) === 'object' && Ember.typeOf(error.responseJSON.errors) === 'object')
            return this._messagesFromObject(error.responseJSON.errors);

        if (Ember.typeOf(error.message) === 'string')
            return [ error.message ];

        return ['There was an unexpected error.'];
    },

    _messagesFromObject: function(object) {

        /*jshint loopfunc: true */

        var messages = [];
        for (var key in object) {
            var value = object[key];
            if(Ember.typeOf(value) === 'array')
                value.forEach(
                    function(message) {
                        messages.push(this._concatenateMessage(key, message));
                    }.bind(this)
                );
            else
                messages.push(this._concatenateMessage(key, value));
        }

        return messages;
    },

    _concatenateMessage: function(key, value) {
        if (key === 'base')
            return value;
        else
            return this._titleize(key) + ' ' + value;
    },

    _titleize: function(s) {
        return s.underscore().replace(/_/g, ' ').capitalize();
    }

});
<|endoftext|>


<commit_before>/**
 * CG Space Invaders
 * CG45179 16'17
 *
 * @author: Rui Ventura ( ist181045 )
 * @author: Diogo Freitas ( ist181586 )
 * @author: Sara Azinhal ( ist181700 )
 */

import './lib/threejs/polyfills.js';
import * as THREE from './lib/threejs/constants';

import { WebGLRenderer } from './lib/threejs/renderers/WebGLRenderer';
import { Scene } from './lib/threejs/scenes/Scene';

import { OrthographicCamera } from './lib/threejs/cameras/OrthographicCamera';
import { PerspectiveCamera } from './lib/threejs/cameras/PerspectiveCamera';

import { DirectionalLight } from './lib/threejs/lights/DirectionalLight';
import { PointLight } from './lib/threejs/lights/PointLight';

import { Clock } from './lib/threejs/core/Clock';

import { Mesh } from './lib/threejs/objects/Mesh';
import { MeshBasicMaterial } from './lib/threejs/materials/MeshBasicMaterial';
import { PlaneGeometry } from './lib/threejs/geometries/PlaneGeometry';
import { TextureLoader } from './lib/threejs/loaders/TextureLoader';

import { WIDTH, HEIGHT } from './Constants';
import { WINDOW_PIXEL_RATIO, WINDOW_WIDTH, WINDOW_HEIGHT } from './Constants';

import GameHUD from './scenes/GameHUD';

import Field from './objects/Field';
import EnemyShip from './entities/EnemyShip';
import PlayerShip from './entities/PlayerShip';

import * as Keyboard from './Keyboard';

class Game {

	constructor () {

		this.renderer = (function () {

			let renderer = new WebGLRenderer({ antialias: true });

			renderer.setPixelRatio( WINDOW_PIXEL_RATIO );
			renderer.setSize( WINDOW_WIDTH(), WINDOW_HEIGHT() );
			renderer.autoClear = false;

			return renderer;

		})();
		this.scene = new Scene();

		this.gameClock = new Clock( false );

		this.field = new Field( 0, 0, 0, WIDTH - 10, HEIGHT - 10 );

		this.cameras = (function ( self ) {

			let cameras = new Array();

			/* Ortho camera (bird's eye) */
			cameras.push( function () {

				let camera = new OrthographicCamera(
					WIDTH / -2, WIDTH / 2, HEIGHT / 2, HEIGHT / -2, 1, 2000
				);

				camera.position.set( 0, 100, 0 );
				camera.lookAt( self.scene.position );

				camera.updateProjectionMatrix();

				return camera;

			}());

			/* Back perspective camera */
			cameras.push( function () {

				let camera = new PerspectiveCamera(
					75, WINDOW_WIDTH() / WINDOW_HEIGHT(), 1, 1000
				);

				camera.position.set( 0, 250, ( self.field.height / 2 ) + 150 );
				camera.lookAt( self.scene.position );

				camera.updateProjectionMatrix();

				return camera;

			}());

			return cameras;

		})( this );
		this.camera = this.cameras[0];

		this.gameObjects = new Array();

		this.playerShip = new PlayerShip( 0, 0, ( this.field.height / 2 ) - 50,
			new PerspectiveCamera( 75, WINDOW_WIDTH() / WINDOW_HEIGHT(), 1, 1000 ) );

		this.HUD = new GameHUD( this.renderer, this.playerShip.MAX_LIVES );

		this.sun = (function ( self ) {

			let sun = new DirectionalLight( 0xffffff, 1 );

			sun.position.set( self.field.width / -4, 100, self.field.height / 4 );
			sun.target = self.scene;

			return sun;

		})( this );
		this.stars = (function ( self, n ) {

			let stars = new Array();

			for ( let i = 0; i < n; ++i ) {

				stars.push( new PointLight( 0xffffff, 0.5 ) );

			}

			return stars;

		}( this, 6 ));

		this.lightsOn = false;

		this.gameOver = false;

		document.body.appendChild( this.renderer.domElement );

		window.addEventListener( 'resize',  this.resize.bind( this ) );
		window.addEventListener( 'keydown', this.keyDown.bind( this ) );
		window.addEventListener( 'keyup',   this.keyUp.bind( this ) );

		this.setup();

		/* HACK: Force a first resize */
		this.resize();

		this.update();

	}

	setup () {

		/* Clear the scene + reset gameObjects array */
		this.scene.children.length = 0;
		this.gameObjects.length = 0;

		/* Build the scene */
		this.scene.add( function () {

			let bgMesh = new Mesh(

				new PlaneGeometry( 10 * WIDTH, 8 * WIDTH ),
				new MeshBasicMaterial()

			);

			let loader = new TextureLoader();
			let texture = loader.load( './resources/bg/game_scene_bg.jpg' );
			texture.wrapS = THREE.RepeatWrapping;
			texture.wrapT = THREE.RepeatWrapping;
			texture.repeat.multiplyScalar( 7 );

			bgMesh.rotateX( -Math.PI / 6 );
			bgMesh.position.set( 0, -20, HEIGHT / -2 );

			bgMesh.material.map = texture;

			return bgMesh;

		}());

		this.field.children.forEach( function ( b ) {

			b.type === 'Barrier' && this.gameObjects.push( b );

		}, this );

		this.field.changeMaterial( 0 );
		this.field.visible = false;
		this.scene.add( this.field );

		this.playerShip = new PlayerShip( 0, 0, ( this.field.height / 2 ) - 50,
			new PerspectiveCamera( 75, WINDOW_WIDTH() / WINDOW_HEIGHT(), 1, 1000 ) );

		this.HUD.setup();

		this.cameras.length > 2 && this.cameras.pop();
		this.cameras.push( this.playerShip.camera );
		this.camera = this.cameras[0];

		this.gameObjects.push( this.playerShip );
		this.scene.add( this.playerShip );

		let [ nx, nz ] = [ 5, 2 ];
		let [ segX, segZ ] = [
			( this.field.width - 120 ) / nx,
			( ( this.field.height - 120 ) / 2 ) / nz
		];

		for ( let i = 0; i < nz; ++i ) {

			for ( let j = 0; j < nx; ++j ) {

				let [ posX, posZ ] = [
					segX * ( j - ( ( nx - 1 ) / 2 ) ),
					segZ * ( i - ( ( nz + 1 ) / 2 ) )
				];

				let alien = new EnemyShip( posX, 0, posZ );

				this.gameObjects.push( alien );
				this.scene.add( alien );

			}

		}

		this.lightsOn = false;
		this.sun.visible = false;
		this.scene.add( this.sun );

		this.stars.forEach( function ( star ) {

			star.position.set(
				this.field.width * ( Math.random() - 0.5 ),
				100,
				this.field.height * ( Math.random() - 0.5 )
			);

			star.visible = false;
			this.scene.add( star );

		}, this );

		this.gameOver = false;

	}

	update () {

		if ( this.gameClock.running ) {

			let dt = this.gameClock.getDelta();

			if ( EnemyShip.count === 0 || !this.playerShip.alive ) {

				this.gameOver = true;
				this.gameClock.stop();
				this.HUD.setVisibility();

			} else {

				if ( this.playerShip.shooting ) {

					let playerBullet = this.playerShip.fire();

					if ( playerBullet !== null ) {

						this.scene.add( playerBullet );
						this.gameObjects.push( playerBullet );

					}

				}

				for ( let i = 0; i < this.gameObjects.length; ++i ) {

					let o1 = this.gameObjects[i];

					o1.update( dt );

					for ( let j = i + 1; j < this.gameObjects.length; ++j ) {

						let o2 = this.gameObjects[j];

						o1.intersect( o2 ) && o1.handleCollision( o2 );

					}

					if ( o1.isEntity && !o1.alive ) {

						this.scene.remove( o1 );
						this.gameObjects.splice( i--, 1 );

					}

				}

				if ( this.playerShip.lives < this.HUD.lives ) {

					--this.HUD.lives;
					this.HUD.setVisibility();

				}

			}

		}

		this.renderer.clear();
		this.renderer.setViewport( 0, 0, WINDOW_WIDTH(), WINDOW_HEIGHT() );
		this.renderer.render( this.scene, this.camera );

		this.HUD.update();

		window.requestAnimationFrame( this.update.bind( this ) );

	}

	updateMaterials () {

		this.gameObjects.forEach( function ( obj ) {

			let index = this.lightsOn ? (obj.phong ? 1 : 2) : 0;

			obj.phong = !obj.phong;

			obj.changeMaterial( index );

		}, this );

	}

	resize () {

		this.renderer.setSize( WINDOW_WIDTH(), WINDOW_HEIGHT() );

		let size = this.renderer.getSize();
		let ratio = size.width / size.height;

		if ( this.camera.type === 'OrthographicCamera' ) {

			if ( ratio > ( WIDTH / HEIGHT ) ) {

				this.camera.left   = ( HEIGHT * ratio ) / -2;
				this.camera.right  = ( HEIGHT * ratio ) /  2;
				this.camera.top    = HEIGHT /  2;
				this.camera.bottom = HEIGHT / -2;

			} else {

				this.camera.left   = WIDTH / -2;
				this.camera.right  = WIDTH /  2;
				this.camera.top    = ( WIDTH / ratio ) /  2;
				this.camera.bottom = ( WIDTH / ratio ) / -2;

			}

		} else {

			this.camera.aspect = ratio;

		}

		this.camera.updateProjectionMatrix();

	}

	keyDown ( event ) {

		if ( this.gameOver ) {

			/* Restart the game */
			if ( event.keyCode === Keyboard.KEY_R ) {

				this.gameOver = false;
				this.setup();

			}

		} else {

			switch ( event.keyCode ) {

				/* Toggle cameras */
				case Keyboard.KEY_1: /* Orthographic (top bird's eye camera) */
				case Keyboard.KEY_2: /* Perspective (back camera) */
				case Keyboard.KEY_3: /* Perspective (player view camera) */

					if ( this.gameClock.running ) {

						this.camera = this.cameras[ event.keyCode - Keyboard.KEY_1 ];
						this.resize();

					}

					break;

				/* Player movement: Left */
				case Keyboard.KEY_A:
				case Keyboard.KEY_LEFT:

					if ( !this.playerShip.moving ) this.playerShip.moving = true;
					this.playerShip.setDirection( -1, 0, 0 );

					break;

				/* Player movement: Right */
				case Keyboard.KEY_D:
				case Keyboard.KEY_RIGHT:

					if ( !this.playerShip.moving ) this.playerShip.moving = true;
					this.playerShip.setDirection( 1, 0, 0 );

					break;

				/* Player action: Toggle shooting */
				case Keyboard.KEY_B:
				case Keyboard.KEY_SPACEBAR:

					this.playerShip.shooting = true;

					break;

				/* Show / hide stars */
				case Keyboard.KEY_C:

					this.stars.forEach( function( star ) {

						star.visible = !star.visible;

					});

					break;

				/* Toggle lights */
				case Keyboard.KEY_L:

					this.lightsOn = !this.lightsOn;
					this.updateMaterials();

					break;

				case Keyboard.KEY_H: /* Toggle playerShip flashlight */

					this.playerShip.toggleFlashlight();

					break;

				/* Toggle Gouraud / Lambert Shading */
				case Keyboard.KEY_G:

					this.updateMaterials();
					break;

				/* Toggle the sun (day/night modes) */
				case Keyboard.KEY_N:

					this.sun.visible = !this.sun.visible;

					break;

				/* Start / Stop the game (clock) */
				case Keyboard.KEY_S:

					this.gameClock.running ? this.gameClock.stop() : this.gameClock.start();

					break;

				/* Toggle wireframe of the objects in the scene */
				case Keyboard.KEY_W:

					this.gameObjects.forEach( function( obj ) {

						obj.traverse( function ( node ) {

							if ( node.isMesh ) {

								node.material.wireframe = !node.material.wireframe;

							}

						});

					});

					break;

				/* Toggle field visibility */
				case Keyboard.KEY_9:

					this.field.visible = !this.field.visible;

					break;

				default: break;

			}
		}

	}

	keyUp ( event ) {

		switch ( event.keyCode ) {

			case Keyboard.KEY_A:
			case Keyboard.KEY_LEFT:
			case Keyboard.KEY_D:
			case Keyboard.KEY_RIGHT:

				this.playerShip.moving = false;

				break;

			case Keyboard.KEY_B:
			case Keyboard.KEY_SPACEBAR:

				this.playerShip.shooting = false;

				break;

			default: break;

		}
	}

}

new Game();
<commit_msg>Reuse old playerShip camera instead of recreating one<commit_after>/**
 * CG Space Invaders
 * CG45179 16'17
 *
 * @author: Rui Ventura ( ist181045 )
 * @author: Diogo Freitas ( ist181586 )
 * @author: Sara Azinhal ( ist181700 )
 */

import './lib/threejs/polyfills.js';
import * as THREE from './lib/threejs/constants';

import { WebGLRenderer } from './lib/threejs/renderers/WebGLRenderer';
import { Scene } from './lib/threejs/scenes/Scene';

import { OrthographicCamera } from './lib/threejs/cameras/OrthographicCamera';
import { PerspectiveCamera } from './lib/threejs/cameras/PerspectiveCamera';

import { DirectionalLight } from './lib/threejs/lights/DirectionalLight';
import { PointLight } from './lib/threejs/lights/PointLight';

import { Clock } from './lib/threejs/core/Clock';

import { Mesh } from './lib/threejs/objects/Mesh';
import { MeshBasicMaterial } from './lib/threejs/materials/MeshBasicMaterial';
import { PlaneGeometry } from './lib/threejs/geometries/PlaneGeometry';
import { TextureLoader } from './lib/threejs/loaders/TextureLoader';

import { WIDTH, HEIGHT } from './Constants';
import { WINDOW_PIXEL_RATIO, WINDOW_WIDTH, WINDOW_HEIGHT } from './Constants';

import GameHUD from './scenes/GameHUD';

import Field from './objects/Field';
import EnemyShip from './entities/EnemyShip';
import PlayerShip from './entities/PlayerShip';

import * as Keyboard from './Keyboard';

class Game {

	constructor () {

		this.renderer = (function () {

			let renderer = new WebGLRenderer({ antialias: true });

			renderer.setPixelRatio( WINDOW_PIXEL_RATIO );
			renderer.setSize( WINDOW_WIDTH(), WINDOW_HEIGHT() );
			renderer.autoClear = false;

			return renderer;

		})();
		this.scene = new Scene();

		this.gameClock = new Clock( false );

		this.field = new Field( 0, 0, 0, WIDTH - 10, HEIGHT - 10 );

		this.cameras = (function ( self ) {

			let cameras = new Array();

			/* Ortho camera (bird's eye) */
			cameras.push( function () {

				let camera = new OrthographicCamera(
					WIDTH / -2, WIDTH / 2, HEIGHT / 2, HEIGHT / -2, 1, 2000
				);

				camera.position.set( 0, 100, 0 );
				camera.lookAt( self.scene.position );

				camera.updateProjectionMatrix();

				return camera;

			}());

			/* Back perspective camera */
			cameras.push( function () {

				let camera = new PerspectiveCamera(
					75, WINDOW_WIDTH() / WINDOW_HEIGHT(), 1, 1000
				);

				camera.position.set( 0, 250, ( self.field.height / 2 ) + 150 );
				camera.lookAt( self.scene.position );

				camera.updateProjectionMatrix();

				return camera;

			}());

			return cameras;

		})( this );
		this.camera = this.cameras[0];

		this.gameObjects = new Array();

		this.playerShip = new PlayerShip( 0, 0, ( this.field.height / 2 ) - 50,
			new PerspectiveCamera( 75, WINDOW_WIDTH() / WINDOW_HEIGHT(), 1, 1000 ) );

		this.HUD = new GameHUD( this.renderer, this.playerShip.MAX_LIVES );

		this.sun = (function ( self ) {

			let sun = new DirectionalLight( 0xffffff, 1 );

			sun.position.set( self.field.width / -4, 100, self.field.height / 4 );
			sun.target = self.scene;

			return sun;

		})( this );
		this.stars = (function ( self, n ) {

			let stars = new Array();

			for ( let i = 0; i < n; ++i ) {

				stars.push( new PointLight( 0xffffff, 0.5 ) );

			}

			return stars;

		}( this, 6 ));

		this.lightsOn = false;

		this.gameOver = false;

		document.body.appendChild( this.renderer.domElement );

		window.addEventListener( 'resize',  this.resize.bind( this ) );
		window.addEventListener( 'keydown', this.keyDown.bind( this ) );
		window.addEventListener( 'keyup',   this.keyUp.bind( this ) );

		this.setup();

		/* HACK: Force a first resize */
		this.resize();

		this.update();

	}

	setup () {

		/* Clear the scene + reset gameObjects array */
		this.scene.children.length = 0;
		this.gameObjects.length = 0;

		/* Build the scene */
		this.scene.add( function () {

			let bgMesh = new Mesh(

				new PlaneGeometry( 10 * WIDTH, 8 * WIDTH ),
				new MeshBasicMaterial()

			);

			let loader = new TextureLoader();
			let texture = loader.load( './resources/bg/game_scene_bg.jpg' );
			texture.wrapS = THREE.RepeatWrapping;
			texture.wrapT = THREE.RepeatWrapping;
			texture.repeat.multiplyScalar( 7 );

			bgMesh.rotateX( -Math.PI / 6 );
			bgMesh.position.set( 0, -20, HEIGHT / -2 );

			bgMesh.material.map = texture;

			return bgMesh;

		}());

		this.field.children.forEach( function ( b ) {

			b.type === 'Barrier' && this.gameObjects.push( b );

		}, this );

		this.field.changeMaterial( 0 );
		this.field.visible = false;
		this.scene.add( this.field );

		this.playerShip = new PlayerShip( 0, 0, ( this.field.height / 2 ) - 50,
			this.playerShip.camera );

		this.HUD.setup();

		this.camera = this.cameras[0];

		this.gameObjects.push( this.playerShip );
		this.scene.add( this.playerShip );

		let [ nx, nz ] = [ 5, 2 ];
		let [ segX, segZ ] = [
			( this.field.width - 120 ) / nx,
			( ( this.field.height - 120 ) / 2 ) / nz
		];

		for ( let i = 0; i < nz; ++i ) {

			for ( let j = 0; j < nx; ++j ) {

				let [ posX, posZ ] = [
					segX * ( j - ( ( nx - 1 ) / 2 ) ),
					segZ * ( i - ( ( nz + 1 ) / 2 ) )
				];

				let alien = new EnemyShip( posX, 0, posZ );

				this.gameObjects.push( alien );
				this.scene.add( alien );

			}

		}

		this.lightsOn = false;
		this.sun.visible = false;
		this.scene.add( this.sun );

		this.stars.forEach( function ( star ) {

			star.position.set(
				this.field.width * ( Math.random() - 0.5 ),
				100,
				this.field.height * ( Math.random() - 0.5 )
			);

			star.visible = false;
			this.scene.add( star );

		}, this );

		this.gameOver = false;

	}

	update () {

		if ( this.gameClock.running ) {

			let dt = this.gameClock.getDelta();

			if ( EnemyShip.count === 0 || !this.playerShip.alive ) {

				this.gameOver = true;
				this.gameClock.stop();
				this.HUD.setVisibility();

			} else {

				if ( this.playerShip.shooting ) {

					let playerBullet = this.playerShip.fire();

					if ( playerBullet !== null ) {

						this.scene.add( playerBullet );
						this.gameObjects.push( playerBullet );

					}

				}

				for ( let i = 0; i < this.gameObjects.length; ++i ) {

					let o1 = this.gameObjects[i];

					o1.update( dt );

					for ( let j = i + 1; j < this.gameObjects.length; ++j ) {

						let o2 = this.gameObjects[j];

						o1.intersect( o2 ) && o1.handleCollision( o2 );

					}

					if ( o1.isEntity && !o1.alive ) {

						this.scene.remove( o1 );
						this.gameObjects.splice( i--, 1 );

					}

				}

				if ( this.playerShip.lives < this.HUD.lives ) {

					--this.HUD.lives;
					this.HUD.setVisibility();

				}

			}

		}

		this.renderer.clear();
		this.renderer.setViewport( 0, 0, WINDOW_WIDTH(), WINDOW_HEIGHT() );
		this.renderer.render( this.scene, this.camera );

		this.HUD.update();

		window.requestAnimationFrame( this.update.bind( this ) );

	}

	updateMaterials () {

		this.gameObjects.forEach( function ( obj ) {

			let index = this.lightsOn ? (obj.phong ? 1 : 2) : 0;

			obj.phong = !obj.phong;

			obj.changeMaterial( index );

		}, this );

	}

	resize () {

		this.renderer.setSize( WINDOW_WIDTH(), WINDOW_HEIGHT() );

		let size = this.renderer.getSize();
		let ratio = size.width / size.height;

		if ( this.camera.type === 'OrthographicCamera' ) {

			if ( ratio > ( WIDTH / HEIGHT ) ) {

				this.camera.left   = ( HEIGHT * ratio ) / -2;
				this.camera.right  = ( HEIGHT * ratio ) /  2;
				this.camera.top    = HEIGHT /  2;
				this.camera.bottom = HEIGHT / -2;

			} else {

				this.camera.left   = WIDTH / -2;
				this.camera.right  = WIDTH /  2;
				this.camera.top    = ( WIDTH / ratio ) /  2;
				this.camera.bottom = ( WIDTH / ratio ) / -2;

			}

		} else {

			this.camera.aspect = ratio;

		}

		this.camera.updateProjectionMatrix();

	}

	keyDown ( event ) {

		if ( this.gameOver ) {

			/* Restart the game */
			if ( event.keyCode === Keyboard.KEY_R ) {

				this.gameOver = false;
				this.setup();

			}

		} else {

			switch ( event.keyCode ) {

				/* Toggle cameras */
				case Keyboard.KEY_1: /* Orthographic (top bird's eye camera) */
				case Keyboard.KEY_2: /* Perspective (back camera) */
				case Keyboard.KEY_3: /* Perspective (player view camera) */

					if ( this.gameClock.running ) {

						this.camera = this.cameras[ event.keyCode - Keyboard.KEY_1 ];
						this.resize();

					}

					break;

				/* Player movement: Left */
				case Keyboard.KEY_A:
				case Keyboard.KEY_LEFT:

					if ( !this.playerShip.moving ) this.playerShip.moving = true;
					this.playerShip.setDirection( -1, 0, 0 );

					break;

				/* Player movement: Right */
				case Keyboard.KEY_D:
				case Keyboard.KEY_RIGHT:

					if ( !this.playerShip.moving ) this.playerShip.moving = true;
					this.playerShip.setDirection( 1, 0, 0 );

					break;

				/* Player action: Toggle shooting */
				case Keyboard.KEY_B:
				case Keyboard.KEY_SPACEBAR:

					this.playerShip.shooting = true;

					break;

				/* Show / hide stars */
				case Keyboard.KEY_C:

					this.stars.forEach( function( star ) {

						star.visible = !star.visible;

					});

					break;

				/* Toggle lights */
				case Keyboard.KEY_L:

					this.lightsOn = !this.lightsOn;
					this.updateMaterials();

					break;

				case Keyboard.KEY_H: /* Toggle playerShip flashlight */

					this.playerShip.toggleFlashlight();

					break;

				/* Toggle Gouraud / Lambert Shading */
				case Keyboard.KEY_G:

					this.updateMaterials();
					break;

				/* Toggle the sun (day/night modes) */
				case Keyboard.KEY_N:

					this.sun.visible = !this.sun.visible;

					break;

				/* Start / Stop the game (clock) */
				case Keyboard.KEY_S:

					this.gameClock.running ? this.gameClock.stop() : this.gameClock.start();

					break;

				/* Toggle wireframe of the objects in the scene */
				case Keyboard.KEY_W:

					this.gameObjects.forEach( function( obj ) {

						obj.traverse( function ( node ) {

							if ( node.isMesh ) {

								node.material.wireframe = !node.material.wireframe;

							}

						});

					});

					break;

				/* Toggle field visibility */
				case Keyboard.KEY_9:

					this.field.visible = !this.field.visible;

					break;

				default: break;

			}
		}

	}

	keyUp ( event ) {

		switch ( event.keyCode ) {

			case Keyboard.KEY_A:
			case Keyboard.KEY_LEFT:
			case Keyboard.KEY_D:
			case Keyboard.KEY_RIGHT:

				this.playerShip.moving = false;

				break;

			case Keyboard.KEY_B:
			case Keyboard.KEY_SPACEBAR:

				this.playerShip.shooting = false;

				break;

			default: break;

		}
	}

}

new Game();
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/options",
    "firebug/lib/dom",
    "firebug/chrome/firefox",
    "firebug/lib/domplate",
    "firebug/lib/locale",
    "firebug/chrome/reps",
    "firebug/chrome/window",
    "firebug/chrome/panelActivation",
    "firebug/lib/events",
    "firebug/lib/css",
],
function(Firebug, FBTrace, Obj, Options, Dom, Firefox, Domplate, Locale, FirebugReps, Win,
    PanelActivation, Events, Css) {

"use strict";

// ********************************************************************************************* //
// Constants

var Cc = Components.classes;
var Ci = Components.interfaces;

var {domplate, SPAN, P, DIV, BUTTON, TABLE, TR, TD, TBODY} = Domplate;

var slowJSDBugUrl = "https://bugzilla.mozilla.org/show_bug.cgi?id=815603";

// ********************************************************************************************* //
// Domplate

var slowJsdTag =
    P({"class": "slowJsdMessage disabledPanelDescription",
        style: "margin: 15px 0 15px 0; color: green"}
    );

var slowJsdRep = domplate(Firebug.Rep,
{
    className: "text",

    tag:
        FirebugReps.OBJECTBOX(
            TABLE({"style": "color: green"},
                TBODY(
                    TR(
                        TD({"valign": "middle"},
                            SPAN({"class": "slowJSD"})
                        ),
                        TD({"valign": "middle", "style": "white-space: nowrap;"},
                            BUTTON({onclick: "$onClick"},
                                Locale.$STR("knownissues.message.slowJSD.GotIt")
                            )
                        )
                    )
                )
            )
        ),

    onClick: function(event)
    {
        Options.set("showSlowJSDMessage", false);

        var row = Dom.getAncestorByClass(event.target, "logRow");
        row.parentNode.removeChild(row);

        Events.cancelEvent(event);
    }
});

// ********************************************************************************************* //

/**
 * This module is responsible for various hacks and workarounds related
 * to known platform issues.
 */
var KnownIssues = Obj.extend(Firebug.Module,
/** @lends KnownIssues */
{
    dispatchName: "knownIssues",

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Initialization

    initialize: function(prefDomain, prefNames)
    {
        Firebug.Module.initialize.apply(this, arguments);

        Firebug.registerUIListener(this);
        PanelActivation.addListener(this);
    },

    shutdown: function()
    {
        Firebug.unregisterUIListener(this);
        PanelActivation.removeListener(this);

        Firebug.Module.shutdown.apply(this, arguments);
    },

    initContext: function(context)
    {
        Firebug.Module.initContext.apply(this, arguments);

        // Initialize default value.
        context.showSlowJSDMessage = Options.get("showSlowJSDMessage");

        this.showSlowJSDMessage(context);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

    showSlowJSDMessage: function(context)
    {
        // Do not display twice for this context
        if (!context.showSlowJSDMessage)
            return;

        // The message is displayed only if the Console panel is enabled.
        var consolePanel = context.getPanel("console");
        if (!consolePanel)
            return;

        // The message is displayed only if the Script panel is enabled.
        var scriptPanel = context.getPanel("script");
        if (!scriptPanel)
            return;

        var row = Firebug.Console.log({}, context, "warn", slowJsdRep, true);

        // xxxHonza: couldn't we have vertical centering (50%) for all ".logRow" elements?
        row.setAttribute("style", "background-position: 4px 50%;")

        var parentNode = row.getElementsByClassName("slowJSD")[0];
        FirebugReps.Description.render(Locale.$STR("knownissues.message.slowJSD"),
            parentNode, Obj.bindFixed(Win.openNewTab, Win, slowJSDBugUrl));

        context.showSlowJSDMessage = false;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // UI Listener

    /**
     * Issue 6821: Tell the user that JSD slows down opening Firebug and tab switching
     */
    showDisabledPanelBox: function(panelName, parentNode)
    {
        if (panelName != "script")
            return;

        var box = parentNode.getElementsByClassName("disabledPanelDescription")[0];
        var message = slowJsdTag.insertAfter({}, box);

        FirebugReps.Description.render(Locale.$STR("knownissues.message.slowJSD"),
            message, Obj.bindFixed(Win.openNewTab, Win, slowJSDBugUrl));
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // PanelActivation Listener

    activationChanged: function(panelType, enable)
    {
        this.showSlowJSDMessage(Firebug.currentContext);
    }
});

// ********************************************************************************************* //
// Registration

Firebug.registerModule(KnownIssues);

return KnownIssues;

// ********************************************************************************************* //
});
<commit_msg>Properly check if a panel is enabled (issue 6821)<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/options",
    "firebug/lib/dom",
    "firebug/chrome/firefox",
    "firebug/lib/domplate",
    "firebug/lib/locale",
    "firebug/chrome/reps",
    "firebug/chrome/window",
    "firebug/chrome/panelActivation",
    "firebug/lib/events",
    "firebug/lib/css",
],
function(Firebug, FBTrace, Obj, Options, Dom, Firefox, Domplate, Locale, FirebugReps, Win,
    PanelActivation, Events, Css) {

"use strict";

// ********************************************************************************************* //
// Constants

var Cc = Components.classes;
var Ci = Components.interfaces;

var {domplate, SPAN, P, DIV, BUTTON, TABLE, TR, TD, TBODY} = Domplate;

var slowJSDBugUrl = "https://bugzilla.mozilla.org/show_bug.cgi?id=815603";

// ********************************************************************************************* //
// Domplate

var slowJsdTag =
    P({"class": "slowJsdMessage disabledPanelDescription",
        style: "margin: 15px 0 15px 0; color: green"}
    );

var slowJsdRep = domplate(Firebug.Rep,
{
    className: "text",

    tag:
        FirebugReps.OBJECTBOX(
            TABLE({"style": "color: green"},
                TBODY(
                    TR(
                        TD({"valign": "middle"},
                            SPAN({"class": "slowJSD"})
                        ),
                        TD({"valign": "middle", "style": "white-space: nowrap;"},
                            BUTTON({onclick: "$onClick"},
                                Locale.$STR("knownissues.message.slowJSD.GotIt")
                            )
                        )
                    )
                )
            )
        ),

    onClick: function(event)
    {
        Options.set("showSlowJSDMessage", false);

        var row = Dom.getAncestorByClass(event.target, "logRow");
        row.parentNode.removeChild(row);

        Events.cancelEvent(event);
    }
});

// ********************************************************************************************* //

/**
 * This module is responsible for various hacks and workarounds related
 * to known platform issues.
 */
var KnownIssues = Obj.extend(Firebug.Module,
/** @lends KnownIssues */
{
    dispatchName: "knownIssues",

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Initialization

    initialize: function(prefDomain, prefNames)
    {
        Firebug.Module.initialize.apply(this, arguments);

        Firebug.registerUIListener(this);
        PanelActivation.addListener(this);
    },

    shutdown: function()
    {
        Firebug.unregisterUIListener(this);
        PanelActivation.removeListener(this);

        Firebug.Module.shutdown.apply(this, arguments);
    },

    initContext: function(context)
    {
        Firebug.Module.initContext.apply(this, arguments);

        // Initialize default value.
        context.showSlowJSDMessage = Options.get("showSlowJSDMessage");

        this.showSlowJSDMessage(context);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

    showSlowJSDMessage: function(context)
    {
        // Do not display twice for this context
        if (!context.showSlowJSDMessage)
            return;

        // The message is displayed only if the Console panel is enabled.
        if (!PanelActivation.isPanelEnabled(Firebug.getPanelType("console")))
            return;

        // The message is displayed only if the Script panel is enabled.
        if (!PanelActivation.isPanelEnabled(Firebug.getPanelType("script")))
            return;

        var row = Firebug.Console.log({}, context, "warn", slowJsdRep, true);

        // xxxHonza: couldn't we have vertical centering (50%) for all ".logRow" elements?
        row.setAttribute("style", "background-position: 4px 50%;")

        var parentNode = row.getElementsByClassName("slowJSD")[0];
        FirebugReps.Description.render(Locale.$STR("knownissues.message.slowJSD"),
            parentNode, Obj.bindFixed(Win.openNewTab, Win, slowJSDBugUrl));

        context.showSlowJSDMessage = false;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // UI Listener

    /**
     * Issue 6821: Tell the user that JSD slows down opening Firebug and tab switching
     */
    showDisabledPanelBox: function(panelName, parentNode)
    {
        if (panelName != "script")
            return;

        var box = parentNode.getElementsByClassName("disabledPanelDescription")[0];
        var message = slowJsdTag.insertAfter({}, box);

        FirebugReps.Description.render(Locale.$STR("knownissues.message.slowJSD"),
            message, Obj.bindFixed(Win.openNewTab, Win, slowJSDBugUrl));
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // PanelActivation Listener

    activationChanged: function(panelType, enable)
    {
        this.showSlowJSDMessage(Firebug.currentContext);
    }
});

// ********************************************************************************************* //
// Registration

Firebug.registerModule(KnownIssues);

return KnownIssues;

// ********************************************************************************************* //
});
<|endoftext|>