<commit_before>console.log('debug lac.js');

if (typeof library_helper != "undefined")
    library_helper.type = 'appliances_and_cooking';
else
    var library_helper = new libraryHelper('appliances_and_cooking', $("#openbem"));

function LAC_initUI() {
    //data.appliancelist.list = [];
    //update();

    //LAC SAP
    $('#LAC-lighting-fuels').html('');
    for (index in data.LAC.fuels_lighting) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_lighting.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_lighting.' + index + '.fraction" default="0">
'
            $('#LAC-lighting-fuels').append(out);
        }
    }
    $('#LAC-appliances-fuels').html('');
    for (index in data.LAC.fuels_appliances) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_appliances.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_appliances.' + index + '.fraction" default="0">
'
            $('#LAC-appliances-fuels').append(out);
        }
    }
    $('#LAC-cooking-fuels').html('');
    for (index in data.LAC.fuels_cooking) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_cooking.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_cooking.' + index + '.fraction" default="0">
'
            $('#LAC-cooking-fuels').append(out);
        }
    }

    // Detailed list
    for (z in data.appliancelist.list)
        add_applianceDetailedList(z);

    // Carbon Coop
    $('.carbonCoop-appliance').remove();
    $('.appliances-Carbon-Coop-category').hide();
    for (z in data.applianceCarbonCoop.list)
        add_applianceCarbonCoop(z);

    //Nothing to do to init the SAP div

    //For all of them
    $('select.fuels').each(function () {
        $(this).html(get_fuels_for_select($(this).attr('category')));
    });

    // Show divs according o the type of calculation
    show_LAC_divs(data.LAC_calculation_type)
}
function LAC_UpdateUI() {
    for (z in data.applianceCarbonCoop.list) {
        data.applianceCarbonCoop.list[z].energy_demand = 1.0 * data.applianceCarbonCoop.list[z].energy_demand.toFixed(2);
    }
    data.applianceCarbonCoop.energy_demand_total.total = 1.0 * data.applianceCarbonCoop.energy_demand_total.total.toFixed(2);
    data.applianceCarbonCoop.energy_demand_total.cooking = 1.0 * data.applianceCarbonCoop.energy_demand_total.cooking.toFixed(2);
    data.applianceCarbonCoop.energy_demand_total.appliances = 1.0 * data.applianceCarbonCoop.energy_demand_total.appliances.toFixed(2);
}

$('#openbem').on('change', '#LAC_calculation_type', function () {
    show_LAC_divs($('#LAC_calculation_type').val());
    library_helper.type = 'appliances_and_cooking';
});
$('#openbem').on('click', ".add-CarbonCoop-from-lib", function () {
    library_helper.init();
    library_helper.type = 'appliances_and_cooking';
    library_helper.onAddItemFromLib();
});
$('#openbem').on('click', "#add-item-detailedlist", function () {
    var size = data.appliancelist.list.length;
    var name = "Item " + (size + 1);
    data.appliancelist.list.push({name: name, category: 'lighting', power: 0, hours: 0, energy: 0, fuel: 'Standard Tariff', efficiency: 1, fuel_input: 0});
    add_applianceDetailedList(size);

    update();
});
$('#openbem').on('click', '.add-item-CarbonCoop', function () {
    var tag = $(this).attr('tag');
    var library = library_helper.get_library_by_id($(this).attr('library')).data;
    var item = library[tag];
    // Add required properties to item
    item.tag = tag;
    if (item.type_of_fuel == "Electricity")
        item.a_plus_rated = false;
    item.number_used = 1;
    item.fuel = get_a_fuel(item.type_of_fuel);
    // Push item
    data.applianceCarbonCoop.list.push(item);
    // Add appliance to the view and update
    add_applianceCarbonCoop(data.applianceCarbonCoop.list.length - 1);
    LAC_initUI();
    update();
});
$("#applianceCarbonCoop").on('click', '.delete-appliance', function () {
    index = $(this).attr('index');
    data.applianceCarbonCoop.list.splice(index, 1);
    //appliannceCarbonCoop_initUI();
    LAC_initUI();
    update();
});
$('#openbem').on('click', '.add_LAC_fuel', function () { // Fix index
    var type = $(this).attr('type');
    var array_name = 'fuels_' + type;
    data.LAC[array_name].push({fuel: 'Standard Tariff', fraction: 0, fuel_input: 0});
    var index = data.LAC[array_name].length - 1;
    var out = '
	<select key="data.LAC.fuels_' + type + '.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_' + type + '.' + index + '.fraction" default="0">
'
    $('#LAC-' + type + '-fuels').append(out);

    // Update
    LAC_initUI();
    update();
});

function show_LAC_divs(type_of_calc) {
    $('#LAC-container .to-be-hidden').hide();
    switch (type_of_calc) {
        case 'detailedlist':
            $('#detailed-list').show();
            break;
        case 'SAP':
            $('#lighting-SAP').show();
            $('#appliances-SAP').show();
            $('#cooking-SAP').show();
            break;
        case 'carboncoop_SAPlighting':
            $('#lighting-SAP').show();
            $('#CarbonCoop').show();
            break;
    }
}
function add_applianceDetailedList(z) {
    $("#appliancelist").append($("#template-detailedlist").html());
    $("#appliancelist [key='data.appliancelist.list.z.name']").attr('key', 'data.appliancelist.list.' + z + '.name');
    $("#appliancelist [key='data.appliancelist.list.z.category']").attr('key', 'data.appliancelist.list.' + z + '.category');
    $("#appliancelist [key='data.appliancelist.list.z.power']").attr('key', 'data.appliancelist.list.' + z + '.power');
    $("#appliancelist [key='data.appliancelist.list.z.hours']").attr('key', 'data.appliancelist.list.' + z + '.hours');
    $("#appliancelist [key='data.appliancelist.list.z.fuel']").attr('key', 'data.appliancelist.list.' + z + '.fuel');
    $("#appliancelist [key='data.appliancelist.list.z.efficiency']").attr('key', 'data.appliancelist.list.' + z + '.efficiency');
    $("#appliancelist [key='data.appliancelist.list.z.energy']").attr('key', 'data.appliancelist.list.' + z + '.energy');
    $("#appliancelist [key='data.appliancelist.list.z.fuel_input']").attr('key', 'data.appliancelist.list.' + z + '.fuel_input');
}
function add_applianceCarbonCoop(z) {
    var category = data.applianceCarbonCoop.list[z].category;
    var table_selector = '';
    switch (category) {
        case 'Food storage':
            table_selector = '#applianceCarbonCoop-' + 'Food-storage';
            break;
        case 'Other kitchen / cleaning':
            table_selector = '#applianceCarbonCoop-' + 'Other-kitchen-cleaning';
            break;
        default:
            table_selector = '#applianceCarbonCoop-' + category;
            break;
    }
    $(table_selector).show();
    var out = '
';
    out += '<input style="text-align:left; width:100px" type="text" key="data.applianceCarbonCoop.list.' + z + '.name" style="width:50px" />	';
    out += '<input type="number" key="data.applianceCarbonCoop.list.' + z + '.number_used" style="width:30px" />	';
    if (data.applianceCarbonCoop.list[z].type_of_fuel == "Electricity")
        out += '<input type="checkbox" key="data.applianceCarbonCoop.list.' + z + '.a_plus_rated" />	';
    else
        out += '';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += '<select key="data.applianceCarbonCoop.list.' + z + '.fuel" class="fuels" category="' + data.applianceCarbonCoop.list[z].type_of_fuel + '" style="width:150px" /> 	';
    out += '	';
    if (data.applianceCarbonCoop.list[z].type_of_fuel == "Electricity")
        out += ' 	';
    else
        out += '<input type="number" max="1" step="0.01" key="data.applianceCarbonCoop.list.' + z + '.efficiency" style="width:50px" /> 	';
    out += '	';
    out += '	';
    out += '
';
    $(table_selector).append(out);
}<commit_msg>Fixed bug LAC view not updating properly after undoing<commit_after>console.log('debug lac.js');

if (typeof library_helper != "undefined")
    library_helper.type = 'appliances_and_cooking';
else
    var library_helper = new libraryHelper('appliances_and_cooking', $("#openbem"));

function LAC_initUI() {
    //data.appliancelist.list = [];
    //update();

    //LAC SAP
    $('#LAC-lighting-fuels').html('');
    for (index in data.LAC.fuels_lighting) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_lighting.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_lighting.' + index + '.fraction" default="0">
'
            $('#LAC-lighting-fuels').append(out);
        }
    }
    $('#LAC-appliances-fuels').html('');
    for (index in data.LAC.fuels_appliances) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_appliances.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_appliances.' + index + '.fraction" default="0">
'
            $('#LAC-appliances-fuels').append(out);
        }
    }
    $('#LAC-cooking-fuels').html('');
    for (index in data.LAC.fuels_cooking) {
        if (index != 0) { // First fuel in array is added on LAC.html so no need to add it here
            var out = '
	<select key="data.LAC.fuels_cooking.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_cooking.' + index + '.fraction" default="0">
'
            $('#LAC-cooking-fuels').append(out);
        }
    }

    // Detailed list
    for (z in data.appliancelist.list)
        add_applianceDetailedList(z);

    // Carbon Coop
    $('.carbonCoop-appliance').remove();
    $('.appliances-Carbon-Coop-category').hide();
    for (z in data.applianceCarbonCoop.list)
        add_applianceCarbonCoop(z);

    //Nothing to do to init the SAP div

    //For all of them
    $('select.fuels').each(function () {
        $(this).html(get_fuels_for_select($(this).attr('category')));
    });

    // Show divs according o the type of calculation
    show_LAC_divs(data.LAC_calculation_type)
}
function LAC_UpdateUI() {
    LAC_initUI();

    for (z in data.applianceCarbonCoop.list) {
        data.applianceCarbonCoop.list[z].energy_demand = 1.0 * data.applianceCarbonCoop.list[z].energy_demand.toFixed(2);
    }
    data.applianceCarbonCoop.energy_demand_total.total = 1.0 * data.applianceCarbonCoop.energy_demand_total.total.toFixed(2);
    data.applianceCarbonCoop.energy_demand_total.cooking = 1.0 * data.applianceCarbonCoop.energy_demand_total.cooking.toFixed(2);
    data.applianceCarbonCoop.energy_demand_total.appliances = 1.0 * data.applianceCarbonCoop.energy_demand_total.appliances.toFixed(2);
}

$('#openbem').on('change', '#LAC_calculation_type', function () {
    show_LAC_divs($('#LAC_calculation_type').val());
    library_helper.type = 'appliances_and_cooking';
});
$('#openbem').on('click', ".add-CarbonCoop-from-lib", function () {
    library_helper.init();
    library_helper.type = 'appliances_and_cooking';
    library_helper.onAddItemFromLib();
});
$('#openbem').on('click', "#add-item-detailedlist", function () {
    var size = data.appliancelist.list.length;
    var name = "Item " + (size + 1);
    data.appliancelist.list.push({name: name, category: 'lighting', power: 0, hours: 0, energy: 0, fuel: 'Standard Tariff', efficiency: 1, fuel_input: 0});
    add_applianceDetailedList(size);

    update();
});
$('#openbem').on('click', '.add-item-CarbonCoop', function () {
    var tag = $(this).attr('tag');
    var library = library_helper.get_library_by_id($(this).attr('library')).data;
    var item = library[tag];
    // Add required properties to item
    item.tag = tag;
    if (item.type_of_fuel == "Electricity")
        item.a_plus_rated = false;
    item.number_used = 1;
    item.fuel = get_a_fuel(item.type_of_fuel);
    // Push item
    data.applianceCarbonCoop.list.push(item);
    // Add appliance to the view and update
    add_applianceCarbonCoop(data.applianceCarbonCoop.list.length - 1);
    LAC_initUI();
    update();
});
$("#applianceCarbonCoop").on('click', '.delete-appliance', function () {
    index = $(this).attr('index');
    data.applianceCarbonCoop.list.splice(index, 1);
    //appliannceCarbonCoop_initUI();
    LAC_initUI();
    update();
});
$('#openbem').on('click', '.add_LAC_fuel', function () { // Fix index
    var type = $(this).attr('type');
    var array_name = 'fuels_' + type;
    data.LAC[array_name].push({fuel: 'Standard Tariff', fraction: 0, fuel_input: 0});
    var index = data.LAC[array_name].length - 1;
    var out = '
	<select key="data.LAC.fuels_' + type + '.' + index + '.fuel" class="fuels" category="Electricity"></select>	<input type="number" style="width:55px" step="0.01" max="1" key="data.LAC.fuels_' + type + '.' + index + '.fraction" default="0">
'
    $('#LAC-' + type + '-fuels').append(out);

    // Update
    LAC_initUI();
    update();
});

function show_LAC_divs(type_of_calc) {
    $('#LAC-container .to-be-hidden').hide();
    switch (type_of_calc) {
        case 'detailedlist':
            $('#detailed-list').show();
            break;
        case 'SAP':
            $('#lighting-SAP').show();
            $('#appliances-SAP').show();
            $('#cooking-SAP').show();
            break;
        case 'carboncoop_SAPlighting':
            $('#lighting-SAP').show();
            $('#CarbonCoop').show();
            break;
    }
}
function add_applianceDetailedList(z) {
    $("#appliancelist").append($("#template-detailedlist").html());
    $("#appliancelist [key='data.appliancelist.list.z.name']").attr('key', 'data.appliancelist.list.' + z + '.name');
    $("#appliancelist [key='data.appliancelist.list.z.category']").attr('key', 'data.appliancelist.list.' + z + '.category');
    $("#appliancelist [key='data.appliancelist.list.z.power']").attr('key', 'data.appliancelist.list.' + z + '.power');
    $("#appliancelist [key='data.appliancelist.list.z.hours']").attr('key', 'data.appliancelist.list.' + z + '.hours');
    $("#appliancelist [key='data.appliancelist.list.z.fuel']").attr('key', 'data.appliancelist.list.' + z + '.fuel');
    $("#appliancelist [key='data.appliancelist.list.z.efficiency']").attr('key', 'data.appliancelist.list.' + z + '.efficiency');
    $("#appliancelist [key='data.appliancelist.list.z.energy']").attr('key', 'data.appliancelist.list.' + z + '.energy');
    $("#appliancelist [key='data.appliancelist.list.z.fuel_input']").attr('key', 'data.appliancelist.list.' + z + '.fuel_input');
}
function add_applianceCarbonCoop(z) {
    var category = data.applianceCarbonCoop.list[z].category;
    var table_selector = '';
    switch (category) {
        case 'Food storage':
            table_selector = '#applianceCarbonCoop-' + 'Food-storage';
            break;
        case 'Other kitchen / cleaning':
            table_selector = '#applianceCarbonCoop-' + 'Other-kitchen-cleaning';
            break;
        default:
            table_selector = '#applianceCarbonCoop-' + category;
            break;
    }
    $(table_selector).show();
    var out = '
';
    out += '<input style="text-align:left; width:100px" type="text" key="data.applianceCarbonCoop.list.' + z + '.name" style="width:50px" />	';
    out += '<input type="number" key="data.applianceCarbonCoop.list.' + z + '.number_used" style="width:30px" />	';
    if (data.applianceCarbonCoop.list[z].type_of_fuel == "Electricity")
        out += '<input type="checkbox" key="data.applianceCarbonCoop.list.' + z + '.a_plus_rated" />	';
    else
        out += '';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += ' 	';
    out += '<select key="data.applianceCarbonCoop.list.' + z + '.fuel" class="fuels" category="' + data.applianceCarbonCoop.list[z].type_of_fuel + '" style="width:150px" /> 	';
    out += '	';
    if (data.applianceCarbonCoop.list[z].type_of_fuel == "Electricity")
        out += ' 	';
    else
        out += '<input type="number" max="1" step="0.01" key="data.applianceCarbonCoop.list.' + z + '.efficiency" style="width:50px" /> 	';
    out += '	';
    out += '	';
    out += '
';
    $(table_selector).append(out);
}<|endoftext|>


<commit_before>/*
   Copyright 2010 Ephox Corporation

   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

       http://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.
*/
(function() {
	if (window.robot) {
		// Don't load if there's already a version of robot loaded.
		return;
	}

	window.robot = {

		onload: function(userCallback) {
			if (this.ready) {
				userCallback();
			} else {
				this.userCallback = userCallback;
			}
		},

		init: function(useDocumentWrite) {
			var jarUrl = "JSRobot.jar";
			var scripts = document.getElementsByTagName('script');
			for (var i = 0; i < scripts.length; i++) {
				var src = scripts[i].src;
				var regex = /^(.*\/?)robot.js(\?|$)/;
				if (src && regex.test(src)) {
					jarUrl = regex.exec(src)[1] + "JSRobot.jar";
				}
			}
			var appletTag = '<applet archive="' + jarUrl + '" code="com.ephox.jsrobot.JSRobot" id="robotApplet" width="10" height="10" mayscript="true"><param name="mayscript" value="true" /></applet>';
			if (useDocumentWrite) {
				document.write(appletTag);
			} else {
				var div = document.createElement('div');
				document.body.appendChild(div);
				div.innerHTML = appletTag;
			}
			this.appletInstance = document.getElementById('robotApplet');
		},

		callback: function() {
			this.ready = true;
			if (this.userCallback) {
				setTimeout(this.userCallback, 100);
			}
			return "Callback received.";
		},

		type: function(key, shiftKey, callback, focusElement) {
			shiftKey = !!shiftKey;
			this.appletAction(focusElement, callback, function() {
				return this.getApplet().typeKey(this.getKeycode(key), shiftKey);
			});
		},

		forwardDelete: function(callback, focusElement) {
			this.type(0x7F, false, callback, focusElement);
		},

		cut: function(callback, focusElement) {
			this.typeAsShortcut('x', callback, focusElement, 'cut');
		},

		copy: function(callback, focusElement) {
			this.typeAsShortcut('c', callback, focusElement, 'copy');
		},

		paste: function(callback, focusElement) {
			this.typeAsShortcut('v', callback, focusElement, 'paste');
		},

		pasteText: function(content, callback, focusElement) {
			var actionResult = this.getApplet().setClipboard(content);
			if (actionResult) {
				throw { message: "JSRobot error: " + actionResult };
			}
			this.paste(callback, focusElement);
		},

		typeAsShortcut: function(key, callback, focusElement, event) {
			this.appletAction(focusElement, callback, function() {
				return this.getApplet().typeAsShortcut(this.getKeycode(key));
			}, event);
		},

		getKeycode: function(key) {
			if (key.toUpperCase && key.charCodeAt) {
				if (/^[a-zA-Z\n\b\t]$/.test(key)) {
					return key.toUpperCase().charCodeAt(0);
				} else {
					throw { message: 'Invalid character to type. Must be a-z or A-Z, otherwise use the key code directly.' };
				}
			}
			return key;
		},

		captureScreenShot: function() {
			return this.getApplet().captureScreenShot();
		},

		setScreenShotDirectory: function(dir) {
			this.getApplet().setScreenShotDirectory(dir);
		},

		getApplet: function() {
			return this.appletInstance;
		},

		appletAction: function(focusElement, continueCallback, action, event) {
			var actionResult, listenerActivated = false, listenerType = event || 'keyup', timeout;
			var listener = function() {
				if (listenerActivated) return;
				listenerActivated = true;
				clearTimeout(timeout);
				doListeners(false);
				setTimeout(continueCallback, 0);
			};
			var doListeners = function(add) {
				if (focusElement.addEventListener) {
					focusElement.ownerDocument[add ? 'addEventListener' : 'removeEventListener'](listenerType, listener, true);
				} else {
					focusElement[add ? 'attachEvent' : 'detachEvent']('on' + listenerType, listener);
				}
			};

			focusElement = focusElement || document.activeElement;
			if (focusElement && focusElement.contentWindow) {
				focusElement = focusElement.contentWindow.document.activeElement;
			}
			if (focusElement) {
				focusElement.focus();
				doListeners(true);

				// Add a timeout of 5 seconds in case the target event isn't supported or something goes wrong.
				timeout = setTimeout(function() {
					if (!listenerActivated) {
						continueCallback();
					}
				}, 5000);
			}
			actionResult = action.apply(this);
			if (actionResult) {
				throw { message: "JSRobot error: " + actionResult };
			}
			if (!focusElement) {
				setTimeout(continueCallback, 100);
			}
		}
	};

	function robotOnload() {
		window.robot.init();
	}
	if (document.addEventListener) {
		window.addEventListener('load', robotOnload, true);
	} else {
		// If you don't init straight away on IE, it gets the applet context wrong.
		window.robot.init(true);
	}
})();
<commit_msg>MAINTENANCE: Upgraded JSRobot<commit_after>/*
   Copyright 2010 Ephox Corporation

   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

       http://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.
*/
(function() {
	if (window.robot) {
		// Don't load if there's already a version of robot loaded.
		return;
	}

	window.robot = {

		onload: function(userCallback) {
			if (this.ready) {
				userCallback();
			} else {
				this.userCallback = userCallback;
			}
		},

		init: function(useDocumentWrite) {
			var jarUrl = "JSRobot.jar";
			var scripts = document.getElementsByTagName('script');
			for (var i = 0; i < scripts.length; i++) {
				var src = scripts[i].src;
				var regex = /^(.*\/?)robot.js(\?|$)/;
				if (src && regex.test(src)) {
					jarUrl = regex.exec(src)[1] + "JSRobot.jar";
				}
			}
			var appletTag = '<applet archive="' + jarUrl + '" code="com.ephox.jsrobot.JSRobot" id="robotApplet" width="10" height="10" mayscript="true"><param name="mayscript" value="true" /></applet>';
			if (useDocumentWrite) {
				document.write(appletTag);
			} else {
				var div = document.createElement('div');
				document.body.appendChild(div);
				div.innerHTML = appletTag;
			}
			this.appletInstance = document.getElementById('robotApplet');
		},

		callback: function() {
			this.ready = true;
			if (this.userCallback) {
				setTimeout(this.userCallback, 100);
			}
			return "Callback received.";
		},

		type: function(key, shiftKey, callback, focusElement) {
			shiftKey = !!shiftKey;
			this.appletAction(focusElement, callback, function() {
				return this.getApplet().typeKey(this.getKeycode(key), shiftKey);
			});
		},

		forwardDelete: function(callback, focusElement) {
			this.type(0x7F, false, callback, focusElement);
		},

		cut: function(callback, focusElement) {
			this.typeAsShortcut('x', callback, focusElement, 'cut');
		},

		copy: function(callback, focusElement) {
			this.typeAsShortcut('c', callback, focusElement, 'copy');
		},

		paste: function(callback, focusElement) {
			this.typeAsShortcut('v', callback, focusElement, 'paste');
		},

		pasteText: function(content, callback, focusElement) {
			var actionResult = this.getApplet().setClipboard(content);
			if (actionResult) {
				throw { message: "JSRobot error: " + actionResult };
			}
			this.paste(callback, focusElement);
		},

		typeAsShortcut: function(key, callback, focusElement, event) {
			this.appletAction(focusElement, callback, function() {
				return this.getApplet().typeAsShortcut(this.getKeycode(key));
			}, event);
		},

		getKeycode: function(key) {
			if (key.toUpperCase && key.charCodeAt) {
				if (/^[a-zA-Z\n\b\t]$/.test(key)) {
					return key.toUpperCase().charCodeAt(0);
				} else {
					throw { message: 'Invalid character to type. Must be a-z or A-Z, otherwise use the key code directly.' };
				}
			}
			return key;
		},

		captureScreenShot: function() {
			return this.getApplet().captureScreenShot();
		},

		setScreenShotDirectory: function(dir) {
			this.getApplet().setScreenShotDirectory(dir);
		},

		getApplet: function() {
			return this.appletInstance;
		},

		appletAction: function(focusElement, continueCallback, action, event) {
			var actionResult, listenerActivated = false, listenerType = event || 'keyup', timeout;
			var listener = function() {
				if (listenerActivated) return;
				listenerActivated = true;
				clearTimeout(timeout);
				doListeners(false);
				setTimeout(continueCallback, 0);
			};
			var doListeners = function(add) {
				var target = focusElement.document || focusElement.ownerDocument || focusElement;
				if (focusElement.addEventListener) {
					target[add ? 'addEventListener' : 'removeEventListener'](listenerType, listener, true);
				} else {
					focusElement[add ? 'attachEvent' : 'detachEvent']('on' + listenerType, listener);
				}
			};

			focusElement = focusElement || document.activeElement;
			if (focusElement.frameElement) {
				// If we have an iframe window we need to make sure the iframe element in the parent document is focussed
				// Otherwise calls to focus within the frame won't have any effect in Safari/Mac.
				focusElement.frameElement.focus();
			}
			if (focusElement && focusElement.contentWindow) {
				// If the element to focus is an iframe element, focus the active element within the frame instead (if available).
				focusElement = focusElement.contentWindow.document.activeElement;
			}
			if (focusElement) {
				focusElement.focus();
				doListeners(true);

				// Add a timeout of 5 seconds in case the target event isn't supported or something goes wrong.
				timeout = setTimeout(function() {
					if (!listenerActivated) {
						continueCallback();
					}
				}, 5000);
			}
			actionResult = action.apply(this);
			if (actionResult) {
				throw { message: "JSRobot error: " + actionResult };
			}
			if (!focusElement) {
				setTimeout(continueCallback, 100);
			}
		}
	};

	function robotOnload() {
		window.robot.init();
	}
	if (document.addEventListener) {
		window.addEventListener('load', robotOnload, true);
	} else {
		// If you don't init straight away on IE, it gets the applet context wrong.
		window.robot.init(true);
	}
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Reboot from 'material-ui/Reboot';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';

import CategoryView from './CategoryView/CategoryView.js';
import DailyView from './DailyView/DailyView.js';
import AppTabs from './AppTabs/AppTabs.js';
import APPVIEWS from './APPVIEWS.js';

const theme = createMuiTheme();

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      view: APPVIEWS.home,
    };
    this.handleTabClick = this.handleTabClick.bind(this)
  }

  handleTabClick(view, e) {
    this.setState({
      view: view
    });
  }

  render() {
    let view = null;
    if (this.state.view === APPVIEWS.categories) {
      view = (
        <CategoryView />
      )
    } else if (this.state.view === APPVIEWS.daily) {
      view = (
        <DailyView />
      )
    }

    return (
      <MuiThemeProvider theme={theme}>
        <Reboot />
        <AppTabs handleTabClick={this.handleTabClick}></AppTabs>
        {view}
      </MuiThemeProvider>
    );
  }
}

export default App;
<commit_msg>dark theme<commit_after>import React, { Component } from 'react';
import Reboot from 'material-ui/Reboot';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';

import CategoryView from './CategoryView/CategoryView.js';
import DailyView from './DailyView/DailyView.js';
import AppTabs from './AppTabs/AppTabs.js';
import APPVIEWS from './APPVIEWS.js';

const theme = createMuiTheme({
  palette: {
    type: 'dark'
  },
});

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      view: APPVIEWS.home,
    };
    this.handleTabClick = this.handleTabClick.bind(this)
  }

  handleTabClick(view, e) {
    this.setState({
      view: view
    });
  }

  render() {
    let view = null;
    if (this.state.view === APPVIEWS.categories) {
      view = (
        <CategoryView />
      )
    } else if (this.state.view === APPVIEWS.daily) {
      view = (
        <DailyView />
      )
    }

    return (
      <MuiThemeProvider theme={theme}>
        <Reboot />
        <AppTabs handleTabClick={this.handleTabClick}></AppTabs>
        {view}
      </MuiThemeProvider>
    );
  }
}

export default App;
<|endoftext|>


<commit_before>'use strict';

var eslint = require('eslint');
var ESLintTester = require('eslint-tester');

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

var eslintTester = new ESLintTester(eslint.linter);
eslintTester.addRuleTest('./lib/rules/no-latethis', {

    valid: [{
        code: 'var self = this, foo = "bar";',
        args: [1, 'self'],
    }, {
        code: 'var self = this; $el.on("click", function () { var $node = $(this); $node.trigger("ok"); });',
        args: [1, 'self']
    }, {
        code: 'console.log(this);'
    }, {
        code: 'this.doSomething();'
    }
    ],

    invalid: [{
        code: 'var that = this; $el.on("click", function () { that.run(); this.trigger("ok"); });',
        errors: [{ message: 'used "this" instead of "that"', }]
    }, {
        code: 'var that = this; $el.on("click", function () { var $node = $(this); $node.trigger("ok"); this.run(); });',
        errors: [{ message: 'used "this" instead of "that"', }]
    },
        // TODO as later part of onevar
        // TODO using this as part of func call, ala $(this)
        // TODO using this in a sub-nested anon function
    ]
});
<commit_msg>test: simplify checks for fn invocations<commit_after>'use strict';

var eslint = require('eslint');
var ESLintTester = require('eslint-tester');

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

var eslintTester = new ESLintTester(eslint.linter);
eslintTester.addRuleTest('./lib/rules/no-latethis', {

    valid: [{
        code: 'var self = this, foo = "bar";',
        args: [1, 'self'],
    }, {
        code: 'var self = this; $el.on("click", function () { var $node = $(this); $node.trigger("ok"); });',
        args: [1, 'self']
    }, {
        code: 'console.log(this);'
    }, {
        code: 'this.doSomething();'
    }
    ],

    invalid: [{
        code: 'var that = this; $el.on("click", function () { this.trigger("ok"); });',
        errors: [{ message: 'used "this" instead of "that"', }]
    }, {
        code: 'var that = this; $el.on("click", function () { var $node = $(this); $node.trigger("ok"); this.run(); });',
        errors: [{ message: 'used "this" instead of "that"', }]
    }, {
        code: 'var self = this; $el.on("click", function () { this.trigger("ok"); });',
        args: [1, 'self'],
        errors: [{ message: 'used "this" instead of "self"', }]
    }
        // TODO as later part of onevar
        // TODO using this as part of func call, ala $(this)
        // TODO using this in a sub-nested anon function
    ]
});
<|endoftext|>


<commit_before>define((require, exports, module) => {
  const store = require('app/data/index')
  const TRHMasterData = require('app/core/master')

  exports.battleStatusText = Vue.filter('battle-status-text', function (statusId) {
    return ['战斗', '軽傷', '中傷', '重傷', '破壞'][statusId]
  })

  exports.statusText = Vue.filter('status-text', function (statusId) {
    return ['-', '手入', '修行', '远征'][statusId]
  })

  exports.statusCname = Vue.filter('status-cname', function (statusId) {
    return ['normal', 'recovery', 'damaged', 'warning', 'danger'][statusId]
  })

  exports.fatigueCname =  Vue.filter('fatigue-cname', function (fatigueFlag) {
    return ['very-tired', 'tired', 'normal', 'perfect'][fatigueFlag]
  })

  exports.fatigueText = Vue.filter('fatigue-text', function (fatigueFlag) {
    return ['过労', '疲労', '通常', '桜吹雪'][fatigueFlag]
  })

  exports.equipNameFormat = Vue.filter('equip-name-format', (name) => {
    return name.replace('兵', '').replace('特上', '特')
  })

  exports.fatigueBuff = Vue.filter('fatigue-buff', function (fatigueFlag) {
    return '(' + ['-40%', '-20%', '+0%', '+20%'][fatigueFlag] + ')'
  })

  exports.swordPattern = Vue.filter('sword-pattern', function (swordId) {
    return swordId ? '../../static/sword/' + swordId + '.png' : '../../static/sword/0.png'
  })

  exports.EnemySwordPattern = Vue.filter('enemy-sword-pattern', function (swordId) {
    let imageId = _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'imageId'], 0)
    let rarity = _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'rarity'], 0)
    return swordId ? '../../static/enemy/' + imageId + '_' + rarity + '.png' : '../../static/sword/0.png'
  })

  exports.MapPattern = Vue.filter('map-pattern', function (mapId) {
    let [episodeId , fieldId , layerNum] = mapId.split('_')
    if(episodeId > 0)
      return '../../static/map/' + episodeId + '_' + fieldId + '_' + layerNum + '.jpg'
    else if (episodeId < 0){
      let type = _.get(TRHMasterData.getMasterData('Event'), [episodeId, 'type'], 0)
      let map = _.get(TRHMasterData.getMasterData('EventLayer'), [episodeId, fieldId, layerNum, 'map'], 0)
      return '../../static/map/event' +  '_' + type + '_' + map + '.jpg'
    }
  })

  exports.swordObject = Vue.filter('sword-object', function (serialId) {
    return serialId
  })

  exports.partyStatus = Vue.filter('party-status', (status) => {
    return [
      '未开放',
      '正常',
      '远征'
    ][status] || ''
  })

  exports.amuletName = Vue.filter('amulet-name', (itemId) => {
    return [
    '-',
    '守',
    '极守'
    ][itemId] || ''
  })

  exports.getNotFlg = Vue.filter('not-flg', (flg) =>{
    return ['○', ''][flg]
  })

  exports.hhmmss = Vue.filter('hhmmss', (time) => {
    return moment(time).format('HH:mm:ss')
  })

  exports.MMDDhhmmss = Vue.filter('MMDDhhmmss', (time) => {
    return moment(time).format('MM/DD HH:mm:ss')
  })

  exports.equipLevelName = Vue.filter('equip-level-name', function (equip_id) {
    let level = _.get(TRHMasterData.getMasterData('Equip'), [equip_id, 'rarity'], 0)
    return {
      0: 'destroyed',
      1: 'n',
      3: 'r',
      5: 'sr'
    }[level]
  })

  exports.equipLevelCname = Vue.filter('equip-level-cname', function (level) {
    return {
      0: 'destroyed',
      1: 'n',
      3: 'r',
      5: 'sr'
    }[level]
  })

  exports.rankName = Vue.filter('rank-name', (rank) => {
    return [
      '0',
      '一騎',
      'S',
      'A',
      'B',
      'C',
      '敗北'
    ][rank] || ''
  })

  exports.formationName = Vue.filter('formation-name', (formationId) => {
    return {
      0: '不明',
      1: '魚鱗陣',
      2: '鶴翼陣',
      3: '方陣',
      4: '横隊陣',
      5: '雁行陣',
      6: '逆行陣'
    }[formationId] || ''
  })

  exports.swordName = Vue.filter('sword-name', (swordId) => {
    return swordId ? _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'name'], '-') : '空'
  })

  exports.swordHp = Vue.filter('sword-hp', (swordId) => {
    return swordId ? _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'hp'], '-') : '0'
  })

  exports.equipName = Vue.filter('equip-name', (equipId) => {
    return equipId ? _.get(TRHMasterData.getMasterData('Equip'), [equipId, 'name'], '-').replace(/\d+/, '') : '空'
  })

  exports.swordSerialName = Vue.filter('sword-serial-name', (serialId) => {
    return _.get(store.state, ['swords', 'serial', serialId, 'name'], '-')
  })

  exports.equipSerialName = Vue.filter('equip-serial-name', (serialId) => {
    return _.get(store.state, ['equip', 'serial', serialId, 'name'], '-').replace(/\d+/, '')
  })

  exports.PracticeEnemyEquipName = Vue.filter('practice-enemy-equip-serial-name', (serialId) => {
    return _.get(store.state, ['practice_enemy', 'enemy_equip', serialId, 'name'], '-').replace(/\d+/, '')
  })

  exports.allEquipSerialName = Vue.filter('all-equip-serial-name', (serialIds) => {
    return _.map(serialIds, (serialId) => _.get(store.state, ['equip', 'serial', serialId, 'name'], '-').replace(/\d+/, '')).join(' / ')
  })

  exports.itemNameFormat = Vue.filter('item-name-format', (ConsumableId) => {
    let name = _.get(TRHMasterData.getMasterData('Consumable'), [ConsumableId, 'name'], '-')
    return name.replace('御札・', '')
  })
})<commit_msg>debug event map<commit_after>define((require, exports, module) => {
  const store = require('app/data/index')
  const TRHMasterData = require('app/core/master')

  exports.battleStatusText = Vue.filter('battle-status-text', function (statusId) {
    return ['战斗', '軽傷', '中傷', '重傷', '破壞'][statusId]
  })

  exports.statusText = Vue.filter('status-text', function (statusId) {
    return ['-', '手入', '修行', '远征'][statusId]
  })

  exports.statusCname = Vue.filter('status-cname', function (statusId) {
    return ['normal', 'recovery', 'damaged', 'warning', 'danger'][statusId]
  })

  exports.fatigueCname =  Vue.filter('fatigue-cname', function (fatigueFlag) {
    return ['very-tired', 'tired', 'normal', 'perfect'][fatigueFlag]
  })

  exports.fatigueText = Vue.filter('fatigue-text', function (fatigueFlag) {
    return ['过労', '疲労', '通常', '桜吹雪'][fatigueFlag]
  })

  exports.equipNameFormat = Vue.filter('equip-name-format', (name) => {
    return name.replace('兵', '').replace('特上', '特')
  })

  exports.fatigueBuff = Vue.filter('fatigue-buff', function (fatigueFlag) {
    return '(' + ['-40%', '-20%', '+0%', '+20%'][fatigueFlag] + ')'
  })

  exports.swordPattern = Vue.filter('sword-pattern', function (swordId) {
    return swordId ? '../../static/sword/' + swordId + '.png' : '../../static/sword/0.png'
  })

  exports.EnemySwordPattern = Vue.filter('enemy-sword-pattern', function (swordId) {
    let imageId = _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'imageId'], 0)
    let rarity = _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'rarity'], 0)
    return swordId ? '../../static/enemy/' + imageId + '_' + rarity + '.png' : '../../static/sword/0.png'
  })

  exports.MapPattern = Vue.filter('map-pattern', function (mapId) {
    let [episodeId , fieldId , layerNum] = mapId.split('_')
    if(episodeId > 0)
      return '../../static/map/' + episodeId + '_' + fieldId + '_' + layerNum + '.jpg'
    else if (episodeId < 0){
      let type = _.get(TRHMasterData.getMasterData('Event'), [episodeId, 'type'], 0)
      let map = _.get(TRHMasterData.getMasterData('EventLayer'), [episodeId, fieldId, layerNum, 'map'], 0)
      if(type == 4){
        map = fieldId
      }
      return '../../static/map/event' +  '_' + type + '_' + map + '.jpg'
    }
  })

  exports.swordObject = Vue.filter('sword-object', function (serialId) {
    return serialId
  })

  exports.partyStatus = Vue.filter('party-status', (status) => {
    return [
      '未开放',
      '正常',
      '远征'
    ][status] || ''
  })

  exports.amuletName = Vue.filter('amulet-name', (itemId) => {
    return [
    '-',
    '守',
    '极守'
    ][itemId] || ''
  })

  exports.getNotFlg = Vue.filter('not-flg', (flg) =>{
    return ['○', ''][flg]
  })

  exports.hhmmss = Vue.filter('hhmmss', (time) => {
    return moment(time).format('HH:mm:ss')
  })

  exports.MMDDhhmmss = Vue.filter('MMDDhhmmss', (time) => {
    return moment(time).format('MM/DD HH:mm:ss')
  })

  exports.equipLevelName = Vue.filter('equip-level-name', function (equip_id) {
    let level = _.get(TRHMasterData.getMasterData('Equip'), [equip_id, 'rarity'], 0)
    return {
      0: 'destroyed',
      1: 'n',
      3: 'r',
      5: 'sr'
    }[level]
  })

  exports.equipLevelCname = Vue.filter('equip-level-cname', function (level) {
    return {
      0: 'destroyed',
      1: 'n',
      3: 'r',
      5: 'sr'
    }[level]
  })

  exports.rankName = Vue.filter('rank-name', (rank) => {
    return [
      '0',
      '一騎',
      'S',
      'A',
      'B',
      'C',
      '敗北'
    ][rank] || ''
  })

  exports.formationName = Vue.filter('formation-name', (formationId) => {
    return {
      0: '不明',
      1: '魚鱗陣',
      2: '鶴翼陣',
      3: '方陣',
      4: '横隊陣',
      5: '雁行陣',
      6: '逆行陣'
    }[formationId] || ''
  })

  exports.swordName = Vue.filter('sword-name', (swordId) => {
    return swordId ? _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'name'], '-') : '空'
  })

  exports.swordHp = Vue.filter('sword-hp', (swordId) => {
    return swordId ? _.get(TRHMasterData.getMasterData('Sword'), [swordId, 'hp'], '-') : '0'
  })

  exports.equipName = Vue.filter('equip-name', (equipId) => {
    return equipId ? _.get(TRHMasterData.getMasterData('Equip'), [equipId, 'name'], '-').replace(/\d+/, '') : '空'
  })

  exports.swordSerialName = Vue.filter('sword-serial-name', (serialId) => {
    return _.get(store.state, ['swords', 'serial', serialId, 'name'], '-')
  })

  exports.equipSerialName = Vue.filter('equip-serial-name', (serialId) => {
    return _.get(store.state, ['equip', 'serial', serialId, 'name'], '-').replace(/\d+/, '')
  })

  exports.PracticeEnemyEquipName = Vue.filter('practice-enemy-equip-serial-name', (serialId) => {
    return _.get(store.state, ['practice_enemy', 'enemy_equip', serialId, 'name'], '-').replace(/\d+/, '')
  })

  exports.allEquipSerialName = Vue.filter('all-equip-serial-name', (serialIds) => {
    return _.map(serialIds, (serialId) => _.get(store.state, ['equip', 'serial', serialId, 'name'], '-').replace(/\d+/, '')).join(' / ')
  })

  exports.itemNameFormat = Vue.filter('item-name-format', (ConsumableId) => {
    let name = _.get(TRHMasterData.getMasterData('Consumable'), [ConsumableId, 'name'], '-')
    return name.replace('御札・', '')
  })
})<|endoftext|>


<commit_before>import { createSelector } from 'reselect'

// ------------------------------------
// Initial State
// ------------------------------------
const initialState = {
  filterPulldown: false,
  filter: { key: 'ALL_ACTIVITY', name: 'All Activity' },
  filters: [
    { key: 'ALL_ACTIVITY', name: 'All' },
    { key: 'SENT_ACTIVITY', name: 'Sent' },
    { key: 'REQUESTED_ACTIVITY', name: 'Requested' },
    { key: 'PENDING_ACTIVITY', name: 'Pending' },
    { key: 'FUNDED_ACTIVITY', name: 'Funding Transactions' }
  ],
  modal: {
    modalType: null,
    modalProps: {}
  },
  searchText: ''
}

// ------------------------------------
// Constants
// ------------------------------------
export const SHOW_ACTIVITY_MODAL = 'SHOW_ACTIVITY_MODAL'
export const HIDE_ACTIVITY_MODAL = 'HIDE_ACTIVITY_MODAL'

export const CHANGE_FILTER = 'CHANGE_FILTER'

export const TOGGLE_PULLDOWN = 'TOGGLE_PULLDOWN'

export const UPDATE_SEARCH_TEXT = 'UPDATE_SEARCH_TEXT'

// ------------------------------------
// Actions
// ------------------------------------
export function showActivityModal(modalType, modalProps) {
  return {
    type: SHOW_ACTIVITY_MODAL,
    modalType,
    modalProps
  }
}

export function hideActivityModal() {
  return {
    type: HIDE_ACTIVITY_MODAL
  }
}

export function changeFilter(filter) {
  return {
    type: CHANGE_FILTER,
    filter
  }
}

export function toggleFilterPulldown() {
  return {
    type: TOGGLE_PULLDOWN
  }
}

export function updateSearchText(searchText) {
  return {
    type: UPDATE_SEARCH_TEXT,
    searchText
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [SHOW_ACTIVITY_MODAL]: (state, { modalType, modalProps }) => ({ ...state, modal: { modalType, modalProps } }),
  [HIDE_ACTIVITY_MODAL]: state => ({ ...state, modal: { modalType: null, modalProps: {} } }),
  [CHANGE_FILTER]: (state, { filter }) => ({ ...state, filter, filterPulldown: false }),
  [TOGGLE_PULLDOWN]: state => ({ ...state, filterPulldown: !state.filterPulldown }),

  [UPDATE_SEARCH_TEXT]: (state, { searchText }) => ({ ...state, searchText })
}

// ------------------------------------
// Selectors
// ------------------------------------
const activitySelectors = {}
const filtersSelector = state => state.activity.filters
const filterSelector = state => state.activity.filter
const searchSelector = state => state.activity.searchText
const paymentsSelector = state => state.payment.payments
const invoicesSelector = state => state.invoice.invoices
const transactionsSelector = state => state.transaction.transactions
const channelsSelector = state => state.channels.channels

const allActivity = createSelector(
  searchSelector,
  paymentsSelector,
  invoicesSelector,
  transactionsSelector,
  (searchText, payments, invoices, transactions) => {
    const searchedArr = [...payments, ...invoices, ...transactions].filter((tx) => {
      if ((tx.tx_hash && tx.tx_hash.includes(searchText)) ||
          (tx.payment_hash && tx.payment_hash.includes(searchText)) ||
          (tx.payment_request && tx.payment_request.includes(searchText))) {
        return true
      }

      return false
    })

    return searchedArr.sort((a, b) => {
      const aTimestamp = Object.prototype.hasOwnProperty.call(a, 'time_stamp') ? a.time_stamp : a.creation_date
      const bTimestamp = Object.prototype.hasOwnProperty.call(b, 'time_stamp') ? b.time_stamp : b.creation_date

      return bTimestamp - aTimestamp
    })
  }
)

const invoiceActivity = createSelector(
  invoicesSelector,
  invoices => invoices
)

const sentActivity = createSelector(
  transactionsSelector,
  paymentsSelector,
  (transactions, payments) => {
    const sentTransactions = transactions.filter(transaction => transaction.amount < 0)
    return [...sentTransactions, ...payments].sort((a, b) => {
      const aTimestamp = Object.prototype.hasOwnProperty.call(a, 'time_stamp') ? a.time_stamp : a.creation_date
      const bTimestamp = Object.prototype.hasOwnProperty.call(b, 'time_stamp') ? b.time_stamp : b.creation_date

      return bTimestamp - aTimestamp
    })
  }
)

const pendingActivity = createSelector(
  invoicesSelector,
  invoices => invoices.filter(invoice => !invoice.settled)
)

const fundedActivity = createSelector(
  transactionsSelector,
  channelsSelector,
  (transactions, channels) => {
    const fundingTxIds = channels.map(channel => channel.channel_point.split(':')[0])

    return transactions.filter(transaction => fundingTxIds.includes(transaction.tx_hash))
  }
)

const FILTERS = {
  ALL_ACTIVITY: allActivity,
  SENT_ACTIVITY: sentActivity,
  REQUESTED_ACTIVITY: invoiceActivity,
  PENDING_ACTIVITY: pendingActivity,
  FUNDED_ACTIVITY: fundedActivity
}

activitySelectors.currentActivity = createSelector(
  filterSelector,
  filter => FILTERS[filter.key]
)

activitySelectors.nonActiveFilters = createSelector(
  filtersSelector,
  filterSelector,
  (filters, filter) => filters.filter(f => f.key !== filter.key)
)

export { activitySelectors }

// ------------------------------------
// Reducer
// ------------------------------------
export default function activityReducer(state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<commit_msg>fix(invoice-sort): make invoices sorted by settle_date if they have been settled rather than creation date<commit_after>import { createSelector } from 'reselect'

// ------------------------------------
// Initial State
// ------------------------------------
const initialState = {
  filterPulldown: false,
  filter: { key: 'ALL_ACTIVITY', name: 'All Activity' },
  filters: [
    { key: 'ALL_ACTIVITY', name: 'All' },
    { key: 'SENT_ACTIVITY', name: 'Sent' },
    { key: 'REQUESTED_ACTIVITY', name: 'Requested' },
    { key: 'PENDING_ACTIVITY', name: 'Pending' },
    { key: 'FUNDED_ACTIVITY', name: 'Funding Transactions' }
  ],
  modal: {
    modalType: null,
    modalProps: {}
  },
  searchText: ''
}

// ------------------------------------
// Constants
// ------------------------------------
export const SHOW_ACTIVITY_MODAL = 'SHOW_ACTIVITY_MODAL'
export const HIDE_ACTIVITY_MODAL = 'HIDE_ACTIVITY_MODAL'

export const CHANGE_FILTER = 'CHANGE_FILTER'

export const TOGGLE_PULLDOWN = 'TOGGLE_PULLDOWN'

export const UPDATE_SEARCH_TEXT = 'UPDATE_SEARCH_TEXT'

// ------------------------------------
// Actions
// ------------------------------------
export function showActivityModal(modalType, modalProps) {
  return {
    type: SHOW_ACTIVITY_MODAL,
    modalType,
    modalProps
  }
}

export function hideActivityModal() {
  return {
    type: HIDE_ACTIVITY_MODAL
  }
}

export function changeFilter(filter) {
  return {
    type: CHANGE_FILTER,
    filter
  }
}

export function toggleFilterPulldown() {
  return {
    type: TOGGLE_PULLDOWN
  }
}

export function updateSearchText(searchText) {
  return {
    type: UPDATE_SEARCH_TEXT,
    searchText
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [SHOW_ACTIVITY_MODAL]: (state, { modalType, modalProps }) => ({ ...state, modal: { modalType, modalProps } }),
  [HIDE_ACTIVITY_MODAL]: state => ({ ...state, modal: { modalType: null, modalProps: {} } }),
  [CHANGE_FILTER]: (state, { filter }) => ({ ...state, filter, filterPulldown: false }),
  [TOGGLE_PULLDOWN]: state => ({ ...state, filterPulldown: !state.filterPulldown }),

  [UPDATE_SEARCH_TEXT]: (state, { searchText }) => ({ ...state, searchText })
}

// ------------------------------------
// Selectors
// ------------------------------------
const activitySelectors = {}
const filtersSelector = state => state.activity.filters
const filterSelector = state => state.activity.filter
const searchSelector = state => state.activity.searchText
const paymentsSelector = state => state.payment.payments
const invoicesSelector = state => state.invoice.invoices
const transactionsSelector = state => state.transaction.transactions
const channelsSelector = state => state.channels.channels

const allActivity = createSelector(
  searchSelector,
  paymentsSelector,
  invoicesSelector,
  transactionsSelector,
  (searchText, payments, invoices, transactions) => {
    const searchedArr = [...payments, ...invoices, ...transactions].filter((tx) => {
      if ((tx.tx_hash && tx.tx_hash.includes(searchText)) ||
          (tx.payment_hash && tx.payment_hash.includes(searchText)) ||
          (tx.payment_request && tx.payment_request.includes(searchText))) {
        return true
      }

      return false
    })

    return searchedArr.sort((a, b) => {
      // this will return the correct timestamp to use when sorting (time_stamp, creation_date, or settle_date)
      function returnTimestamp(transaction) {
        // if on-chain txn
        if (Object.prototype.hasOwnProperty.call(transaction, 'time_stamp')) { return transaction.time_stamp }
        // if invoice that has been paid
        if (transaction.settled) { return transaction.settle_date }
        // if invoice that has not been paid or an LN payment
        return transaction.creation_date
      }

      const aTimestamp = returnTimestamp(a)
      const bTimestamp = returnTimestamp(b)

      return bTimestamp - aTimestamp
    })
  }
)

const invoiceActivity = createSelector(
  invoicesSelector,
  invoices => invoices
)

const sentActivity = createSelector(
  transactionsSelector,
  paymentsSelector,
  (transactions, payments) => {
    const sentTransactions = transactions.filter(transaction => transaction.amount < 0)
    return [...sentTransactions, ...payments].sort((a, b) => {
      const aTimestamp = Object.prototype.hasOwnProperty.call(a, 'time_stamp') ? a.time_stamp : a.creation_date
      const bTimestamp = Object.prototype.hasOwnProperty.call(b, 'time_stamp') ? b.time_stamp : b.creation_date

      return bTimestamp - aTimestamp
    })
  }
)

const pendingActivity = createSelector(
  invoicesSelector,
  invoices => invoices.filter(invoice => !invoice.settled)
)

const fundedActivity = createSelector(
  transactionsSelector,
  channelsSelector,
  (transactions, channels) => {
    const fundingTxIds = channels.map(channel => channel.channel_point.split(':')[0])

    return transactions.filter(transaction => fundingTxIds.includes(transaction.tx_hash))
  }
)

const FILTERS = {
  ALL_ACTIVITY: allActivity,
  SENT_ACTIVITY: sentActivity,
  REQUESTED_ACTIVITY: invoiceActivity,
  PENDING_ACTIVITY: pendingActivity,
  FUNDED_ACTIVITY: fundedActivity
}

activitySelectors.currentActivity = createSelector(
  filterSelector,
  filter => FILTERS[filter.key]
)

activitySelectors.nonActiveFilters = createSelector(
  filtersSelector,
  filterSelector,
  (filters, filter) => filters.filter(f => f.key !== filter.key)
)

export { activitySelectors }

// ------------------------------------
// Reducer
// ------------------------------------
export default function activityReducer(state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<|endoftext|>


<commit_before>import { alerts } from '../stores/alerts'

// Handle axios errors from backend API so that they can be shown
export function errorHandler (error) {
    if (error.response) {
        const response = error.response

        // The request was made and the server responded with a status code
        // that falls out of the range of 2xx
        console.error(response.data)
        console.log(response.status)
        console.log(response.headers)

        alerts.error(response.data.errors.join('\n'))

        throw new Error(error.response.data.errors)
    } else if (error.request) {
        // The request was made but no response was received
        // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
        // http.ClientRequest in node.js
        console.log(error.request)
    } else {
        // Something happened in setting up the request that triggered an Error
        console.log('Error', error.message)
    }

    console.log(error.config)
    throw error
}
<commit_msg>Comment out extra logging on errorHandler<commit_after>import { alerts } from '../stores/alerts'

// Handle axios errors from backend API so that they can be shown
export function errorHandler (error) {
    if (error.response) {
        const response = error.response

        // The request was made and the server responded with a status code
        // that falls out of the range of 2xx

        // console.error(response.data)
        // console.log(response.status)
        // console.log(response.headers)

        alerts.error(response.data.errors.join('\n'))

        throw new Error(error.response.data.errors)
    } else if (error.request) {
        // The request was made but no response was received
        // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
        // http.ClientRequest in node.js
        console.log(error.request)
    } else {
        // Something happened in setting up the request that triggered an Error
        console.log('Error', error.message)
    }

    // console.log(error.config)
    throw error
}
<|endoftext|>


<commit_before>'use strict'

let AppDispatcher = require('../dispatcher/app-dispatcher')
let AppConstants = require('../constants/app-constants')
let AppActions = require('../actions/app-actions')
let Store = require('./store')
let CredentialsStore = require('./credentials-store')

let errors = require('../tasks/errors')
let Transition = errors.Transition
let InputRequired = errors.InputRequired
let Crash = errors.Crash

let app = require('electron').app
let path = require('path')

let Logger = require('../util/log').Logger
let log = require('../util/log')('cave-store')
let db = require('../util/db')

let library_dir = path.join(app.getPath('home'), 'Downloads', 'itch.io')
let archives_dir = path.join(library_dir, 'archives')
let apps_dir = path.join(library_dir, 'apps')

let logger = new Logger()
let opts = {logger}

const CAVE_TABLE = 'caves'

let CaveStore = Object.assign(new Store('cave-store'), {
  find: function (id) {
    return db.find_one({_table: CAVE_TABLE, _id: id})
  },

  find_for_game: function (game_id) {
    return db.find_one({_table: CAVE_TABLE, game_id: game_id})
  },

  archive_path: function (upload) {
    log(opts, `In archive_path, me = ${JSON.stringify(CredentialsStore.get_me())}`)
    return path.join(archives_dir, `${upload.id}${path.extname(upload.filename)}`)
  },

  app_path: function (cave_id) {
    return path.join(apps_dir, cave_id)
  }
})

let natural_transitions = {
  'find-upload': 'download',
  'download': 'install',
  'install': 'configure'
}

function handle_task_error (err, id, task_name) {
  if (err instanceof Transition) {
    log(opts, `[${task_name} => ${err.to}] ${err.reason}`)
    let data = err.data || {}
    setImmediate(() => queue_task(id, err.to, data))
  } else if (err instanceof InputRequired) {
    let msg = `(stub) input required by ${task_name}`
    log(opts, msg)
    AppActions.cave_progress({id, task: 'error', error: msg})
  } else if (err instanceof Crash) {
    let msg = `crashed with: ${JSON.stringify(err, null, 2)}`
    log(opts, msg)
    AppActions.cave_progress({id, task: 'idle', error: msg})
  } else {
    log(opts, err.stack || err)
    AppActions.cave_progress({id, task: 'error', error: '' + err})
  }
}

async function queue_task (id, task_name, data) {
  if (typeof data === 'undefined') {
    data = {}
  }

  let task = require(`../tasks/${task_name}`)
  let task_opts = Object.assign({}, opts, data, {
    id,
    onprogress: (state) => {
      AppActions.cave_progress({id, progress: state.percent * 0.01, task: task_name})
    }
  })
  log(opts, `starting ${task_name}`)

  AppActions.cave_progress({id, progress: 0, task: task_name})

  try {
    let res = await task.start(task_opts)
    if (task_name === 'install') {
      let cave = await CaveStore.find(id)
      if (!cave.success_once) {
        let game = await db.find_one({_table: 'games', id: cave.game_id})
        AppActions.notify(`${game.title} is ready!`)
        AppActions.cave_update(id, {success_once: true})
      }
    }

    let transition = natural_transitions[task_name]
    if (transition) throw new Transition({to: transition})

    log(opts, `task ${task_name} finished with ${JSON.stringify(res)}`)
    AppActions.cave_progress({id, progress: 0})

    if (task_opts.then) {
      queue_task(id, task_opts.then)
    } else {
      AppActions.cave_progress({id, task: 'idle'})
    }
  } catch (err) {
    handle_task_error(err, id, task_name)
  }
}

function initial_progress (record) {
  AppActions.cave_progress(Object.assign({id: record._id}, record))
  db.find_one({_table: 'games', id: record.game_id}).then(game => {
    AppActions.cave_progress({id: record._id, game})
  })
}

function queue_cave (game_id) {
  let data = { _table: CAVE_TABLE, game_id }
  db.insert(data).then((record) => {
    db.find_one({_table: 'games', id: game_id}).then((game) => {
      initial_progress(record)
      queue_task(record._id, 'download', opts)
    })
  })
}

function update_cave (_id, data) {
  return db.merge_one({_table: CAVE_TABLE, _id}, data)
}

AppDispatcher.register('cave-store', Store.action_listeners(on => {
  on(AppConstants.CAVE_QUEUE, action => {
    db.find_one({_table: CAVE_TABLE, game_id: action.game_id}).then((record) => {
      if (record) {
        if (record.launchable) {
          queue_task(record._id, 'launch')
        }
      } else {
        queue_cave(action.game_id)
      }
    })
  })

  on(AppConstants.CAVE_UPDATE, action => {
    return update_cave(action.id, action.data)
  })

  on(AppConstants.AUTHENTICATED, action => {
    return (
      db.load()
      .then(() => db.find({_table: CAVE_TABLE}))
      .each((record, i) => {
        initial_progress(record)
        setTimeout(() => {
          queue_task(record._id, 'download')
        }, i * 250)
      })
    )
  })
}))

module.exports = CaveStore
<commit_msg>Closes #60<commit_after>'use strict'

let AppDispatcher = require('../dispatcher/app-dispatcher')
let AppConstants = require('../constants/app-constants')
let AppActions = require('../actions/app-actions')
let Store = require('./store')
let CredentialsStore = require('./credentials-store')

let errors = require('../tasks/errors')
let Transition = errors.Transition
let InputRequired = errors.InputRequired
let Crash = errors.Crash

let app = require('electron').app
let path = require('path')

let Logger = require('../util/log').Logger
let log = require('../util/log')('cave-store')
let db = require('../util/db')

let library_dir = path.join(app.getPath('home'), 'Downloads', 'itch.io')
let archives_dir = path.join(library_dir, 'archives')
let apps_dir = path.join(library_dir, 'apps')

let logger = new Logger()
let opts = {logger}

const CAVE_TABLE = 'caves'

let CaveStore = Object.assign(new Store('cave-store'), {
  find: function (id) {
    return db.find_one({_table: CAVE_TABLE, _id: id})
  },

  find_for_game: function (game_id) {
    return db.find_one({_table: CAVE_TABLE, game_id: game_id})
  },

  archive_path: function (upload) {
    log(opts, `In archive_path, me = ${JSON.stringify(CredentialsStore.get_me())}`)
    return path.join(archives_dir, `${upload.id}${path.extname(upload.filename)}`)
  },

  app_path: function (cave_id) {
    return path.join(apps_dir, cave_id)
  }
})

let natural_transitions = {
  'find-upload': 'download',
  'download': 'install',
  'install': 'configure'
}

function handle_task_error (err, id, task_name) {
  if (err instanceof Transition) {
    log(opts, `[${task_name} => ${err.to}] ${err.reason}`)
    let data = err.data || {}
    setImmediate(() => queue_task(id, err.to, data))
  } else if (err instanceof InputRequired) {
    let msg = `(stub) input required by ${task_name}`
    log(opts, msg)
    AppActions.cave_progress({id, task: 'error', error: msg})
  } else if (err instanceof Crash) {
    let msg = `crashed with: ${JSON.stringify(err, null, 2)}`
    log(opts, msg)
    AppActions.cave_progress({id, task: 'idle', error: msg})
  } else {
    log(opts, err.stack || err)
    AppActions.cave_progress({id, task: 'error', error: '' + err})
  }
}

let current_tasks = {}

function set_current_task (id, data) {
  // potentially send an event here
  current_tasks[id] = data
}

async function queue_task (id, task_name, data) {
  if (typeof data === 'undefined') {
    data = {}
  }

  if (current_tasks[id]) {
    log(opts, `task already in progress for ${id}, ignoring ${task_name} request`)
    return
  }

  let task = require(`../tasks/${task_name}`)
  let task_opts = Object.assign({}, opts, data, {
    id,
    onprogress: (state) => {
      AppActions.cave_progress({id, progress: state.percent * 0.01, task: task_name})
    }
  })
  log(opts, `starting ${task_name}`)

  AppActions.cave_progress({id, progress: 0, task: task_name})

  try {
    set_current_task(id, {
      name: task_name,
      opts: task_opts
    })
    let res = await task.start(task_opts)
    set_current_task(id, null)

    if (task_name === 'install') {
      let cave = await CaveStore.find(id)
      if (!cave.success_once) {
        let game = await db.find_one({_table: 'games', id: cave.game_id})
        AppActions.notify(`${game.title} is ready!`)
        AppActions.cave_update(id, {success_once: true})
      }
    }

    let transition = natural_transitions[task_name]
    if (transition) throw new Transition({to: transition})

    log(opts, `task ${task_name} finished with ${JSON.stringify(res)}`)
    AppActions.cave_progress({id, progress: 0})

    if (task_opts.then) {
      queue_task(id, task_opts.then)
    } else {
      AppActions.cave_progress({id, task: 'idle'})
    }
  } catch (err) {
    set_current_task(id, null)
    handle_task_error(err, id, task_name)
  }
}

function initial_progress (record) {
  AppActions.cave_progress(Object.assign({id: record._id}, record))
  db.find_one({_table: 'games', id: record.game_id}).then(game => {
    AppActions.cave_progress({id: record._id, game})
  })
}

function queue_cave (game_id) {
  let data = { _table: CAVE_TABLE, game_id }
  db.insert(data).then((record) => {
    db.find_one({_table: 'games', id: game_id}).then((game) => {
      initial_progress(record)
      queue_task(record._id, 'download', opts)
    })
  })
}

function update_cave (_id, data) {
  return db.merge_one({_table: CAVE_TABLE, _id}, data)
}

AppDispatcher.register('cave-store', Store.action_listeners(on => {
  on(AppConstants.CAVE_QUEUE, action => {
    db.find_one({_table: CAVE_TABLE, game_id: action.game_id}).then((record) => {
      if (record) {
        if (record.launchable) {
          queue_task(record._id, 'launch')
        }
      } else {
        queue_cave(action.game_id)
      }
    })
  })

  on(AppConstants.CAVE_UPDATE, action => {
    return update_cave(action.id, action.data)
  })

  on(AppConstants.AUTHENTICATED, action => {
    return (
      db.load()
      .then(() => db.find({_table: CAVE_TABLE}))
      .each((record, i) => {
        initial_progress(record)
        setTimeout(() => {
          queue_task(record._id, 'download')
        }, i * 250)
      })
    )
  })
}))

module.exports = CaveStore
<|endoftext|>


<commit_before>
let spawn = require('../../util/spawn')
let glob = require('../../promised/glob')
let fs = require('../../promised/fs')

let errors = require('../errors')

let ibrew = require('../../util/ibrew')
let log = require('../../util/log')('installers/air')

let path = require('path')

// Adobe Air docs: http://help.adobe.com/en_US/air/redist/WS485a42d56cd19641-70d979a8124ef20a34b-8000.html

let MANIFEST_GLOB = '**/META-INF/AIR/application.xml'
let ID_RE = /<id>(.*)<\/id>/
let CODE_MESSAGES = {
  1: 'Successful, but restart required for completion',
  2: 'Usage error (incorrect arguments)',
  3: 'Runtime not found',
  4: 'Loading runtime failed',
  5: 'Unknown error',
  6: 'Installation canceled',
  7: 'Installation failed',
  8: 'Installation failed; update already in progress',
  9: 'Installation failed; application already installed'
}

let self = {
  install: async function (opts) {
    if (!opts.has_user_blessing) {
      throw new errors.Transition({
        to: 'ask-before-install',
        reason: `going to pop up an UAC dialog, need user's permission first`
      })
    }

    let archive_path = opts.archive_path
    let dest_path = opts.dest_path

    let spawn_opts = {
      command: 'elevate.exe',
      args: [
        archive_path, // the installer
        '-silent', // run the installer silently
        '-eulaAccepted', // let AIR install if it so wishes
        '-location', dest_path // install where we want to
      ],
      ontoken: (token) => log(opts, token)
    }
    let code = await spawn(spawn_opts)
    log(opts, `air installer exited with code ${code}`)

    if (code !== 0) {
      let message = CODE_MESSAGES[code]
      throw new Error(`AIR installer error: ${message}`)
    }
  },

  uninstall: async function (opts) {
    log(opts, `Grabbing adobe's Air Runtime Helper if needed...`)

    let dest_path = opts.dest_path
    let logger = opts.logger

    let ibrew_opts = {
      logger,
      onstatus: (msg) => log(opts, `ibrew status: ${msg}`)
    }
    await ibrew.fetch(ibrew_opts, 'arh')

    log(opts, `Locating app manifest`)

    let candidates = await glob(MANIFEST_GLOB, {cwd: dest_path})
    if (candidates.length === 0) {
      throw new Error(`Adobe AIR app manifest not found, cannot uninstall`)
    }

    log(opts, `Found app manifest at ${candidates[0]}`)

    let manifest_path = path.join(dest_path, candidates[0])
    let manifest_contents = await fs.readFileAsync(manifest_path, {encoding: 'utf8'})
    let matches = ID_RE.execute(manifest_contents)
    if (!matches) {
      throw new Error(`Could not extract app id from manifest at ${manifest_path}`)
    }

    let appid = matches[1]
    log(opts, `Found appid ${appid}, uninstalling...`)

    let spawn_opts = {
      command: 'arh',
      args: [
        '-uninstallAppSilent',
        appid
      ],
      ontoken: (tok) => log(opts, `arh: ${tok}`)
    }
    let code = await spawn(spawn_opts)
    if (code !== 0) {
      throw new Error(`arh uninstall failed with code ${code}`)
    }
  }
}

module.exports = self
<commit_msg>:bug:<commit_after>
let spawn = require('../../util/spawn')
let glob = require('../../promised/glob')
let fs = require('../../promised/fs')

let errors = require('../errors')

let ibrew = require('../../util/ibrew')
let log = require('../../util/log')('installers/air')

let path = require('path')

// Adobe Air docs: http://help.adobe.com/en_US/air/redist/WS485a42d56cd19641-70d979a8124ef20a34b-8000.html

let MANIFEST_GLOB = '**/META-INF/AIR/application.xml'
let ID_RE = /<id>(.*)<\/id>/
let CODE_MESSAGES = {
  1: 'Successful, but restart required for completion',
  2: 'Usage error (incorrect arguments)',
  3: 'Runtime not found',
  4: 'Loading runtime failed',
  5: 'Unknown error',
  6: 'Installation canceled',
  7: 'Installation failed',
  8: 'Installation failed; update already in progress',
  9: 'Installation failed; application already installed'
}

let self = {
  install: async function (opts) {
    if (!opts.has_user_blessing) {
      throw new errors.Transition({
        to: 'ask-before-install',
        reason: `going to pop up an UAC dialog, need user's permission first`
      })
    }

    let archive_path = opts.archive_path
    let dest_path = opts.dest_path

    let spawn_opts = {
      command: 'elevate.exe',
      args: [
        archive_path, // the installer
        '-silent', // run the installer silently
        '-eulaAccepted', // let AIR install if it so wishes
        '-location', dest_path // install where we want to
      ],
      ontoken: (token) => log(opts, token)
    }
    let code = await spawn(spawn_opts)
    log(opts, `air installer exited with code ${code}`)

    if (code !== 0) {
      let message = CODE_MESSAGES[code]
      throw new Error(`AIR installer error: ${message}`)
    }
  },

  uninstall: async function (opts) {
    log(opts, `Grabbing adobe's Air Runtime Helper if needed...`)

    let dest_path = opts.dest_path
    let logger = opts.logger

    let ibrew_opts = {
      logger,
      onstatus: (msg) => log(opts, `ibrew status: ${msg}`)
    }
    await ibrew.fetch(ibrew_opts, 'arh')

    log(opts, `Locating app manifest`)

    let candidates = await glob(MANIFEST_GLOB, {cwd: dest_path})
    if (candidates.length === 0) {
      throw new Error(`Adobe AIR app manifest not found, cannot uninstall`)
    }

    log(opts, `Found app manifest at ${candidates[0]}`)

    let manifest_path = path.join(dest_path, candidates[0])
    let manifest_contents = await fs.readFileAsync(manifest_path, {encoding: 'utf8'})
    let matches = ID_RE.exec(manifest_contents)
    if (!matches) {
      throw new Error(`Could not extract app id from manifest at ${manifest_path}`)
    }

    let appid = matches[1]
    log(opts, `Found appid ${appid}, uninstalling...`)

    let spawn_opts = {
      command: 'arh',
      args: [
        '-uninstallAppSilent',
        appid
      ],
      ontoken: (tok) => log(opts, `arh: ${tok}`)
    }
    let code = await spawn(spawn_opts)
    if (code !== 0) {
      throw new Error(`arh uninstall failed with code ${code}`)
    }
  }
}

module.exports = self
<|endoftext|>


<commit_before>if (!String.prototype.includes) {
    String.prototype.includes = function() {
        return String.prototype.indexOf.apply(this, arguments) !== -1;
    };
}

var stringUtils = {
    format: function(value,args){
        return value.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
                ;
        });
    },

    formatProperty: function(property, indexes){
        if(!indexes || indexes.length == 0 || property == ''){
            return property;
        }

        var propertyPaths = property.split('.');

        var j = indexes.length-1;

        for(var i = propertyPaths.length-1; i>=0; i--){
            if(propertyPaths[i] == '#' && j >= 0){
                propertyPaths[i] = indexes[j];
                j--;
            }else if(propertyPaths[i] == '$' || stringUtils.isNumeric(propertyPaths[i])){
                j--;
            }
        }

        return propertyPaths.join('.');
    },

    padLeft: function a (value, len, char) {
        if (typeof char == 'undefined' || char === null) {
            char = ' ';
        }

        var str = String(value);

        if (str.length < len) {
            return new Array(len - str.length + 1).join(char) + str;
        }
        return str;
    },

    isNumeric: function(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    },

    replaced: {
        '+': '%2B'
    },

    joinDataForQuery: function(data){
        var result = [];
        var that = this;

        for(var k in data){
            var p = _.isString(data[k]) ? data[k].replace(/[\+]/g, function (c) {
                return that.replaced[c] || c;
            }) : data[k];

            result.push(k + '=' + p);
        }

        return result.join('&');
    }
};

window.InfinniUI.StringUtils = stringUtils;

function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
<commit_msg>fix guid function<commit_after>if (!String.prototype.includes) {
    String.prototype.includes = function() {
        return String.prototype.indexOf.apply(this, arguments) !== -1;
    };
}

var stringUtils = {
    format: function(value,args){
        return value.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
                ;
        });
    },

    formatProperty: function(property, indexes){
        if(!indexes || indexes.length == 0 || property == ''){
            return property;
        }

        var propertyPaths = property.split('.');

        var j = indexes.length-1;

        for(var i = propertyPaths.length-1; i>=0; i--){
            if(propertyPaths[i] == '#' && j >= 0){
                propertyPaths[i] = indexes[j];
                j--;
            }else if(propertyPaths[i] == '$' || stringUtils.isNumeric(propertyPaths[i])){
                j--;
            }
        }

        return propertyPaths.join('.');
    },

    padLeft: function a (value, len, char) {
        if (typeof char == 'undefined' || char === null) {
            char = ' ';
        }

        var str = String(value);

        if (str.length < len) {
            return new Array(len - str.length + 1).join(char) + str;
        }
        return str;
    },

    isNumeric: function(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    },

    replaced: {
        '+': '%2B'
    },

    joinDataForQuery: function(data){
        var result = [];
        var that = this;

        for(var k in data){
            var p = _.isString(data[k]) ? data[k].replace(/[\+]/g, function (c) {
                return that.replaced[c] || c;
            }) : data[k];

            result.push(k + '=' + p);
        }

        return result.join('&');
    }
};

window.InfinniUI.StringUtils = stringUtils;
window.InfinniUI.guid = guid;

function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
<|endoftext|>


<commit_before>

$(document).ready(function () {

    /************************
     * CONNEXION SUBMIT EVENT
     ***/
      $(".connexion").submit(function () {

            var form = $(this);
            $(".form_error", form).hide();

            var data = form.serializeArray();
            $.each(data, function (key, o) {
                  if(o.name == "password")
                        data[key].value = $.md5(data[key].value);
            });

            $.ajax({
                  data: data,
                  type: "POST",
                  dataType: "json",
                  url: "./",
                  success: function (data) {

                        var $form  = $(".connexion");

                        // unlock input
                        $(":input", $form).attr("disabled", false);

                        if(data.statut == false) {
                              $(":input[type=password]", $form).val("");
                              showFormError($form, 1);
                        } else
                              window.location = "index.php";
                  }
            });

            // lock input
            $(":input", form).attr("disabled", true);

            return false;

      });

      /***********
       * Templates
       ***/
      // error
      $.get("./appinc/template/tmpl/error-tooltip.tmpl", {}, function(tmpl) {
            $.template( "error-tooltip", tmpl);
            $("#errors").html();

            if(err.length) {

                for(var i in err) {
                      var tooltip  = {
                            msg : err[i].msg
                            };
                      $.tmpl("error-tooltip", tooltip).appendTo( $("#errors") );
                }

                showErrorTooltip(0);
            }

      } );

      /**************************
       * INSCRIPTION SUBMIT EVENT
       ***/
      $(".inscription").submit(function () {

            var form = $(this);
            $(".form_error", form).hide();

            if( $(":input[name=email]", form).val() != ""
            &&  $(":input[name=password_1]", form).val() != ""
            &&  $(":input[name=password_2]", form).val() != "" ) {

                  if( $(":input[name=password_1]", form).val() == $(":input[name=password_2]", form).val() ) {

                        var pattern=/^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/;
                        if(pattern.test( $(":input[name=email]", form).val() )){

                              var data = form.serializeArray();
                              $.each(data, function (key, o) {
                                    if(o.name == "password_1" || o.name == "password_2")
                                          data[key].value = $.md5(data[key].value);
                              });

                              $.ajax({
                                    data: data,
                                    type: "POST",
                                    dataType: "json",
                                    url: "./",
                                    success: function (data) {

                                          var $form  = $(".inscription");

                                          // unlock input
                                          $(":input", $form).attr("disabled", false);

                                          if(data.statut == false) {
                                                showFormError($form, data.message);
                                          } else {

                                                // empty the fields
                                                $(":input", $form).empty();

                                                // remove the formulaire
                                                $form.removeClass("hidden");
                                                signUp();

                                                showErrorTooltip(data.message);

                                          }

                                    }
                              });

                              // lock input
                              $(":input", form).attr("disabled", true);

                        } else
                              // Form is incomplete.
                              showFormError(form, 3);

                  }else
                        // Passwords are not matching.
                        showFormError(form, 2);

            } else
                  // Form is incomplete
                  showFormError(form, 1);

            return false;

      });

      /********************
     * USER ACTIVITY BAND
     ***/
      $(".user_status .label").mouseenter(function () {

            $(".user_activity").stop().css({
                  zIndex: 888
            });

            $(".user_activity .headband").stop().css({
                  display:"block",
                  marginRight: -1 * $(".user_activity .headband").outerWidth()
            });

            $(".user_activity .headband").stop().animate({
                  marginRight: 0
            }, 700, 'easeOutBounce');

      });

      $(".user_corner").mouseleave(function () {

            $(".user_activity .headband").stop().animate({
                  display:"block",
                  marginRight: -1 * $(".user_activity .headband").outerWidth()
            }, 700, 'easeOutBounce', function() {

                  $(".user_activity").stop().css({
                        zIndex: 666
                  });

            });

      });

      /*********************
     * HIDE FREEBASE DATA
     ***/

      $(".deroule").tipsy({
            gravity:'n',
            opacity:1
      }).click(function () {

            if( $(this).hasClass("open") ) {
                  $(this).removeClass("open");
                  $(".hiddable").slideUp(400, function () {
                        $(this).css("display", "none");
                  });
            } else {
                  $(this).addClass("open");
                  $(".hiddable").slideDown(400);
            }

      });

      initPlaceholder();

      if( typeof $().center == "function") $(".center").center();

      $(".trust_level").tipsy({
            gravity:'ne',
            opacity:1
      });

      $("#partenaires ul li a").tipsy({
            gravity:'sw',
            opacity:1,
            offset: 20
      });

      $(".review,.add,.visualise", ".main_menu").tipsy({
            gravity:'s',
            opacity:1
      });
      $(".review,.add,.visualise", ".up_menu").tipsy({
            gravity:'n',
            opacity:1
      });

      $(".showFooter .trigger").mouseenter(function () {
            showFooter();
      });

      $("footer").mouseenter(function () {
            showFooter();
      });

      $("#workspace").mouseenter(function () {
            hideFooter();
      });

      $("#app").mouseleave(function () {
            hideFooter();
      });

      if( RR_UTILS.isApple() )  {
            $(".showFooter .trigger").click(function () {
                  showFooter();
            });
            $("footer").click(function () {
                  showFooter();
            });
            $("#workspace").click(function () {
                  hideFooter();
            });
      }

      $("#errors .tooltip .close").live("click", function () {
            $(this).parent().hide();
      });

});

function initPlaceholder() {

      /**********************
     * Placeholder on input
     ***/
      $(":input").each(function (i) {
            if( $(this).attr("placeholder") != "" && $(this).val() == "") {
                  $(this).val( $(this).attr("placeholder") )
                  .addClass("placeholder")
                  .focus(function () {
                        if( $(this).attr("placeholder") == $(this).val() )
                              $(this).val("").removeClass("placeholder");
                  })
                  .blur(function () {
                        if( $(this).val() == "" )
                              $(this).val( $(this).attr("placeholder")  ).addClass("placeholder");
                  });
            }
      });
}

function signUp() {

      if( $(".inscription").hasClass("hidden") ) {

            // remove class
            $(".inscription").removeClass("hidden");

            // pre-hide the sign up block
            $(".inscription").css({
                  marginTop: -1 * $(".inscription").outerHeight() - 20,
                  display: "block",
                  opacity: 0
            });

            // show form
            $(".inscription").animate({
                  marginTop: 0,
                  opacity: 1
            }, 700, 'easeOutBounce');

      } else {

            // add class
            $(".inscription").addClass("hidden");

            // hide inscription form
            $(".inscription").animate({
                  marginTop: -1 * $(".inscription").outerHeight() - 20,
                  display: "none",
                  opacity: 0
            }, 700, 'easeOutBounce');

      }

}

function showFormError(form, err) {

      form.effect("shake", {}, 70);

      $(".form_error", form).hide();

      if(typeof err == "string")
            $(".form_error:first", form).html(err).show();
      else
            $(".form_error:eq("+err+")", form).show();

}

function showErrorTooltip(i) {

      // i is a number
      if( !isNaN(i) ) {

          if(i < err.length) {
              $("#errors .tooltip:eq("+i+")").css({
                    display:"block",
                    position: "relative",
                    top: -20 - $("#errors .tooltip:eq("+i+")").outerHeight()
              }).animate({
                    top:0
              },
              1200,
              'easeOutElastic',
              function () {
                    if($("#errors .tooltip:eq("+(i+1)+")").length > 0)
                          showErrorTooltip(i+1);
              });

          }

      // i is a message
      } else if(typeof i == "string") {

          $.tmpl("error-tooltip", {msg : i} ).appendTo( $("#errors") );

          $("#errors .tooltip:last").css({

                                            display:"block",
                                            position: "relative",
                                            top: -200

                                         }).animate({top:0}, 1200, 'easeOutElastic');

      }
}

// Affiche le code d'embed pour les apps
function doEmbed() {

      $("#mask").fadeIn(500);
      $(".inputEmbed").fadeIn(500);

      // cache l'embed au click sur le masque
      $("#mask").click(function () {
            $(".inputEmbed").fadeOut(500);
      });
}

function showFooter() {

      if( RR_UTILS.isApple() ) {
            $(".showFooter .trigger").stop().css({
                  opacity:0
            });
            $(".showFooter").stop().css({
                  marginTop:-85
            });
      } else {
            $(".showFooter").stop().animate({
                  marginTop:-85
            }, 500, function () {
                  $(".showFooter .trigger").stop().animate({
                        opacity:0,
                        marginTop:30,
                        marginBottom:-100
                  }, 250);
            });
      }

}

function hideFooter() {

      if( RR_UTILS.isApple() ) {

            $(".showFooter .trigger").stop().css({
                  opacity:1
            });

            $(".showFooter").stop().css( {
                  marginTop:-30
            } );

      } else {

            $(".showFooter .trigger").stop().animate({
                  opacity:1,
                  marginTop:-36,
                  marginBottom:0
            }, 250);

            $(".showFooter").stop().animate({
                  marginTop:-30
            }, 500);
      }
}
<commit_msg>Clean code<commit_after>(function(window, $, undefined) {

    // CURRENT APP INSTANCE
    var app = this;

    /**
     * Init the page
     * @function
     * @public
     */
    app.init = function() {

        // CONNEXION SUBMIT EVENT
        $(".connexion").live("submit", app.submitConnexion);

        // CONNEXION SUBMIT EVENT
        $(".inscription").live("submit", app.submitInscription);

        // SHOW USER ACTIVITY BAND
        $(".user_status .label").mouseenter(app.showUserActivity);

        // HIDE USER ACTIVITY BAND
        $(".user_corner").mouseleave(app.hideUserActivity);

        // INIT PLACEHOLER
        app.initPlaceholder();

        // INIT TIPSY
        app.tipsy();

        // LOAD TEMPLATES
        app.loadTemplate();

        // CLOSE ERROR MESSAGE
        $("#errors .tooltip .close").live("click", function () {
              $(this).parent().hide();
        });

        // EXPLORE FREEBASE TOPIC
        $(".fb-topic").freebaseTopic();

    };

    /**
     * Show user activity
     * @function
     * @public
     */
    app.showUserActivity = function() {

        $(".user_activity").stop().css({
              zIndex: 888
        });

        $(".user_activity .headband").stop().css({
              display:"block",
              marginRight: -1 * $(".user_activity .headband").outerWidth()
        });

        $(".user_activity .headband").stop().animate({
              marginRight: 0
        }, 700, 'easeOutBounce');
    }

    /**
     * Hide user activity
     * @function
     * @public
     */
    app.hideUserActivity = function() {

        $(".user_activity .headband").stop().animate({
              display:"block",
              marginRight: -1 * $(".user_activity .headband").outerWidth()
        }, 700, 'easeOutBounce', function() {

              $(".user_activity").stop().css({
                    zIndex: 666
              });

        });

    }

    /**
     * Submit Inscription form
     * @function
     * @public
     */
    app.submitInscription = function() {

        var form = $(this);
        $(".form_error", form).hide();

        if( $(":input[name=email]", form).val() != ""
            &&  $(":input[name=password_1]", form).val() != ""
            &&  $(":input[name=password_2]", form).val() != "" ) {

            if( $(":input[name=password_1]", form).val() == $(":input[name=password_2]", form).val() ) {

                var pattern=/^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/;
                if(pattern.test( $(":input[name=email]", form).val() )){

                    var data = form.serializeArray();
                    $.each(data, function (key, o) {
                        if(o.name == "password_1" || o.name == "password_2")
                            data[key].value = $.md5(data[key].value);
                    });

                    $.ajax({
                        data: data,
                        type: "POST",
                        dataType: "json",
                        url: "./",
                        success: function (data) {

                            var $form  = $(".inscription");

                            // unlock input
                            $(":input", $form).attr("disabled", false);

                            if(data.statut == false) {
                                app.showFormError($form, data.message);
                            } else {

                                // empty the fields
                                $(":input", $form).empty();

                                // remove the formulaire
                                $form.removeClass("hidden");
                                app.signUp();

                                app.showErrorTooltip(data.message);

                            }

                        }
                    });

                    // lock input
                    $(":input", form).attr("disabled", true);

                } else
                    // Form is incomplete.
                    app.showFormError(form, 3);

            }else
                // Passwords are not matching.
                app.showFormError(form, 2);

        } else
            // Form is incomplete
            app.showFormError(form, 1);

        return false;
    };

    /**
     * Submit Connexion form
     * @function
     * @public
     */
    app.submitConnexion = function() {

        var form = $(this);
        $(".form_error", form).hide();

        var data = form.serializeArray();
        $.each(data, function (key, o) {
              if(o.name == "password")
                    data[key].value = $.md5(data[key].value);
        });

        $.ajax({
              data: data,
              type: "POST",
              dataType: "json",
              url: "./",
              success: function (data) {

                    var $form  = $(".connexion");

                    // unlock input
                    $(":input", $form).attr("disabled", false);

                    if(data.statut == false) {
                          $(":input[type=password]", $form).val("");
                          app.showFormError($form, 1);
                    } else
                        window.location = "index.php";

              }
        });

        // lock input
        $(":input", form).attr("disabled", true);

        return false;
    };

    /**
     * Init placeholer attributes in inputs
     * @function
     * @public
     */
    app.initPlaceholder = function() {

          // for each input...
          $(":input").each(function (i) {

                // with a placeholder attribut
                if( $(this).attr("placeholder") != "" && $(this).val() == "") {
                      $(this).val( $(this).attr("placeholder") )
                      .addClass("placeholder")
                      .focus(function () {
                            if( $(this).attr("placeholder") == $(this).val() )
                                  $(this).val("").removeClass("placeholder");
                      })
                      .blur(function () {
                            if( $(this).val() == "" )
                                  $(this).val( $(this).attr("placeholder")  ).addClass("placeholder");
                      });
                }
          });
    };

    /**
     * Show the inscription form
     * @function
     * @public
     */
    app.signUp = function() {

          $(".inscription").toggleClass("hidden");

    };

    /**
     * Load template files
     * @function
     * @public
     */
    app.loadTemplate = function() {

        // error
        $.get("./appinc/template/tmpl/error-tooltip.tmpl", {}, function(tmpl) {

            $.template( "error-tooltip", tmpl);
            $("#errors").html();

            if(window.err.length) {

                for(var i in window.err) {
                      var tooltip  = {
                            msg : window.err[i].msg
                            };
                      $.tmpl("error-tooltip", tooltip).appendTo( $("#errors") );
                }

                app.showErrorTooltip(0);
            }

        });

    };

    /**
     * Initialize tipsy tooltips
     * @function
     * @public
     */
    app.tipsy = function() {

        $(".trust_level").tipsy({
            gravity:'ne',
            opacity:1
        });

        $("#partenaires ul li a").tipsy({
            gravity:'sw',
            opacity:1,
            offset: 20
        });

        $(".review,.add,.visualise", ".main_menu").tipsy({
            gravity:'s',
            opacity:1
        });
        $(".review,.add,.visualise", ".up_menu").tipsy({
            gravity:'n',
            opacity:1
        });

    };

    /**
     * Show errors in the form
     * @function
     * @public
     *
     * @param jQuery $form
     * @param string err
     */
    app.showFormError = function($form, err) {

          $form.effect("shake", {}, 70);

          $(".form_error", $form).hide();

          if(typeof err == "string")
                $(".form_error:first", $form).html(err).show();
          else
                $(".form_error:eq("+err+")", $form).show();

    };

    /**
     * Show global error number i
     * @function
     * @public
     *
     * @param integer i
     */
    app.showErrorTooltip = function(i) {

          // i is a number
          if( !isNaN(i) ) {

              if(i < err.length) {
                  $("#errors .tooltip:eq("+i+")").css({
                        display:"block",
                        position: "relative",
                        top: -20 - $("#errors .tooltip:eq("+i+")").outerHeight()
                  }).animate({
                        top:0
                  },
                  1200,
                  'easeOutElastic',
                  function () {
                        if($("#errors .tooltip:eq("+(i+1)+")").length > 0)
                              app.showErrorTooltip(i+1);
                  });

              }

          // i is a message
          } else if(typeof i == "string") {

              $.tmpl("error-tooltip", {msg : i} ).appendTo( $("#errors") );

              $("#errors .tooltip:last").css({ display:"block",
                                               position: "relative",
                                               top: -200
                                             }).animate({top:0}, 1200, 'easeOutElastic');

         }
    };

    // WHEN THE DOCUMENT IS READY, INIT THE APP
    $(document).ready(app.init);

})(window, jQuery);

<|endoftext|>