<commit_before>/*
 * TreeAPI.js
 *
 * Provide a "Person" object where data is gathered from the WikiTree API.
 * We use the WikiTree API action "getPerson" to retrieve the profile data and then store it in object fields.
 *
 */

// Put our functions into a "WikiTreeAPI" namespace.
window.WikiTreeAPI = window.WikiTreeAPI || {};

// Our basic constructor for a Person. We expect the "person" data from the API returned result
// (see getPerson below). The basic fields are just stored in the internal _data array.
// We pull out the Parent and Child elements as their own Person objects.
WikiTreeAPI.Person = class Person {
	constructor(data) {
		this._data = data;

		if(data.Parents){
			for(var p in data.Parents){
				this._data.Parents[p] = new WikiTreeAPI.Person(data.Parents[p]);
			}
		}
		if(data.Children){
			for(var c in data.Children){
				this._data.Children[c] = new WikiTreeAPI.Person(data.Children[c]);
			}
		}
	}

	// Basic "getters" for the data elements.
	getId() { return this._data.Id; }
	getName() { return this._data.Name; }
	getGender() { return this._data.Gender; }
	getBirthDate() { return this._data.BirthDate; }
	getBirthLocation() { return this._data.BirthLocation; }
	getDeathDate() { return this._data.DeathDate; }
	getDeathLocation() { return this._data.DeathLocation; }
	getChildren() { return this._data.Children; }
	getFatherId() { return this._data.Father; }
	getMotherId() { return this._data.Mother; }
	getDisplayName() { return this._data.BirthName ? this._data.BirthName : this._data.BirthNamePrivate; }
	getPhotoUrl() {
		if (this._data.PhotoData && this._data.PhotoData['url']) {
			return this._data.PhotoData['url'];
		}
	}

// Getters for Mother and Father return the Person objects, if there is one.
// The getMotherId and getFatherId functions above return the actual .Mother and .Father data elements (ids).
	getMother() {
		if (this._data.Mother && this._data.Parents) {
			return this._data.Parents[this._data.Mother];
		}
	}
	getFather() {
		if (this._data.Father && this._data.Parents) {
			return this._data.Parents[this._data.Father];
		}
	}

	// We use a few "setters". For the parents, we want to update the Parents Person objects as well as the ids themselves.
	// For TreeViewer we only set the parents and children, so we don't need setters for all the _data elements.
	setMother(person) {
		var id = person.getId();
		var oldId = this._data.Mother;
		this._data.Mother = id;
		if (!this._data.Parents) { this._data.Parents = {}; }
		else if (oldId) { delete this._data.Parents[oldId]; }
		this._data.Parents[id] = person;
	}
	setFather(person) {
		var id = person.getId();
		var oldId = this._data.Father;
		this._data.Father = id;
		if (!this._data.Parents) { this._data.Parents = {}; }
		else if (oldId) { delete this._data.Parents[oldId]; }
		this._data.Parents[id] = person;
	}
	setChildren(children) { this._data.Children = children; }

} // End Person class definition

// To get a Person for a given id, we POST to the APIs getPerson action. When we get a result back,
// we convert the returned JSON data into a Person object.
// Note that postToAPI returns the Promise from jquerys .ajax() call.
// That feeds our .then() here, which also returns a Promise, which gets resolved by the return inside the "then" function.
// So we can use this through our asynchronous actions with something like:
// WikiTree.getPerson.then(function(result) {
//    // the "result" here is that from our API call. The profile data is in result[0].person.
// });
//
WikiTreeAPI.getPerson = function(id,fields) {
	return WikiTreeAPI.postToAPI( { 'action': 'getPerson', 'key': id, 'fields': fields.join(','), 'resolveRedirect': 1 } )
		.then(function(result) {
			return new WikiTreeAPI.Person(result[0].person);
		});
}

// This is just a wrapper for the Ajax call, sending along necessary options for the WikiTree API.
WikiTreeAPI.postToAPI = function (postData) {
	var API_URL = 'https://api.wikitree.com/api.php';

	var ajax = $.ajax({
		// The WikiTree API endpoint
		'url': API_URL,

		// We tell the browser to send any cookie credentials we might have (in case we authenticated).
		'xhrFields': { withCredentials: true },

		// We're POSTing the data, so we don't worry about URL size limits and want JSON back.
		type: 'POST',
		dataType: 'json',
		data: postData
	});

	return ajax;
}

// Utility function to get/set cookie data.
// Adapted from https://github.com/carhartl/jquery-cookie which is obsolete and has been
// superseded by https://github.com/js-cookie/js-cookie. The latter is a much more complete cookie utility.
// Here we just want to get and set some simple values in limited circumstances to track an API login.
// So we'll use a stripped-down function here and eliminate a prerequisite. This function should not be used
// in complex circumstances.
//
// key     = The name of the cookie to set/read. If reading and no key, then array of all key/value pairs is returned.
// value   = The value to set the cookie to. If undefined, the value is instead returned. If null, cookie is deleted.
// options = Used when setting the cookie,
//           options.expires = Date or number of days in the future (converted to Date for cookie)
//           options.path, e.g. "/"
//           options.domain, e.g. "apps.wikitree.com"
//           options.secure, if true then cookie created with ";secure"
WikiTreeAPI.cookie = function(key, value, options) {
	if (options === undefined) { options = {}; }

	// If we have a value, we're writing/setting the cookie.
	if (value !== undefined) {
		if (value === null) { options.expires = -1; }
		if (typeof options.expires === 'number') {
			var days = options.expires;
			options.expires = new Date();
			options.expires.setDate(options.expires.getDate() + days);
		}
		value = String(value);
		return (document.cookie = [
			encodeURIComponent(key), '=', value,
			options.expires ? '; expires=' + options.expires.toUTCString() : '',
			options.path    ? '; path=' + options.path : '',
			options.domain  ? '; domain=' + options.domain : '',
			options.secure  ? '; secure' : ''
		].join(''));
	}

	// We're not writing/setting the cookie, we're reading a value from it.
	var cookies = document.cookie.split('; ');

	var result = key ? null : {};
	for (var i=0,l=cookies.length; i<l; i++) {
		var parts = cookies[i].split('=');
		var name = parts.shift();
		name = decodeURIComponent(name.replace(/\+/g, ' '));
		var value = parts.join('=');
		value = decodeURIComponent(value.replace(/\+/g, ' '));

		if (key && key === name) {
			result = value;
			break;
		}
		if (!key) {
			result[name] = value;
		}

	}
	return result;
}
<commit_msg>Update TreeAPI.js<commit_after>/*
 * TreeAPI.js
 *
 * Provide a "Person" object where data is gathered from the WikiTree API.
 * We use the WikiTree API action "getPerson" to retrieve the profile data and then store it in object fields.
 *
 */

// Put our functions into a "WikiTreeAPI" namespace.
window.WikiTreeAPI = window.WikiTreeAPI || {};

// Our basic constructor for a Person. We expect the "person" data from the API returned result
// (see getPerson below). The basic fields are just stored in the internal _data array.
// We pull out the Parent and Child elements as their own Person objects.
WikiTreeAPI.Person = class Person {
	constructor(data) {
		this._data = data;

		if(data.Parents){
			for(var p in data.Parents){
				this._data.Parents[p] = new WikiTreeAPI.Person(data.Parents[p]);
			}
		}
		if(data.Children){
			for(var c in data.Children){
				this._data.Children[c] = new WikiTreeAPI.Person(data.Children[c]);
			}
		}
	}

	// Basic "getters" for the data elements.
	getId() { return this._data.Id; }
	getName() { return this._data.Name; }
	getGender() { return this._data.Gender; }
	getBirthDate() { return this._data.BirthDate; }
	getBirthLocation() { return this._data.BirthLocation; }
	getDeathDate() { return this._data.DeathDate; }
	getDeathLocation() { return this._data.DeathLocation; }
	getChildren() { return this._data.Children; }
	getFatherId() { return this._data.Father; }
	getMotherId() { return this._data.Mother; }
	getDisplayName() { return this._data.BirthName ? this._data.BirthName : this._data.BirthNamePrivate; }
	getPhotoUrl() {
		if (this._data.PhotoData && this._data.PhotoData['url']) {
			return this._data.PhotoData['url'];
		}
	}

// Getters for Mother and Father return the Person objects, if there is one.
// The getMotherId and getFatherId functions above return the actual .Mother and .Father data elements (ids).
	getMother() {
		if (this._data.Mother && this._data.Parents) {
			return this._data.Parents[this._data.Mother];
		}
	}
	getFather() {
		if (this._data.Father && this._data.Parents) {
			return this._data.Parents[this._data.Father];
		}
	}

	// We use a few "setters". For the parents, we want to update the Parents Person objects as well as the ids themselves.
	// For TreeViewer we only set the parents and children, so we don't need setters for all the _data elements.
	setMother(person) {
		var id = person.getId();
		var oldId = this._data.Mother;
		this._data.Mother = id;
		if (!this._data.Parents) { this._data.Parents = {}; }
		else if (oldId) { delete this._data.Parents[oldId]; }
		this._data.Parents[id] = person;
	}
	setFather(person) {
		var id = person.getId();
		var oldId = this._data.Father;
		this._data.Father = id;
		if (!this._data.Parents) { this._data.Parents = {}; }
		else if (oldId) { delete this._data.Parents[oldId]; }
		this._data.Parents[id] = person;
	}
	setChildren(children) { this._data.Children = children; }

} // End Person class definition

// To get a Person for a given id, we POST to the API's getPerson action. When we get a result back,
// we convert the returned JSON data into a Person object.
// Note that postToAPI returns the Promise from jquerys .ajax() call.
// That feeds our .then() here, which also returns a Promise, which gets resolved by the return inside the "then" function.
// So we can use this through our asynchronous actions with something like:
// WikiTree.getPerson.then(function(result) {
//    // the "result" here is that from our API call. The profile data is in result[0].person.
// });
//
WikiTreeAPI.getPerson = function(id,fields) {
	return WikiTreeAPI.postToAPI( { 'action': 'getPerson', 'key': id, 'fields': fields.join(','), 'resolveRedirect': 1 } )
		.then(function(result) {
			return new WikiTreeAPI.Person(result[0].person);
		});
}

// This is just a wrapper for the Ajax call, sending along necessary options for the WikiTree API.
WikiTreeAPI.postToAPI = function (postData) {
	var API_URL = 'https://api.wikitree.com/api.php';

	var ajax = $.ajax({
		// The WikiTree API endpoint
		'url': API_URL,

		// We tell the browser to send any cookie credentials we might have (in case we authenticated).
		'xhrFields': { withCredentials: true },

		// We're POSTing the data, so we don't worry about URL size limits and want JSON back.
		type: 'POST',
		dataType: 'json',
		data: postData
	});

	return ajax;
}

// Utility function to get/set cookie data.
// Adapted from https://github.com/carhartl/jquery-cookie which is obsolete and has been
// superseded by https://github.com/js-cookie/js-cookie. The latter is a much more complete cookie utility.
// Here we just want to get and set some simple values in limited circumstances to track an API login.
// So we'll use a stripped-down function here and eliminate a prerequisite. This function should not be used
// in complex circumstances.
//
// key     = The name of the cookie to set/read. If reading and no key, then array of all key/value pairs is returned.
// value   = The value to set the cookie to. If undefined, the value is instead returned. If null, cookie is deleted.
// options = Used when setting the cookie,
//           options.expires = Date or number of days in the future (converted to Date for cookie)
//           options.path, e.g. "/"
//           options.domain, e.g. "apps.wikitree.com"
//           options.secure, if true then cookie created with ";secure"
WikiTreeAPI.cookie = function(key, value, options) {
	if (options === undefined) { options = {}; }

	// If we have a value, we're writing/setting the cookie.
	if (value !== undefined) {
		if (value === null) { options.expires = -1; }
		if (typeof options.expires === 'number') {
			var days = options.expires;
			options.expires = new Date();
			options.expires.setDate(options.expires.getDate() + days);
		}
		value = String(value);
		return (document.cookie = [
			encodeURIComponent(key), '=', value,
			options.expires ? '; expires=' + options.expires.toUTCString() : '',
			options.path    ? '; path=' + options.path : '',
			options.domain  ? '; domain=' + options.domain : '',
			options.secure  ? '; secure' : ''
		].join(''));
	}

	// We're not writing/setting the cookie, we're reading a value from it.
	var cookies = document.cookie.split('; ');

	var result = key ? null : {};
	for (var i=0,l=cookies.length; i<l; i++) {
		var parts = cookies[i].split('=');
		var name = parts.shift();
		name = decodeURIComponent(name.replace(/\+/g, ' '));
		var value = parts.join('=');
		value = decodeURIComponent(value.replace(/\+/g, ' '));

		if (key && key === name) {
			result = value;
			break;
		}
		if (!key) {
			result[name] = value;
		}

	}
	return result;
}
<|endoftext|>


<commit_before>'use strict';

// Dependencies
// ---
var _ = require('lodash');
var Bluebird = require('bluebird');
var Backbone = require('backbone');
var request = require('request');
var debug = require('./debug');
var BootieError = require('./error');

module.exports = Backbone.Model.extend({
  urlRoot: '',

  /**
   * If there's an error, try your damndest to find it.
   * APIs hide errors in all sorts of places these days
   *
   * @param {String|Object} body
   * @return {String}
   */

  _extractError: function(body) {
    if (_.isString(body)) {
      return body;
    } else if (_.isObject(body) && _.isString(body.error)) {
      return body.error;
    } else if (_.isObject(body) && _.isString(body.msg)) {
      return body.msg;
    } else if (_.isObject(body) && _.isObject(body.error)) {
      return this._extractError(body.error);
    } else if (_.isObject(body) && _.isString(body.message)) {
      return body.message;
    } else if (_.isObject(body) &&
      body.meta &&
      _.isString(body.meta.error_message)) {
      return body.meta.error_message;
    } else {
      return 'Unknown Request Error';
    }
  },

  /**
   * Build and configure the request options
   *
   * @param {Object} options
   * @param {String} options.url
   * @param {String} [options.path=]
   * @param {String} [options.method=GET]
   * @param {String} [options.qs={}]
   * @param {String} [options.headers={}]
   * @param {String} options.json
   * @param {String} options.form
   * @param {String} options.body
   * @param {String} options.access_token
   * @param {String} options.oauth_token
   * @param {String} options.authorization_token
   * @param {String} options.auth
   * @return {Object}
   */

  _buildRequestOptions: function(options) {
    options = options || {};

    // Set default path
    if (!options.url && !options.path) {
      options.path = '';
    }

    // Prepare the request
    var requestOptions = {
      method: options.method || 'GET',
      url: options.url || this.urlRoot + options.path,
      qs: options.qs || {},
      headers: options.headers || {},
    };

    // Add `form`, `body`, or `json` as Request Payload (only one per request)
    //
    // If `json` is a Boolean,
    // Request will set` Content-Type`
    // and call `JSON.stringify()` on `body`
    if (options.body) {
      requestOptions.body = options.body;
      requestOptions.json = _.isBoolean(options.json) ? options.json : true;
    } else if (options.form) {
      requestOptions.form = options.form;
      requestOptions.headers['Content-Type'] =
        'application/x-www-form-urlencoded; charset=utf-8';
    } else if (_.isBoolean(options.json) || _.isObject(options.json)) {
      requestOptions.json = options.json;
    }

    // Basic HTTP Auth
    if (options.auth) {
      requestOptions.auth = options.auth;
    }

    // Access Token
    var accessToken = options.access_token || this.get('access_token');
    if (accessToken) {
      _.defaults(requestOptions.headers, {
        Authorization: ['Bearer', accessToken].join(' ')
      });
    }

    // OAuth Token
    var oauthToken = options.oauth_token || this.get('oauth_token');
    if (oauthToken) {
      _.defaults(requestOptions.headers, {
        Authorization: ['OAuth', oauthToken].join(' ')
      });
    }

    // Authorization Token (No Scheme)
    var authorizationToken = options.authorization_token || this.get('authorization_token');
    if (authorizationToken) {
      _.defaults(requestOptions.headers, {
        Authorization: authorizationToken
      });
    }
    return requestOptions;
  },

  /**
   * Send an HTTP Request with provided request options
   *
   * @param {Object}   options
   * @param {Function} callback
   * @return {Promise}
   */

  sendRequest: function(options, callback) {
    // Create a promise to defer to later
    var deferred = Bluebird.defer();
    var requestOptions = this._buildRequestOptions(options);

    // Fire the request
    request(this._buildRequestOptions(options), function(err, response, body) {
      // Handle Errors
      if (err) {
        // Usually a connection error (server unresponsive)
        err = new BootieError(err.message || 'Internal Server Error', err.code || 500);
      } else if (response.statusCode >= 400) {
        // Usually an intentional error from the server
        err = new BootieError(this._extractError(body), response.statusCode);
      }
      if (err) {
        debug.error(
          'Adapter Request Error with Code: %d and Message: %s',
          err.code,
          err.message
        );
        callback && callback(err);
        return deferred.reject(err);
      }

      // Handle Success
      debug.log(
        'Adapter Request Sent with code: %d and body: %s',
        response.statusCode,
        body
      );
      callback && callback(null, body);
      return deferred.resolve(body);
    }.bind(this));

    return deferred.promise;
  }
});
<commit_msg>remove unnecessary line<commit_after>'use strict';

// Dependencies
// ---
var _ = require('lodash');
var Bluebird = require('bluebird');
var Backbone = require('backbone');
var request = require('request');
var debug = require('./debug');
var BootieError = require('./error');

module.exports = Backbone.Model.extend({
  urlRoot: '',

  /**
   * If there's an error, try your damndest to find it.
   * APIs hide errors in all sorts of places these days
   *
   * @param {String|Object} body
   * @return {String}
   */

  _extractError: function(body) {
    if (_.isString(body)) {
      return body;
    } else if (_.isObject(body) && _.isString(body.error)) {
      return body.error;
    } else if (_.isObject(body) && _.isString(body.msg)) {
      return body.msg;
    } else if (_.isObject(body) && _.isObject(body.error)) {
      return this._extractError(body.error);
    } else if (_.isObject(body) && _.isString(body.message)) {
      return body.message;
    } else if (_.isObject(body) &&
      body.meta &&
      _.isString(body.meta.error_message)) {
      return body.meta.error_message;
    } else {
      return 'Unknown Request Error';
    }
  },

  /**
   * Build and configure the request options
   *
   * @param {Object} options
   * @param {String} options.url
   * @param {String} [options.path=]
   * @param {String} [options.method=GET]
   * @param {String} [options.qs={}]
   * @param {String} [options.headers={}]
   * @param {String} options.json
   * @param {String} options.form
   * @param {String} options.body
   * @param {String} options.access_token
   * @param {String} options.oauth_token
   * @param {String} options.authorization_token
   * @param {String} options.auth
   * @return {Object}
   */

  _buildRequestOptions: function(options) {
    options = options || {};

    // Set default path
    if (!options.url && !options.path) {
      options.path = '';
    }

    // Prepare the request
    var requestOptions = {
      method: options.method || 'GET',
      url: options.url || this.urlRoot + options.path,
      qs: options.qs || {},
      headers: options.headers || {},
    };

    // Add `form`, `body`, or `json` as Request Payload (only one per request)
    //
    // If `json` is a Boolean,
    // Request will set` Content-Type`
    // and call `JSON.stringify()` on `body`
    if (options.body) {
      requestOptions.body = options.body;
      requestOptions.json = _.isBoolean(options.json) ? options.json : true;
    } else if (options.form) {
      requestOptions.form = options.form;
      requestOptions.headers['Content-Type'] =
        'application/x-www-form-urlencoded; charset=utf-8';
    } else if (_.isBoolean(options.json) || _.isObject(options.json)) {
      requestOptions.json = options.json;
    }

    // Basic HTTP Auth
    if (options.auth) {
      requestOptions.auth = options.auth;
    }

    // Access Token
    var accessToken = options.access_token || this.get('access_token');
    if (accessToken) {
      _.defaults(requestOptions.headers, {
        Authorization: ['Bearer', accessToken].join(' ')
      });
    }

    // OAuth Token
    var oauthToken = options.oauth_token || this.get('oauth_token');
    if (oauthToken) {
      _.defaults(requestOptions.headers, {
        Authorization: ['OAuth', oauthToken].join(' ')
      });
    }

    // Authorization Token (No Scheme)
    var authorizationToken = options.authorization_token || this.get('authorization_token');
    if (authorizationToken) {
      _.defaults(requestOptions.headers, {
        Authorization: authorizationToken
      });
    }
    return requestOptions;
  },

  /**
   * Send an HTTP Request with provided request options
   *
   * @param {Object}   options
   * @param {Function} callback
   * @return {Promise}
   */

  sendRequest: function(options, callback) {
    // Create a promise to defer to later
    var deferred = Bluebird.defer();

    // Fire the request
    request(this._buildRequestOptions(options), function(err, response, body) {
      // Handle Errors
      if (err) {
        // Usually a connection error (server unresponsive)
        err = new BootieError(err.message || 'Internal Server Error', err.code || 500);
      } else if (response.statusCode >= 400) {
        // Usually an intentional error from the server
        err = new BootieError(this._extractError(body), response.statusCode);
      }
      if (err) {
        debug.error(
          'Adapter Request Error with Code: %d and Message: %s',
          err.code,
          err.message
        );
        callback && callback(err);
        return deferred.reject(err);
      }

      // Handle Success
      debug.log(
        'Adapter Request Sent with code: %d and body: %s',
        response.statusCode,
        body
      );
      callback && callback(null, body);
      return deferred.resolve(body);
    }.bind(this));

    return deferred.promise;
  }
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 Nils Schneider
 * Distributed under the MIT/X11 software license, see the accompanying
 * file license.txt or http://www.opensource.org/licenses/mit-license.php.
 */

/* settings:
 * {
 *  generateConfirm: 120
 * }
 */
function TXList(list, app, settings) {
	this.sortTX = function(a, b) {
		if(a.time != b.time)
			return (a.time - b.time);

		if(a.category != b.category)
			return (b.category < a.category) ? -1 : 1;

		return (b.amount - a.amount);
	}

	this.clear = function() {
		list.children().remove();
	}

	this.processRPC = function(transactions, error) {
		if (error)
			return;

		var start = new Date().getTime();

		var transactions = jQuery.grep(transactions,
				function(n, i) {
					return n.account == app.bitcoin.settings.account;
				});

		transactions.sort(this.sortTX);

		list.children('#txlistempty').remove();

		if (transactions.length == 0)
			list.append('
no transactions
');

		for (var key in transactions)
			this.processTX(transactions[key]);

		list.children('tr:not(.txinfo):odd').addClass('odd').next('.txinfo').addClass('odd');
		list.children('tr:not(.txinfo):even').removeClass('odd').next('.txinfo').removeClass('odd');

		/* adjust refresh interval of app depending processing time of txlist */
		var end = new Date().getTime();
		var time = end - start;
		app.setRefreshInterval(time * 10);
	}

	this.processTX = function(tx) {
		if (tx.time == undefined)
			tx.time = 0;

		if (tx.txid == undefined)
			tx.txid = (tx.time + tx.amount + tx.otheraccount).replace(/ /g,'');

		tx.txid += tx.category;

		var txrow = $(document.getElementById(tx.txid));

		if (txrow.length == 0) {
			txrow = $('

');
			list.prepend(txrow);
			var txdiv = $('

');
			txrow.after(txdiv);

			txrow.click( function() {
					var div = $(this).next('tr.txinfo').children('td').children('div');
					if (app.useSlide) div.slideToggle('fast');
					else div.toggle();
				});
		}

		var checksum = tx.txid + tx.confirmations + tx.time;

		/* Only update TX if it differs from current one */
		if(txrow.attr('checksum') != checksum) {
			txrow.attr('checksum', checksum);
			txrow.html(this.renderRow(tx));

			txrow.next('tr.txinfo').children('td').children('div').html(this.renderInfo(tx));

			if (tx.confirmations == 0 || (tx.category == "generate" && tx.confirmations < settings.generateConfirm))
				txrow.addClass("unconfirmed");
			else
				txrow.removeClass("unconfirmed");
		}
	}

	this.renderInfo = function(tx) {
		var html = "";
		var extra = "";

		switch (tx.category) {
			case "generate":
				html += "Generated coins
";
				break;
			case "move":
				html += "Moved " + (tx.amount<0?"to":"from") + ": " + tx.otheraccount.prettyAccount() + "
";
				break;
			case "send":
				if (tx.to)
					extra = " (" + tx.to + ")";
				html += "Sent to: " + tx.address + extra + "
";
				break;
			case "receive":
				if (tx.from)
					extra = " (" + tx.from + ")";
				html += "Received on: " + tx.address + extra + "
";
				break;
			default:
				html += "Category: " + tx.category + "
";
		}

		if(tx.confirmations != undefined) html += "Confirmations: " + tx.confirmations + "
";
		if(tx.fee != undefined) html += "Fee: " + tx.fee.formatBTC() + "
";
		if(tx.comment != "" && tx.comment != undefined) html += "Comment: " + tx.comment + "
";

		return html;
	}

	this.renderRow = function(tx) {
		var confirmations = tx.confirmations<10?tx.confirmations:'✓';

		if (tx.category == "generate")
			confirmations = tx.confirmations<settings.generateConfirm?'&#x2717':'&#x2713';

		var timestamp = new Date();
		timestamp.setTime (tx.time * 1000);

		var info = tx.category.capitalize();

		if (tx.category == 'send')
			if (tx.to)
				info = tx.to;
			else
				info = tx.address;

		if (tx.category == 'receive')
			if (tx.from)
				info = tx.from;
			else
				info = tx.address;

		if (tx.comment)
			info += " (" + tx.comment + ")";

		if (tx.category == 'move')
			info = (tx.amount<0?"to ":"from ") + tx.otheraccount.prettyAccount();

		var amountClass = (tx.amount<0?'debit':'credit');

		var html = '' + confirmations + '	';
		html += '' + timestamp.format(app.dateFormat) + '	';
		html += '' + info + '	';
		html += '' + tx.amount.formatBTC(true) + '	';

		return html;
	}

	this.refresh = function() {
		app.bitcoin.listTransactions(jQuery.proxy(this, 'processRPC'));
	}
}
<commit_msg>log TXlist rebuild time<commit_after>/*
 * Copyright (c) 2010 Nils Schneider
 * Distributed under the MIT/X11 software license, see the accompanying
 * file license.txt or http://www.opensource.org/licenses/mit-license.php.
 */

/* settings:
 * {
 *  generateConfirm: 120
 * }
 */
function TXList(list, app, settings) {
	this.sortTX = function(a, b) {
		if(a.time != b.time)
			return (a.time - b.time);

		if(a.category != b.category)
			return (b.category < a.category) ? -1 : 1;

		return (b.amount - a.amount);
	}

	this.clear = function() {
		list.children().remove();
	}

	this.processRPC = function(transactions, error) {
		if (error)
			return;

		var start = new Date().getTime();

		var transactions = jQuery.grep(transactions,
				function(n, i) {
					return n.account == app.bitcoin.settings.account;
				});

		transactions.sort(this.sortTX);

		list.children('#txlistempty').remove();

		if (transactions.length == 0)
			list.append('
no transactions
');

		for (var key in transactions)
			this.processTX(transactions[key]);

		list.children('tr:not(.txinfo):odd').addClass('odd').next('.txinfo').addClass('odd');
		list.children('tr:not(.txinfo):even').removeClass('odd').next('.txinfo').removeClass('odd');

		/* adjust refresh interval of app depending processing time of txlist */
		var end = new Date().getTime();
		var time = end - start;
		app.setRefreshInterval(time * 10);
		console.log("TX rebuild took " + time + " ms");
	}

	this.processTX = function(tx) {
		if (tx.time == undefined)
			tx.time = 0;

		if (tx.txid == undefined)
			tx.txid = (tx.time + tx.amount + tx.otheraccount).replace(/ /g,'');

		tx.txid += tx.category;

		var txrow = $(document.getElementById(tx.txid));

		if (txrow.length == 0) {
			txrow = $('

');
			list.prepend(txrow);
			var txdiv = $('

');
			txrow.after(txdiv);

			txrow.click( function() {
					var div = $(this).next('tr.txinfo').children('td').children('div');
					if (app.useSlide) div.slideToggle('fast');
					else div.toggle();
				});
		}

		var checksum = tx.txid + tx.confirmations + tx.time;

		/* Only update TX if it differs from current one */
		if(txrow.attr('checksum') != checksum) {
			txrow.attr('checksum', checksum);
			txrow.html(this.renderRow(tx));

			txrow.next('tr.txinfo').children('td').children('div').html(this.renderInfo(tx));

			if (tx.confirmations == 0 || (tx.category == "generate" && tx.confirmations < settings.generateConfirm))
				txrow.addClass("unconfirmed");
			else
				txrow.removeClass("unconfirmed");
		}
	}

	this.renderInfo = function(tx) {
		var html = "";
		var extra = "";

		switch (tx.category) {
			case "generate":
				html += "Generated coins
";
				break;
			case "move":
				html += "Moved " + (tx.amount<0?"to":"from") + ": " + tx.otheraccount.prettyAccount() + "
";
				break;
			case "send":
				if (tx.to)
					extra = " (" + tx.to + ")";
				html += "Sent to: " + tx.address + extra + "
";
				break;
			case "receive":
				if (tx.from)
					extra = " (" + tx.from + ")";
				html += "Received on: " + tx.address + extra + "
";
				break;
			default:
				html += "Category: " + tx.category + "
";
		}

		if(tx.confirmations != undefined) html += "Confirmations: " + tx.confirmations + "
";
		if(tx.fee != undefined) html += "Fee: " + tx.fee.formatBTC() + "
";
		if(tx.comment != "" && tx.comment != undefined) html += "Comment: " + tx.comment + "
";

		return html;
	}

	this.renderRow = function(tx) {
		var confirmations = tx.confirmations<10?tx.confirmations:'✓';

		if (tx.category == "generate")
			confirmations = tx.confirmations<settings.generateConfirm?'&#x2717':'&#x2713';

		var timestamp = new Date();
		timestamp.setTime (tx.time * 1000);

		var info = tx.category.capitalize();

		if (tx.category == 'send')
			if (tx.to)
				info = tx.to;
			else
				info = tx.address;

		if (tx.category == 'receive')
			if (tx.from)
				info = tx.from;
			else
				info = tx.address;

		if (tx.comment)
			info += " (" + tx.comment + ")";

		if (tx.category == 'move')
			info = (tx.amount<0?"to ":"from ") + tx.otheraccount.prettyAccount();

		var amountClass = (tx.amount<0?'debit':'credit');

		var html = '' + confirmations + '	';
		html += '' + timestamp.format(app.dateFormat) + '	';
		html += '' + info + '	';
		html += '' + tx.amount.formatBTC(true) + '	';

		return html;
	}

	this.refresh = function() {
		app.bitcoin.listTransactions(jQuery.proxy(this, 'processRPC'));
	}
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { themeGet } from 'styled-system'
import { Box, Flex } from 'rebass'
import { Card, Heading } from 'components/UI'
import AutopayAddButton from './AutopayAddButton'
import AutopayLimitBadge from './AutopayLimitBadge'

const CardWithBg = styled(Card)`
  position: relative;
  background-image: url(${props => props.src});
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  height: 300px;
  width: 195px;
  border-radius: 40px;
  padding: 0;
  cursor: pointer;
`

const Overlay = styled(Flex)`
  position: absolute;
  height: 100%;
  width: 100%;
  pointer-events: none;
`

const GradientOverlay = styled(Card)`
  position: absolute;
  background-image: linear-gradient(
    146deg,
    ${themeGet('colors.tertiaryColor')},
    ${themeGet('colors.primaryColor')}
  );
  opacity: 0.5;
  width: 100%;
  height: 100%;
  border-radius: 40px;
  transition: all 0.25s;
  &:hover {
    opacity: 0;
  }
`

const TextOverlay = styled(Overlay)`
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
`

const AutopayCardView = ({
  merchant: { image, nickname, pubkey, isActive, limit, limitCurrency },
  onClick,
  ...rest
}) => (
  <Box {...rest} onClick={() => onClick(`${pubkey}`)}>
    <CardWithBg mb="12px" src={image}>
      <GradientOverlay />
      <TextOverlay alignItems="center" flexDirection="column" justifyContent="center" p={3}>
        <Heading.h1 fontWeight="normal" textAlign="center">
          {nickname}
        </Heading.h1>
      </TextOverlay>
      <Overlay alignItems="flex-end" justifyContent="center" mt={isActive ? -15 : 12}>
        {isActive ? (
          <AutopayLimitBadge limit={limit} limitCurrency={limitCurrency} />
        ) : (
          <AutopayAddButton />
        )}
      </Overlay>
    </CardWithBg>
  </Box>
)

AutopayCardView.propTypes = {
  merchant: PropTypes.shape({
    description: PropTypes.string.isRequired,
    image: PropTypes.string.isRequired,
    nickname: PropTypes.string.isRequired,
    pubkey: PropTypes.string.isRequired,
  }),
  onClick: PropTypes.func.isRequired,
}

export default React.memo(AutopayCardView)
<commit_msg>refactor: add missing prop types<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { themeGet } from 'styled-system'
import { Box, Flex } from 'rebass'
import { Card, Heading } from 'components/UI'
import AutopayAddButton from './AutopayAddButton'
import AutopayLimitBadge from './AutopayLimitBadge'

const CardWithBg = styled(Card)`
  position: relative;
  background-image: url(${props => props.src});
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  height: 300px;
  width: 195px;
  border-radius: 40px;
  padding: 0;
  cursor: pointer;
`

const Overlay = styled(Flex)`
  position: absolute;
  height: 100%;
  width: 100%;
  pointer-events: none;
`

const GradientOverlay = styled(Card)`
  position: absolute;
  background-image: linear-gradient(
    146deg,
    ${themeGet('colors.tertiaryColor')},
    ${themeGet('colors.primaryColor')}
  );
  opacity: 0.5;
  width: 100%;
  height: 100%;
  border-radius: 40px;
  transition: all 0.25s;
  &:hover {
    opacity: 0;
  }
`

const TextOverlay = styled(Overlay)`
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
`

const AutopayCardView = ({
  merchant: { image, nickname, pubkey, isActive, limit, limitCurrency },
  onClick,
  ...rest
}) => (
  <Box {...rest} onClick={() => onClick(`${pubkey}`)}>
    <CardWithBg mb="12px" src={image}>
      <GradientOverlay />
      <TextOverlay alignItems="center" flexDirection="column" justifyContent="center" p={3}>
        <Heading.h1 fontWeight="normal" textAlign="center">
          {nickname}
        </Heading.h1>
      </TextOverlay>
      <Overlay alignItems="flex-end" justifyContent="center" mt={isActive ? -15 : 12}>
        {isActive ? (
          <AutopayLimitBadge limit={limit} limitCurrency={limitCurrency} />
        ) : (
          <AutopayAddButton />
        )}
      </Overlay>
    </CardWithBg>
  </Box>
)

AutopayCardView.propTypes = {
  merchant: PropTypes.shape({
    description: PropTypes.string.isRequired,
    image: PropTypes.string.isRequired,
    isActive: PropTypes.bool,
    limit: PropTypes.string.isRequired,
    limitCurrency: PropTypes.string.isRequired,
    nickname: PropTypes.string.isRequired,
    pubkey: PropTypes.string.isRequired,
  }),
  onClick: PropTypes.func.isRequired,
}

export default React.memo(AutopayCardView)
<|endoftext|>


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

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/system",
    "firebug/chrome/module",
],
function(Firebug, FBTrace, Obj, Dom, String, System, Module) {

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

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_STATUSPATH");

var statusCropSize = 20;

// ********************************************************************************************* //
// StatusPath

/**
 * @object The object is responsible for 'Status path' maintenance (aka breadcrumbs) that
 * is used to display path to the selected element in the {@HTMLPanel}, path to the
 * selected object in the {@DOMPanel} and call-stack in the {@ScriptPanel}.
 *
 * The path is displayed in panel-toolbar and the logic is based on {@Panel.getObjectPath}
 * method, so any panel can support it.
 *
 * The path can be updated through clear and update methods. A {@Panel} instance can specify
 * whether the update should be synchronous or asynchronous through: 'objectPathAsyncUpdate'
 * member.
 */
var StatusPath =
/** @lends StatusPath */
{
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Public API

    clear: function()
    {
        this.clearFlag = true;
        this.executor();
    },

    update: function()
    {
        this.updateFlag = true;
        this.executor();
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Private API

    executor: function()
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        var panel = panelBar1.selectedPanel;
        if (!panel)
            return;

        if (this.timeout)
            clearTimeout(this.timeout);

        // Asynchronous update is not necessary for every panel,
        // so it's up to the current panel what to do.
        var asyncUpdate = panel.objectPathAsyncUpdate;

        // Synchronous update is always used when panels are switched.
        if (panel.name != panelStatus.lastPanelName)
            asyncUpdate = false;

        Trace.sysout("statusPath.executor; asyncUpdate: " + asyncUpdate + ", " +
            panelStatus.lastPanelName + " -> " + panel.name);

        if (asyncUpdate)
            this.timeout = setTimeout(this.flush.bind(this), 100);
        else
            this.flush();
    },

    flush: function()
    {
        this.timeout = null;

        if (this.clearFlag)
            this.doClear();

        if (this.updateFlag)
            this.doUpdate();

        this.clearFlag = false;
        this.updateFlag = false;
    },

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

    doClear: function()
    {
        Trace.sysout("statusPath.clear;");

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        panelStatus.clear();
    },

    doUpdate: function()
    {
        Trace.sysout("statusPath.update;");

        var context = Firebug.currentContext;

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        var panelStatusSeparator = Firebug.chrome.getElementById("fbStatusSeparator");
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;

        if (!panel || (panel && !panel.selection))
        {
            panelStatus.clear();
        }
        else
        {
            var path = panel.getObjectPath(panel.selection);
            if (!path || !path.length)
            {
                Dom.hide(panelStatusSeparator, true);
                panelStatus.clear();
            }
            else
            {
                // Update the visibility of the separator. The separator
                // is displayed only if there are some other buttons on the left side.
                // Before showing the status separator let's see whether there are any other
                // buttons on the left.
                var hide = true;
                var sibling = panelStatusSeparator.parentNode.previousSibling;
                while (sibling)
                {
                    if (!Dom.isCollapsed(sibling))
                    {
                        hide = false;
                        break;
                    }

                    sibling = sibling.previousSibling;
                }

                Dom.hide(panelStatusSeparator, hide);

                if (panel.name != panelStatus.lastPanelName)
                    panelStatus.clear();

                // If the object already exists in the list, just select it and keep the path.
                var selection = panel.selection;
                var existingItem = panelStatus.getItemByObject(panel.selection);
                if (existingItem)
                {
                    // Update the labels of the status path elements, because it can be,
                    // that the elements changed even when the selected element exists
                    // inside the path (issue 4826)
                    var statusItems = panelStatus.getItems();
                    for (var i = 0; i < statusItems.length; ++i)
                    {
                        var object = Firebug.getRepObject(statusItems[i]);
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        statusItems[i].label = title;
                    }

                    panelStatus.selectItem(existingItem);
                }
                else
                {
                    panelStatus.clear();

                    for (var i = 0; i < path.length; i++)
                    {
                        var object = path[i];
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        panelStatus.addItem(title, object, rep, panel.statusSeparator);
                    }

                    panelStatus.selectObject(panel.selection);

                    Trace.sysout("statusPath.update " + path.length + " items ", path);
                }
            }
        }

        panelStatus.lastPanelName = panel.name;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Arrow Navigation

    getNextObject: function(reverse)
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;
        if (panel)
        {
            var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
            var item = panelStatus.getItemByObject(panel.selection);
            if (item)
            {
                if (reverse)
                    item = item.previousSibling ? item.previousSibling.previousSibling : null;
                else
                    item = item.nextSibling ? item.nextSibling.nextSibling : null;

                if (item)
                    return item.repObject;
            }
        }
    },

    gotoNextObject: function(reverse)
    {
        var nextObject = this.getNextObject(reverse);
        if (nextObject)
            Firebug.chrome.select(nextObject);
        else
            System.beep();
    },
};

// ********************************************************************************************* //
// StatusPath Module

/**
 * @module Responsible for handling 'omitObjectPathStack' option used in the {@CallstackPanel}
 * Options menu.
 */
var StatusPathModule = Obj.extend(Module,
/** @lends StatusPathModule */
{
    dispatchName: "StatusPathModule",

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

    updateOption: function()
    {
        if (name == "omitObjectPathStack")
            this.obeyOmitObjectPathStack(value);
    },

    obeyOmitObjectPathStack: function(value)
    {
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        // The element does not exist immediately at start-up.
        if (!panelStatus)
            return;

        Dom.hide(panelStatus, (value ? true : false));
    },
});

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

Firebug.registerModule(StatusPathModule);

// xxxHonza: exposed for XUL (see firebugMenuOverlay.xul)
Firebug.StatusPath = StatusPath;

return StatusPath;

// ********************************************************************************************* //
});
<commit_msg>The current panel can be disabled (issue 7019)<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/system",
    "firebug/chrome/module",
],
function(Firebug, FBTrace, Obj, Dom, String, System, Module) {

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

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_STATUSPATH");

var statusCropSize = 20;

// ********************************************************************************************* //
// StatusPath

/**
 * @object The object is responsible for 'Status path' maintenance (aka breadcrumbs) that
 * is used to display path to the selected element in the {@HTMLPanel}, path to the
 * selected object in the {@DOMPanel} and call-stack in the {@ScriptPanel}.
 *
 * The path is displayed in panel-toolbar and the logic is based on {@Panel.getObjectPath}
 * method, so any panel can support it.
 *
 * The path can be updated through clear and update methods. A {@Panel} instance can specify
 * whether the update should be synchronous or asynchronous through: 'objectPathAsyncUpdate'
 * member.
 */
var StatusPath =
/** @lends StatusPath */
{
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Public API

    clear: function()
    {
        this.clearFlag = true;
        this.executor();
    },

    update: function()
    {
        this.updateFlag = true;
        this.executor();
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Private API

    executor: function()
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        var panel = panelBar1.selectedPanel;
        if (!panel)
            return;

        if (this.timeout)
            clearTimeout(this.timeout);

        // Asynchronous update is not necessary for every panel,
        // so it's up to the current panel what to do.
        var asyncUpdate = panel.objectPathAsyncUpdate;

        // Synchronous update is always used when panels are switched.
        if (panel.name != panelStatus.lastPanelName)
            asyncUpdate = false;

        Trace.sysout("statusPath.executor; asyncUpdate: " + asyncUpdate + ", " +
            panelStatus.lastPanelName + " -> " + panel.name);

        if (asyncUpdate)
            this.timeout = setTimeout(this.flush.bind(this), 100);
        else
            this.flush();
    },

    flush: function()
    {
        this.timeout = null;

        if (this.clearFlag)
            this.doClear();

        if (this.updateFlag)
            this.doUpdate();

        this.clearFlag = false;
        this.updateFlag = false;
    },

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

    doClear: function()
    {
        Trace.sysout("statusPath.clear;");

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        panelStatus.clear();
    },

    doUpdate: function()
    {
        Trace.sysout("statusPath.update;");

        var context = Firebug.currentContext;

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        var panelStatusSeparator = Firebug.chrome.getElementById("fbStatusSeparator");
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;

        if (!panel || (panel && !panel.selection))
        {
            panelStatus.clear();
        }
        else
        {
            var path = panel.getObjectPath(panel.selection);
            if (!path || !path.length)
            {
                Dom.hide(panelStatusSeparator, true);
                panelStatus.clear();
            }
            else
            {
                // Update the visibility of the separator. The separator
                // is displayed only if there are some other buttons on the left side.
                // Before showing the status separator let's see whether there are any other
                // buttons on the left.
                var hide = true;
                var sibling = panelStatusSeparator.parentNode.previousSibling;
                while (sibling)
                {
                    if (!Dom.isCollapsed(sibling))
                    {
                        hide = false;
                        break;
                    }

                    sibling = sibling.previousSibling;
                }

                Dom.hide(panelStatusSeparator, hide);

                if (panel.name != panelStatus.lastPanelName)
                    panelStatus.clear();

                // If the object already exists in the list, just select it and keep the path.
                var selection = panel.selection;
                var existingItem = panelStatus.getItemByObject(panel.selection);
                if (existingItem)
                {
                    // Update the labels of the status path elements, because it can be,
                    // that the elements changed even when the selected element exists
                    // inside the path (issue 4826)
                    var statusItems = panelStatus.getItems();
                    for (var i = 0; i < statusItems.length; ++i)
                    {
                        var object = Firebug.getRepObject(statusItems[i]);
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        statusItems[i].label = title;
                    }

                    panelStatus.selectItem(existingItem);
                }
                else
                {
                    panelStatus.clear();

                    for (var i = 0; i < path.length; i++)
                    {
                        var object = path[i];
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        panelStatus.addItem(title, object, rep, panel.statusSeparator);
                    }

                    panelStatus.selectObject(panel.selection);

                    Trace.sysout("statusPath.update " + path.length + " items ", path);
                }
            }
        }

        // If the current panel is disabled there is no panel instance.
        panelStatus.lastPanelName = panel ? panel.name : "";
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Arrow Navigation

    getNextObject: function(reverse)
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;
        if (panel)
        {
            var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
            var item = panelStatus.getItemByObject(panel.selection);
            if (item)
            {
                if (reverse)
                    item = item.previousSibling ? item.previousSibling.previousSibling : null;
                else
                    item = item.nextSibling ? item.nextSibling.nextSibling : null;

                if (item)
                    return item.repObject;
            }
        }
    },

    gotoNextObject: function(reverse)
    {
        var nextObject = this.getNextObject(reverse);
        if (nextObject)
            Firebug.chrome.select(nextObject);
        else
            System.beep();
    },
};

// ********************************************************************************************* //
// StatusPath Module

/**
 * @module Responsible for handling 'omitObjectPathStack' option used in the {@CallstackPanel}
 * Options menu.
 */
var StatusPathModule = Obj.extend(Module,
/** @lends StatusPathModule */
{
    dispatchName: "StatusPathModule",

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

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

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        panelStatus.lastPanelName = "";
    },

    updateOption: function()
    {
        if (name == "omitObjectPathStack")
            this.obeyOmitObjectPathStack(value);
    },

    obeyOmitObjectPathStack: function(value)
    {
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        // The element does not exist immediately at start-up.
        if (!panelStatus)
            return;

        Dom.hide(panelStatus, (value ? true : false));
    },
});

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

Firebug.registerModule(StatusPathModule);

// xxxHonza: exposed for XUL (see firebugMenuOverlay.xul)
Firebug.StatusPath = StatusPath;

return StatusPath;

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


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

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/system",
    "firebug/chrome/module",
],
function(Firebug, FBTrace, Obj, Dom, String, System, Module) {

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

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_STATUSPATH");

var statusCropSize = 20;

// ********************************************************************************************* //
// StatusPath

/**
 * @object The object is responsible for 'Status path' maintenance (aka breadcrumbs) that
 * is used to display path to the selected element in the {@HTMLPanel}, path to the
 * selected object in the {@DOMPanel} and call-stack in the {@ScriptPanel}.
 *
 * The path is displayed in panel-toolbar and the logic is based on {@Panel.getObjectPath}
 * method, so any panel can support it.
 *
 * The path is updated asynchronously (to avoid flickering) through: clear and update methods.
 */
var StatusPath =
{
    clear: function()
    {
        this.clearFlag = true;
        this.flushAsync();
    },

    update: function()
    {
        this.updateFlag = true;
        this.flushAsync();
    },

    flushAsync: function()
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        var panel = panelBar1.selectedPanel;
        if (!panel)
            return;

        if (this.timeout)
            clearTimeout(this.timeout);

        // If different panel has been selected perform synchronous update, so the
        // user can see the new value immediately. Asynchronous update is mainly useful
        // when stepping in the debugger.
        if (panel.name != panelStatus.lastPanelName)
        {
            Trace.sysout("statusPath.setTimeout; changing panels, sync update " +
                panelStatus.lastPanelName + " -> " + panel.name);

            this.flush();
            return;
        }

        this.timeout = setTimeout(this.flush.bind(this), 100);
    },

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

    flush: function()
    {
        this.timeout = null;

        if (this.clearFlag)
            this.doClear();

        if (this.updateFlag)
            this.doUpdate();

        this.clearFlag = false;
        this.updateFlag = false;
    },

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

    doClear: function()
    {
        Trace.sysout("statusPath.clear;");

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        panelStatus.clear();
    },

    doUpdate: function()
    {
        Trace.sysout("statusPath.update;");

        var context = Firebug.currentContext;

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        var panelStatusSeparator = Firebug.chrome.getElementById("fbStatusSeparator");
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;

        if (!panel || (panel && !panel.selection))
        {
            panelStatus.clear();
        }
        else
        {
            var path = panel.getObjectPath(panel.selection);
            if (!path || !path.length)
            {
                Dom.hide(panelStatusSeparator, true);
                panelStatus.clear();
            }
            else
            {
                // Update the visibility of the separator. The separator
                // is displayed only if there are some other buttons on the left side.
                // Before showing the status separator let's see whether there are any other
                // buttons on the left.
                var hide = true;
                var sibling = panelStatusSeparator.parentNode.previousSibling;
                while (sibling)
                {
                    if (!Dom.isCollapsed(sibling))
                    {
                        hide = false;
                        break;
                    }

                    sibling = sibling.previousSibling;
                }

                Dom.hide(panelStatusSeparator, hide);

                if (panel.name != panelStatus.lastPanelName)
                    panelStatus.clear();

                panelStatus.lastPanelName = panel.name;

                // If the object already exists in the list, just select it and keep the path.
                var selection = panel.selection;
                var existingItem = panelStatus.getItemByObject(panel.selection);
                if (existingItem)
                {
                    // Update the labels of the status path elements, because it can be,
                    // that the elements changed even when the selected element exists
                    // inside the path (issue 4826)
                    var statusItems = panelStatus.getItems();
                    for (var i = 0; i < statusItems.length; ++i)
                    {
                        var object = Firebug.getRepObject(statusItems[i]);
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        statusItems[i].label = title;
                    }

                    panelStatus.selectItem(existingItem);
                }
                else
                {
                    panelStatus.clear();

                    for (var i = 0; i < path.length; i++)
                    {
                        var object = path[i];
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        panelStatus.addItem(title, object, rep, panel.statusSeparator);
                    }

                    panelStatus.selectObject(panel.selection);

                    Trace.sysout("statusPath.update " + path.length + " items ", path);
                }
            }
        }
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Arrow Navigation

    getNextObject: function(reverse)
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;
        if (panel)
        {
            var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
            var item = panelStatus.getItemByObject(panel.selection);
            if (item)
            {
                if (reverse)
                    item = item.previousSibling ? item.previousSibling.previousSibling : null;
                else
                    item = item.nextSibling ? item.nextSibling.nextSibling : null;

                if (item)
                    return item.repObject;
            }
        }
    },

    gotoNextObject: function(reverse)
    {
        var nextObject = this.getNextObject(reverse);
        if (nextObject)
            Firebug.chrome.select(nextObject);
        else
            System.beep();
    },
};

// ********************************************************************************************* //
// StatusPath Module

/**
 * @module Responsible for handling 'omitObjectPathStack' option used in the {@CallstackPanel}
 * Options menu.
 */
var StatusPathModule = Obj.extend(Module,
/** @lends StatusPathModule */
{
    dispatchName: "StatusPathModule",

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

    updateOption: function()
    {
        if (name == "omitObjectPathStack")
            this.obeyOmitObjectPathStack(value);
    },

    obeyOmitObjectPathStack: function(value)
    {
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        // The element does not exist immediately at start-up.
        if (!panelStatus)
            return;

        Dom.hide(panelStatus, (value ? true : false));
    },
});

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

Firebug.registerModule(StatusPathModule);

// xxxHonza: exposed for XUL (see firebugMenuOverlay.xul)
Firebug.StatusPath = StatusPath;

return StatusPath;

// ********************************************************************************************* //
});
<commit_msg>Use async update only for the Script panel (issue 7019)<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/object",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/system",
    "firebug/chrome/module",
],
function(Firebug, FBTrace, Obj, Dom, String, System, Module) {

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

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_STATUSPATH");

var statusCropSize = 20;

// ********************************************************************************************* //
// StatusPath

/**
 * @object The object is responsible for 'Status path' maintenance (aka breadcrumbs) that
 * is used to display path to the selected element in the {@HTMLPanel}, path to the
 * selected object in the {@DOMPanel} and call-stack in the {@ScriptPanel}.
 *
 * The path is displayed in panel-toolbar and the logic is based on {@Panel.getObjectPath}
 * method, so any panel can support it.
 *
 * The path can be updated through clear and update methods.
 */
var StatusPath =
{
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Public API

    clear: function()
    {
        this.clearFlag = true;
        this.executor();
    },

    update: function()
    {
        this.updateFlag = true;
        this.executor();
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Private API

    executor: function()
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        var panel = panelBar1.selectedPanel;
        if (!panel)
            return;

        if (this.timeout)
            clearTimeout(this.timeout);

        Trace.sysout("statusPath.executor; current panel: " + panel.name);

        // Asynchronous update of the UI is mainly useful when the user is stepping
        // in the debugger, it avoids flickering. So, do it only if the Script panel
        // is actually selected. Note that the script panel is using the status path
        // to display the current JS call-stack (when the debugger is active).
        if (panel.name == "script")
            this.timeout = setTimeout(this.flush.bind(this), 100);
        else
            this.flush();
    },

    flush: function()
    {
        this.timeout = null;

        if (this.clearFlag)
            this.doClear();

        if (this.updateFlag)
            this.doUpdate();

        this.clearFlag = false;
        this.updateFlag = false;
    },

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

    doClear: function()
    {
        Trace.sysout("statusPath.clear;");

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        panelStatus.clear();
    },

    doUpdate: function()
    {
        Trace.sysout("statusPath.update;");

        var context = Firebug.currentContext;

        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
        var panelStatusSeparator = Firebug.chrome.getElementById("fbStatusSeparator");
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;

        if (!panel || (panel && !panel.selection))
        {
            panelStatus.clear();
        }
        else
        {
            var path = panel.getObjectPath(panel.selection);
            if (!path || !path.length)
            {
                Dom.hide(panelStatusSeparator, true);
                panelStatus.clear();
            }
            else
            {
                // Update the visibility of the separator. The separator
                // is displayed only if there are some other buttons on the left side.
                // Before showing the status separator let's see whether there are any other
                // buttons on the left.
                var hide = true;
                var sibling = panelStatusSeparator.parentNode.previousSibling;
                while (sibling)
                {
                    if (!Dom.isCollapsed(sibling))
                    {
                        hide = false;
                        break;
                    }

                    sibling = sibling.previousSibling;
                }

                Dom.hide(panelStatusSeparator, hide);

                if (panel.name != panelStatus.lastPanelName)
                    panelStatus.clear();

                // If the object already exists in the list, just select it and keep the path.
                var selection = panel.selection;
                var existingItem = panelStatus.getItemByObject(panel.selection);
                if (existingItem)
                {
                    // Update the labels of the status path elements, because it can be,
                    // that the elements changed even when the selected element exists
                    // inside the path (issue 4826)
                    var statusItems = panelStatus.getItems();
                    for (var i = 0; i < statusItems.length; ++i)
                    {
                        var object = Firebug.getRepObject(statusItems[i]);
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        statusItems[i].label = title;
                    }

                    panelStatus.selectItem(existingItem);
                }
                else
                {
                    panelStatus.clear();

                    for (var i = 0; i < path.length; i++)
                    {
                        var object = path[i];
                        var rep = Firebug.getRep(object, context);
                        var objectTitle = rep.getTitle(object, context);
                        var title = String.cropMultipleLines(objectTitle, statusCropSize);

                        panelStatus.addItem(title, object, rep, panel.statusSeparator);
                    }

                    panelStatus.selectObject(panel.selection);

                    Trace.sysout("statusPath.update " + path.length + " items ", path);
                }
            }
        }

        panelStatus.lastPanelName = panel.name;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Arrow Navigation

    getNextObject: function(reverse)
    {
        var panelBar1 = Firebug.chrome.getElementById("fbPanelBar1");
        var panel = panelBar1.selectedPanel;
        if (panel)
        {
            var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");
            var item = panelStatus.getItemByObject(panel.selection);
            if (item)
            {
                if (reverse)
                    item = item.previousSibling ? item.previousSibling.previousSibling : null;
                else
                    item = item.nextSibling ? item.nextSibling.nextSibling : null;

                if (item)
                    return item.repObject;
            }
        }
    },

    gotoNextObject: function(reverse)
    {
        var nextObject = this.getNextObject(reverse);
        if (nextObject)
            Firebug.chrome.select(nextObject);
        else
            System.beep();
    },
};

// ********************************************************************************************* //
// StatusPath Module

/**
 * @module Responsible for handling 'omitObjectPathStack' option used in the {@CallstackPanel}
 * Options menu.
 */
var StatusPathModule = Obj.extend(Module,
/** @lends StatusPathModule */
{
    dispatchName: "StatusPathModule",

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

    updateOption: function()
    {
        if (name == "omitObjectPathStack")
            this.obeyOmitObjectPathStack(value);
    },

    obeyOmitObjectPathStack: function(value)
    {
        var panelStatus = Firebug.chrome.getElementById("fbPanelStatus");

        // The element does not exist immediately at start-up.
        if (!panelStatus)
            return;

        Dom.hide(panelStatus, (value ? true : false));
    },
});

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

Firebug.registerModule(StatusPathModule);

// xxxHonza: exposed for XUL (see firebugMenuOverlay.xul)
Firebug.StatusPath = StatusPath;

return StatusPath;

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


<commit_before>'use strict';

var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');

var $ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});

gulp.task('partials', function () {
  return gulp.src([
    path.join(conf.paths.src, '/app/**/*.html'),
    path.join(conf.paths.tmp, '/serve/app/**/*.html')
  ])
    .pipe($.htmlmin({
      removeEmptyAttributes: true,
      removeAttributeQuotes: true,
      collapseBooleanAttributes: true,
      collapseWhitespace: true
    }))
    .pipe($.angularTemplatecache('templateCacheHtml.js', {
      module: 'static',
      root: 'app'
    }))
    .pipe(gulp.dest(conf.paths.tmp + '/partials/'));
});

gulp.task('html', ['inject', 'partials'], function () {
  var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false });
  var partialsInjectOptions = {
    starttag: '<!-- inject:partials -->',
    ignorePath: path.join(conf.paths.tmp, '/partials'),
    addRootSlash: false
  };

  var htmlFilter = $.filter('*.html', { restore: true });
  var jsFilter = $.filter('**/*.js', { restore: true });
  var cssFilter = $.filter('**/*.css', { restore: true });

  return gulp.src(path.join(conf.paths.tmp, '/serve/*.html'))
    .pipe($.inject(partialsInjectFile, partialsInjectOptions))
    .pipe($.useref())
    .pipe(jsFilter)
    .pipe($.sourcemaps.init())
    .pipe($.ngAnnotate())
    .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify'))
    .pipe($.rev())
    .pipe($.sourcemaps.write('maps'))
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    // .pipe($.sourcemaps.init())
    .pipe($.cssnano())
    .pipe($.rev())
    // .pipe($.sourcemaps.write('maps'))
    .pipe(cssFilter.restore)
    .pipe($.revReplace())
    .pipe(htmlFilter)
    .pipe($.htmlmin({
      removeEmptyAttributes: true,
      removeAttributeQuotes: true,
      collapseBooleanAttributes: true,
      collapseWhitespace: true
    }))
    .pipe(htmlFilter.restore)
    .pipe(gulp.dest(path.join(conf.paths.dist, '/')))
    .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
  });

// Only applies for fonts from bower dependencies
// Custom fonts are handled by the "other" task
gulp.task('fonts', function () {
  return gulp.src($.mainBowerFiles())
    .pipe($.filter('**/*.{eot,otf,svg,ttf,woff,woff2}'))
    .pipe($.flatten())
    .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/')));
});

gulp.task('other', function () {
  var fileFilter = $.filter(function (file) {
    return file.stat.isFile();
  });

  return gulp.src([
    path.join(conf.paths.src, '/**/*'),
    path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}')
  ])
    .pipe(fileFilter)
    .pipe(gulp.dest(path.join(conf.paths.dist, '/')));
});

gulp.task('clean', function () {
  return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]);
});

gulp.task('build', ['html', 'fonts', 'other']);
<commit_msg>Turn off gulp-angular's asset revisioning<commit_after>'use strict';

var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');

var $ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});

gulp.task('partials', function () {
  return gulp.src([
    path.join(conf.paths.src, '/app/**/*.html'),
    path.join(conf.paths.tmp, '/serve/app/**/*.html')
  ])
    .pipe($.htmlmin({
      removeEmptyAttributes: true,
      removeAttributeQuotes: true,
      collapseBooleanAttributes: true,
      collapseWhitespace: true
    }))
    .pipe($.angularTemplatecache('templateCacheHtml.js', {
      module: 'static',
      root: 'app'
    }))
    .pipe(gulp.dest(conf.paths.tmp + '/partials/'));
});

gulp.task('html', ['inject', 'partials'], function () {
  var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false });
  var partialsInjectOptions = {
    starttag: '<!-- inject:partials -->',
    ignorePath: path.join(conf.paths.tmp, '/partials'),
    addRootSlash: false
  };

  var htmlFilter = $.filter('*.html', { restore: true });
  var jsFilter = $.filter('**/*.js', { restore: true });
  var cssFilter = $.filter('**/*.css', { restore: true });

  return gulp.src(path.join(conf.paths.tmp, '/serve/*.html'))
    .pipe($.inject(partialsInjectFile, partialsInjectOptions))
    .pipe($.useref())
    .pipe(jsFilter)
    .pipe($.sourcemaps.init())
    .pipe($.ngAnnotate())
    .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify'))
    // .pipe($.rev())
    .pipe($.sourcemaps.write('maps'))
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    // .pipe($.sourcemaps.init())
    .pipe($.cssnano())
    // .pipe($.rev())
    // .pipe($.sourcemaps.write('maps'))
    .pipe(cssFilter.restore)
    // .pipe($.revReplace())
    .pipe(htmlFilter)
    .pipe($.htmlmin({
      removeEmptyAttributes: true,
      removeAttributeQuotes: true,
      collapseBooleanAttributes: true,
      collapseWhitespace: true
    }))
    .pipe(htmlFilter.restore)
    .pipe(gulp.dest(path.join(conf.paths.dist, '/')))
    .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
  });

// Only applies for fonts from bower dependencies
// Custom fonts are handled by the "other" task
gulp.task('fonts', function () {
  return gulp.src($.mainBowerFiles())
    .pipe($.filter('**/*.{eot,otf,svg,ttf,woff,woff2}'))
    .pipe($.flatten())
    .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/')));
});

gulp.task('other', function () {
  var fileFilter = $.filter(function (file) {
    return file.stat.isFile();
  });

  return gulp.src([
    path.join(conf.paths.src, '/**/*'),
    path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}')
  ])
    .pipe(fileFilter)
    .pipe(gulp.dest(path.join(conf.paths.dist, '/')));
});

gulp.task('clean', function () {
  return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]);
});

gulp.task('build', ['html', 'fonts', 'other']);
<|endoftext|>


<commit_before>const readline = require('readline');
const fs = require('fs');
const path = require('path');

const rl = readline.createInterface({
  input: process.stdin,
  output: fs.createWriteStream('/dev/null')
});

rl.on('line', (cmd) => {
  main(cmd)
});

function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
function createLogger (type, willKill, language, id) {
  return function (info) {
    if (info instanceof Buffer) {
      info = info.toString('utf8')
    } else if (String(info) !== info) {
      info = JSON.stringify(info, null, 4);
    }
    console.log(JSON.stringify({
      type: type,
      text: info,
      language: language,
      id: id
    }))
    if (willKill) {
      process.exit(-1);
    }
  }
}
var con = global.con = {
  stdout: createLogger('stdout'),
  stderr: createLogger('stderr'),
  log: createLogger('log'),
  error: createLogger('error'),
  status: createLogger('status'),
  throw: createLogger('throw', true),
  exit: createLogger('exit'),
  createNamedLogger: function (language, id) {
    language = language || 'unknown'
    id = id || guidGenerator()
    return {
      stdout: createLogger('stdout', false, language, id),
      stderr: createLogger('stderr', false, language, id),
      log: createLogger('log', false, language, id),
      error: createLogger('error', false, language, id),
      status: createLogger('status', false, language, id),
      throw: createLogger('throw', true, language, id),
      exit: createLogger('exit', false, language, id),
    }
  }
}

function main (input) {
  // console.log(input.toString('utf8'));

  var parsedCommnad = JSON.parse(input);

  if (parsedCommnad.encoding) {
    switch (parsedCommnad.encoding) {
      case 'base64':
        input.program = new Buffer(input.program, 'base64');
        break;
      default:
        // throw new Error('bad encoding', parsedCommnad.encoding)
        con.throw('bad encoding', parsedCommnad.encoding)
    }
  }

  var myConsole = con.createNamedLogger(parsedCommnad.type);

  var folder = path.resolve(process.env.HOME, 'runner-' + Date.now())
  fs.mkdirSync(folder);
  // myConsole.log(parsedCommnad);
  try {
    var runner = require('./runner/' + parsedCommnad.type)
  } catch (e) {
    return myConsole.error('cannot find runner for ' + parsedCommnad.type + ', aborted.')
  }
  myConsole.status('setting up')
  runner.setup(folder, parsedCommnad.program, function (file_path) {
    // myConsole.log('setup finished');
    myConsole.status('executing')
    runner.execute(file_path, function (child) {
      myConsole.log('starting process with file ' + file_path);
      child.stdout.on('data', myConsole.stdout);
      child.stderr.on('data', myConsole.stderr);
      child.on('exit', function (code, sig) {
        myConsole.status('exited')
        myConsole.exit({code: code, signal: sig});
        myConsole.log('child exit with code ' + code + ' and signal ' + sig)
        // process.exit();
      })
    }, myConsole)
  }, myConsole)
}<commit_msg>update executer<commit_after>const readline = require('readline');
const fs = require('fs');
const path = require('path');
const child_process = require("child_process");
const EventEmitter = require("events").EventEmitter;

const rl = readline.createInterface({
  input: process.stdin,
  output: fs.createWriteStream('/dev/null')
});

rl.on('line', (cmd) => {
  main(cmd)
});

function trim(str) {
  return str.replace(/^[\s\r\n]+|[\s\r\n]+$/g, '');
}

function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}

function createLogger(emitter, type, willKill, language, id) {
  return function (info) {
    if (info instanceof Buffer) {
      info = info.toString('utf8');
    } else if (info instanceof Error) {
      info = info.stack;
    } else if (String(info) !== info) {
      info = JSON.stringify(info);
    }

    var response = {
      type: type,
      text: info,
      language: language,
      id: id
    }

    emitter.emit(type, response);
    console.log(JSON.stringify(response));

    if (willKill) {
      process.exit(-1);
    }
  }
}

function RunnerInfo() {
  this.stdins = [];
  this.signals = [];
  this.process = null;
  this.console = null;
}

var con = global.con = new EventEmitter();
con.on('error', function nuzz() {});

con.stdout = createLogger(con, 'stdout')
con.stderr = createLogger(con, 'stderr')
con.log = createLogger(con, 'log')
con.error = createLogger(con, 'error')
con.throw = createLogger(con, 'throw')
con.status = createLogger(con, 'status')
con.exit = createLogger(con, 'exit')
con.createNamedLogger = function (language, id) {
  language = language || 'unknown';

  if (id == null) {
    id = guidGenerator();
  }

  var logger = new EventEmitter();
  logger.on('error', function nuzz() {});

  logger.stdout = createLogger(logger, 'stdout', false, language, id);
  logger.stderr = createLogger(logger, 'stderr', false, language, id);
  logger.log = createLogger(logger, 'log', false, language, id);
  logger.error = createLogger(logger, 'error', false, language, id);
  logger.throw = createLogger(logger, 'throw', false, language, id);
  logger.status = createLogger(logger, 'status', false, language, id);
  logger.exit = createLogger(logger, 'exit', false, language, id);

  return logger;
}

var runnerInfos = new Map();

function main (input) {
  // console.log(input.toString('utf8'));
  try {
    var parsedCommnad = JSON.parse(input);
  } catch (err) {
    con.error('bad encoding: ' + err.stack)
  }

  if (parsedCommnad.id == null) {
    parsedCommnad.id = guidGenerator();
  }

  var myConsole = runnerInfos.get(parsedCommnad.id) ?
    runnerInfos.get(parsedCommnad.id).console :
    con.createNamedLogger(parsedCommnad.type, parsedCommnad.id);

  if (parsedCommnad.encoding) {
    switch (parsedCommnad.encoding) {
      case 'base64':
        try {
          if (parsedCommnad.program) {
            parsedCommnad.program = new Buffer(parsedCommnad.program, 'base64');
          }

          if (parsedCommnad.stdin) {
            parsedCommnad.stdin = new Buffer(parsedCommnad.program, 'base64');
          }
        } catch (err) {
          return myConsole.throw('corruoted base 64 string: ' + err.stack);
        }
        break;
      default:
        // throw new Error('bad encoding', parsedCommnad.encoding)
        return myConsole.throw('bad encoding: ' + parsedCommnad.encoding)
    }
  }

  if (!parsedCommnad.action || parsedCommnad.action === 'spawn') {
    return spawn(parsedCommnad, myConsole)
  }

  if (parsedCommnad.action === 'write') {
    return write(parsedCommnad, myConsole)
  }

  if (parsedCommnad.action === 'kill') {
    return kill(parsedCommnad, myConsole)
  }
}

function spawn(parsedCommnad, con) {
  var runnerInfo = new RunnerInfo();
  runnerInfos.set(parsedCommnad.id, runnerInfo);
  runnerInfos.console = con;

  function onExitOrThrow() {
    runnerInfos.delete(runnerInfo);
    con.removeListener('throw', onExitOrThrow);
    con.removeListener('exit', onExitOrThrow);
  }

  con.once('throw', onExitOrThrow);
  con.once('exit', onExitOrThrow);

  if (parsedCommnad.stdin) {
    runnerInfo.stdins.push(parsedCommnad.stdin)
  }

  var folder = path.resolve(process.env.HOME, 'runner-' + Date.now())
  fs.mkdirSync(folder);

  // myConsole.log(parsedCommnad);
  try {
    var runner = require('./runner/' + parsedCommnad.type)
  } catch (e) {
    return con.throw('cannot find runner for ' + parsedCommnad.type + ', aborted.')
  }

  con.status('setting up');

  runner.setup(folder, parsedCommnad.program, function (file_path) {
    // myConsole.log('setup finished');
    con.status('executing')
    if (runner.getExecuteArgs) {
      var temp = runner.getExecuteArgs(file_path);
      var oldPath = temp.path;
      var oldArgs = temp.args || [];
      var oldOpts = temp.opts || {};

      var timeBinPath = '/usr/bin/time';
      var newArgs = ['--verbose', '-o', process.env.HOME + '/time_result.txt', oldPath].concat(oldArgs);
      var newOpts = Object.assign({}, oldOpts, {
        cwd: path.dirname(file_path)
      })

      try {
        var child = child_process.spawn(timeBinPath, newArgs, newOpts);
      } catch (e) {
        return con.throw(e.stack || e.toString());
      }

      runnerInfo.process = child;

      child.stdin.on('error', con.error)
      child.stdout.on('error', con.error)
      child.stderr.on('error', con.error)

      while (runnerInfo.stdins.length > 0) {
        child.stdin.write(runnerInfo.stdins.shift());
      }

      while (runnerInfo.signals.length > 0) {
        child.kill(runnerInfo.signals.shift());
      }

      con.log('starting process with file ' + file_path);
      child.stdout.on('data', con.stdout);
      child.stderr.on('data', con.stderr);

      child.on('exit', function (code, sig) {
        con.status('exited');

        fs.readFile(process.env.HOME + '/time_result.txt', 'utf8', function (err, res) {
          var time = [];

          if (err) {
            time.push(["error", "unknown timing"]);
          } else {
            res = trim(res);
            res.split(/\r?\n/g).forEach(function (line) {
              var temp = line.split(/:/);

              if (trim(temp[0]) === "Elapsed (wall clock) time (h") {
                time.push([
                  "Elapsed (wall clock) time (h:mm:ss or m:ss)",
                  trim(line.replace("Elapsed (wall clock) time (h:mm:ss or m:ss):", ""))
                ])
                return;
              }

              temp[1] = temp[1] || '';
              time.push([trim(temp[0]), trim(temp[1])])
            });
          }

          con.log('child exit with code ' + code + ' and signal ' + sig);
          con.exit({code: code, signal: sig, time: time})
          // process.exit();
        })
      })
    } else {
      con.throw('missing handle: ' + parsedCommnad.type);
    }
  }, con)
}

function write(parsedCommnad, con) {
  var runnerInfo = runnerInfos.get(parsedCommnad.id);

  if (!runnerInfo) {
    return con.throw('runner ' + parsedCommnad.id + ' does not exist');
  }

  if (!parsedCommnad.stdin) {
    return con.error('no stdin provided');
  }

  runnerInfo.stdins.push(parsedCommnad.stdin);
  try {
    if (runnerInfo.process) {
      while (runnerInfo.stdins.length > 0) {
        runnerInfo.process.stdin.write(runnerInfo.stdins.shift());
      }
    }
  } catch (err) {
    con.error(err.stack);
  }
}

function kill(parsedCommnad, con) {
  var runnerInfo = runnerInfos.get(parsedCommnad.id);

  if (!runnerInfo) {
    return con.throw('runner ' + parsedCommnad.id + ' does not exist');
  }

  if (!parsedCommnad.signal) {
    parsedCommnad.signal = 'SIGTERM';
  }

  if (runnerInfo.process) {
    runnerInfo.process.kill(parsedCommnad.signal)
  } else {
    runnerInfo.signals.push(parsedCommnad.signal);
  }

  try {
    if (runnerInfo.process) {
      while (runnerInfo.stdins.length > 0) {
        runnerInfo.process.stdin.write(runnerInfo.stdins.shift());
      }
    }
  } catch (err) {
    con.error(err.stack);
  }
}<|endoftext|>