<commit_before>// ==UserScript==
// @name         Risibot
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       Risitop
// @match        http://play.pokemonshowdown.com/*
// @grant        none
// ==/UserScript==

getRoom = function() {
  url = window.location.href;
  while (url[0] != 'b') {
      url = url.slice(1);
  }
  return app.rooms[url];
};

getMaxIndex = function(tab) {
	iM = 0;
	for (i = 1; i < tab.length; i++) {
		if (tab[i] > tab[iM])
			iM = i;
	}
	return iM;
};

///////////////////////////////////////////////////////////////////////////////

function Risibot() {

	this.room = getRoom();

  this.movesParsed = false;
	this.moves = undefined;
  this.buttonsMove = undefined;
  this.lastMove = 0;

	this.ennemyParsed = false;
	this.ennemy = undefined;

	this.pokemonParsed = false;
	this.pokemon = undefined;

	this.havePlayed = false;

	this.AI = new PokeyI(this);
};

Risibot.prototype.choseMove = function() {
	movesInterests = [0, 0, 0, 0];
	for (var moveType in this.moves) {
        for (var j=0; j < this.moves[moveType].length; j++) {
            move = this.moves[moveType][j][0];
            k = this.moves[moveType][j][1];
            switch (moveType) {
                case 'physical':
                case 'physicalS':
                case 'special':
                case 'specialS':
                    movesInterests[k - 1] = this.AI.evalDamagingMove(move);
                    break;
				case 'status':
                    movesInterests[k - 1] = this.AI.evalStatus(move);
                    break;
				case 'traps':
                    movesInterests[k - 1] = this.AI.evalTraps(move);
                    break;
                case 'heal':
                    movesInterests[k - 1] = this.AI.evalHeal(move);
                    break;
<<<<<<< HEAD
								case 'spin':
										movesInterests[k - 1] = this.AI.evalHeal(move);
										break;
=======
		case 'spin':
		    movesInterests[k - 1] = this.AI.evalHeal(move);
		    break;
>>>>>>> b5e8a58d0cac7b151d7b729561c4e602fcf55df1
            }
		}
	}
  console.log(movesInterests);
	choice = getMaxIndex(movesInterests);
	return choice;
};

// Gets a formatted moves object
Risibot.prototype.parseMoves = function() {
	movesTab = [];
	this.buttonsMoves = document.getElementsByName("chooseMove");
    if (this.buttonsMoves.length == 0)
        return undefined;

	for (var i = 0; i < this.buttonsMoves.length; i++) {
		movesTab.push(Tools.getMove(this.buttonsMoves[i].attributes['data-move'].nodeValue));
	}

	this.moves = {
		'traps': [], // Entry hazards
		'status': [], // Thunder wave
		'special': [], // Hydro pump
		'physical': [], // Earthquake
		'boost': [], // Swords dance
		'specialS': [], // Scald
		'physicalS': [], // Dynamic punch
		'specialB': [], // Power up punch
		'physicalB': [], // ?
		'protect': [],
		'seeds': [],
		'defog': [],
		'spin': [],
		'taunt': [],
		'heal': [],
		'cure': [],
		'roar': [],
		'uTurn': [],
		'voltSwitch': [],
		'trick': [],
		'fakeOut': []
	};

	for (i = 0; i < movesTab.length; i++) {
		m = movesTab[i];
        k = parseInt(this.buttonsMoves[i].value);

		// Particular moves
		if (m.id == 'leechseed')
			this.moves.seeds.push( [m, k] );
		else if (m.id == 'rapidspin')
			this.moves.spin.push( [m, k] );
		else if (m.id == 'defog')
			this.moves.defog.push( [m, k] );
		else if (m.id == 'taunt')
			this.moves.taunt.push( [m, k] );
        else if (m.priority == -6)
			this.moves.roar.push( [m, k] );
		else if (m.heal)
			this.moves.heal.push( [m, k] );
		else if (m.target == 'allyTeam')
			this.moves.cure.push( [m, k] );
		else if (m.selfSwitch)
			if (m.baseType == 'bug')
				this.moves.uTurn.push( [m, k] );
			else
				this.moves.voltSwitch.push( [m, k] );
		else if (m.id == 'trick' || m.id == 'switcheroo')
			this.moves.trick.push( [m, k] );
		else if (m.id == 'fakeout')
			this.moves.fakeOut.push( [m, k] );

		else if (m.category == 'Status')	{
			if (m.target == 'foeSide')
				this.moves.traps.push( [m, k] );
			else if (m.status)
				this.moves.status.push( [m, k] );
			else if (m.target == 'self')
				if (m.volatileStatus == 'protect')
					this.moves.protect.push( [m, k] );
				else
					this.moves.boost.push( [m, k] );
		}	else if (m.category == 'Special') {
			if (m.secondaries)
				if (m.boosts)
					this.moves.specialB.push( [m, k] );
				else
					this.moves.specialS.push( [m, k] );
			else
				this.moves.special.push( [m, k] );
		}		else if (m.category == 'Physical') {
			if (m.secondaries)
				if (m.boosts)
					this.moves.physicalB.push( [m, k] );
				else
					this.moves.physicalS.push( [m, k] );
			else
				this.moves.physical.push( [m, k] );
		}
	}

    this.movesParsed = true;
};

Risibot.prototype.getPokemon = function() {
	this.pokemon = this.room.battle.mySide.active;
	if (this.pokemon)
		this.pokemonParsed = true;
};

Risibot.prototype.getEnnemyPokemon = function() {
	this.ennemy = this.room.battle.yourSide.active;
	if (this.ennemy)
		this.ennemyParsed = true;
};

Risibot.prototype.waitingForMe = function(){
	if (!this.room)
		return false;
	else if (!this.room.choice)
		return false;
	else if (!this.room.choice.waiting)
		return true;
	return false;
};

Risibot.prototype.attack = function(id) {
    try {
        this.room.chooseMove(id, this.buttonsMoves[id - 1]);
    } catch (TypeError) {
        this.room.chooseMove(this.lastMove, this.buttonsMoves[this.lastMove - 1]);
        return false;
    }
    return true;
};

Risibot.prototype.routine = function() {

    if (!this.movesParsed) {
        this.parseMoves();
    }
	if (!this.ennemyParsed)
        this.getEnnemyPokemon();
    if (!this.pokemonParsed)
        this.getPokemon();

	if (this.waitingForMe()) {
        if (this.pokemon[0]) {
            m = this.choseMove();
            success = this.attack(m + 1);
            if (success) {
                this.lastMove = m;
            }
            this.movesParsed = false;
            this.ennemyParsed = false;
            this.pokemonParsed = false;
        } else { //Chose another
            placeholder = 1;
        }
	}

    that = this;
	setTimeout( function() { that.routine(); }, 500 );
};

///////////////////////////////////////////////////////////////////////////////

PokeyI = function(bot) {

	this.bot = bot;
};

PokeyI.prototype.evalDamagingMove = function(move) {

	coef = 1.0;
	for (i = 0; i < this.bot.ennemy[0].types.length; i++) {
		t = this.bot.ennemy[0].types[i];
		switch (exports.BattleTypeChart[t]['damageTaken'][move.baseType]) {
			case 1:
				coef *= 2;
				break;
			case 2:
				coef /= 2;
				break;
			case 3:
				coef = 0;
				break;
		}
	}
	for (i = 0; i < this.bot.pokemon[0].types.length; i++) {
		if (this.bot.pokemon[0] && this.bot.pokemon[0].types[i] == move.baseType)
			coef *= 1.5;
	}

  if (move.id == "lowkick") {
		wgt = this.bot.ennemy[0].weightkg;
		if (wgt < 10)
			move.basePower = 20;
		else if (wgt < 25)
			move.basePower = 40;
		else if (wgt < 50)
			move.basePower = 60;
		else if (wgt < 100)
			move.basePower = 80;
		else if (wgt < 200)
			move.basePower = 100;
		else
			move.basePower = 120;
	}

  if (move.accuracy == true)
      move.accuracy = 100;

	volatileEffects = this.getMultiplicator(this.bot.pokemon[0], (move.category == "physical") ? 'atk' : 'spa');

	return coef * move.basePower * (move.accuracy / 100) * volatileEffects;

};

PokeyI.prototype.evalStatus = function(move) {
	coef = 1.0;
	if (this.bot.ennemy[0].status != "" ||
		(move.status == "par" && this.hasType(this.bot.ennemy[0], "Electric")) ||
		(move.status == "brn" && this.hasType(this.bot.ennemy[0], "Fire")) ||
		(move.baseType == "Grass" && this.hasType(this.bot.ennemy[0], "Grass")) ||
		(move.status == "tox" && this.hasType(this.bot.ennemy[0], "Poison"))) {
			return 0;
	}

	switch (move.status) { // DIVISIONS ENTIERES
		case "par":
			coef *= (this.getStat(this.bot.ennemy[0], "spe") / 100);
		case "brn":
			coef *= (this.getStat(this.bot.ennemy[0], "atk") / 100);
		case "slp":
			coef *= (this.getDanger(this.bot.ennemy[0]) / 60);
		case "tox":
			coef *= (this.getBulk(this.bot.ennemy[0]) / 100);
	}

	if (coef < 0.5)
		return 30;
	if (coef < 1)
		return 60;
	if (coef < 1.2)
		return 150;
	return 400;

};

PokeyI.prototype.evalTraps = function(move) {

	if (this.getDanger(this.bot.ennemy[0]) > 100)
		return 0;

	switch (move.id) {
		case "stealthrock":
			if (!this.bot.room.battle.yourSide.sideConditions.stealthrock)
				return 150;
			break;
		case "spikes":
			if (!this.bot.room.battle.yourSide.sideConditions.spikes)
				return 150;
			break;
		case "stickyweb":
			if (!this.bot.room.battle.yourSide.sideConditions.stickyweb)
				return 150;
			break;
	}
	return 0;
};

PokeyI.prototype.evalSpin = function(move) {

    if(jQuery.isEmptyObject(this.bot.room.battle.mySide.sideConditions))
            return 0;
    return 150;
};
<<<<<<< HEAD

=======

>>>>>>> b5e8a58d0cac7b151d7b729561c4e602fcf55df1
PokeyI.prototype.evalHeal = function(move) {

    hp = this.bot.pokemon[0].hp;
    if (hp < 25)
        return 1500;
    if (hp < 50)
        return 1000;
    if (hp < 60)
        return 500;
    if (hp < 75)
        return 100;
    if (hp < 90)
        return 30;
    return 0;
};

PokeyI.prototype.hasType = function(pokemon, type) {
	for (var i = 0; i < pokemon.types.length; i++) {
		if (pokemon.types[i] == type)
			return true;
	}
	return false;
};

PokeyI.prototype.getStat = function(pokemon, stat) {
	return pokemon.baseStats[stat];
};

PokeyI.prototype.getBulk = function(pokemon) {
	return (this.getStat(pokemon, 'hp')/2 +
		Math.max(this.getStat(pokemon, 'def'), this.getStat(pokemon, 'spd')) / 2);
};

PokeyI.prototype.getDanger = function(pokemon) {
	return (this.getStat(pokemon, 'spe')/2 +
		Math.max(this.getStat(pokemon, 'atk'), this.getStat(pokemon, 'spa')) / 2);
};

PokeyI.prototype.getMultiplicator = function(pokemon, stat) {
    console.log(pokemon.boosts[stat]);
	if (pokemon.boosts[stat] > 0)
		return 1.0 + 0.5 * pokemon.boosts[stat];
	else if (pokemon.boosts[stat] < 0)
        switch (pokemon.boosts[stat]) {
            case -1:
                return 0.67;
            case -2:
                return 0.5;
            case -3:
                return 0.4;
            case -4:
                return 0.33;
            case -5:
                return 0.29;
            case -6:
                return 0.25;
        }
    return 1.0;
};
///////////////////////////////////////////////////////////////////////////////

risibotWatcher = function() {
    console.log("Watcher");
    if (window.location.href != "http://play.pokemonshowdown.com/") {
        room = getRoom();
        if (room)
        {
            if (room.chatHistory.lines[room.chatHistory.lines.length - 1] === "La chancla !") {
                risitas = new Risibot();
                risitas.routine(null);
                return;
            }
        }
    }
	setTimeout( risibotWatcher, 500 );
};

<<<<<<< HEAD
risibotWatcher();
=======
risibotWatcher();
>>>>>>> b5e8a58d0cac7b151d7b729561c4e602fcf55df1
<commit_msg>Update Risibot.js<commit_after>// ==UserScript==
// @name         Risibot
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       Risitop
// @match        http://play.pokemonshowdown.com/*
// @grant        none
// ==/UserScript==

getRoom = function() {
  url = window.location.href;
  while (url[0] != 'b') {
      url = url.slice(1);
  }
  return app.rooms[url];
};

getMaxIndex = function(tab) {
	iM = 0;
	for (i = 1; i < tab.length; i++) {
		if (tab[i] > tab[iM])
			iM = i;
	}
	return iM;
};

///////////////////////////////////////////////////////////////////////////////

function Risibot() {

	this.room = getRoom();

  this.movesParsed = false;
	this.moves = undefined;
  this.buttonsMove = undefined;
  this.lastMove = 0;

	this.ennemyParsed = false;
	this.ennemy = undefined;

	this.pokemonParsed = false;
	this.pokemon = undefined;

	this.havePlayed = false;

	this.AI = new PokeyI(this);
};

Risibot.prototype.choseMove = function() {
	movesInterests = [0, 0, 0, 0];
	for (var moveType in this.moves) {
        for (var j=0; j < this.moves[moveType].length; j++) {
            move = this.moves[moveType][j][0];
            k = this.moves[moveType][j][1];
            switch (moveType) {
                case 'physical':
                case 'physicalS':
                case 'special':
                case 'specialS':
                    movesInterests[k - 1] = this.AI.evalDamagingMove(move);
                    break;
				case 'status':
                    movesInterests[k - 1] = this.AI.evalStatus(move);
                    break;
				case 'traps':
                    movesInterests[k - 1] = this.AI.evalTraps(move);
                    break;
                case 'heal':
                    movesInterests[k - 1] = this.AI.evalHeal(move);
                    break;
								case 'spin':
                    movesInterests[k - 1] = this.AI.evalsSpin(move);
                    break;
            }
		}
	}
  console.log(movesInterests);
	choice = getMaxIndex(movesInterests);
	return choice;
};

// Gets a formatted moves object
Risibot.prototype.parseMoves = function() {
	movesTab = [];
	this.buttonsMoves = document.getElementsByName("chooseMove");
    if (this.buttonsMoves.length == 0)
        return undefined;

	for (var i = 0; i < this.buttonsMoves.length; i++) {
		movesTab.push(Tools.getMove(this.buttonsMoves[i].attributes['data-move'].nodeValue));
	}

	this.moves = {
		'traps': [], // Entry hazards
		'status': [], // Thunder wave
		'special': [], // Hydro pump
		'physical': [], // Earthquake
		'boost': [], // Swords dance
		'specialS': [], // Scald
		'physicalS': [], // Dynamic punch
		'specialB': [], // Power up punch
		'physicalB': [], // ?
		'protect': [],
		'seeds': [],
		'defog': [],
		'spin': [],
		'taunt': [],
		'heal': [],
		'cure': [],
		'roar': [],
		'uTurn': [],
		'voltSwitch': [],
		'trick': [],
		'fakeOut': []
	};

	for (i = 0; i < movesTab.length; i++) {
		m = movesTab[i];
        k = parseInt(this.buttonsMoves[i].value);

		// Particular moves
		if (m.id == 'leechseed')
			this.moves.seeds.push( [m, k] );
		else if (m.id == 'rapidspin')
			this.moves.spin.push( [m, k] );
		else if (m.id == 'defog')
			this.moves.defog.push( [m, k] );
		else if (m.id == 'taunt')
			this.moves.taunt.push( [m, k] );
        else if (m.priority == -6)
			this.moves.roar.push( [m, k] );
		else if (m.heal)
			this.moves.heal.push( [m, k] );
		else if (m.target == 'allyTeam')
			this.moves.cure.push( [m, k] );
		else if (m.selfSwitch)
			if (m.baseType == 'bug')
				this.moves.uTurn.push( [m, k] );
			else
				this.moves.voltSwitch.push( [m, k] );
		else if (m.id == 'trick' || m.id == 'switcheroo')
			this.moves.trick.push( [m, k] );
		else if (m.id == 'fakeout')
			this.moves.fakeOut.push( [m, k] );

		else if (m.category == 'Status')	{
			if (m.target == 'foeSide')
				this.moves.traps.push( [m, k] );
			else if (m.status)
				this.moves.status.push( [m, k] );
			else if (m.target == 'self')
				if (m.volatileStatus == 'protect')
					this.moves.protect.push( [m, k] );
				else
					this.moves.boost.push( [m, k] );
		}	else if (m.category == 'Special') {
			if (m.secondaries)
				if (m.boosts)
					this.moves.specialB.push( [m, k] );
				else
					this.moves.specialS.push( [m, k] );
			else
				this.moves.special.push( [m, k] );
		}		else if (m.category == 'Physical') {
			if (m.secondaries)
				if (m.boosts)
					this.moves.physicalB.push( [m, k] );
				else
					this.moves.physicalS.push( [m, k] );
			else
				this.moves.physical.push( [m, k] );
		}
	}

    this.movesParsed = true;
};

Risibot.prototype.getPokemon = function() {
	this.pokemon = undefined;
	for (i = 0; i<this.room.battle.myPokemon) {
		if (this.room.battle.pokemon[i] == 'active')
			this.pokemon = this.room.battle.pokemon[i];
	}
	if (this.pokemon)
		this.pokemonParsed = true;
};

Risibot.prototype.getEnnemyPokemon = function() {
	this.ennemy = this.room.battle.yourSide.active;
	if (this.ennemy)
		this.ennemyParsed = true;
};

Risibot.prototype.waitingForMe = function(){
	if (!this.room)
		return false;
	else if (!this.room.choice)
		return false;
	else if (!this.room.choice.waiting)
		return true;
	return false;
};

Risibot.prototype.attack = function(id) {
    try {
        this.room.chooseMove(id, this.buttonsMoves[id - 1]);
    } catch (TypeError) {
        this.room.chooseMove(this.lastMove, this.buttonsMoves[this.lastMove - 1]);
        return false;
    }
    return true;
};

Risibot.prototype.routine = function() {

    if (!this.movesParsed) {
        this.parseMoves();
    }
	if (!this.ennemyParsed)
        this.getEnnemyPokemon();
    if (!this.pokemonParsed)
        this.getPokemon();

	if (this.waitingForMe()) {
        if (this.pokemon[0]) {
            m = this.choseMove();
            success = this.attack(m + 1);
            if (success) {
                this.lastMove = m;
            }
            this.movesParsed = false;
            this.ennemyParsed = false;
            this.pokemonParsed = false;
        } else { //Chose another
            placeholder = 1;
        }
	}

    that = this;
	setTimeout( function() { that.routine(); }, 500 );
};

///////////////////////////////////////////////////////////////////////////////

PokeyI = function(bot) {

	this.bot = bot;
};

PokeyI.prototype.evalDamagingMove = function(move) {

	coef = 1.0;
	for (i = 0; i < this.bot.ennemy[0].types.length; i++) {
		t = this.bot.ennemy[0].types[i];
		switch (exports.BattleTypeChart[t]['damageTaken'][move.baseType]) {
			case 1:
				coef *= 2;
				break;
			case 2:
				coef /= 2;
				break;
			case 3:
				coef = 0;
				break;
		}
	}
	for (i = 0; i < this.bot.pokemon[0].types.length; i++) {
		if (this.bot.pokemon[0] && this.bot.pokemon[0].types[i] == move.baseType)
			coef *= 1.5;
	}

  if (move.id == "lowkick") {
		wgt = this.bot.ennemy[0].weightkg;
		if (wgt < 10)
			move.basePower = 20;
		else if (wgt < 25)
			move.basePower = 40;
		else if (wgt < 50)
			move.basePower = 60;
		else if (wgt < 100)
			move.basePower = 80;
		else if (wgt < 200)
			move.basePower = 100;
		else
			move.basePower = 120;
	}

  if (move.accuracy == true)
      move.accuracy = 100;

	volatileEffects = this.getMultiplicator(this.bot.pokemon[0], (move.category == "physical") ? 'atk' : 'spa');

	return coef * move.basePower * (move.accuracy / 100) * volatileEffects;

};

PokeyI.prototype.evalStatus = function(move) {
	coef = 1.0;
	if (this.bot.ennemy[0].status != "" ||
		(move.status == "par" && this.hasType(this.bot.ennemy[0], "Electric")) ||
		(move.status == "brn" && this.hasType(this.bot.ennemy[0], "Fire")) ||
		(move.baseType == "Grass" && this.hasType(this.bot.ennemy[0], "Grass")) ||
		(move.status == "tox" && this.hasType(this.bot.ennemy[0], "Poison"))) {
			return 0;
	}

	switch (move.status) {
		case "par":
			coef *= (this.getStat(this.bot.ennemy[0], "spe") / 100);
		case "brn":
			coef *= (this.getStat(this.bot.ennemy[0], "atk") / 100);
		case "slp":
			coef *= (this.getDanger(this.bot.ennemy[0]) / 60);
		case "tox":
			coef *= (this.getBulk(this.bot.ennemy[0]) / 100);
	}

	if (coef < 0.5)
		return 30;
	if (coef < 1)
		return 60;
	if (coef < 1.2)
		return 150;
	return 400;

};

PokeyI.prototype.evalSpin = function(move) {

  if(jQuery.isEmptyObject(this.bot.room.battle.mySide.sideConditions))
    return 0;
  return 150;
};

PokeyI.prototype.evalTraps = function(move) {

	if (this.getDanger(this.bot.ennemy[0]) > 100)
		return 0;

	switch (move.id) {
		case "stealthrock":
			if (!this.bot.room.battle.yourSide.sideConditions.stealthrock)
				return 150;
			break;
		case "spikes":
			if (!this.bot.room.battle.yourSide.sideConditions.spikes)
				return 150;
			break;
		case "stickyweb":
			if (!this.bot.room.battle.yourSide.sideConditions.stickyweb)
				return 150;
			break;
	}
	return 0;
};

PokeyI.prototype.evalHeal = function(move) {

	hp = this.bot.pokemon[0].hp;
    if (hp < 25)
        return 1500;
    if (hp < 50)
        return 1000;
    if (hp < 60)
        return 500;
    if (hp < 75)
        return 100;
    if (hp < 90)
        return 30;
    return 0;
};

PokeyI.prototype.hasType = function(pokemon, type) {
	for (var i = 0; i < pokemon.types.length; i++) {
		if (pokemon.types[i] == type)
			return true;
	}
	return false;
};

PokeyI.prototype.getStat = function(pokemon, stat) {
	return pokemon.baseStats[stat];
};

PokeyI.prototype.getBulk = function(pokemon) {
	return (this.getStat(pokemon, 'hp')/2 +
		Math.max(this.getStat(pokemon, 'def'), this.getStat(pokemon, 'spd')) / 2);
};

PokeyI.prototype.getDanger = function(pokemon) {
	return (this.getStat(pokemon, 'spe')/2 / (pokemon.status == 'par' ? 2 : 1) +
		Math.max(this.getStat(pokemon, 'atk') / (pokemon.status == 'par' ? 2 : 1), this.getStat(pokemon, 'spa') / (pokemon.status == 'par' ? 2 : 1)) / 2);
};

PokeyI.prototype.getMultiplicator = function(pokemon, stat) {
    console.log(pokemon.boosts[stat]);
	if (pokemon.boosts[stat] > 0)
		return 1.0 + 0.5 * pokemon.boosts[stat];
	else if (pokemon.boosts[stat] < 0)
        switch (pokemon.boosts[stat]) {
            case -1:
                return 0.67;
            case -2:
                return 0.5;
            case -3:
                return 0.4;
            case -4:
                return 0.33;
            case -5:
                return 0.29;
            case -6:
                return 0.25;
        }
    return 1.0;
};
///////////////////////////////////////////////////////////////////////////////

risibotWatcher = function() {
    console.log("Watcher");
    if (window.location.href != "http://play.pokemonshowdown.com/") {
        room = getRoom();
        if (room)
        {
            if (room.chatHistory.lines[room.chatHistory.lines.length - 1] === "La chancla !") {
                risitas = new Risibot();
                risitas.routine(null);
                return;
            }
        }
    }
	setTimeout( risibotWatcher, 500 );
};

risibotWatcher();
<|endoftext|>


<commit_before>/**
 * The Publishable Behaviour class
 *
 * @constructor
 * @extends       alchemy.classes.Behaviour
 *
 * @author        Jelle De Loecker   <jelle@codedor.be>
 * @since         0.1.0
 * @version       0.1.0
 */
Behaviour.extend(function PublishableBehaviour (){

	/**
	 * Set publish options
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.0
	 * @version  0.1.0
	 */
	this.beforeFind = function beforeFind(next, options) {

		var dateCondition;

		if (options.publishableDate) {

			if (Date.isDate(options.publishableDate)) {
				dateCondition = options.publishableDate;
			} else {
				dateCondition = new Date();
			}

			if (!options.conditions.$and) {
				options.conditions.$and = [];
			}

			options.conditions.$and.push({
				$or: [
					// Or the publish date is lower than the given date
					{publish_date: {$lt: dateCondition}},
					// Or no publish date is set
					{publish_date: {$exists: false}}
				]
			});
		}

		next();
	};

});<commit_msg>Fix bug in publishable behaviour<commit_after>/**
 * The Publishable Behaviour class
 *
 * @constructor
 * @extends       alchemy.classes.Behaviour
 *
 * @author        Jelle De Loecker   <jelle@codedor.be>
 * @since         0.1.0
 * @version       0.1.0
 */
Behaviour.extend(function PublishableBehaviour (){

	/**
	 * Set publish options
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.0
	 * @version  0.1.0
	 */
	this.beforeFind = function beforeFind(next, options) {

		var dateCondition;

		if (options.publishableDate) {

			if (Date.isDate(options.publishableDate)) {
				dateCondition = options.publishableDate;
			} else {
				dateCondition = new Date();
			}

			if (!options.conditions.$and) {
				options.conditions.$and = [];
			} else if (!Array.isArray(options.conditions.$and)) {
				options.conditions.$and = [options.conditions.$and];
			}

			options.conditions.$and.push({
				$or: [
					// Or the publish date is lower than the given date
					{publish_date: {$lt: dateCondition}},
					// Or no publish date is set
					{publish_date: {$exists: false}}
				]
			});
		}

		next();
	};

});<|endoftext|>


<commit_before>var sys = require("sys"),
    utils = require("utils");

var Events = require("./events");

var SuperClass = require("superclass");
Channel = module.exports = new SuperClass;

Channel.extend({
  channels: {},

  find: function(name){
    if ( !this.channels[name] )
      this.channels[name] = new Channel(name)
    return this.channels[name];
  },

  publish: function(message){
    var channels = message.getChannels();
    delete message.channels;

    sys.log(
      "Publishing to channels: " +
      utils.inspect(channels) + " : " + message.data
    );

    for(var i=0, len = channels.length; i < len; i++) {
      message.channel = channels[i];
      var clients     = this.find(channels[i]).clients;

      for(var x=0, len = clients.length; x < len; x++)
        clients[x].write(message);
    }
  },

  unsubscribe: function(client){
    for (var name in this.channels)
      this.channels[name].unsubscribe(client);
  }
});

Channel.include({
  init: function(name){
    this.name    = name;
    this.clients = [];
  },

  subscribe: function(client){
    this.clients.push(client);
    Events.subscribe(this, client);
  },

  unsubscribe: function(client){
    this.clients.delete(client)
    Events.unsubscribe(this, client);
  }
});<commit_msg>Fix two bugs. First is that the unsubscribe event is triggered even if the client isn't subscribed. Second is that that messages weren't being sent to all clients due to the 'len' variable being cached.<commit_after>var sys = require("sys"),
    utils = require("utils");

var Events = require("./events");

var SuperClass = require("superclass");
Channel = module.exports = new SuperClass;

Channel.extend({
  channels: {},

  find: function(name){
    if ( !this.channels[name] )
      this.channels[name] = new Channel(name)
    return this.channels[name];
  },

  publish: function(message){
    var channels = message.getChannels();
    delete message.channels;

    sys.log(
      "Publishing to channels: " +
      channels.join(", ") + " : " + message.data
    );

    for(var i=0, len = channels.length; i < len; i++) {
      message.channel = channels[i];
      var clients     = this.find(channels[i]).clients;

      for(var x=0, len2 = clients.length; x < len2; x++) {
        clients[x].write(message);
      }
    }
  },

  unsubscribe: function(client){
    for (var name in this.channels)
      this.channels[name].unsubscribe(client);
  }
});

Channel.include({
  init: function(name){
    this.name    = name;
    this.clients = [];
  },

  subscribe: function(client){
    this.clients.push(client);
    Events.subscribe(this, client);
  },

  unsubscribe: function(client){
    if ( !this.clients.include(client) ) return;
    this.clients = this.clients.delete(client);
    Events.unsubscribe(this, client);
  }
});<|endoftext|>


<commit_before>require(["dijit/Dialog", "dijit/form/Button", "dojo/domReady!", "dojox/widget/DialogSimple", "dojo/io-query"], function(Dialog, Button, ready, simple, ioQuery){

    var detailed_threshold = 15;

    var dlg = new dojox.widget.DialogSimple({
           title:"perfSONAR Chart",
           style: "width: 85%; height:85%; max-height:750px",
           },
       'chartDialog');

    dlg.connect(dlg, "hide", function(e){
        clear_iframe();
        });

    var createDialog = function(source, dest) {
        clear_iframe();
        var iframe = dojo.byId('chart_iframe');
        iframe.src = "/serviceTest/graphWidget.cgi?source="  + source + "&dest="
            + dest + "&url=" + ma_url;

        dlg.show();

    };

    var clear_iframe = function() {
        var iframe = dojo.byId('chart_iframe');
        iframe.src = ''; // Clear the iframe
    };

    var ma_url = 'http%3A%2F%2Flocalhost%2Fesmond%2Fperfsonar%2Farchive%2F';
    var uri = document.URL;
    if (uri.indexOf('?') > -1) {
	var query = uri.substring(uri.indexOf("?") + 1, uri.length);
	var queryObject = ioQuery.queryToObject(query);
	if (queryObject.url) {
	    ma_url = queryObject.url;
	    if (ma_url.indexOf('#') > -1) {
		ma_url = ma_url.substring(0, ma_url.indexOf('#'));
	    }
	}
    }
    //ma_url = encodeURI(ma_url);

    var url = '/serviceTest/graphData.cgi?action=test_list&url=' + ma_url;
    d3.json(url, function(list_error, list_data) {
        var detailed = true;
        if (list_error) { display_error('Error retrieving test data: ' + list_error.statusText); };
        if (list_data.length > detailed_threshold) {
            detailed = false;
            render_test_table(list_error, list_data, detailed);
        } else {
            var url = '/serviceTest/graphData.cgi?action=tests&url=' + ma_url;
            d3.json(url, function(error, ps_data) {
                render_test_table(error, ps_data, detailed);
            });
        }
    });

    function display_error(error_message) {
        var div = d3.selectAll('.psGraphError');
        div.html(error_message);
        d3.select('#summaryTable').style('display', 'none');
        d3.select('#loading').style('display', 'none');
    }

    function render_test_table(error, ps_data, detailed) {

                var ndx = crossfilter(ps_data);
                var tableDimension = ndx.dimension(function (d) { return d.source; });
                var dataTable = dc.dataTable(".dc-data-table");
                var now_seconds = new Date() / 1000; // current date in seconds since the epoch

                var inactive_threshold = now_seconds - 86400 * 7; // now minus 7 days
                var order = 'asc';

                dataTable.on("postRender", function(chart){ d3.select('#loading').style('display', 'none');  });

                dataTable.renderlet(function(table) {
                    var rows = d3.selectAll('#summaryTable tr.dc-table-row');
                    rows.on('click', function(node) {
                        var src = node.source;
                        var dest = node.destination;
                        createDialog(src, dest);
                        });
                    });

                var sourceHeader = d3.select('#sourceHeader');
                var destHeader = d3.select('#destHeader');
                var sortHeaders = d3.selectAll('.sortHeader');
                var sortHeaderDivs = sortHeaders.insert('span');
                sortHeaderDivs.classed('sort', true);

                var sourceDiv = d3.select('#sourceHeader span.sort');
                sourceDiv.classed('asc', true);
                var destDiv = d3.select('#destHeader span.sort');

                sourceHeader.on('click', function(node){
                        set_sort('source');
                        } );

                destHeader.on('click', function(node){
                        set_sort('destination');
                        } );

                var set_sort = function(sort_field) {
                    dataTable.sortBy( function(d) { return format_host(d, sort_field); } );

                    // Remove all icon classes
                    destDiv.classed("asc", false);
                    destDiv.classed("desc", false);
                    sourceDiv.classed("asc", false);
                    sourceDiv.classed("desc", false);

                    if (order == 'asc') {
                        // order is currently asc, change to desc
                        order = 'desc';
                        dataTable.order(d3.descending);
                        if (sort_field == 'source') {
                            sourceDiv.classed("desc", true);
                        } else {
                            destDiv.classed("desc", true);
                        }
                    } else {
                        // order is currently desc, change to asc
                        order = 'asc';
                        dataTable.order(d3.ascending);
                        if (sort_field == 'source') {
                            sourceDiv.classed("asc", true);
                        } else {
                            destDiv.classed("asc", true);
                        }
                    }
                    dataTable.redraw();

                }

                dataTable.width(400)
                    .height(400)
                    .dimension(tableDimension)
                    .group(function(d) { return "perfSONAR Test Result Summary" })
                    .size(100)
                if (detailed) {
                    dataTable.columns([
                            function(d) { return '' + format_host(d, 'source') + ''; },
                            function(d) { return '' + format_host(d, 'destination') + ''; },
                            function(d) { return format_stats(d, 'throughput_src'); },
                            function(d) { return format_stats(d, 'throughput_dst'); },
                            function(d) { return format_stats(d, 'owdelay_src'); },
                            function(d) { return format_stats(d, 'owdelay_dst'); },
                            function(d) { return format_stats(d, 'loss_src'); },
                            function(d) { return format_stats(d, 'loss_dst'); }
                            ]);
                } else {
                    dataTable.columns([
                        function(d) { return '' + format_host_list(d, 'source') + ''; },
                        function(d) { return '' + format_host_list(d, 'destination') + ''; }
                    ]);
                    d3.selectAll('.detailedOnly').style('display', 'none');
                }

                var format_stats = function(d, prefix) {
                    var format_str = '';
                    var suffix = '';
                    var avg = null;
                    var min = null;
                    var max = null;

                    avg = d[prefix + '_average'];
                    min = d[prefix + '_min'];
                    max = d[prefix + '_max'];

                    if ((/^throughput_/).test(prefix)) {
                        format_str = '.3s';
                        suffix = 'bps';
                    } else if ((/^owdelay_/).test(prefix)) {
                        format_str = '.2f';
                    } else if ((/^loss_/).test(prefix)) {
                        format_str = '.2f';
                    }

                    // Account for the last_update field name not including _src or _dst
                    prefix = prefix.replace('_src', '');
                    prefix = prefix.replace('_dst', '');

                    var data = new Array();

                    var inactive;
                    var last_update_key = prefix + '_last_update';
                    if (d[last_update_key] != null && d[last_update_key] < inactive_threshold) {
                        inactive = true;
                    } else {
                        inactive = false;
                    }

                    data[0] = new Object();

                    if (avg !== null && ! isNaN(avg)){
                        var prefix = d3.formatPrefix(avg);
                        data[0].value = prefix.scale(avg).toFixed(2) + " " + prefix.symbol + suffix;
                    }
                    else {
                        data[0].value = "n/a";
                    }

                    data[0].inactive = inactive;

                    var ret = format_output(data);
                    return ret;
                }

                var format_output = function(data) {
                    var ret = '';
                    var inactive_class = '';
                    ret += '
';
                    for(var d in data) {
                        inactive_class = '';
                        if (data[d].inactive) {
                            inactive_class = ' inactive';
                        }
                        ret += '
';
                        ret += '' +
                            '	' +
                            ((data[d].value !== null
                              && typeof data[d].value !== 'undefined')
                             ? data[d].value
                             : 'n/a ')
                            +  '	';
                        ret += '
';
                    }
                    ret += "
";
                    return ret;
                }

                var format_test_values = function(d, suffix) {
                    var ret = '';
                    var data = new Array();
                    data[0] = new Object();
                    data[0].label = 'throughput';
                    data[0].value = d["throughput_" + suffix];
                    if (d["throughput_last_update"] < inactive_threshold) {
                        data[0].inactive = true;
                    } else {
                        data[0].inactive = false;
                    }
                    data[1] = new Object();
                    data[1].label = 'latency';
                    data[1].value = d["owdelay_" + suffix];
                    if (d["owdelay_last_update"] < inactive_threshold) {
                        data[1].inactive = true;
                    } else {
                        data[1].inactive = false;
                    }
                    data[2] = new Object();
                    data[2].label = 'loss';
                    data[2].value = d["loss_" + suffix];
                    if (d["loss_last_update"] < inactive_threshold) {
                        data[2].inactive = true;
                    } else {
                        data[2].inactive = false;
                    }

                    ret = format_output(data);

                    return ret;
                }

                var format_host_list = function(d, type) {
                    var ret = '';
                    if (d[type + '_host']) {
                       ret += d[type + '_host'];
                    }
                    if (d[type + '_ip'] && d[type + '_ip'] != d[type + '_host']) {
                        ret += ' (' + d[type + '_ip'] + ') ';
                    } else {
                        ret = d[type];
                    }
                    if (d.last_updated < inactive_threshold) {
                        ret = '' + ret + '';
                    }
                    return ret;
                }

                var format_host = function(d, type) {
                    var ret = '';
                    if (d['throughput_' + type + '_host'] !== undefined && d['throughput_' + type + '_host'] !== null) {
                        ret = d['throughput_' + type + '_host'];
                    } else if (d['owdelay_' + type + '_host'] !== undefined && d['owdelay_' + type + '_host'] !== null) {
                        ret = d['owdelay_' + type + '_host'];
                    } else if (d['loss_' + type + '_host'] !== undefined && d['loss_' + type + '_host'] !== null) {
                        ret = d['loss_' + type + '_host'];
                    }
                    ret += '  (' + d[type]  + ')';
                            return ret;
                            }

                            var format_bidirectional = function(d) {
                            var ret = '';
                            var data = new Array();
                            data[0] = new Object();
                            data[0].label = 'throughput';
                            data[0].value = format_boolean(d.throughput_bidirectional);
                            data[1] = new Object();
                            data[1].label = 'latency';
                            data[1].value = format_boolean(d.owdelay_bidirectional);
                            data[2] = new Object();
                            data[2].label = 'loss';
                            data[2].value = format_boolean(d.loss_bidirectional);
                            ret = format_output(data);

                            return ret;
                            }

                            var format_boolean = function(val) {
                                var ret = '';
                                if (val === 1) {
                                    ret = 'yes';
                                } else {
                                    ret = 'no';
                                }
                                return ret;
                            }

                            dc.renderAll();

    } // end render_test_table()

    }); // end dojo function
<commit_msg>Improve sorting on the table listing all tests<commit_after>require(["dijit/Dialog", "dijit/form/Button", "dojo/domReady!", "dojox/widget/DialogSimple", "dojo/io-query"], function(Dialog, Button, ready, simple, ioQuery){

    var detailed_threshold = 15;

    var dlg = new dojox.widget.DialogSimple({
           title:"perfSONAR Chart",
           style: "width: 85%; height:85%; max-height:750px",
           },
       'chartDialog');

    dlg.connect(dlg, "hide", function(e){
        clear_iframe();
        });

    var createDialog = function(source, dest) {
        clear_iframe();
        var iframe = dojo.byId('chart_iframe');
        iframe.src = "/serviceTest/graphWidget.cgi?source="  + source + "&dest="
            + dest + "&url=" + ma_url;

        dlg.show();

    };

    var clear_iframe = function() {
        var iframe = dojo.byId('chart_iframe');
        iframe.src = ''; // Clear the iframe
    };

    var ma_url = 'http%3A%2F%2Flocalhost%2Fesmond%2Fperfsonar%2Farchive%2F';
    var uri = document.URL;
    if (uri.indexOf('?') > -1) {
	var query = uri.substring(uri.indexOf("?") + 1, uri.length);
	var queryObject = ioQuery.queryToObject(query);
	if (queryObject.url) {
	    ma_url = queryObject.url;
	    if (ma_url.indexOf('#') > -1) {
		ma_url = ma_url.substring(0, ma_url.indexOf('#'));
	    }
	}
    }
    //ma_url = encodeURI(ma_url);

    var url = '/serviceTest/graphData.cgi?action=test_list&url=' + ma_url;
    d3.json(url, function(list_error, list_data) {
        var detailed = true;
        if (list_error) { display_error('Error retrieving test data: ' + list_error.statusText); };
        if (list_data.length > detailed_threshold) {
            detailed = false;
            render_test_table(list_error, list_data, detailed);
        } else {
            var url = '/serviceTest/graphData.cgi?action=tests&url=' + ma_url;
            d3.json(url, function(error, ps_data) {
                render_test_table(error, ps_data, detailed);
            });
        }
    });

    function display_error(error_message) {
        var div = d3.selectAll('.psGraphError');
        div.html(error_message);
        d3.select('#summaryTable').style('display', 'none');
        d3.select('#loading').style('display', 'none');
    }

    function render_test_table(error, ps_data, detailed) {

                var ndx = crossfilter(ps_data);
                var tableDimension = ndx.dimension(function (d) { return d.source; });
                var dataTable = dc.dataTable(".dc-data-table");
                var now_seconds = new Date() / 1000; // current date in seconds since the epoch

                var inactive_threshold = now_seconds - 86400 * 7; // now minus 7 days
                var order = 'asc';

                dataTable.on("postRender", function(chart){ d3.select('#loading').style('display', 'none');
                    order = 'desc';
                    set_sort('source_name');

                        });

                dataTable.renderlet(function(table) {
                    var rows = d3.selectAll('#summaryTable tr.dc-table-row');
                    rows.on('click', function(node) {
                        var src = node.source;
                        var dest = node.destination;
                        createDialog(src, dest);
                        });
                    });

                var sourceHeader = d3.select('#sourceHeader');
                var destHeader = d3.select('#destHeader');
                var sortHeaders = d3.selectAll('.sortHeader');
                var sortHeaderDivs = sortHeaders.insert('span');
                sortHeaderDivs.classed('sort', true);

                var sourceDiv = d3.select('#sourceHeader span.sort');
                sourceDiv.classed('asc', true);
                var destDiv = d3.select('#destHeader span.sort');

                sourceHeader.on('click', function(node){
                        set_sort('source_name');
                        } );

                destHeader.on('click', function(node){
                        set_sort('destination_name');
                        } );

                var set_sort = function(sort_field) {
                    dataTable.sortBy( function(d) { return format_host(d, sort_field); } );

                    // Remove all icon classes
                    destDiv.classed("asc", false);
                    destDiv.classed("desc", false);
                    sourceDiv.classed("asc", false);
                    sourceDiv.classed("desc", false);

                    if (order == 'asc') {
                        // order is currently asc, change to desc
                        order = 'desc';
                        dataTable.order(d3.descending);
                        if (sort_field == 'source_name') {
                            sourceDiv.classed("desc", true);
                        } else {
                            destDiv.classed("desc", true);
                        }
                    } else {
                        // order is currently desc, change to asc
                        order = 'asc';
                        dataTable.order(d3.ascending);
                        if (sort_field == 'source_name') {
                            sourceDiv.classed("asc", true);
                        } else {
                            destDiv.classed("asc", true);
                        }
                    }
                    dataTable.redraw();

                }

                dataTable.width(400)
                    .height(400)
                    .dimension(tableDimension)
                    .group(function(d) { return "perfSONAR Test Result Summary" })
                    .size(100)
                if (detailed) {
                    dataTable.columns([
                            function(d) { return '' + format_host(d, 'source') + ''; },
                            function(d) { return '' + format_host(d, 'destination') + ''; },
                            function(d) { return format_stats(d, 'throughput_src'); },
                            function(d) { return format_stats(d, 'throughput_dst'); },
                            function(d) { return format_stats(d, 'owdelay_src'); },
                            function(d) { return format_stats(d, 'owdelay_dst'); },
                            function(d) { return format_stats(d, 'loss_src'); },
                            function(d) { return format_stats(d, 'loss_dst'); }
                            ]);
                } else {
                    dataTable.columns([
                        function(d) { return '' + format_host_list(d, 'source') + ''; },
                        function(d) { return '' + format_host_list(d, 'destination') + ''; }
                    ]);
                    d3.selectAll('.detailedOnly').style('display', 'none');
                }

                var format_stats = function(d, prefix) {
                    var format_str = '';
                    var suffix = '';
                    var avg = null;
                    var min = null;
                    var max = null;

                    avg = d[prefix + '_average'];
                    min = d[prefix + '_min'];
                    max = d[prefix + '_max'];

                    if ((/^throughput_/).test(prefix)) {
                        format_str = '.3s';
                        suffix = 'bps';
                    } else if ((/^owdelay_/).test(prefix)) {
                        format_str = '.2f';
                    } else if ((/^loss_/).test(prefix)) {
                        format_str = '.2f';
                    }

                    // Account for the last_update field name not including _src or _dst
                    prefix = prefix.replace('_src', '');
                    prefix = prefix.replace('_dst', '');

                    var data = new Array();

                    var inactive;
                    var last_update_key = prefix + '_last_update';
                    if (d[last_update_key] != null && d[last_update_key] < inactive_threshold) {
                        inactive = true;
                    } else {
                        inactive = false;
                    }

                    data[0] = new Object();

                    if (avg !== null && ! isNaN(avg)){
                        var prefix = d3.formatPrefix(avg);
                        data[0].value = prefix.scale(avg).toFixed(2) + " " + prefix.symbol + suffix;
                    }
                    else {
                        data[0].value = "n/a";
                    }

                    data[0].inactive = inactive;

                    var ret = format_output(data);
                    return ret;
                }

                var format_output = function(data) {
                    var ret = '';
                    var inactive_class = '';
                    ret += '
';
                    for(var d in data) {
                        inactive_class = '';
                        if (data[d].inactive) {
                            inactive_class = ' inactive';
                        }
                        ret += '
';
                        ret += '' +
                            '	' +
                            ((data[d].value !== null
                              && typeof data[d].value !== 'undefined')
                             ? data[d].value
                             : 'n/a ')
                            +  '	';
                        ret += '
';
                    }
                    ret += "
";
                    return ret;
                }

                var format_test_values = function(d, suffix) {
                    var ret = '';
                    var data = new Array();
                    data[0] = new Object();
                    data[0].label = 'throughput';
                    data[0].value = d["throughput_" + suffix];
                    if (d["throughput_last_update"] < inactive_threshold) {
                        data[0].inactive = true;
                    } else {
                        data[0].inactive = false;
                    }
                    data[1] = new Object();
                    data[1].label = 'latency';
                    data[1].value = d["owdelay_" + suffix];
                    if (d["owdelay_last_update"] < inactive_threshold) {
                        data[1].inactive = true;
                    } else {
                        data[1].inactive = false;
                    }
                    data[2] = new Object();
                    data[2].label = 'loss';
                    data[2].value = d["loss_" + suffix];
                    if (d["loss_last_update"] < inactive_threshold) {
                        data[2].inactive = true;
                    } else {
                        data[2].inactive = false;
                    }

                    ret = format_output(data);

                    return ret;
                }

                var format_host_list = function(d, type) {
                    var ret = '';
                    if (d[type + '_host']) {
                       ret += d[type + '_host'];
                    }
                    if (d[type + '_ip'] && d[type + '_ip'] != d[type + '_host']) {
                        ret += ' (' + d[type + '_ip'] + ') ';
                    } else {
                        ret = d[type];
                    }
                    d[type + '_name'] = ret;
                    if (d.last_updated < inactive_threshold) {
                        ret = '' + ret + '';
                    }
                    return ret;
                }

                var format_host = function(d, type) {
                    var ret = '';
                    if (d['throughput_' + type + '_host'] !== undefined && d['throughput_' + type + '_host'] !== null) {
                        ret = d['throughput_' + type + '_host'];
                    } else if (d['owdelay_' + type + '_host'] !== undefined && d['owdelay_' + type + '_host'] !== null) {
                        ret = d['owdelay_' + type + '_host'];
                    } else if (d['loss_' + type + '_host'] !== undefined && d['loss_' + type + '_host'] !== null) {
                        ret = d['loss_' + type + '_host'];
                    }
                    ret += '  (' + d[type]  + ')';
                            d[type + '_name'] = ret;
                            return ret;
                }

                            var format_bidirectional = function(d) {
                            var ret = '';
                            var data = new Array();
                            data[0] = new Object();
                            data[0].label = 'throughput';
                            data[0].value = format_boolean(d.throughput_bidirectional);
                            data[1] = new Object();
                            data[1].label = 'latency';
                            data[1].value = format_boolean(d.owdelay_bidirectional);
                            data[2] = new Object();
                            data[2].label = 'loss';
                            data[2].value = format_boolean(d.loss_bidirectional);
                            ret = format_output(data);

                            return ret;
                            }

                            var format_boolean = function(val) {
                                var ret = '';
                                if (val === 1) {
                                    ret = 'yes';
                                } else {
                                    ret = 'no';
                                }
                                return ret;
                            }

                            dc.renderAll();

    } // end render_test_table()

    }); // end dojo function
<|endoftext|>


<commit_before>import("fastJSON");
import("comet");
import("jsutils.eachProperty");
import("utils.renderTemplateAsString");

import("globals.*");

var _UniqueArray = function() {
    this._a = [];
    this._m = {};
};
_UniqueArray.prototype.add = function(x) {
    if (!this._m[x]) {
        this._a.push(x);
        this._m[x] = true;
    }
};
_UniqueArray.prototype.asArray = function() {
    return this._a;
};

function _hd() {
    if (!appjet.requestCache.helperData) {
        appjet.requestCache.helperData = {
                clientVars: {},
                htmlTitle: "",
                headExtra: "",
                bodyId: "",
                bodyClasses: new _UniqueArray(),
                cssIncludes: new _UniqueArray(),
                jsIncludes: new _UniqueArray(),
                includeCometJs: false,
                suppressGA: false,
                showHeader: true,
                robotsPolicy: null
        };
    }
    return appjet.requestCache.helperData;
}

function addBodyClass(c) {
    _hd().bodyClasses.add(c);
}

function addClientVars(vars) {
    eachProperty(vars, function(k,v) {
        _hd().clientVars[k] = v;
    });
}

function addToHead(stuff) {
    _hd().headExtra += stuff;
}

function setHtmlTitle(t) {
    if (t instanceof Array) {
        t = t.join(' - ');
    }
    _hd().htmlTitle = t;
}

function setBodyId(id) {
    _hd().bodyId = id;
}

function includeJs(relpath) {
    _hd().jsIncludes.add(relpath);
}

function includeJQuery() {
    includeJs("jquery-1.3.2.js");
}

function includeCss(relpath) {
    _hd().cssIncludes.add(relpath);
}

function includeCometJs() {
    _hd().includeCometJs = true;
}

function hideHeader() {
    _hd().showHeader = false;
}

function bodyClasses() {
    return _hd().bodyClasses.asArray().join(' ');
}

function clientVarsScript() {
    var x = _hd().clientVars;
    x = fastJSON.stringify(x);
    if (x == '{}') {
        return '';
    }
    x = x.replace(/</g, '\\x3c');
    return [
            ''
            ].join('\n');
}

function htmlTitle() {
    return _hd().htmlTitle;
}

function bodyId() {
    return _hd().bodyId;
}

function baseHref() {
    return request.scheme + "://"+ request.host + "/";
}

function headExtra() {
    return _hd().headExtra;
}

function jsIncludes() {
    /*
    if (isProduction()) {
        var jsincludes = _hd().jsIncludes.asArray();
        if (_hd().includeCometJs) {
            jsincludes.splice(0, 0, {
                getPath: function() { return 'comet-client.js'; },
                getContents: function() { return comet.clientCode(); },
                getMTime: function() { return comet.clientMTime(); }
            });
        }
        if (jsincludes.length < 1) { return ''; }
        var key = faststatic.getCompressedFilesKey('js', '/static/js', jsincludes);
        return '';
    } else {
     */
    var ts = +(new Date);
    var r = [];
    if (_hd().includeCometJs) {
        r.push('');
    }
    _hd().jsIncludes.asArray().forEach(function(relpath) {
        r.push('');
    });
    return r.join('\n');
    //}
}

function cssIncludes() {
    /*
    if (isProduction()) {
        var key = faststatic.getCompressedFilesKey('css', '/static/css', _hd().cssIncludes.asArray());
        return '<link href="/static/compressed/'+key+'" rel="stylesheet" type="text/css" />';
    } else {
     */
    var ts = +(new Date);
    var r = [];
    _hd().cssIncludes.asArray().forEach(function(relpath) {
        r.push('<link href="/static/css/'+relpath+'?'+ts+'" rel="stylesheet" type="text/css" />');
    });
    return r.join('\n');
    //}
}

function isHeaderVisible() {
    return _hd().showHeader;
}

function renderList(name, list, here) {
  var r = [];
  list.forEach(function(item) {
    if (item instanceof Array) {
      r.push(renderList(name, item, here))
    } else {
      r.push((item.equals(here) ? '
' : '
') + renderView(name, item) + '
');
    }
  });
  return '
' + r.join('\n') + '
';
}

function renderView(name, item) {
  return renderTemplateAsString(name + "/" + item.getClass().getSimpleName().toLowerCase() + ".ejs", {
    item: item
  });
}

function renderPartial(name, data) {
  return renderTemplateAsString(name + ".ejs", data);
}
<commit_msg>Allow arbitrary list and item wrapper tags<commit_after>import("fastJSON");
import("comet");
import("jsutils.eachProperty");
import("utils.renderTemplateAsString");

import("globals.*");

var _UniqueArray = function() {
    this._a = [];
    this._m = {};
};
_UniqueArray.prototype.add = function(x) {
    if (!this._m[x]) {
        this._a.push(x);
        this._m[x] = true;
    }
};
_UniqueArray.prototype.asArray = function() {
    return this._a;
};

function _hd() {
    if (!appjet.requestCache.helperData) {
        appjet.requestCache.helperData = {
                clientVars: {},
                htmlTitle: "",
                headExtra: "",
                bodyId: "",
                bodyClasses: new _UniqueArray(),
                cssIncludes: new _UniqueArray(),
                jsIncludes: new _UniqueArray(),
                includeCometJs: false,
                suppressGA: false,
                showHeader: true,
                robotsPolicy: null
        };
    }
    return appjet.requestCache.helperData;
}

function addBodyClass(c) {
    _hd().bodyClasses.add(c);
}

function addClientVars(vars) {
    eachProperty(vars, function(k,v) {
        _hd().clientVars[k] = v;
    });
}

function addToHead(stuff) {
    _hd().headExtra += stuff;
}

function setHtmlTitle(t) {
    if (t instanceof Array) {
        t = t.join(' - ');
    }
    _hd().htmlTitle = t;
}

function setBodyId(id) {
    _hd().bodyId = id;
}

function includeJs(relpath) {
    _hd().jsIncludes.add(relpath);
}

function includeJQuery() {
    includeJs("jquery-1.3.2.js");
}

function includeCss(relpath) {
    _hd().cssIncludes.add(relpath);
}

function includeCometJs() {
    _hd().includeCometJs = true;
}

function hideHeader() {
    _hd().showHeader = false;
}

function bodyClasses() {
    return _hd().bodyClasses.asArray().join(' ');
}

function clientVarsScript() {
    var x = _hd().clientVars;
    x = fastJSON.stringify(x);
    if (x == '{}') {
        return '';
    }
    x = x.replace(/</g, '\\x3c');
    return [
            ''
            ].join('\n');
}

function htmlTitle() {
    return _hd().htmlTitle;
}

function bodyId() {
    return _hd().bodyId;
}

function baseHref() {
    return request.scheme + "://"+ request.host + "/";
}

function headExtra() {
    return _hd().headExtra;
}

function jsIncludes() {
    /*
    if (isProduction()) {
        var jsincludes = _hd().jsIncludes.asArray();
        if (_hd().includeCometJs) {
            jsincludes.splice(0, 0, {
                getPath: function() { return 'comet-client.js'; },
                getContents: function() { return comet.clientCode(); },
                getMTime: function() { return comet.clientMTime(); }
            });
        }
        if (jsincludes.length < 1) { return ''; }
        var key = faststatic.getCompressedFilesKey('js', '/static/js', jsincludes);
        return '';
    } else {
     */
    var ts = +(new Date);
    var r = [];
    if (_hd().includeCometJs) {
        r.push('');
    }
    _hd().jsIncludes.asArray().forEach(function(relpath) {
        r.push('');
    });
    return r.join('\n');
    //}
}

function cssIncludes() {
    /*
    if (isProduction()) {
        var key = faststatic.getCompressedFilesKey('css', '/static/css', _hd().cssIncludes.asArray());
        return '<link href="/static/compressed/'+key+'" rel="stylesheet" type="text/css" />';
    } else {
     */
    var ts = +(new Date);
    var r = [];
    _hd().cssIncludes.asArray().forEach(function(relpath) {
        r.push('<link href="/static/css/'+relpath+'?'+ts+'" rel="stylesheet" type="text/css" />');
    });
    return r.join('\n');
    //}
}

function isHeaderVisible() {
    return _hd().showHeader;
}

function renderList(name, list, here, wrap) {
  if ( ! wrap) {
    wrap = { item: 'li', list: 'ul' };
  }
  var r = [];
  list.forEach(function(item) {
    if (item instanceof Array) {
      r.push(renderList(name, item, here, wrap))
    } else {
      r.push('<'+wrap.item+(item.equals(here) ? ' class="here">' : '>') + renderView(name, item) + '</'+wrap.item+'>');
    }
  });
  return '<'+wrap.list+'>' + r.join('\n') + '</'+wrap.list+'>';
}

function renderView(name, item) {
  return renderTemplateAsString(name + "/" + item.getClass().getSimpleName().toLowerCase() + ".ejs", {
    item: item
  });
}

function renderPartial(name, data) {
  return renderTemplateAsString(name + ".ejs", data);
}
<|endoftext|>


<commit_before>var m = require('mithril');
var partial = require('chessground').util.partial;

module.exports = {
  controller: function(onUpdate) {
    var data = {
      open: m.prop(true),
      db: {
        available: ['lichess', 'masters'], //, 'me'],
        selected: m.prop('lichess')
      },
      rating: {
        available: [1600, 1800, 2000, 2200, 2500],
        selected: m.prop([2000, 2200, 2500])
      },
      speed: {
        available: ['bullet', 'blitz', 'classical'],
        selected: m.prop(['blitz', 'classical'])
      }
    };

    var toggleMany = function(c, value) {
      if (c().indexOf(value) === -1) c(c().concat([value]));
      else if (c().length > 1) c(c().filter(function(v) {
        return v !== value;
      }));
      onUpdate();
    };

    return {
      data: data,
      toggleOpen: function() {
        data.open(!data.open());
        onUpdate();
      },
      toggleDb: function(db) {
        data.db.selected(db);
        onUpdate();
      },
      toggleRating: partial(toggleMany, data.rating.selected),
      toggleSpeed: partial(toggleMany, data.speed.selected)
    };
  },
  view: function(ctrl) {
    var d = ctrl.data;
    return m('div.config', [
      m('div.title', 'Opening explorer configuration'),
      m('section.db', [
        m('label', 'Database'),
        m('div.choices',
          d.db.available.map(function(s) {
            return m('span', {
              class: d.db.selected() === s ? 'selected' : '',
              onclick: partial(ctrl.toggleDb, s)
            }, s);
          })
        )
      ]),
      m('div', {
        class: 'adv' + (d.db.selected() === 'masters' ? ' hidden' : '')
      }, [
        m('section.rating', [
          m('label', 'Players Average rating'),
          m('div.choices',
            d.rating.available.map(function(r) {
              return m('span', {
                class: d.rating.selected().indexOf(r) > -1 ? 'selected' : '',
                onclick: partial(ctrl.toggleRating, r)
              }, r);
            })
          )
        ]),
        m('section.speed', [
          m('label', 'Game speed'),
          m('div.choices',
            d.speed.available.map(function(s) {
              return m('span', {
                class: d.speed.selected().indexOf(s) > -1 ? 'selected' : '',
                onclick: partial(ctrl.toggleSpeed, s)
              }, s);
            })
          )
        ])
      ])
    ]);
  }
};
<commit_msg>locally persist explorer preferences<commit_after>var m = require('mithril');
var partial = require('chessground').util.partial;

function storedProp(keySuffix, initialValue) {
  var key = 'explorer.' + keySuffix;
  return function() {
    if (arguments.length) lichess.storage.set(key, JSON.stringify(arguments[0]));
    var ret = JSON.parse(lichess.storage.get(key));
    return (ret !== null) ? ret : initialValue;
  };
}

module.exports = {
  controller: function(onUpdate) {
    var data = {
      open: m.prop(true),
      db: {
        available: ['lichess', 'masters'], //, 'me'],
        selected: storedProp('db', 'lichess')
      },
      rating: {
        available: [1600, 1800, 2000, 2200, 2500],
        selected: storedProp('rating', [2000, 2200, 2500])
      },
      speed: {
        available: ['bullet', 'blitz', 'classical'],
        selected: storedProp('speed', ['blitz', 'classical'])
      }
    };

    var toggleMany = function(c, value) {
      if (c().indexOf(value) === -1) c(c().concat([value]));
      else if (c().length > 1) c(c().filter(function(v) {
        return v !== value;
      }));
      onUpdate();
    };

    return {
      data: data,
      toggleOpen: function() {
        data.open(!data.open());
        onUpdate();
      },
      toggleDb: function(db) {
        data.db.selected(db);
        onUpdate();
      },
      toggleRating: partial(toggleMany, data.rating.selected),
      toggleSpeed: partial(toggleMany, data.speed.selected)
    };
  },
  view: function(ctrl) {
    var d = ctrl.data;
    return m('div.config', [
      m('div.title', 'Opening explorer configuration'),
      m('section.db', [
        m('label', 'Database'),
        m('div.choices',
          d.db.available.map(function(s) {
            return m('span', {
              class: d.db.selected() === s ? 'selected' : '',
              onclick: partial(ctrl.toggleDb, s)
            }, s);
          })
        )
      ]),
      m('div', {
        class: 'adv' + (d.db.selected() === 'masters' ? ' hidden' : '')
      }, [
        m('section.rating', [
          m('label', 'Players Average rating'),
          m('div.choices',
            d.rating.available.map(function(r) {
              return m('span', {
                class: d.rating.selected().indexOf(r) > -1 ? 'selected' : '',
                onclick: partial(ctrl.toggleRating, r)
              }, r);
            })
          )
        ]),
        m('section.speed', [
          m('label', 'Game speed'),
          m('div.choices',
            d.speed.available.map(function(s) {
              return m('span', {
                class: d.speed.selected().indexOf(s) > -1 ? 'selected' : '',
                onclick: partial(ctrl.toggleSpeed, s)
              }, s);
            })
          )
        ])
      ])
    ]);
  }
};
<|endoftext|>


<commit_before>//template feather
module.exports = function plugin(bot, info)
{
  'use strict';
  //feather obj
  const plugin = {};
  //set variable for config
  const config = info.config;
  //requires
  const request = require('request');
  //plugin functions
  function createCard(content)
  {
    request.post({
      url: `https://api.trello.com/1/cards?key=${config.api.trello.api_key}&token=${config.api.trello.token}`,
      json: true,
      form: content
    }, (err, response, body) =>
    {
      if(err)
      {
        console.log(err);
      }
    });
  };
  bot.on('messageReactionAdd', (reaction) =>
  {
    if(reaction.user_id === '190175637271478273' && reaction.channel_id === info.config.suggestion_channel && reaction.emoji.name === '👍')
    {
      bot.getMessage(info.config.suggestion_channel,reaction.message_id).then((message) =>
      {
        let newCard = {
          name: `${message.embeds[0].description}\n${message.embeds[0].footer.text}`,
          idList: '58fe3b0d4e2f17d3cddb5f11',
          pos: 'top',
          idLabels: '58fe3a14ced82109ff526fbf'
        };
        createCard(newCard);
      }).catch((err) =>
      {
        console.log(err);
      });
    }
  });

  return plugin;
};
<commit_msg>debug<commit_after>//template feather
module.exports = function plugin(bot, info)
{
  'use strict';
  //feather obj
  const plugin = {};
  //set variable for config
  const config = info.config;
  //requires
  const request = require('request');
  //plugin functions
  function createCard(content)
  {
    request.post({
      url: `https://api.trello.com/1/cards?key=${config.api.trello.api_key}&token=${config.api.trello.token}`,
      json: true,
      form: content
    }, (err, response, body) =>
    {
      if(err)
      {
        console.log(err);
      }
    });
  };
  bot.on('messageReactionAdd', (reaction) =>
  {
    if(reaction.user_id === '190175637271478273' && reaction.channel_id === info.config.suggestion_channel && reaction.emoji.name === '👍')
    {
      bot.getMessage(info.config.suggestion_channel,reaction.message_id).then((message) =>
      {
        console.log(message);
        let newCard = {
          name: `${message.embeds[0].description}\n${message.embeds[0].footer.text}`,
          idList: '58fe3b0d4e2f17d3cddb5f11',
          pos: 'top',
          idLabels: '58fe3a14ced82109ff526fbf'
        };
        createCard(newCard);
      }).catch((err) =>
      {
        console.log(err);
      });
    }
  });

  return plugin;
};
<|endoftext|>


<commit_before>/*global JsonFx, JsonML, jQuery */
/*
	JsonFx_Bindings.js
	dynamic behavior binding support

	Created: 2006-11-11-1759
	Modified: 2009-02-28-1407

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* namespace JsonFx */
if ("undefined" === typeof window.JsonFx) {
	window.JsonFx = {};
}
/* namespace JsonFx.UI */
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* dependency checks --------------------------------------------*/

/* singleton JsonFx.Bindings */
JsonFx.Bindings = function() {

	/*object*/ var b = this;
	/*bool*/ var jQ = ("undefined" !== typeof jQuery);
	/*const string*/ var BIND = 1, UNBIND = 2;

	/*
		the structure of bindings and the implementation of add, bind, and unbind fork on presence of jQuery.
		if jQuery is present before JsonFx.Bindings, then the selector implementation is delegated to jQuery.
		otherwise a simple selector lookup structure is built to very specifically allow lookups without
		a lot of iterations.
	*/
	/*Dictionary<string,object>*/ var bindings = jQ ? [] : {};

	/*RegExp*/ var re = /^\s*([\w\-]*|[*])(?:#([\w\-]+)|\.([\w\-]+))?(?:#([\w\-]+)|\.([\w\-]+))?\s*$/;

	/*void*/ b.add = jQ ?
		// jQuery JsonFx.Bindings.add implementation
		function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			var binding = { selector: selector };
			binding[BIND] = bind;
			binding[UNBIND] = unbind;
			bindings.push(binding);
		} :
		// simple JsonFx.Bindings.add implementation
		function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			var s = selector instanceof Array ?
				selector :
				String(selector).split(',');
			while (s.length > 1) {
				b.add(s.shift(), bind, unbind);
			}
			selector = s.shift();

			s = re.exec(selector);
			if (!s) {
				// http://www.w3.org/TR/css3-selectors/#simple-selectors
				throw new Error("JsonFx.Bindings only supports simple tag, class, and id selectors. Selector: \""+selector+"\"");
			}

			s = {
				tag: (s[1]||"*").toLowerCase(),
				css: (s[3]||s[5]||"*"),
				id: (s[2]||s[4]||"")
			};

			if (s.id) {
				if (s.tag !== "*" || s.css !== "*") {
					throw new Error("JsonFx.Bindings only supports simple ID selectors. Add jQuery to enable full selector support. Selector: \""+selector+"\"");
				}
				if ("undefined" === typeof bindings["#"]) {
					/*object*/ bindings["#"] = {};
				}

				/*object*/ bindings["#"][s.id] = {};
				bindings["#"][s.id][BIND] = bind;
				bindings["#"][s.id][UNBIND] = unbind;
			} else {
				if ("undefined" === typeof bindings[s.tag]) {
					/*object*/ bindings[s.tag] = {};
				} else if (bindings[s.tag][s.css]) {
					throw new Error("A binding for "+selector+" has already been registered.");
				}

				/*object*/ bindings[s.tag][s.css] = {};
				bindings[s.tag][s.css][BIND] = bind;
				bindings[s.tag][s.css][UNBIND] = unbind;
			}
		};

	/*deprecated*/
	/*void*/ b.register = function(/*string*/ tag, /*string*/ css, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
		b.add(tag+'.'+css, bind, unbind);
	};

	/*DOM*/ var performOne = jQ ?
		// jQuery performOne implementation
		function(/*DOM*/ elem, /*actionKey*/ a) {
			for (var i=0; i<bindings.length; i++) {
				if (bindings[i][a]) {
					var action = bindings[i][a];
					jQuery(elem).filter(bindings[i].selector).each(
						function() {
							try {
								elem = action(this) || this;
							} catch (ex) {
								window.alert("Error binding "+bindings[i].selector+":\n\n\""+ex.message+"\"");
							}
						});
				}
			}
			return elem;
		} :
		// simple performOne implementation
		function(/*DOM*/ elem, /*actionKey*/ a) {

			function bindSet(/*object*/ binds, /*string*/ css) {
				if (binds && binds[css] && binds[css][a]) {
					try {
						// perform action on element and
						// allow binding to replace element
						elem = binds[css][a](elem) || elem;
					} catch (ex) {
						window.alert("Error binding "+elem.tagName+"."+css+":\n\n\""+ex.message+"\"");
					}
				}
			}

			if (elem && elem.tagName) {

				// only perform on registered tags
				var tag = elem.tagName.toLowerCase();
				var allBinds = bindings["*"];
				var tagBinds = bindings[tag];

				if (tagBinds || allBinds) {

					bindSet(tagBinds, "*");
					bindSet(allBinds, "*");

					if (elem.className) {
						// for each css class in elem
						var classes = elem.className.split(/\s+/);
						for (var i=0; i<classes.length; i++) {
							var css = classes[i];
							bindSet(tagBinds, css);
							bindSet(allBinds, css);
						}
					}
				}
			}
			return elem;
		};

	var performOneID = jQ ?
		// no jQuery performOneID implementation
		null :
		// simple performOneID implementation
		function (/*DOM*/ elem, /*actionKey*/ a) {
			var action = bindings["#"][elem.id];
			action = action && action[a];
			return (action && action(elem)) || elem;
		};

	// perform a binding action on all child elements
	/*void*/ var perform = jQ ?
		// jQuery perform implementation
		function(/*DOM*/ root, /*actionKey*/ a) {
			for (var i=0; i<bindings.length; i++) {
				if (bindings[i][a]) {
					var action = bindings[i][a];
					jQuery(bindings[i].selector, root).each(
						function() {
							try {
								var elem = action(this) || this;
								if (elem !== this) {
									this.parentNode.replaceChild(elem, this);
								}
							} catch (ex) {
								window.alert("Error binding "+bindings[i].selector+":\n\n\""+ex.message+"\"");
							}
						});
				}
			}
		} :
		// simple perform implementation
		function(/*DOM*/ root, /*actionKey*/ a) {

	// TODO: add ability to bind on ID, className, tagName or any combination
	// determine how to most efficiently select the smallest set of eligible elements

			/*create a closure for replacement*/
			function queueReplacer(newer, older) {
				window.setTimeout(function() {
					if (older && older.parentNode) {
						older.parentNode.replaceChild(newer, older);
					}
					// free references
					newer = older = null;
				}, 0);
			}

			function bindTagSet(/*string*/ tag) {
				// for each element in root with tagName
				var elems = root.getElementsByTagName(tag);
				for (var i=0; i<elems.length; i++) {
					// perform action on element and
					// allow binding to replace element
					var replace = performOne(elems[i], a);
					if (replace !== elems[i] && elems[i].parentNode) {
						// queue up replacement at the end so as not to disrupt the list
						queueReplacer(replace, elems[i]);
					}
				}
			}

			if (bindings["#"]) {
				for (var id in bindings["#"]) {
					if (bindings["#"].hasOwnProperty(id)) {
						var elem = document.getElementById(id);
						if (!elem) {
							continue;
						}
						var replace = performOneID(elem, a);
						if (replace !== elem) {
							// queue up replacement at the end so as not to disrupt the list
							queueReplacer(replace, elem);
						}
					}
				}
			}
			root = root || document.body;
			if (root.getElementsByTagName) {
				if (bindings["*"]) {
					// if star rule, then must apply to all
					bindTagSet("*");
				} else {
					// only apply to tags with rules
					for (var tag in bindings) {
						if (bindings.hasOwnProperty(tag) && tag !== "*" && tag !== "#") {
							bindTagSet(tag);
						}
					}
				}
			}
		};

	// bind
	/*void*/ b.bind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, BIND);
	};

	// unbind
	/*void*/ b.unbind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, UNBIND);
	};

	// use bindOne as the default JBST filter
	if ("undefined" !== typeof JsonML && JsonML.BST) {
		/*DOM*/ function bindOne(/*DOM*/ elem) {
			if (performOneID) {
				elem = performOneID(elem, BIND);
			}
			elem = performOne(elem, BIND);
			return elem;
		};

		if ("function" !== typeof JsonML.BST.filter) {
			JsonML.BST.filter = bindOne;
		} else {
			JsonML.BST.filter = (function() {
				var jbstFilter = JsonML.BST.filter;
				return function(/*DOM*/ elem) {
					elem = jbstFilter(elem);
					return elem && bindOne(elem);
				};
			})();
		}
	}

	// register bind events
	if (typeof jQuery !== "undefined") {
		jQuery(b.bind);
		jQuery(window).bind("unload", b.unbind);
	} else if (window.addEventListener) {
		//DOM Level 2 model for binding events
		window.addEventListener("load", b.bind, false);
		window.addEventListener("unload", b.unbind, false);
	} else if (window.attachEvent) {
		//IE model for binding events
		window.attachEvent("onload", b.bind);
		window.attachEvent("onunload", b.unbind);
	} else {
		//DOM Level 0 model for binding events
		var onload = window.onload;
		window.onload =
			("function" === typeof onload) ?
			function(/*Event*/ evt) { b.bind(evt); return onload(evt); } :
			b.bind;

		var onunload = window.onunload;
		window.onunload =
			("function" === typeof onunload) ?
			function(/*Event*/ evt) { b.unbind(evt); return onunload(evt); } :
			b.unbind;
	}
};

// doing instead of anonymous fn for JSLint compatibility
// instantiate only one, destroying the constructor
JsonFx.Bindings = new JsonFx.Bindings();
<commit_msg>- fixing bug when no ID bindings were specified<commit_after>/*global JsonFx, JsonML, jQuery */
/*
	JsonFx_Bindings.js
	dynamic behavior binding support

	Created: 2006-11-11-1759
	Modified: 2009-02-28-1407

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* namespace JsonFx */
if ("undefined" === typeof window.JsonFx) {
	window.JsonFx = {};
}
/* namespace JsonFx.UI */
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* dependency checks --------------------------------------------*/

/* singleton JsonFx.Bindings */
JsonFx.Bindings = function() {

	/*object*/ var b = this;
	/*bool*/ var jQ = ("undefined" !== typeof jQuery);
	/*const string*/ var BIND = 1, UNBIND = 2;

	/*
		the structure of bindings and the implementation of add, bind, and unbind fork on presence of jQuery.
		if jQuery is present before JsonFx.Bindings, then the selector implementation is delegated to jQuery.
		otherwise a simple selector lookup structure is built to very specifically allow lookups without
		a lot of iterations.
	*/
	/*Dictionary<string,object>*/ var bindings = jQ ? [] : {};

	/*RegExp*/ var re = /^\s*([\w\-]*|[*])(?:#([\w\-]+)|\.([\w\-]+))?(?:#([\w\-]+)|\.([\w\-]+))?\s*$/;

	/*void*/ b.add = jQ ?
		// jQuery JsonFx.Bindings.add implementation
		function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			var binding = { selector: selector };
			binding[BIND] = bind;
			binding[UNBIND] = unbind;
			bindings.push(binding);
		} :
		// simple JsonFx.Bindings.add implementation
		function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			var s = selector instanceof Array ?
				selector :
				String(selector).split(',');
			while (s.length > 1) {
				b.add(s.shift(), bind, unbind);
			}
			selector = s.shift();

			s = re.exec(selector);
			if (!s) {
				// http://www.w3.org/TR/css3-selectors/#simple-selectors
				throw new Error("JsonFx.Bindings only supports simple tag, class, and id selectors. Selector: \""+selector+"\"");
			}

			s = {
				tag: (s[1]||"*").toLowerCase(),
				css: (s[3]||s[5]||"*"),
				id: (s[2]||s[4]||"")
			};

			if (s.id) {
				if (s.tag !== "*" || s.css !== "*") {
					throw new Error("JsonFx.Bindings only supports simple ID selectors. Add jQuery to enable full selector support. Selector: \""+selector+"\"");
				}
				if ("undefined" === typeof bindings["#"]) {
					/*object*/ bindings["#"] = {};
				}

				/*object*/ bindings["#"][s.id] = {};
				bindings["#"][s.id][BIND] = bind;
				bindings["#"][s.id][UNBIND] = unbind;
			} else {
				if ("undefined" === typeof bindings[s.tag]) {
					/*object*/ bindings[s.tag] = {};
				} else if (bindings[s.tag][s.css]) {
					throw new Error("A binding for "+selector+" has already been registered.");
				}

				/*object*/ bindings[s.tag][s.css] = {};
				bindings[s.tag][s.css][BIND] = bind;
				bindings[s.tag][s.css][UNBIND] = unbind;
			}
		};

	/*deprecated*/
	/*void*/ b.register = function(/*string*/ tag, /*string*/ css, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
		b.add(tag+'.'+css, bind, unbind);
	};

	/*DOM*/ var performOne = jQ ?
		// jQuery performOne implementation
		function(/*DOM*/ elem, /*actionKey*/ a) {
			for (var i=0; i<bindings.length; i++) {
				if (bindings[i][a]) {
					var action = bindings[i][a];
					jQuery(elem).filter(bindings[i].selector).each(
						function() {
							try {
								elem = action(this) || this;
							} catch (ex) {
								window.alert("Error binding "+bindings[i].selector+":\n\n\""+ex.message+"\"");
							}
						});
				}
			}
			return elem;
		} :
		// simple performOne implementation
		function(/*DOM*/ elem, /*actionKey*/ a) {

			function bindSet(/*object*/ binds, /*string*/ css) {
				if (binds && binds[css] && binds[css][a]) {
					try {
						// perform action on element and
						// allow binding to replace element
						elem = binds[css][a](elem) || elem;
					} catch (ex) {
						window.alert("Error binding "+elem.tagName+"."+css+":\n\n\""+ex.message+"\"");
					}
				}
			}

			if (elem && elem.tagName) {

				// only perform on registered tags
				var tag = elem.tagName.toLowerCase();
				var allBinds = bindings["*"];
				var tagBinds = bindings[tag];

				if (tagBinds || allBinds) {

					bindSet(tagBinds, "*");
					bindSet(allBinds, "*");

					if (elem.className) {
						// for each css class in elem
						var classes = elem.className.split(/\s+/);
						for (var i=0; i<classes.length; i++) {
							var css = classes[i];
							bindSet(tagBinds, css);
							bindSet(allBinds, css);
						}
					}
				}
			}
			return elem;
		};

	var performOneID = jQ ?
		// no jQuery performOneID implementation
		null :
		// simple performOneID implementation
		function (/*DOM*/ elem, /*actionKey*/ a) {
			var action = bindings["#"][elem.id];
			action = action && action[a];
			return (action && action(elem)) || elem;
		};

	// perform a binding action on all child elements
	/*void*/ var perform = jQ ?
		// jQuery perform implementation
		function(/*DOM*/ root, /*actionKey*/ a) {
			for (var i=0; i<bindings.length; i++) {
				if (bindings[i][a]) {
					var action = bindings[i][a];
					jQuery(bindings[i].selector, root).each(
						function() {
							try {
								var elem = action(this) || this;
								if (elem !== this) {
									this.parentNode.replaceChild(elem, this);
								}
							} catch (ex) {
								window.alert("Error binding "+bindings[i].selector+":\n\n\""+ex.message+"\"");
							}
						});
				}
			}
		} :
		// simple perform implementation
		function(/*DOM*/ root, /*actionKey*/ a) {

	// TODO: add ability to bind on ID, className, tagName or any combination
	// determine how to most efficiently select the smallest set of eligible elements

			/*create a closure for replacement*/
			function queueReplacer(newer, older) {
				window.setTimeout(function() {
					if (older && older.parentNode) {
						older.parentNode.replaceChild(newer, older);
					}
					// free references
					newer = older = null;
				}, 0);
			}

			function bindTagSet(/*string*/ tag) {
				// for each element in root with tagName
				var elems = root.getElementsByTagName(tag);
				for (var i=0; i<elems.length; i++) {
					// perform action on element and
					// allow binding to replace element
					var replace = performOne(elems[i], a);
					if (replace !== elems[i] && elems[i].parentNode) {
						// queue up replacement at the end so as not to disrupt the list
						queueReplacer(replace, elems[i]);
					}
				}
			}

			if (bindings["#"]) {
				for (var id in bindings["#"]) {
					if (bindings["#"].hasOwnProperty(id)) {
						var elem = document.getElementById(id);
						if (!elem) {
							continue;
						}
						var replace = performOneID(elem, a);
						if (replace !== elem) {
							// queue up replacement at the end so as not to disrupt the list
							queueReplacer(replace, elem);
						}
					}
				}
			}
			root = root || document.body;
			if (root.getElementsByTagName) {
				if (bindings["*"]) {
					// if star rule, then must apply to all
					bindTagSet("*");
				} else {
					// only apply to tags with rules
					for (var tag in bindings) {
						if (bindings.hasOwnProperty(tag) && tag !== "*" && tag !== "#") {
							bindTagSet(tag);
						}
					}
				}
			}
		};

	// bind
	/*void*/ b.bind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, BIND);
	};

	// unbind
	/*void*/ b.unbind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, UNBIND);
	};

	// use bindOne as the default JBST filter
	if ("undefined" !== typeof JsonML && JsonML.BST) {
		/*DOM*/ function bindOne(/*DOM*/ elem) {
			if (performOneID && bindings["#"]) {
				elem = performOneID(elem, BIND);
			}
			elem = performOne(elem, BIND);
			return elem;
		};

		if ("function" !== typeof JsonML.BST.filter) {
			JsonML.BST.filter = bindOne;
		} else {
			JsonML.BST.filter = (function() {
				var jbstFilter = JsonML.BST.filter;
				return function(/*DOM*/ elem) {
					elem = jbstFilter(elem);
					return elem && bindOne(elem);
				};
			})();
		}
	}

	// register bind events
	if (typeof jQuery !== "undefined") {
		jQuery(b.bind);
		jQuery(window).bind("unload", b.unbind);
	} else if (window.addEventListener) {
		//DOM Level 2 model for binding events
		window.addEventListener("load", b.bind, false);
		window.addEventListener("unload", b.unbind, false);
	} else if (window.attachEvent) {
		//IE model for binding events
		window.attachEvent("onload", b.bind);
		window.attachEvent("onunload", b.unbind);
	} else {
		//DOM Level 0 model for binding events
		var onload = window.onload;
		window.onload =
			("function" === typeof onload) ?
			function(/*Event*/ evt) { b.bind(evt); return onload(evt); } :
			b.bind;

		var onunload = window.onunload;
		window.onunload =
			("function" === typeof onunload) ?
			function(/*Event*/ evt) { b.unbind(evt); return onunload(evt); } :
			b.unbind;
	}
};

// doing instead of anonymous fn for JSLint compatibility
// instantiate only one, destroying the constructor
JsonFx.Bindings = new JsonFx.Bindings();
<|endoftext|>