<commit_before>var jokesURL = "./destination/chucknorrisjokes/jokes/random?limitTo=[nerdy]";

// configure the app
var app = new Vue({
    el: '#app',
    data: {
        message: '',
        id: ''
    },
    methods: {
        onJokeButtonClick: function() {
            getJoke();
        }
    }
});

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    // because the JavaScript fetch API did not work... 503?
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error('Network Error'));
    };

    // Make the request
    req.send();
  });
}

function getJoke() {
    get(jokesURL).then(function(response) {

	  var responseJSON = "";
	    try {
            responseJSON = JSON.parse(response);
        } catch (e) {
            console.log('Error parsing the JSON response: ', e);
            app.message = '-- Error parsing jokes response. --';
            return;
        }
        // the joke is stored inside the value object with the joke property
        if (responseJSON && responseJSON.value) {

            app.message = responseJSON.value.joke || '-- no joke --';
            app.id = responseJSON.value.id || '';
        }
	}, function(error) {
		app.message = '-- Failed loading jokes! --';
	  console.error('Failed loading jokes!', error);
	});
}

// when starting the app load a joke
getJoke();<commit_msg>delete app id when no joke was loaded<commit_after>var jokesURL = "./destination/chucknorrisjokes/jokes/random?limitTo=[nerdy]";

// configure the app
var app = new Vue({
    el: '#app',
    data: {
        message: '',
        id: ''
    },
    methods: {
        onJokeButtonClick: function() {
            getJoke();
        }
    }
});

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    // because the JavaScript fetch API did not work... 503?
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error('Network Error'));
    };

    // Make the request
    req.send();
  });
}

function getJoke() {
    get(jokesURL).then(function(response) {

	  var responseJSON = "";
	    try {
            responseJSON = JSON.parse(response);
        } catch (e) {
            console.log('Error parsing the JSON response: ', e);
            app.message = '-- Error parsing jokes response. --';
            return;
        }
        // the joke is stored inside the value object with the joke property
        if (responseJSON && responseJSON.value) {

            app.message = responseJSON.value.joke || '-- no joke --';
            app.id = responseJSON.value.id || '';
        }
	}, function(error) {
		app.message = '-- Failed loading jokes! --';
		app.id = '-';
	  console.error('Failed loading jokes!', error);
	});
}

// when starting the app load a joke
getJoke();<|endoftext|>


<commit_before>'use strict';
var AWS = require('aws-sdk');
AWS.config.region = 'eu-central-1';

var ec2 = new AWS.EC2();
var route53 = new AWS.Route53();

// 1- Read userData file
var fs = require('fs');
var bitmap = fs.readFileSync('userdata.sh');
var userData = new Buffer(bitmap).toString('base64');

var params = {
  ImageId: 'ami-08df3d67', // Docker + MYSQL
  InstanceType: 't2.micro',
  MinCount: 1, MaxCount: 1,
  SecurityGroups: ["SSH+Mysql"],
  KeyName:"EC2-Server",
	UserData:userData
};

var dataVolumeID = "vol-d178e56b"; // The ID of the DATA EBS volume

/*
 * HELPER FUNCTIONS
 */
function detachVolume(instanceId){
	ec2.detachVolume({
			VolumeId: dataVolumeID,
			Force: true
		}, function(err, data) {
	if (err) console.log(err, err.stack); // an error occurred
	else // Attach EBS to NEW istance
		attachVolume(instanceId);
	});
}

function attachVolume(instanceId){
	ec2.waitFor("volumeAvailable", {VolumeIds:[dataVolumeID]}, function(err,data) {
			ec2.attachVolume({
					Device: '/dev/xvdf',
					InstanceId: instanceId,
					VolumeId: dataVolumeID,
				}, function(err, data) {
				if (err) console.log(err, err.stack); // an error occurred
				else {
					console.log("DATA volume attached succesfully");
					callback("Completed");
				}
			});
	}); //End wait for volumeAvailable
}

exports.handler = (event, context, callback) => {
   // Create the instance
    ec2.runInstances(params, function(err, data) {
      if (err) { console.log("Could not create instance", err); return; }

      var instanceId = data.Instances[0].InstanceId;
      console.log("Created instance " + instanceId);

    	ec2.waitFor('instanceRunning', {InstanceIds:[instanceId]}, function(err, data) {
    		console.log("Instance is running.");
    		// get EBS state
    		ec2.describeVolumes({VolumeIds:[dataVolumeID]},function(err,data){
    			var volumeState = data.Volumes[0].State
    			console.log("DATA volume is in " + volumeState + " state");
    			if (volumeState == "in-use")
    				detachVolume(instanceId);
    			else
    				attachVolume(instanceId);
    		});

    		//Update ROUTE53 entry to new server
    		//1- Get public DNS
    		ec2.describeInstances({InstanceIds:[instanceId]},function(err,data){
    			var instanceDNS = data.Reservations[0].Instances[0].PublicDnsName
    			//2- Update
    			var params = {
    				ChangeBatch: {
    					Changes: [{
    						  Action: 'UPSERT', // IF not present insert else update
    						  ResourceRecordSet: {
    						    Name: 'server.abeltra.me.',
    						    Type: 'CNAME',
    						    ResourceRecords: [{
    						        Value: instanceDNS //The new ip of the instance
    						    }],
    						    TTL: 60,
    						  }
    						}]
    				},
    				HostedZoneId: 'Z79DT7EWNW7FT'
    			};
    			route53.changeResourceRecordSets(params, function(err, data) {
    				if (err) console.log(err, err.stack); // an error occurred
    				else     console.log("Updated ROUTE53 server.abeltra.me with ",instanceDNS);
    			});
    		});
    	}); // End wait for instanceRunning
    });
};
<commit_msg>Fixed the report to AWS<commit_after>'use strict';
var AWS = require('aws-sdk');
AWS.config.region = 'eu-central-1';

var ec2 = new AWS.EC2();
var route53 = new AWS.Route53();

// 1- Read userData file
var fs = require('fs');
var bitmap = fs.readFileSync('userdata.sh');
var userData = new Buffer(bitmap).toString('base64');

var params = {
  ImageId: 'ami-08df3d67', // Docker + MYSQL
  InstanceType: 't2.micro',
  MinCount: 1, MaxCount: 1,
  SecurityGroups: ["SSH+Mysql"],
  KeyName:"EC2-Server",
	UserData:userData
};

var dataVolumeID = "vol-d178e56b"; // The ID of the DATA EBS volume

/*
 * HELPER FUNCTIONS
 */
function detachVolume(instanceId,cb){
	ec2.detachVolume({
			VolumeId: dataVolumeID,
			Force: true
		}, function(err, data) {
		if (err) console.log(err, err.stack); // an error occurred
		else{
			console.log("Detached volume");
			cb();
		}
	});
}

function attachVolume(instanceId,cb){
	ec2.waitFor("volumeAvailable", {VolumeIds:[dataVolumeID]}, function(err,data) {
		ec2.attachVolume({
				Device: '/dev/xvdf',
				InstanceId: instanceId,
				VolumeId: dataVolumeID,
			}, function(err, data) {
			if (err) console.log(err, err.stack); // an error occurred
			else {
				console.log("Detached volume");
				cb();
			}
		});
	}); //End wait for volumeAvailable
}

exports.handler = (event, context, cbLambda) => {
   // Create the instance
    ec2.runInstances(params, function(err, data) {
      if (err) { console.log("Could not create instance", err); return; }

      var instanceId = data.Instances[0].InstanceId;
      console.log("Created instance " + instanceId);

    	ec2.waitFor('instanceRunning', {InstanceIds:[instanceId]}, function(err, data) {
    		console.log("Instance is running.");
    		// get EBS state
    		ec2.describeVolumes({VolumeIds:[dataVolumeID]},function(err,data){
    			var volumeState = data.Volumes[0].State
    			console.log("DATA volume is in " + volumeState + " state");
    			if (volumeState == "in-use")
    				detachVolume(instanceId,function(){
						attachVolume(instanceId,function(){
							cbLambda(done,"Completato lo script")
						})
					});
    			else
					attachVolume(instanceId,function(){
						cbLambda(done,"Completato lo script")
					})
    		});

    		//Update ROUTE53 entry to new server
    		//1- Get public DNS
    		ec2.describeInstances({InstanceIds:[instanceId]},function(err,data){
    			var instanceDNS = data.Reservations[0].Instances[0].PublicDnsName
    			//2- Update
    			var params = {
    				ChangeBatch: {
    					Changes: [{
    						  Action: 'UPSERT', // IF not present insert else update
    						  ResourceRecordSet: {
    						    Name: 'server.abeltra.me.',
    						    Type: 'CNAME',
    						    ResourceRecords: [{
    						        Value: instanceDNS //The new ip of the instance
    						    }],
    						    TTL: 60,
    						  }
    						}]
    				},
    				HostedZoneId: 'Z79DT7EWNW7FT'
    			};
    			route53.changeResourceRecordSets(params, function(err, data) {
    				if (err) console.log(err, err.stack); // an error occurred
    				else     console.log("Updated ROUTE53 server.abeltra.me with ",instanceDNS);
    			});
    		});
    	}); // End wait for instanceRunning
    });
};
<|endoftext|>


<commit_before>// Structure of items.
//var items = [{
//    id: "",
//    entityType: "",
//    rarity: 1,
//    type: "",
//    subType: "",
//    ts: 0,
//    plus: 0,
//    ageLevel: 0,
//    handed: 1,
//    stats: {
//        hp: 0,
//        attackMin: 0,
//        attackMax: 0,
//        defense: 0,
//        overkill: 0,
//        heal: 0,
//        hpBonus: 0
//    },
//    name: "", // {Helmet, Armor, Gloves, Leggings, Boots, Sword, 2-handed Sword, Bow, Crossbow, Wand, Staff, Shield}
//
//}];

/** ============= Battle INF Script to End All Scripts ==========
 * Authored by Sam 'Halithor' Marquart.
 * Licenced under MIT (https://opensource.org/licenses/MIT).
 *
 * Features:
 * - Sells items below a threshold.
 * - Crafts new items into equipped items and, optionally, inventory items.
 *      + Inventory items is useful for getting higher rarity gear to be more powerful than current gear
 * - Equips items that are better than currently equipped items.
 * - Sells items that have reached maximum Plus, and aren't better than the currently equipped item of that type.
 * - Dips all of your items into the fountain, automagically, to increase the age modifiers.
 */

// Settings for the game. Edit these to fit your character better.
var settings = {
    version: 1.0,
    sellBelow: 2, // The threshold below which we automatically sell (exclusive), without combining. Increase this as you like.
    keepAbove: 4, // The rarity above which we DO NOT ever auto sell (exclusive).
    craftInventory: true, // Whether or not to craft items in your inventory.
    sellDuplicateInventory: true, // If we should sell any duplicates of a given item type in the inventory, and only keep the strongest item.
    forceEquipHighestStrength: false // If you always want to equip the highest rarity, no matter the stats. I recommend this to be true if you don't craft the inventory.
};

var _rarities = ["None", "Gray", "Green", "Blue", "Red", "Orange", "Purple", "Teal"];
var _ages = ["Worn" , "Fine", "Refined", "Aged", "Exotic", "Famous", "Master", "Heroic", "Ancient", "Fabled", "Ascended", "Legendary", "Eternal"];

function postMessage(text) {
    console.log(text);
    API.notifications.create("" + text, 10);
}

// String that displays most info about an item.
function getItemString(item) {
    return '' + item.rarity + "." + item.mod + " " + _ages[item.ageLevel] + " " + item.name  + " +" + item.plus;
}

// Calculates the relative starting strength of an item.
function getItemStrength(item) {
    return (item.mod * 2) + item.rarity;
}

function isItemAtMaxPlus(item) {
    return item.plus >= (5 + item.rarity * 5);
}

function isSameItemType(first, second) {
    return first.type == second.type && first.subType == second.subType
}

// Returns if two items are compatible for crafting.
function canCraftItems(first, second) {
    return isSameItemType(first, second)
        && candidate.rarity == secondary.rarity
        && candidate.mod == secondary.mod;
}

// Tries to find a good item from items for secondary to combined into. Picks the first one found.
function findPrimaryCraft(items, secondary) {
    for (var j = 0; j < items.length; j++) {
        var candidate = items[j];
        if (canCraftItems(candidate, secondary) && !isItemAtMaxPlus(candidate)) {
            return candidate;
        }
    }
    return undefined;
}

// Find the item equipped matching the given item.
function findEquipped(primary) {
    var equipment = ScriptAPI.$user.character.equipment;
    for (var i in equipment) {
        var candidate = equipment[i];
        if (isSameItemType(primary, candidate)) {
            return candidate;
        }
    }
    return undefined;
}

// Returns true if first is better than second. False otherwise.
// Does not care about rarity, age, etc. Purely based on stats.
// This is one of the things you can change to value items differently!
function isItemBetter(first, second) {
    if (!isSameItemType(first, second)) {
        return false; // Don't even compare if not the same.
    }

    if (first.type == "weapon") {
        // Damage consideration
        var damageFirst = (first.stats.attackMax + first.stats.attackMin) / 2;
        var damageSecond = (second.stats.attackMax + second.stats.attackMin) / 2;
        var damageRatio = damageSecond > 0 ? damageFirst / damageSecond : 1.0;
        // Overkill consideration
        var overkillDiff = first.stats.overkill - second.stats.overkill;
        // Healing ratio.
        var healRatio =  second.stats.heal > 0 ? (first.stats.heal / second.stats.heal) : 1.0;
        var armorRatio = second.stats.defense > 0 ? first.stats.defense / second.stats.defense : 1.0;
        var hpBonusDiff = (first.hpBonus - second.hpBonus);
        return damageRatio + healRatio + armorRatio + (overkillDiff/15) + (hpBonusDiff/50) > 3.0;
    } else {
        // Everything that's not a weapon is armor.
        var armorRatio = first.stats.defense / second.stats.defense;
        var hpBonusDiff = (first.hpBonus - second.hpBonus);
        return armorRatio + (hpBonusDiff/50) > 1.0;
    }
}

function isItemStronger(first, second) {
    return getItemStrength(first) > getItemStrength(second);
}

// Sells an item if it's at the max level.
function sellIfMax(item) {
    if (isItemAtMaxPlus(item) && item.rarity <= settings.keepAbove) {
        postMessage("Selling " + getItemString(item));
        API.inventory.sell(item);
    }
}

// Tries to equip the item if better. Returns the unequiped item if it works, false otherwise.
function equipIfBetter(item, callback) {
    var equip = findEquipped(item);

    if (equip && (isItemBetter(item, equip) || (settings.forceEquipHighestStrength && isItemStronger(item, equip)) ) ) {
        postMessage("Changed equipped " + equip.type + ":" + equip.subType);
        API.inventory.unequip(equip, function() {
            API.inventory.equip(item, function() {
                callback(equip);
            });
        });
    }
    if (callback) {
        callback(false);
    }
}

// Get a sorted list of the inventory items.
var inventory = ScriptAPI.$user.inventory.items.sort(function (a, b) {
    if (getItemStrength(a) == getItemStrength(b)) {
        if (a.plus == b.plus) {
            if (a.ageLevel == b.ageLevel) {
                return 0;
            } else {
                return a.ageLevel > b.ageLevel ? -1 : 1;
            }
        } else {
            return a.plus > b.plus ? -1 : 1;
        }
    } else {
        return getItemStrength(a) > getItemStrength(b) ? -1 : 1;
    }
});

// Get the equipment
var equipment = ScriptAPI.$user.character.equipment;

items.forEach(function (item) {

    if (item.rarity < settings.sellBelow && !(item.rarity > settings.keepAbove)) {
        postMessage('Selling ' + getItemString(item));
        API.inventory.sell(item);
        return;
    }

    // Now we want to combine the item with the inventory into more powerful items. First, we want to upgrade your currently
    // equipped items fully. Then we want to try to combine between items in your inventory. After combining, we look to see
    // if any of the items we have are better than equipped, if so, switch them. Finally, if anything has
    // reached the max Plus value that it can, and it isn't equipped,  sell it.

    // Find a good candidate to craft this item into.
    var isEquipped = false;
    var primary = findPrimaryCraft(equipment, item);
    if (primary) isEquipped = true;

    if (!primary && settings.craftInventory) {
        primary = findPrimaryCraft(inventory, item);
    }

    if (primary) {
        postMessage("Crafting " + getItemString(primary) + (isEquipped ? " [equipped]" : " [inventory]") + " with " + getItemString(item));
        API.inventory.craft(primary, item);

        // Primary has now been upgraded. Compare it to the currently equipped piece of equipment, and if it wins, equip it.
        if (!isEquipped) {
            equipIfBetter(primary, function(unequippedItem) {
                // If we changed equipment, try to sell the un-equipped item.
                if (unequippedItem) {
                    sellIfMax(unequippedItem);
                } else {
                    sellIfMax(primary);
                }
            });
        }
    } else {
        equipIfBetter(item, function (unequippedItem) {
            if (unequippedItem) {
                sellIfMax(unequippedItem);
            }
        });

        // If we're not crafting the inventory,
        if (!settings.craftInventory && settings.sellDuplicateInventory) {
            var better = findPrimaryCraft(inventory, item);
            if (isItemBetter(better)) {
                postMessage('Selling ' + getItemString(item) + " as a duplicate.");
                API.inventory.sell(item);
            }
        }
    }
});

// Age up everything that we own, if possible.
inventory.forEach(ScriptAPI.$craftingService.ageUpItem);
equipment.forEach(ScriptAPI.$craftingService.ageUpItem);

<commit_msg>I accidentallied a thing<commit_after>// Structure of items.
//var items = [{
//    id: "",
//    entityType: "",
//    rarity: 1,
//    type: "",
//    subType: "",
//    ts: 0,
//    plus: 0,
//    ageLevel: 0,
//    handed: 1,
//    stats: {
//        hp: 0,
//        attackMin: 0,
//        attackMax: 0,
//        defense: 0,
//        overkill: 0,
//        heal: 0,
//        hpBonus: 0
//    },
//    name: "", // {Helmet, Armor, Gloves, Leggings, Boots, Sword, 2-handed Sword, Bow, Crossbow, Wand, Staff, Shield}
//
//}];

/** ============= Battle INF Script to End All Scripts ==========
 * Authored by Sam 'Halithor' Marquart.
 * Licenced under MIT (https://opensource.org/licenses/MIT).
 *
 * Features:
 * - Sells items below a threshold.
 * - Crafts new items into equipped items and, optionally, inventory items.
 *      + Inventory items is useful for getting higher rarity gear to be more powerful than current gear
 * - Equips items that are better than currently equipped items.
 * - Sells items that have reached maximum Plus, and aren't better than the currently equipped item of that type.
 * - Dips all of your items into the fountain, automagically, to increase the age modifiers.
 */

// Settings for the game. Edit these to fit your character better.
var settings = {
    version: 1.0,
    sellBelow: 2, // The threshold below which we automatically sell (exclusive), without combining. Increase this as you like.
    keepAbove: 4, // The rarity above which we DO NOT ever auto sell (exclusive).
    craftInventory: true, // Whether or not to craft items in your inventory.
    sellDuplicateInventory: true, // If we should sell any duplicates of a given item type in the inventory, and only keep the strongest item.
    forceEquipHighestStrength: false // If you always want to equip the highest rarity, no matter the stats. I recommend this to be true if you don't craft the inventory.
};

var _rarities = ["None", "Gray", "Green", "Blue", "Red", "Orange", "Purple", "Teal"];
var _ages = ["Worn" , "Fine", "Refined", "Aged", "Exotic", "Famous", "Master", "Heroic", "Ancient", "Fabled", "Ascended", "Legendary", "Eternal"];

function postMessage(text) {
    console.log(text);
    API.notifications.create("" + text, 10);
}

// String that displays most info about an item.
function getItemString(item) {
    return '' + item.rarity + "." + item.mod + " " + _ages[item.ageLevel] + " " + item.name  + " +" + item.plus;
}

// Calculates the relative starting strength of an item.
function getItemStrength(item) {
    return (item.mod * 2) + item.rarity;
}

function isItemAtMaxPlus(item) {
    return item.plus >= (5 + item.rarity * 5);
}

function isSameItemType(first, second) {
    return first.type == second.type && first.subType == second.subType
}

// Returns if two items are compatible for crafting.
function canCraftItems(first, second) {
    return isSameItemType(first, second)
        && first.rarity == second.rarity
        && first.mod == second.mod;
}

// Tries to find a good item from items for secondary to combined into. Picks the first one found.
function findPrimaryCraft(items, secondary) {
    for (var j = 0; j < items.length; j++) {
        var candidate = items[j];
        if (canCraftItems(candidate, secondary) && !isItemAtMaxPlus(candidate)) {
            return candidate;
        }
    }
    return undefined;
}

// Find the item equipped matching the given item.
function findEquipped(primary) {
    var equipment = ScriptAPI.$user.character.equipment;
    for (var i in equipment) {
        var candidate = equipment[i];
        if (isSameItemType(primary, candidate)) {
            return candidate;
        }
    }
    return undefined;
}

// Returns true if first is better than second. False otherwise.
// Does not care about rarity, age, etc. Purely based on stats.
// This is one of the things you can change to value items differently!
function isItemBetter(first, second) {
    if (!isSameItemType(first, second)) {
        return false; // Don't even compare if not the same.
    }

    if (first.type == "weapon") {
        // Damage consideration
        var damageFirst = (first.stats.attackMax + first.stats.attackMin) / 2;
        var damageSecond = (second.stats.attackMax + second.stats.attackMin) / 2;
        var damageRatio = damageSecond > 0 ? damageFirst / damageSecond : 1.0;
        // Overkill consideration
        var overkillDiff = first.stats.overkill - second.stats.overkill;
        // Healing ratio.
        var healRatio =  second.stats.heal > 0 ? (first.stats.heal / second.stats.heal) : 1.0;
        var armorRatio = second.stats.defense > 0 ? first.stats.defense / second.stats.defense : 1.0;
        var hpBonusDiff = (first.hpBonus - second.hpBonus);
        return damageRatio + healRatio + armorRatio + (overkillDiff/15) + (hpBonusDiff/50) > 3.0;
    } else {
        // Everything that's not a weapon is armor.
        var armorRatio = first.stats.defense / second.stats.defense;
        var hpBonusDiff = (first.hpBonus - second.hpBonus);
        return armorRatio + (hpBonusDiff/50) > 1.0;
    }
}

function isItemStronger(first, second) {
    return getItemStrength(first) > getItemStrength(second);
}

// Sells an item if it's at the max level.
function sellIfMax(item) {
    if (isItemAtMaxPlus(item) && item.rarity <= settings.keepAbove) {
        postMessage("Selling " + getItemString(item));
        API.inventory.sell(item);
    }
}

// Tries to equip the item if better. Returns the unequiped item if it works, false otherwise.
function equipIfBetter(item, callback) {
    var equip = findEquipped(item);

    if (equip && (isItemBetter(item, equip) || (settings.forceEquipHighestStrength && isItemStronger(item, equip)) ) ) {
        postMessage("Changed equipped " + equip.type + ":" + equip.subType);
        API.inventory.unequip(equip, function() {
            API.inventory.equip(item, function() {
                callback(equip);
            });
        });
    }
    if (callback) {
        callback(false);
    }
}

// Get a sorted list of the inventory items.
var inventory = ScriptAPI.$user.inventory.items.sort(function (a, b) {
    if (getItemStrength(a) == getItemStrength(b)) {
        if (a.plus == b.plus) {
            if (a.ageLevel == b.ageLevel) {
                return 0;
            } else {
                return a.ageLevel > b.ageLevel ? -1 : 1;
            }
        } else {
            return a.plus > b.plus ? -1 : 1;
        }
    } else {
        return getItemStrength(a) > getItemStrength(b) ? -1 : 1;
    }
});

// Get the equipment
var equipment = ScriptAPI.$user.character.equipment;

items.forEach(function (item) {

    if (item.rarity < settings.sellBelow && !(item.rarity > settings.keepAbove)) {
        postMessage('Selling ' + getItemString(item));
        API.inventory.sell(item);
        return;
    }

    // Now we want to combine the item with the inventory into more powerful items. First, we want to upgrade your currently
    // equipped items fully. Then we want to try to combine between items in your inventory. After combining, we look to see
    // if any of the items we have are better than equipped, if so, switch them. Finally, if anything has
    // reached the max Plus value that it can, and it isn't equipped,  sell it.

    // Find a good candidate to craft this item into.
    var isEquipped = false;
    var primary = findPrimaryCraft(equipment, item);
    if (primary) isEquipped = true;

    if (!primary && settings.craftInventory) {
        primary = findPrimaryCraft(inventory, item);
    }

    if (primary) {
        postMessage("Crafting " + getItemString(primary) + (isEquipped ? " [equipped]" : " [inventory]") + " with " + getItemString(item));
        API.inventory.craft(primary, item);

        // Primary has now been upgraded. Compare it to the currently equipped piece of equipment, and if it wins, equip it.
        if (!isEquipped) {
            equipIfBetter(primary, function(unequippedItem) {
                // If we changed equipment, try to sell the un-equipped item.
                if (unequippedItem) {
                    sellIfMax(unequippedItem);
                } else {
                    sellIfMax(primary);
                }
            });
        }
    } else {
        equipIfBetter(item, function (unequippedItem) {
            if (unequippedItem) {
                sellIfMax(unequippedItem);
            }
        });

        // If we're not crafting the inventory,
        if (!settings.craftInventory && settings.sellDuplicateInventory) {
            var better = findPrimaryCraft(inventory, item);
            if (isItemBetter(better)) {
                postMessage('Selling ' + getItemString(item) + " as a duplicate.");
                API.inventory.sell(item);
            }
        }
    }
});

// Age up everything that we own, if possible.
inventory.forEach(ScriptAPI.$craftingService.ageUpItem);
equipment.forEach(ScriptAPI.$craftingService.ageUpItem);

<|endoftext|>


<commit_before>if (
  !window.Worker ||
  !window.Intl ||
  !window.Intl.DateTimeFormat ||
  !("onhashchange" in window) ||
  !("history" in window) ||
  !('content' in document.createElement('template')) ||
  !("classList" in document.createElement("_"))
) {
  document.body.className = "unsupported";
}

(function() {
  function slice(arr) {
    return Array.prototype.slice.call(arr);
  }
  function q(selector, node) {
    return (node || document.body).querySelector(selector);
  }
  function qa(selector, node) {
    return (node || document.body).querySelectorAll(selector);
  }
  if (!window.data) { // let the data load
    var nodes = slice(document.head.childNodes).filter(function(node) {
      return node.nodeType === Node.ELEMENT_NODE
        && node.nodeName === 'SCRIPT'
        && /data\.js$/.test(node.src);
    }).forEach(function(node) {
      node.addEventListener('load', build, false);
    });
  } else {
    build();
  }

  var local = q('.time.local');
  var game = q('.time.game');
  var formatter = new Intl.DateTimeFormat(undefined, {
    hour: 'numeric', minute: 'numeric', timeZone: 'UTC'
  });
  var sorts = {
    'default': function(a, b) {
      var delta = Number(a.dataset.time) - Number(b.dataset.time);
      if (delta !== 0) return delta;
      delta = Number(a.dataset.nodeid) - Number(b.dataset.nodeid);
      if (delta !== 0) return delta;
      return Number(a.dataset.slot) - Number(b.dataset.slot);
    }
  };

  try {
    // Start the web wokrer
    var worker = new Worker("worker.js");
    worker.onmessage = function(e) {
      local.textContent = e.data[1];
      game.textContent = e.data[2];
    };
  } catch(e) {
    console.error(e);
  }

  window.addEventListener("hashchange", unhash, false);

  function resort(parent, elems, compare) {
    elems = slice(elems || list.childNodes || [])
    .filter(function(node) {
      return node.nodeType === Node.ELEMENT_NODE;
    });
    elems.sort(compare).forEach(function(elem) {
      parent.appendChild(elem);
    });
  }

  function build() {
    mining(data.filter(function(item) {
      return item.type === 'mining';
    }));
    botany(data.filter(function(item) {
      return item.type === 'botany';
    }));
    fishing(data.filter(function(item) {
      return item.type === 'fishing';
    }));

    slice(qa('li[data-nodeid]')).forEach(function(node, idx, arr) {
      node.addEventListener('click', function(e) {
        var target = e.currentTarget;
        arr.forEach(function(check) {
          if (check.dataset.nodeid === target.dataset.nodeid)
            check.classList.toggle('selected');
        });
        hash();
      });
    });

    unhash();
  }

  function mining(data) {
    var list = q('section.mining ol');
    list.innerHTML = '';

    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  function botany(data) {
    var list = q('section.botany ol');
    list.innerHTML = '';

    // use the mining template for now.
    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  function fishing(data) {
    var list = q('section.fishing ol');
    list.innerHTML = '';

    // use the mining template for now.
    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  /**
   * Construct a mask of selected nodeids and encode it into the location hash.
   */
  function hash() {
    var data = [];
    slice(qa('li[data-nodeid]')).forEach(function(node) {
      if (node.classList.contains('selected')) {
        var id = Number(node.dataset.nodeid)
        var idx = ~~(id / 8);
        var val = id % 8;
        data[idx] = (data[idx] || 0) | (1 << val);
      }
    });
    for (var i = 0; i < data.length; i++)
      data[i] = String.fromCharCode(data[i] || 0);
    history.replaceState(undefined, undefined, '#' + btoa(data.join('')));
  }

  /**
   * Using the location hash as a nodeid mask, mark the nodes selected.
   */
  function unhash() {
    var hash = window.location.hash.substring(1);
    var data = atob(hash);
    for (var idx = 0; idx < data.length; idx++) {
      var mask = data.charCodeAt(idx);
      for (var i = 0; i < 8; i++) {
        if (mask && (mask & 1)) {
          var nodes = qa('li[data-nodeid="' + (8 * idx + i) + '"]');
          slice(nodes || []).forEach(function(node) {
            node.classList.add('selected')
          });
        }
        mask >>>= 1;
      }
    };
  }

})();
<commit_msg>a bit more code cleanup<commit_after>if (
  !window.Worker ||
  !window.Intl ||
  !window.Intl.DateTimeFormat ||
  !("onhashchange" in window) ||
  !("history" in window) ||
  !('content' in document.createElement('template')) ||
  !("classList" in document.createElement("_"))
) {
  document.body.className = "unsupported";
}

(function() {
  function slice(arr) {
    return Array.prototype.slice.call(arr);
  }
  function q(selector, node) {
    return (node || document.body).querySelector(selector);
  }
  function qa(selector, node) { // snapshot
    return slice((node || document.body).querySelectorAll(selector) || []);
  }
  if (!window.data) { // let the data load
    var nodes = slice(document.head.childNodes).filter(function(node) {
      return node.nodeType === Node.ELEMENT_NODE
        && node.nodeName === 'SCRIPT'
        && /data\.js$/.test(node.src);
    }).forEach(function(node) {
      node.addEventListener('load', build, false);
    });
  } else {
    build();
  }

  var local = q('.time.local');
  var game = q('.time.game');
  var formatter = new Intl.DateTimeFormat(undefined, {
    hour: 'numeric', minute: 'numeric', timeZone: 'UTC'
  });
  var sorts = {
    'default': function(a, b) {
      var delta = Number(a.dataset.time) - Number(b.dataset.time);
      if (delta !== 0) return delta;
      delta = Number(a.dataset.nodeid) - Number(b.dataset.nodeid);
      if (delta !== 0) return delta;
      return Number(a.dataset.slot) - Number(b.dataset.slot);
    }
  };

  try {
    // Start the web wokrer
    var worker = new Worker("worker.js");
    worker.onmessage = function(e) {
      local.textContent = e.data[1];
      game.textContent = e.data[2];
    };
  } catch(e) {
    console.error(e);
  }

  window.addEventListener("hashchange", unhash, false);

  function resort(parent, elems, compare) {
    elems = slice(elems || parent.childNodes || [])
    .filter(function(node) {
      return node.nodeType === Node.ELEMENT_NODE;
    });
    elems.sort(compare).forEach(function(elem) {
      parent.appendChild(elem);
    });
  }

  function build() {
    mining(data.filter(function(item) {
      return item.type === 'mining';
    }));
    botany(data.filter(function(item) {
      return item.type === 'botany';
    }));
    fishing(data.filter(function(item) {
      return item.type === 'fishing';
    }));

    qa('li[data-nodeid]').forEach(function(node, idx, arr) {
      node.addEventListener('click', function(e) {
        var target = e.currentTarget;
        arr.forEach(function(check) {
          if (check.dataset.nodeid === target.dataset.nodeid)
            check.classList.toggle('selected');
        });
        hash();
      });
    });

    unhash();
  }

  function mining(data) {
    var list = q('section.mining ol');
    list.innerHTML = '';

    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  function botany(data) {
    var list = q('section.botany ol');
    list.innerHTML = '';

    // use the mining template for now.
    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  function fishing(data) {
    var list = q('section.fishing ol');
    list.innerHTML = '';

    // use the mining template for now.
    var content = q('template.mining.row').content;
    resort(list, data.map(function(item, idx) {
      var li = q('li', content);
      Object.keys(item).forEach(function(key) {
        li.dataset[key] = item[key];
      });
      li.dataset.id = idx;
      q('.time', li).textContent = formatter.format(new Date(item.time * 1000));
      q('.name', li).textContent = item.name;
      q('.location', li).textContent = item.location;

      return document.importNode(content, true).firstElementChild;
    }), sorts.default);
  }

  /**
   * Construct a mask of selected nodeids and encode it into the location hash.
   */
  function hash() {
    var data = [];
    qa('li[data-nodeid]').forEach(function(node) {
      if (node.classList.contains('selected')) {
        var id = Number(node.dataset.nodeid)
        var idx = ~~(id / 8);
        var val = id % 8;
        data[idx] = (data[idx] || 0) | (1 << val);
      }
    });
    for (var i = 0; i < data.length; i++)
      data[i] = String.fromCharCode(data[i] || 0);
    history.replaceState(undefined, undefined, '#' + btoa(data.join('')));
  }

  /**
   * Using the location hash as a nodeid mask, mark the nodes selected.
   */
  function unhash() {
    var hash = window.location.hash.substring(1);
    var data = atob(hash);
    for (var idx = 0; idx < data.length; idx++) {
      var mask = data.charCodeAt(idx);
      for (var i = 0; i < 8; i++) {
        if (mask && (mask & 1)) {
          qa('li[data-nodeid="' + (8 * idx + i) + '"]').forEach(function(node) {
            node.classList.add('selected')
          });
        }
        mask >>>= 1;
      }
    };
  }

})();
<|endoftext|>


<commit_before>var query = '';
var counter = 0;

var map;

var heatmap;

var data;

function update_heatmap(newLatLng){
  data.push(newLatLng);
}

function set_heatmap(data, map){

  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);

  heatmap = new google.maps.visualization.HeatmapLayer({
    data: heatmapData,
    gradient: ["#060990", "#4400ff", "#ff0000", "#f2aaaa"],
    radius: 5
  });
  heatmap.setMap(map);

}

function set_map(map){
  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);

  map = new google.maps.Map(document.getElementById('map'), {
    center: sanFrancisco,
    zoom: 13,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  });
}

function scroll_to_div()
{
	$('html, body').animate({
    scrollTop: $("#anchor").offset().top
 	});
}

function apply_updates(){
	$.getJSON("twitter_query.php",{"q":query},
		function(data) {
		console.log(data);
		/*for (dp in data)
		{
			console.log(dp);
		}*/
  });
}

function send_query(q)
{
	query = q
	timer_fired();
}

function timer_fired()
{
	if (counter == 5)
		return;
	setTimeout(
		function(){
			counter+=1;
			apply_updates();
			timer_fired();
		}
		,1000);
}

$( document ).ready(function() {
  data = [
    new google.maps.LatLng(37.782, -122.447),
    new google.maps.LatLng(37.782, -122.445),
    new google.maps.LatLng(37.782, -122.443),
    new google.maps.LatLng(37.782, -122.441),
    new google.maps.LatLng(37.782, -122.439),
    new google.maps.LatLng(37.782, -122.437),
    new google.maps.LatLng(37.782, -122.435),
    new google.maps.LatLng(37.785, -122.447),
    new google.maps.LatLng(37.785, -122.445),
    new google.maps.LatLng(37.785, -122.443),
    new google.maps.LatLng(37.785, -122.441),
    new google.maps.LatLng(37.785, -122.439),
    new google.maps.LatLng(37.785, -122.437),
    new google.maps.LatLng(37.785, -122.435)
  ];

  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);
  map = new google.maps.Map(document.getElementById('map'), {
    center: sanFrancisco,
    zoom: 13
  });

  set_heatmap(data, map);

  $('#submit').click(function(){
  		var val = $('#query_text').val();
  		if (val != '')
  		{
  			send_query();
			scroll_to_div();
  		}
	});
});

<commit_msg>FUCK FUCK<commit_after>var query = '';
var counter = 0;

var map;

var heatmap;

var data;

function update_heatmap(newLatLng){
  data.push(newLatLng);
}

function set_heatmap(data, map){

  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);

  heatmap = new google.maps.visualization.HeatmapLayer({
    data: data,
    //gradient: ["#060990", "#4400ff", "#ff0000", "#f2aaaa"],
    radius: 5
  });
  heatmap.setMap(map);

}

function set_map(map){
  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);

  map = new google.maps.Map(document.getElementById('map'), {
    center: sanFrancisco,
    zoom: 13,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  });
}

function scroll_to_div()
{
	$('html, body').animate({
    scrollTop: $("#anchor").offset().top
 	});
}

function apply_updates(){
	$.getJSON("twitter_query.php",{"q":query},
		function(data) {
		console.log(data);
		/*for (dp in data)
		{
			console.log(dp);
		}*/
  });
}

function send_query(q)
{
	query = q
	timer_fired();
}

function timer_fired()
{
	if (counter == 5)
		return;
	setTimeout(
		function(){
			counter+=1;
			apply_updates();
			timer_fired();
		}
		,1000);
}

$( document ).ready(function() {
  data = [
    new google.maps.LatLng(37.782, -122.447),
    new google.maps.LatLng(37.782, -122.445),
    new google.maps.LatLng(37.782, -122.443),
    new google.maps.LatLng(37.782, -122.441),
    new google.maps.LatLng(37.782, -122.439),
    new google.maps.LatLng(37.782, -122.437),
    new google.maps.LatLng(37.782, -122.435),
    new google.maps.LatLng(37.785, -122.447),
    new google.maps.LatLng(37.785, -122.445),
    new google.maps.LatLng(37.785, -122.443),
    new google.maps.LatLng(37.785, -122.441),
    new google.maps.LatLng(37.785, -122.439),
    new google.maps.LatLng(37.785, -122.437),
    new google.maps.LatLng(37.785, -122.435)
  ];

  var sanFrancisco = new google.maps.LatLng(37.774546, -122.433523);
  map = new google.maps.Map(document.getElementById('map'), {
    center: sanFrancisco,
    zoom: 13
  });

  set_heatmap(data, map);

  $('#submit').click(function(){
  		var val = $('#query_text').val();
  		if (val != '')
  		{
  			send_query();
			scroll_to_div();
  		}
	});
});

<|endoftext|>


<commit_before>

class gifVisual{

    constructor(view, effects){

        this.view = view;
        this.effects = effects;
        this.hue = 0;
        this.invert = 0;
        this.blinker = null;
        this.allImages = [];
        this.images = [];
        this.imagesNum = 0;
        this.visual = window;
        this.firstIndex = 0;

        this.mainElement = this.visual.document.querySelector(".wrapper-main");
        this.initControls.call(this, effects);
        this.getImages.call(this);
        this.initEvents.call(this);

        //setInterval(this.switchRandom.bind(this), 3000);
        window.addEventListener("keypress", this.onKey.bind(this));
    }

    initControls(effects){
       // $("#control-random").click(this.switchRandom.bind(this));
        /*$("#control-switch").click(this.mapImages.bind(this, parseInt(4)));
        $("#control-roll").click(()=>{
            let elements = document.querySelectorAll(".gif");
            effects.applyEffect(elements, "colorRoll")
        });
        $("#control-zoom").click(()=>{
            let elements = document.querySelectorAll(".gif");
            effects.applyEffect(elements, "zoomRoll")
        });*/

        document.addEventListener("touchstart", e=>{
            this.switchBlinker.call(this, true);
        });

        document.addEventListener("touchend", e=>{
            this.switchBlinker.call(this, false);
        });
    }

    initEvents(){

        ['orientationchange'].forEach(event => window.addEventListener(event, ()=>{

            this.view.optimizeGrid.call(this.view);
    	    this.view.initGrid.call(this.view, this.images);

    	    let elements = this.mainElement.querySelectorAll(".gif");
    	    this.effects.applyEffect(elements, "colorRoll");

        }));
    }

    getImages(m){

        let gifs, gifsRoot;

        let r = Math.random()>0.5 ? 0:1;
        r=0;
        gifs = gifObj[r].list;
        gifsRoot = gifObj[r].root;

        this.allImages = [];
        for(var i=0; i<gifs.length; i++){
            this.allImages.push(gifsRoot+gifs[i]);
        }
        this.imagesNum = 20;

        let tag = $("#control-tag").val();

        this.mapImages.call(this, 4);

        /*for(var i=0; i<this.imagesNum; i++){

            $.get("http://api.giphy.com/v1/gifs/translate?s="+tag+"&api_key=dc6zaTOxFJmzC", this.loadImage.bind(this));
        }*/
    }

    mapImages(combinations){

    	combinations = combinations ? combinations : Math.ceil(Math.random()*5);
    	this.images = [];
    	let j=0;

    	for(var i=0; i<combinations; i++){
    		let randomImageIndex = Math.floor(Math.random()*this.allImages.length);
    		this.images.push(this.allImages[randomImageIndex]);
    	}

    	this.view.initGrid.call(this.view, this.images);
    	let elements = this.mainElement.querySelectorAll(".gif");
	    this.effects.applyEffect(elements, "colorRoll");

    }

    switchBlinker(force){
        if(force){
            this.invertColor.call(this);
            this.blinker = setInterval(this.invertColor.bind(this), 70);
        }else{
            if(this.blinker)
                clearInterval(this.blinker);
            this.blinker = false;
            this.invert = 0;
            this.setStyle.call(this);
        }
    }

    setGrid(imagesPerRow){

        this.view.initGrid.call(this.view, null, imagesPerRow);

    }

    changeColor(){
        this.hue+=80;
        this.setStyle.call(this);
    }

    invertColor(){
        this.invert = this.invert == 0 ? 1 : 0;
        this.setStyle.call(this);
    }

    setStyle(){

        var filter = "";
        filter+="hue-rotate("+ this.hue +"deg)";
        filter+="invert("+this.invert*100+"%)";

        this.mainElement.style.filter = filter;
    }

    onKey(e){
        var key = e.key;
        if(key>0) {
            this.setGrid.call(this, parseInt(key));
            return false;
        }

        let elements = document.querySelectorAll(".gif");

        switch (key) {
            case "i":
                this.switchBlinker.call(this);
                break;
            case "o":
                this.effects.applyEffect(elements, "colorRoll");
                break;
            case "p":
                this.effects.applyEffect(elements, "zoomRoll");
                break;
            case " ":
                this.mapImages.call(this, parseInt(10));
                break;
            default:
                break;
        }
    }

}

$(document).ready(function () {

    let view = new VisualView(document.querySelector(".wrapper-main"));
    let effects = new VisualEffects(view);
    let controller = new gifVisual(view, effects);

});
<commit_msg>resize event<commit_after>

class gifVisual{

    constructor(view, effects){

        this.view = view;
        this.effects = effects;
        this.hue = 0;
        this.invert = 0;
        this.blinker = null;
        this.allImages = [];
        this.images = [];
        this.imagesNum = 0;
        this.visual = window;
        this.firstIndex = 0;

        this.mainElement = this.visual.document.querySelector(".wrapper-main");
        this.initControls.call(this, effects);
        this.getImages.call(this);
        this.initEvents.call(this);

        //setInterval(this.switchRandom.bind(this), 3000);
        window.addEventListener("keypress", this.onKey.bind(this));
    }

    initControls(effects){
       // $("#control-random").click(this.switchRandom.bind(this));
        /*$("#control-switch").click(this.mapImages.bind(this, parseInt(4)));
        $("#control-roll").click(()=>{
            let elements = document.querySelectorAll(".gif");
            effects.applyEffect(elements, "colorRoll")
        });
        $("#control-zoom").click(()=>{
            let elements = document.querySelectorAll(".gif");
            effects.applyEffect(elements, "zoomRoll")
        });*/

        document.addEventListener("touchstart", e=>{
            this.switchBlinker.call(this, true);
        });

        document.addEventListener("touchend", e=>{
            this.switchBlinker.call(this, false);
        });
    }

    initEvents(){

        ['orientationchange', 'resize'].forEach(event => window.addEventListener(event, ()=>{

            this.view.optimizeGrid.call(this.view);
    	    this.view.initGrid.call(this.view, this.images);

    	    let elements = this.mainElement.querySelectorAll(".gif");
    	    this.effects.applyEffect(elements, "colorRoll");

        }));
    }

    getImages(m){

        let gifs, gifsRoot;

        let r = Math.random()>0.5 ? 0:1;
        r=0;
        gifs = gifObj[r].list;
        gifsRoot = gifObj[r].root;

        this.allImages = [];
        for(var i=0; i<gifs.length; i++){
            this.allImages.push(gifsRoot+gifs[i]);
        }
        this.imagesNum = 20;

        let tag = $("#control-tag").val();

        this.mapImages.call(this, 4);

        /*for(var i=0; i<this.imagesNum; i++){

            $.get("http://api.giphy.com/v1/gifs/translate?s="+tag+"&api_key=dc6zaTOxFJmzC", this.loadImage.bind(this));
        }*/
    }

    mapImages(combinations){

    	combinations = combinations ? combinations : Math.ceil(Math.random()*5);
    	this.images = [];
    	let j=0;

    	for(var i=0; i<combinations; i++){
    		let randomImageIndex = Math.floor(Math.random()*this.allImages.length);
    		this.images.push(this.allImages[randomImageIndex]);
    	}

    	this.view.initGrid.call(this.view, this.images);
    	let elements = this.mainElement.querySelectorAll(".gif");
	    this.effects.applyEffect(elements, "colorRoll");

    }

    switchBlinker(force){
        if(force){
            this.invertColor.call(this);
            this.blinker = setInterval(this.invertColor.bind(this), 70);
        }else{
            if(this.blinker)
                clearInterval(this.blinker);
            this.blinker = false;
            this.invert = 0;
            this.setStyle.call(this);
        }
    }

    setGrid(imagesPerRow){

        this.view.initGrid.call(this.view, null, imagesPerRow);

    }

    changeColor(){
        this.hue+=80;
        this.setStyle.call(this);
    }

    invertColor(){
        this.invert = this.invert == 0 ? 1 : 0;
        this.setStyle.call(this);
    }

    setStyle(){

        var filter = "";
        filter+="hue-rotate("+ this.hue +"deg)";
        filter+="invert("+this.invert*100+"%)";

        this.mainElement.style.filter = filter;
    }

    onKey(e){
        var key = e.key;
        if(key>0) {
            this.setGrid.call(this, parseInt(key));
            return false;
        }

        let elements = document.querySelectorAll(".gif");

        switch (key) {
            case "i":
                this.switchBlinker.call(this);
                break;
            case "o":
                this.effects.applyEffect(elements, "colorRoll");
                break;
            case "p":
                this.effects.applyEffect(elements, "zoomRoll");
                break;
            case " ":
                this.mapImages.call(this, parseInt(10));
                break;
            default:
                break;
        }
    }

}

$(document).ready(function () {

    let view = new VisualView(document.querySelector(".wrapper-main"));
    let effects = new VisualEffects(view);
    let controller = new gifVisual(view, effects);

});
<|endoftext|>


<commit_before>$(document).ready( function() {
  // next line was supposed to give focus to the add button but can't get it to work
  // $('#add').focus();

  // watches for keypress on return key
  $(document).keydown( function (key) {
      switch (parseInt(key.which,10)) {
          // Enter key pressed
          case 13:
              addNewTask();
          break;
      }
  });

  // pressing the return key should activate the 'add' button

  //watches for the click event on div '#add'
  $('#add').click( function() {
      addNewTask();
  });

  // === FUNCTION TO HANDLE WHAT HAPPENS WHEN YOU CLICK THE ADD "BUTTON" (which actually is just a div)
  // Basically, when '#add' div is clicked, the function gets the text
  // typed in the input text box whose name is '#newTaskTextInput'
  // and appends a new "listItem" list entry (li) within the "todoList" div

    function addNewTask () {
        // initializes the default text value of input text box to 'enter new task here'
        var defaultVal = 'enter new task here';
        //stores text from text input into the itemText variable
        var itemText = $('input[name=newTaskTextInput]').val();

        // condition to detect if the user has not modified the default textinput value
        // (i.e. still displaying 'enter new task here')
        // or if user has clicked (given focus to) text input but not typed text yet
        if(itemText == defaultVal || itemText == '' || itemText == ' ') {
        // prevents from adding a new task if "#add" div is clicked
        // whereas nothing has been typed in the input text box;
        // in this case, there is no subsequent action except displaying an error message
        // that is appended to the ".error-message" class (to control formatting with CSS)
          $('.error-message').append('Please enter a new task before clicking the add button!
');
        }
        else { // user has actually typed text in the newTaskTextInput field; a space would be accepted, though…
          //appends a new list item, consisting of a checkbox followed by the text typed by the user, to the '.list' div
          $('.list').append('
   ' + itemText + '
');
          // empties the '.error-message' div because a new task was actually created
          $('.error-message').empty();
          // restores default value of input text box
          // mainly implemented to prevent the user from inadvertently adding the same task again
          // by clicking several times on the '#add' div
          $('input[name=newTaskTextInput]').val(defaultVal);
        };
        return false;
    };

  // === END OF FUNCTION HANDLING NEW TASKS ===

  // little function that toggles 'itemdone' class
  // on items (from the '.list') that are clicked
  // so that the item is greyed out and formatted as strikethrough;
  // it also moves the item to the '.listdone' div
  $(document).on('click', '.item', function() {
      $(this).toggleClass('itemdone');
      // moves the done item to the 'listdone' div
      $('.listdone').append(this);
  });
  // the little function below does the opposite
  // e.g. moving back a "done" item to the "todo" list when clicked
  $(document).on('click', '.itemdone', function() {
      $(this).removeClass('itemdone');
      // moves back the undone item to the 'list' div
      $('.list').append(this);
  });

  // this function clear all completed tasks
  // when the '#delete' div is clicked
  $(document).on('click', '#delete', function() {
      confirm("Deleted tasks can't be recovered. Do you really want to DELETE all done tasks?");
    $('.itemdone').hide();
  });

  // this function marks all tasks from the "To do" list
  // as completed, which moves them to the "Done" list
  $(document).on('click', '#alldone', function() {
    // stores content (html, including li tags) of the "To do" list
    var $list = $('.list').html();
    // un-comment the line below to print $list to the console for debugging
    // console.log('The $list variable contains: ',$list);
    // appends all the items included in the $list var to the "Done list"
    $('.listdone').append($list);
    // adds class '.itemdone' to all these items
    // newly added to the "Done list"
    $('.item').addClass('itemdone');
    // removes all items from the "Todo list"
    $('.list').empty();
  });

  // this function unchecks all tasks from the "Done" list
  // and moves them back to the "To do" list
  $(document).on('click', '#undo', function() {
    // stores content (html, including li tags) of the "Done" list
    var $listdone = $('.listdone').html();
    // un-comment the line below to print $list to the console for debugging
    // console.log('The $listdone variable contains: ',$listdone);
    // appends all the items included in the $listdone var to the "To do" list
    $('.list').append($listdone);
    // removes class '.itemdone' from all these items
    // newly added to the "To do" list
    $('.itemdone').removeClass('itemdone');
    // removes all items from the "Done" list
    $('.listdone').empty();
  });

  // makes list items sortable with jQuery UI
      $('ul').sortable();

});
<commit_msg>Add preventDefault to form<commit_after>$(document).ready( function() {
  // next line was supposed to give focus to the add button but can't get it to work
  // $('#add').focus();

  // trying to solve this bug:
  // "when user hits enter key, the page is reloaded"
  // with the help of http://stackoverflow.com/a/15488912
  $('form').on('submit', function(event) {
      event.preventDefault();
  });

  // watches for keypress on return key
  $(document).keydown( function (key) {
      switch (parseInt(key.which,10)) {
          // Enter key pressed
          case 13:
              addNewTask();
          break;
      }
  });

  // pressing the return key should activate the 'add' button

  //watches for the click event on div '#add'
  $('#add').click( function() {
      addNewTask();
  });

  // === FUNCTION TO HANDLE WHAT HAPPENS WHEN YOU CLICK THE ADD "BUTTON" (which actually is just a div)
  // Basically, when '#add' div is clicked, the function gets the text
  // typed in the input text box whose name is '#newTaskTextInput'
  // and appends a new "listItem" list entry (li) within the "todoList" div

    function addNewTask () {
        // initializes the default text value of input text box to 'enter new task here'
        var defaultVal = 'enter new task here';
        //stores text from text input into the itemText variable
        var itemText = $('input[name=newTaskTextInput]').val();

        // condition to detect if the user has not modified the default textinput value
        // (i.e. still displaying 'enter new task here')
        // or if user has clicked (given focus to) text input but not typed text yet
        if(itemText == defaultVal || itemText == '' || itemText == ' ') {
        // prevents from adding a new task if "#add" div is clicked
        // whereas nothing has been typed in the input text box;
        // in this case, there is no subsequent action except displaying an error message
        // that is appended to the ".error-message" class (to control formatting with CSS)
          $('.error-message').append('Please enter a new task before clicking the add button!
');
        }
        else { // user has actually typed text in the newTaskTextInput field; a space would be accepted, though…
          //appends a new list item, consisting of a checkbox followed by the text typed by the user, to the '.list' div
          $('.list').append('
   ' + itemText + '
');
          // empties the '.error-message' div because a new task was actually created
          $('.error-message').empty();
          // restores default value of input text box
          // mainly implemented to prevent the user from inadvertently adding the same task again
          // by clicking several times on the '#add' div
          $('input[name=newTaskTextInput]').val(defaultVal);
        };
        return false;
    };

  // === END OF FUNCTION HANDLING NEW TASKS ===

  // little function that toggles 'itemdone' class
  // on items (from the '.list') that are clicked
  // so that the item is greyed out and formatted as strikethrough;
  // it also moves the item to the '.listdone' div
  $(document).on('click', '.item', function() {
      $(this).toggleClass('itemdone');
      // moves the done item to the 'listdone' div
      $('.listdone').append(this);
  });
  // the little function below does the opposite
  // e.g. moving back a "done" item to the "todo" list when clicked
  $(document).on('click', '.itemdone', function() {
      $(this).removeClass('itemdone');
      // moves back the undone item to the 'list' div
      $('.list').append(this);
  });

  // this function clear all completed tasks
  // when the '#delete' div is clicked
  $(document).on('click', '#delete', function() {
      confirm("Deleted tasks can't be recovered. Do you really want to DELETE all done tasks?");
    $('.itemdone').hide();
  });

  // this function marks all tasks from the "To do" list
  // as completed, which moves them to the "Done" list
  $(document).on('click', '#alldone', function() {
    // stores content (html, including li tags) of the "To do" list
    var $list = $('.list').html();
    // un-comment the line below to print $list to the console for debugging
    // console.log('The $list variable contains: ',$list);
    // appends all the items included in the $list var to the "Done list"
    $('.listdone').append($list);
    // adds class '.itemdone' to all these items
    // newly added to the "Done list"
    $('.item').addClass('itemdone');
    // removes all items from the "Todo list"
    $('.list').empty();
  });

  // this function unchecks all tasks from the "Done" list
  // and moves them back to the "To do" list
  $(document).on('click', '#undo', function() {
    // stores content (html, including li tags) of the "Done" list
    var $listdone = $('.listdone').html();
    // un-comment the line below to print $list to the console for debugging
    // console.log('The $listdone variable contains: ',$listdone);
    // appends all the items included in the $listdone var to the "To do" list
    $('.list').append($listdone);
    // removes class '.itemdone' from all these items
    // newly added to the "To do" list
    $('.itemdone').removeClass('itemdone');
    // removes all items from the "Done" list
    $('.listdone').empty();
  });

  // makes list items sortable with jQuery UI
      $('ul').sortable();

});
<|endoftext|>


<commit_before>/*
 * Websensor video stabilization project
 * https://github.com/jessenie-intel/websensor-video
 *
 * Copyright (c) 2017 Jesse Nieminen
 *
 * 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.
 *
*/

'use strict';

var constraints = {audio: true,video: {  width: { min: 640, ideal: 640, max: 640 },  height: { min: 480, ideal: 480, max: 480 }}};
var mediaRecorder = null;
var chunks = [];
var videoData = null;
var interval = null;

var accel_sensor = null;
var orientation_sensor = null;
var sensorfreq = 60;

//var roll = null;
//var pitch = null;
//var yaw = null;
var accel = {"x": null, "y": null, "z": null};
var ori = {"roll": null, "pitch": null, "yaw": null, "time": null};
var oriInitial = {"roll": null, "pitch": null, "yaw": null, "time": null};
var initialoriobtained = false;
var orientationData = [];       //array to store all the orientation data
var frameData = {"data": null, "time": null, "ori": null};
var dataArray = [];     //array to store all the combined data
var dataArray2 = [];     //array to store all the combined data

var time = null;
var timestamps = [];
var nFrame = 0; //frame number with which we can combine timestamp and frame data

//canvas
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');

//video element
var videoElement = document.querySelector('video');
videoElement.controls = false;

var ref = null;

class AbsOriSensor {
        constructor() {
        const sensor = new AbsoluteOrientationSensor({ frequency: sensorfreq });
        const mat4 = new Float32Array(16);
        const euler = new Float32Array(3);
        sensor.onreading = () => {
                sensor.populateMatrix(mat4);
                toEulerianAngle(sensor.quaternion, euler);      //From quaternion to Eulerian angles
                this.roll = euler[0];
                this.pitch = euler[1];
                this.yaw = euler[2];
                this.timestamp = sensor.timestamp;
                if (this.onreading) this.onreading();
        };
        sensor.onactivate = () => {
                if (this.onactivate) this.onactivate();
        };
        const start = () => sensor.start();
        Object.assign(this, { start });
        }
}

//WINDOWS 10 HAS DIFFERENT CONVENTION: Yaw z, pitch x, roll y
function toEulerianAngle(quat, out)
{
        const ysqr = quat[1] ** 2;

        // Roll (x-axis rotation).
        const t0 = 2 * (quat[3] * quat[0] + quat[1] * quat[2]);
        const t1 = 1 - 2 * (ysqr + quat[0] ** 2);
        out[0] = Math.atan2(t0, t1);
        // Pitch (y-axis rotation).
        let t2 = 2 * (quat[3] * quat[1] - quat[2] * quat[0]);
        t2 = t2 > 1 ? 1 : t2;
        t2 = t2 < -1 ? -1 : t2;
        out[1] = Math.asin(t2);
        // Yaw (z-axis rotation).
        const t3 = 2 * (quat[3] * quat[2] + quat[0] * quat[1]);
        const t4 = 1 - 2 * (ysqr + quat[2] ** 2);
        out[2] = Math.atan2(t3, t4);
        return out;
}

function errorCallback(error){
	console.log("error: ", error);
}

function startDemo () {
		navigator.getUserMedia(constraints, startRecording, errorCallback);
}

function startRecording(stream) {

                try {
                //Initialize sensors
                /*accel_sensor = new Accelerometer();
                accel_sensor.onreading = () => {
                        accel = {"x": accel_sensor.x, "y": accel_sensor.y, "z": accel_sensor.z};
                };
                accel_sensor.onactivate = () => {
                };
                accel_sensor.start();*/
                orientation_sensor = new AbsOriSensor();
                orientation_sensor.onreading = () => {
                        let roll = orientation_sensor.roll;
                        let pitch = orientation_sensor.pitch;
                        let yaw = orientation_sensor.yaw;
                        time = orientation_sensor.timestamp;
                        if(!initialoriobtained) //obtain initial orientation
                        {
                                oriInitial = {"roll": orientation_sensor.roll, "pitch": orientation_sensor.pitch, "yaw": orientation_sensor.yaw, "time": orientation_sensor.timestamp};
                                initialoriobtained = true;
                        }
                        ori = {"roll": orientation_sensor.roll, "pitch": orientation_sensor.pitch, "yaw": orientation_sensor.yaw, "time": orientation_sensor.timestamp};
                };
                orientation_sensor.onactivate = () => {
                };
                orientation_sensor.start();
                }
                catch(err) {
                        console.log(err.message);
                        console.log("Your browser doesn't seem to support generic sensors. If you are running Chrome, please enable it in about:flags.");
                        //this.innerHTML = "Your browser doesn't seem to support generic sensors. If you are running Chrome, please enable it in about:flags";
                }
	        //var options = {mimeType: 'video/webm;codecs=vp9'};
		//mediaRecorder = new MediaRecorder(stream, options);
		mediaRecorder = new MediaRecorder(stream);

	        mediaRecorder.start(10);

	        var url = window.URL;
	        videoElement.src = url ? url.createObjectURL(stream) : stream;
                //videoElement.play();

	        mediaRecorder.ondataavailable = function(e) {
                        //console.log("Data available", e);
                        //console.log(time);
                        timestamps.push(time);
                        frameData.time = time;
		        chunks.push(e.data);
                        frameData.data = e.data;
                        orientationData.push(ori);
                        frameData.ori = ori;
                        var b = new Object;     //need to push by value
                        Object.assign(b, frameData);
                        dataArray.push(b);
	        };

	        mediaRecorder.onerror = function(e){
		        console.log('Error: ', e);
	        };

	        mediaRecorder.onstart = function(){
                        console.log("Recording started", mediaRecorder.state);
	        };

	        mediaRecorder.onstop = function(){
		        var blob = new Blob(chunks, {type: "video/webm"});
		        chunks = [];

		        var videoURL = window.URL.createObjectURL(blob);

		        videoElement.src = videoURL;
                        //videoElement.load();

                        //resize canvas
videoElement.addEventListener('loadedmetadata', function() {
  canvas.width = videoElement.videoWidth;
  canvas.height = videoElement.videoHeight;
});

                        /*//Read blob data so we can stabilize the video
                        var reader = new FileReader();
                         reader.onload = function(event){
                                let text = reader.result;
                                console.log(text);
                          };
                        reader.readAsText(blob, "video/webm");*/
                        //console.log(orientationData);
                        //console.log(timestamps);
                        //console.log(dataArray);
/*
var blobUrl = URL.createObjectURL(blob);
var x = new XMLHttpRequest();
// set x.responseType = 'blob' if you want to get a Blob object:
// x.responseType = 'blob';
x.onload = function() {
    alert(x.responseText);
};
console.log(x.open('get', blobUrl));*/
                        readFrameData(blob, orientationData);    //reads the video into dataArray2
                        /*videoElement.onended = function() {
                                alert("The video has ended");
                                cancelAnimationFrame(ref);
                        };*/
                        //ctx.clearRect(0, 0, canvas.width, canvas.height);
                        //stabilize(dataArray2);        //now we can operate on it
                        //interval=window.setInterval(stabilize,20);
	        };

	        mediaRecorder.onpause = function(){
	        }

	        mediaRecorder.onresume = function(){
	        }

	        mediaRecorder.onwarning = function(e){
	        };
}

function stopRecording(){
	mediaRecorder.stop();
        //Now stabilize
	videoElement.controls = true;
}
//Idea: copy video to canvas, operate on the video, and then use the canvas with the stabilized video as source for the video element
function readFrameData(blob, oriArray) {     //Read video data from blob to object form with pixel data we can operate on
        console.log("frame");
        //console.log(orientationData);
        //console.log(oriInitial);
        //console.log(timestamps[nFrame] - timestamps[0], videoElement.currentTime);
        //while(!videoElement.ended)
        //{
                //videoElement.playbackRate = 0.5;        //fix playback being too fast
                let ori = orientationData[nFrame];
                //let oriDiff = {"roll": ori.roll-oriInitial.roll, "pitch": ori.pitch-oriInitial.pitch, "yaw": ori.yaw-oriInitial.yaw};
                //let x = videoElement.videoWidth*(oriDiff.yaw/(2*Math.Pi));
                //let y = videoElement.videoWidth*(oriDiff.roll/(2*Math.Pi));     //each 2pi means 1 video height
                let x = 0;
                let y = 0;
                let widthR = 100;
                let heightR = 100;
                ctx.drawImage(videoElement,0,0, videoElement.videoWidth, videoElement.videoHeight);
                /*ctx.beginPath();
                ctx.rect(x,y,widthR,heightR);
                ctx.stroke();*/

                //ctx.drawImage(videoElement, 0, 0);
                let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                /*let pixeldataArray = [];
                //loop through every pixel
                for(let i=0; i<imageData.data.length; i = i+4)
                {
                        let pixeldata = {"red": imageData.data[i], "green":imageData.data[i+1], "blue": imageData.data[i+2], "alpha":imageData.data[i+3]};
                        //pixeldataArray.push(pixeldata);
                }
                //pixeldataArray.push(imageData);*/
                //if(nFrame < dataArray.length) {
                        let timestamp = dataArray[nFrame].time;
                        //let frameData2 = {"imagedata": imageData, "time": timestamp, "oridiff": oriDiff};
                        //var b = new Object;     //need to push by value
                        //Object.assign(b, frameData2);
                        //dataArray2.push(b);
                        //dataArray2.push(frameData2);
                        //console.log(pixeldataArray);
                        //newImageData.data = data;
                    // Draw the pixels onto the visible canvas
                    //ctx.putImageData(newImageData,0,0);
                        //ctx.putImageData(imageData, 0, 0)
                        //xD
                //}
        //}
                nFrame = nFrame + 1;
                ref = requestAnimationFrame(readFrameData);
        /*
        if(dataArray2.length === timestamps.length)     //now we have read the whole blob - should use callback here instead of if condition
        {
                console.log("ended");
                cancelAnimationFrame(ref);
                console.log(dataArray2);
                stabilize(dataArray2);
        } */
        if(nFrame >= orientationData.length-1)
        {
                //cancelAnimationFrame(ref);
        }
}

function stabilize(dataArrayArg) { //Create a stabilized video from the pixel data given as input
        let frame = dataArrayArg[0];      //first frame
        console.log(frame);
        //ctx.drawImage(frame.imagedata,0,0, videoElement.videoWidth, videoElement.videoHeight);
        //ctx.putImageData(frame.imagedata, 0, 0);
}
<commit_msg>Working on reacting to sensor input<commit_after>/*
 * Websensor video stabilization project
 * https://github.com/jessenie-intel/websensor-video
 *
 * Copyright (c) 2017 Jesse Nieminen
 *
 * 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.
 *
*/

'use strict';

var constraints = {audio: true,video: {  width: { min: 640, ideal: 640, max: 640 },  height: { min: 480, ideal: 480, max: 480 }}};
var mediaRecorder = null;
var chunks = [];
var videoData = null;
var interval = null;

var accel_sensor = null;
var orientation_sensor = null;
var sensorfreq = 60;

//var roll = null;
//var pitch = null;
//var yaw = null;
var accel = {"x": null, "y": null, "z": null};
var ori = {"roll": null, "pitch": null, "yaw": null, "time": null};
var oriInitial = {"roll": null, "pitch": null, "yaw": null, "time": null};
var initialoriobtained = false;
var orientationData = [];       //array to store all the orientation data
var frameData = {"data": null, "time": null, "ori": null};
var dataArray = [];     //array to store all the combined data
var dataArray2 = [];     //array to store all the combined data

var time = null;
var timestamps = [];
var nFrame = 0; //frame number with which we can combine timestamp and frame data

//canvas
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');

//video element
var videoElement = document.querySelector('video');
videoElement.controls = false;

var ref = null;

class AbsOriSensor {
        constructor() {
        const sensor = new AbsoluteOrientationSensor({ frequency: sensorfreq });
        const mat4 = new Float32Array(16);
        const euler = new Float32Array(3);
        sensor.onreading = () => {
                sensor.populateMatrix(mat4);
                toEulerianAngle(sensor.quaternion, euler);      //From quaternion to Eulerian angles
                this.roll = euler[0];
                this.pitch = euler[1];
                this.yaw = euler[2];
                this.timestamp = sensor.timestamp;
                if (this.onreading) this.onreading();
        };
        sensor.onactivate = () => {
                if (this.onactivate) this.onactivate();
        };
        const start = () => sensor.start();
        Object.assign(this, { start });
        }
}

//WINDOWS 10 HAS DIFFERENT CONVENTION: Yaw z, pitch x, roll y
function toEulerianAngle(quat, out)
{
        const ysqr = quat[1] ** 2;

        // Roll (x-axis rotation).
        const t0 = 2 * (quat[3] * quat[0] + quat[1] * quat[2]);
        const t1 = 1 - 2 * (ysqr + quat[0] ** 2);
        out[0] = Math.atan2(t0, t1);
        // Pitch (y-axis rotation).
        let t2 = 2 * (quat[3] * quat[1] - quat[2] * quat[0]);
        t2 = t2 > 1 ? 1 : t2;
        t2 = t2 < -1 ? -1 : t2;
        out[1] = Math.asin(t2);
        // Yaw (z-axis rotation).
        const t3 = 2 * (quat[3] * quat[2] + quat[0] * quat[1]);
        const t4 = 1 - 2 * (ysqr + quat[2] ** 2);
        out[2] = Math.atan2(t3, t4);
        return out;
}

function errorCallback(error){
	console.log("error: ", error);
}

function startDemo () {
		navigator.getUserMedia(constraints, startRecording, errorCallback);
}

function startRecording(stream) {

                try {
                //Initialize sensors
                /*accel_sensor = new Accelerometer();
                accel_sensor.onreading = () => {
                        accel = {"x": accel_sensor.x, "y": accel_sensor.y, "z": accel_sensor.z};
                };
                accel_sensor.onactivate = () => {
                };
                accel_sensor.start();*/
                orientation_sensor = new AbsOriSensor();
                orientation_sensor.onreading = () => {
                        let roll = orientation_sensor.roll;
                        let pitch = orientation_sensor.pitch;
                        let yaw = orientation_sensor.yaw;
                        time = orientation_sensor.timestamp;
                        if(!initialoriobtained) //obtain initial orientation
                        {
                                oriInitial = {"roll": orientation_sensor.roll, "pitch": orientation_sensor.pitch, "yaw": orientation_sensor.yaw, "time": orientation_sensor.timestamp};
                                initialoriobtained = true;
                        }
                        ori = {"roll": orientation_sensor.roll, "pitch": orientation_sensor.pitch, "yaw": orientation_sensor.yaw, "time": orientation_sensor.timestamp};
                };
                orientation_sensor.onactivate = () => {
                };
                orientation_sensor.start();
                }
                catch(err) {
                        console.log(err.message);
                        console.log("Your browser doesn't seem to support generic sensors. If you are running Chrome, please enable it in about:flags.");
                        //this.innerHTML = "Your browser doesn't seem to support generic sensors. If you are running Chrome, please enable it in about:flags";
                }
	        //var options = {mimeType: 'video/webm;codecs=vp9'};
		//mediaRecorder = new MediaRecorder(stream, options);
		mediaRecorder = new MediaRecorder(stream);

	        mediaRecorder.start(10);

	        var url = window.URL;
	        videoElement.src = url ? url.createObjectURL(stream) : stream;
                //videoElement.play();

	        mediaRecorder.ondataavailable = function(e) {
                        //console.log("Data available", e);
                        //console.log(time);
                        timestamps.push(time);
                        frameData.time = time;
		        chunks.push(e.data);
                        frameData.data = e.data;
                        orientationData.push(ori);
                        frameData.ori = ori;
                        var b = new Object;     //need to push by value
                        Object.assign(b, frameData);
                        dataArray.push(b);
	        };

	        mediaRecorder.onerror = function(e){
		        console.log('Error: ', e);
	        };

	        mediaRecorder.onstart = function(){
                        console.log("Recording started", mediaRecorder.state);
	        };

	        mediaRecorder.onstop = function(){
		        var blob = new Blob(chunks, {type: "video/webm"});
		        chunks = [];

		        var videoURL = window.URL.createObjectURL(blob);

		        videoElement.src = videoURL;
                        //videoElement.load();

                        //resize canvas
videoElement.addEventListener('loadedmetadata', function() {
  canvas.width = videoElement.videoWidth;
  canvas.height = videoElement.videoHeight;
});

                        /*//Read blob data so we can stabilize the video
                        var reader = new FileReader();
                         reader.onload = function(event){
                                let text = reader.result;
                                console.log(text);
                          };
                        reader.readAsText(blob, "video/webm");*/
                        //console.log(orientationData);
                        //console.log(timestamps);
                        //console.log(dataArray);
/*
var blobUrl = URL.createObjectURL(blob);
var x = new XMLHttpRequest();
// set x.responseType = 'blob' if you want to get a Blob object:
// x.responseType = 'blob';
x.onload = function() {
    alert(x.responseText);
};
console.log(x.open('get', blobUrl));*/
                        readFrameData(blob, orientationData);    //reads the video into dataArray2
                        /*videoElement.onended = function() {
                                alert("The video has ended");
                                cancelAnimationFrame(ref);
                        };*/
                        //ctx.clearRect(0, 0, canvas.width, canvas.height);
                        //stabilize(dataArray2);        //now we can operate on it
                        //interval=window.setInterval(stabilize,20);
	        };

	        mediaRecorder.onpause = function(){
	        }

	        mediaRecorder.onresume = function(){
	        }

	        mediaRecorder.onwarning = function(e){
	        };
}

function stopRecording(){
	mediaRecorder.stop();
        //Now stabilize
	videoElement.controls = true;
}
//Idea: copy video to canvas, operate on the video, and then use the canvas with the stabilized video as source for the video element
function readFrameData(blob, oriArray) {     //Read video data from blob to object form with pixel data we can operate on
        console.log("frame");
        //console.log(orientationData);
        //console.log(oriInitial);
        //console.log(timestamps[nFrame] - timestamps[0], videoElement.currentTime);
        //while(!videoElement.ended)
        //{
                //videoElement.playbackRate = 0.5;        //fix playback being too fast
                let ori = orientationData[nFrame];
                //let oriDiff = {"roll": ori.roll-oriInitial.roll, "pitch": ori.pitch-oriInitial.pitch, "yaw": ori.yaw-oriInitial.yaw};
                //let x = videoElement.videoWidth*(oriDiff.yaw/(2*Math.Pi));
                //let y = videoElement.videoWidth*(oriDiff.roll/(2*Math.Pi));     //each 2pi means 1 video height
                let x = 0;
                let y = 0;
                let widthR = 100;
                let heightR = 100;
                ctx.drawImage(videoElement,0,0, videoElement.videoWidth, videoElement.videoHeight);
                /*ctx.beginPath();
                ctx.rect(x,y,widthR,heightR);
                ctx.stroke();*/

                //ctx.drawImage(videoElement, 0, 0);
                let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                /*let pixeldataArray = [];
                //loop through every pixel
                for(let i=0; i<imageData.data.length; i = i+4)
                {
                        let pixeldata = {"red": imageData.data[i], "green":imageData.data[i+1], "blue": imageData.data[i+2], "alpha":imageData.data[i+3]};
                        //pixeldataArray.push(pixeldata);
                }
                //pixeldataArray.push(imageData);*/
                //if(nFrame < dataArray.length) {
                        //let timestamp = dataArray[nFrame].time;
                        //let frameData2 = {"imagedata": imageData, "time": timestamp, "oridiff": oriDiff};
                        //var b = new Object;     //need to push by value
                        //Object.assign(b, frameData2);
                        //dataArray2.push(b);
                        //dataArray2.push(frameData2);
                        //console.log(pixeldataArray);
                        //newImageData.data = data;
                    // Draw the pixels onto the visible canvas
                    //ctx.putImageData(newImageData,0,0);
                        //ctx.putImageData(imageData, 0, 0)
                        //xD
                //}
        //}
                nFrame = nFrame + 1;
                ref = requestAnimationFrame(readFrameData);
        /*
        if(dataArray2.length === timestamps.length)     //now we have read the whole blob - should use callback here instead of if condition
        {
                console.log("ended");
                cancelAnimationFrame(ref);
                console.log(dataArray2);
                stabilize(dataArray2);
        } */
        if(nFrame >= orientationData.length-1)
        {
                //cancelAnimationFrame(ref);
        }
}

function stabilize(dataArrayArg) { //Create a stabilized video from the pixel data given as input
        let frame = dataArrayArg[0];      //first frame
        console.log(frame);
        //ctx.drawImage(frame.imagedata,0,0, videoElement.videoWidth, videoElement.videoHeight);
        //ctx.putImageData(frame.imagedata, 0, 0);
}
<|endoftext|>