<commit_before>Calc = {};
// Default State
Calc.calcing = false;
Calc.relevantObjs = {
	attackerAbility:1,
	attackerItem:1,
	defenderAbility:1,
	defenderItem:1,
	move:1
};

Calc.calcDamageNumbers = function (attacker, defender, move, field) {
	// We are in the middle of calcing
	this.calcing = true;
	// Move
	if (typeof move === 'string') move = Data.Movedex[move]; // Calc.getMove(move)
	if (!move || move.category === 'Status') return;
	// Clone attacker, defender, and move.
	//this.attacker = attacker;
	//this.defender = defender;
	this.move = Calc.moveClone(move);
	this.attacker = attacker;
	this.attackerAbility = Calc.abilityClone(attacker.ability);
	this.attackerItem = Calc.itemClone(attacker.item);
	this.defender = defender;
	this.defenderAbility = Calc.abilityClone(defender.ability);
	this.defenderItem = Calc.itemClone(defender.item);
	this.args = {}; // Keep variables from Calc.get() here

	/* listed move type -> moves that call other moves use the new move instead ->
	 * Normalize changes the move to Normal -> moves now change type (Hidden Power/Judgment/Natural Gift/Techno Blast/Weather Ball) ->
	 * if the move is Normal, Aerilate/Pixilate/Refrigerate change it to Flying/Fairy/Ice
     * -> if the move is still Normal, Ion Deluge changes to Electric -> Electrify changes the move to Electric ->
	 * Protean activates -> Gems activate if the Gem matches the move type
	*/
	// console.log(this.get('moveType'));
	this.move.type = this.get('moveType') || move.type;
	// Abilities
	//attacker.ability = Calc.getAbility();
	//defender.ability = Calc.getAbility();
	// Items
	//attacker.item = Calc.getItem();
	//defender.item = Calc.getItem();

	attackStatName = (move.category === 'Physical' ? 'atk' : 'spa');
	defendStatName = (move.category === 'Physical' ? 'def' : 'spd');

	attackStat = attacker.stats[attackStatName];
	defendStat = defender.stats[defendStatName];

	// attackStat = Calc.getEffectiveStat(attackStatName, attackStat, attackBoosts, attacker);
	// defendStat
	var damage = 0;

	this.move.basePower = this.getFrom('basePower', 'move') || this.move.basePower;
	if (!this.move.basePower) return;
	var bpMod = this.getMod('bpMod') || 0x1000;
	this.move.basePower = this.modify(this.move.basePower, bpMod);

	// Base Damage
	baseDamage = (Math.floor(Math.floor(Math.floor(2 * attacker.level / 5 + 2) * this.move.basePower * attackStat / defendStat) / 50) + 2);
	damage = baseDamage;

	// Spread?
	// TODO

	// Weather?
	// TODO

	// Crit?
	var critMod = this.get('critMod') || 0x1800;
	var crit = crit || false;
	if (crit) this.modify(damage, critMod);

	// Random Factor Begins To Apply Here
	// Store other variables for calculations in loop

	// STAB
	var hasSTAB = false;
	for (var i = 0; i < attacker.types.length && !hasSTAB; i++) {
		if (this.move.type === attacker.types[i]) hasSTAB = true;
	}
	var stabMod = this.get('stabMod') || 0x1800;

	// Type Effectiveness
	// var typeEff = 1;
	var typeEff = this.getTypeEff(this.move.type, defender.types);

	// Burn
	var burnEffect = false;
	if (attacker.status === 'brn') burnEffect = true;

	// Final Mods
	// TODO
	var finalMod = this.getMod('finalMod') || 0x1000; console.log()

	// Loop through damage rolls
	var damageNumbers = [];
	for (var dmgRoll = 15; damageNumbers.length < 16; dmgRoll--) {
		var rolledDamage = Math.floor(damage * (100 - dmgRoll) / 100);
		rolledDamage = this.modify(rolledDamage, (hasSTAB ? stabMod : 0x1000));
		rolledDamage = Math.floor(rolledDamage * typeEff);
		if (burnEffect) rolledDamage = Math.floor(rolledDamage/2);
		// Final Modifier
		rolledDamage = this.modify(rolledDamage, finalMod);
		if (rolledDamage < 1) rolledDamage = 1;
		damageNumbers.push(rolledDamage);
	}
	// done calcing
	this.calcing = false;
	// Clear relevantObjs
	for (var obj in this.relevantObjs) delete this[obj];
	for (var side in {attacker:1,defender:2}) delete this[side];
	delete this.args;
	return damageNumbers;
};

Calc.toModifier = function (value, numerator, denominator) {
	if (!denominator) denominator = 1;
	if (numerator && numerator.length) {
		denominator = numerator[1];
		numerator = numerator[0];
	}
	return Math.floor(numerator * 0x1000 / denominator);
};

Calc.modify = function (value, mod) {
	mod = mod || 0x1000;
	return Math.floor((value * mod + 0x800 - 1) / 0x1000);
};

Calc.chainModifiers = function (mod1, mod2) {
	mod1 = mod1 || 0x1000;
	mod2 = mod2 || 0x1000;
	return ((mod1 * mod2 + 0x800) >>> 12); // M'' = ((M * M') + 0x800) >> 12
}

Calc.compareTypes = function (oType, dType) {
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	if (!Data.TypeChart[dType]) return false;
	eff *= Data.TypeChart[dType].damageTaken[oType];
}

/* Calc.get() - returns the highest priority value or an array of values.
 * Calc.get() is a function that checks the relevant variables in a battle
 * that could affect the part of damage calculation passed to the function.
 * Uses Calc.getFrom().
*/

Calc.get = function (handle, returnArray) {
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return console.log('Blank Handle') || null;
	returnValues = [];
	var sides = {
		attack: "Attack",
		defend: "Defend"
	}
	for (obj in this.relevantObjs) {
		var value = this.getFrom(handle,obj,true);
		if (typeof value !== 'undefined') returnValues.push(value);
		if (obj.substr(0,6) in sides) {
			value = this.getFrom(handle+sides[obj.substr(0,6)], obj, true);
			if (typeof value !== 'undefined') returnValues.push(value);
		}
	}
	returnValues.sort(function(a,b){
		return b.priority - a.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};

Calc.getFrom = function (handle, fromObj, returnObj) {
	if (!this.calcing) return null;
	handle = handle || '';
	fromObj = fromObj || '';
	if (!handle || !fromObj) return null;
	var returnValues = [];
	if (!this[fromObj]) {
		console.log('Could not find this.'+fromObj);
		return;
	}
	// console.log('Running',handle,'on',fromObj);
	if (!this[fromObj]['handles'] || !this[fromObj]['handles'][handle]) return;
	var returnValue = {};
	this.self = this[fromObj];
	switch (typeof this[fromObj]['handles'][handle]) {
		case 'function':
			returnValue.value = this[fromObj]['handles'][handle].call(this);
			if (typeof returnValue.value === 'object') returnValue = $.extend(returnValue, returnValue.value);
			break;
		case 'object':
			returnValue = $.extend(returnValue, this[fromObj]['handles'][handle]);
			if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
			break;
		default: returnValue.value = this[fromObj]['handles'][handle];
	}
	if (this.self) delete this.self;
	if (typeof returnValue.value === 'undefined') return;
	returnValue.source = this[fromObj];
	if (returnObj) return returnValue;
	return returnValue.value;
};

Calc.getTypeEff = function (oType, dTypes) {
	if (!oType) return false;
	var ignoreImmunities = false;
	var immune = this.getFrom('immuneTo'+oType, 'defenderAbility');
	if (immune) return 0;
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	for (var j = 0, damageTaken; j < dTypes.length; j++) {
		if (!Data.TypeChart[dTypes[j]]) return false;
		//console.log("this.getFrom('typeEff'"+oType+", 'move'): ", this.getFrom('typeEff'+oType, 'move'))
		damageTaken = this.getFrom('typeEff'+dTypes[j], 'move') || Data.TypeChart[dTypes[j]].damageTaken[oType];
		eff *= (damageTaken !== 0 ? damageTaken : (ignoreImmunities ? 1 : 0));
	}
	return eff;
};

Calc.getMod = function (modName) { // Responsible for chaining modifiers as well
	modName = modName || '';
	modifiers = this.get(modName, true); // Get an array of modifiers
	console.log(modifiers);
	var totalMod = 0x1000;
	for (var i = 0; i < modifiers.length; i++) {
		totalMod = this.chainModifiers(totalMod, modifiers[i]);
	}
	return totalMod;
};

Calc.moveClone = function (move) {
	if (!move) return {};
	if (typeof move === 'string') move = Data.Movedex[move];
	if (typeof move !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, move);
};

Calc.itemClone = function (item) {
	if (!item) return {};
	if (typeof item === 'string') item = Data.Items[item];
	if (typeof item !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, item);
};

Calc.abilityClone = function (ability) {
	if (!ability) return {};
	if (typeof ability === 'string') ability = Data.Abilities[ability];
	if (typeof ability !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, ability);
};

/*
Calc.get = function (handle, returnArray) { // bool returnArray - if true, return array of values
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return null;
	var returnValues = [];
	for (var obj in this.relevantObjs) {
		if (!this[obj]) {
			console.log('Could not find this.'+obj);
			continue;
		}
		if (!this[obj]['handles'] || !this[obj]['handles'][handle]) continue;
		var returnValue = {};
		this.self = this[obj];
		switch (typeof this[obj]['handles'][handle]) {
			case 'function':
				returnValue.value = this[obj]['handles'][handle].call(this);
				if (typeof returnValue.value === 'object') returnValue = $.extend({}, returnValue, returnValue.value);
				break;
			case 'object':
				returnValue = $.extend(returnValue, this[obj]['handles'][handle]);
				if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
				break;
			default: returnValue.value = this[obj]['handles'][handle];
		}
		if (typeof returnValue.value === 'undefined') continue;
		returnValue.priority = returnValue.priority || 0;
		returnValue.source = this[obj];
		returnValues.push(returnValue);
		if () {

		}
	}
	if (this.self) delete this.self;
	//console.log(returnValues);
	returnValues.sort(function(a,b){
		return a.priority - b.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};*/
<commit_msg>Introduce `Calc.getStat()`<commit_after>Calc = {};
// Default State
Calc.calcing = false;
Calc.relevantObjs = {
	attackerAbility:1,
	attackerItem:1,
	defenderAbility:1,
	defenderItem:1,
	move:1
};

Calc.calcDamageNumbers = function (attacker, defender, move, field) {
	// We are in the middle of calcing
	this.calcing = true;
	// Move
	if (typeof move === 'string') move = Data.Movedex[move]; // Calc.getMove(move)
	if (!move || move.category === 'Status') return;
	// Clone attacker, defender, and move.
	//this.attacker = attacker;
	//this.defender = defender;
	this.move = Calc.moveClone(move);
	this.attacker = attacker;
	this.attackerAbility = Calc.abilityClone(attacker.ability);
	this.attackerItem = Calc.itemClone(attacker.item);
	this.defender = defender;
	this.defenderAbility = Calc.abilityClone(defender.ability);
	this.defenderItem = Calc.itemClone(defender.item);
	this.args = {}; // Keep variables from Calc.get() here

	/* listed move type -> moves that call other moves use the new move instead ->
	 * Normalize changes the move to Normal -> moves now change type (Hidden Power/Judgment/Natural Gift/Techno Blast/Weather Ball) ->
	 * if the move is Normal, Aerilate/Pixilate/Refrigerate change it to Flying/Fairy/Ice
     * -> if the move is still Normal, Ion Deluge changes to Electric -> Electrify changes the move to Electric ->
	 * Protean activates -> Gems activate if the Gem matches the move type
	*/
	// console.log(this.get('moveType'));
	this.move.type = this.get('moveType') || move.type;
	// Abilities
	//attacker.ability = Calc.getAbility();
	//defender.ability = Calc.getAbility();
	// Items
	//attacker.item = Calc.getItem();
	//defender.item = Calc.getItem();

	attackStatName = (move.category === 'Physical' ? 'atk' : 'spa');
	defendStatName = (move.category === 'Physical' ? 'def' : 'spd');

	attackStat = attacker.stats[attackStatName]; console.log(this.getStat(attacker, attackStatName, true, true));
	defendStat = defender.stats[defendStatName]; console.log(this.getStat2(attackStatName, attacker.stats[attackStatName], attacker.boosts[attackStatName], true));

	// attackStat = Calc.getEffectiveStat(attackStatName, attackStat, attackBoosts, attacker);
	// defendStat
	var damage = 0;

	this.move.basePower = this.getFrom('basePower', 'move') || this.move.basePower;
	if (!this.move.basePower) return;
	var bpMod = this.getMod('bpMod') || 0x1000;
	this.move.basePower = this.modify(this.move.basePower, bpMod);

	// Base Damage
	baseDamage = (Math.floor(Math.floor(Math.floor(2 * attacker.level / 5 + 2) * this.move.basePower * attackStat / defendStat) / 50) + 2);
	damage = baseDamage;

	// Spread?
	// TODO

	// Weather?
	// TODO

	// Crit?
	var critMod = this.get('critMod') || 0x1800;
	var crit = crit || false;
	if (crit) this.modify(damage, critMod);

	// Random Factor Begins To Apply Here
	// Store other variables for calculations in loop

	// STAB
	var hasSTAB = false;
	for (var i = 0; i < attacker.types.length && !hasSTAB; i++) {
		if (this.move.type === attacker.types[i]) hasSTAB = true;
	}
	var stabMod = this.get('stabMod') || 0x1800;

	// Type Effectiveness
	// var typeEff = 1;
	var typeEff = this.getTypeEff(this.move.type, defender.types);

	// Burn
	var burnEffect = false;
	if (attacker.status === 'brn') burnEffect = true;

	// Final Mods
	// TODO
	var finalMod = this.getMod('finalMod') || 0x1000; console.log()

	// Loop through damage rolls
	var damageNumbers = [];
	for (var dmgRoll = 15; damageNumbers.length < 16; dmgRoll--) {
		var rolledDamage = Math.floor(damage * (100 - dmgRoll) / 100);
		rolledDamage = this.modify(rolledDamage, (hasSTAB ? stabMod : 0x1000));
		rolledDamage = Math.floor(rolledDamage * typeEff);
		if (burnEffect) rolledDamage = Math.floor(rolledDamage/2);
		// Final Modifier
		rolledDamage = this.modify(rolledDamage, finalMod);
		if (rolledDamage < 1) rolledDamage = 1;
		damageNumbers.push(rolledDamage);
	}
	// done calcing
	this.calcing = false;
	// Clear relevantObjs
	for (var obj in this.relevantObjs) delete this[obj];
	for (var side in {attacker:1,defender:2}) delete this[side];
	delete this.args;
	return damageNumbers;
};

Calc.toModifier = function (value, numerator, denominator) {
	if (!denominator) denominator = 1;
	if (numerator && numerator.length) {
		denominator = numerator[1];
		numerator = numerator[0];
	}
	return Math.floor(numerator * 0x1000 / denominator);
};

Calc.modify = function (value, mod) {
	mod = mod || 0x1000;
	return Math.floor((value * mod + 0x800 - 1) / 0x1000);
};

Calc.chainModifiers = function (mod1, mod2) {
	mod1 = mod1 || 0x1000;
	mod2 = mod2 || 0x1000;
	return ((mod1 * mod2 + 0x800) >>> 12); // M'' = ((M * M') + 0x800) >> 12
}

Calc.compareTypes = function (oType, dType) {
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	if (!Data.TypeChart[dType]) return false;
	eff *= Data.TypeChart[dType].damageTaken[oType];
}

/* Calc.get() - returns the highest priority value or an array of values.
 * Calc.get() is a function that checks the relevant variables in a battle
 * that could affect the part of damage calculation passed to the function.
 * Uses Calc.getFrom().
*/

Calc.get = function (handle, returnArray) {
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return console.log('Blank Handle') || null;
	returnValues = [];
	var sides = {
		attack: "Attack",
		defend: "Defend"
	}
	for (obj in this.relevantObjs) {
		var value = this.getFrom(handle,obj,true);
		if (typeof value !== 'undefined') returnValues.push(value);
		if (obj.substr(0,6) in sides) {
			value = this.getFrom(handle+sides[obj.substr(0,6)], obj, true);
			if (typeof value !== 'undefined') returnValues.push(value);
		}
	}
	returnValues.sort(function(a,b){
		return b.priority - a.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};

Calc.getFrom = function (handle, fromObj, returnObj) {
	if (!this.calcing) return null;
	handle = handle || '';
	fromObj = fromObj || '';
	if (!handle || !fromObj) return null;
	var returnValues = [];
	if (!this[fromObj]) {
		console.log('Could not find this.'+fromObj);
		return;
	}
	// console.log('Running',handle,'on',fromObj);
	if (!this[fromObj]['handles'] || !this[fromObj]['handles'][handle]) return;
	var returnValue = {};
	this.self = this[fromObj];
	switch (typeof this[fromObj]['handles'][handle]) {
		case 'function':
			returnValue.value = this[fromObj]['handles'][handle].call(this);
			if (typeof returnValue.value === 'object') returnValue = $.extend(returnValue, returnValue.value);
			break;
		case 'object':
			returnValue = $.extend(returnValue, this[fromObj]['handles'][handle]);
			if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
			break;
		default: returnValue.value = this[fromObj]['handles'][handle];
	}
	if (this.self) delete this.self;
	if (typeof returnValue.value === 'undefined') return;
	returnValue.source = this[fromObj];
	if (returnObj) return returnValue;
	return returnValue.value;
};

Calc.getTypeEff = function (oType, dTypes) {
	if (!oType) return false;
	var ignoreImmunities = false;
	var immune = this.getFrom('immuneTo'+oType, 'defenderAbility');
	if (immune) return 0;
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	for (var j = 0, damageTaken; j < dTypes.length; j++) {
		if (!Data.TypeChart[dTypes[j]]) return false;
		//console.log("this.getFrom('typeEff'"+oType+", 'move'): ", this.getFrom('typeEff'+oType, 'move'))
		damageTaken = this.getFrom('typeEff'+dTypes[j], 'move') || Data.TypeChart[dTypes[j]].damageTaken[oType];
		eff *= (damageTaken !== 0 ? damageTaken : (ignoreImmunities ? 1 : 0));
	}
	return eff;
};

Calc.getMod = function (modName) { // Responsible for chaining modifiers as well
	modName = modName || '';
	modifiers = this.get(modName, true); // Get an array of modifiers
	console.log(modifiers);
	var totalMod = 0x1000;
	for (var i = 0; i < modifiers.length; i++) {
		totalMod = this.chainModifiers(totalMod, modifiers[i]);
	}
	return totalMod;
};

Calc.getStat = function (statName, stat, boost, modify) {
	if (boost) {
		if (boost > 0) stat *= ( 2 + boost ) / 2;
		if (boost < 0) stat *= 2 / (2 - boost);
		stat = Math.floor(stat);
	}
	if (modify) {
		var mod = this.getMod(statName+'Mod') || 0x1000;
		stat = this.modify(stat, mod);
	}
	return stat;
};

Calc.moveClone = function (move) {
	if (!move) return {};
	if (typeof move === 'string') move = Data.Movedex[move];
	if (typeof move !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, move);
};

Calc.itemClone = function (item) {
	if (!item) return {};
	if (typeof item === 'string') item = Data.Items[item];
	if (typeof item !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, item);
};

Calc.abilityClone = function (ability) {
	if (!ability) return {};
	if (typeof ability === 'string') ability = Data.Abilities[ability];
	if (typeof ability !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, ability);
};

/*
Calc.get = function (handle, returnArray) { // bool returnArray - if true, return array of values
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return null;
	var returnValues = [];
	for (var obj in this.relevantObjs) {
		if (!this[obj]) {
			console.log('Could not find this.'+obj);
			continue;
		}
		if (!this[obj]['handles'] || !this[obj]['handles'][handle]) continue;
		var returnValue = {};
		this.self = this[obj];
		switch (typeof this[obj]['handles'][handle]) {
			case 'function':
				returnValue.value = this[obj]['handles'][handle].call(this);
				if (typeof returnValue.value === 'object') returnValue = $.extend({}, returnValue, returnValue.value);
				break;
			case 'object':
				returnValue = $.extend(returnValue, this[obj]['handles'][handle]);
				if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
				break;
			default: returnValue.value = this[obj]['handles'][handle];
		}
		if (typeof returnValue.value === 'undefined') continue;
		returnValue.priority = returnValue.priority || 0;
		returnValue.source = this[obj];
		returnValues.push(returnValue);
		if () {

		}
	}
	if (this.self) delete this.self;
	//console.log(returnValues);
	returnValues.sort(function(a,b){
		return a.priority - b.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};*/
<|endoftext|>


<commit_before>//
//  Core.js
//  Tentia
//
//  Created by Jeena on 15.04.10.
//  Licence: BSD (see attached LICENCE.txt file).
//

function Core(action) {
    this.max_length = 200;
    // this.timeout = 2 * 60 * 1000;
    this.timeout = 10 * 1000; // every 10 seconds
    this.action = action;
    this.getNewData();
    this.unread_mentions = 0;
    this.since_id = null;
    this.since_id_entity = null;
    this.since_time = 0;

    this.body = document.createElement("ol");
    this.body.className = this.action;
    this.cache = {};
    this.is_not_init = false;

    var _this = this;
    setInterval(function() { _this.getNewData() }, this.timeout);
}

Core.prototype.newStatus = function(status) {

	if(status != null && status.length > 0) {
		for(var i = status.length-1, c=0; i>=c; --i) {
			if(this.body.childNodes.length > 0) {
				if(this.body.childNodes.length > this.max_length) {
					this.body.removeChild(this.body.lastChild);
				}
			    this.body.insertBefore(this.getItem(status[i]), this.body.firstChild);
			} else {
                this.body.appendChild(this.getItem(status[i]));
			}
		}
	}

	if(this.action == "mentions" && this.is_not_init) {
		this.unread_mentions += status.length;
		controller.unreadMentions_(this.unread_mentions);
	}
	this.is_not_init = true;
}

Core.prototype.logout = function() {
    this.body.innerHTML = "";
}

Core.prototype.getItem = function(status) {

	var _this = this;
	this.since_id = status.id;
    this.since_id_entity = status.entity;

	var template = this.getTemplate();

	template.reply_to.onclick = function() {
        var mentions = [];
        for (var i = 0; i < status.mentions.length; i++) {
            var mention = status.mentions[i];
            if(mention.entity != controller.stringForKey_("entity"))
                mentions.push(mention);
        };
        replyTo(status.entity, status.id, mentions);
        return false;
    }
	//template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; }

	template.username.innerText = status.entity;
	template.username.href = status.entity; // FIXME open profile

    findProfileURL(status.entity, function(profile_url) {
        if (profile_url) {
            getURL(profile_url, "GET", function(resp) {
                var profile = JSON.parse(resp.responseText);
                var basic = profile["https://tent.io/types/info/basic/v0.1.0"];

                if (profile && basic) {
                    if(basic.name) {
                        template.username.title = template.username.innerText;
                        template.username.innerText = basic.name;
                    }
                    if(basic.avatar_url) {
                        template.image.onerror = function() { template.image.src = 'default-avatar.png' };
                        template.image.src = basic.avatar_url;
                    }
                }
            }, null, false); // do not send auth-headers
        }
    });

	template.in_reply.parentNode.className = "hidden";

	template.message.innerHTML = replaceUsernamesWithLinks(replaceURLWithHTMLLinks(status.content.text, status.entities, template.message));
    findMentions(template.message, status.mentions);

	var time = document.createElement("abbr");
	time.innerText = ISODateString(new Date(status.published_at * 1000));
	time.title = time.innerText;
	time.className = "timeago";
	$(time).timeago();
	template.ago.appendChild(time);

	// {"type":"Point","coordinates":[57.10803113,12.25854746]}
	if (status.content && status.content.location && status.content.location.type == "Point") {
		template.geo.href = "http://maps.google.com/maps?q=" + status.content.location.coordinates[0] + "," + status.content.location.coordinates[1];
		template.geo.style.display = "";
	}

    template.source.href = status.app.url;
	template.source.innerHTML = status.app.name;
    template.source.title = status.id;

	return template.item;
}

Core.prototype.getTemplate = function() {

	if(this.template == "undefined") {
		return jQuery.extend(true, {}, this.template);
	}

	var a = document.createElement("a");

	var item = document.createElement("li");

	var reply_to = a.cloneNode();
	reply_to.className = "reply_to"
	reply_to.innerText = " ";
	reply_to.href = "#";
	item.appendChild(reply_to);

	var retweet = a.cloneNode();
	retweet.className = "retweet";
	retweet.innerText = " ";
	retweet.href = "#";
	// item.appendChild(retweet); // FIXME

	var image = document.createElement("img");
	image.className = "image";
    image.src = "default-avatar.png";
	image.onmousedown = function(e) { e.preventDefault(); };
	item.appendChild(image);

	var image_username = a.cloneNode();
	image.appendChild(image_username);

	var data = document.createElement("div");
	data.className = "data";
	item.appendChild(data);

	var head = document.createElement("h1");
	data.appendChild(head);

	var username = a.cloneNode();
	head.appendChild(username);

	var in_reply = document.createElement("span");
	in_reply.className = "reply";
	head.appendChild(in_reply);

	var space = document.createTextNode(" ");
	head.appendChild(space);

	var geo = document.createElement("a");
	geo.style.display = "none";
	head.appendChild(geo);

	var pin = document.createElement("img");
	pin.src = "pin.png";
	pin.alt = "Map link";
	geo.appendChild(pin);

	var in_reply_text = document.createTextNode(" in reply to ");
	in_reply.appendChild(in_reply_text)

	var in_reply_a = a.cloneNode();
	in_reply.appendChild(in_reply_a);

	var message = document.createElement("p");
	message.className = "message";
	data.appendChild(message);

    var images = document.createElement("p")
    images.className = "images";
    data.appendChild(images);

	var date = message.cloneNode();
	date.className = "date";
	data.appendChild(date);

	var ago = a.cloneNode();
	date.appendChild(ago);

	var from = document.createTextNode(" from ");
	date.appendChild(from)

	var source = document.createElement("a");
	source.className = "source";
	date.appendChild(source)

	this.template = {
		item: item,
		reply_to: reply_to,
		retweet: retweet,
		image: image,
		username: username,
		in_reply: in_reply_a,
		message: message,
		ago: ago,
		source: source,
		geo: geo,
        images: images
	}

	return jQuery.extend(true, {}, this.template);
}

Core.prototype.getNewData = function() {
    if (this.action == "mentions") return;

    var those = this;
    var url = URI(mkApiRootPath("/posts"));
    url.addSearch("post_types", "https://tent.io/types/post/status/v0.1.0");
    url.addSearch("limit", this.max_length);
    if(this.since_id) {
        url.addSearch("since_id", this.since_id);
        url.addSearch("since_id_entity", this.since_id_entity);
    }

    if (this.action == "mentions") {
        url.addSearch("mentioned_entity", controller.stringForKey_("entity"));
    }

    var http_method = "GET";
    var callback = function(resp) {

        try {
            var json = JSON.parse(resp.responseText)
        } catch (e) {
            //alert(resp.responseText);
            alert(url + " JSON parse error");
            throw e;
        }

        those.newStatus(json);
    }

    var data = null;

    if (controller.stringForKey_("user_access_token")) {
        getURL(url.toString(), http_method, callback, data); // FIXME: error callback
    }
}

Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity) {

    var _this = this;

    var url = URI(mkApiRootPath("/posts"));

    var http_method = "POST";
    var callback = function(data) { _this.getNewData(); }

    var data = {
        "type": "https://tent.io/types/post/status/v0.1.0",
        "published_at": (new Date().getTime() / 1000),
        "permissions": {
            "public": true
        },
        "content": {
            "text": content,
        },
    };

    var mentions = parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
    if (mentions.length > 0) {
        data["mentions"] = mentions;
    }

    getURL(url.toString(), http_method, callback, JSON.stringify(data)); // FIXME: error callback
}

/* Helper functions */

function replaceURLWithHTMLLinks(text, entities, message_node) {
    var exp = /(([^\^]https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_()|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
    return text.replace(exp, "$1");
}

function replaceUsernamesWithLinks(text, mentions) {
    return text; // FIXME!
	var username = /(^|\s)(\^)(\w+)/ig;
	var hash = /(^|\s)(#)(\w+)/ig;
	text = text.replace(username, "$1$2$3");
	return text.replace(hash, "$1$2$3");
}

function replyTo(entity, status_id, mentions) {
    var string = "^" + entity.replace("https://", "") + " ";
    for (var i = 0; i < mentions.length; i++) {
      var e = mentions[i].entity.replace("https://", "");
      if(string.indexOf(e) == -1) string += "^" + e + " ";
    }
	controller.openNewMessageWindowInReplyTo_statusId_withString_(entity, status_id, string);
}

function loadPlugin(url) {
	var plugin = document.createElement("script");
	plugin.type = "text/javascript";
	plugin.src = url;
	document.getElementsByTagName("head")[0].appendChild(plugin);
}

String.prototype.startsWith = function(prefix) {
    return this.indexOf(prefix) === 0;
}

String.prototype.endsWith = function(suffix) {
    return this.match(suffix+"$") == suffix;
};

function getUrlVars(url)
{
    var vars = [], hash;
    if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#"));
    var hashes = url.slice(url.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}

function replaceShortened(url, message_node) {
    var api = "http://api.bitly.com";
    if(url.startsWith("http://j.mp/")) {
       api = "http://api.j.mp";
    }

    var api_url = api + "/v3/expand?format=json&apiKey=R_4fc2a1aa461d076556016390fa6400f6&login=twittia&shortUrl=" + url; // FIXME: new api key

    $.ajax({
           url: api_url,
           success: function(data) {
            var new_url = data.data.expand[0].long_url;
            if (new_url) {
                var regex = new RegExp(url, "g");
                message_node.innerHTML = message_node.innerHTML.replace(regex, new_url);
            }
           },
           error:function (xhr, ajaxOptions, thrownError) {
            alert(xhr.status);
            alert(thrownError);
           }
    });
}

function findMentions(node, mentions) {
    var text = node.innerHTML;
    var mentions_in_text = [];
    var res = text.match(/(\^\S+)/ig);

    if (res) {
        for (var i = 0; i < res.length; i++) {
            var name = res[i];
            var e = name.substring(1);
            if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
              e = "https://" + e;
            }
            for (var j = 0; j < mentions.length; j++) {
                var m = mentions[j];
                if(m.entity.startsWith(e)) {
                    mentions_in_text.push({
                        entity: m.entity,
                        text: name
                    });
                }
            }
        }
    }

    for (var i = 0; i < mentions_in_text.length; i++) {
        var mention = mentions_in_text[i];

        (function(mention) { // need this closure
            findProfileURL(mention.entity, function(profile_url) {
                if (profile_url) {
                    getURL(profile_url, "GET", function(resp) {
                        var profile = JSON.parse(resp.responseText);
                        var basic = profile["https://tent.io/types/info/basic/v0.1.0"];

                        if (profile && basic) {
                            if(basic.name) {
                                var new_text = node.innerHTML.replace(
                                    mention.text,
                                    ""
                                    + basic.name
                                    + ""
                                );
                                node.innerHTML = new_text;
                            }
                        }
                    }, null, false); // do not send auth-headers
                }
            });
        })(mention);
    }
}

function parseMentions(text, post_id, entity) {
    var mentions = [];

    if (post_id && entity) {
        mentions.push({
            post: post_id,
            entity: entity
        })
    }

    var res = text.match(/(\^\S+)/ig);

    if (res) {
        for (var i = 0; i < res.length; i++) {
            var e = res[i].substring(1);
            if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
              e = "https://" + e;
            }
            if (e != entity) {
                mentions.push({entity:e});
            }
        }
    }

    return mentions;
}

function ISODateString(d){
  function pad(n){return n<10 ? '0'+n : n}
  return d.getUTCFullYear()+'-'
      + pad(d.getUTCMonth()+1)+'-'
      + pad(d.getUTCDate())+'T'
      + pad(d.getUTCHours())+':'
      + pad(d.getUTCMinutes())+':'
      + pad(d.getUTCSeconds())+'Z'
}

var tentia_instance;
<commit_msg>removed debug stuff<commit_after>//
//  Core.js
//  Tentia
//
//  Created by Jeena on 15.04.10.
//  Licence: BSD (see attached LICENCE.txt file).
//

function Core(action) {
    this.max_length = 200;
    // this.timeout = 2 * 60 * 1000;
    this.timeout = 10 * 1000; // every 10 seconds
    this.action = action;
    this.getNewData();
    this.unread_mentions = 0;
    this.since_id = null;
    this.since_id_entity = null;
    this.since_time = 0;

    this.body = document.createElement("ol");
    this.body.className = this.action;
    this.cache = {};
    this.is_not_init = false;

    var _this = this;
    setInterval(function() { _this.getNewData() }, this.timeout);
}

Core.prototype.newStatus = function(status) {

	if(status != null && status.length > 0) {
		for(var i = status.length-1, c=0; i>=c; --i) {
			if(this.body.childNodes.length > 0) {
				if(this.body.childNodes.length > this.max_length) {
					this.body.removeChild(this.body.lastChild);
				}
			    this.body.insertBefore(this.getItem(status[i]), this.body.firstChild);
			} else {
                this.body.appendChild(this.getItem(status[i]));
			}
		}
	}

	if(this.action == "mentions" && this.is_not_init) {
		this.unread_mentions += status.length;
		controller.unreadMentions_(this.unread_mentions);
	}
	this.is_not_init = true;
}

Core.prototype.logout = function() {
    this.body.innerHTML = "";
}

Core.prototype.getItem = function(status) {

	var _this = this;
	this.since_id = status.id;
    this.since_id_entity = status.entity;

	var template = this.getTemplate();

	template.reply_to.onclick = function() {
        var mentions = [];
        for (var i = 0; i < status.mentions.length; i++) {
            var mention = status.mentions[i];
            if(mention.entity != controller.stringForKey_("entity"))
                mentions.push(mention);
        };
        replyTo(status.entity, status.id, mentions);
        return false;
    }
	//template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; }

	template.username.innerText = status.entity;
	template.username.href = status.entity; // FIXME open profile

    findProfileURL(status.entity, function(profile_url) {
        if (profile_url) {
            getURL(profile_url, "GET", function(resp) {
                var profile = JSON.parse(resp.responseText);
                var basic = profile["https://tent.io/types/info/basic/v0.1.0"];

                if (profile && basic) {
                    if(basic.name) {
                        template.username.title = template.username.innerText;
                        template.username.innerText = basic.name;
                    }
                    if(basic.avatar_url) {
                        template.image.onerror = function() { template.image.src = 'default-avatar.png' };
                        template.image.src = basic.avatar_url;
                    }
                }
            }, null, false); // do not send auth-headers
        }
    });

	template.in_reply.parentNode.className = "hidden";

	template.message.innerHTML = replaceUsernamesWithLinks(replaceURLWithHTMLLinks(status.content.text, status.entities, template.message));
    findMentions(template.message, status.mentions);

	var time = document.createElement("abbr");
	time.innerText = ISODateString(new Date(status.published_at * 1000));
	time.title = time.innerText;
	time.className = "timeago";
	$(time).timeago();
	template.ago.appendChild(time);

	// {"type":"Point","coordinates":[57.10803113,12.25854746]}
	if (status.content && status.content.location && status.content.location.type == "Point") {
		template.geo.href = "http://maps.google.com/maps?q=" + status.content.location.coordinates[0] + "," + status.content.location.coordinates[1];
		template.geo.style.display = "";
	}

    template.source.href = status.app.url;
	template.source.innerHTML = status.app.name;
    template.source.title = status.app.url;

	return template.item;
}

Core.prototype.getTemplate = function() {

	if(this.template == "undefined") {
		return jQuery.extend(true, {}, this.template);
	}

	var a = document.createElement("a");

	var item = document.createElement("li");

	var reply_to = a.cloneNode();
	reply_to.className = "reply_to"
	reply_to.innerText = " ";
	reply_to.href = "#";
	item.appendChild(reply_to);

	var retweet = a.cloneNode();
	retweet.className = "retweet";
	retweet.innerText = " ";
	retweet.href = "#";
	// item.appendChild(retweet); // FIXME

	var image = document.createElement("img");
	image.className = "image";
    image.src = "default-avatar.png";
	image.onmousedown = function(e) { e.preventDefault(); };
	item.appendChild(image);

	var image_username = a.cloneNode();
	image.appendChild(image_username);

	var data = document.createElement("div");
	data.className = "data";
	item.appendChild(data);

	var head = document.createElement("h1");
	data.appendChild(head);

	var username = a.cloneNode();
	head.appendChild(username);

	var in_reply = document.createElement("span");
	in_reply.className = "reply";
	head.appendChild(in_reply);

	var space = document.createTextNode(" ");
	head.appendChild(space);

	var geo = document.createElement("a");
	geo.style.display = "none";
	head.appendChild(geo);

	var pin = document.createElement("img");
	pin.src = "pin.png";
	pin.alt = "Map link";
	geo.appendChild(pin);

	var in_reply_text = document.createTextNode(" in reply to ");
	in_reply.appendChild(in_reply_text)

	var in_reply_a = a.cloneNode();
	in_reply.appendChild(in_reply_a);

	var message = document.createElement("p");
	message.className = "message";
	data.appendChild(message);

    var images = document.createElement("p")
    images.className = "images";
    data.appendChild(images);

	var date = message.cloneNode();
	date.className = "date";
	data.appendChild(date);

	var ago = a.cloneNode();
	date.appendChild(ago);

	var from = document.createTextNode(" from ");
	date.appendChild(from)

	var source = document.createElement("a");
	source.className = "source";
	date.appendChild(source)

	this.template = {
		item: item,
		reply_to: reply_to,
		retweet: retweet,
		image: image,
		username: username,
		in_reply: in_reply_a,
		message: message,
		ago: ago,
		source: source,
		geo: geo,
        images: images
	}

	return jQuery.extend(true, {}, this.template);
}

Core.prototype.getNewData = function() {

    var those = this;
    var url = URI(mkApiRootPath("/posts"));
    url.addSearch("post_types", "https://tent.io/types/post/status/v0.1.0");
    url.addSearch("limit", this.max_length);
    if(this.since_id) {
        url.addSearch("since_id", this.since_id);
        url.addSearch("since_id_entity", this.since_id_entity);
    }

    if (this.action == "mentions") {
        url.addSearch("mentioned_entity", controller.stringForKey_("entity"));
    }

    var http_method = "GET";
    var callback = function(resp) {

        try {
            var json = JSON.parse(resp.responseText)
        } catch (e) {
            //alert(resp.responseText);
            alert(url + " JSON parse error");
            throw e;
        }

        those.newStatus(json);
    }

    var data = null;

    if (controller.stringForKey_("user_access_token")) {
        getURL(url.toString(), http_method, callback, data); // FIXME: error callback
    }
}

Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity) {

    var _this = this;

    var url = URI(mkApiRootPath("/posts"));

    var http_method = "POST";
    var callback = function(data) { _this.getNewData(); }

    var data = {
        "type": "https://tent.io/types/post/status/v0.1.0",
        "published_at": (new Date().getTime() / 1000),
        "permissions": {
            "public": true
        },
        "content": {
            "text": content,
        },
    };

    var mentions = parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
    if (mentions.length > 0) {
        data["mentions"] = mentions;
    }

    getURL(url.toString(), http_method, callback, JSON.stringify(data)); // FIXME: error callback
}

/* Helper functions */

function replaceURLWithHTMLLinks(text, entities, message_node) {
    var exp = /(([^\^]https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_()|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
    return text.replace(exp, "$1");
}

function replaceUsernamesWithLinks(text, mentions) {
    return text; // FIXME!
	var username = /(^|\s)(\^)(\w+)/ig;
	var hash = /(^|\s)(#)(\w+)/ig;
	text = text.replace(username, "$1$2$3");
	return text.replace(hash, "$1$2$3");
}

function replyTo(entity, status_id, mentions) {
    var string = "^" + entity.replace("https://", "") + " ";
    for (var i = 0; i < mentions.length; i++) {
      var e = mentions[i].entity.replace("https://", "");
      if(string.indexOf(e) == -1) string += "^" + e + " ";
    }
	controller.openNewMessageWindowInReplyTo_statusId_withString_(entity, status_id, string);
}

function loadPlugin(url) {
	var plugin = document.createElement("script");
	plugin.type = "text/javascript";
	plugin.src = url;
	document.getElementsByTagName("head")[0].appendChild(plugin);
}

String.prototype.startsWith = function(prefix) {
    return this.indexOf(prefix) === 0;
}

String.prototype.endsWith = function(suffix) {
    return this.match(suffix+"$") == suffix;
};

function getUrlVars(url)
{
    var vars = [], hash;
    if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#"));
    var hashes = url.slice(url.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}

function replaceShortened(url, message_node) {
    var api = "http://api.bitly.com";
    if(url.startsWith("http://j.mp/")) {
       api = "http://api.j.mp";
    }

    var api_url = api + "/v3/expand?format=json&apiKey=R_4fc2a1aa461d076556016390fa6400f6&login=twittia&shortUrl=" + url; // FIXME: new api key

    $.ajax({
           url: api_url,
           success: function(data) {
            var new_url = data.data.expand[0].long_url;
            if (new_url) {
                var regex = new RegExp(url, "g");
                message_node.innerHTML = message_node.innerHTML.replace(regex, new_url);
            }
           },
           error:function (xhr, ajaxOptions, thrownError) {
            alert(xhr.status);
            alert(thrownError);
           }
    });
}

function findMentions(node, mentions) {
    var text = node.innerHTML;
    var mentions_in_text = [];
    var res = text.match(/(\^\S+)/ig);

    if (res) {
        for (var i = 0; i < res.length; i++) {
            var name = res[i];
            var e = name.substring(1);
            if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
              e = "https://" + e;
            }
            for (var j = 0; j < mentions.length; j++) {
                var m = mentions[j];
                if(m.entity.startsWith(e)) {
                    mentions_in_text.push({
                        entity: m.entity,
                        text: name
                    });
                }
            }
        }
    }

    for (var i = 0; i < mentions_in_text.length; i++) {
        var mention = mentions_in_text[i];

        (function(mention) { // need this closure
            findProfileURL(mention.entity, function(profile_url) {
                if (profile_url) {
                    getURL(profile_url, "GET", function(resp) {
                        var profile = JSON.parse(resp.responseText);
                        var basic = profile["https://tent.io/types/info/basic/v0.1.0"];

                        if (profile && basic) {
                            if(basic.name) {
                                var new_text = node.innerHTML.replace(
                                    mention.text,
                                    "^"
                                    + basic.name
                                    + ""
                                );
                                node.innerHTML = new_text;
                            }
                        }
                    }, null, false); // do not send auth-headers
                }
            });
        })(mention);
    }
}

function parseMentions(text, post_id, entity) {
    var mentions = [];

    if (post_id && entity) {
        mentions.push({
            post: post_id,
            entity: entity
        })
    }

    var res = text.match(/(\^\S+)/ig);

    if (res) {
        for (var i = 0; i < res.length; i++) {
            var e = res[i].substring(1);
            if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
              e = "https://" + e;
            }
            if (e != entity) {
                mentions.push({entity:e});
            }
        }
    }

    return mentions;
}

function ISODateString(d){
  function pad(n){return n<10 ? '0'+n : n}
  return d.getUTCFullYear()+'-'
      + pad(d.getUTCMonth()+1)+'-'
      + pad(d.getUTCDate())+'T'
      + pad(d.getUTCHours())+':'
      + pad(d.getUTCMinutes())+':'
      + pad(d.getUTCSeconds())+'Z'
}

var tentia_instance;
<|endoftext|>


<commit_before>Sugar = {};
Sugar.Array    = {};
Sugar.Boolean  = {};
Sugar.Date     = {};
Sugar.Date.addLocale = function() {};
Sugar.Date.millisecondsFromNow = function() {};
Sugar.Date.daysFromNow   = function() {};
Sugar.Date.monthsFromNow = function() {};
Sugar.Date.daysSince = function() {};
Sugar.Date.clone  = function() {};
Sugar.Date.create = function() {};
Sugar.Function = {};
Sugar.Number   = {};
Sugar.Number.thousands = '';
Sugar.Number.decimal   = '';
Sugar.Object   = {};
Sugar.RegExp   = {};
Sugar.String   = {};
Sugar.String.Inflector = {};
Sugar.String.Inflector.acronyms = {};
Sugar.String.Inflector.acronym     = function() {};
Sugar.String.Inflector.plural      = function() {};
Sugar.String.Inflector.singular    = function() {};
Sugar.String.Inflector.irregular   = function() {};
Sugar.String.Inflector.uncountable = function() {};
Sugar.String.Inflector.human       = function() {};
Sugar.String.Inflector.clear       = function() {};
Sugar.natives  = [];
Sugar.extend  = function() {};
Sugar.revert  = function() {};
Sugar.restore = function() {};
Sugar.define  = function() {};
Sugar.global  = function() {};
Sugar.noConflict        = false;
Sugar.hasOwnProperty    = function() {};
Sugar.iterateOverObject = function() {};

Date.prototype._utc = false;
Function.prototype.timers = [];

// ES6
String.prototype.startsWith = function() {};
String.prototype.endsWith   = function() {};
String.prototype.contains   = function() {};

Range                   = function() {};
Range.prototype.step    = function() {};
Range.prototype.clamp   = function() {};
Range.prototype.every   = function() {};
Range.prototype.isValid   = function() {};

var l = new Localization();
l.modifiers       = [{ name: 'shift', src: 'last', value: -1 }];
l.cachedFormat    = l.compiledFormats[0];
l.compiledFormats = [{ variant: false, locale: '', reg: /date/, to: [] }];
l.modifiersByName = {};

process = { env: {} };
module  = { exports: {} };
<commit_msg>adding Hash to externs<commit_after>Sugar = {};
Sugar.Array    = {};
Sugar.Boolean  = {};
Sugar.Date     = {};
Sugar.Date.addLocale = function() {};
Sugar.Date.millisecondsFromNow = function() {};
Sugar.Date.daysFromNow   = function() {};
Sugar.Date.monthsFromNow = function() {};
Sugar.Date.daysSince = function() {};
Sugar.Date.clone  = function() {};
Sugar.Date.create = function() {};
Sugar.Function = {};
Sugar.Number   = {};
Sugar.Number.thousands = '';
Sugar.Number.decimal   = '';
Sugar.Object   = {};
Sugar.RegExp   = {};
Sugar.String   = {};
Sugar.String.Inflector = {};
Sugar.String.Inflector.acronyms = {};
Sugar.String.Inflector.acronym     = function() {};
Sugar.String.Inflector.plural      = function() {};
Sugar.String.Inflector.singular    = function() {};
Sugar.String.Inflector.irregular   = function() {};
Sugar.String.Inflector.uncountable = function() {};
Sugar.String.Inflector.human       = function() {};
Sugar.String.Inflector.clear       = function() {};
Sugar.natives  = [];
Sugar.extend  = function() {};
Sugar.revert  = function() {};
Sugar.restore = function() {};
Sugar.define  = function() {};
Sugar.global  = function() {};
Sugar.noConflict        = false;
Sugar.hasOwnProperty    = function() {};
Sugar.iterateOverObject = function() {};

Date.prototype._utc = false;
Function.prototype.timers = [];

// ES6
String.prototype.startsWith = function() {};
String.prototype.endsWith   = function() {};
String.prototype.contains   = function() {};

Range                   = function() {};
Range.prototype.step    = function() {};
Range.prototype.clamp   = function() {};
Range.prototype.every   = function() {};
Range.prototype.isValid   = function() {};

var l = new Localization();
l.modifiers       = [{ name: 'shift', src: 'last', value: -1 }];
l.cachedFormat    = l.compiledFormats[0];
l.compiledFormats = [{ variant: false, locale: '', reg: /date/, to: [] }];
l.modifiersByName = {};

process = { env: {} };
module  = { exports: {} };

function Hash() {};
<|endoftext|>


<commit_before>// 74: String - `endsWith()`
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`str.endsWith(searchString)` determines whether `str` ends with `searchString`.', function() {
  const s = 'el fin';
  describe('1st parameter, the string to search for', function() {
    it('can be a character', function() {
      //// const doesEndWith = s.doesItReallyEndWith('n');
      const doesEndWith = s.endsWith('n');
      assert.equal(doesEndWith, true);
    });
    it('can be a string', function() {
      //// const expected = false;
      const expected = true;
      assert.equal(s.endsWith('fin'), expected);
    });
    it('can contain unicode characters', function() {
      //// const nuclear = 'NO ☢ Oh NO!';
      const nuclear = 'NO ☢';
      assert.equal(nuclear.endsWith('☢'), true);
    });
    it('a regular expression throws a TypeError', function() {
      //// const aRegExp = '/the/';
      const aRegExp = /the/;
      assert.throws(() => {''.endsWith(aRegExp)}, TypeError);
    });
  });
  describe('2nd parameter, the position where the search ends (as if the string was only that long)', function() {
    it('find "el" at a substring of the length 2', function() {
      //// const endPos = 0;
      const endPos = 2;
      assert.equal(s.endsWith('el', endPos), true);
    });
    it('`undefined` uses the entire string', function() {
      //// const _undefined_ = 'i would like to be undefined';
      const _undefined_ = undefined;
      assert.equal(s.endsWith('fin', _undefined_), true);
    });
    it('the parameter gets coerced to an integer (e.g. "5" becomes 5)', function() {
      //// const position = 'five';
      const position = '5';
      assert.equal(s.endsWith('fi', position), true);
    });
    describe('value less than 0', function() {
      it('returns `true`, when searching for an empty string', function() {
        //// const emptyString = '??';
        const emptyString = '';
        assert.equal('1'.endsWith(emptyString, -1), true);
      });
      it('return `false`, when searching for a non-empty string', function() {
        //// const notEmpty = '';
        const notEmpty = ' ';
        assert.equal('1'.endsWith(notEmpty, -1), false);
      });
    });
  });
  describe('transfer the functionality to other objects', function() {
    const endsWith = (string, searchFor, endPosition = undefined) =>
      String.prototype.endsWith.call(string, searchFor, endPosition);
    it('e.g. a boolean', function() {
      //// let aBool = false;
      let aBool = true;
      assert.equal(endsWith(!aBool, 'lse'), true);
    });
    it('e.g. a number', function() {
      //// let aNumber = 0;
      let aNumber = 84;
      assert.equal(endsWith(aNumber + 1900, 84), true);
    });
    it('also using the position works', function() {
      //// const position = '??';
      const position = 3;
      assert.equal(endsWith(1994, '99', position), true);
    });
  });
});
<commit_msg>SOme final polishing.<commit_after>// 74: String - `endsWith()`
// To do: make all tests pass, leave the assert lines unchanged!
// Follow the hints of the failure messages!

describe('`str.endsWith(searchString)` determines whether `str` ends with `searchString`', function() {
  const s = 'el fin';
  describe('the 1st parameter the string to search for', function() {
    it('can be a character', function() {
      //// const doesEndWith = s.doesItReallyEndWith('n');
      const doesEndWith = s.endsWith('n');
      assert.equal(doesEndWith, true);
    });
    it('can be a string', function() {
      //// const expected = false;
      const expected = true;
      assert.equal(s.endsWith('fin'), expected);
    });
    it('can contain unicode characters', function() {
      //// const nuclear = 'NO ☢ Oh NO!';
      const nuclear = 'NO ☢';
      assert.equal(nuclear.endsWith('☢'), true);
    });
    it('a regular expression throws a TypeError', function() {
      //// const aRegExp = '/the/';
      const aRegExp = /the/;
      assert.throws(() => {''.endsWith(aRegExp)}, TypeError);
    });
  });
  describe('the 2nd parameter, the position where the search ends (as if the string was only that long)', function() {
    it('find "el" at a substring of the length 2', function() {
      //// const endPos = 0;
      const endPos = 2;
      assert.equal(s.endsWith('el', endPos), true);
    });
    it('`undefined` uses the entire string', function() {
      //// const _undefined_ = 'i would like to be undefined';
      const _undefined_ = undefined;
      assert.equal(s.endsWith('fin', _undefined_), true);
    });
    it('the parameter gets coerced to an integer (e.g. "5" becomes 5)', function() {
      //// const position = 'five';
      const position = '5';
      assert.equal(s.endsWith('fi', position), true);
    });
    describe('value less than 0', function() {
      it('returns `true`, when searching for an empty string', function() {
        //// const emptyString = '??';
        const emptyString = '';
        assert.equal('1'.endsWith(emptyString, -1), true);
      });
      it('return `false`, when searching for a non-empty string', function() {
        //// const notEmpty = '';
        const notEmpty = ' ';
        assert.equal('1'.endsWith(notEmpty, -1), false);
      });
    });
  });
  describe('this functionality can be used on non-strings too', function() {
    const endsWith = (string, searchFor, endPosition = undefined) =>
      String.prototype.endsWith.call(string, searchFor, endPosition);
    it('e.g. a boolean', function() {
      //// let aBool = false;
      let aBool = true;
      assert.equal(endsWith(!aBool, 'lse'), true);
    });
    it('e.g. a number', function() {
      //// let aNumber = 0;
      let aNumber = 84;
      assert.equal(endsWith(aNumber + 1900, 84), true);
    });
    it('also using the position works', function() {
      //// const position = '??';
      const position = 3;
      assert.equal(endsWith(1994, '99', position), true);
    });
  });
});
<|endoftext|>


<commit_before>var page = require('webpage').create(),
    opts = JSON.parse(require('system').args[1]);

page.viewportSize = opts.viewportSize;
if (opts.userAgent) {
  page.settings.userAgent = opts.userAgent;
}

page.open(opts.address, function(status) {
  setTimeout(function() {
    // Try to prevent animations from running, to reduce variation in
    // snapshots.
    page.evaluate(function() {
      // CSS Transitions
      var css   = document.createElement('style');
      css.type  = 'text/css';
      document.head.appendChild(css);
      var sheet = css.sheet;
      sheet.addRule('*', '-webkit-transition: none !important;');
      sheet.addRule('*', 'transition: none !important;');

      // jQuery
      if (typeof $ !== 'undefined' && typeof $.fx !== 'undefined') {
        $.fx.off = true;
      }
    });

    // Save a PNG of the rendered page
    page.render(opts.outfile);

    // Capture metadata
    var response = page.evaluate(function() {
      return { title: document.title };
    });

    response.opts   = opts;
    response.status = status;

    // The phantomjs gem can read what is written to STDOUT which includes
    // console.log, so we can use that to pass information from phantomjs back
    // to the app.
    console.log(JSON.stringify(response));

    phantom.exit();
  }, 5000);
});
<commit_msg>Set animation-duration to 0 when taking snapshots<commit_after>var page = require('webpage').create(),
    opts = JSON.parse(require('system').args[1]);

page.viewportSize = opts.viewportSize;
if (opts.userAgent) {
  page.settings.userAgent = opts.userAgent;
}

page.open(opts.address, function(status) {
  setTimeout(function() {
    // Try to prevent animations from running, to reduce variation in
    // snapshots.
    page.evaluate(function() {
      // CSS Transitions
      var css   = document.createElement('style');
      css.type  = 'text/css';
      document.head.appendChild(css);
      var sheet = css.sheet;
      sheet.addRule('*', '-webkit-transition: none !important;');
      sheet.addRule('*', 'transition: none !important;');
      sheet.addRule('*', '-webkit-animation-duration: 0 !important;');
      sheet.addRule('*', 'animation-duration: 0 !important;');

      // jQuery
      if (typeof $ !== 'undefined' && typeof $.fx !== 'undefined') {
        $.fx.off = true;
      }
    });

    // Save a PNG of the rendered page
    page.render(opts.outfile);

    // Capture metadata
    var response = page.evaluate(function() {
      return { title: document.title };
    });

    response.opts   = opts;
    response.status = status;

    // The phantomjs gem can read what is written to STDOUT which includes
    // console.log, so we can use that to pass information from phantomjs back
    // to the app.
    console.log(JSON.stringify(response));

    phantom.exit();
  }, 5000);
});
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides the Design Time Metadata for the sap.m.ObjectIdentifier control.
sap.ui.define([
	'sap/m/library',
	"sap/base/Log"
], function(MLibrary, Log) {
	"use strict";
	var oWrapper;
	return {
		palette: {
			group: "DISPLAY",
			icons: {
				svg: "sap/m/designtime/ObjectIdentifier.icon.svg"
			}
		},
		// There is a dependency to 'sap.ui.comp' library because the so called 'settings' handler is implemented for SmartLink. So we register
		// the 'settings' handler in 'sap.ui.comp' library which basically do the same stuff as for SmartLink. The registration mechanism has been
		// chosen in order to be on the save site if 'sap.ui.comp' library is not used at all (e.g. OpenUI5).
		registerSettingsHandler: function(oWrapper_) {
			oWrapper = oWrapper_;
		},
		getStableElements: function(oObjectIdentifier) {
			return oWrapper ? oWrapper.getStableElements(oObjectIdentifier) : null;
		},
		actions: {
			settings: function() {
				if (!oWrapper) {
					return;
				}
				if (!oWrapper.isSettingsAvailable()) {
					Log.error("sap.ui.comp.navpopover.ObjectIdentifier.designtime: 'settings' action is not available");
					return;
				}
				return {
					handler: function(oObjectIdentifier, fGetUnsavedChanges) {
						return oWrapper.execute(oObjectIdentifier, fGetUnsavedChanges);
					}
				};
			}
		},
		templates: {
			create: "sap/m/designtime/ObjectIdentifier.create.fragment.xml"
		}
	};
});<commit_msg>[INTERNAL] ObjectIdentifier: disable RTA settings when not a SmartLink<commit_after>/*!
 * ${copyright}
 */

// Provides the Design Time Metadata for the sap.m.ObjectIdentifier control.
sap.ui.define([
	'sap/m/library',
	"sap/base/Log"
], function(MLibrary, Log) {
	"use strict";
	var oWrapper;
	return {
		palette: {
			group: "DISPLAY",
			icons: {
				svg: "sap/m/designtime/ObjectIdentifier.icon.svg"
			}
		},
		// There is a dependency to 'sap.ui.comp' library because the so called 'settings' handler is implemented for SmartLink. So we register
		// the 'settings' handler in 'sap.ui.comp' library which basically do the same stuff as for SmartLink. The registration mechanism has been
		// chosen in order to be on the save site if 'sap.ui.comp' library is not used at all (e.g. OpenUI5).
		registerSettingsHandler: function(oWrapper_) {
			oWrapper = oWrapper_;
		},
		getStableElements: function(oObjectIdentifier) {
			return oWrapper ? oWrapper.getStableElements(oObjectIdentifier) : null;
		},
		actions: {
			settings: function(oObjectIdentifier) {
				// Checking for the model which is set inside the sap.ui.comp.providers.ControlProvider in case the title link has SmartLink functionality
				if (oObjectIdentifier.getModel("$sapuicompcontrolprovider_distinctSO")) {
					if (!oWrapper) {
						return;
					}
					if (!oWrapper.isSettingsAvailable()) {
						Log.error("sap.m.ObjectIdentifier.designtime: 'settings' action is not available");
						return;
					}
					return {
						handler: function(oObjectIdentifier, fGetUnsavedChanges) {
							return oWrapper.execute(oObjectIdentifier, fGetUnsavedChanges);
						}
					};
				}
				return null;
			}
		},
		templates: {
			create: "sap/m/designtime/ObjectIdentifier.create.fragment.xml"
		}
	};
});<|endoftext|>


<commit_before>/*global QUnit, sinon */

sap.ui.define( [
	"./PDFViewerTestUtils",
	"sap/ui/Device",
	"sap/m/PDFViewerRenderer"
], function (TestUtils, Device, PDFViewerRenderer) {
	"use strict";

	var oPDFViewer;
	QUnit.module('Special use cases', {
		afterEach: function (assert) {
			oPDFViewer.destroy();
		}
	});

	// if the environment does not have pdf plugin, then it is not possible to run standard test suite
	if (!PDFViewerRenderer._isPdfPluginEnabled() || /HeadlessChrome/.test(window.navigator.userAgent)) {
		return;
	}

	if (TestUtils.isSourceValidationSupported()) {
		// does not make as much sense cause firefox does not allow check it if the content is pdf
		// and also it is not possible to access contentType of document due to cross domain browser policy
		QUnit.test("Different resource's mimeType passed in", function (assert) {
			assert.expect(1);
			var done = assert.async();

			var oOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/different-content.html",
				"loaded": function () {
					if (!Device.browser.firefox) {
						assert.ok(false, "'Load' event should not be fired");
					}

				},
				"error": function (oEvent) {
					oEvent.preventDefault();
					assert.ok(true, "'Error' event fired");
					done();
				},
				"sourceValidationFailed": function (oEvent) {
					if (Device.browser.firefox) {
						assert.ok(true, "'sourceValidationFailed' event fired");
						oEvent.preventDefault();
					} else {
						assert.ok(false, "'sourceValidationFailed' event should not be fired");
					}
				}
			};

			oPDFViewer = TestUtils.createPdfViewer(oOptions);
			TestUtils.renderPdfViewer(oPDFViewer);
		});
	}

	QUnit.test('Error state of component is rendered.', function (assert) {
		assert.expect(3);
		var done = assert.async();

		var oOptions = {
			"source": "test-resources/sap/m/qunit/pdfviewer/not-existing",
			"loaded": function () {
				assert.ok(false, "'Load' event fired but should not.");
			},
			"error": function (oEvent) {
				assert.ok(true, "'Error' event fired");
				assert.ok(oEvent.getParameter("target"), "iFrame element is returned");
			}
		};
		oPDFViewer = TestUtils.createPdfViewer(oOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(4000)()
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				done();
			});
	});

	QUnit.test("Render multiple times with valid or invalid source", function (assert) {
		var done = assert.async(),
			fnLoadedFailListener = function () {
				assert.ok(false, "'Load' event fired but should not.");
			},
			fnErrorOkListener = function (oEvent) {
				assert.ok(true, "'Error' event fired");
				assert.ok(oEvent.getParameter("target"), "iFrame element is returned");
			},
			oErrorOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/not-existing",
				"loaded": fnLoadedFailListener,
				"error": fnErrorOkListener
			},
			fnLoadedOkListener = function () {
				assert.ok(true, "'Load' event fired");
			},
			fnErrorFailListener = function () {
				assert.ok(false, "'Error' event fired but should not");
			};

		oPDFViewer = TestUtils.createPdfViewer(oErrorOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(4000)()
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				oPDFViewer.detachLoaded(fnLoadedFailListener);
				oPDFViewer.detachError(fnErrorOkListener);
				oPDFViewer.attachLoaded(fnLoadedOkListener);
				oPDFViewer.attachError(fnErrorFailListener);
				oPDFViewer.setSource("test-resources/sap/m/qunit/pdfviewer/sample-file.pdf");
				TestUtils.rerender();
			})
			.then(TestUtils.wait(4000))
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 0, 'The error content should be hidden');
				oPDFViewer.detachLoaded(fnLoadedOkListener);
				oPDFViewer.detachError(fnErrorFailListener);
				oPDFViewer.attachLoaded(fnLoadedFailListener);
				oPDFViewer.attachError(fnErrorOkListener);
				oPDFViewer.setSource("test-resources/sap/m/qunit/pdfviewer/not-existing");
				TestUtils.rerender();
			})
			.then(TestUtils.wait(4000))
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				done();
			});
	});

	QUnit.test("Changes of height & width propagates directly to DOM", function (assert) {
		assert.expect(4);
		var done = assert.async(),
			fnInvalidate,
			sExpectedHeight = "666px",
			sExpectedWidth = "999px",
			fnLoadedListener = function () {
				assert.ok(true, "'Load' event should be fired");
			},
			fnSpyPdfViewer = function () {
				fnInvalidate = sinon.spy(oPDFViewer, "invalidate");
			},
			fnErrorListener = function () {
				assert.ok(false, "'Error' event fired");
			},
			oErrorOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/sample-file.pdf",
				"loaded": fnLoadedListener,
				"error": fnErrorListener
			},
			fnChangeHeightHandler = function () {
				oPDFViewer.setHeight(sExpectedHeight);
			},
			fnChangeWidthHandler = function () {
				oPDFViewer.setWidth(sExpectedWidth);
			},
			fnCheckHeight = function () {
				var sCurrentHeight = oPDFViewer.$().css('height');
				assert.ok(sCurrentHeight === sExpectedHeight, "Height differs. Expects: " +
					sExpectedHeight + ", but " + sCurrentHeight + " found.");
			},
			fnCheckWidth = function () {
				var sCurrentWidth = oPDFViewer.$().css('width');
				assert.ok(sCurrentWidth === sExpectedWidth, "Width differs. Expects: " +
					sExpectedWidth + ", but " + sCurrentWidth + " found.");
			};

		oPDFViewer = TestUtils.createPdfViewer(oErrorOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(2000)()
			.then(fnSpyPdfViewer)
			.then(fnChangeHeightHandler)
			.then(fnCheckHeight)
			.then(fnChangeWidthHandler)
			.then(fnCheckWidth)
			.then(function () {
				sinon.assert.callCount(fnInvalidate, 0);
				done();
			});
	});

	QUnit.test("Loads pdf with non ascii name", function (assert) {
		var done = assert.async();

		oPDFViewer = TestUtils.createPdfViewer({
			source: "test-resources/sap/m/qunit/pdfviewer/sample file with spaces.pdf",
			loaded: function fnLoadedHandler() {
				assert.ok(true, "The pdf was loaded");
				done();
			},
			error: function fnErrorHandler() {
				assert.ok(false, "The pdf was loaded");
				done();
			}
		});

		TestUtils.renderPdfViewer(oPDFViewer);
	});

	QUnit.test("Height on mobile/tablet devices is always auto", function (assert) {
		this.stub(Device, "system").value({desktop: false});

		oPDFViewer = TestUtils.createPdfViewer({
			height: '250px',
			source: "test-resources/sap/m/qunit/pdfviewer/sample file with spaces.pdf"
		});

		TestUtils.renderPdfViewer(oPDFViewer);

		assert.equal(oPDFViewer.$()[0].style.height, 'auto');
	});

	QUnit.test("Desktop View Emulated from Mobile", function (assert) {
		this.stub(Device, "system").value({desktop: true});
		this.stub(window.navigator, "pdfViewerEnabled").value(false);

		if (navigator && navigator.pdfViewerEnabled) {
			this.stub(navigator, "pdfViewerEnabled").value(false);
		}

		oPDFViewer = TestUtils.createPdfViewer({
			source: "test-resources/sap/m/qunit/pdfviewer/sample-file.pdf"
		});

		TestUtils.renderPdfViewer(oPDFViewer);

		assert.equal(document.querySelector("iframe"), null, "iFrame is not rendered");
	});

});<commit_msg>[INTERNAL] Qunit fix of PDFViewer<commit_after>/*global QUnit, sinon */

sap.ui.define( [
	"./PDFViewerTestUtils",
	"sap/ui/Device",
	"sap/m/PDFViewerRenderer"
], function (TestUtils, Device, PDFViewerRenderer) {
	"use strict";

	var oPDFViewer;
	QUnit.module('Special use cases', {
		afterEach: function (assert) {
			oPDFViewer.destroy();
		}
	});

	// if the environment does not have pdf plugin, then it is not possible to run standard test suite
	if (!PDFViewerRenderer._isPdfPluginEnabled() || /HeadlessChrome/.test(window.navigator.userAgent)) {
		return;
	}

	if (TestUtils.isSourceValidationSupported()) {
		// does not make as much sense cause firefox does not allow check it if the content is pdf
		// and also it is not possible to access contentType of document due to cross domain browser policy
		QUnit.test("Different resource's mimeType passed in", function (assert) {
			assert.expect(1);
			var done = assert.async();

			var oOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/different-content.html",
				"loaded": function () {
					if (!Device.browser.firefox) {
						assert.ok(false, "'Load' event should not be fired");
					}

				},
				"error": function (oEvent) {
					oEvent.preventDefault();
					assert.ok(true, "'Error' event fired");
					done();
				},
				"sourceValidationFailed": function (oEvent) {
					if (Device.browser.firefox) {
						assert.ok(true, "'sourceValidationFailed' event fired");
						oEvent.preventDefault();
					} else {
						assert.ok(false, "'sourceValidationFailed' event should not be fired");
					}
				}
			};

			oPDFViewer = TestUtils.createPdfViewer(oOptions);
			TestUtils.renderPdfViewer(oPDFViewer);
		});
	}

	QUnit.test('Error state of component is rendered.', function (assert) {
		assert.expect(3);
		var done = assert.async();

		var oOptions = {
			"source": "test-resources/sap/m/qunit/pdfviewer/not-existing",
			"loaded": function () {
				assert.ok(false, "'Load' event fired but should not.");
			},
			"error": function (oEvent) {
				assert.ok(true, "'Error' event fired");
				assert.ok(oEvent.getParameter("target"), "iFrame element is returned");
			}
		};
		oPDFViewer = TestUtils.createPdfViewer(oOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(4000)()
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				done();
			});
	});

	QUnit.test("Render multiple times with valid or invalid source", function (assert) {
		var done = assert.async(),
			fnLoadedFailListener = function () {
				assert.ok(false, "'Load' event fired but should not.");
			},
			fnErrorOkListener = function (oEvent) {
				assert.ok(true, "'Error' event fired");
				assert.ok(oEvent.getParameter("target"), "iFrame element is returned");
			},
			oErrorOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/not-existing",
				"loaded": fnLoadedFailListener,
				"error": fnErrorOkListener
			},
			fnLoadedOkListener = function () {
				assert.ok(true, "'Load' event fired");
			},
			fnErrorFailListener = function () {
				assert.ok(false, "'Error' event fired but should not");
			};

		oPDFViewer = TestUtils.createPdfViewer(oErrorOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(4000)()
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				oPDFViewer.detachLoaded(fnLoadedFailListener);
				oPDFViewer.detachError(fnErrorOkListener);
				oPDFViewer.attachLoaded(fnLoadedOkListener);
				oPDFViewer.attachError(fnErrorFailListener);
				oPDFViewer.setSource("test-resources/sap/m/qunit/pdfviewer/sample-file.pdf");
				TestUtils.rerender();
			})
			.then(TestUtils.wait(4000))
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 0, 'The error content should be hidden');
				oPDFViewer.detachLoaded(fnLoadedOkListener);
				oPDFViewer.detachError(fnErrorFailListener);
				oPDFViewer.attachLoaded(fnLoadedFailListener);
				oPDFViewer.attachError(fnErrorOkListener);
				oPDFViewer.setSource("test-resources/sap/m/qunit/pdfviewer/not-existing");
				TestUtils.rerender();
			})
			.then(TestUtils.wait(4000))
			.then(function () {
				assert.ok(oPDFViewer.$().find('.sapMPDFViewerError').length === 1, 'The error content is missing');
				done();
			});
	});

	QUnit.test("Changes of height & width propagates directly to DOM", function (assert) {
		assert.expect(4);
		var done = assert.async(),
			fnInvalidate,
			sExpectedHeight = "666px",
			sExpectedWidth = "999px",
			fnLoadedListener = function () {
				assert.ok(true, "'Load' event should be fired");
			},
			fnSpyPdfViewer = function () {
				fnInvalidate = sinon.spy(oPDFViewer, "invalidate");
			},
			fnErrorListener = function () {
				assert.ok(false, "'Error' event fired");
			},
			oErrorOptions = {
				"source": "test-resources/sap/m/qunit/pdfviewer/sample-file.pdf",
				"loaded": fnLoadedListener,
				"error": fnErrorListener
			},
			fnChangeHeightHandler = function () {
				oPDFViewer.setHeight(sExpectedHeight);
			},
			fnChangeWidthHandler = function () {
				oPDFViewer.setWidth(sExpectedWidth);
			},
			fnCheckHeight = function () {
				var sCurrentHeight = oPDFViewer.$().css('height');
				assert.ok(sCurrentHeight === sExpectedHeight, "Height differs. Expects: " +
					sExpectedHeight + ", but " + sCurrentHeight + " found.");
			},
			fnCheckWidth = function () {
				var sCurrentWidth = oPDFViewer.$().css('width');
				assert.ok(sCurrentWidth === sExpectedWidth, "Width differs. Expects: " +
					sExpectedWidth + ", but " + sCurrentWidth + " found.");
			};

		oPDFViewer = TestUtils.createPdfViewer(oErrorOptions);
		TestUtils.renderPdfViewer(oPDFViewer);

		TestUtils.wait(2000)()
			.then(fnSpyPdfViewer)
			.then(fnChangeHeightHandler)
			.then(fnCheckHeight)
			.then(fnChangeWidthHandler)
			.then(fnCheckWidth)
			.then(function () {
				sinon.assert.callCount(fnInvalidate, 0);
				done();
			});
	});

	QUnit.test("Loads pdf with non ascii name", function (assert) {
		var done = assert.async();

		oPDFViewer = TestUtils.createPdfViewer({
			source: "test-resources/sap/m/qunit/pdfviewer/sample file with spaces.pdf",
			loaded: function fnLoadedHandler() {
				assert.ok(true, "The pdf was loaded");
				done();
			},
			error: function fnErrorHandler() {
				assert.ok(false, "The pdf was loaded");
				done();
			}
		});

		TestUtils.renderPdfViewer(oPDFViewer);
	});

	QUnit.test("Height on mobile/tablet devices is always auto", function (assert) {
		this.stub(Device, "system").value({desktop: false});

		oPDFViewer = TestUtils.createPdfViewer({
			height: '250px',
			source: "test-resources/sap/m/qunit/pdfviewer/sample file with spaces.pdf"
		});

		TestUtils.renderPdfViewer(oPDFViewer);

		assert.equal(oPDFViewer.$()[0].style.height, 'auto');
	});

	QUnit.test("Desktop View Emulated from Mobile", function (assert) {
		this.stub(Device, "system").value({desktop: true});

		if (window && window.navigator && window.navigator.pdfViewerEnabled) {
            this.stub(navigator, "pdfViewerEnabled").value(false);
        }

		oPDFViewer = TestUtils.createPdfViewer({
			source: "test-resources/sap/m/qunit/pdfviewer/sample-file.pdf"
		});

		TestUtils.renderPdfViewer(oPDFViewer);

		assert.equal(document.querySelector("iframe"), null, "iFrame is not rendered");
	});

});<|endoftext|>


<commit_before>/*
 * ! ${copyright}
 */
sap.ui.define([
	'sap/base/util/merge'
], function(merge) {
	"use strict";

	/*
	* NOTE: As the PropertyInfoFlex is the central change handler for property info
	* processing, it might happen that the in/out handling of the ConditionModel
	* might cause multiple condition changes to be applied in parallel. Due to the
	* asynchronous modifier handling, we need to make sure to queue these changes in their
	* incoming order as parallel processing might falsely overwrite the 'filterConditions' or the 'propertyInfo'
	* properties causing the change handler to break the controls housekeeping and the last
	* parallel filter change would always win.
	*
	* Same processing is done in the ConditionFlex - handler.
	*/
	var fnQueueChange = function(oControl, fTask) {
		var fCleanupPromiseQueue = function(pOriginalPromise) {
			if (oControl._pQueue === pOriginalPromise){
				delete oControl._pQueue;
			}
		};

		oControl._pQueue = oControl._pQueue instanceof Promise ? oControl._pQueue.then(fTask) : fTask();
		oControl._pQueue.then(fCleanupPromiseQueue.bind(null, oControl._pQueue));

		return oControl._pQueue;
	};

	var fAddFilterInfo = function(oChange, oChangeContent, oControl, mPropertyBag) {

		return fnQueueChange(oControl, function(){
			var oModifier = mPropertyBag.modifier;

			return oModifier.getProperty(oControl, "propertyInfo")
			.then(function(aPropertyInfo) {

				var aPropertiesInfo = merge([], aPropertyInfo);
				var nIdx = aPropertiesInfo.findIndex(function(oEntry) {
					return oEntry.name === oChangeContent.name;
				});
				if (nIdx < 0) {
					aPropertiesInfo.push({
						name: oChangeContent.name,
						dataType: oChangeContent.dataType,
						maxConditions: oChangeContent.maxConditions,
						constraints: oChangeContent.constraints,
						formatOptions: oChangeContent.formatOptions,
						required: oChangeContent.required,
						caseSensitive: oChangeContent.caseSensitive,
						display: oChangeContent.display
					});

					oModifier.setProperty(oControl, "propertyInfo", aPropertiesInfo);

					// Set revert data on the change
					oChange.setRevertData({ name: oChangeContent.name});
				}
			});
		});
	};

	var fRemoveFilterInfo = function(oChange, oChangeContent, oControl, mPropertyBag) {

		return fnQueueChange(oControl, function(){
			var oModifier = mPropertyBag.modifier;

			return oModifier.getProperty(oControl, "propertyInfo")
			.then(function(aPropertyInfos) {
				var aPropertiesInfo = merge([], aPropertyInfos);
				var nIdx = aPropertiesInfo.findIndex(function(oEntry) {
					return oEntry.name === oChangeContent.name;
				});
				if (nIdx >= 0) {
					aPropertiesInfo.splice(nIdx, 1);
					oModifier.setProperty(oControl, "propertyInfo", aPropertiesInfo);
				}
			});
		});
	};

	var oPropertyInfoFlex = {};

	oPropertyInfoFlex.addPropertyInfo = {
		"changeHandler": {
			applyChange: function(oChange, oControl, mPropertyBag) {
				return fAddFilterInfo(oChange, oChange.getContent(), oControl, mPropertyBag);
			},
			completeChangeContent: function(oChange, mChangeSpecificInfo, mPropertyBag) {
				// TODO
			},
			revertChange: function(oChange, oControl, mPropertyBag) {
				return fRemoveFilterInfo(oChange, oChange.getRevertData(), oControl, mPropertyBag).then(function() {
					oChange.resetRevertData();
				});
			}
		},
		"layers": {
			"USER": true
		}
	};

	return oPropertyInfoFlex;
});<commit_msg>[INTERNAL][FIX] sap.ui.mdc: Mark changes as not applicable if property already exists<commit_after>/*
 * ! ${copyright}
 */
sap.ui.define([
	"sap/base/util/merge",
	"sap/ui/fl/changeHandler/Base"
], function (
	merge,
	Base
) {
	"use strict";

	/*
	* NOTE: As the PropertyInfoFlex is the central change handler for property info
	* processing, it might happen that the in/out handling of the ConditionModel
	* might cause multiple condition changes to be applied in parallel. Due to the
	* asynchronous modifier handling, we need to make sure to queue these changes in their
	* incoming order as parallel processing might falsely overwrite the 'filterConditions' or the 'propertyInfo'
	* properties causing the change handler to break the controls housekeeping and the last
	* parallel filter change would always win.
	*
	* Same processing is done in the ConditionFlex - handler.
	*/
	var fnQueueChange = function(oControl, fTask) {
		var fCleanupPromiseQueue = function(pOriginalPromise) {
			if (oControl._pQueue === pOriginalPromise){
				delete oControl._pQueue;
			}
		};

		oControl._pQueue = oControl._pQueue instanceof Promise ? oControl._pQueue.then(fTask) : fTask();
		oControl._pQueue.then(fCleanupPromiseQueue.bind(null, oControl._pQueue));

		return oControl._pQueue;
	};

	var fAddFilterInfo = function(oChange, oChangeContent, oControl, mPropertyBag) {

		return fnQueueChange(oControl, function(){
			var oModifier = mPropertyBag.modifier;

			return oModifier.getProperty(oControl, "propertyInfo")
			.then(function(aPropertyInfo) {

				var aPropertiesInfo = merge([], aPropertyInfo);
				var nIdx = aPropertiesInfo.findIndex(function(oEntry) {
					return oEntry.name === oChangeContent.name;
				});
				if (nIdx < 0) {
					aPropertiesInfo.push({
						name: oChangeContent.name,
						dataType: oChangeContent.dataType,
						maxConditions: oChangeContent.maxConditions,
						constraints: oChangeContent.constraints,
						formatOptions: oChangeContent.formatOptions,
						required: oChangeContent.required,
						caseSensitive: oChangeContent.caseSensitive,
						display: oChangeContent.display
					});

					oModifier.setProperty(oControl, "propertyInfo", aPropertiesInfo);

					// Set revert data on the change
					oChange.setRevertData({ name: oChangeContent.name});
				} else {
					return Base.markAsNotApplicable(
						"Property " + oChangeContent.name + " already exists on control " + oModifier.getId(oControl),
						/*bAsync*/true
					);
				}
			});
		});
	};

	var fRemoveFilterInfo = function(oChange, oChangeContent, oControl, mPropertyBag) {

		return fnQueueChange(oControl, function(){
			var oModifier = mPropertyBag.modifier;

			return oModifier.getProperty(oControl, "propertyInfo")
			.then(function(aPropertyInfos) {
				var aPropertiesInfo = merge([], aPropertyInfos);
				var nIdx = aPropertiesInfo.findIndex(function(oEntry) {
					return oEntry.name === oChangeContent.name;
				});
				if (nIdx >= 0) {
					aPropertiesInfo.splice(nIdx, 1);
					oModifier.setProperty(oControl, "propertyInfo", aPropertiesInfo);
				}
			});
		});
	};

	var oPropertyInfoFlex = {};

	oPropertyInfoFlex.addPropertyInfo = {
		"changeHandler": {
			applyChange: function(oChange, oControl, mPropertyBag) {
				return fAddFilterInfo(oChange, oChange.getContent(), oControl, mPropertyBag);
			},
			completeChangeContent: function(oChange, mChangeSpecificInfo, mPropertyBag) {
				// TODO
			},
			revertChange: function(oChange, oControl, mPropertyBag) {
				return fRemoveFilterInfo(oChange, oChange.getRevertData(), oControl, mPropertyBag).then(function() {
					oChange.resetRevertData();
				});
			}
		},
		"layers": {
			"USER": true
		}
	};

	return oPropertyInfoFlex;
});<|endoftext|>


<commit_before>BI.DownListGroupItem = BI.inherit(BI.BasicButton, {
    _defaultConfig: function () {
        var conf = BI.DownListGroupItem.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            baseCls: (conf.baseCls || "") + " bi-down-list-group-item",
            logic: {
                dynamic: false
            },
            // invalid: true,
            iconCls1: "dot-e-font",
            iconCls2: "pull-right-e-font"
        });
    },
    _init: function () {
        BI.DownListGroupItem.superclass._init.apply(this, arguments);
        var o = this.options;
        var self = this;
        this.text = BI.createWidget({
            type: "bi.label",
            cls: "list-group-item-text",
            textAlign: "left",
            text: o.text,
            value: o.value,
            height: o.height
        });

        this.icon1 = BI.createWidget({
            type: "bi.icon_button",
            cls: o.iconCls1,
            width: 36,
            disableSelected: true,
            selected: this._digest(o.value)
        });

        this.icon2 = BI.createWidget({
            type: "bi.icon_button",
            cls: o.iconCls2,
            width: 24,
            forceNotSelected: true
        });

        var blank = BI.createWidget({
            type: "bi.layout",
            width: 24
        });
        BI.createWidget({
            type: "bi.absolute",
            element: this,
            items: [{
                el: this.icon2,
                top: 0,
                bottom: 0,
                right: 0
            }]
        });

        BI.createWidget(BI.extend({
            element: this
        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
            items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon1, this.text, blank)
        }))));

        this.element.hover(function () {
            if (self.isEnabled()) {
                self.hover();
            }
        }, function () {
            if (self.isEnabled()) {
                self.dishover();
            }
        });
    },

    _getLevel: function () {
        var child = BI.first(this.options.childValues);
        return BI.isNotNull(child) ? (child + "").split(BI.BlankSplitChar).length : 0;
    },

    _digest: function (v) {
        var self = this, o = this.options;
        v = BI.isArray(v) ? v : [v];
        var level = this._getLevel();
        return BI.any(v, function (idx, value) {
            return BI.contains(o.childValues, (value + "").split(BI.BlankSplitChar).slice(0, level).join(BI.BlankSplitChar));
        });
    },

    hover: function () {
        BI.DownListGroupItem.superclass.hover.apply(this, arguments);
        this.icon1.element.addClass("hover");
        this.icon2.element.addClass("hover");

    },

    dishover: function () {
        BI.DownListGroupItem.superclass.dishover.apply(this, arguments);
        this.icon1.element.removeClass("hover");
        this.icon2.element.removeClass("hover");
    },

    doClick: function () {
        BI.DownListGroupItem.superclass.doClick.apply(this, arguments);
        if (this.isValid()) {
            this.fireEvent(BI.DownListGroupItem.EVENT_CHANGE, this.getValue());
        }
    },

    doRedMark: function () {
        this.text.doRedMark.apply(this.text, arguments);
    },

    unRedMark: function () {
        this.text.unRedMark.apply(this.text, arguments);
    },

    setValue: function (v) {
        this.icon1.setSelected(this._digest(v));
    }
});
BI.DownListGroupItem.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.down_list_group_item", BI.DownListGroupItem);<commit_msg>Pull request #2621: REPORT-69121 修复DownListGroupItem设置dynamic后左图标没有高度<commit_after>BI.DownListGroupItem = BI.inherit(BI.BasicButton, {
    _defaultConfig: function () {
        var conf = BI.DownListGroupItem.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            baseCls: (conf.baseCls || "") + " bi-down-list-group-item",
            logic: {
                dynamic: false
            },
            // invalid: true,
            iconCls1: "dot-e-font",
            iconCls2: "pull-right-e-font"
        });
    },
    _init: function () {
        BI.DownListGroupItem.superclass._init.apply(this, arguments);
        var o = this.options;
        var self = this;
        this.text = BI.createWidget({
            type: "bi.label",
            cls: "list-group-item-text",
            textAlign: "left",
            text: o.text,
            value: o.value,
            height: o.height
        });

        this.icon1 = BI.createWidget({
            type: "bi.icon_button",
            cls: o.iconCls1,
            width: 36,
            height: o.height,
            disableSelected: true,
            selected: this._digest(o.value)
        });

        this.icon2 = BI.createWidget({
            type: "bi.icon_button",
            cls: o.iconCls2,
            width: 24,
            forceNotSelected: true
        });

        var blank = BI.createWidget({
            type: "bi.layout",
            width: 24
        });
        BI.createWidget({
            type: "bi.absolute",
            element: this,
            items: [{
                el: this.icon2,
                top: 0,
                bottom: 0,
                right: 0
            }]
        });

        BI.createWidget(BI.extend({
            element: this
        }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, {
            items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon1, this.text, blank)
        }))));

        this.element.hover(function () {
            if (self.isEnabled()) {
                self.hover();
            }
        }, function () {
            if (self.isEnabled()) {
                self.dishover();
            }
        });
    },

    _getLevel: function () {
        var child = BI.first(this.options.childValues);
        return BI.isNotNull(child) ? (child + "").split(BI.BlankSplitChar).length : 0;
    },

    _digest: function (v) {
        var self = this, o = this.options;
        v = BI.isArray(v) ? v : [v];
        var level = this._getLevel();
        return BI.any(v, function (idx, value) {
            return BI.contains(o.childValues, (value + "").split(BI.BlankSplitChar).slice(0, level).join(BI.BlankSplitChar));
        });
    },

    hover: function () {
        BI.DownListGroupItem.superclass.hover.apply(this, arguments);
        this.icon1.element.addClass("hover");
        this.icon2.element.addClass("hover");

    },

    dishover: function () {
        BI.DownListGroupItem.superclass.dishover.apply(this, arguments);
        this.icon1.element.removeClass("hover");
        this.icon2.element.removeClass("hover");
    },

    doClick: function () {
        BI.DownListGroupItem.superclass.doClick.apply(this, arguments);
        if (this.isValid()) {
            this.fireEvent(BI.DownListGroupItem.EVENT_CHANGE, this.getValue());
        }
    },

    doRedMark: function () {
        this.text.doRedMark.apply(this.text, arguments);
    },

    unRedMark: function () {
        this.text.unRedMark.apply(this.text, arguments);
    },

    setValue: function (v) {
        this.icon1.setSelected(this._digest(v));
    }
});
BI.DownListGroupItem.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.down_list_group_item", BI.DownListGroupItem);<|endoftext|>


<commit_before>/* SauceNao query Handler
 *
 *
 * Contributed by Capuccino
 */

const got = require('got');
const fs = require('fs');
const urlRegex = str => /(http(s)?:\/\/)?(www\.)?[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi.test(str);

/**
 * Query Handler for SauceNao-related requests.
 * PEPPYNOTE: Do not add Discord-Related hooks here as this would be backported to Sagiri
 */

class SauceHandler {
    /**
     * @param {Object} options Query Options for queries.
     * @param {Number} options.dbMaskI Mask for selecting specific indexes to ENABLE. dbmask=8191 will search all of the first 14 indexes. If intending to search all databases, the db=999 option is more appropriate.
     * @param {Number} options.dbMask  Mask for selecting specific indexes to DISABLE. dbmaski=8191 would search only indexes higher than the first 14. This is ideal when attempting to disable only certain indexes, while allowing future indexes to be included by default.
     * @param {Number} options.outputType 0=normal html 1=xml api(not implemented) 2=json api.
     * @param {Number} options.numRes number to change maximum results requested. Default 5.
     * @param {String} apiKey  API Key for SauceNao.
     */
    constructor(options, apiKey) {
        this.apiKey = apiKey;
        this.options = {
            outputType: 2,
            dbMask: this.dbMask,
            dbMaskI: this.dbMaskI,
            numRes: 5
        };
    }
    getSauce(file, link) {
        if (file === typeof path) {
            /** @todo figure out how to upload images/links in saucenao */
            //do nothing for now
        } else if (link) {
            if (!urlRegex === link) {
                throw new Error('Link is not valid HTTP/HTTPS Address.');
            } else {
                got('').then();
            }
            /** @todo figure out how to upload images/links in saucenao */
            //do nothing for now
        }
    }
}

module.exports = SauceHandler;
<commit_msg>wew why did put a fucking eqeq in here<commit_after>/* SauceNao query Handler
 *
 *
 * Contributed by Capuccino
 */

const got = require('got');
const fs = require('fs');
const urlRegex = str => /(http(s)?:\/\/)?(www\.)?[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi.test(str);

/**
 * Query Handler for SauceNao-related requests.
 * PEPPYNOTE: Do not add Discord-Related hooks here as this would be backported to Sagiri
 */

class SauceHandler {
    /**
     * @param {Object} options Query Options for queries.
     * @param {Number} options.dbMaskI Mask for selecting specific indexes to ENABLE. dbmask=8191 will search all of the first 14 indexes. If intending to search all databases, the db=999 option is more appropriate.
     * @param {Number} options.dbMask  Mask for selecting specific indexes to DISABLE. dbmaski=8191 would search only indexes higher than the first 14. This is ideal when attempting to disable only certain indexes, while allowing future indexes to be included by default.
     * @param {Number} options.outputType 0=normal html 1=xml api(not implemented) 2=json api.
     * @param {Number} options.numRes number to change maximum results requested. Default 5.
     * @param {String} apiKey  API Key for SauceNao.
     */
    constructor(options, apiKey) {
        this.apiKey = apiKey;
        this.options = {
            outputType: 2,
            dbMask: this.dbMask,
            dbMaskI: this.dbMaskI,
            numRes: 5
        };
    }
    getSauce(file, link) {
        if (file === typeof path) {
            /** @todo figure out how to upload images/links in saucenao */
            //do nothing for now
        } else if (link) {
            if (!urlRegex) {
                throw new Error('Link is not valid HTTP/HTTPS Address.');
            } else {
                got('').then();
            }
            /** @todo figure out how to upload images/links in saucenao */
            //do nothing for now
        }
    }
}

module.exports = SauceHandler;
<|endoftext|>