<commit_before>/*
 * Boardfarm Management application
 * Copyright (c) 2017 Heiko Stuebner <heiko@sntech.de>
 *
 * License:
 *   MIT: https://opensource.org/licenses/MIT
 *   See the LICENSE file in the project's top-level directory for details.
 */

var mux = require("./AbstractMux");

/*
 * Aten VS0801H is a rackmountable 8-to-1 hdmi mux
 * with a serial interface capable of also switch ports.
 * Serial connection as specified by the manual:
 * - baud rate: 19200
 * - data bits: 8
 * - parity:    none
 * - stop bits: 1
 * - flow ctrl: none
 *
 * The control interface numbers ports from 1-8, we do 0-7
 */
qx.Class.define("sn.boardfarm.backend.mux.AtenVS0801H",
{
	extend : sn.boardfarm.backend.mux.AbstractMux,

	construct : function(ident, ctrl, pwr)
	{
		console.log("Mux: added Aten VS0801H HDMI Mux at " + ctrl);
		this.base(arguments, ident, ctrl, pwr);

		var mux = sn.boardfarm.backend.mux.Mux.getInstance();

		this.__sPortExpect = [];

		/* setup serialport instance */
		var SerialPort = require("serialport");
		this.__sPort = new SerialPort(ctrl, {
				baudRate: 19200,
				parser: SerialPort.parsers.readline('\n')
		});

		this.__sPort.on('open',
			qx.lang.Function.bind(this._serialPortOpen, this));
		this.__sPort.on('close',
			qx.lang.Function.bind(this._serialPortClose, this));
		this.__sPort.on('data',
			qx.lang.Function.bind(this._serialPortData, this));
		this.__sPort.on('error',
			qx.lang.Function.bind(this._serialPortError, this));

		mux.addMux(this.getIdent(), this);
	},

	events :
	{
		"sourcePortChanged" : "qx.event.type.Data",
		"stateChanged" : "qx.event.type.Data"
	},

	properties :
	{
		sourcePort : { init : -1, apply : "_applySourcePort", event : "sourcePortChanged" },
		state : { init : -1, apply : "_applyState", event : "stateChanged" },
	},

	members :
	{
		__sPort : null,
		__sPortReady : false,
		__sPortExpect : null,

		_serialPortOpen : function()
		{
			this.__sPortReady = true;

			/* we want an initial state reading once open */
			this._serialPortWrite("read");
		},

		_serialPortClose : function()
		{
			this.__sPortReady = false;
		},

		_serialPortData : function(data)
		{
			/* remove the last \r */
			data = data.substring(0, data.length - 1);

			if (this.__sPortExpect.length == 0) {
				console.log("Mux: " + this.getIdent() + " received unexpected line " + data);
				return;
			}

			var expect = this.__sPortExpect.shift();

			/* only "read" produces additional output */
			if (expect == "") {
				this._handleReadData(data);
				return;
			}

			if (data != expect)
				console.log("Mux: on " + this.getIdent() + " line /" + data + "/ did not match expectation /" + expect + "/");
		},

		_serialPortError : function(err)
		{
			console.log(this.getIdent() + " error: ", err.message);
		},

		_serialPortWrite : function(data)
		{
			if (!this.__sPortReady)
				throw "port not ready yet";

			this.__sPortExpect.push(data + " Command OK");

			/* read commands will return 5 additional lines */
			if (data == "read") {
				for (var i = 0; i < 5; i++)
					this.__sPortExpect.push("");
			}

			this.__sPort.write(data + "\r\n");
		},

		_handleReadData : function(data)
		{
			var d = data.split(":");
			var par = d[0];
			var val = d[1].substring(1);

			switch (par) {
			case "Input":
				var port = val.substring(4) - 1;
				this.setSourcePort(port);
				break;

			case "Output":
				var state = (val == "ON") ? 1 : 0;
				this.setState(state);
				break;
			case "Mode":
			case "Goto":
			case "F/W":
				break;
			default:
				console.log("Mux: unknown read parameter " + par + " on " + this.getIdent());
			}
		},

		getDestinationPort : function()
		{
			return 0;
		},

		setDestinationPort : function(n)
		{
			if (n == 0)
				return;

			throw "AtenVS0801H only has one output port";
		},

		/*
		 * Port change involves:
		 * Send: sw i01
		 * Recv: sw i01 Command OK
		 */
		_applySourcePort : function(n, o)
		{
			/* initial port setting, nothing to do */
			if (o == -1)
				return;

			console.log("Mux: setting source port to " + n + " on " + this.getIdent());
			this._serialPortWrite("sw i0"+(parseInt(n)+1));
		},

		/* State change involves:
		 * Send: sw off
		 * Recv: sw off Command OK
		 */
		_applyState : function(n, o)
		{
			/* initial state setting, nothing to do */
			if (o == -1)
				return;

			console.log("Mux: " + (n ? "enabling" : "disabline" ) + " " + this.getIdent());
			this._serialPortWrite("sw "+(n ? "on" : "off"));
		},

		muxReadState : function()
		{
			try {
				this._serialPortWrite("read");
			} catch(e) {
			}
		}
	}
});
<commit_msg>AtenVS0801H: fix typo<commit_after>/*
 * Boardfarm Management application
 * Copyright (c) 2017 Heiko Stuebner <heiko@sntech.de>
 *
 * License:
 *   MIT: https://opensource.org/licenses/MIT
 *   See the LICENSE file in the project's top-level directory for details.
 */

var mux = require("./AbstractMux");

/*
 * Aten VS0801H is a rackmountable 8-to-1 hdmi mux
 * with a serial interface capable of also switch ports.
 * Serial connection as specified by the manual:
 * - baud rate: 19200
 * - data bits: 8
 * - parity:    none
 * - stop bits: 1
 * - flow ctrl: none
 *
 * The control interface numbers ports from 1-8, we do 0-7
 */
qx.Class.define("sn.boardfarm.backend.mux.AtenVS0801H",
{
	extend : sn.boardfarm.backend.mux.AbstractMux,

	construct : function(ident, ctrl, pwr)
	{
		console.log("Mux: added Aten VS0801H HDMI Mux at " + ctrl);
		this.base(arguments, ident, ctrl, pwr);

		var mux = sn.boardfarm.backend.mux.Mux.getInstance();

		this.__sPortExpect = [];

		/* setup serialport instance */
		var SerialPort = require("serialport");
		this.__sPort = new SerialPort(ctrl, {
				baudRate: 19200,
				parser: SerialPort.parsers.readline('\n')
		});

		this.__sPort.on('open',
			qx.lang.Function.bind(this._serialPortOpen, this));
		this.__sPort.on('close',
			qx.lang.Function.bind(this._serialPortClose, this));
		this.__sPort.on('data',
			qx.lang.Function.bind(this._serialPortData, this));
		this.__sPort.on('error',
			qx.lang.Function.bind(this._serialPortError, this));

		mux.addMux(this.getIdent(), this);
	},

	events :
	{
		"sourcePortChanged" : "qx.event.type.Data",
		"stateChanged" : "qx.event.type.Data"
	},

	properties :
	{
		sourcePort : { init : -1, apply : "_applySourcePort", event : "sourcePortChanged" },
		state : { init : -1, apply : "_applyState", event : "stateChanged" },
	},

	members :
	{
		__sPort : null,
		__sPortReady : false,
		__sPortExpect : null,

		_serialPortOpen : function()
		{
			this.__sPortReady = true;

			/* we want an initial state reading once open */
			this._serialPortWrite("read");
		},

		_serialPortClose : function()
		{
			this.__sPortReady = false;
		},

		_serialPortData : function(data)
		{
			/* remove the last \r */
			data = data.substring(0, data.length - 1);

			if (this.__sPortExpect.length == 0) {
				console.log("Mux: " + this.getIdent() + " received unexpected line " + data);
				return;
			}

			var expect = this.__sPortExpect.shift();

			/* only "read" produces additional output */
			if (expect == "") {
				this._handleReadData(data);
				return;
			}

			if (data != expect)
				console.log("Mux: on " + this.getIdent() + " line /" + data + "/ did not match expectation /" + expect + "/");
		},

		_serialPortError : function(err)
		{
			console.log(this.getIdent() + " error: ", err.message);
		},

		_serialPortWrite : function(data)
		{
			if (!this.__sPortReady)
				throw "port not ready yet";

			this.__sPortExpect.push(data + " Command OK");

			/* read commands will return 5 additional lines */
			if (data == "read") {
				for (var i = 0; i < 5; i++)
					this.__sPortExpect.push("");
			}

			this.__sPort.write(data + "\r\n");
		},

		_handleReadData : function(data)
		{
			var d = data.split(":");
			var par = d[0];
			var val = d[1].substring(1);

			switch (par) {
			case "Input":
				var port = val.substring(4) - 1;
				this.setSourcePort(port);
				break;

			case "Output":
				var state = (val == "ON") ? 1 : 0;
				this.setState(state);
				break;
			case "Mode":
			case "Goto":
			case "F/W":
				break;
			default:
				console.log("Mux: unknown read parameter " + par + " on " + this.getIdent());
			}
		},

		getDestinationPort : function()
		{
			return 0;
		},

		setDestinationPort : function(n)
		{
			if (n == 0)
				return;

			throw "AtenVS0801H only has one output port";
		},

		/*
		 * Port change involves:
		 * Send: sw i01
		 * Recv: sw i01 Command OK
		 */
		_applySourcePort : function(n, o)
		{
			/* initial port setting, nothing to do */
			if (o == -1)
				return;

			console.log("Mux: setting source port to " + n + " on " + this.getIdent());
			this._serialPortWrite("sw i0"+(parseInt(n)+1));
		},

		/* State change involves:
		 * Send: sw off
		 * Recv: sw off Command OK
		 */
		_applyState : function(n, o)
		{
			/* initial state setting, nothing to do */
			if (o == -1)
				return;

			console.log("Mux: " + (n ? "enabling" : "disabling" ) + " " + this.getIdent());
			this._serialPortWrite("sw "+(n ? "on" : "off"));
		},

		muxReadState : function()
		{
			try {
				this._serialPortWrite("read");
			} catch(e) {
			}
		}
	}
});
<|endoftext|>


<commit_before>"use strict";

const config = require('config');

// set up ======================================================================
var express = require('express');
var app = express(); 						// create our app w/ express
var mongoose = require('mongoose'); 				// mongoose for mongodb
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var path = require ("path");

var master_db_config = config.get('db');

mongoose.connect('mongodb://' + master_db_config.user + ':' + master_db_config.password + '@' + master_db_config.url);

app.use(express.static(__dirname + '/public'));                 // set the static files location /public/img will be /img for users
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

// routes ======================================================================
// routes ======================================================================
require('./app/routes.js')(app, __dirname);

// listen (start app with node server.js) ======================================
app.listen(config.get('port'));
console.log("App listening on port "+ config.get('port'));
<commit_msg>Try fix bug on server<commit_after>"use strict";

const config = require('config');

// set up ======================================================================
var express = require('express');
var app = express(); 						// create our app w/ express
var mongoose = require('mongoose'); 				// mongoose for mongodb
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

var master_db_config = config.get('db');

mongoose.connect('mongodb://' + master_db_config.user + ':' + master_db_config.password + '@' + master_db_config.url);

app.use(express.static(__dirname + '/public'));                 // set the static files location /public/img will be /img for users
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

// routes ======================================================================
// routes ======================================================================
// require('./app/routes.js')(app, __dirname);
app.get('*', function (req, res) {

    console.log("send index.html");
    console.log(dirname);
    res.sendFile(dirname + '/public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});

// listen (start app with node server.js) ======================================
app.listen(config.get('port'));
console.log("App listening on port "+ config.get('port'));
<|endoftext|>


<commit_before>var VirtualJoystick	= function(opts)
{
	opts			= opts			|| {};
	this._container		= opts.container	|| document.body;
	this._strokeStyle	= opts.strokeStyle	|| 'cyan';
	this._stickEl		= opts.stickElement	|| this._buildJoystickStick();
	this._baseEl		= opts.baseElement	|| this._buildJoystickBase();
	this._mouseSupport	= opts.mouseSupport !== undefined ? opts.mouseSupport : false;

	this._container.style.position	= "relative";

	this._container.appendChild(this._baseEl);
	this._baseEl.style.position	= "absolute"
	this._baseEl.style.display	= "none";

	this._container.appendChild(this._stickEl);
	this._stickEl.style.position	= "absolute"
	this._stickEl.style.display	= "none";

	this._pressed	= false;
	this._touchIdx	= null;
	this._baseX	= 0;
	this._baseY	= 0;
	this._stickX	= 0;
	this._stickY	= 0;

	var __bind	= function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
	this._$onTouchStart	= __bind(this._onTouchStart	, this);
	this._$onTouchEnd	= __bind(this._onTouchEnd	, this);
	this._$onTouchMove	= __bind(this._onTouchMove	, this);
	this._container.addEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.addEventListener( 'touchend'	, this._$onTouchEnd	, false );
	this._container.addEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._$onMouseDown	= __bind(this._onMouseDown	, this);
		this._$onMouseUp	= __bind(this._onMouseUp	, this);
		this._$onMouseMove	= __bind(this._onMouseMove	, this);
		this._container.addEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.addEventListener( 'mouseup'	, this._$onMouseUp	, false );
		this._container.addEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

VirtualJoystick.prototype.destroy	= function()
{
	this._container.removeChild(this._baseEl);
	this._container.removeChild(this._stickEl);

	this._container.removeEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.removeEventListener( 'touchend'		, this._$onTouchEnd	, false );
	this._container.removeEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._container.removeEventListener( 'mouseup'		, this._$onMouseUp	, false );
		this._container.removeEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.removeEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

/**
 * @returns {Boolean} true if touchscreen is currently available, false otherwise
*/
VirtualJoystick.touchScreenAvailable	= function()
{
	return 'createTouch' in document ? true : false;
}

/**
 * microevents.js - https://github.com/jeromeetienne/microevent.js
*/
;(function(destObj){
	destObj.addEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		this._events[event] = this._events[event]	|| [];
		this._events[event].push(fct);
		return fct;
	};
	destObj.removeEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		if( event in this._events === false  )	return;
		this._events[event].splice(this._events[event].indexOf(fct), 1);
	};
	destObj.dispatchEvent		= function(event /* , args... */){
		if(this._events === undefined) 	this._events	= {};
		if( this._events[event] === undefined )	return;
		var tmpArray	= this._events[event].slice();
		for(var i = 0; i < tmpArray.length; i++){
			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
			if( result !== undefined )	return result;
		}
		return undefined
	};
})(VirtualJoystick.prototype);

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

VirtualJoystick.prototype.deltaX	= function(){ return this._stickX - this._baseX;	}
VirtualJoystick.prototype.deltaY	= function(){ return this._stickY - this._baseY;	}

VirtualJoystick.prototype.up	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY >= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.down	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY <= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.right	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX <= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}
VirtualJoystick.prototype.left	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX >= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}

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

VirtualJoystick.prototype._onUp	= function()
{
	this._pressed	= false;
	this._stickEl.style.display	= "none";
	this._baseEl.style.display	= "none";

	this._baseX	= this._baseY	= 0;
	this._stickX	= this._stickY	= 0;
}

VirtualJoystick.prototype._onDown	= function(x, y)
{
	this._pressed	= true;
	this._baseX	= x;
	this._baseY	= y;
	this._stickX	= x;
	this._stickY	= y;

	this._stickEl.style.display	= "";
	this._stickEl.style.left	= (x - this._stickEl.width /2)+"px";
	this._stickEl.style.top		= (y - this._stickEl.height/2)+"px";

	this._baseEl.style.display	= "";
	this._baseEl.style.left		= (x - this._baseEl.width /2)+"px";
	this._baseEl.style.top		= (y - this._baseEl.height/2)+"px";
}

VirtualJoystick.prototype._onMove	= function(x, y)
{
	if( this._pressed === true ){
		this._stickX	= x;
		this._stickY	= y;
		this._stickEl.style.left	= (x - this._stickEl.width /2)+"px";
		this._stickEl.style.top		= (y - this._stickEl.height/2)+"px";
	}
}

//////////////////////////////////////////////////////////////////////////////////
//		bind touch events (and mouse events for debug)			//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onMouseUp	= function(event)
{
	return this._onUp();
}

VirtualJoystick.prototype._onMouseDown	= function(event)
{
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onDown(x, y);
}

VirtualJoystick.prototype._onMouseMove	= function(event)
{
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onMove(x, y);
}

//////////////////////////////////////////////////////////////////////////////////
//		comment								//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onTouchStart	= function(event)
{
	// if there is already a touch inprogress do nothing
	if( this._touchIdx !== null )	return;

	// notify event for validation
	var isValid	= this.dispatchEvent('touchStartValidation', event);
	if( isValid === false )	return;

	event.preventDefault();
	// get the first who changed
	var touch	= event.changedTouches[0];
	// set the touchIdx of this joystick
	this._touchIdx	= touch.identifier;

	// forward the action
	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onDown(x, y)
}

VirtualJoystick.prototype._onTouchEnd	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);
	// if touch event isnt found,
	if( i === touchList.length)	return;

	// reset touchIdx - mark it as no-touch-in-progress
	this._touchIdx	= null;

//??????
// no preventDefault to get click event on ios
event.preventDefault();

	return this._onUp()
}

VirtualJoystick.prototype._onTouchMove	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );
	// if touch event with the proper identifier isnt found, do nothing
	if( i === touchList.length)	return;
	var touch	= touchList[i];

	event.preventDefault();

	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onMove(x, y)
}

//////////////////////////////////////////////////////////////////////////////////
//		build default stickEl and baseEl				//
//////////////////////////////////////////////////////////////////////////////////

/**
 * build the canvas for joystick base
 */
VirtualJoystick.prototype._buildJoystickBase	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 126;
	canvas.height	= 126;

	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle = this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();

	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 2;
	ctx.arc( canvas.width/2, canvas.width/2, 60, 0, Math.PI*2, true);
	ctx.stroke();

	return canvas;
}

/**
 * build the canvas for joystick stick
 */
VirtualJoystick.prototype._buildJoystickStick	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 86;
	canvas.height	= 86;
	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();
	return canvas;
}

<commit_msg>kolor joystica<commit_after>var VirtualJoystick	= function(opts)
{
	opts			= opts			|| {};
	this._container		= opts.container	|| document.body;
	this._strokeStyle	= opts.strokeStyle	|| 'blue';
	this._stickEl		= opts.stickElement	|| this._buildJoystickStick();
	this._baseEl		= opts.baseElement	|| this._buildJoystickBase();
	this._mouseSupport	= opts.mouseSupport !== undefined ? opts.mouseSupport : false;

	this._container.style.position	= "relative";

	this._container.appendChild(this._baseEl);
	this._baseEl.style.position	= "absolute"
	this._baseEl.style.display	= "none";

	this._container.appendChild(this._stickEl);
	this._stickEl.style.position	= "absolute"
	this._stickEl.style.display	= "none";

	this._pressed	= false;
	this._touchIdx	= null;
	this._baseX	= 0;
	this._baseY	= 0;
	this._stickX	= 0;
	this._stickY	= 0;

	var __bind	= function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
	this._$onTouchStart	= __bind(this._onTouchStart	, this);
	this._$onTouchEnd	= __bind(this._onTouchEnd	, this);
	this._$onTouchMove	= __bind(this._onTouchMove	, this);
	this._container.addEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.addEventListener( 'touchend'	, this._$onTouchEnd	, false );
	this._container.addEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._$onMouseDown	= __bind(this._onMouseDown	, this);
		this._$onMouseUp	= __bind(this._onMouseUp	, this);
		this._$onMouseMove	= __bind(this._onMouseMove	, this);
		this._container.addEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.addEventListener( 'mouseup'	, this._$onMouseUp	, false );
		this._container.addEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

VirtualJoystick.prototype.destroy	= function()
{
	this._container.removeChild(this._baseEl);
	this._container.removeChild(this._stickEl);

	this._container.removeEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._container.removeEventListener( 'touchend'		, this._$onTouchEnd	, false );
	this._container.removeEventListener( 'touchmove'	, this._$onTouchMove	, false );
	if( this._mouseSupport ){
		this._container.removeEventListener( 'mouseup'		, this._$onMouseUp	, false );
		this._container.removeEventListener( 'mousedown'	, this._$onMouseDown	, false );
		this._container.removeEventListener( 'mousemove'	, this._$onMouseMove	, false );
	}
}

/**
 * @returns {Boolean} true if touchscreen is currently available, false otherwise
*/
VirtualJoystick.touchScreenAvailable	= function()
{
	return 'createTouch' in document ? true : false;
}

/**
 * microevents.js - https://github.com/jeromeetienne/microevent.js
*/
;(function(destObj){
	destObj.addEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		this._events[event] = this._events[event]	|| [];
		this._events[event].push(fct);
		return fct;
	};
	destObj.removeEventListener	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		if( event in this._events === false  )	return;
		this._events[event].splice(this._events[event].indexOf(fct), 1);
	};
	destObj.dispatchEvent		= function(event /* , args... */){
		if(this._events === undefined) 	this._events	= {};
		if( this._events[event] === undefined )	return;
		var tmpArray	= this._events[event].slice();
		for(var i = 0; i < tmpArray.length; i++){
			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
			if( result !== undefined )	return result;
		}
		return undefined
	};
})(VirtualJoystick.prototype);

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

VirtualJoystick.prototype.deltaX	= function(){ return this._stickX - this._baseX;	}
VirtualJoystick.prototype.deltaY	= function(){ return this._stickY - this._baseY;	}

VirtualJoystick.prototype.up	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY >= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.down	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaY <= 0 )				return false;
	if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
	return true;
}
VirtualJoystick.prototype.right	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX <= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}
VirtualJoystick.prototype.left	= function(){
	if( this._pressed === false )	return false;
	var deltaX	= this.deltaX();
	var deltaY	= this.deltaY();
	if( deltaX >= 0 )				return false;
	if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
	return true;
}

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

VirtualJoystick.prototype._onUp	= function()
{
	this._pressed	= false;
	this._stickEl.style.display	= "none";
	this._baseEl.style.display	= "none";

	this._baseX	= this._baseY	= 0;
	this._stickX	= this._stickY	= 0;
}

VirtualJoystick.prototype._onDown	= function(x, y)
{
	this._pressed	= true;
	this._baseX	= x;
	this._baseY	= y;
	this._stickX	= x;
	this._stickY	= y;

	this._stickEl.style.display	= "";
	this._stickEl.style.left	= (x - this._stickEl.width /2)+"px";
	this._stickEl.style.top		= (y - this._stickEl.height/2)+"px";

	this._baseEl.style.display	= "";
	this._baseEl.style.left		= (x - this._baseEl.width /2)+"px";
	this._baseEl.style.top		= (y - this._baseEl.height/2)+"px";
}

VirtualJoystick.prototype._onMove	= function(x, y)
{
	if( this._pressed === true ){
		this._stickX	= x;
		this._stickY	= y;
		this._stickEl.style.left	= (x - this._stickEl.width /2)+"px";
		this._stickEl.style.top		= (y - this._stickEl.height/2)+"px";
	}
}

//////////////////////////////////////////////////////////////////////////////////
//		bind touch events (and mouse events for debug)			//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onMouseUp	= function(event)
{
	return this._onUp();
}

VirtualJoystick.prototype._onMouseDown	= function(event)
{
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onDown(x, y);
}

VirtualJoystick.prototype._onMouseMove	= function(event)
{
	var x	= event.clientX;
	var y	= event.clientY;
	return this._onMove(x, y);
}

//////////////////////////////////////////////////////////////////////////////////
//		comment								//
//////////////////////////////////////////////////////////////////////////////////

VirtualJoystick.prototype._onTouchStart	= function(event)
{
	// if there is already a touch inprogress do nothing
	if( this._touchIdx !== null )	return;

	// notify event for validation
	var isValid	= this.dispatchEvent('touchStartValidation', event);
	if( isValid === false )	return;

	event.preventDefault();
	// get the first who changed
	var touch	= event.changedTouches[0];
	// set the touchIdx of this joystick
	this._touchIdx	= touch.identifier;

	// forward the action
	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onDown(x, y)
}

VirtualJoystick.prototype._onTouchEnd	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);
	// if touch event isnt found,
	if( i === touchList.length)	return;

	// reset touchIdx - mark it as no-touch-in-progress
	this._touchIdx	= null;

//??????
// no preventDefault to get click event on ios
event.preventDefault();

	return this._onUp()
}

VirtualJoystick.prototype._onTouchMove	= function(event)
{
	// if there is no touch in progress, do nothing
	if( this._touchIdx === null )	return;

	// try to find our touch event
	var touchList	= event.changedTouches;
	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );
	// if touch event with the proper identifier isnt found, do nothing
	if( i === touchList.length)	return;
	var touch	= touchList[i];

	event.preventDefault();

	var x		= touch.pageX;
	var y		= touch.pageY;
	return this._onMove(x, y)
}

//////////////////////////////////////////////////////////////////////////////////
//		build default stickEl and baseEl				//
//////////////////////////////////////////////////////////////////////////////////

/**
 * build the canvas for joystick base
 */
VirtualJoystick.prototype._buildJoystickBase	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 126;
	canvas.height	= 126;

	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle = this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();

	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 2;
	ctx.arc( canvas.width/2, canvas.width/2, 60, 0, Math.PI*2, true);
	ctx.stroke();

	return canvas;
}

/**
 * build the canvas for joystick stick
 */
VirtualJoystick.prototype._buildJoystickStick	= function()
{
	var canvas	= document.createElement( 'canvas' );
	canvas.width	= 86;
	canvas.height	= 86;
	var ctx		= canvas.getContext('2d');
	ctx.beginPath();
	ctx.strokeStyle	= this._strokeStyle;
	ctx.lineWidth	= 6;
	ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
	ctx.stroke();
	return canvas;
}

<|endoftext|>


<commit_before>
module.exports = function (conf) {

	var fs = require('fs');
	var Promise = require('bluebird');
	var _ = require("underscore");
	var path = require("path");
	var tarGzip = require('node-targz');
	var Joi = require('@hapi/joi');
	var clustermodel = require('clusterpost-model');
	var clusterpost = require('clusterpost-lib');

	var agentOptions = {
		rejectUnauthorized: false
	}

	clusterpost.setClusterPostServer(conf.uri);
	clusterpost.setAgentOptions(agentOptions);
	clusterpost.setUserToken(conf.token);

	var handler = {};

	handler.getDataProvider = function(){

		var couchserver = conf.dataprovider;
		var url = couchserver.hostname;
		return url;

	}

	handler.uploadDocumentDataProvider = function(doc){
		return clusterpost.updateDocument(doc);
	}

	handler.getDocument = function(id){
		Joi.assert(id, Joi.string().alphanum());

		return clusterpost.getDocument(id)
		.then(function(job){
			Joi.assert(job, clustermodel.job);
			return job;
		});
	}

	handler.deleteDocument = function(doc){
		return clusterpost.deleteJob(doc._id);
	}

	//Read all files in directory and return an array with all files
	const getAllFiles = function(dir){
		return _.compact(_.flatten(_.map(fs.readdirSync(dir), (file)=>{
			var current = path.join(dir, file);
			try{
				var stat = fs.statSync(current);
				if (stat && stat.isDirectory()) {
					return getAllFiles(current);
				}else {
				    return current;
				}
			}catch(e){
				console.error(e);
				return null;
			}

		})));
	}

	handler.addDocumentDirectoryAttachment = function(doc, cwd, output){
		var dir = output.name;
		var allfiles = getAllFiles(path.join(cwd, dir));

		return Promise.map(allfiles, function(filename){
			var name = filename.replace(path.normalize(cwd) + path.sep, '');
			return handler.addDocumentAttachment(doc, filename, {...output, name});
		}, {concurrency: 1})
		.then(function(status){
			var ok = _.reduce(status, function(memo, s){
				return memo && (s.ok || s.statusCode == 409);
			},
			true);

			return {
				name: dir,
				status: status,
				ok: ok
			}
		});
	}

	handler.addDocumentAttachment = function(doc, filename, output){
		Joi.assert(doc._id, Joi.string().alphanum());
		Joi.assert(filename, Joi.string());
		Joi.assert(output, clustermodel.output);

		if(output.local_storage){
			//This uploads the file to the local storage in the server
			var target_path;
			//We check if the target path is in the current filename, if is not, we don't add it again
			if(output.name.indexOf(output.local_storage.target_path) != -1){
				target_path = output.name
			}else{
				target_path = path.join(output.local_storage.target_path, output.name)
			}
			return clusterpost.uploadToStorage(filename, target_path)
		}else if(output.local){
			//Local output this assumes the disk is mounted in both the execution server and provider. i.e., there is no file transfer.
			//Only links are generated
			if(conf.local_fs === undefined){
				return Promise.reject("No local_fs configuration in the execution server");
			}
			try{
				var local_path = output.local.useDefault? conf.local_fs[conf.local_fs.default].path : conf.local_fs[output.local.key].path
				var target_file = path.join(local_path, output.name);

				if(!fs.existsSync(target_file)){
					var target_dir = path.dirname(target_file);
					if(!fs.existsSync(target_dir)){
						fs.mkdirSync(target_dir, {recursive: true});
					}
					fs.renameSync(filename, target_file);
					fs.symlinkSync(target_file, filename);
				}
			}catch(e){
				return Promise.reject(e);
			}
			return Promise.resolve({
				ok: true
			});
		}else{
			return clusterpost.uploadFile(doc._id, filename, output.name);
		}
	}

	handler.fileExists = function(cwd, input){
		try{
			return fs.existsSync(path.join(cwd, input.name));
		}catch(e){
			return false;
		}
	}

	handler.savePromise = function(doc, cwd, input){
		var inp = _.find(doc.inputs, function(inp){
			return inp.name === input.name;
		});

		if(!inp || (doc._attachments && !doc._attachments[input.name] && !inp.remote && !inp.local && !inp.local_storage)){
			return Promise.reject({
				"status" : false,
				"error": "Document is missing attachment" + input.name
			});
		}else{
			if(inp.local_storage){
				return clusterpost.getFromStorage(path.join(cwd, input.name), input.name);
			}else if(inp && inp.local){
				if(conf.local_fs === undefined){
					throw "No local_fs configuration";
				}
				var local_path = inp.local.useDefault? conf.local_fs[conf.local_fs.default].path : conf.local_fs[inp.local.key].path
				var full_file_path = path.join(local_path, inp.name);

				if(fs.existsSync(full_file_path)){
					fs.mkdirSync(path.join(cwd, inp.name.replace(path.basename(inp.name), '')), {recursive: true})
					if(!fs.existsSync(path.join(cwd, inp.name))){
						fs.symlinkSync(full_file_path, path.join(cwd, inp.name));
					}
					return Promise.resolve({
                        "path" : full_file_path,
                        "status" : true
                    });
				}else{
					return Promise.reject({
                        "path" : full_file_path,
                        "status" : false,
                        "error": "File not found!"
                    });
				}
			}else{
				return clusterpost.getDocumentAttachmentSave(doc._id, input.name, path.join(cwd, input.name));
			}
		}
	}

	handler.getAllDocumentInputs = function(doc, cwd){

		var inputs = doc.inputs;
		var alldownloads = [];
		var downloadstatus = [];

		if(!inputs){
			return Promise.all([]);
		}
		//Initialize download status to false
		for(var i = 0; i < inputs.length; i++){
			downloadstatus.push(false);
		}

		//Check for the jobstatus and downloadstatus part of the job
		//They are organized the same way as the array initialize in the previous step
		if(doc.jobstatus && doc.jobstatus.downloadstatus){
			var ds = doc.jobstatus.downloadstatus;
			for(var i = 0; i < ds.length; i++){
				if(ds[i].status){
					downloadstatus[i] = ds[i];
				}
			}
		}

		//If the download status is ok then don't download again.
		for(var i = 0; i < inputs.length; i++){
			var input = inputs[i];
			if(downloadstatus[i] && handler.fileExists(cwd, input)){
				alldownloads.push(downloadstatus[i]);
			}else{
				alldownloads.push(handler.savePromise(doc, cwd, input)
				.catch(function(e){
					console.error(e);
					return e;
				}));
			}
		}
		return Promise.all(alldownloads);
	}

	handler.getDirectoryCWD = function(doc){
		return path.join(conf.storagedir, doc._id);
	}

	handler.createDirectoryCWD = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		try{
			fs.mkdirSync(cwd);
		}catch(e){
			if(e.code !== 'EEXIST'){
				throw e;
			}
		}

		return cwd;
	}

	handler.createOutputDirs = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		_.each(doc.outputs, (output)=>{
			if(output.type == "directory"){
				var target_dir = path.join(cwd, output.name);
			}else{
				var target_dir = path.dirname(path.join(cwd, output.name));
			}

			if(!fs.existsSync(target_dir)){
				fs.mkdirSync(target_dir, {recursive: true});
			}
		});
	}

	handler.compressdirectory = function(doc, name){
		return new Promise(function(resolve, reject){
			var dirname;
			if(name === "cwd"){
				dirname = handler.getDirectoryCWD(doc);
			}else{
				dirname = path.join(handler.getDirectoryCWD(doc), name);
				if(dirname.substr(-1) === '/'){
					dirname = dirname.substr(0, dirname.length - 1);
				}
			}

			var tarname = dirname + ".tar.gz";

			var dirstat;
			try{
				dirstat = fs.statSync(dirname);
				if(dirstat){
					tarGzip.compress({
					    source: dirname,
					    destination: tarname
					}, function(){
						resolve(tarname);
					});
				}else{
					reject({
						"error": "Directory not found: " + dirname
					})
				}

			}catch(e){
				reject({
					"error": e
				});
			}

		});
	}

	handler.compressAndAddAttachment = function(doc, cwd, output){
		return handler.compressdirectory(doc, output.name)
		.then(function(compressedpath){
			output.name = path.basename(compressedpath);
			return handler.addDocumentAttachment(doc, compressedpath, output)
		})
		.catch(function(e){
			return e;
		});
	}

	const uploadAttachment = function(params){
		var doc = params.doc;
		var output = params.output;
		var cwd = params.cwd;

		var getlatestdoc = handler.getDocument(doc._id);

		if(output.type === 'file'){
			return getlatestdoc
			.then(function(latestdoc){
				var filepath = path.join(cwd, output.name);
				return handler.addDocumentAttachment(latestdoc, filepath, output);
			});

		}else if(output.type === 'tar.gz'){
			return getlatestdoc
			.then(function(latestdoc){
				return handler.compressAndAddAttachment(latestdoc, cwd, output);
			});
		}else if(output.type === 'directory'){
			return getlatestdoc
			.then(function(latestdoc){
				return handler.addDocumentDirectoryAttachment(latestdoc, cwd, output);
			});
		}else{
			throw "Upload handler for " + output.type + "not available";
		}
	}

	handler.setAllDocumentOutputs = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		var outputs = doc.outputs;

		var promparams = [];
		for(var i = 0; i < outputs.length; i++){
			promparams.push({
				doc: doc,
				output: outputs[i],
				cwd: cwd
			});
		}

		return Promise.map(promparams, uploadAttachment, {concurrency: 1});
	}

	const checkBeforeUpload = function(params){
		if(!params.ok){
			return uploadAttachment(params)
			.catch(function(e){
				return e;
			});
		}
		return params;
	}

	handler.checkAllDocumentOutputs = function(doc){
		var uploadstatus = doc.jobstatus.uploadstatus;
        var outputs = doc.outputs;
        var cwd = handler.getDirectoryCWD(doc);

        var promparams = [];

        for(var i = 0; i < outputs.length; i++){
            if(!uploadstatus || !uploadstatus[i] || !uploadstatus[i].ok){
                promparams.push({
					doc: doc,
					output: outputs[i],
					cwd: cwd
				});
            }else{
            	promparams.push(uploadstatus[i]);
            }
        }
        return Promise.map(promparams, checkBeforeUpload, {concurrency: 1})
	}

	handler.deleteFolderRecursive = function(dir) {
		var dirstat;
		try{
			dirstat = fs.statSync(dir);
		}catch(e){
			//does not exist
			dirstat = undefined;
		}
		if(dirstat){
			fs.readdirSync(dir).forEach(function(file) {
				var currentpath = path.join(dir, file);
				if(fs.statSync(currentpath).isDirectory()) {
					handler.deleteFolderRecursive(currentpath);
				}else{
					fs.unlinkSync(currentpath);
				}
			});
			fs.rmdirSync(dir);
			return true;
	    }
	    return false;
	}

	//One of
	//'CREATE', 'QUEUE', 'DOWNLOADING', 'RUN', 'FAIL', 'KILL', 'UPLOADING', 'EXIT', 'DONE'
	handler.getJobsStatus = function(status){
		if(conf.executionserver){
			return clusterpost.getExecutionServerJobs(conf.executionserver, status);
		}else{
			return Promise.reject("No executionserver in configuration.", JSON.stringify(conf), "Set the codename for the executionserver as 'executionserver: servername'");
		}
	}

	handler.getJobsQueue = function(){
		return handler.getJobsStatus("QUEUE")
	}

	handler.getJobsRun = function(){
		return handler.getJobsStatus("RUN");
	}

	handler.getJobsUploading = function(){
		return handler.getJobsStatus("UPLOADING");
	}

	handler.getJobsKill = function(){
		return handler.getJobsStatus("KILL");
	}

	handler.getJobsDelete = function(){
		return clusterpost.getDeleteQueue();
	}

	handler.getSoftware = function(id){
		return clusterpost.getSoftware(id)
	}

	return handler;

}
<commit_msg>ENH: Function to get GPU job queue<commit_after>
module.exports = function (conf) {

	var fs = require('fs');
	var Promise = require('bluebird');
	var _ = require("underscore");
	var path = require("path");
	var tarGzip = require('node-targz');
	var Joi = require('@hapi/joi');
	var clustermodel = require('clusterpost-model');
	var clusterpost = require('clusterpost-lib');

	var agentOptions = {
		rejectUnauthorized: false
	}

	clusterpost.setClusterPostServer(conf.uri);
	clusterpost.setAgentOptions(agentOptions);
	clusterpost.setUserToken(conf.token);

	var handler = {};

	handler.getDataProvider = function(){

		var couchserver = conf.dataprovider;
		var url = couchserver.hostname;
		return url;

	}

	handler.uploadDocumentDataProvider = function(doc){
		return clusterpost.updateDocument(doc);
	}

	handler.getDocument = function(id){
		Joi.assert(id, Joi.string().alphanum());

		return clusterpost.getDocument(id)
		.then(function(job){
			Joi.assert(job, clustermodel.job);
			return job;
		});
	}

	handler.deleteDocument = function(doc){
		return clusterpost.deleteJob(doc._id);
	}

	//Read all files in directory and return an array with all files
	const getAllFiles = function(dir){
		return _.compact(_.flatten(_.map(fs.readdirSync(dir), (file)=>{
			var current = path.join(dir, file);
			try{
				var stat = fs.statSync(current);
				if (stat && stat.isDirectory()) {
					return getAllFiles(current);
				}else {
				    return current;
				}
			}catch(e){
				console.error(e);
				return null;
			}

		})));
	}

	handler.addDocumentDirectoryAttachment = function(doc, cwd, output){
		var dir = output.name;
		var allfiles = getAllFiles(path.join(cwd, dir));

		return Promise.map(allfiles, function(filename){
			var name = filename.replace(path.normalize(cwd) + path.sep, '');
			return handler.addDocumentAttachment(doc, filename, {...output, name});
		}, {concurrency: 1})
		.then(function(status){
			var ok = _.reduce(status, function(memo, s){
				return memo && (s.ok || s.statusCode == 409);
			},
			true);

			return {
				name: dir,
				status: status,
				ok: ok
			}
		});
	}

	handler.addDocumentAttachment = function(doc, filename, output){
		Joi.assert(doc._id, Joi.string().alphanum());
		Joi.assert(filename, Joi.string());
		Joi.assert(output, clustermodel.output);

		if(output.local_storage){
			//This uploads the file to the local storage in the server
			var target_path;
			//We check if the target path is in the current filename, if is not, we don't add it again
			if(output.name.indexOf(output.local_storage.target_path) != -1){
				target_path = output.name
			}else{
				target_path = path.join(output.local_storage.target_path, output.name)
			}
			return clusterpost.uploadToStorage(filename, target_path)
		}else if(output.local){
			//Local output this assumes the disk is mounted in both the execution server and provider. i.e., there is no file transfer.
			//Only links are generated
			if(conf.local_fs === undefined){
				return Promise.reject("No local_fs configuration in the execution server");
			}
			try{
				var local_path = output.local.useDefault? conf.local_fs[conf.local_fs.default].path : conf.local_fs[output.local.key].path
				var target_file = path.join(local_path, output.name);

				if(!fs.existsSync(target_file)){
					var target_dir = path.dirname(target_file);
					if(!fs.existsSync(target_dir)){
						fs.mkdirSync(target_dir, {recursive: true});
					}
					fs.renameSync(filename, target_file);
					fs.symlinkSync(target_file, filename);
				}
			}catch(e){
				return Promise.reject(e);
			}
			return Promise.resolve({
				ok: true
			});
		}else{
			return clusterpost.uploadFile(doc._id, filename, output.name);
		}
	}

	handler.fileExists = function(cwd, input){
		try{
			return fs.existsSync(path.join(cwd, input.name));
		}catch(e){
			return false;
		}
	}

	handler.savePromise = function(doc, cwd, input){
		var inp = _.find(doc.inputs, function(inp){
			return inp.name === input.name;
		});

		if(!inp || (doc._attachments && !doc._attachments[input.name] && !inp.remote && !inp.local && !inp.local_storage)){
			return Promise.reject({
				"status" : false,
				"error": "Document is missing attachment" + input.name
			});
		}else{
			if(inp.local_storage){
				return clusterpost.getFromStorage(path.join(cwd, input.name), input.name);
			}else if(inp && inp.local){
				if(conf.local_fs === undefined){
					throw "No local_fs configuration";
				}
				var local_path = inp.local.useDefault? conf.local_fs[conf.local_fs.default].path : conf.local_fs[inp.local.key].path
				var full_file_path = path.join(local_path, inp.name);

				if(fs.existsSync(full_file_path)){
					fs.mkdirSync(path.join(cwd, inp.name.replace(path.basename(inp.name), '')), {recursive: true})
					if(!fs.existsSync(path.join(cwd, inp.name))){
						fs.symlinkSync(full_file_path, path.join(cwd, inp.name));
					}
					return Promise.resolve({
                        "path" : full_file_path,
                        "status" : true
                    });
				}else{
					return Promise.reject({
                        "path" : full_file_path,
                        "status" : false,
                        "error": "File not found!"
                    });
				}
			}else{
				return clusterpost.getDocumentAttachmentSave(doc._id, input.name, path.join(cwd, input.name));
			}
		}
	}

	handler.getAllDocumentInputs = function(doc, cwd){

		var inputs = doc.inputs;
		var alldownloads = [];
		var downloadstatus = [];

		if(!inputs){
			return Promise.all([]);
		}
		//Initialize download status to false
		for(var i = 0; i < inputs.length; i++){
			downloadstatus.push(false);
		}

		//Check for the jobstatus and downloadstatus part of the job
		//They are organized the same way as the array initialize in the previous step
		if(doc.jobstatus && doc.jobstatus.downloadstatus){
			var ds = doc.jobstatus.downloadstatus;
			for(var i = 0; i < ds.length; i++){
				if(ds[i].status){
					downloadstatus[i] = ds[i];
				}
			}
		}

		//If the download status is ok then don't download again.
		for(var i = 0; i < inputs.length; i++){
			var input = inputs[i];
			if(downloadstatus[i] && handler.fileExists(cwd, input)){
				alldownloads.push(downloadstatus[i]);
			}else{
				alldownloads.push(handler.savePromise(doc, cwd, input)
				.catch(function(e){
					console.error(e);
					return e;
				}));
			}
		}
		return Promise.all(alldownloads);
	}

	handler.getDirectoryCWD = function(doc){
		return path.join(conf.storagedir, doc._id);
	}

	handler.createDirectoryCWD = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		try{
			fs.mkdirSync(cwd);
		}catch(e){
			if(e.code !== 'EEXIST'){
				throw e;
			}
		}

		return cwd;
	}

	handler.createOutputDirs = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		_.each(doc.outputs, (output)=>{
			if(output.type == "directory"){
				var target_dir = path.join(cwd, output.name);
			}else{
				var target_dir = path.dirname(path.join(cwd, output.name));
			}

			if(!fs.existsSync(target_dir)){
				fs.mkdirSync(target_dir, {recursive: true});
			}
		});
	}

	handler.compressdirectory = function(doc, name){
		return new Promise(function(resolve, reject){
			var dirname;
			if(name === "cwd"){
				dirname = handler.getDirectoryCWD(doc);
			}else{
				dirname = path.join(handler.getDirectoryCWD(doc), name);
				if(dirname.substr(-1) === '/'){
					dirname = dirname.substr(0, dirname.length - 1);
				}
			}

			var tarname = dirname + ".tar.gz";

			var dirstat;
			try{
				dirstat = fs.statSync(dirname);
				if(dirstat){
					tarGzip.compress({
					    source: dirname,
					    destination: tarname
					}, function(){
						resolve(tarname);
					});
				}else{
					reject({
						"error": "Directory not found: " + dirname
					})
				}

			}catch(e){
				reject({
					"error": e
				});
			}

		});
	}

	handler.compressAndAddAttachment = function(doc, cwd, output){
		return handler.compressdirectory(doc, output.name)
		.then(function(compressedpath){
			output.name = path.basename(compressedpath);
			return handler.addDocumentAttachment(doc, compressedpath, output)
		})
		.catch(function(e){
			return e;
		});
	}

	const uploadAttachment = function(params){
		var doc = params.doc;
		var output = params.output;
		var cwd = params.cwd;

		var getlatestdoc = handler.getDocument(doc._id);

		if(output.type === 'file'){
			return getlatestdoc
			.then(function(latestdoc){
				var filepath = path.join(cwd, output.name);
				return handler.addDocumentAttachment(latestdoc, filepath, output);
			});

		}else if(output.type === 'tar.gz'){
			return getlatestdoc
			.then(function(latestdoc){
				return handler.compressAndAddAttachment(latestdoc, cwd, output);
			});
		}else if(output.type === 'directory'){
			return getlatestdoc
			.then(function(latestdoc){
				return handler.addDocumentDirectoryAttachment(latestdoc, cwd, output);
			});
		}else{
			throw "Upload handler for " + output.type + "not available";
		}
	}

	handler.setAllDocumentOutputs = function(doc){
		var cwd = handler.getDirectoryCWD(doc);
		var outputs = doc.outputs;

		var promparams = [];
		for(var i = 0; i < outputs.length; i++){
			promparams.push({
				doc: doc,
				output: outputs[i],
				cwd: cwd
			});
		}

		return Promise.map(promparams, uploadAttachment, {concurrency: 1});
	}

	const checkBeforeUpload = function(params){
		if(!params.ok){
			return uploadAttachment(params)
			.catch(function(e){
				return e;
			});
		}
		return params;
	}

	handler.checkAllDocumentOutputs = function(doc){
		var uploadstatus = doc.jobstatus.uploadstatus;
        var outputs = doc.outputs;
        var cwd = handler.getDirectoryCWD(doc);

        var promparams = [];

        for(var i = 0; i < outputs.length; i++){
            if(!uploadstatus || !uploadstatus[i] || !uploadstatus[i].ok){
                promparams.push({
					doc: doc,
					output: outputs[i],
					cwd: cwd
				});
            }else{
            	promparams.push(uploadstatus[i]);
            }
        }
        return Promise.map(promparams, checkBeforeUpload, {concurrency: 1})
	}

	handler.deleteFolderRecursive = function(dir) {
		var dirstat;
		try{
			dirstat = fs.statSync(dir);
		}catch(e){
			//does not exist
			dirstat = undefined;
		}
		if(dirstat){
			fs.readdirSync(dir).forEach(function(file) {
				var currentpath = path.join(dir, file);
				if(fs.statSync(currentpath).isDirectory()) {
					handler.deleteFolderRecursive(currentpath);
				}else{
					fs.unlinkSync(currentpath);
				}
			});
			fs.rmdirSync(dir);
			return true;
	    }
	    return false;
	}

	//One of
	//'CREATE', 'QUEUE', 'DOWNLOADING', 'RUN', 'FAIL', 'KILL', 'UPLOADING', 'EXIT', 'DONE'
	handler.getJobsStatus = function(status){
		if(conf.executionserver){
			return clusterpost.getExecutionServerJobs(conf.executionserver, status);
		}else{
			return Promise.reject("No executionserver in configuration.", JSON.stringify(conf), "Set the codename for the executionserver as 'executionserver: servername'");
		}
	}

	handler.getJobsQueue = function(){
		return handler.getJobsStatus("QUEUE")
	}

	handler.getJobsRun = function(){
		return handler.getJobsStatus("RUN");
	}

	handler.getJobsUploading = function(){
		return handler.getJobsStatus("UPLOADING");
	}

	handler.getJobsKill = function(){
		return handler.getJobsStatus("KILL");
	}

	handler.getJobsDelete = function(){
		return clusterpost.getDeleteQueue();
	}

	handler.getSoftware = function(id){
		return clusterpost.getSoftware(id)
	}

	handler.splitJobsGPU = function( all_jobs, softwares) {
// Return cpu and gpu jobs

	    var jobs =  _.filter(all_jobs, (job)=>{
	        var software = _.find(softwares, (s)=>{
	            if(job.data && job.data.software_id && job.data.software_id == s._id){
	                return true;
	            }
	            return false;
	        })
	        return !software.gpu;
	    })

	    var jobs_gpu = _.filter(all_jobs, (job)=>{
	        var software = _.find(softwares, (s)=>{
	            if(job.data && job.data.software_id && job.data.software_id == s._id){
	                return true;
	            }
	            return false;
	        })
	        return software.gpu;
	    })

	    return {
	        jobs,
	        jobs_gpu
	    }

	}

	return handler;

}
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import _ from 'underscore';
import { Checkbox } from 'react-bootstrap';
import * as globals from './../globals';
import { console, object, expFxn, ajax, Schemas, layout, fileUtil, isServerSide } from './../util';
import { FormattedInfoBlock, TabbedView, ExperimentSetTables, ExperimentSetTablesLoaded, WorkflowNodeElement } from './components';
import { OverViewBodyItem, OverviewHeadingContainer } from './DefaultItemView';
import { ExperimentSetDetailPane, ResultRowColumnBlockValue, ItemPageTable } from './../browse/components';
import { browseTableConstantColumnDefinitions } from './../browse/BrowseView';
import Graph, { parseAnalysisSteps, parseBasicIOAnalysisSteps } from './../viz/Workflow';
import { requestAnimationFrame } from './../viz/utilities';
import { commonGraphPropsFromProps, doValidAnalysisStepsExist, RowSpacingTypeDropdown } from './WorkflowView';
import { mapEmbeddedFilesToStepRunDataIDs, allFilesForWorkflowRunMappedByUUID } from './WorkflowRunView';
import { filterOutParametersFromGraphData, filterOutReferenceFilesFromGraphData, WorkflowRunTracingView, FileViewGraphSection } from './WorkflowRunTracingView';
import { FileDownloadButton } from '../util/file';

let HiGlassComponent = null;

export default class FileView extends WorkflowRunTracingView {

    /* TODO : Move to WorkflowRunTracingView, DRY up re: WorkflowRunTracingView.loadGraphSteps() */
    static doesGraphExist(context){
        return (
            (Array.isArray(context.workflow_run_outputs) && context.workflow_run_outputs.length > 0)
        );
    }

    getTabViewContents(){

        var initTabs = [];
        var context = this.props.context;

        var width = (!isServerSide() && this.refs && this.refs.tabViewContainer && this.refs.tabViewContainer.offsetWidth) || null;
        if (width) width -= 20;

        initTabs.push(FileViewOverview.getTabObject(context, this.props.schemas, width));

        var steps = this.state.steps;

        if (FileView.doesGraphExist(context)){
            initTabs.push(FileViewGraphSection.getTabObject(this.props, this.state, this.handleToggleAllRuns));
        }

        if (context.file_format === 'mcool'){
            initTabs.push(HiGlassTabView.getTabObject(context, this.props.schemas, width));
        }

        return initTabs.concat(this.getCommonTabs());
    }

    itemMidSection(){
        return <layout.WindowResizeUpdateTrigger><FileOverviewHeading context={this.props.context} /></layout.WindowResizeUpdateTrigger>;
    }

}

globals.content_views.register(FileView, 'File');

class HiGlassTabView extends React.Component {

    static getTabObject(context, schemas, width){
        return {
            'tab' :  Visualize File,
            'key' : 'higlass',
            //'disabled' : !Array.isArray(context.experiments),
            'content' : (

                        HiGlass Browser

                    <HiGlassTabView context={context} schemas={schemas} width={width} />

            )
        };

    }

    constructor(props){
        super(props);
        this.state = { 'mounted' : false };
        this.options = { "bounded" : true }; // ToDo: Own state component wrapper if linked to UI
        this.viewConfig = {
            "editable": true,
            "zoomFixed": false,
            "trackSourceServers": [
                "http://54.86.58.34/api/v1"
            ],
            "exportViewUrl": "/api/v1/viewconfs",
            "views": [
                {
                    "uid": "aa",
                    "initialXDomain": [
                        234746886.15079364,
                        238230126.6906902
                    ],
                    "tracks": {
                        "top": [],
                        "left": [],
                        "center": [
                            {
                                "uid": "c1",
                                "type": "combined",
                                "height": 551,
                                "contents": [
                                    {
                                        "server": "http://54.86.58.34/api/v1",
                                        "tilesetUid": "W2hNwnu2TwiDqqCUxxzA1g",
                                        "type": "heatmap",
                                        "position": "center",
                                        "uid": "GjuZed1ySGW1IzZZqFB9BA"
                                    }
                                ],
                                "position": "center"
                            }
                        ],
                        "right": [],
                        "bottom": []
                    },
                    "layout": {
                        "w": 12,
                        "h": 13,
                        "x": 0,
                        "y": 0,
                        "i": "aa",
                        "moved": false,
                        "static": false
                    },
                    "initialYDomain": [
                        235207586.8246398,
                        238862012.2628646
                    ]
                }
            ],
        };
    }

    componentDidMount(){
        setTimeout(()=>{ // Allow tab CSS transition to finish (the render afterwards lags browser a little bit).
            HiGlassComponent = require('higlass').HiGlassComponent;
            this.setState({ 'mounted' : true });
        }, 250);
    }

    render(){
        if (!this.state.mounted) return null;
        let hiGlassInstance = null;
        if (this.state.mounted){
            hiGlassInstance = (

                    <HiGlassComponent
                        //ref={(r)=>{ this.element = r; }}
                        options={this.options}
                        viewConfig={this.viewConfig}
                    />

            );
        }
        return (

                <link type="text/css" rel="stylesheet" href="https://unpkg.com/higlass@0.10.19/dist/styles/hglib.css" />
                { hiGlassInstance }

        );
    }
}

class FileViewOverview extends React.Component {

    static getTabObject(context, schemas, width){
        return {
            'tab' :  Overview,
            'key' : 'experiments-info',
            //'disabled' : !Array.isArray(context.experiments),
            'content' : (

                        More Information

                    <FileViewOverview context={context} schemas={schemas} width={width} />

            )
        };
    }

    static propTypes = {
        'context' : PropTypes.shape({
            'experiments' : PropTypes.arrayOf(PropTypes.shape({
                'experiment_sets' : PropTypes.arrayOf(PropTypes.shape({
                    'link_id' : PropTypes.string.isRequired
                }))
            })),
            'experiment_sets' : PropTypes.arrayOf(PropTypes.shape({
                'experiments_in_set' : PropTypes.arrayOf(PropTypes.shape({
                    'link_id' : PropTypes.string.isRequired
                }))
            }))
        }).isRequired
    }

    render(){
        var { context } = this.props;

        var setsByKey;
        var table = null;

        if (context && (
            (Array.isArray(context.experiments) && context.experiments.length > 0) || (Array.isArray(context.experiment_sets) && context.experiment_sets.length > 0)
        )){
            setsByKey = expFxn.experimentSetsFromFile(context);
        }

        if (setsByKey && _.keys(setsByKey).length > 0){
            table = <ExperimentSetTablesLoaded experimentSetObject={setsByKey} width={this.props.width} defaultOpenIndices={[0]} />;
        }

        return (

                <FileOverViewBody result={context} schemas={this.props.schemas} />
                { table }

        );

    }

}

export class FileOverviewHeading extends React.Component {

    constructor(props){
        super(props);
        this.onTransition = this.onTransition.bind(this);
        this.overviewBlocks = this.overviewBlocks.bind(this);
        this.state = {
            isPropertiesOpen : true,
            mounted : false
        };
    }

    componentDidMount(){
        this.setState({ mounted : true });
    }

    onTransition(isOpen = false){
        this.setState({ isPropertiesOpen : isOpen });
    }

    overviewBlocks(){
        var file = this.props.context;
        var tips = object.tipsFromSchema(this.props.schemas || Schemas.get(), file); // In form of { 'description' : {'title', 'description', 'type'}, 'experiment_type' : {'title', 'description', ...}, ... }
        return [
            <OverViewBodyItem tips={tips} result={file} property='file_format' fallbackTitle="File Format" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_type' fallbackTitle="File Type" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_classification' fallbackTitle="General Classification" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_size' fallbackTitle="File Size" wrapInColumn="col-sm-3 col-lg-3" titleRenderFxn={(field, size)=>
                 { Schemas.Term.toName('file_size', size) }
            } />
        ];
    }

    render(){
        var responsiveSize = layout.responsiveGridState();
        var isSmallerSize = this.state.mounted && (responsiveSize === 'xs' || responsiveSize === 'sm');
        return (

                    <OverviewHeadingContainer onStartClose={this.onTransition.bind(this, false)} onFinishOpen={this.onTransition.bind(this, true)} children={this.overviewBlocks()}/>

                    <FileViewDownloadButtonContainer file={this.props.context} size="lg" verticallyCentered={!isSmallerSize && this.state.isPropertiesOpen} />

        );
    }
}

export class FileViewDownloadButtonContainer extends React.Component {

    static defaultProps = {
        'size' : null
    }

    render(){
        var file = this.props.file || this.props.context || this.props.result;
        return (
            <layout.VerticallyCenteredChild disabled={!this.props.verticallyCentered}>

                    <fileUtil.FileDownloadButtonAuto result={file} size={this.props.size} />

            </layout.VerticallyCenteredChild>
        );
    }
}

export class FileOverViewBody extends React.Component {

    render(){
        var file = this.props.result;
        var tips = object.tipsFromSchema(this.props.schemas || Schemas.get(), file);

        return (

                        <RelatedFilesOverViewBlock tips={tips} file={file} property="related_files" wrapInColumn />

        );

    }
}

/**
 * Reuse when showing related_files of an Item.
 */
export class RelatedFilesOverViewBlock extends React.Component {

    static defaultProps = {
        'wrapInColumn' : true,
        'property' : 'related_files'
    }

    relatedFiles(){
        var { file, related_files, property } = this.props;
        var relatedFiles;
        if (Array.isArray(related_files) && related_files.length > 0){
            relatedFiles = related_files;
        } else {
            relatedFiles = file[property] || file.related_files;
        }

        if (!Array.isArray(relatedFiles) || relatedFiles.length === 0){
            return null;
        }

        console.log('RFFFF', relatedFiles);

        return _.map(relatedFiles, function(rf, i){
            return (
{ rf.relationship_type }  -  { object.linkFromItem(rf.file) }
);
        });

    }

    render(){
        var { file, related_files, property, hideIfNoValue, tips, wrapInColumn } = this.props;

        var relatedFiles = this.relatedFiles();

        if (hideIfNoValue && !relatedFiles){
            return null;
        } else if (!relatedFiles) {
            relatedFiles =
None
;
        }

        var elem = (

                <object.TooltipInfoIconContainerAuto result={file} property={property || "related_files"} tips={tips} elementType="h5" fallbackTitle="Related Files" />

{ relatedFiles }

        );

        if (wrapInColumn){
            return
;
        } else {
            return elem;
        }

    }
}

<commit_msg>Minor layouting etc edits<commit_after>'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import _ from 'underscore';
import { Checkbox } from 'react-bootstrap';
import * as globals from './../globals';
import { console, object, expFxn, ajax, Schemas, layout, fileUtil, isServerSide } from './../util';
import { FormattedInfoBlock, TabbedView, ExperimentSetTables, ExperimentSetTablesLoaded, WorkflowNodeElement } from './components';
import { OverViewBodyItem, OverviewHeadingContainer } from './DefaultItemView';
import { ExperimentSetDetailPane, ResultRowColumnBlockValue, ItemPageTable } from './../browse/components';
import { browseTableConstantColumnDefinitions } from './../browse/BrowseView';
import Graph, { parseAnalysisSteps, parseBasicIOAnalysisSteps } from './../viz/Workflow';
import { requestAnimationFrame } from './../viz/utilities';
import { commonGraphPropsFromProps, doValidAnalysisStepsExist, RowSpacingTypeDropdown } from './WorkflowView';
import { mapEmbeddedFilesToStepRunDataIDs, allFilesForWorkflowRunMappedByUUID } from './WorkflowRunView';
import { filterOutParametersFromGraphData, filterOutReferenceFilesFromGraphData, WorkflowRunTracingView, FileViewGraphSection } from './WorkflowRunTracingView';
import { FileDownloadButton } from '../util/file';

let HiGlassComponent = null;

export default class FileView extends WorkflowRunTracingView {

    /* TODO : Move to WorkflowRunTracingView, DRY up re: WorkflowRunTracingView.loadGraphSteps() */
    static doesGraphExist(context){
        return (
            (Array.isArray(context.workflow_run_outputs) && context.workflow_run_outputs.length > 0)
        );
    }

    getTabViewContents(){

        var initTabs = [];
        var context = this.props.context;

        var width = (!isServerSide() && this.refs && this.refs.tabViewContainer && this.refs.tabViewContainer.offsetWidth) || null;
        if (width) width -= 20;

        initTabs.push(FileViewOverview.getTabObject(context, this.props.schemas, width));

        var steps = this.state.steps;

        if (FileView.doesGraphExist(context)){
            initTabs.push(FileViewGraphSection.getTabObject(this.props, this.state, this.handleToggleAllRuns));
        }

        if (context.file_format === 'mcool'){
            // TODO: pass true to 4th param (disabled, bool) if not met some condition like not in HiGlass server yet.
            // Perhaps could check e.g. http://54.86.58.34/api/v1/tileset_info/?d=W2hNwnu2TwiDqqCUxxzA1g&s=EHMd6XGAQyCRHRTCuU4KDA if:
            //   has `{ W2hNwnu2TwiDqqCUxxzA1g: { min_pos: number, max_pos: number } }`
            initTabs.push(HiGlassTabView.getTabObject(context, this.props.schemas, width));
        }

        return initTabs.concat(this.getCommonTabs());
    }

    itemMidSection(){
        return <layout.WindowResizeUpdateTrigger><FileOverviewHeading context={this.props.context} /></layout.WindowResizeUpdateTrigger>;
    }

}

globals.content_views.register(FileView, 'File');

class HiGlassTabView extends React.Component {

    static getTabObject(context, schemas, width, disabled = false){
        return {
            'tab' :  HiGlass Browser,
            'key' : 'higlass',
            'disabled' : disabled,
            'content' : (

                        HiGlass Browser

                    <HiGlassTabView context={context} schemas={schemas} width={width} />

            )
        };

    }

    constructor(props){
        super(props);
        this.state = { 'mounted' : false };
        this.options = { "bounded" : true };
        this.viewConfig = {
            "editable": true,
            "zoomFixed": false,
            "trackSourceServers": [
                "http://54.86.58.34/api/v1"
            ],
            "exportViewUrl": "/api/v1/viewconfs",
            "views": [
                {
                    "uid": "aa",
                    "initialXDomain": [
                        234746886.15079364,
                        238230126.6906902
                    ],
                    "tracks": {
                        "top": [],
                        "left": [],
                        "center": [
                            {
                                "uid": "c1",
                                "type": "combined",
                                "height": 551,
                                "contents": [
                                    {
                                        "server": "http://54.86.58.34/api/v1",
                                        "tilesetUid": "W2hNwnu2TwiDqqCUxxzA1g",
                                        "type": "heatmap",
                                        "position": "center",
                                        "uid": "GjuZed1ySGW1IzZZqFB9BA"
                                    }
                                ],
                                "position": "center"
                            }
                        ],
                        "right": [],
                        "bottom": []
                    },
                    "layout": {
                        "w": 12,
                        "h": 13,
                        "x": 0,
                        "y": 0,
                        "i": "aa",
                        "moved": false,
                        "static": false
                    },
                    "initialYDomain": [
                        235207586.8246398,
                        238862012.2628646
                    ]
                }
            ],
        };
        this.hiGlassElement = null;
    }

    componentDidMount(){
        setTimeout(()=>{ // Allow tab CSS transition to finish (the render afterwards lags browser a little bit).
            HiGlassComponent = require('higlass').HiGlassComponent;
            this.setState({ 'mounted' : true });
        }, 250);
    }

    render(){
        let hiGlassInstance = null;
        if (this.state.mounted){
            hiGlassInstance = (
                <HiGlassComponent
                    ref={(r)=>{ this.hiGlassElement = window.hiGlassElement = r; }}
                    options={this.options}
                    viewConfig={this.viewConfig}
                />
            );
        }
        /**
         * TODO: Some state + UI functions to make higlass view full screen.
         * Should try to make as common as possible between one for workflow tab & this. Won't be 100% compatible since adjust workflow detail tab inner elem styles, but maybe some common func for at least width, height, etc.
         */
        return (

                <link type="text/css" rel="stylesheet" href="https://unpkg.com/higlass@0.10.19/dist/styles/hglib.css" />

                    { hiGlassInstance || (

                            Initializing

                    ) }

        );
    }
}

class FileViewOverview extends React.Component {

    static getTabObject(context, schemas, width){
        return {
            'tab' :  Overview,
            'key' : 'experiments-info',
            //'disabled' : !Array.isArray(context.experiments),
            'content' : (

                        More Information

                    <FileViewOverview context={context} schemas={schemas} width={width} />

            )
        };
    }

    static propTypes = {
        'context' : PropTypes.shape({
            'experiments' : PropTypes.arrayOf(PropTypes.shape({
                'experiment_sets' : PropTypes.arrayOf(PropTypes.shape({
                    'link_id' : PropTypes.string.isRequired
                }))
            })),
            'experiment_sets' : PropTypes.arrayOf(PropTypes.shape({
                'experiments_in_set' : PropTypes.arrayOf(PropTypes.shape({
                    'link_id' : PropTypes.string.isRequired
                }))
            }))
        }).isRequired
    }

    render(){
        var { context } = this.props;

        var setsByKey;
        var table = null;

        if (context && (
            (Array.isArray(context.experiments) && context.experiments.length > 0) || (Array.isArray(context.experiment_sets) && context.experiment_sets.length > 0)
        )){
            setsByKey = expFxn.experimentSetsFromFile(context);
        }

        if (setsByKey && _.keys(setsByKey).length > 0){
            table = <ExperimentSetTablesLoaded experimentSetObject={setsByKey} width={this.props.width} defaultOpenIndices={[0]} />;
        }

        return (

                <FileOverViewBody result={context} schemas={this.props.schemas} />
                { table }

        );

    }

}

export class FileOverviewHeading extends React.Component {

    constructor(props){
        super(props);
        this.onTransition = this.onTransition.bind(this);
        this.overviewBlocks = this.overviewBlocks.bind(this);
        this.state = {
            isPropertiesOpen : true,
            mounted : false
        };
    }

    componentDidMount(){
        this.setState({ mounted : true });
    }

    onTransition(isOpen = false){
        this.setState({ isPropertiesOpen : isOpen });
    }

    overviewBlocks(){
        var file = this.props.context;
        var tips = object.tipsFromSchema(this.props.schemas || Schemas.get(), file); // In form of { 'description' : {'title', 'description', 'type'}, 'experiment_type' : {'title', 'description', ...}, ... }
        return [
            <OverViewBodyItem tips={tips} result={file} property='file_format' fallbackTitle="File Format" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_type' fallbackTitle="File Type" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_classification' fallbackTitle="General Classification" wrapInColumn="col-sm-3 col-lg-3" />,
            <OverViewBodyItem tips={tips} result={file} property='file_size' fallbackTitle="File Size" wrapInColumn="col-sm-3 col-lg-3" titleRenderFxn={(field, size)=>
                 { Schemas.Term.toName('file_size', size) }
            } />
        ];
    }

    render(){
        var responsiveSize = layout.responsiveGridState();
        var isSmallerSize = this.state.mounted && (responsiveSize === 'xs' || responsiveSize === 'sm');
        return (

                    <OverviewHeadingContainer onStartClose={this.onTransition.bind(this, false)} onFinishOpen={this.onTransition.bind(this, true)} children={this.overviewBlocks()}/>

                    <FileViewDownloadButtonContainer file={this.props.context} size="lg" verticallyCentered={!isSmallerSize && this.state.isPropertiesOpen} />

        );
    }
}

export class FileViewDownloadButtonContainer extends React.Component {

    static defaultProps = {
        'size' : null
    }

    render(){
        var file = this.props.file || this.props.context || this.props.result;
        return (
            <layout.VerticallyCenteredChild disabled={!this.props.verticallyCentered}>

                    <fileUtil.FileDownloadButtonAuto result={file} size={this.props.size} />

            </layout.VerticallyCenteredChild>
        );
    }
}

export class FileOverViewBody extends React.Component {

    render(){
        var file = this.props.result;
        var tips = object.tipsFromSchema(this.props.schemas || Schemas.get(), file);

        return (

                        <RelatedFilesOverViewBlock tips={tips} file={file} property="related_files" wrapInColumn />

        );

    }
}

/**
 * Reuse when showing related_files of an Item.
 */
export class RelatedFilesOverViewBlock extends React.Component {

    static defaultProps = {
        'wrapInColumn' : true,
        'property' : 'related_files'
    }

    relatedFiles(){
        var { file, related_files, property } = this.props;
        var relatedFiles;
        if (Array.isArray(related_files) && related_files.length > 0){
            relatedFiles = related_files;
        } else {
            relatedFiles = file[property] || file.related_files;
        }

        if (!Array.isArray(relatedFiles) || relatedFiles.length === 0){
            return null;
        }

        console.log('RFFFF', relatedFiles);

        return _.map(relatedFiles, function(rf, i){
            return (
{ rf.relationship_type }  -  { object.linkFromItem(rf.file) }
);
        });

    }

    render(){
        var { file, related_files, property, hideIfNoValue, tips, wrapInColumn } = this.props;

        var relatedFiles = this.relatedFiles();

        if (hideIfNoValue && !relatedFiles){
            return null;
        } else if (!relatedFiles) {
            relatedFiles =
None
;
        }

        var elem = (

                <object.TooltipInfoIconContainerAuto result={file} property={property || "related_files"} tips={tips} elementType="h5" fallbackTitle="Related Files" />

{ relatedFiles }

        );

        if (wrapInColumn){
            return
;
        } else {
            return elem;
        }

    }
}

<|endoftext|>


<commit_before>export default class FormController {
    constructor($scope, $state, WriteQueries, Configuration, progression, notification, view, dataStore) {
        this.$scope = $scope;
        this.$state = $state;
        this.WriteQueries = WriteQueries;
        this.dataStore = dataStore;
        this.progression = progression;
        this.notification = notification;
        this.title = view.title();
        this.description = view.description();
        this.actions = view.actions();
        this.fields = view.fields();
        this.config = Configuration();
        this.view = view;
        this.entity = this.view.getEntity();
        this.$scope.entry = dataStore.getFirstEntry(this.entity.uniqueId);
        this.$scope.view = view;
        this.$scope.entity = this.entity;

        // in case of entity identifier being modified
        this.originEntityId = this.$scope.entry.values[this.entity.identifier().name()];

        $scope.$on('$destroy', this.destroy.bind(this));
    }

    validateEntry() {
        if (!this.form.$valid) {
            this.notification.log('invalid form', { addnCls: 'humane-flatty-error' });
            return false;
        }

        try {
            this.view.validate(this.$scope.entry);
        } catch (e) {
            this.notification.log(e, { addnCls: 'humane-flatty-error' });
            return false;
        }

        return true;
    }

    submitCreation($event) {
        $event.preventDefault();
        if (!this.validateEntry()) {
            return;
        }
        var entity = this.entity;
        var view = this.view;
        var route = !entity.editionView().enabled ? 'show' : 'edit';
        var restEntry = this.$scope.entry.transformToRest(view.fields());
        this.progression.start();
        return this.WriteQueries
            .createOne(view, restEntry)
            .then(rawEntry => {
                this.progression.done();
                this.notification.log('Element successfully created.', { addnCls: 'humane-flatty-success' });
                var entry = view.mapEntry(rawEntry);
                this.$state.go(this.$state.get(route), { entity: entity.name(), id: entry.identifierValue });
            }, this.handleError.bind(this));
    }

    submitEdition($event) {
        $event.preventDefault();
        if (!this.validateEntry()) {
            return;
        }
        var view = this.view;
        var restEntry = this.$scope.entry.transformToRest(view.fields());
        this.progression.start();
        return this.WriteQueries
            .updateOne(view, restEntry, this.originEntityId)
            .then(() => {
                this.progression.done();
                this.notification.log('Changes successfully saved.', { addnCls: 'humane-flatty-success' });
            }, this.handleError.bind(this));
    }

    /**
     * Handle create or update errors
     *
     * @param {Object} response
     */
    handleError(response) {
        var errorMessage = this.config.getErrorMessageFor(this.view, response);

        this.progression.done();
        this.notification.log(errorMessage, {addnCls: 'humane-flatty-error'});
    }

    destroy() {
        this.$scope = undefined;
        this.$state = undefined;
        this.WriteQueries = undefined;
        this.dataStore = undefined;
        this.view = undefined;
        this.entity = undefined;
    }
}

FormController.$inject = ['$scope', '$state', 'WriteQueries', 'NgAdminConfiguration', 'progression', 'notification', 'view', 'dataStore'];
<commit_msg>[formController] Let users know the server reply<commit_after>export default class FormController {
    constructor($scope, $state, WriteQueries, Configuration, progression, notification, view, dataStore) {
        this.$scope = $scope;
        this.$state = $state;
        this.WriteQueries = WriteQueries;
        this.dataStore = dataStore;
        this.progression = progression;
        this.notification = notification;
        this.title = view.title();
        this.description = view.description();
        this.actions = view.actions();
        this.fields = view.fields();
        this.config = Configuration();
        this.view = view;
        this.entity = this.view.getEntity();
        this.$scope.entry = dataStore.getFirstEntry(this.entity.uniqueId);
        this.$scope.view = view;
        this.$scope.entity = this.entity;

        // in case of entity identifier being modified
        this.originEntityId = this.$scope.entry.values[this.entity.identifier().name()];

        $scope.$on('$destroy', this.destroy.bind(this));
    }

    validateEntry() {
        if (!this.form.$valid) {
            this.notification.log('invalid form', { addnCls: 'humane-flatty-error' });
            return false;
        }

        try {
            this.view.validate(this.$scope.entry);
        } catch (e) {
            this.notification.log(e, { addnCls: 'humane-flatty-error' });
            return false;
        }

        return true;
    }

    submitCreation($event) {
        $event.preventDefault();
        if (!this.validateEntry()) {
            return;
        }
        var entity = this.entity;
        var view = this.view;
        var route = !entity.editionView().enabled ? 'show' : 'edit';
        var restEntry = this.$scope.entry.transformToRest(view.fields());
        this.progression.start();
        return this.WriteQueries
            .createOne(view, restEntry)
            .then(rawEntry => {
                this.progression.done();
                this.notification.log('Element successfully created.', { addnCls: 'humane-flatty-success' });
                var entry = view.mapEntry(rawEntry);
                this.$state.go(this.$state.get(route), { entity: entity.name(), id: entry.identifierValue });
                return true;
            }, this.handleError.bind(this));
    }

    submitEdition($event) {
        $event.preventDefault();
        if (!this.validateEntry()) {
            return;
        }
        var view = this.view;
        var restEntry = this.$scope.entry.transformToRest(view.fields());
        this.progression.start();
        return this.WriteQueries
            .updateOne(view, restEntry, this.originEntityId)
            .then(() => {
                this.progression.done();
                this.notification.log('Changes successfully saved.', { addnCls: 'humane-flatty-success' });
                return true;
            }, this.handleError.bind(this));
    }

    /**
     * Handle create or update errors
     *
     * @param {Object} response
     */
    handleError(response) {
        var errorMessage = this.config.getErrorMessageFor(this.view, response);

        this.progression.done();
        this.notification.log(errorMessage, {addnCls: 'humane-flatty-error'});
        return false;
    }

    destroy() {
        this.$scope = undefined;
        this.$state = undefined;
        this.WriteQueries = undefined;
        this.dataStore = undefined;
        this.view = undefined;
        this.entity = undefined;
    }
}

FormController.$inject = ['$scope', '$state', 'WriteQueries', 'NgAdminConfiguration', 'progression', 'notification', 'view', 'dataStore'];
<|endoftext|>