<commit_before>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

connectionJSON="{ \"name\":\"$connection_name\", \"host\":\"$host\", \"database\":\"$database\", \"db_timezone\":\"$db_timezone\", \"query_timezone\":\"$query_timezone\", \"tmp_db_name\":\"$tmp_db_name\", \"dialect_name\":\"$dialect_name\", \"pdts_enabled\":$pdts_enabled, \"uses_oauth\":$uses_oauth, \"username\":\"$username\", \"certificate\":\"$certificate\", \"file_type\":\"$file_type\" }"

file_type=".json"

module.exports = {
	label: "Create a new BQ Connection",
	handler: async function({state,host,log}){

		const {user, adminApi} = host

		let ok = true
		// if(!state.userId){
		// 	log("User to disable not provided.")
		// 	log("Retreiving user list for prompt")
		// 	const allUsers = await adminApi(`users.id,display_name,email,avatar_url,is_disabled`)
		// 	const disableCandidates = allUsers.filter(u =>
		// 		! u.is_disabled // Hide already disabled users
		// 		&& u.id !== user.id // Don't suggest our user to disable themselves, for safety
		// 		)
		// 		.sort((a,b)=>(a.display_name||'').localeCompare(b.display_name||''))
		// 	log(`Returning list of ${disableCandidates.length} users for prompt`)

		// 	}
		if(!state.connectionName){ok=false}
		//if(!state.host){ok=false}
		if(!state.database){ok=false}
		//if(!state.username){ok=false}
		if(!state.certificateUpload){ok=false}
		if(!ok){
			return {
				//message:"this param is missing...",
				prompt: {
					connectionName: {
						type: "string",
						required:true
						},
					// host: { // This is the project name, which is already defined in the certificate json
					// 	type: "string",
					// 	required:true
					// 	},
					database: {
						type: "string",
						title: "Default Dataset",
						required:true
						},
					pdtsEnabled: {
						type: "boolean"
					},
					// username:{
					// 	type: "string",
					// 	required: true
					// 	},
					certificateUpload:{
						type: "string",
						title: "Certificate",
						required: true,
						media: {
							type:"application/json",
							binaryEncoding: "base64"
							}
						}
					}
				}
			}

		const base64EncodedCertificate = state.certificateUpload.replace(/^data:.*?base64,/,'')
		const certificateJson = Buffer.from(base64EncodedCertificate,'base64').toString('utf8')
		const certificate = JSON.parse(certificateJson)

		const username = certificate.client_email
		const dbHost = certificate.project_id

		if(!username){return {message:"Invalid certificate: Missing client_email"}}
		if(!dbHost){return {message:"Invalid certificate: Missing project_id"}}

		// TODO fetch existing connections and check for conflicts?

		await adminApi("POST connections",{body:{
			name:state.connectionName,
			host:dbHost,
			database:state.database,
			db_timezone: state.dbTimezone,
			query_timezone: state.queryTimezone,
			"tmp_db_name": state.tempDbName,
			"dialect_name":"bigquery_standard_sql",
			"pdts_enabled": state.pdtsEnabled,
			"uses_oauth": false,
			"username":username,
			"certificate":base64EncodedCertificate,
			"file_type":".json"
			}})

		}
	}<commit_msg>Cleanup flow<commit_after>/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

connectionJSON="{ \"name\":\"$connection_name\", \"host\":\"$host\", \"database\":\"$database\", \"db_timezone\":\"$db_timezone\", \"query_timezone\":\"$query_timezone\", \"tmp_db_name\":\"$tmp_db_name\", \"dialect_name\":\"$dialect_name\", \"pdts_enabled\":$pdts_enabled, \"uses_oauth\":$uses_oauth, \"username\":\"$username\", \"certificate\":\"$certificate\", \"file_type\":\"$file_type\" }"

file_type=".json"

module.exports = {
	label: "Create a new BQ Connection",
	handler: async function({state,host,log}){

		const {user, adminApi} = host

		let ok = true

		if(!state.connectionName){ok=false}
		if(!state.database){ok=false}
		if(!state.certificateUpload){ok=false}
		if(!ok){
			return {
				prompt: {
					connectionName: {
						type: "string",
						required:true
						},
					// host: { // This is the project name, which is already defined in the certificate json
					// 	type: "string",
					// 	required:true
					// 	},
					database: {
						type: "string",
						title: "Default Dataset",
						required:true
						},
					pdtsEnabled: {
						type: "boolean"
					},
					certificateUpload:{
						type: "string",
						title: "Certificate",
						required: true,
						media: {
							type:"application/json",
							binaryEncoding: "base64"
							}
						}
					}
				}
			}

		const base64EncodedCertificate = state.certificateUpload.replace(/^data:.*?base64,/,'')
		const certificateJson = Buffer.from(base64EncodedCertificate,'base64').toString('utf8')
		const certificate = JSON.parse(certificateJson)

		const username = certificate.client_email
		const dbHost = certificate.project_id

		if(!username){return {message:"Invalid certificate: Missing client_email"}}
		if(!dbHost){return {message:"Invalid certificate: Missing project_id"}}

		// May want to fetch existing connections and check for conflicts/duplicates?

		await adminApi("POST connections",{body:{
			name:state.connectionName,
			host:dbHost,
			database:state.database,
			db_timezone: state.dbTimezone,
			query_timezone: state.queryTimezone,
			"tmp_db_name": state.tempDbName,
			"dialect_name":"bigquery_standard_sql",
			"pdts_enabled": state.pdtsEnabled,
			"uses_oauth": false,
			"username":username,
			"certificate":base64EncodedCertificate,
			"file_type":".json"
			}})

		}
	}<|endoftext|>


<commit_before>'use strict';

var mano     = require('mano')
  , gm       = require('./gm')
  , path     = require('path')
  , unlink   = require('fs2/unlink')
  , contains = require('es5-ext/string/#/contains')
  , replace  = require('es5-ext/string/#/plain-replace-all')
  , deferred = require('deferred')

  , resolve = path.resolve
  , uploadsPath = mano.uploadsPath;

module.exports = function (file) {
	var path        = uploadsPath
	  , previewPath = file.path
	  , processPath = file.path
	  , thumbPath   = replace.call(file.__id__, '/', '-')
			+ '.thumb.' + file.name
	  , thumb, preview, processFullPath, thumbFullPath, previewFullPath;

	if (file.type !== 'image/jpeg') {
		thumbPath += '.jpg';
		previewPath += '.jpg';
	}
	if (file.type === 'application/pdf') {
		processPath += '[0]';
	}

	processFullPath = resolve(path, processPath);
	thumbFullPath = resolve(path, thumbPath);
	thumb = gm(processFullPath).resize(500, 500).writeP(thumbFullPath);

	if (file.path !== previewPath) {
		previewFullPath = resolve(path, previewPath);
		preview = gm(processFullPath).resize(1500, 1500).writeP(previewFullPath);
	}

	return deferred(thumb, preview)(function () {
		if (!file.path) {
			return deferred(unlink(thumbFullPath), preview && unlink(previewFullPath));
		}

		file.thumb.path = thumbPath;
		if (preview) {
			file.generatedPreview.path = previewPath;
		} else {
			file.isPreviewGenerated = false;
		}
	}, function (e) {
		if (!file.path && contains.call(e.message, 'Unable to open file')) {
			return deferred(unlink(thumbFullPath), preview && unlink(previewFullPath))(null, false);
		}
		throw e;
	});
};
<commit_msg>Improve quality of PDF convertion<commit_after>'use strict';

var mano     = require('mano')
  , gm       = require('./gm')
  , path     = require('path')
  , unlink   = require('fs2/unlink')
  , contains = require('es5-ext/string/#/contains')
  , replace  = require('es5-ext/string/#/plain-replace-all')
  , deferred = require('deferred')

  , resolve = path.resolve
  , uploadsPath = mano.uploadsPath;

module.exports = function (file) {
	var path        = uploadsPath
	  , previewPath = file.path
	  , processPath = file.path
	  , thumbPath   = replace.call(file.__id__, '/', '-')
			+ '.thumb.' + file.name
	  , thumb, preview, processFullPath, thumbFullPath, previewFullPath;

	if (file.type !== 'image/jpeg') {
		thumbPath += '.jpg';
		previewPath += '.jpg';
	}
	if (file.type === 'application/pdf') {
		processPath += '[0]';
	}

	processFullPath = resolve(path, processPath);
	thumbFullPath = resolve(path, thumbPath);
	thumb = gm(processFullPath).density(300, 300).resize(500, 500).writeP(thumbFullPath);

	if (file.path !== previewPath) {
		previewFullPath = resolve(path, previewPath);
		preview = gm(processFullPath).density(300, 300).resize(1500, 1500).writeP(previewFullPath);
	}

	return deferred(thumb, preview)(function () {
		if (!file.path) {
			return deferred(unlink(thumbFullPath), preview && unlink(previewFullPath));
		}

		file.thumb.path = thumbPath;
		if (preview) {
			file.generatedPreview.path = previewPath;
		} else {
			file.isPreviewGenerated = false;
		}
	}, function (e) {
		if (!file.path && contains.call(e.message, 'Unable to open file')) {
			return deferred(unlink(thumbFullPath), preview && unlink(previewFullPath))(null, false);
		}
		throw e;
	});
};
<|endoftext|>


<commit_before>/**
 * Created by Omnius on 18/07/2016.
 *
 * These codes were done to address the inability of the client web pages (non-framework-based) to set its own headers
 * on a form GET request (NOT XHR requests), i.e. web page content instead of JSON. Eran Hammer's Hawk server codes
 * (and hapi-auth-hawk) checks the client-sent headers for a MAC and a hash that was retrieved from the
 * ID, key, and algorithm processing using the Hawk client.  This file acts as a middleware/adapter to convert the
 * session cookie information into Hawk-readable header data for hapi-auth-hawk.
 *
 */
'use strict';

const Hawk = require('hawk');
const retrieveFromToken = require(process.cwd() + '/server/helpers/hkdfTokenGenerator').retrieveFromToken;

module.exports = (request, reply) => {

    const clientToken = request.state['Hawk-Session-Token'];

    if (!(clientToken && clientToken.hawkSessionToken)) {
        return reply.continue();
    }

    const server = request.server;

    const ikm = clientToken.hawkSessionToken;
    const info = request.info.host + '/hawkSessionToken';
    const salt = '';
    const length = 2 * 32;

    server.log(ikm + ' ' + info + ' ' + salt + ' ' + length);

    retrieveFromToken(ikm, info, salt, length, (id, key) => {
        if (!(id && key)) {
            return reply.continue();
        }

        const algorithm = clientToken.algorithm;

        const hawkCredentials = {
            id: id,
            key: key,
            algorithm: algorithm
        };

        const url = request.connection.info.protocol
            + '://'
            + request.info.host + '/user/profile';

        request.raw.req.url = url;

        const header = Hawk.client.header(url,
            'GET',
            {credentials: hawkCredentials, ext: 'some-app-data'});

        request.raw.req.headers.authorization = header.field;

        return reply.continue();
    });
};
<commit_msg>Add 443 to URL<commit_after>/**
 * Created by Omnius on 18/07/2016.
 *
 * These codes were done to address the inability of the client web pages (non-framework-based) to set its own headers
 * on a form GET request (NOT XHR requests), i.e. web page content instead of JSON. Eran Hammer's Hawk server codes
 * (and hapi-auth-hawk) checks the client-sent headers for a MAC and a hash that was retrieved from the
 * ID, key, and algorithm processing using the Hawk client.  This file acts as a middleware/adapter to convert the
 * session cookie information into Hawk-readable header data for hapi-auth-hawk.
 *
 */
'use strict';

const Hawk = require('hawk');
const retrieveFromToken = require(process.cwd() + '/server/helpers/hkdfTokenGenerator').retrieveFromToken;

module.exports = (request, reply) => {

    const clientToken = request.state['Hawk-Session-Token'];

    if (!(clientToken && clientToken.hawkSessionToken)) {
        return reply.continue();
    }

    const server = request.server;

    const ikm = clientToken.hawkSessionToken;
    const info = request.info.host + '/hawkSessionToken';
    const salt = '';
    const length = 2 * 32;

    server.log(ikm + ' ' + info + ' ' + salt + ' ' + length);

    retrieveFromToken(ikm, info, salt, length, (id, key) => {
        if (!(id && key)) {
            return reply.continue();
        }

        const algorithm = clientToken.algorithm;

        const hawkCredentials = {
            id: id,
            key: key,
            algorithm: algorithm
        };

        const protocol = request.connection.info.protocol;

        const url = protocol
            + '://'
            + request.info.host + (protocol === 'https' ? '443' : '') + '/user/profile';

        request.server.log('hawkPreAuth url: ' + url);

        request.raw.req.url = url;

        const header = Hawk.client.header(url,
            'GET',
            {credentials: hawkCredentials, ext: 'some-app-data'});

        request.raw.req.headers.authorization = header.field;

        return reply.continue();
    });
};
<|endoftext|>


<commit_before>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    ready: undefined, // callback on layoutready
    stop: undefined, // callback on layoutstop
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0 // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var nodes = cy.nodes();
    var edges = cy.edges();
    var graph = nodes.add(edges);
    var container = cy.container();

    var width = container.clientWidth;
    var height = container.clientHeight;

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var maxDegree = nodes.maxDegree( false );
        roots = nodes.filter('[[degree = ' + maxDegree + ']]');
      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};

    // find the depths of the nodes
    graph.bfs(roots, function(i, depth){
      var ele = this[0];

      if( !depths[depth] ){
        depths[depth] = [];
      }

      depths[depth].push( ele );
      foundByBfs[ ele.id() ] = true;
      id2depth[ ele.id() ] = depth;
    }, options.directed);

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.BreadthFirstLayout = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges('[target = "' + node.id() + '"]');
      var thisInfo = node._private.scratch.BreadthFirstLayout;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.BreadthFirstLayout;

        if( thisInfo.depth < otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.BreadthFirstLayout;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.BreadthFirstLayout;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.BreadthFirstLayout;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    for( var i = 0; i < nodes.length; i++ ){
      var w = nodes[i].outerWidth();
      var h = nodes[i].outerHeight();

      minDistance = Math.max(minDistance, w, h);
    }
    minDistance *= 1.75; // just to have some nice spacing

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.BreadthFirstLayout.depth;
      var neighbors = ele.neighborhood().nodes();
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var nEdges = neighbor.edgesWith( ele );
        var index = neighbor._private.scratch.BreadthFirstLayout.index;
        var depth = neighbor._private.scratch.BreadthFirstLayout.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity
    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        var depth = i;
        var newDepths = [];

        depths[i] = depths[i].sort(function(a, b){
          var apct = getWeightedPercent( a );
          var bpct = getWeightedPercent( b );

          return apct - bpct;
        });
      }
      assignDepthsToEles(); // and update

    }

    var center = {
      x: width/2,
      y: height/2
    };
    nodes.positions(function(){
      var ele = this[0];
      var info = ele._private.scratch.BreadthFirstLayout;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( width / (depthSize + 1), minDistance );
      var distanceY = Math.max( height / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( width / 2 / depths.length, height / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( options.circle ){
        var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
        var theta = 2 * Math.PI / depths[depth].length * index;

        if( depth === 0 && depths[0].length === 1 ){
          radius = 1;
        }

        return {
          x: center.x + radius * Math.cos(theta),
          y: center.y + radius * Math.sin(theta)
        };

      } else {
        return {
          x: center.x + (index + 1 - depthSize/2) * distanceX,
          y: (depth + 1) * distanceY
        };
      }

    });

    if( params.fit ){
      cy.fit( options.padding );
    }

    cy.one('layoutready', params.ready);
    cy.trigger('layoutready');

    cy.one('layoutstop', params.stop);
    cy.trigger('layoutstop');
  };

  BreadthFirstLayout.prototype.stop = function(){
    // not a continuous layout
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<commit_msg>better alignment<commit_after>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    ready: undefined, // callback on layoutready
    stop: undefined, // callback on layoutstop
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0 // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var nodes = cy.nodes();
    var edges = cy.edges();
    var graph = nodes.add(edges);
    var container = cy.container();

    var width = container.clientWidth;
    var height = container.clientHeight;

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var maxDegree = nodes.maxDegree( false );
        roots = nodes.filter('[[degree = ' + maxDegree + ']]');
      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};

    // find the depths of the nodes
    graph.bfs(roots, function(i, depth){
      var ele = this[0];

      if( !depths[depth] ){
        depths[depth] = [];
      }

      depths[depth].push( ele );
      foundByBfs[ ele.id() ] = true;
      id2depth[ ele.id() ] = depth;
    }, options.directed);

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.BreadthFirstLayout = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges('[target = "' + node.id() + '"]');
      var thisInfo = node._private.scratch.BreadthFirstLayout;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.BreadthFirstLayout;

        if( thisInfo.depth < otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.BreadthFirstLayout;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.BreadthFirstLayout;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.BreadthFirstLayout;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    for( var i = 0; i < nodes.length; i++ ){
      var w = nodes[i].outerWidth();
      var h = nodes[i].outerHeight();

      minDistance = Math.max(minDistance, w, h);
    }
    minDistance *= 1.75; // just to have some nice spacing

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.BreadthFirstLayout.depth;
      var neighbors = ele.neighborhood().nodes();
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var nEdges = neighbor.edgesWith( ele );
        var index = neighbor._private.scratch.BreadthFirstLayout.index;
        var depth = neighbor._private.scratch.BreadthFirstLayout.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity
    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        var depth = i;
        var newDepths = [];

        depths[i] = depths[i].sort(function(a, b){
          var apct = getWeightedPercent( a );
          var bpct = getWeightedPercent( b );

          return apct - bpct;
        });
      }
      assignDepthsToEles(); // and update

    }

    var center = {
      x: width/2,
      y: height/2
    };
    nodes.positions(function(){
      var ele = this[0];
      var info = ele._private.scratch.BreadthFirstLayout;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( width / (depthSize + 1), minDistance );
      var distanceY = Math.max( height / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( width / 2 / depths.length, height / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( options.circle ){
        var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
        var theta = 2 * Math.PI / depths[depth].length * index;

        if( depth === 0 && depths[0].length === 1 ){
          radius = 1;
        }

        return {
          x: center.x + radius * Math.cos(theta),
          y: center.y + radius * Math.sin(theta)
        };

      } else {
        return {
          x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
          y: (depth + 1) * distanceY
        };
      }

    });

    if( params.fit ){
      cy.fit( options.padding );
    }

    cy.one('layoutready', params.ready);
    cy.trigger('layoutready');

    cy.one('layoutstop', params.stop);
    cy.trigger('layoutstop');
  };

  BreadthFirstLayout.prototype.stop = function(){
    // not a continuous layout
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<|endoftext|>


<commit_before>'use strict';

jest.dontMock('../../scripts/stores/ExerciseStore.js');
jest.mock('../../scripts/dispatcher/AppDispatcher.js');
jest.mock('../../scripts/utils/LocalStorageUtil.js');

describe("ExerciseStore", () => {
    let cb,
        LocalStorageUtil,
        AppDispatcher,
        ExerciseStore,
        ActionTypes = require('../../scripts/constants/ActionTypes.js'),
        actionAddExercises = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.ADD_EXERCISE,
                exercise: 'Hyperextensions'
            }
        },
        actionUpdateExercise = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.UPDATE_EXERCISE,
                exercise: {
                    id: 1,
                    label: 'newLabel'
                }
            }
        },
        actionRemoveExercise = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.REMOVE_EXERCISE,
                index: 0
            }
        },
        actionRequestExercises = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.GET_EXERCISES
            }
        };

    beforeEach(() => {
        AppDispatcher = require('../../scripts/dispatcher/AppDispatcher');
        ExerciseStore = require('../../scripts/stores/ExerciseStore.js');
        LocalStorageUtil.lsGet.mockImplementation(() => {
            return [];
        });
        cb = AppDispatcher.register.mock.calls[0][0];
    });

    afterEach(() => {
        LocalStorageUtil.lsGet.mockClear();
        LocalStorageUtil.lsSet.mockClear();
    });

    it("getExercises", () => {
        var exercises = ExerciseStore.getExercises();
        expect(exercises.size).toEqual(0);
    });

    it("doesn't throw on an unregistered action", () => {
        expect(cb.bind(null, {
            source: 'VIEW_ACTION',
            action: {
                type: 'NULL'
            }
        })).not.toThrow();
    });

    describe('has exercises', () => {
        it("getExerciseForId", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return [
                    {
                        id: '1',
                        label: 'T-Bar-Rows'
                    }
                ];
            });
            var exercise = ExerciseStore.getExerciseForId('1');
            expect(exercise.get('label')).toEqual('T-Bar-Rows');
        });

        it("requests exercises if they are initialized", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return [];
            });
            cb(actionRequestExercises);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(0);
        });

        it("creates initial exercises, if they are uninitialized", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return null;
            });
            cb(actionRequestExercises);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(1);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('id')).toBe('1');
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('label')).toBe('T-Bar-Rows');
        });

        it("adds exercises", () => {
            cb(actionAddExercises);
            cb(actionAddExercises);
            expect(ExerciseStore.getExercises().size).toBe(2);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(2);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('label')).toBe('Hyperextensions');
        });

        it("updates exercises", () => {
            cb(actionAddExercises);
            cb(actionAddExercises);
            cb(actionUpdateExercise);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(3);
            expect(LocalStorageUtil.lsSet.mock.calls[2][1].get(0).get('label')).toBe('newLabel');
        });

        it("removes exercises", () => {
            cb(actionRemoveExercise);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(1);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].size).toBe(0);
        });
    });
});

<commit_msg>fix exercisestore spec<commit_after>'use strict';

jest.dontMock('../../scripts/stores/ExerciseStore.js');
jest.mock('../../scripts/dispatcher/AppDispatcher.js');
jest.mock('../../scripts/utils/LocalStorageUtil.js');

describe("ExerciseStore", () => {
    let cb,
        AppDispatcher,
        LocalStorageUtil,
        ExerciseStore,
        ActionTypes = require('../../scripts/constants/ActionTypes.js'),
        actionAddExercises = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.ADD_EXERCISE,
                exercise: 'Hyperextensions'
            }
        },
        actionUpdateExercise = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.UPDATE_EXERCISE,
                exercise: {
                    id: 1,
                    label: 'newLabel'
                }
            }
        },
        actionRemoveExercise = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.REMOVE_EXERCISE,
                index: 0
            }
        },
        actionRequestExercises = {
            source: 'VIEW_ACTION',
            action: {
                type: ActionTypes.GET_EXERCISES
            }
        };

    beforeEach(() => {
        LocalStorageUtil = require('../../scripts/utils/LocalStorageUtil.js');
        AppDispatcher = require('../../scripts/dispatcher/AppDispatcher');
        ExerciseStore = require('../../scripts/stores/ExerciseStore.js');
        LocalStorageUtil.lsGet.mockImplementation(() => {
            return [];
        });
        cb = AppDispatcher.register.mock.calls[0][0];
    });

    afterEach(() => {
        LocalStorageUtil.lsGet.mockClear();
        LocalStorageUtil.lsSet.mockClear();
    });

    it("getExercises", () => {
        var exercises = ExerciseStore.getExercises();
        expect(exercises.size).toEqual(0);
    });

    it("doesn't throw on an unregistered action", () => {
        expect(cb.bind(null, {
            source: 'VIEW_ACTION',
            action: {
                type: 'NULL'
            }
        })).not.toThrow();
    });

    describe('has exercises', () => {
        it("getExerciseForId", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return [
                    {
                        id: '1',
                        label: 'T-Bar-Rows'
                    }
                ];
            });
            var exercise = ExerciseStore.getExerciseForId('1');
            expect(exercise.get('label')).toEqual('T-Bar-Rows');
        });

        it("requests exercises if they are initialized", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return [];
            });
            cb(actionRequestExercises);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(0);
        });

        it("creates initial exercises, if they are uninitialized", () => {
            LocalStorageUtil.lsGet.mockImplementation(() => {
                return null;
            });
            cb(actionRequestExercises);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(1);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('id')).toBe('1');
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('label')).toBe('T-Bar-Rows');
        });

        it("adds exercises", () => {
            cb(actionAddExercises);
            cb(actionAddExercises);
            expect(ExerciseStore.getExercises().size).toBe(2);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(2);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].get(0).get('label')).toBe('Hyperextensions');
        });

        it("updates exercises", () => {
            cb(actionAddExercises);
            cb(actionAddExercises);
            cb(actionUpdateExercise);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(3);
            expect(LocalStorageUtil.lsSet.mock.calls[2][1].get(0).get('label')).toBe('newLabel');
        });

        it("removes exercises", () => {
            cb(actionRemoveExercise);
            expect(LocalStorageUtil.lsSet.mock.calls.length).toBe(1);
            expect(LocalStorageUtil.lsSet.mock.calls[0][1].size).toBe(0);
        });
    });
});

<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function (grunt) {

    // Project configuration.
    grunt.initConfig({

        // Metadata.
        meta: {
            version: {
                eva: '1.0.0'
            }
        },

        bannereva: '/*! EVA - v<%= meta.version.eva %> - ' +
            '<%= grunt.template.today("yyyy-mm-dd HH:MM:ss") %>\n' +
            '* http://https://github.com/EBIvariation/eva.git/\n' +
            '* Copyright (c) <%= grunt.template.today("yyyy") %> ' +
            ' ' +
            'Licensed GPLv2 */\n',
        // Task configuration.

        concat: {
            options: {
                banner: '<%= bannereva %>',
                stripBanners: true
            },

            eva: {
                src: [
                    /** eva app js **/
                    'src/eva.js',
//                    'src/eva-study-browser-panel.old.js',
                    'src/eva-variant-widget.js',
                    'src/eva-menu.js',
                    'src/eva-adapter.js',
                    'src/eva-manager.js',
                    'src/eva-config.js'
                ],
                dest: 'build/<%= meta.version.eva %>/eva-<%= meta.version.eva %>.js'
            }

        },
        uglify: {

            eva: {
                src: '<%= concat.eva.dest %>',
                dest: 'build/<%= meta.version.eva %>/eva-<%= meta.version.eva %>.min.js'
            }
        },
        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                immed: true,
                latedef: true,
                newcap: true,
                noarg: true,
                sub: true,
                undef: true,
                unused: true,
                boss: true,
                eqnull: true,
                browser: true,
                globals: {}
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            lib_test: {
                src: ['lib/**/*.js', 'test/**/*.js']
            }
        },
        qunit: {
            files: ['test/**/*.html']
        },

        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            lib_test: {
                files: '<%= jshint.lib_test.src %>',
                tasks: ['jshint:lib_test', 'qunit']
            }
        },

        copy: {

            eva: {
                files: [
                    {   expand: true, src: ['src/files/*'], dest: 'build/<%= meta.version.eva %>/files', flatten: true},
                    {   expand: true, src: ['src/fonts/*'], dest: 'build/<%= meta.version.eva %>/fonts', flatten: true},
                    {   expand: true, src: ['src/css/*'], dest: 'build/<%= meta.version.eva %>/css', flatten: true},
                    {   expand: true, src: ['src/img/*'], dest: 'build/<%= meta.version.eva %>/img', flatten: true},
                    {   expand: true, src: ['src/*.html'], dest: 'build/<%= meta.version.eva %>/', flatten: true, filter: 'isFile'},
                    {   expand: true, src: ['lib/jsorolla/build/*/*.js'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['lib/jsorolla/vendor/**'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['lib/jsorolla/styles/**'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['vendor/bootstrap-*/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/ext-*/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/highchart-*/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/platform-*/**'], dest: 'build/<%= meta.version.eva %>'}
                ]
            }

        },

        clean: {
            eva: ['build/<%= meta.version.eva %>/']
        },

        htmlbuild: {
            eva: {
                src: 'src/index.html',
                dest: 'build/<%= meta.version.eva %>/',
                options: {
                    beautify: true,
                    scripts: {
                        'eva-js': '<%= uglify.eva.dest %>',
                        'lib': [
//                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/genome-viewer/gv-config.js',
//                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/genome-viewer/genome-viewer.js',
                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/lib.min.js'
                               ],
                        'vendor': [
                            'build/<%= meta.version.eva %>/vendor/ext-5.0.1/js/ext-all.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/underscore-min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/backbone-min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.min.js',
                            'build/<%= meta.version.eva %>/vendor/bootstrap-*/js/bootstrap.min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.cookie.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.sha1.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/purl.min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.qtip.min.js',
                            'build/<%= meta.version.eva %>/vendor/highcharts-4.0.3/js/highcharts.js'

                        ],
                        'platform': [
                            'build/<%= meta.version.eva %>/vendor/platform-0.3.5/js/platform.js'
                        ]
//                        'internal-dependencies': [
//                            'build/<%= meta.version.eva %>/gv-config.js'
//                        ]
                    },
                    styles: {
                        'css': [
                            'build/<%= meta.version.eva %>/lib/jsorolla/styles/css/style.css',
                            'build/<%= meta.version.eva %>/css/eva.css'
                        ],
                        'vendor': [
                            'build/<%= meta.version.eva %>/vendor/ext-5.0.1/theme-ebi-embl/theme-ebi-embl-all.css',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.qtip.min.css',
                            'build/<%= meta.version.eva %>/vendor/bootstrap-3.2.0/css/bootstrap.min.css'
                        ]
                    }
                }
            }
        },

        'curl-dir': {
            long: {
                src: [
                    'http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js',
                    'http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.map',
                    'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-1.5.2.min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.map',
                    'http://hub.chemdoodle.com/cwc/5.1.0/ChemDoodleWeb.css',
                    'http://hub.chemdoodle.com/cwc/5.1.0/ChemDoodleWeb.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.0.6/jquery.mousewheel.min.js',
                    'https://raw.github.com/toji/gl-matrix/master/dist/gl-matrix-min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.3.1/jquery.cookie.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-url-parser/2.2.1/purl.min.js',
                    'http://jsapi.bioinfo.cipf.es/ext-libs/jquery-plugins/jquery.sha1.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.1.1/jquery.qtip.min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.1.1/jquery.qtip.min.css',
//                    'http://jsapi.bioinfo.cipf.es/ext-libs/qtip2/jquery.qtip.min.js',
//                    'http://jsapi.bioinfo.cipf.es/ext-libs/qtip2/jquery.qtip.min.css',
                    'http://jsapi.bioinfo.cipf.es/ext-libs/rawdeflate.js'
                ],
                dest: 'vendor'
            }
        },

        watch: {
            src: {
                files: ['app/**'],
                tasks: ['default'],
                options: {spawn: false}
            }

        }
    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
//    grunt.loadNpmTasks('grunt-contrib-qunit');
//    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-rename');
    grunt.loadNpmTasks('grunt-html-build');
    grunt.loadNpmTasks('grunt-curl');

    grunt.registerTask('vendor', ['curl-dir']);

    // Default task.
    grunt.registerTask('default', ['clean:eva','concat:eva','uglify:eva', 'copy:eva', 'htmlbuild:eva'])

//    grunt.registerTask('clean', ['clean:eva']);

};
<commit_msg>[web] Gruntfile bug fixed<commit_after>/*global module:false*/
module.exports = function (grunt) {

    // Project configuration.
    grunt.initConfig({

        // Metadata.
        meta: {
            version: {
                eva: '1.0.0'
            }
        },

        bannereva: '/*! EVA - v<%= meta.version.eva %> - ' +
            '<%= grunt.template.today("yyyy-mm-dd HH:MM:ss") %>\n' +
            '* http://https://github.com/EBIvariation/eva.git/\n' +
            '* Copyright (c) <%= grunt.template.today("yyyy") %> ' +
            ' ' +
            'Licensed GPLv2 */\n',
        // Task configuration.

        concat: {
            options: {
                banner: '<%= bannereva %>',
                stripBanners: true
            },

            eva: {
                src: [
                    /** eva app js **/
                    'src/eva.js',
//                    'src/eva-study-browser-panel.old.js',
                    'src/eva-variant-widget.js',
                    'src/eva-menu.js',
                    'src/eva-adapter.js',
                    'src/eva-manager.js',
                    'src/eva-config.js'
                ],
                dest: 'build/<%= meta.version.eva %>/eva-<%= meta.version.eva %>.js'
            }

        },
        uglify: {

            eva: {
                src: '<%= concat.eva.dest %>',
                dest: 'build/<%= meta.version.eva %>/eva-<%= meta.version.eva %>.min.js'
            }
        },
        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                immed: true,
                latedef: true,
                newcap: true,
                noarg: true,
                sub: true,
                undef: true,
                unused: true,
                boss: true,
                eqnull: true,
                browser: true,
                globals: {}
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            lib_test: {
                src: ['lib/**/*.js', 'test/**/*.js']
            }
        },
        qunit: {
            files: ['test/**/*.html']
        },

        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            lib_test: {
                files: '<%= jshint.lib_test.src %>',
                tasks: ['jshint:lib_test', 'qunit']
            }
        },

        copy: {

            eva: {
                files: [
                    {   expand: true, src: ['src/files/*'], dest: 'build/<%= meta.version.eva %>/files', flatten: true},
                    {   expand: true, src: ['src/fonts/*'], dest: 'build/<%= meta.version.eva %>/fonts', flatten: true},
                    {   expand: true, src: ['src/css/*'], dest: 'build/<%= meta.version.eva %>/css', flatten: true},
                    {   expand: true, src: ['src/img/*'], dest: 'build/<%= meta.version.eva %>/img', flatten: true},
                    {   expand: true, src: ['src/*.html'], dest: 'build/<%= meta.version.eva %>/', flatten: true, filter: 'isFile'},
                    {   expand: true, src: ['lib/jsorolla/build/*/*.js'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['lib/jsorolla/vendor/**'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['lib/jsorolla/styles/**'], dest: 'build/<%= meta.version.eva %>',flatten: false},
                    {   expand: true, src: ['vendor/bootstrap-*/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/ext-*/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/highcharts-4.0.3/**'], dest: 'build/<%= meta.version.eva %>'},
                    {   expand: true, src: ['vendor/platform-0.3.5/**'], dest: 'build/<%= meta.version.eva %>'}
                ]
            }

        },

        clean: {
            eva: ['build/<%= meta.version.eva %>/']
        },

        htmlbuild: {
            eva: {
                src: 'src/index.html',
                dest: 'build/<%= meta.version.eva %>/',
                options: {
                    beautify: true,
                    scripts: {
                        'eva-js': '<%= uglify.eva.dest %>',
                        'lib': [
//                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/genome-viewer/gv-config.js',
//                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/genome-viewer/genome-viewer.js',
                                'build/<%= meta.version.eva %>/lib/jsorolla/build/1.1.6/lib.min.js'
                               ],
                        'vendor': [
                            'build/<%= meta.version.eva %>/vendor/ext-5.0.1/js/ext-all.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/underscore-min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/backbone-min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.min.js',
                            'build/<%= meta.version.eva %>/vendor/bootstrap-*/js/bootstrap.min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.cookie.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.sha1.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/purl.min.js',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.qtip.min.js',
                            'build/<%= meta.version.eva %>/vendor/highcharts-4.0.3/js/highcharts.js'

                        ],
                        'platform': [
                            'build/<%= meta.version.eva %>/vendor/platform-0.3.5/js/platform.js'
                        ]
//                        'internal-dependencies': [
//                            'build/<%= meta.version.eva %>/gv-config.js'
//                        ]
                    },
                    styles: {
                        'css': [
                            'build/<%= meta.version.eva %>/lib/jsorolla/styles/css/style.css',
                            'build/<%= meta.version.eva %>/css/eva.css'
                        ],
                        'vendor': [
                            'build/<%= meta.version.eva %>/vendor/ext-5.0.1/theme-ebi-embl/theme-ebi-embl-all.css',
                            'build/<%= meta.version.eva %>/lib/jsorolla/vendor/jquery.qtip.min.css',
                            'build/<%= meta.version.eva %>/vendor/bootstrap-3.2.0/css/bootstrap.min.css'
                        ]
                    }
                }
            }
        },

        'curl-dir': {
            long: {
                src: [
                    'http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js',
                    'http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.map',
                    'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-1.5.2.min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.map',
                    'http://hub.chemdoodle.com/cwc/5.1.0/ChemDoodleWeb.css',
                    'http://hub.chemdoodle.com/cwc/5.1.0/ChemDoodleWeb.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.0.6/jquery.mousewheel.min.js',
                    'https://raw.github.com/toji/gl-matrix/master/dist/gl-matrix-min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.3.1/jquery.cookie.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/jquery-url-parser/2.2.1/purl.min.js',
                    'http://jsapi.bioinfo.cipf.es/ext-libs/jquery-plugins/jquery.sha1.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.1.1/jquery.qtip.min.js',
                    'http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.1.1/jquery.qtip.min.css',
//                    'http://jsapi.bioinfo.cipf.es/ext-libs/qtip2/jquery.qtip.min.js',
//                    'http://jsapi.bioinfo.cipf.es/ext-libs/qtip2/jquery.qtip.min.css',
                    'http://jsapi.bioinfo.cipf.es/ext-libs/rawdeflate.js'
                ],
                dest: 'vendor'
            }
        },

        watch: {
            src: {
                files: ['app/**'],
                tasks: ['default'],
                options: {spawn: false}
            }

        }
    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
//    grunt.loadNpmTasks('grunt-contrib-qunit');
//    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-rename');
    grunt.loadNpmTasks('grunt-html-build');
    grunt.loadNpmTasks('grunt-curl');

    grunt.registerTask('vendor', ['curl-dir']);

    // Default task.
    grunt.registerTask('default', ['clean:eva','concat:eva','uglify:eva', 'copy:eva', 'htmlbuild:eva'])

//    grunt.registerTask('clean', ['clean:eva']);

};
<|endoftext|>


<commit_before>exports.func = (client, oldUser, newUser) => {
	if(!(oldUser.tag == newUser.tag)) {
		client.guilds.reduce((list, guild) => {
			guild.fetchMember(newUser)
				.then((user) => {
					client.logToGuild(guild, `:pen_ballpoint: ${client.formatUser(oldUser)} tag was changed to \`${newUser.tag}\``);
			}).catch((err) => { return; });
		}, []);
	}
};<commit_msg>Update text for tag changes.<commit_after>exports.func = (client, oldUser, newUser) => {
	if(!(oldUser.tag == newUser.tag)) {
		client.guilds.reduce((list, guild) => {
			guild.fetchMember(newUser)
				.then((user) => {
					client.logToGuild(guild, `:pen_ballpoint: ${client.formatUser(newUser)} tag was changed from \`${oldUser.tag}\` to \`${newUser.tag}\``);
			}).catch((err) => { return; });
		}, []);
	}
};<|endoftext|>


<commit_before>(function() {
  String.lunch = {
    moment_cache: {},
    s2_cache: {},

    date: "YYYYMMDD",
    time: "Hmm",
    datetime: "",

    hdate: "MMM Do, YYYY",
    hdate_no_year: "MMM Do",
    htime_hour: "H? A",
    htime_minute: ":mm",
    _seconds_math: {
      second: 1,
      minute: 60,
      hour: 60*60,
      day: 24*60*60,
      week: 7*24*60*60,
      list: ['week','day','hour','minute','second'],
    },
    clear: function() {
      delete String.lunch.moment_cache;
      delete String.lunch.s2_cache;
      String.lunch.moment_cache = {};
      String.lunch.s2_cache = {}
    },
  };

  var Sl = String.lunch;
  String.prototype.moment = function moment() {
    if (String.lunch.moment_cache[this]) { return String.lunch.moment_cache[this] }
    var s1 = this,m1,s2,m2;
    if (s1.indexOf("||") != -1) {
      [s1,s2] = s1.split("||");
    }
    if (this.match(/^\d\d?:\d\d/)) { // passing in time with no date, set date to today
      m1 = window.moment(window.moment().format("YYYY-MM-DD ") + s1);
    } else {
      var m1 = window.moment(s1.toString());
    }
    if (s2 && s2.match(/^\d\d?:\d\d/)) {
      s2 = m1.format(Strin.lunch.date)+" "+s2;
      m2 = window.moment(s2);
      if (m2 < m1) {
        m2 = m2.add(1,'days')
      }
    }
    String.lunch.moment_cache[this] = m1;
    String.lunch.s2_cache[this] = s2;
    return m1;
  }
  String.prototype.format = function(s) { return this.moment().format(s); }
  String.prototype.calendar = function calendar(s) {
    return this.moment().calendar(s);
  }
  String.prototype.range = function(format) {
    this.moment();
    return this.hdate()+ " - "+Sl.s2_cache[this].hdate();
  }
  String.prototype.htimedelta = function() {
    if (this.indexOf("||") == -1) { return (this+"||"+moment().format()).htimedelta() }
    var m = this.moment();
    var seconds = (this.moment()-Sl.s2_cache[this].moment())/1000;
    var abs = Math.abs(seconds);
    var _sm = Sl._seconds_math; // going to be typing this a lot
    var unit_big,unit_small,value = abs;
    var s=(seconds<0)?"-":"+"; // sign of timedelta
    var v="",V; // value big and small, (eg [3,2] for "3 days and 2 hours", would return "3d2h")
    var u="",U; // unit abbreviation big and small, (eg ["d","h"] for above example)
    for (var i=0;i<_sm.list.length;i++) {
      unit_big = _sm.list[i];
      if (abs > _sm[unit_big]) { // eg. absolute value of seconds is more than 1 month|week|day... worth of seconds
        V = Math.floor(abs/_sm[unit_big]); // value/big_conversion_factor
        U = unit_big[0];
        unit_small = _sm.list[i+1];
        if (unit_small) {
          v = Math.floor((abs%_sm[unit_big])/_sm[unit_small]); // remainder/small_conversion_factor
          u = unit_small[0]
        }
        break;
      }
    }
    return `${s}${V}${U}${v}${u}`; // sVUvu or "+3d2h" or "sign big_value big_unit small_value small_unit", ya dig?
  }
  String.prototype.htimerange = function(format) {
    this.moment();
    var m1 = this.moment();
    var m2 = Sl.s2_cache[this].moment();
    var time1 = m1.format(m1.minute()?"h:mm":"h"); // 12 or 12:45
    if (m1.hour()>=12 != m2.hour()>=12) { time1 += m1.format(" A") } // add am/pm if am/pm changes from time1 to time2
    return time1 + " - " + Sl.s2_cache[this].htime() // h(:mm)? (am|pm)? - h(:mm)? am|pm
  }

  String.prototype.date = function date() { return this.moment().format(Sl.date); }
  String.prototype.time = function time() { return this.moment().format(Sl.time); }
  String.prototype.datetime = function datetime() { return this.moment().format(Sl.datetime); }

  String.prototype.hdate = function() {
    var now = window.moment();
    var m = this.moment();
    var diff = m-now;
    if (Math.abs(diff) < 1000 * 3600 * 24 *60) { // less than two months away from now
      if (now.month() == m.month() && now.date() == m.date()) {
        return "Today";
      }
      if (diff > 0) {
        if (diff < 1000*3600*24) { return "Tomorrow" }
      }
      return m.format(String.lunch.hdate_no_year)
    }
    return m.format(String.lunch.hdate)
  }
  String.prototype.htime = function htime() {
    var m  = this.moment();
    return m.format('h? A').replace("?",m.minutes()?m.format(":mm"):"")
  }
  String.prototype.hdatetime = function() {
    return this.hdate() + " at " + this.htime();
  }
  String.prototype.itime = function() {
    return parseInt(this.time());
  }
  String.prototype.unixtime = function() { return this.moment()+0 }
})();
<commit_msg>fixing small_conversion_factor so it does not show for 0 values<commit_after>(function() {
  String.lunch = {
    moment_cache: {},
    s2_cache: {},

    date: "YYYYMMDD",
    time: "Hmm",
    datetime: "",

    hdate: "MMM Do, YYYY",
    hdate_no_year: "MMM Do",
    htime_hour: "H? A",
    htime_minute: ":mm",
    _seconds_math: {
      second: 1,
      minute: 60,
      hour: 60*60,
      day: 24*60*60,
      week: 7*24*60*60,
      list: ['week','day','hour','minute','second'],
    },
    clear: function() {
      delete String.lunch.moment_cache;
      delete String.lunch.s2_cache;
      String.lunch.moment_cache = {};
      String.lunch.s2_cache = {}
    },
  };

  var Sl = String.lunch;
  String.prototype.moment = function moment() {
    if (String.lunch.moment_cache[this]) { return String.lunch.moment_cache[this] }
    var s1 = this,m1,s2,m2;
    if (s1.indexOf("||") != -1) {
      [s1,s2] = s1.split("||");
    }
    if (this.match(/^\d\d?:\d\d/)) { // passing in time with no date, set date to today
      m1 = window.moment(window.moment().format("YYYY-MM-DD ") + s1);
    } else {
      var m1 = window.moment(s1.toString());
    }
    if (s2 && s2.match(/^\d\d?:\d\d/)) {
      s2 = m1.format(Strin.lunch.date)+" "+s2;
      m2 = window.moment(s2);
      if (m2 < m1) {
        m2 = m2.add(1,'days')
      }
    }
    String.lunch.moment_cache[this] = m1;
    String.lunch.s2_cache[this] = s2;
    return m1;
  }
  String.prototype.format = function(s) { return this.moment().format(s); }
  String.prototype.calendar = function calendar(s) {
    return this.moment().calendar(s);
  }
  String.prototype.range = function(format) {
    this.moment();
    return this.hdate()+ " - "+Sl.s2_cache[this].hdate();
  }
  String.prototype.htimedelta = function() {
    if (this.indexOf("||") == -1) { return (this+"||"+moment().format()).htimedelta() }
    var m = this.moment();
    var seconds = (this.moment()-Sl.s2_cache[this].moment())/1000;
    var abs = Math.abs(seconds);
    var _sm = Sl._seconds_math; // going to be typing this a lot
    var unit_big,unit_small,value = abs;
    var s=(seconds<0)?"-":"+"; // sign of timedelta
    var v="",V; // value big and small, (eg [3,2] for "3 days and 2 hours", would return "3d2h")
    var u="",U; // unit abbreviation big and small, (eg ["d","h"] for above example)
    for (var i=0;i<_sm.list.length;i++) {
      unit_big = _sm.list[i];
      if (abs >= _sm[unit_big]) { // eg. absolute value of seconds is more than 1 month|week|day... worth of seconds
        V = Math.floor(abs/_sm[unit_big]); // value/big_conversion_factor
        U = unit_big[0];
        unit_small = _sm.list[i+1];
        if (unit_small) {
          v = Math.floor((abs%_sm[unit_big])/_sm[unit_small]) || ""; // remainder/small_conversion_factor
          u = v && unit_small[0];
        }
        break;
      }
    }
    return `${s}${V}${U}${v}${u}`; // sVUvu or "+3d2h" or "sign big_value big_unit small_value small_unit", ya dig?
  }
  String.prototype.htimerange = function(format) {
    this.moment();
    var m1 = this.moment();
    var m2 = Sl.s2_cache[this].moment();
    var time1 = m1.format(m1.minute()?"h:mm":"h"); // 12 or 12:45
    if (m1.hour()>=12 != m2.hour()>=12) { time1 += m1.format(" A") } // add am/pm if am/pm changes from time1 to time2
    return time1 + " - " + Sl.s2_cache[this].htime() // h(:mm)? (am|pm)? - h(:mm)? am|pm
  }

  String.prototype.date = function date() { return this.moment().format(Sl.date); }
  String.prototype.time = function time() { return this.moment().format(Sl.time); }
  String.prototype.datetime = function datetime() { return this.moment().format(Sl.datetime); }

  String.prototype.hdate = function() {
    var now = window.moment();
    var m = this.moment();
    var diff = m-now;
    if (Math.abs(diff) < 1000 * 3600 * 24 *60) { // less than two months away from now
      if (now.month() == m.month() && now.date() == m.date()) {
        return "Today";
      }
      if (diff > 0) {
        if (diff < 1000*3600*24) { return "Tomorrow" }
      }
      return m.format(String.lunch.hdate_no_year)
    }
    return m.format(String.lunch.hdate)
  }
  String.prototype.htime = function htime() {
    var m  = this.moment();
    return m.format('h? A').replace("?",m.minutes()?m.format(":mm"):"")
  }
  String.prototype.hdatetime = function() {
    return this.hdate() + " at " + this.htime();
  }
  String.prototype.itime = function() {
    return parseInt(this.time());
  }
  String.prototype.unixtime = function() { return this.moment()+0 }
})();
<|endoftext|>


<commit_before>/**
 * Created by suparngupta on 11/16/13.
 */

/**
 * Module dependencies.
 */

var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var socket = require("socket.io");
var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
    app.use(express.errorHandler());
}

app.get('/', routes.index);
app.get('/users', user.list);

var server = require('http').createServer(app);
server.listen(3000);
var io = socket.listen(server);

io.sockets.on('connection', function (socket) {
    console.log("connection");
    socket.on('message', function(message){
        console.log(message);
        socket.send(message);

        socket.emit("contact_req", {'data': 'yahoo'});
        socket.emit('sms_req', {data: 'yahoo'});
    });

    //socket.emit('news', { hello: 'world' });
    socket.on('my other event', function (data) {
        console.log(data);
    });

    socket.on('contact_res', function(message){
        console.log(message);
        console.log("Received the contacts list");
        socket.send("Received the contacts");
    });
    socket.on('sms_res', function(message){
        console.log("Received the smses");
        console.log(message);
        socket.send('Received the smses');
    });
});<commit_msg>Changed to app1.js<commit_after>/**
 * Created by suparngupta on 11/16/13.
 */

/**
 * Module dependencies.
 */

var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var socket = require("socket.io");
var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
    app.use(express.errorHandler());
}

app.get('/', routes.index);
app.get('/users', user.list);

var server = require('http').createServer(app);
server.listen(3000);
var io = socket.listen(server);

io.sockets.on('connection', function (socket) {
    console.log("connection");
    socket.on('message', function(message){
        console.log(message);
        socket.send(message);

        socket.emit("contact_req", {'data': 'yahoo'});
        socket.emit('sms_req', {data: 'yahoo'});
        socket.emit('send_sms_req', JSON.stringify({number: '2149371110', message: "I am also!"}));
    });

    //socket.emit('news', { hello: 'world' });
    socket.on('my other event', function (data) {
        console.log(data);
    });

    socket.on('contact_res', function(message){
        console.log(message);
        console.log("Received the contacts list");
        socket.send("Received the contacts");
    });
    socket.on('sms_res', function(message){
        console.log("Received the smses");
        console.log(message);
        socket.send('Received the smses');
    });

    socket.on('send_sms_res', function(message){
        console.log("Send SMS response received");
        console.log(message);
    });
});<|endoftext|>


<commit_before><commit_msg>LanguageInput: Use consistent spacing style in code<commit_after><|endoftext|>


<commit_before>import { getBaseDestination, addVideoInDownloads, filterVideoInfoToStore } from '../storage/storage';

const youtubedl = require('youtube-dl');
const path = require('path');
const fs = require('fs');
const { remote } = require('electron');

export var init = function () { };

export var downloadVideo = function (link, onInfo, onProgress, onError, onEnd) {
  let filePath;

  const baseDestination = getBaseDestination();
  if (! fs.existsSync(baseDestination)) {
    fs.mkdirSync(baseDestination);
  }

  const video = youtubedl(
    link,
    ['--format=18'],
    { cwd: baseDestination }
  );

  let size = 0;
  video.on('info', function (info) {
    onInfo(info);

    size = info.size;

    const destination = getDestination(baseDestination, info);
    if (! fs.existsSync(destination)) {
      fs.mkdirSync(destination);
    }

    filePath = getFilePath(destination, info);
    video.pipe(fs.createWriteStream(filePath));

    addVideoInDownloads(info.id, filterVideoInfoToStore(info, filePath));
  });

  let position = 0;
  video.on('data', function (chunk) {
    position += chunk.length;

    if (size > 0) {
        onProgress((position / size * 100).toFixed(2));
    }
  });

  video.on('error', onError);
  video.on('end', () => {
    console.log('finished downloading!');
    onEnd(filePath);
  });
};

function getDestination(baseDestination, info) {
  if (info.playlist === null || info.playlist === 'NA') {
    return path.join(baseDestination, info.uploader);
  }

  return path.join(baseDestination, info.uploader, info.playlist);
}

function getFilePath(destination, info) {
  if (info.playlist_index === null || info.playlist_index === 'NA') {
    return path.join(destination, info._filename);
  }

  return path.join(destination, info.playlist_index + ' - ' + info._filename);
}
<commit_msg>Pass percentage number instead of string<commit_after>import { getBaseDestination, addVideoInDownloads, filterVideoInfoToStore } from '../storage/storage';

const youtubedl = require('youtube-dl');
const path = require('path');
const fs = require('fs');
const { remote } = require('electron');

export var init = function () { };

export var downloadVideo = function (link, onInfo, onProgress, onError, onEnd) {
  let filePath;

  const baseDestination = getBaseDestination();
  if (! fs.existsSync(baseDestination)) {
    fs.mkdirSync(baseDestination);
  }

  const video = youtubedl(
    link,
    ['--format=18'],
    { cwd: baseDestination }
  );

  let size = 0;
  video.on('info', function (info) {
    onInfo(info);

    size = info.size;

    const destination = getDestination(baseDestination, info);
    if (! fs.existsSync(destination)) {
      fs.mkdirSync(destination);
    }

    filePath = getFilePath(destination, info);
    video.pipe(fs.createWriteStream(filePath));

    addVideoInDownloads(info.id, filterVideoInfoToStore(info, filePath));
  });

  let position = 0;
  video.on('data', function (chunk) {
    position += chunk.length;

    if (size > 0) {
        onProgress((position / size) * 100);
    }
  });

  video.on('error', onError);
  video.on('end', () => {
    console.log('finished downloading!');
    onEnd(filePath);
  });
};

function getDestination(baseDestination, info) {
  if (info.playlist === null || info.playlist === 'NA') {
    return path.join(baseDestination, info.uploader);
  }

  return path.join(baseDestination, info.uploader, info.playlist);
}

function getFilePath(destination, info) {
  if (info.playlist_index === null || info.playlist_index === 'NA') {
    return path.join(destination, info._filename);
  }

  return path.join(destination, info.playlist_index + ' - ' + info._filename);
}
<|endoftext|>


<commit_before>/* *
 *
 * Создает простой способ доступа к JSON данным на сервере.
 * Реализует основные REST методы save, get, list, update, delete
 * В дополнение к этому есть:
 * findBy - поиск по одному из полей
 * filter - поиск по ряду полей
 *
 * */
var notRecord_stdObjectProps = {
    writable: false,
    enumerable: false
};

function capitalizeFirstLetter(string) {
    'use strict';
    return string.charAt(0).toUpperCase() + string.slice(1);
}

var DEFAULT_RECORD_ID_FIELD_NAME = '_id';
var DEFAULT_PAGE_NUMBER = 1;
var DEFAULT_PAGE_SIZE = 10;

var notRecord_Interface = {
    //описание методов запросов
    /*api: {
        //корневой урл, :modelName название модели
        url: '/api/:modelName',
        //что можно делать
        actions: {
            //добавление новой записи
            save: {
                //метод
                method: 'POST',
                // что будем передавать в массиве POST, тут механизм простой у notRecord должен быть метод с названием getFoo,
                // в данном случае getRecord, его результаты будут переданы в POST запросе,
                // все результаты возвращаемые такими функциями должны быть объектами,
                // если их несколько, то они будут объединены в один объект
                data: ['record']
            },
            //получать по номеру записи
            get: {
                method: 'GET',
                //то что будет, прибавленно к URL
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
                    //:record[название поля из объекта], варианты /:record[_id]/:record[name] или /:record[date]
                    //поле должно существовать
            },
            //получить массив
            list: {
                method: 'GET',
                //применяются данные для постраницной выдачи
                data: ['pager'],
                isArray: true
            },
            //поиск по паре [название поля],[значение поля]
            findBy: {
                method: 'POST',
                postFix: '/findBy',
                data: ['filter']
            },
            //более комплексный вариант, пар может быть много
            filter: {
                method: 'POST',
                postFix: '/filter',
                data: ['pager', 'filter'],
                isArray: true
            },
            //сохранение изменений
            update: {
                method: 'POST',
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
            },
            //удаление записи с сервера
            'delete': {
                method: 'DELETE',
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
            }
        }
    },
*/
    extendObject: function (obj1, obj2) {
        'use strict';
        var attrName = '';
        for (attrName in obj2) {
            if (obj2.hasOwnProperty(attrName)) {
                obj1[attrName] = obj2[attrName];
            }
        }
        return obj1;
    },

    parseLine: function (line, record, actionName) {
        'use strict';
        var i = 0,
            recordRE = /\:record\[([\dA-z_\-]+)\]/gi,
            recordFields = line.match(recordRE);
        if (recordFields && (recordFields.length > 1)) {
            for (i = 1; i < recordFields.length; i++) {
                line = line.replace(':record[' + recordFields[i] + ']', record[recordFields[i]]);
            }
        }
        line = line.replace(':modelName', record.modelName);
        line = line.replace(':actionName', actionName);
        return line;
    },

    getURL: function (record, actionData, actionName) {
        'use strict';
        var line = this.parseLine(record.interfaceManifest.url, record) + ((actionData.hasOwnProperty('postFix')) ? this.parseLine(actionData.postFix, record) : '');
        return line;
    },

    collectRequestData: function (record, actionData) {
        'use strict';
        var requestData = {},
            i = 0;
        if ((actionData.hasOwnProperty('data')) && typeof (actionData.data) !== 'undefined' && actionData.data !== null) {
            for (i = 0; i < actionData.data.length; i++) {
                var dataProviderName = 'get' + capitalizeFirstLetter(actionData.data[i]);
                if (dataProviderName in record) {
                    requestData = this.extendObject(requestData, record[dataProviderName]());
                }
            }
        }
        return requestData;
    },

    request: function (record, actionName, callback) {
        'use strict';
        console.log('request', actionName);
        var actionData = record.interfaceManifest.actions[actionName];
        $.ajax(this.getURL(record, actionData, actionName), {
            method: actionData.method,
            dataType: 'json',
            data: this.collectRequestData(record, actionData),
            success: function (data) {
                var result = [];
                if (('isArray' in actionData) && actionData.isArray) {
                    $.each(data, function (index, item) {
                        result.push(new notRecord(record.interfaceManifest, item));
                    });
                } else {
                    result = new notRecord(record.interfaceManifest, data);
                }
                callback(result);
            }
        });
    }
};

/*
 *
 */

//создаем объект с заданым манифестом интерфейса, если есть данные, то добавляем в него
var notRecord = function (interfaceManifest, item) {
    'use strict';
    this._notOptions = {
        interfaceManifest: interfaceManifest,
        filter: {},
        pageNumber: DEFAULT_PAGE_NUMBER,
        pageSize: DEFAULT_PAGE_SIZE,
        fields: []
    };
    if (typeof item !== 'undefined' && item !== null) {
        notRecord_Interface.extendObject(this, item);
        this._notOptions.fields = Object.keys(item);
    }
    var that = this;
    $.each(this._notOptions.interfaceManifest.actions, function (index, actionManifest) {
        if (!(this.hasOwnProperty('$' + index))) {
            that['$' + index] = function (callback) {
                console.log('$'+index);
                (notRecord_Interface.request.bind(notRecord_Interface, that, index+'', callback)).call();
            }
        } else {
            console.error('interface manifest for ', interfaceManifest.model, ' conflict with notRecord property "', '$' + index, '" that alredy exists');
        }
    });
    return this;
};

Object.defineProperties(notRecord.prototype, {
    'modelName': {
        get: function () {
            'use strict';
            return this._notOptions.interfaceManifest.model;
        }
    },
    'interfaceManifest': {
        get: function () {
            'use strict';
            return this._notOptions.interfaceManifest;
        }
    }
});

notRecord.prototype.setParam = function (paramName, paramValue) {
    'use strict';
    this._notOptions[paramName] = paramValue;
    return this;
}

notRecord.prototype.getParam = function (paramName) {
    'use strict';
    return this._notOptions[paramName];
}

notRecord.prototype.setAttr = function (attrName, attrValue) {
    'use strict';
    this[attrName] = attrValue;
    return this;
}

notRecord.prototype.getAttr = function (attrName) {
    'use strict';
    if (attrName in this.getParam('fields')) {
        return this[attrName];
    } else {
        return undefined;
    }
}

notRecord.prototype.setFilter = function (filterData) {
    'use strict';
    this.setParam('filter', filterData);
    return this;
};

notRecord.prototype.getFilter = function () {
    'use strict';
    return this.getParam('filter');
};

notRecord.prototype.setPageNumber = function (pageNumber) {
    'use strict';
    this.setParam('pageNumber', pageNumber);
    return this;
};

notRecord.prototype.setPageSize = function (pageSize) {
    'use strict';
    this.setParam('pageSize', pageSize);
    return this;
};

notRecord.prototype.setPager = function (pageSize, pageNumber) {
    'use strict';
    this.setParam('pageSize', pageSize).setParam('pageNumber', pageNumber);
    return this;
};

notRecord.prototype.getPager = function () {
    'use strict';
    return {
        pageSize: this.getParam('pageSize'),
        pageNumber: this.getParam('pageNumber')
    };
};

notRecord.prototype.getRecord = function () {
    'use strict';
    var result = {};
    for (var fieldName in this.getParam('fields')) {
        if (this.hasOwnProperty(fieldName)) result[fieldName] = this[fieldName];
    }
    return result;
};

notRecord.prototype.setFindBy = function (key, value) {
    'use strict';
    var obj = {};
    obj[key] = value;
    return this.setFilter(obj);
};
<commit_msg>add fields option update on adding new Attribute<commit_after>/* *
 *
 * Создает простой способ доступа к JSON данным на сервере.
 * Реализует основные REST методы save, get, list, update, delete
 * В дополнение к этому есть:
 * findBy - поиск по одному из полей
 * filter - поиск по ряду полей
 *
 * */
var notRecord_stdObjectProps = {
    writable: false,
    enumerable: false
};

function capitalizeFirstLetter(string) {
    'use strict';
    return string.charAt(0).toUpperCase() + string.slice(1);
}

var DEFAULT_RECORD_ID_FIELD_NAME = '_id';
var DEFAULT_PAGE_NUMBER = 1;
var DEFAULT_PAGE_SIZE = 10;

var notRecord_Interface = {
    //описание методов запросов
    /*api: {
        //корневой урл, :modelName название модели
        url: '/api/:modelName',
        //что можно делать
        actions: {
            //добавление новой записи
            save: {
                //метод
                method: 'POST',
                // что будем передавать в массиве POST, тут механизм простой у notRecord должен быть метод с названием getFoo,
                // в данном случае getRecord, его результаты будут переданы в POST запросе,
                // все результаты возвращаемые такими функциями должны быть объектами,
                // если их несколько, то они будут объединены в один объект
                data: ['record']
            },
            //получать по номеру записи
            get: {
                method: 'GET',
                //то что будет, прибавленно к URL
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
                    //:record[название поля из объекта], варианты /:record[_id]/:record[name] или /:record[date]
                    //поле должно существовать
            },
            //получить массив
            list: {
                method: 'GET',
                //применяются данные для постраницной выдачи
                data: ['pager'],
                isArray: true
            },
            //поиск по паре [название поля],[значение поля]
            findBy: {
                method: 'POST',
                postFix: '/findBy',
                data: ['filter']
            },
            //более комплексный вариант, пар может быть много
            filter: {
                method: 'POST',
                postFix: '/filter',
                data: ['pager', 'filter'],
                isArray: true
            },
            //сохранение изменений
            update: {
                method: 'POST',
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
            },
            //удаление записи с сервера
            'delete': {
                method: 'DELETE',
                postFix: '/:record[' + DEFAULT_RECORD_ID_FIELD_NAME + ']'
            }
        }
    },
*/
    extendObject: function (obj1, obj2) {
        'use strict';
        var attrName = '';
        for (attrName in obj2) {
            if (obj2.hasOwnProperty(attrName)) {
                obj1[attrName] = obj2[attrName];
            }
        }
        return obj1;
    },

    parseLine: function (line, record, actionName) {
        'use strict';
        var i = 0,
            recordRE = /\:record\[([\dA-z_\-]+)\]/gi,
            recordFields = line.match(recordRE);
        if (recordFields && (recordFields.length > 1)) {
            for (i = 1; i < recordFields.length; i++) {
                line = line.replace(':record[' + recordFields[i] + ']', record[recordFields[i]]);
            }
        }
        line = line.replace(':modelName', record.modelName);
        line = line.replace(':actionName', actionName);
        return line;
    },

    getURL: function (record, actionData, actionName) {
        'use strict';
        var line = this.parseLine(record.interfaceManifest.url, record) + ((actionData.hasOwnProperty('postFix')) ? this.parseLine(actionData.postFix, record) : '');
        return line;
    },

    collectRequestData: function (record, actionData) {
        'use strict';
        var requestData = {},
            i = 0;
        if ((actionData.hasOwnProperty('data')) && typeof (actionData.data) !== 'undefined' && actionData.data !== null) {
            for (i = 0; i < actionData.data.length; i++) {
                var dataProviderName = 'get' + capitalizeFirstLetter(actionData.data[i]);
                if (dataProviderName in record) {
                    requestData = this.extendObject(requestData, record[dataProviderName]());
                }
            }
        }
        return requestData;
    },

    request: function (record, actionName, callback) {
        'use strict';
        console.log('request', actionName);
        var actionData = record.interfaceManifest.actions[actionName];
        $.ajax(this.getURL(record, actionData, actionName), {
            method: actionData.method,
            dataType: 'json',
            data: this.collectRequestData(record, actionData),
            success: function (data) {
                var result = [];
                if (('isArray' in actionData) && actionData.isArray) {
                    $.each(data, function (index, item) {
                        result.push(new notRecord(record.interfaceManifest, item));
                    });
                } else {
                    result = new notRecord(record.interfaceManifest, data);
                }
                callback(result);
            }
        });
    }
};

/*
 *
 */

//создаем объект с заданым манифестом интерфейса, если есть данные, то добавляем в него
var notRecord = function (interfaceManifest, item) {
    'use strict';
    this._notOptions = {
        interfaceManifest: interfaceManifest,
        filter: {},
        pageNumber: DEFAULT_PAGE_NUMBER,
        pageSize: DEFAULT_PAGE_SIZE,
        fields: []
    };
    if (typeof item !== 'undefined' && item !== null) {
        notRecord_Interface.extendObject(this, item);
        this._notOptions.fields = Object.keys(item);
    }
    var that = this;
    $.each(this._notOptions.interfaceManifest.actions, function (index, actionManifest) {
        if (!(this.hasOwnProperty('$' + index))) {
            that['$' + index] = function (callback) {
                console.log('$'+index);
                (notRecord_Interface.request.bind(notRecord_Interface, that, index+'', callback)).call();
            }
        } else {
            console.error('interface manifest for ', interfaceManifest.model, ' conflict with notRecord property "', '$' + index, '" that alredy exists');
        }
    });
    return this;
};

Object.defineProperties(notRecord.prototype, {
    'modelName': {
        get: function () {
            'use strict';
            return this._notOptions.interfaceManifest.model;
        }
    },
    'interfaceManifest': {
        get: function () {
            'use strict';
            return this._notOptions.interfaceManifest;
        }
    }
});

notRecord.prototype.setParam = function (paramName, paramValue) {
    'use strict';
    this._notOptions[paramName] = paramValue;
    return this;
}

notRecord.prototype.getParam = function (paramName) {
    'use strict';
    return this._notOptions[paramName];
}

notRecord.prototype.setAttr = function (attrName, attrValue) {
    'use strict';
    var fields = this.getParam('fields');
    if (!(attrName in fields)) {
        fields.push(attrName);
        this.setParam('fields', fields);
    }
    this[attrName] = attrValue;
    return this;
}

notRecord.prototype.getAttr = function (attrName) {
    'use strict';
    if (attrName in this.getParam('fields')) {
        return this[attrName];
    } else {
        return undefined;
    }
}

notRecord.prototype.setFilter = function (filterData) {
    'use strict';
    this.setParam('filter', filterData);
    return this;
};

notRecord.prototype.getFilter = function () {
    'use strict';
    return this.getParam('filter');
};

notRecord.prototype.setPageNumber = function (pageNumber) {
    'use strict';
    this.setParam('pageNumber', pageNumber);
    return this;
};

notRecord.prototype.setPageSize = function (pageSize) {
    'use strict';
    this.setParam('pageSize', pageSize);
    return this;
};

notRecord.prototype.setPager = function (pageSize, pageNumber) {
    'use strict';
    this.setParam('pageSize', pageSize).setParam('pageNumber', pageNumber);
    return this;
};

notRecord.prototype.getPager = function () {
    'use strict';
    return {
        pageSize: this.getParam('pageSize'),
        pageNumber: this.getParam('pageNumber')
    };
};

notRecord.prototype.getRecord = function () {
    'use strict';
    var result = {};
    for (var fieldName in this.getParam('fields')) {
        if (this.hasOwnProperty(fieldName)) result[fieldName] = this[fieldName];
    }
    return result;
};

notRecord.prototype.setFindBy = function (key, value) {
    'use strict';
    var obj = {};
    obj[key] = value;
    return this.setFilter(obj);
};
<|endoftext|>