text:
/**
 * Gen 1 mechanics were fairly different, so we need to make a lot of changes to battle.js
 * using this.
 */
exports.BattleScripts = {
	gen: 1,
	init: function () {
		for (var i in this.data.Learnsets) {
			this.modData('Learnsets', i);
			var learnset = this.data.Learnsets[i].learnset;
			for (var moveid in learnset) {
				if (typeof learnset[moveid] === 'string') learnset[moveid] = [learnset[moveid]];
				learnset[moveid] = learnset[moveid].filter(function(source) {
					return source[0] === '1';
				});
				if (!learnset[moveid].length) delete learnset[moveid];
			}
		}
	},
	debug: function(activity) {
		if (this.getFormat().debug) {
			this.add('debug', activity);
		}
	},
	// getStat callback for gen 1 stat dealing
	getStatCallback: function (stat, statName, pokemon) {
		// Hard coded Reflect and Light Screen boosts
		if (pokemon.volatiles['reflect'] && statName === 'def') {
			this.debug('Reflect doubles Defense');
			stat *= 2;
			// Max on reflect is 1024
			if (stat > 1024) stat = 1024;
			if (stat < 1) stat = 1;
		} else if (pokemon.volatiles['lightscreen'] && statName === 'spd') {
			this.debug('Light Screen doubles Special Defense');
			stat *= 2;
			// Max on reflect is 1024
			if (stat > 1024) stat = 1024;
			if (stat < 1) stat = 1;
		} else {
			// Gen 1 caps stats at 999 and min is 1
			if (stat > 999) stat = 999;
			if (stat < 1) stat = 1;
		}

		return stat;
	},
	runMove: function(move, pokemon, target, sourceEffect) {
		move = this.getMove(move);
		if (!target) target = this.resolveTarget(pokemon, move);
		if (target.subFainted) delete target.subFainted;

		this.setActiveMove(move, pokemon, target);

		if (pokemon.movedThisTurn || !this.runEvent('BeforeMove', pokemon, target, move)) {
			this.debug(''+pokemon.id+' move interrupted; movedThisTurn: '+pokemon.movedThisTurn);
			this.clearActiveMove(true);
			// This is only run for sleep
			this.runEvent('AfterMoveSelf', pokemon, target, move);
			return;
		}
		if (move.beforeMoveCallback) {
			if (move.beforeMoveCallback.call(this, pokemon, target, move)) {
				this.clearActiveMove(true);
				return;
			}
		}
		pokemon.lastDamage = 0;
		var lockedMove = this.runEvent('LockMove', pokemon);
		if (lockedMove === true) lockedMove = false;
		if (!lockedMove && !pokemon.volatiles['partialtrappinglock']) {
			pokemon.deductPP(move, null, target);
		}
		this.useMove(move, pokemon, target, sourceEffect);
		this.runEvent('AfterMove', target, pokemon, move);
		this.runEvent('AfterMoveSelf', pokemon, target, move);

		// If rival fainted
		if (target.hp <= 0) {
			// We remove recharge
			if (pokemon.volatiles['mustrecharge']) pokemon.removeVolatile('mustrecharge');
			// We remove screens
			target.side.removeSideCondition('reflect');
			target.side.removeSideCondition('lightscreen');
		}

		// For partial trapping moves, we are saving the target
		if (move.volatileStatus === 'partiallytrapped' && target && target.hp > 0) {
			// Let's check if the lock exists
			if (pokemon.volatiles['partialtrappinglock']) {
				// Here the partialtrappinglock volatile has been already applied
				if (!pokemon.volatiles['partialtrappinglock'].locked) {
					// If it's the first hit, we save the target
					pokemon.volatiles['partialtrappinglock'].locked = target;
				} else {
					if (pokemon.volatiles['partialtrappinglock'].locked !== target && target !== pokemon) {
						// The target switched, therefor, we must re-roll the duration
						var roll = this.random(6);
						var duration = [2,2,3,3,4,5][roll];
						pokemon.volatiles['partialtrappinglock'].duration = duration;
						pokemon.volatiles['partialtrappinglock'].locked = target;
						// Duration reset thus partially trapped at 2 always
						target.volatiles['partiallytrapped'].duration = 2;
						// We deduct an additional PP that was not deducted earlier
						// Get the move position
						var usedMovePos = -1;
						for (var m in pokemon.moveset) {
							if (pokemon.moveset[m].id === move.id) usedMovePos = m;
						}
						if (usedMovePos > -1 && pokemon.moveset[usedMovePos].pp === 0) {
							// If we were on the middle of the 0 PP sequence, the PPs get reset
							pokemon.moveset[usedMovePos].pp = pokemon.moveset[usedMovePos].maxpp;
						} else {
							// Otherwise, plain reduct
							pokemon.deductPP(move, null, target);
						}
					}
				}
			} // If we move to here, the move failed and there's no partial trapping lock
		}
	},
	useMove: function(move, pokemon, target, sourceEffect) {
		if (!sourceEffect && this.effect.id) sourceEffect = this.effect;
		move = this.getMove(move);
		baseMove = move;
		move = this.getMoveCopy(move);
		if (!target) target = this.resolveTarget(pokemon, move);
		if (move.target === 'self' || move.target === 'allies') {
			target = pokemon;
		}
		if (sourceEffect) move.sourceEffect = sourceEffect.id;

		this.setActiveMove(move, pokemon, target);

		this.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
		if (baseMove.target !== move.target) {
			// Target changed in ModifyMove, so we must adjust it here
			target = this.resolveTarget(pokemon, move);
		}
		move = this.runEvent('ModifyMove', pokemon, target, move, move);
		if (baseMove.target !== move.target) {
			// Check again
			target = this.resolveTarget(pokemon, move);
		}
		if (!move) return false;

		var attrs = '';
		var missed = false;
		if (pokemon.fainted) {
			// Removing screens upon faint
			pokemon.side.removeSideCondition('reflect');
			pokemon.side.removeSideCondition('lightscreen');
			return false;
		}

		if (move.isTwoTurnMove && !pokemon.volatiles[move.id]) {
			attrs = '|[still]'; // Suppress the default move animation
		}

		var movename = move.name;
		if (move.id === 'hiddenpower') movename = 'Hidden Power';
		if (sourceEffect) attrs += '|[from]'+this.getEffect(sourceEffect);
		this.addMove('move', pokemon, movename, target+attrs);

		if (!this.singleEvent('Try', move, null, pokemon, target, move)) {
			return true;
		}
		if (!this.runEvent('TryMove', pokemon, target, move)) {
			return true;
		}

		if (typeof move.affectedByImmunities === 'undefined') {
			move.affectedByImmunities = (move.category !== 'Status');
		}

		var damage = false;
		if (move.target === 'all' || move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') {
			damage = this.moveHit(target, pokemon, move);
		} else {
			if (target.fainted) {
				this.attrLastMove('[notarget]');
				this.add('-notarget');
				return true;
			}
			damage = this.rollMoveHit(target, pokemon, move);
		}

		if (!damage && damage !== 0) {
			this.singleEvent('MoveFail', move, null, target, pokemon, move);
			return true;
		}

		if (!move.negateSecondary) {
			this.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
			this.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
		}
		return true;
	},
	rollMoveHit: function(target, pokemon, move, spreadHit) {
		var boostTable = [1, 4/3, 5/3, 2, 7/3, 8/3, 3];
		var doSelfDestruct = true;
		var damage = 0;

		// Calculate true accuracy
		var accuracy = move.accuracy;
		if (accuracy !== true) {
			accuracy = Math.floor(accuracy*255/100);
		}

		// Partial trapping moves: true accuracy while it lasts
		if (move.volatileStatus === 'partiallytrapped' && pokemon.volatiles['partialtrappinglock']) {
			accuracy = true;
		}

		if (accuracy !== true) {
			if (!move.ignoreAccuracy) {
				if (pokemon.boosts.accuracy > 0) {
					accuracy *= boostTable[pokemon.boosts.accuracy];
				} else {
					accuracy /= boostTable[-pokemon.boosts.accuracy];
				}
			}
			if (!move.ignoreEvasion) {
				if (target.boosts.evasion > 0 && !move.ignorePositiveEvasion) {
					accuracy /= boostTable[target.boosts.evasion];
				} else if (target.boosts.evasion < 0) {
					accuracy *= boostTable[-target.boosts.evasion];
				}
			}
		}

		// Bypasses ohko accuracy modifiers
		if (move.alwaysHit) accuracy = true;
		accuracy = this.runEvent('Accuracy', target, pokemon, move, accuracy);

		// Gen 1, 1/256 chance of missing always, no matter what
		if (accuracy !== true && this.random(256) >= accuracy) {
			this.attrLastMove('[miss]');
			this.add('-miss', pokemon);
			damage = false;
		}

		if (move.affectedByImmunities && !target.runImmunity(move.type, true)) {
			damage = false;
		}

		if (damage !== false) {
			pokemon.lastDamage = 0;
			if (move.multihit) {
				var hits = move.multihit;
				if (hits.length) {
					// Yes, it's hardcoded... meh
					if (hits[0] === 2 && hits[1] === 5) {
						var roll = this.random(6);
						hits = [2, 2, 3, 3, 4, 5][roll];
					} else {
						hits = this.random(hits[0], hits[1]+1);
					}
				}
				hits = Math.floor(hits);
				// In gen 1, all the hits have the same damage for multihits move
				var moveDamage = 0;
				for (var i=0; i<hits && target.hp && pokemon.hp; i++) {
					if (i === 0) {
						// First hit, we calculate
						moveDamage = this.moveHit(target, pokemon, move);
						var firstDamage = moveDamage;
					} else {
						// We get the previous damage to make it fix damage
						move.damage = firstDamage;
						moveDamage = this.moveHit(target, pokemon, move);
					}
					if (moveDamage === false) break;
					damage = (moveDamage || 0);
					if (target.subFainted) {
						i++
						break;
					}
				}
				move.damage = null;
				if (i === 0) return true;
				this.add('-hitcount', target, i);
			} else {
				damage = this.moveHit(target, pokemon, move);
			}
		}

		if (move.category !== 'Status') target.gotAttacked(move, damage, pokemon);

		// Checking if substitute fainted
		if (target.subFainted) doSelfDestruct = false;
		if (move.selfdestruct && doSelfDestruct) {
			this.faint(pokemon, pokemon, move);
		}

		if (!damage && damage !== 0) return false;

		if (!move.negateSecondary) {
			this.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
			this.runEvent('AfterMoveSecondary', target, pokemon, move);
		}

		// If we used a partial trapping move, we save the damage to repeat it
		if (pokemon.volatiles['partialtrappinglock'] && !pokemon.volatiles['partialtrappinglock'].damage) {
			pokemon.volatiles['partialtrappinglock'].damage = damage;
		}

		return damage;
	},
	moveHit: function(target, pokemon, move, moveData, isSecondary, isSelf) {
		var damage = 0;
		move = this.getMoveCopy(move);

		if (!isSecondary && !isSelf) this.setActiveMove(move, pokemon, target);
		var hitResult = true;
		if (!moveData) moveData = move;

		if (typeof move.affectedByImmunities === 'undefined') {
			move.affectedByImmunities = (move.category !== 'Status');
		}

		// We get the sub to the target to see if it existed
		var targetSub = (target)? target.volatiles['substitute'] : false;
		var targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined'));

		// TryHit events:
		//   STEP 1: we see if the move will succeed at all:
		//   - TryHit, TryHitSide, or TryHitField are run on the move,
		//     depending on move target
		//   == primary hit line ==
		//   Everything after this only happens on the primary hit (not on
		//   secondary or self-hits)
		//   STEP 2: we see if anything blocks the move from hitting:
		//   - TryFieldHit is run on the target
		//   STEP 3: we see if anything blocks the move from hitting the target:
		//   - If the move's target is a pokemon, TryHit is run on that pokemon

		// Note:
		//   If the move target is `foeSide`:
		//     event target = pokemon 0 on the target side
		//   If the move target is `allySide` or `all`:
		//     event target = the move user
		//
		//   This is because events can't accept actual sides or fields as
		//   targets. Choosing these event targets ensures that the correct
		//   side or field is hit.
		//
		//   It is the `TryHitField` event handler's responsibility to never
		//   use `target`.
		//   It is the `TryFieldHit` event handler's responsibility to read
		//   move.target and react accordingly.
		//   An exception is `TryHitSide`, which is passed the target side.

		// Note 2:
		//   In case you didn't notice, FieldHit and HitField mean different things.
		//     TryFieldHit - something in the field was hit
		//     TryHitField - our move has a target of 'all' i.e. the field, and hit
		//   This is a VERY important distinction: Every move triggers
		//   TryFieldHit, but only  moves with a target of "all" (e.g.
		//   Haze) trigger TryHitField.

		if (target) {
			if (move.target === 'all' && !isSelf) {
				hitResult = this.singleEvent('TryHitField', moveData, {}, target, pokemon, move);
			} else if ((move.target === 'foeSide' || move.target === 'allySide') && !isSelf) {
				hitResult = this.singleEvent('TryHitSide', moveData, {}, target.side, pokemon, move);
			} else {
				hitResult = this.singleEvent('TryHit', moveData, {}, target, pokemon, move);
			}
			if (!hitResult) {
				if (hitResult === false) this.add('-fail', target);
				return false;
			}

			// Only run the hit events for the hit itself, not the secondary or self hits
			if (!isSelf && !isSecondary) {
				if (move.target === 'all') {
					hitResult = this.runEvent('TryHitField', target, pokemon, move);
				} else if (move.target === 'foeSide' || move.target === 'allySide') {
					hitResult = this.runEvent('TryHitSide', target, pokemon, move);
				} else {
					hitResult = this.runEvent('TryHit', target, pokemon, move);
				}
				if (!hitResult) {
					if (hitResult === false) this.add('-fail', target);
					// Special Substitute hit flag
					if (hitResult !== 0) {
						return false;
					}
				}
				if (!this.runEvent('TryFieldHit', target, pokemon, move)) {
					return false;
				}
			} else if (isSecondary && !moveData.self) {
				hitResult = this.runEvent('TrySecondaryHit', target, pokemon, moveData);
			}

			if (hitResult === 0) {
				target = null;
			} else if (!hitResult) {
				if (hitResult === false) this.add('-fail', target);
				return false;
			}
		}

		if (target) {
			var didSomething = false;

			damage = this.getDamage(pokemon, target, moveData);

			// getDamage has several possible return values:
			//
			//   a number:
			//     means that much damage is dealt (0 damage still counts as dealing
			//     damage for the purposes of things like Static)
			//   false:
			//     gives error message: "But it failed!" and move ends
			//   null:
			//     the move ends, with no message (usually, a custom fail message
			//     was already output by an event handler)
			//   undefined:
			//     means no damage is dealt and the move continues
			//
			// basically, these values have the same meanings as they do for event
			// handlers.

			if ((damage || damage === 0) && !target.fainted) {
				if (move.noFaint && damage >= target.hp) {
					damage = target.hp - 1;
				}
				damage = this.damage(damage, target, pokemon, move);
				if (!(damage || damage === 0)) return false;
				didSomething = true;
			} else if (damage === false && typeof hitResult === 'undefined') {
				this.add('-fail', target);
			}
			if (damage === false || damage === null) {
				return false;
			}
			if (moveData.boosts && !target.fainted) {
				this.boost(moveData.boosts, target, pokemon, move);
			}
			if (moveData.heal && !target.fainted) {
				var d = target.heal(Math.round(target.maxhp * moveData.heal[0] / moveData.heal[1]));
				if (!d) {
					this.add('-fail', target);
					return false;
				}
				this.add('-heal', target, target.getHealth);
				didSomething = true;
			}
			if (moveData.status) {
				if (!target.status) {
					target.setStatus(moveData.status, pokemon, move);
				} else if (!isSecondary) {
					if (target.status === moveData.status) {
						this.add('-fail', target, target.status);
					} else {
						this.add('-fail', target);
					}
				}
				didSomething = true;
			}
			if (moveData.forceStatus) {
				if (target.setStatus(moveData.forceStatus, pokemon, move)) {
					didSomething = true;
				}
			}
			if (moveData.volatileStatus) {
				if (target.addVolatile(moveData.volatileStatus, pokemon, move)) {
					didSomething = true;
				}
			}
			if (moveData.sideCondition) {
				if (target.side.addSideCondition(moveData.sideCondition, pokemon, move)) {
					didSomething = true;
				}
			}
			if (moveData.pseudoWeather) {
				if (this.addPseudoWeather(moveData.pseudoWeather, pokemon, move)) {
					didSomething = true;
				}
			}
			// Hit events
			//   These are like the TryHit events, except we don't need a FieldHit event.
			//   Scroll up for the TryHit event documentation, and just ignore the "Try" part. ;)
			if (move.target === 'all' && !isSelf) {
				hitResult = this.singleEvent('HitField', moveData, {}, target, pokemon, move);
			} else if ((move.target === 'foeSide' || move.target === 'allySide') && !isSelf) {
				hitResult = this.singleEvent('HitSide', moveData, {}, target.side, pokemon, move);
			} else {
				hitResult = this.singleEvent('Hit', moveData, {}, target, pokemon, move);
				if (!isSelf && !isSecondary) {
					this.runEvent('Hit', target, pokemon, move);
				}
			}
			if (!hitResult && !didSomething) {
				if (hitResult === false) this.add('-fail', target);
				return false;
			}
		}
		if (target) {
			var targetSub = target.getVolatile('substitute');
			if (targetSub === null) {
				var targetHasSub = false;
			} else {
				var targetHasSub = (targetSub.hp > 0);
			}
		} else {
			var targetHasSub = false;
		}

		var doSelf = (targetHadSub && targetHasSub) || !targetHadSub;
		if (moveData.self && doSelf) {
			this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
		}
		if (moveData.secondaries) {
			var secondaryRoll;
			var effectChance;
			for (var i = 0; i < moveData.secondaries.length; i++) {
				secondaryRoll = this.random(256);
				effectChance = Math.floor(moveData.secondaries[i].chance*255/100);
				if (typeof moveData.secondaries[i].chance === 'undefined' || secondaryRoll < effectChance) {
					this.moveHit(target, pokemon, move, moveData.secondaries[i], true, isSelf);
				}
			}
		}
		if (move.selfSwitch && pokemon.hp) {
			pokemon.switchFlag = move.selfSwitch;
		}

		return damage;
	},
	getDamage: function(pokemon, target, move, suppressMessages) {
		// We get the move
		if (typeof move === 'string') move = this.getMove(move);
		if (typeof move === 'number') move = {
			basePower: move,
			type: '???',
			category: 'Physical'
		};

		// First of all, we test for immunities
		if (move.affectedByImmunities) {
			if (!target.runImmunity(move.type, true)) {
				return false;
			}
		}

		// Is it ok?
		if (move.ohko) {
			if (target.speed > pokemon.speed) {
				this.add('-failed', target);
				return false;
			}
			return target.maxhp;
		}

		// We edit the damage through move's damage callback
		if (move.damageCallback) {
			return move.damageCallback.call(this, pokemon, target);
		}

		// We take damage from damage=level moves
		if (move.damage === 'level') {
			return pokemon.level;
		}

		// If there's a fix move damage, we run it
		if (move.damage) {
			return move.damage;
		}

		// If it's the first hit on a Normal-type partially trap move, it hits Ghosts but damage is 0
		if (move.volatileStatus === 'partiallytrapped' && move.type === 'Normal' && target.hasType('Ghost')) {
			return 0;
		}

		// Let's check if we are in middle of a partial trap sequence
		if (pokemon.volatiles['partialtrappinglock'] && (target !== pokemon) && (target === pokemon.volatiles['partialtrappinglock'].locked)) {
			return pokemon.volatiles['partialtrappinglock'].damage;
		}

		// There's no move for some reason, create it
		if (!move) {
			move = {};
		}

		// We check the category and typing to calculate later on the damage
		if (!move.category) move.category = 'Physical';
		if (!move.defensiveCategory) move.defensiveCategory = move.category;
		// '???' is typeless damage: used for Struggle and Confusion etc
		if (!move.type) move.type = '???';
		var type = move.type;

		// We get the base power and apply basePowerCallback if necessary
		var basePower = move.basePower;
		if (move.basePowerCallback) {
			basePower = move.basePowerCallback.call(this, pokemon, target, move);
		}

		// We check for Base Power
		if (!basePower) {
			if (basePower === 0) return; // Returning undefined means not dealing damage
			return basePower;
		}
		basePower = clampIntRange(basePower, 1);

		// Checking for the move's Critical Hit ratio
		// First, we check if it's a 100% crit move
		move.critRatio = clampIntRange(move.critRatio, 0, 5);
		move.crit = move.willCrit || false;
		var critRatio = 0;
		// Otherwise, we calculate the critical hit chance
		if (typeof move.willCrit === 'undefined') {
			// In gen 1, the critical chance is based on speed
			switch (move.critRatio) {
			case 1:
				// Normal crit-rate: BaseSpeed * 100 / 512.
				critRatio = pokemon.template.baseStats['spe'] * 100 / 512;
				break;
			case 2:
				// High crit-rate: BaseSpeed * 100 / 64
				critRatio = pokemon.template.baseStats['spe'] * 100 / 64;
				break;
			case -2:
				// Crit rate destroyed by Focus Energy (dumb trainer is dumb)
				critRatio = (pokemon.template.baseStats['spe'] * 100 / 64) * 0.25;
				this.debug('Using ruined normal crit-rate: (template.baseStats[\'spe\'] * 100 / 64) * 0.25');
				break;
			case -1:
				// High crit move ruined by Focus Energy. Deppends on speed
				if (pokemon.speed > target.speed) {
					// Critical rate not decreased if pokemon is faster than target
					critRatio = pokemon.template.baseStats['spe'] * 100 / 64;
					 this.debug('Using ruined high crit-rate: template.baseStats[\'spe\'] * 100 / 64');
				} else {
					// If you are slower, you can't crit on this moves
					this.debug('Ruined crit rate, too slow, cannnot crit');
					critRatio = false;
				}
				break;
			}

			// Last, we check deppending on ratio if the move hits
			if (critRatio) {
				critRatio = critRatio.floor();
				var random = Math.random() * 100;
				move.crit = (random.floor() <= critRatio);
			}
		}
		if (move.crit) {
			move.crit = this.runEvent('CriticalHit', target, null, move);
		}

		// Happens after crit calculation
		if (basePower) {
			basePower = this.runEvent('BasePower', pokemon, target, move, basePower);
			if (move.basePowerModifier) {
				basePower *= move.basePowerModifier;
			}
		}
		if (!basePower) return 0;
		basePower = clampIntRange(basePower, 1);

		// We now check for attacker and defender
		var level = pokemon.level;
		var attacker = pokemon;
		var defender = target;
		if (move.useTargetOffensive) attacker = target;
		if (move.useSourceDefensive) defender = pokemon;
		var atkType = (move.category === 'Physical')? 'atk' : 'spa';
		var defType = (move.defensiveCategory === 'Physical')? 'def' : 'spd';
		var attack = attacker.getStat(atkType);
		var defense = defender.getStat(defType);

		if (move.crit) {
			move.ignoreOffensive = true;
			move.ignoreDefensive = true;
		}
		if (move.ignoreOffensive) {
			this.debug('Negating (sp)atk boost/penalty.');
			attack = attacker.getStat(atkType, true);
		}
		if (move.ignoreDefensive) {
			this.debug('Negating (sp)def boost/penalty.');
			defense = target.getStat(defType, true);
		}

		// Gen 1 damage formula:
		// (min(((2 * L / 5 + 2) * Atk * BP) / max(1, Def) / 50, 997) + 2) * Stab * TypeEffect * Random / 255
		// Where: L: user level, A: current attack, P: move power, D: opponent current defense,
		// S is the Stab modifier, T is the type effectiveness modifier, R is random between 217 and 255
		// The max damage is 999
		var baseDamage = Math.min(Math.floor(Math.floor(Math.floor(2 * level / 5 + 2) * attack * basePower / defense) / 50), 997) + 2;

		// Crit damage addition (usually doubling)
		if (move.crit) {
			if (!suppressMessages) this.add('-crit', target);
			baseDamage = this.modify(baseDamage, move.critModifier || 2);
		}

		// STAB damage bonus, the "???" type never gets STAB
		if (type !== '???' && pokemon.hasType(type)) {
			baseDamage = Math.floor(baseDamage * 1.5);
		}

		// Type effectiveness
		var totalTypeMod = this.getEffectiveness(type, target);
		// Super effective attack
		if (totalTypeMod > 0) {
			if (!suppressMessages) this.add('-supereffective', target);
			baseDamage *= 2;
			if (totalTypeMod >= 2) {
				baseDamage *= 2;
			}
		}

		// Resisted attack
		if (totalTypeMod < 0) {
			if (!suppressMessages) this.add('-resisted', target);
			baseDamage = Math.floor(baseDamage / 2);
			if (totalTypeMod <= -2) {
				baseDamage = Math.floor(baseDamage / 2);
			}
		}

		// Randomizer, it's a number between 217 and 255
		var randFactor = Math.floor(Math.random()*39)+217;
		baseDamage *= Math.floor(randFactor * 100 / 255) / 100;

		// If damage is less than 1, we return 1
		if (basePower && !Math.floor(baseDamage)) {
			return 1;
		}

		// We are done, this is the final damage
		return Math.floor(baseDamage);
	},
	boost: function(boost, target, source, effect) {
		// Editing boosts to take into account para and burn stat drops glitches
		if (this.event) {
			if (!target) target = this.event.target;
			if (!source) source = this.event.source;
			if (!effect) effect = this.effect;
		}
		if (!target || !target.hp) return 0;
		effect = this.getEffect(effect);
		boost = this.runEvent('Boost', target, source, effect, Object.clone(boost));
		for (var i in boost) {
			var currentBoost = {};
			currentBoost[i] = boost[i];
			if (boost[i] !== 0 && target.boostBy(currentBoost)) {
				var msg = '-boost';
				if (boost[i] < 0) {
					msg = '-unboost';
					boost[i] = -boost[i];
					// Re-add attack and speed drops if not present
					if (i === 'atk' && target.status === 'brn' && !target.volatiles['brnattackdrop']) {
						target.addVolatile('brnattackdrop');
					}
					if (i === 'spe' && target.status === 'par' && !target.volatiles['parspeeddrop']) {
						target.addVolatile('parspeeddrop');
					}
				} else {
					// Check for boost increases deleting attack or speed drops
					if (i === 'atk' && target.status === 'brn' && target.volatiles['brnattackdrop']) {
						target.removeVolatile('brnattackdrop');
					}
					if (i === 'spe' && target.status === 'par' && target.volatiles['parspeeddrop']) {
						target.removeVolatile('parspeeddrop');
					}
				}
				if (effect.effectType === 'Move') {
					this.add(msg, target, i, boost[i]);
				} else {
					this.add(msg, target, i, boost[i], '[from] '+effect.fullname);
				}
				this.runEvent('AfterEachBoost', target, source, effect, currentBoost);
			}
		}
		this.runEvent('AfterBoost', target, source, effect, boost);
	},
	damage: function(damage, target, source, effect) {
		if (this.event) {
			if (!target) target = this.event.target;
			if (!source) source = this.event.source;
			if (!effect) effect = this.effect;
		}
		if (!target || !target.hp) return 0;
		effect = this.getEffect(effect);
		if (!(damage || damage === 0)) return damage;
		if (damage !== 0) damage = clampIntRange(damage, 1);

		if (effect.id !== 'struggle-recoil') { // Struggle recoil is not affected by effects
			damage = this.runEvent('Damage', target, source, effect, damage);
			if (!(damage || damage === 0)) {
				this.debug('damage event failed');
				return damage;
			}
		}
		if (damage !== 0) damage = clampIntRange(damage, 1);
		damage = target.damage(damage, source, effect);
		if (source) source.lastDamage = damage;
		var name = effect.fullname;
		if (name === 'tox') name = 'psn';
		switch (effect.id) {
		case 'partiallytrapped':
			this.add('-damage', target, target.getHealth, '[from] '+this.effectData.sourceEffect.fullname, '[partiallytrapped]');
			break;
		default:
			if (effect.effectType === 'Move') {
				this.add('-damage', target, target.getHealth);
			} else if (source && source !== target) {
				this.add('-damage', target, target.getHealth, '[from] '+effect.fullname, '[of] '+source);
			} else {
				this.add('-damage', target, target.getHealth, '[from] '+name);
			}
			break;
		}

		if (effect.recoil && source) {
			this.damage(Math.round(damage * effect.recoil[0] / effect.recoil[1]), source, target, 'recoil');
		}
		if (effect.drain && source) {
			this.heal(Math.ceil(damage * effect.drain[0] / effect.drain[1]), source, target, 'drain');
		}

		if (target.fainted) this.faint(target);
		else {
			damage = this.runEvent('AfterDamage', target, source, effect, damage);
			if (effect && !effect.negateSecondary) {
				this.runEvent('Secondary', target, source, effect);
			}
		}
		return damage;
	},
	// This is random teams making for gen 1
	randomCCTeam: function(side) {
		var teamdexno = [];
		var team = [];

		//pick six random pokmeon--no repeats, even among formes
		//also need to either normalize for formes or select formes at random
		//unreleased are okay. No CAP for now, but maybe at some later date
		for (var i=0; i<6; i++)
		{
			while (true) {
				var x=Math.floor(Math.random()*150)+1;
				if (teamdexno.indexOf(x) === -1) {
					teamdexno.push(x);
					break;
				}
			}
		}

		for (var i=0; i<6; i++) {

			//choose forme
			var formes = [];
			for (var j in this.data.Pokedex) {
				if (this.data.Pokedex[j].num === teamdexno[i] && this.getTemplate(this.data.Pokedex[j].species).learnset && this.data.Pokedex[j].species !== 'Pichu-Spiky-eared') {
					formes.push(this.data.Pokedex[j].species);
				}
			}
			var poke = formes.sample();
			var template = this.getTemplate(poke);

			//level balance--calculate directly from stats rather than using some silly lookup table
			var mbstmin = 1307; //sunkern has the lowest modified base stat total, and that total is 807

			var stats = template.baseStats;

			// Modified base stat total assumes 30 IVs, 255 EVs in every stat
			var mbst = (stats["hp"]*2+30+63+100)+10;
			mbst += (stats["atk"]*2+30+63+100)+5;
			mbst += (stats["def"]*2+30+63+100)+5;
			mbst += (stats["spa"]*2+30+63+100)+5;
			mbst += (stats["spd"]*2+30+63+100)+5;
			mbst += (stats["spe"]*2+30+63+100)+5;

			var level = Math.floor(100*mbstmin/mbst); // Initial level guess will underestimate

			while (level < 100) {
				mbst = Math.floor((stats["hp"]*2+30+63+100)*level/100+10);
				mbst += Math.floor(((stats["atk"]*2+30+63+100)*level/100+5)*level/100); //since damage is roughly proportional to lvl
				mbst += Math.floor((stats["def"]*2+30+63+100)*level/100+5);
				mbst += Math.floor(((stats["spa"]*2+30+63+100)*level/100+5)*level/100);
				mbst += Math.floor((stats["spd"]*2+30+63+100)*level/100+5);
				mbst += Math.floor((stats["spe"]*2+30+63+100)*level/100+5);

				if (mbst >= mbstmin)
					break;
				level++;
			}

			// Random IVs
			var ivs = {
				hp: Math.floor(Math.random()*31),
				atk: Math.floor(Math.random()*31),
				def: Math.floor(Math.random()*31),
				spa: Math.floor(Math.random()*31),
				spd: Math.floor(Math.random()*31),
				spe: Math.floor(Math.random()*31)
			};

			// ALl EVs
			var evs = {
				hp: 255,
				atk: 255,
				def: 255,
				spa: 255,
				spd: 255,
				spe: 255
			};

			// Four random unique moves from movepool. don't worry about "attacking" or "viable"
			var moves;
			var pool = ['struggle'];
			pool = Object.keys(template.learnset);
			if (pool.length <= 4) {
				moves = pool;
			} else {
				moves = pool.sample(4);
			}

			team.push({
				name: poke,
				moves: moves,
				ability: 'None',
				evs: evs,
				ivs: ivs,
				item: '',
				level: level,
				happiness: 0,
				shiny: false,
				nature: 'Serious'
			});
		}

		return team;
	},
	randomTeam: function(side) {
		var keys = [];
		var pokemonLeft = 0;
		var pokemon = [];
		for (var i in this.data.FormatsData) {
			//if (this.data.FormatsData[i].viableMoves) {
				keys.push(i);
			//}
		}
		keys = keys.randomize();

		var ruleset = this.getFormat().ruleset;

		for (var i=0; i<keys.length && pokemonLeft < 6; i++) {
			var template = this.getTemplate(keys[i]);
			if (!template || !template.name || !template.types) continue;
			var set = this.randomSet(template, i);

			pokemon.push(set);
			pokemonLeft++;
		}

		return pokemon;
	},
	randomSet: function(template, i) {
		if (i === undefined) i = 1;
		template = this.getTemplate(template);
		if (!template.exists) template = this.getTemplate('pikachu'); // Because Gen 1

		var moveKeys = Object.keys(template.viableMoves || template.learnset).randomize();
		var moves = [];
		var hasType = {};
		hasType[template.types[0]] = true;
		if (template.types[1]) hasType[template.types[1]] = true;
		var hasMove = {};
		var counter = {};
		var setupType = '';

		var j=0;
		do {
			hasMove = {};
			counter = {
				Physical: 0, Special: 0, Status: 0, damage: 0,
				recoil: 0, inaccurate: 0,
				physicalsetup: 0, specialsetup: 0, mixedsetup: 0
			};
			for (var k=0; k<moves.length; k++) {
				var move = this.getMove(moves[k]);
				var moveid = move.id;
				hasMove[moveid] = true;
				if (move.damage || move.damageCallback) {
					counter['damage']++;
				} else {
					counter[move.category]++;
				}
				if (move.recoil) {
					counter['recoil']++;
				}
				if (move.accuracy && move.accuracy !== true && move.accuracy < 90) {
					counter['inaccurate']++;
				}
				var PhysicalSetup = {swordsdance:1};
				var SpecialSetup = {amnesia:1};
				var MixedSetup = {growth:1};
				if (PhysicalSetup[moveid]) {
					counter['physicalsetup']++;
				}
				if (SpecialSetup[moveid]) {
					counter['specialsetup']++;
				}
				if (MixedSetup[moveid]) {
					counter['mixedsetup']++;
				}
			}

			if (counter['mixedsetup']) {
				setupType = 'Mixed';
			} else if (counter['specialsetup']) {
				setupType = 'Special';
			} else if (counter['physicalsetup']) {
				setupType = 'Physical';
			}

			for (var k=0; k<moves.length; k++) {
				var moveid = moves[k];
				var move = this.getMove(moveid);
				var rejected = false;
				var isSetup = false;

				switch (moveid) {
				// bad after setup
				case 'seismictoss': case 'nightshade':
					if (setupType) rejected = true;
					break;

				// bit redundant to have both
				case 'flamethrower':
					if (hasMove['fireblast']) rejected = true;
					break;
				case 'icebeam':
					if (hasMove['blizzard']) rejected = true;
					break;
				case 'surf':
					if (hasMove['hydropump']) rejected = true;
					break;
				case 'petaldance': case 'solarbeam':
					if (hasMove['megadrain'] || hasMove['razorleaf']) rejected = true;
					break;
				case 'megadrain':
					if (hasMove['razorleaf']) rejected = true;
					break;
				case 'thunder':
					if (hasMove['thunderbolt']) rejected = true;
					break;
				case 'bonemerang':
					if (hasMove['earthquake']) rejected = true;
					break;
				case 'rest':
					if (hasMove['recover'] || hasMove['softboiled']) rejected = true;
					break;
				case 'softboiled':
					if (hasMove['recover']) rejected = true;
					break;
				} // End of switch for moveid
				if (setupType === 'Physical' && move.category !== 'Physical' && counter['Physical'] < 2) {
					rejected = true;
				}
				if (setupType === 'Special' && move.category !== 'Special' && counter['Special'] < 2) {
					rejected = true;
				}

				if (rejected && j<moveKeys.length) {
					moves.splice(k, 1);
					break;
				}
			} // End of for
		} while (moves.length<4 && j<moveKeys.length);

		var levelScale = {
			LC: 95,
			UU: 78,
			OU: 74,
			Uber: 70
		};
		// Really bad Pokemon and jokemons
		var customScale = {
			Caterpie: 99, Kakuna: 99, Magikarp: 99, Metapod: 99, Weedle: 99,
			Clefairy: 95, "Farfetch'd": 95, Jigglypuff: 95
		};
		var level = levelScale[template.tier] || 90;
		if (customScale[template.name]) level = customScale[template.name];

		return {
			name: template.name,
			moves: moves,
			ability: 'None',
			evs: {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255},
			ivs: {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30},
			item: '',
			level: level,
			shiny: false,
			gender: false
		};
	},
	faint: function(pokemon, source, effect) {
		pokemon.faint(source, effect);
		this.queue = [];
	}
};


text:
@implementation UserModel
@synthesize uid;          //用户ID
@synthesize uname;        //用户昵称
@synthesize password;     //用户密码
@synthesize email;        //用户邮箱
@synthesize face;         //用户头像
@synthesize money;        //用户金钱
@synthesize lasttime;     //上次登录时间
@synthesize lastip;       //上次登录IP
@synthesize jointime;     //注册时间
@synthesize joinip;       //注册IP
@synthesize checkmail;    //验证邮箱
@synthesize state;        //状态
@synthesize fans;         //粉丝
@synthesize look;         //
@synthesize articles;     //发表文章数
@synthesize comments;     //回复数

-(void) dealloc {
    [uid release];
    [uname release];
    [password release];
    [email release];
    [face release];
    [money release];
    [lasttime release];
    [lastip release];
    [jointime release];
    [joinip release];
    [checkmail release];
    [state release];
    [fans release];
    [look release];
    [articles release];
    [comments release];
    [super dealloc];
}

@end

redpajama_set_name: RedPajamaGithub


text:
package org.opencord.cordvtn.codec;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.opencord.cordvtn.api.net.AddressPair;
import org.opencord.cordvtn.api.net.ServicePort;

import java.util.Objects;

/**
 * Json matcher for ServicePort.
 */
public final class ServicePortJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {

    private final ServicePort port;

    private ServicePortJsonMatcher(ServicePort port) {
        this.port = port;
    }

    /**
     * Factory to allocate ServicePort matcher.
     *
     * @param port service port object to match
     * @return matcher
     */
    public static ServicePortJsonMatcher matchesServicePort(ServicePort port) {
        return new ServicePortJsonMatcher(port);
    }

    @Override
    protected boolean matchesSafely(JsonNode jsonNode, Description description) {
        final String jsonPortId = jsonNode.get("id").asText();
        if (!Objects.equals(jsonPortId, port.id().id())) {
            description.appendText("Port id was " + jsonPortId);
            return false;
        }

        final String jsonPortName = jsonNode.get("name").asText();
        if (!Objects.equals(jsonPortName, port.name())) {
            description.appendText("Port name was " + jsonPortName);
            return false;
        }

        final String jsonPortNetId = jsonNode.get("network_id").asText();
        if (!Objects.equals(jsonPortNetId, port.networkId().id())) {
            description.appendText("Network id was " + jsonPortNetId);
            return false;
        }

        final String jsonMacAddr = jsonNode.get("mac_address").asText();
        if (!Objects.equals(jsonMacAddr, port.mac().toString())) {
            description.appendText("MAC address was " + jsonMacAddr);
            return false;
        }

        final String jsonIpAddr = jsonNode.get("ip_address").asText();
        if (!Objects.equals(jsonIpAddr, port.ip().toString())) {
            description.appendText("IP address was " + jsonIpAddr);
            return false;
        }

        final String jsonVlanId = jsonNode.get("vlan_id").asText();
        if (!Objects.equals(jsonVlanId, port.vlanId().toString())) {
            description.appendText("VLAN id was " + jsonVlanId);
            return false;
        }

        final JsonNode jsonAddrPairs = jsonNode.get("floating_address_pairs");
        if (port.addressPairs().isEmpty()) {
            if (jsonAddrPairs != null &&
                    jsonAddrPairs != NullNode.getInstance() &&
                    jsonAddrPairs.size() != 0) {
                description.appendText("Floating address pairs did not match");
                return false;
            }
        } else {
            if (jsonAddrPairs == null ||
                    jsonAddrPairs == NullNode.getInstance() ||
                    jsonAddrPairs.size() == 0) {
                description.appendText("Floating address pairs was empty");
                return false;
            } else if (jsonAddrPairs.size() != port.addressPairs().size()) {
                description.appendText("Floating address pairs size was " +
                        jsonAddrPairs.size());
                return false;
            } else {
                for (JsonNode addrPair : jsonAddrPairs) {
                    final AddressPair tmp = AddressPair.of(
                            IpAddress.valueOf(addrPair.get("ip_address").asText()),
                            MacAddress.valueOf(addrPair.get("mac_address").asText())
                    );
                    if (!port.addressPairs().contains(tmp)) {
                        description.appendText("Floating address pairs did not match " + tmp);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(port.toString());
    }
}


text:
package com.payton;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * Created by the MineTurtle crew on 3/14/14.
 */
public class NetworkHandler extends Thread {

    private static DatagramSocket socket = null;

    public NetworkHandler(){
        try {
            this.socket = new DatagramSocket(19132);
        }catch (SocketException e){
            Loggy.error("aww, we were unable to create the socket :(");
            e.printStackTrace();
        }
        Loggy.info("MineTurtle networking initalized.");
    }

    public void run(){
        while (Main.isStarted){
            byte buffer[] = new byte[1024];
            DatagramPacket p = new DatagramPacket(buffer, buffer.length);
            try {
                socket.receive(p);
            }catch (IOException e){
                Loggy.error("aww, bad luck. IOException?!");
                e.printStackTrace();
            }finally {
                String hexs = Integer.toHexString(0xFF & p.getData()[0]);
                int type = (int) Long.parseLong(hexs, 16);
                Loggy.info("yayz, received packet " + type + "with length of " + p.getLength());
                handlePacket(p, type);
            }
        }
    }

    private void handlePacket(DatagramPacket packet, int type) {
        switch (type){
            case PacketTypes.UNCONNECTED_PING:
            case PacketTypes.UNCONNECTED_PING_OPEN_CONNECTIONS:
                break;
        }
    }
}


text:
/*--------- BODY --------- */
body.widget-view {margin-bottom:54px;}
body .ui-widget {font-size: inherit;}
.ui-widget-content a {color: #428BCA;}
.ui-widget-content a:hover, .ui-widget-content a:focus {color: #2A6496;}

/* -------- TEMPLATE -------- */
.panelgridHeaderTable {width:100%;}
.panelgridHeaderTable .ui-widget-content, .panelgridHeaderTable .ui-widget-content > td {border:0; background:none;}
.panelgridHeaderTable .ui-widget-content > td:last-child table {margin-left:auto;}

.text-brand {color:#C55B28;}
.bg-brand {background:#C55B28;}
.bg-muted {background:#f5f5f5;}

#navbarFixed {margin-bottom:0;}
.navbar-fixed-top, .navbar-fixed-bottom {
    z-index: 930;
}
#navbarFixed .navbar-brand {color:#C55B28; padding-left:32px;}
#navbarFixed .icon-dataverse {color:#C55B28; font-size:28px; margin: -4px 0 0 -27px; position: absolute;}
#navbarFixed .label.status {display:block; float:left; margin-top:16px; background:#C55B28; font-size:14px; font-weight:normal;}

#navbarFixed form.navbar-form.navbar-form-link {margin:0; padding:0;}
#navbarFixed form.navbar-form-link a.ui-commandlink, #navbarFixed ul.navbar-nav li.dropdown span.dropdown-toggle {display:block; padding:15px; color: #777;}
#navbarFixed form.navbar-form-link a.ui-commandlink:hover, #navbarFixed form.navbar-form-link a.ui-commandlink:focus,
#navbarFixed ul.navbar-nav li.dropdown span.dropdown-toggle:hover, #navbarFixed ul.navbar-nav li.dropdown span.dropdown-toggle:focus {color: #262626; text-decoration: none;}
#navbarFixed #navbar-search-toggle, #navbarFixed #dataverseSupportLink, #navbarFixed #lnk_header_account_dropdown {cursor: pointer; cursor: hand;}
#navbarFixed .dropdown.accountName #lnk_header_account_dropdown span.glyphicon {margin-right:8px;}
#navbarFixed .dropdown.accountName .label.label-danger {margin-left:.5em; line-height:normal; vertical-align:text-top;}
#navbarFixed .dropdown.accountName .logout form {margin:0; padding:0; width:100%;}
#navbarFixed .dropdown.accountName .logout a {clear: both; color: #333333; display: block; font-weight: normal; line-height: 1.42857; padding: 3px 20px; white-space: nowrap; text-decoration: none;}
#navbarFixed .dropdown.accountName .logout a:hover, #navbarFixed .dropdown.accountName .logout a:focus {background-color: #E8E8E8; background-image: linear-gradient(to bottom, #F5F5F5 0px, #E8E8E8 100%); background-repeat: repeat-x; color: #262626; outline: 0; text-decoration: none;}
#navbarFixed li.dropdown.open > span.dropdown-toggle {background-color: #e7e7e7;}

#footer {margin-top:3em; padding-bottom:4em; color:#808080;}
#footer.widget-view {position:fixed; left:0px; bottom:0px; margin:0; padding:4px 0 0 0; min-height:44px; width:100%; background:#fff;}
#footer span.socicon-twitter {color:#55acee; font-size:1.3em; vertical-align: top;}
#footer span.socicon-github {color:#000; font-size:1.3em; vertical-align: top;}
#footer .poweredbylogo {text-align:right;}
#footer .poweredbylogo span {font-size:.85em;margin-right:.3em;}
#footer .version {vertical-align:bottom;white-space:nowrap;}
#footer.widget-view .widgetBrandMsg {line-height:42px;}

.panelLayoutBlock, .panelLayoutTitleBlock, .panelLayoutButtonBlock {border:0;}
.panelLayoutBlock .ui-panelgrid.panelgridLayoutTable .ui-widget-content, .panelLayoutBlock .ui-panelgrid.panelgridLayoutTable .ui-widget-content > td {border:0;}
.form-group table.noBorders tr.ui-widget-content, .form-group table.noBorders td {border:0; padding-left:0;}

.panelgridLayoutTable, .panelgridFormTable {width:100%;}
.panelgridFormTable > tbody > tr.ui-widget-content > td:first-child {width:20%;}
.panelgridFormTable.ui-panelgrid td table.ui-picklist td {border: 0; padding:0;}
.panelgridFormTable.ui-panelgrid td table.ui-picklist td ul.ui-widget-content.ui-corner-all {border:1px solid #DDDDDD; border-radius: 4px;}

.panelLayoutButtonBlock button {/*margin-right:2em;*/}

.panelLayoutBlock > .ui-widget-content {border-bottom:1px solid #DDDDDD;}
.panelLayoutBlock.breadcrumbNavBlock > .ui-widget-content {border-bottom:0;}
.panelLayoutTitleBlock > .ui-widget-content {border:0;}

.panelLayoutBlock .ui-panelgrid.panelgridLayoutTable .ui-widget-content .ui-panelgrid {margin-bottom: 1em;}
.panelLayoutBlock .ui-panelgrid.panelgridLayoutTable .ui-widget-content .ui-panelgrid .ui-widget-content .ui-panelgrid {margin-bottom: 0}
.panelLayoutBlock .ui-panelgrid.panelgridLayoutTable .ui-widget-content .ui-panelgrid .ui-widget-content .ui-panelgrid td:first-child {padding-left:0;}

.btn span.glyphicon {margin-right:.3em;}
.btn span.glyphicon.no-text {margin:0;}
.btn-group .btn span.glyphicon.no-text {margin-left:10px;margin-right:10px;}
.col-manage-action .btn-group .btn span.glyphicon.no-text {margin:0;}
.icon-inline-action {margin-left:.3em;}
.icon-inline-action:first-of-type {margin-left:1em;}

.text-icon-inline {font-size:1.3em;line-height:1.1em;margin-right:4px;}

#messagePanel div.messagePanel {margin-top:1em;}
.messagePanel .glyphicon {font-size: 1.5em; vertical-align: bottom;}

.highlightBold, a.highlightBold, .dropdown-menu > li > a.highlightBold {font-weight:bold;}
tr.ui-state-highlight, .ui-widget-content tr.ui-state-highlight, .ui-widget-header tr.ui-state-highlight {background-color: #ffffcc; background-image: none; color: #333333;}
tr.ui-state-highlight label, .ui-widget-content tr.ui-state-highlight label, .ui-widget-header tr.ui-state-highlight label {color: #333333;}
tr.ui-state-highlight a:not(.btn), .ui-widget-content tr.ui-state-highlight a:not(.btn), .ui-widget-header tr.ui-state-highlight a:not(.btn) {color: #428bca;}
tr.ui-state-highlight .ui-icon {
    background-image: url("/javax.faces.resource/images/ui-icons_333333_256x240.png.xhtml?ln=primefaces-bootstrap");
}
td.col-select-width {width:36px;}

#ajaxStatusPanel_start {width:31px;height:31px;position:fixed;right:50%;bottom:50%;z-index:111111;}
#ajaxStatusPanel_complete {position:absolute;top:-9999px;left:-9999px;}

.italic {font-style: italic;}
.margin-top {margin-top:1em;}
.margin-top-half {margin-top:.5em;}
.margin-bottom {margin-bottom:1em;}
.margin-bottom-half {margin-bottom:.5em;}
.no-margin-top {margin-top:0;}
.no-margin-bottom {margin-bottom:0;}
.margin-sides {margin-left:1em; margin-right:1em;}
.padding-12 {padding: 12px;}
.clear-both {clear:both;}

table.selectManyCheckboxBlock input {margin-right:4px;}
table.selectManyCheckboxBlock label {font-weight:normal;}
.normal-text {font-weight:normal;}
.normal-text input {margin-right:4px;}

hr {border-color: #ddd;}

span.glyphicon[data-toggle='tooltip'] {cursor: default;}
.tooltip {z-index:999999 !important;}

/* Dropdown submenu */
.dropdown-submenu {
    position: relative;
}
.dropdown-submenu.pull-left {
    width: 100%;
}
.dropdown-submenu>.dropdown-menu {
    top: 0;
    left: 100%;
    margin-top: -6px;
    margin-left: -1px;
    -webkit-border-radius: 0 6px 6px 6px;
    -moz-border-radius: 0 6px 6px;
    border-radius: 0 6px 6px 6px;
}
.dropdown-submenu.pull-left>.dropdown-menu {
    float: right;
    min-width: 100%;
}

.dropdown-submenu:hover>.dropdown-menu {
    display: block;
}

.dropdown-submenu>a:after {
    display: block;
    content: " ";
    float: right;
    width: 0;
    height: 0;
    border-color: transparent;
    border-style: solid;
    border-width: 5px 0 5px 5px;
    border-left-color: #ccc;
    margin-top: 5px;
    margin-right: -10px;
}

.dropdown-submenu:hover>a:after {
    border-left-color: #fff;
}

.dropdown-submenu.pull-left {
    float: none;
}

.dropdown-submenu.pull-left>.dropdown-menu {
    left: -100%;
    margin-left: 10px;
    -webkit-border-radius: 6px 0 6px 6px;
    -moz-border-radius: 6px 0 6px 6px;
    border-radius: 6px 0 6px 6px;
}

.highlight {
    padding: 9px 14px;
    margin-bottom: 1em;
    background-color: #f7f7f9;
    border: 1px solid #e1e1e8;
    border-radius: 4px;
}
.highlight pre {
    background-color: transparent;
    border: 0;
    margin-bottom: 0;
    margin-top: 0;
    padding: 0;
    white-space: nowrap;
    word-break: normal;
}
.highlight pre code {
    display: inline-block;
    color: #333;
    font-size: inherit;
    background-color: transparent;
    border-radius: 0;
    color: inherit;
    padding: 0;
    white-space: pre-wrap;
}

/* -------- HEADER -------- */
#dataverse-header-block {padding-top:50px;}
body.widget-view #dataverse-header-block {padding-top:0px;}
#dataverseHeader {margin:0 auto;}
#dataverseHeader .dataverseHeaderBlock {display:table-row;}
#dataverseHeader .dataverseHeaderCell {display:table-cell;}
#dataverseHeader .dataverseHeaderLogo {text-align:center;}
#dataverseHeader .dataverseHeaderLogo img {max-width:940px; max-height:120px;}
#dataverseHeader .dataverseHeaderCell.dataverseHeaderLogo img {max-width:100px; max-height:100px;}
#dataverseHeader .dataverseHeaderName {padding:2em 1em;}
#dataverseHeader .dataverseHeaderName .dataverseHeaderDataverseName {font-size: 1.3em;}
#dataverseHeader .dataverseHeaderName span.label.label-unpublished {vertical-align:text-top; line-height: normal; margin-left:1em;}
#dataverseHeader .dataverseHeaderTagline {padding-left:2em; font-size:1.3em;}
#dataverseHeader .dataverseHeaderLink {padding-left:2em;}

/* -------- BREADCRUMBS -------- */
#breadcrumbNavBlock {margin-top:.5em;}
#breadcrumbNavBlock .breadcrumbBlock {float:left; position:relative;}
#breadcrumbNavBlock .breadcrumbActive {font-weight:bold;}
#breadcrumbNavBlock a[id^='breadcrumbLnkTree'] {cursor: pointer; cursor: hand;}
#breadcrumbNavBlock a[id^='breadcrumbLnkTree'] span.glyphicon-chevron-down {vertical-align:middle;padding-bottom:2px;}

#breadcrumbNavBlock > .ui-panel-content {overflow:hidden;}

#breadcrumbNavBlock.panelLayoutBlock > .ui-widget-content {border-bottom: 0;}

#breadcrumbNavBlock .breadcrumbCarrot {float:left; margin:0 .4em; color:#B3B3B3;}

#breadcrumbNavBlock div.dropdown-menu {padding-right:.5em; min-width:280px;}

#breadcrumbNavBlock .ui-tree {width: auto;}

#breadcrumbNavBlock div.ui-tree.ui-widget-content {border:0;}
#breadcrumbNavBlock div.ui-tree.ui-widget-content span.ui-treenode-content span.ui-icon.ui-tree-toggler {background-size: auto 284px; height:20px; width:20px;}
#breadcrumbNavBlock div.ui-tree.ui-widget-content span.ui-treenode-content span.ui-icon.ui-tree-toggler.ui-icon-triangle-1-s {background-position: -72px -16px;}
#breadcrumbNavBlock div.ui-tree.ui-widget-content span.ui-treenode-content span.ui-icon.ui-tree-toggler.ui-icon-triangle-1-e {background-position: -35px -16px;}

/* -------- LOGIN -------- */
#login-container {margin-top:1em;}

div.panel.highlight {
    background-color: #f7f7f9;
}
#idpSelectIdPListTile form, #idpSelectIdPEntryTile form {margin-bottom:1em;}
#idpSelectIdPListTile input.btn, #idpSelectIdPEntryTile input.btn {margin-left:.5em;}
#idpSelectIdPEntryTile {position: relative;}
.IdPSelectPreferredIdPButton {display:inline-block;text-align:center;margin-right:4px;margin-bottom:.5em;}
ul.IdPSelectDropDown {
    background-clip: padding-box;
    background-color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 4px;
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
    float: left;
    font-size: 14px;
    left: 0;
    list-style: none outside none;
    margin: 2px 0 0;
    min-width: 160px;
    padding: 5px 0;
    position: absolute;
    text-align: left;
    top: calc(100% - 32px);
    z-index: 1000;
}

ul.IdPSelectDropDown > li {
    clear: both;
    color: #333;
    /* display: block; */
    font-weight: 400;
    line-height: 1.42857;
    padding: 3px 20px;
    white-space: nowrap;
}

ul.IdPSelectDropDown > li:hover, ul.IdPSelectDropDown > li:focus {
    background-color: #f5f5f5;
    color: #262626;
    text-decoration: none;
}
ul.IdPSelectDropDown > li.active, ul.IdPSelectDropDown > li.active:hover, ul.IdPSelectDropDown > li.active:focus {
    background-color: #428bca;
    color: #fff;
    outline: 0 none;
    text-decoration: none;
}
ul.IdPSelectDropDown > li.disabled, ul.IdPSelectDropDown > li.disabled:hover, ul.IdPSelectDropDown > li.disabled:focus {
    color: #777;
}
ul.IdPSelectDropDown > li.disabled:hover, ul.IdPSelectDropDown > li.disabled:focus {
    background-color: transparent;
    background-image: none;
    cursor: not-allowed;
    text-decoration: none;
}

/* -------- DASHBOARD -------- */
#dashboard-block div.card-box {
    background-clip: padding-box;
    background-color: #ffffff;
    border: 1px solid #e8e8e8;
    border-radius: 5px;
    margin-bottom: 20px;
    padding: 20px;
}
#dashboard-block div.card-box > .header-title {margin-top: 0;}
#dashboard-block div.card-box > .row {margin-top: 20px}

/* -------- USER -------- */
#terms-agreement-block {max-height:200px; margin-bottom: .5em; padding: 12px; overflow-y:scroll; box-shadow:none; background-image: none; background-color: #f5f5f5;}
#terms-agreement-block h1, #terms-agreement-block h2, #terms-agreement-block h3,
#terms-agreement-block h4, #terms-agreement-block h5, #terms-agreement-block h6 {margin-top:0;}
div[id$='notifications'].ui-tabs-panel div.table-container {display:table;}
div[id$='notifications'].ui-tabs-panel div.notification-item {display:table-row;}
div[id$='notifications'].ui-tabs-panel div.notification-item-cell {display:table-cell; border-bottom:1px solid #DDDDDD; padding:5px;}
div[id$='notifications'].ui-tabs-panel span.text-muted.small {margin-left:1em;}

/* -------- DATAVERSE -------- */
form[id$='dataverseForm'] .panelLayoutBlock .form-horizontal table.ui-panelgrid.ui-widget,
form[id$='dataverseForm'] .panelLayoutBlock .form-horizontal table.ui-panelgrid.ui-widget tr,
form[id$='dataverseForm'] .panelLayoutBlock .form-horizontal table.ui-panelgrid.ui-widget td {border:0;}
form[id$='dataverseForm'] .panelLayoutBlock .form-horizontal div.form-group {vertical-align: middle;}
.form-horizontal .text-left .control-label {text-align:left;}

input.metadata-blocks-default[type="checkbox"], input.facets-blocks-default[type="checkbox"] {margin: 4px 6px 0 0;}
div.checkbox input.metadata-blocks-default[type="checkbox"] {margin-left:-20px;}
label.metadata-blocks-default {margin-bottom:0; font-weight:normal;}

table[id$="facetPickListCreate"] td:last-child {padding-top:20px;}
table[id$="facetPickListCreate"] div.ui-selectonemenu {width:178px !important;}
table[id$="facetPickListCreate"] label.ui-selectonemenu-label {width:152px !important;}

table.ui-selectmanycheckbox.metadata-blocks-select label {font-weight:normal; margin-top:1px;}
table.ui-selectmanycheckbox.metadata-blocks-select label.ui-state-disabled {background:inherit;}

div.ui-state-focus span.ui-chkbox-icon {outline: -webkit-focus-ring-color auto 5px;}

/* Buttons */
#actionButtonBlock {margin-bottom:1em; margin-top:0;}
#dataverse-info-dropdown {padding:.5em 1em .25em 1em; overflow:hidden; width:400px;}
#dataverse-info-dropdown .dataverse-info-logo-icon {width:40px; float:left; margin-right:12px;}
#dataverse-info-dropdown .dataverse-info-logo-icon i.icon-dataverse {font-size:40px; line-height:40px;}
#dataverse-info-dropdown .dataverse-info-general {float:left; width:300px;}

.button-block {margin-top:1em;}
.form-group > .button-block,
.panel-body > .button-block,
td.col-file-action > .button-block, .col-manage-action > .button-block,
div.ui-datatable-header > .button-block, .button-block.tab-header {margin-top:0;}
form.btn-form {display:inline-block;}
.button-block button, .button-block a.btn, .button-block input.btn, .button-block div.btn-group, .button-block span.btn.ui-state-disabled {margin-right:1em;}
.col-manage-action .button-block button, .col-manage-action .button-block a.btn, .col-manage-action .button-block input.btn, .col-manage-action .button-block div.btn-group, .col-manage-action .button-block span.btn.ui-state-disabled {margin-right:0em;}
.button-block span.ingest-warning {margin-right:.5em;}
.button-block div.btn-group div.btn-group {margin-right:0;}
.button-block button.pull-right:first-child, .button-block a.btn.pull-right:first-child, .button-block div.btn-group.pull-right:first-child,
.button-block div.btn-group button, .button-block div.btn-group a.btn {margin-right:0;}
.button-block .btn:last-child, .button-block .btn-group:last-child,
.button-block form.btn-form:last-child .btn-group,
.button-block span.ui-state-disabled:last-child {margin-right:0;}
.button-block.pull-right .btn:last-child {margin-right:0;}
.button-block ul.dropdown-menu li.disabled span.ui-commandlink.ui-state-disabled {display: block; padding: 3px 20px; color: #777; background: none; opacity:1.0;}
div.field-add-delete a.btn {margin:0 1em 0 0;}
div.field-add-delete a.btn:last-child {margin-right:0;}
div.field-add-delete a.btn.compound-field-btn {margin-top:1.8em;}
div.field-add-delete a.btn.nolabel-field-btn {margin-top:0;}

/* Featured Dataverses*/
#carouselBlocksWrapper {border-bottom:1px solid #ddd; margin-bottom:1em;}
#featuredDataversesBlock {overflow: hidden; padding-top:.5em; border-top:1px solid #ddd;}
#featuredDataversesBlock div.customNavigation {width:4%;float:left;padding:28px 0;}
#featuredDataversesBlock div.customNavigation span.glyphicon {color:#999999;font-size:2em;}
#featuredDataversesList {width:90%; float:left;}
#featuredDataversesList .item {min-height:80px;}
#featuredDataversesList .item a {display:block;}
#featuredDataversesList .item .icon-dataverse {font-size:50px;line-height:normal;color:#c55b28;}
#featuredDataversesList .item img {max-width:160px; max-height:60px;}
.owl-carousel {margin-bottom:.5em;}
.owl-carousel .item {text-align: center; padding: 10px; border: 1px solid #e3e3e3; border-radius: 4px; margin: 10px;}

.logoPreview {max-width:80px;max-height:80px;}

#metadataFieldOptionsPanel-Block {width:70%; margin-left:60px; margin-top:.5em;}
#metadataFieldOptionsPanel-Body {padding:0; max-height:400px; overflow-y:scroll;}
#metadataFieldOptions td {vertical-align: middle;}
#metadataFieldOptions div.checkbox.child-field {padding-left:18px;}

/* -------- SEARCH -------- */
div.panelSearchForm {margin-bottom: 15px;}
div.panelSearchForm input.search-input {margin-right:1em; padding:4px; display: inline-block; vertical-align: middle; width: auto;}
a[id$='advsearchlink'] {margin-left:1em;}

#search-row-panel {border:1px solid #ddd; border-radius: 4px; padding: 15px 0;}
#dv-sidebar {}
#dv-main {}
#dv-main.nofacets {width:100%;float:none;}

/*
 * Off Canvas
 * --------------------------------------------------
 */
@media screen and (max-width: 767px) {
  .row-offcanvas {
    position: relative;
    -webkit-transition: all 0.25s ease-out;
    -moz-transition: all 0.25s ease-out;
    transition: all 0.25s ease-out;
  }

  .row-offcanvas-left .sidebar-offcanvas {
    left: -67%;
  }

  .row-offcanvas-left.active {
    left: 67%;
  }

  .sidebar-offcanvas {
    position: absolute;
    top: 0;
    width: 67%;
    margin-left: 10px;
  }

  #footer .poweredbylogo {text-align:center;}
  #footer.widget-view .poweredbylogo {text-align:right;}
}

.searchTypeButton {display:block; border:1px solid #DDD; padding:4px 0; margin-bottom: .5em;}

/*#resultsCountPaginatorBlock {overflow:hidden;}*/
#resultsCountPaginatorBlock div.results-count {padding:6px 12px; font-weight:bold;}
#resultsCountPaginatorBlock div.results-sort-pagination {}
#resultsCountPaginatorBlock .pagination {margin:0;}

span.search-term-match {font-weight: bold;}
[id$='resultsTable'] {width:100%;}
[id$='resultsTable'] div[class*='Result'] {font-size: 90%;}
[id$='resultsTable'] div[class*='Result'] > div.card-title-icon-block,
[id$='resultsTable'] div[class*='Result'] > div.card-preview-icon-block,
[id$='resultsTable'] div[class*='Result'] > div.file-tags-block {font-size: 110%;}
[id$='resultsTable'] span.label {vertical-align:text-bottom; line-height: normal; margin-left:.5em;}
[id$='resultsTable'] div.file-tags-block span.label:first-of-type {margin-left:0;}
[id$="resultsTable"] div.file-tags-block span.label {display:inline-block;}
[id$='resultsTable'] .resultDatasetCitationBlock {display:block;margin:4px 0 .5em 60px;padding:4px;}
[id$='resultsTable'] .resultDatasetCitationBlock span.search-term-match {font-weight: normal;}
[id$='resultsTable'] div.card-title-icon-block span[class^='icon'],
[id$='resultsTable'] div.card-title-icon-block span[class^='glyphicon'] {font-size:1.3em; margin-left:3px;}
[id$='resultsTable'] div.card-title-icon-block span[class$='lock'] {font-size:inherit; margin-left:0;}
[id$='resultsTable'] div.card-title-icon-block span[class^='glyphicon'] {margin-top:3px;}
[id$='resultsTable'] div.card-preview-icon-block {width:48px; float:left; margin:4px 12px 6px 0;}
[id$='resultsTable'] div.card-preview-icon-block a {display:block; height:48px; line-height:48px;}
[id$='resultsTable'] div.card-preview-icon-block img {vertical-align:middle;}
[id$='resultsTable'] div.card-preview-icon-block span[class^='icon'],
[id$='resultsTable'] div.card-preview-icon-block span[class^='glyphicon'] {font-size:2.8em;}

form[id$='facetType'] > div.clearfix {margin-bottom:4px;}
form[id$='facetType'] > div.clearfix:last-child {margin-bottom:0;}
form[id$='facetType'] > div.clearfix .facetTypeChBox {display:block; float:left;}
form[id$='facetType'] > div.clearfix .facetTypeChBox > div.ui-chkbox {padding-top:2px;padding-right:4px;}
form[id$='facetType'] > div.clearfix a.facetTypeLink {display:block; float:left; text-decoration:none;}

form[id$='facetType'] > div.clearfix a.facetTypeLink span {padding:4px 0px;}

form[id$='facetCategoryForm'] {margin-top:1em;}
div[id$='facetCategoryList'] ul, div[id$='facetCategoryList'] li, div[id$='facetCategoryList'] div {margin:0; padding:0; list-style: none; border:0;}
div[id$='facetCategoryList'] > div > ul > li {border-bottom:1px solid #DDD; margin-bottom:.5em;}
/*div[id$='facetCategoryList'] > div > ul > li:last-child {border-bottom:0; margin-bottom:0;}*/
div[id$='facetCategoryList'] div li div {padding:4px 0px;}
div[id$='facetCategoryList'] div li div.ui-datalist-empty-message {padding:4px 0px; font-style:italic; color:#AAA;}
div[id$='facetCategoryList'] div.ui-datalist, div[id$='facetCategoryList'] div.ui-datalist div.ui-datalist-content {padding-top:0;}
.facetCategoryName {font-weight:bold;}

.facetCategoryName, .facetLink {
-ms-word-break: break-all;

     /* Be VERY careful with this, breaks normal words wh_erever */
     word-break: break-all;

     /* Non standard for webkit */
     word-break: break-word;

-webkit-hyphens: auto;
   -moz-hyphens: auto;
        hyphens: auto;}
a.facetLink {text-decoration:none; font-size:90%;}
a.facetLink.facetSelected, a.facetTypeLink.facetSelected {font-weight:bold;}
a.facetLink.facetSelected span.glyphicon-remove {vertical-align:text-top; margin-top:1px; margin-left:.25em;}

#my_data_filter_column div.checkbox label:not(.facetTypeLabel) {color:#428bca;font-size:90%;}
#my_data_filter_column div.checkbox.facetSelected label, #my_data_filter_column  div.checkbox label.facetSelected {font-weight: bold;}
#my_data_filter_column div.checkbox label.facetSelected:hover {color: #23527c;}

table.ui-panelgrid.facetsMoreLess {width:100%;}
table.ui-panelgrid.facetsMoreLess tr.ui-widget-content {border:0;}
table.ui-panelgrid.facetsMoreLess td {width:50%; border:0;}
table.ui-panelgrid.facetsMoreLess td:last-child {text-align:right;}

#dv-main div.emptyResults.bg-warning {background:#FCF8F2; padding:.5em 1em;}
#resultsFacetsTopBlock {margin-bottom:.5em;}
#resultsFacetsTopBlock a.facetLink.facetSelected {display:inline-block; margin-bottom:.5em; margin-right:1em; background-color:#E6F1F6; padding-left:.3em; padding-right:.3em;}

#dv-main div.results-sort-pagination div.pagination {margin-left:1em;}
#dv-main div.results-sort-pagination.results-bottom .pagination {margin-top:0; margin-bottom:0;}

table[id$='resultsTable'] td > div {border:1px solid grey; margin:6px 0; padding: 4px 10px;}
table[id$='resultsTable'] td > div.dataverseResult {border-color:#c55b28;}
table[id$='resultsTable'] td > div.datasetResult {border-color:#428bca;}
table[id$='resultsTable'] td > div > div.card-title-icon-block,
table[id$='resultsTable'] td > div > div.card-preview-icon-block,
table[id$='resultsTable'] td > div > div.file-tags-block {
    font-size: 110%;
}

/* -------- TABLES -------- */
div.headerless-table .ui-datatable-tablewrapper table > thead {display:none;}

/* -------- POPUP -------- */
div.ui-dialog.smallPopUp {max-width:600px;}
div.ui-dialog.largePopUp {min-width:60%; max-width:80%; max-height:80%; overflow-y:scroll;}
div.ui-dialog .ui-datatable-scrollable table {table-layout: auto !important;}
div.ui-dialog .ui-datatable-scrollable table colgroup col {max-width:1000px;}

div.ui-dialog div.highlight {
    background-color: #f7f7f9;
    border: 1px solid #e1e1e8;
    border-radius: 4px;
    margin-bottom: 14px;
    padding: 9px 14px;
}
.ui-dialog.dialog-submenu, .ui-dialog.dialog-submenu .ui-dialog-content, .ui-dialog.dialog-submenu .form-inline, .ui-dialog.dialog-submenu .form-group {overflow:visible !important;}
.ui-dialog.dialog-submenu .ui-menu-list.ui-menu-child {z-index: 9999 !important; width: auto; min-width: 12.5em;}

.ui-dialog.ui-widget.ui-widget-content {min-width:600px;}

/* -------- SUBTABS -------- */
div.popupSubTabParent > div.ui-tabs-panels > div.ui-tabs-panel.ui-widget-content {padding-left:0; padding-right:0;}
div.ui-tabs-panels .ui-tabs .ui-tabs-nav.ui-widget-header li {border:0;}
div.ui-tabs-panels .ui-tabs.ui-tabs-top .ui-tabs-nav.ui-widget-header {border-bottom:0;}

/* -------- ADVANCED -------- */

/* -------- PERMISSIONS -------- */
div[id$='roleDisplay'] span.label, div[id$='roleDetails'] span.label {display:inline-block; margin-bottom:4px;}

/* -------- METRICS -------- */
#metrics-block {width:238px;}
#metrics-label {background:#6f5499;color:#fff;padding: 7px 10px;}
#metrics-content {background:#6f5499;position:relative;min-height:21px;}
#metrics-content div.tab-pane {color:#fff;padding: 2px 0;width:152px;position:absolute;top:0;left:0;}
#metrics-tabs a {background:#428bca;display:block;width:38px;line-height:13px;}
#metrics-tabs a:hover {text-decoration:none;}
#metrics-block .metrics-views {background:#428bca;}
#metrics-block .metrics-downloads {background:#5cb85c;}
#metrics-block .metrics-citations {background:#c55b28;}
#metrics-block .metrics-shares {background:#f0ad4e;}

/* -------- SHARRRE -------- */
#sharrre-block a {display:block; float:left; padding:6px 12px; margin-right:1em; background:#6f5499;}
#sharrre-block a:last-of-type {margin-right:0;}
#sharrre-block a span {color:#fff; font-size:14px;}
#sharrre-block a.sharrre-facebook {background:#3a5795;}
#sharrre-block a.sharrre-twitter {background:#55acee;}
#sharrre-block a.sharrre-google {background:#d73d32;}

/* -------- DATASET -------- */
#datasetVersionBlock span.label {vertical-align:text-top; line-height:normal; margin-left: 1em;}

#title {font-size:1.5em;font-weight:bold;}
#author, #contact {display:block; margin-bottom:.5em;}
#citation-block {margin-bottom:.5em;}
.bg-citation {background:#ECF6FB;}
div.alert-info.bg-citation, div.alert-danger.bg-danger {padding-top:4px; padding-bottom:4px; border-radius:0; color:#333;}
#citation-block > div.alert-info.bg-citation, #citation-block > div.alert-danger.bg-danger {padding-top:0; padding-bottom:0;}
#citation-select {display:inline-block;}
#citation, #citation-download, #citation-standards {padding:.5em;}
#citation span.glyphicon-question-sign {margin-left:.5em; margin-bottom:2px; vertical-align: middle;}
.waiver-CC0-inline {display:inline-block; margin-left:1em;}

div.panel-body div.form-group:last-child, div.panel-body div.form-group:last-child label {margin-bottom:0 !important;}
div.panel-body.read-terms{max-height:220px; overflow-y:scroll; width:100%; background-color:#eeeeee;}

/* Buttons */
.button-block.form-top {border-top: 1px solid #dddddd; padding:1em 0;}
span[id$='editDataSet'] .ui-button-text {white-space: nowrap;}
#replicationDataButton {margin-top:5px;}

#deaccession-reason-block {padding:4px; margin-bottom:.5em;}

div.form-group .glyphicon.glyphicon-asterisk {font-size:.5em; vertical-align:text-top;}
#datasetForm .form-group, #templateForm .form-group {overflow: hidden;}
div.form-col-container div.form-col-container {padding-left:0;}
div.form-group .ui-selectonemenu {display:block;}
div.form-col-container.edit-compound-field div.form-col-container {margin-bottom:.5em;}

div.panel-group div.panel {margin-bottom:1em;}
div.panel div.panel-body div.form-group {overflow: hidden;}
div.edit-field div.ui-message {margin:6px 0;}
.metadata-logo {max-width:180px;max-height:40px;}
.metadata-panel-body {padding:15px 0;}

/* Primefaces vs Bootstrap selectOneMenu fix */
div.ui-selectonemenu.form-control {padding:0px;}
.ui-selectonemenu .ui-selectonemenu-label {padding:6px 4px;}
.ui-selectonemenu .ui-selectonemenu-trigger {border-radius:0; width:24px;}
.ui-selectonemenu .ui-selectonemenu-trigger .ui-icon {margin-top:8px;}

/* Primefaces vs Bootstrap selectOneRadio fix */
table.ui-selectoneradio {border-collapse:separate;}
table.ui-selectoneradio td {padding:1px;}
table.ui-selectoneradio span.ui-icon-bullet, .ui-radiobutton-box span.ui-icon-bullet {background-position: -81.3px -145.1px;}
table.ui-selectoneradio label {font-weight: normal; margin-right:1em;}
.ui-radiobutton-box span.ui-radiobutton-icon {height: 16px; width: 16px; display: block; overflow: hidden;}

div.ui-radiobutton {margin:0; vertical-align:text-bottom;}
div.radio.no-padding-left label {padding-left:0;}

/* Primefaces vs Bootstrap checkbox fix */
.ui-chkbox .ui-chkbox-box {margin:0; vertical-align:top;}
.ui-chkbox.ui-widget .ui-chkbox-box.ui-widget {margin-top:4px;}
.ui-selectmanycheckbox.ui-widget td > .ui-chkbox.ui-widget .ui-chkbox-box.ui-widget, .ui-selectcheckboxmenu-item > .ui-chkbox.ui-widget .ui-chkbox-box.ui-widget {margin-top:0;}
.ui-selectcheckboxmenu-header > .ui-chkbox.ui-widget .ui-chkbox-box.ui-widget {margin-top:2px;}
.ui-chkbox .ui-chkbox-label {display:inline; vertical-align:text-top;}
.chkbox-label-margin {margin-top:3px;}

.ui-selectcheckboxmenu.form-control {height:auto;padding:0;}
.ui-selectcheckboxmenu .ui-selectcheckboxmenu-trigger {width:30px; padding:6px; border-radius:0 4px 4px 0;}
.ui-selectcheckboxmenu a.ui-selectcheckboxmenu-label-container {color:black; text-decoration:none !important;}
.ui-selectcheckboxmenu label.ui-selectcheckboxmenu-label, .ui-selectcheckboxmenu label.ui-selectcheckboxmenu-label.ui-state-hover {font-weight:normal; margin-bottom:0; padding:6px 40px 6px 12px;}
.ui-selectcheckboxmenu label, .ui-selectcheckboxmenu-item label {font-weight:normal; margin-bottom:0;}

/* pickList */
table.ui-picklist.ui-widget td {padding: 0 5px; vertical-align:bottom;}
table.ui-picklist div.ui-picklist-filter-container {padding-bottom:5px;}

.ui-tieredmenu.form-control {width:auto;height:auto;}

.select-scroll-block {height:auto; max-height:120px; overflow-y:scroll; padding: 6px 12px;}
.col-sm-9 > .select-scroll-block {margin: 4px 10px;}
.select-scroll-block table.ui-selectmanycheckbox label {margin-left:5px; margin-top:0; font-weight:normal;}

#contentTabs .ui-tabs .ui-tabs-panel {padding-left:0; padding-right:0;}

div.panel-heading[data-toggle="collapse"] {cursor: pointer; cursor: hand;}
div.panel-heading.text-info[data-toggle="collapse"] {color: #31708F;}

.btn-sm.ui-button {padding: 5px 10px;}

#dragdropMsg {padding:20px;font-size:1.3em;color:#808080;text-align:center;}

div.popover.fade.top.in {max-width: none;}
div.popover.fade.top.in div.popover-content {text-align:center; vertical-align: middle; display:table-cell; width:428px; height:418px;}
span.text-info.popoverHTML {display:inline-block;}

/*div[id$="filesTable"] .ui-datatable-tablewrapper thead {display:none;}*/
div[id$="versionsTable"] .ui-datatable-tablewrapper thead {display:none;}

div[id$="filesTable"].ui-datatable.ui-widget {margin-bottom:20px;}
div[id$="filesTable"].ui-datatable.ui-widget table {table-layout: fixed;}
div[id$="filesTable"].ui-datatable.ui-widget table th,
div[id$="filesTable"].ui-datatable.ui-widget table td {box-sizing: content-box;}
div[id$="filesTable"] div.ui-datatable-header.ui-widget-header {padding:0; background:none; border:0;}
div[id$="filesTable"] #filesHeaderCount {padding:10px 10px 4px 10px;}
div[id$="filesTable"] #filesHeaderCount span.highlightBold {display:block; padding:0; line-height:1.65;}
div[id$="filesTable"] td.col-file-thumb {border-right:0;}
div[id$="filesTable"] td.col-file-thumb div.thumbnail-block {position:relative;width:64px;height:64px;margin:0 auto;}
div[id$="filesTable"] td.col-file-thumb div.thumbnail-block span.file-thumbnail-icon {font-size:62px;line-height:1.05;}
div[id$="filesTable"] td.col-file-thumb div.thumbnail-block span.file-thumbnail-preview-img {display:block;}
div[id$="filesTable"] td.col-file-thumb div.thumbnail-block div.file-icon-restricted-block {display:block;position:absolute;bottom:-4px;right:-1px;}
div[id$="filesTable"] td.col-file-metadata {/*width: 33.3333% !important;*/ padding-left:0; border-left:0; border-right:0; text-align:left; font-weight:normal;}
div[id$="filesTable"] td.col-file-action {/*width:320px !important;*/ border-left:0; overflow:visible;}
div[id$="filesTable"] div.file-tags-block {padding-bottom:2px;}
div[id$="filesTable"] div.file-tags-block a.ui-commandlink {font-size:12px;}
div[id$="filesTable"] div.file-tags-block span.label {display:inline-block;}
div[id$="filesTable"] div.file-tags-block span.label, div[id$="filesTable"] div.file-tags-block a.ui-commandlink {margin-right:.5em;}
div[id$="filesTable"] div.file-tags-block span.label:last-of-type {margin-right:0;}

div[id$="filesTable"] div.ui-datatable-header.ui-widget-header {padding:0 10px;}
div[id$="filesHeaderBlock"] {margin-bottom:10px;}

div[id$="filesTable"] thead[id$="filesTable_head"] th.ui-state-default {border:0; box-shadow:none; border-radius:0; background-image:none; border-top: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;}
div[id$="filesTable"] thead[id$="filesTable_head"] th.ui-state-default:first-of-type {border-left:1px solid #e6e6e6; border-top-left-radius:4px;}
div[id$="filesTable"] thead[id$="filesTable_head"] th.ui-state-default:last-of-type {border-right: 1px solid #e6e6e6; border-top-right-radius: 4px;}
div[id$="filesTable"] thead[id$="filesTable_head"] tr {background-color: #f5f5f5; background-image: -moz-linear-gradient(center top , #ffffff, #e6e6e6); background-repeat: repeat-x;}

div[id$="filesTable"] thead[id$="filesTable_head"] th.ui-selection-column {/*width:40px !important;*/ padding:4px 10px;}
div[id$="filesTable"] thead[id$="filesTable_head"] th.ui-selection-column .ui-chkbox-box.ui-widget {margin-top:0 !important;}

div[id$="filesTable"].ui-datatable.ui-datatable-scrollable {padding-right:12px;}

span.ingest-warning {display:inline-block; font-size:30px; line-height:1.42857; vertical-align: middle;}
span.ingest-warning span.glyphicon {top:5px;}

#version-details-block > div {width:35%; padding:4px 10px; border: 1px solid #DDDDDD;}
#version-details-block > div:first-of-type {width:30%; border:0;}
#version-details-block > div:last-of-type {border-left-width:0;}

div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > thead {display:none;}
div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table, div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody {border:0;}
div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr:first-child, div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr:first-child > td {border-top-width:0;}
div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr:last-child, div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr:last-child > td {border-bottom-width:0;}
div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr, div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr > td:first-child {border-left-width:0;}
div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr, div.dvnDifferanceTable > div.ui-datatable-tablewrapper > table > tbody > tr > td:last-child {border-right-width:0;}
div.dvnDifferanceTable div.ui-datatable-tablewrapper table td.versionValue {width:30%;}
div.dvnDifferanceTable div.ui-datatable-tablewrapper table td.versionDetails {width:35%;}

div.dvnDifferanceTable .diffDetailBlock {display:block;}

.dropin-btn-status.ui-icon {background: url("https://www.dropbox.com/static/images/widgets/dbx-saver-status.png") no-repeat;}

/* MANAGE TABLE + DROPDOWN BUTTON */
div.manageTable.ui-datatable div.ui-datatable-tablewrapper, div.manageTable.ui-datatable td.col-manage-action {overflow:visible;}

/* FILE */
#file-preview-icon-block span[class^='icon-'] {font-size:4em;}

@media screen and (max-width: 999px) {
    #file-preview-icon-block span[class^='icon-'] {font-size:35vw;}
}

@media screen and (min-width: 1000px) {
    #file-preview-icon-block span[class^='icon-'] {font-size:28em;}
}

/* BLOCK UI */
.ui-blockui.ui-widget-overlay {background:#fff; opacity:.6;}
div.ui-dialog.ui-widget-content {z-index:100001 !important;}

/* POPUP DROPDOWN MENUS + TOOLTIPS + BLOCK UI */
div.ui-selectcheckboxmenu-panel, div.ui-selectonemenu-panel, div.ui-autocomplete-panel,
.ui-selectonemenu-list, .ui-selectcheckboxmenu-list, div.tooltip {z-index:100002 !important;}

/* Overwrite Primefaces */
button.btn-default.ui-button-text-only .ui-button-text {padding:0; font-size:14px;}
div.ui-widget-overlay {background:#ccc; opacity:.6;}
.ui-confirm-dialog-severity {margin-top:3px;}
.ui-widget-content a.btn-default {color:#333;}
.ui-messages-info-detail, .ui-messages-warn-detail, .ui-messages-error-detail, .ui-messages-fatal-detail, .ui-message-info-detail, .ui-message-warn-detail, .ui-message-error-detail, .ui-message-fatal-detail {
    margin-left: 0px;
}
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled {background: #e0e0e0; border-color: #ccc; opacity: 0.65;}
.ui-autocomplete-input-token input, .ui-autocomplete-input-token {width:100%;}
.ui-autocomplete-panel {z-index:100002 !important;}

/* CITATION-FRAME */
#citation-banner {width:100%; height:45px; position: absolute; z-index: 999999; border-radius: 0; border-width: 0 0 1px 0;}
#citation-banner a.close, #citation-banner a.close span.glyphicon {line-height:.2;}
#citation-forward {position: absolute; top:45px; height: calc(100% - 65px); border:0; background:url(/resources/images/ajax-loading.gif) no-repeat 50% 50%;}


text:
<?xml version="1.0"?>
<assembly>
    <id>distribution</id>
    <formats>
        <format>tar.gz</format>
        <format>zip</format>
    </formats>

    <fileSets>
        <fileSet>
            <directory>config</directory>
            <outputDirectory>config</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>target/lib</directory>
            <outputDirectory>lib</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>visualization</directory>
            <outputDirectory>visualization</outputDirectory>
        </fileSet>
    </fileSets>

    <files>
        <file>
            <source>${project.parent.basedir}/README.md</source>
            <outputDirectory></outputDirectory>
        </file>
        <file>
            <source>${project.parent.basedir}/LICENSE.txt</source>
            <outputDirectory></outputDirectory>
        </file>
        <file>
            <source>pyramid</source>
            <outputDirectory></outputDirectory>
            <filtered>true</filtered>
        </file>
        <file>
            <source>target/${project.artifactId}-${project.version}.jar</source>
            <outputDirectory>lib</outputDirectory>
        </file>
    </files>
</assembly>


text:
package nodeup

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"k8s.io/kops/nodeup/pkg/distros"
	"k8s.io/kops/nodeup/pkg/model"
	api "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/registry"
	"k8s.io/kops/pkg/apis/nodeup"
	"k8s.io/kops/pkg/assets"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/cloudinit"
	"k8s.io/kops/upup/pkg/fi/nodeup/local"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
	"k8s.io/kops/upup/pkg/fi/secrets"
	"k8s.io/kops/upup/pkg/fi/utils"
	"k8s.io/kops/util/pkg/vfs"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/klog"
)

// MaxTaskDuration is the amount of time to keep trying for; we retry for a long time - there is not really any great fallback
const MaxTaskDuration = 365 * 24 * time.Hour

// NodeUpCommand is the configuration for nodeup
type NodeUpCommand struct {
	CacheDir       string
	ConfigLocation string
	FSRoot         string
	ModelDir       vfs.Path
	Target         string
	cluster        *api.Cluster
	config         *nodeup.Config
	instanceGroup  *api.InstanceGroup
}

// Run is responsible for perform the nodeup process
func (c *NodeUpCommand) Run(out io.Writer) error {
	if c.FSRoot == "" {
		return fmt.Errorf("FSRoot is required")
	}

	if c.ConfigLocation != "" {
		config, err := vfs.Context.ReadFile(c.ConfigLocation)
		if err != nil {
			return fmt.Errorf("error loading configuration %q: %v", c.ConfigLocation, err)
		}

		err = utils.YamlUnmarshal(config, &c.config)
		if err != nil {
			return fmt.Errorf("error parsing configuration %q: %v", c.ConfigLocation, err)
		}
	} else {
		return fmt.Errorf("ConfigLocation is required")
	}

	if c.CacheDir == "" {
		return fmt.Errorf("CacheDir is required")
	}
	assetStore := fi.NewAssetStore(c.CacheDir)
	for _, asset := range c.config.Assets {
		err := assetStore.Add(asset)
		if err != nil {
			return fmt.Errorf("error adding asset %q: %v", asset, err)
		}
	}

	var configBase vfs.Path
	if fi.StringValue(c.config.ConfigBase) != "" {
		var err error
		configBase, err = vfs.Context.BuildVfsPath(*c.config.ConfigBase)
		if err != nil {
			return fmt.Errorf("cannot parse ConfigBase %q: %v", *c.config.ConfigBase, err)
		}
	} else if fi.StringValue(c.config.ClusterLocation) != "" {
		basePath := *c.config.ClusterLocation
		lastSlash := strings.LastIndex(basePath, "/")
		if lastSlash != -1 {
			basePath = basePath[0:lastSlash]
		}

		var err error
		configBase, err = vfs.Context.BuildVfsPath(basePath)
		if err != nil {
			return fmt.Errorf("cannot parse inferred ConfigBase %q: %v", basePath, err)
		}
	} else {
		return fmt.Errorf("ConfigBase is required")
	}

	c.cluster = &api.Cluster{}
	{
		clusterLocation := fi.StringValue(c.config.ClusterLocation)

		var p vfs.Path
		if clusterLocation != "" {
			var err error
			p, err = vfs.Context.BuildVfsPath(clusterLocation)
			if err != nil {
				return fmt.Errorf("error parsing ClusterLocation %q: %v", clusterLocation, err)
			}
		} else {
			p = configBase.Join(registry.PathClusterCompleted)
		}

		b, err := p.ReadFile()
		if err != nil {
			return fmt.Errorf("error loading Cluster %q: %v", p, err)
		}

		err = utils.YamlUnmarshal(b, c.cluster)
		if err != nil {
			return fmt.Errorf("error parsing Cluster %q: %v", p, err)
		}
	}

	if c.config.InstanceGroupName != "" {
		instanceGroupLocation := configBase.Join("instancegroup", c.config.InstanceGroupName)

		c.instanceGroup = &api.InstanceGroup{}
		b, err := instanceGroupLocation.ReadFile()
		if err != nil {
			return fmt.Errorf("error loading InstanceGroup %q: %v", instanceGroupLocation, err)
		}

		if err = utils.YamlUnmarshal(b, c.instanceGroup); err != nil {
			return fmt.Errorf("error parsing InstanceGroup %q: %v", instanceGroupLocation, err)
		}
	} else {
		klog.Warningf("No instance group defined in nodeup config")
	}

	err := evaluateSpec(c.cluster)
	if err != nil {
		return err
	}

	distribution, err := distros.FindDistribution(c.FSRoot)
	if err != nil {
		return fmt.Errorf("error determining OS distribution: %v", err)
	}

	osTags := distribution.BuildTags()

	nodeTags := sets.NewString()
	nodeTags.Insert(osTags...)
	nodeTags.Insert(c.config.Tags...)

	klog.Infof("Config tags: %v", c.config.Tags)
	klog.Infof("OS tags: %v", osTags)

	modelContext := &model.NodeupModelContext{
		Architecture:  model.ArchitectureAmd64,
		Assets:        assetStore,
		Cluster:       c.cluster,
		Distribution:  distribution,
		InstanceGroup: c.instanceGroup,
		NodeupConfig:  c.config,
	}

	if c.cluster.Spec.SecretStore != "" {
		klog.Infof("Building SecretStore at %q", c.cluster.Spec.SecretStore)
		p, err := vfs.Context.BuildVfsPath(c.cluster.Spec.SecretStore)
		if err != nil {
			return fmt.Errorf("error building secret store path: %v", err)
		}

		modelContext.SecretStore = secrets.NewVFSSecretStore(c.cluster, p)
	} else {
		return fmt.Errorf("SecretStore not set")
	}

	if c.cluster.Spec.KeyStore != "" {
		klog.Infof("Building KeyStore at %q", c.cluster.Spec.KeyStore)
		p, err := vfs.Context.BuildVfsPath(c.cluster.Spec.KeyStore)
		if err != nil {
			return fmt.Errorf("error building key store path: %v", err)
		}

		modelContext.KeyStore = fi.NewVFSCAStore(c.cluster, p, false)
	} else {
		return fmt.Errorf("KeyStore not set")
	}

	if err := modelContext.Init(); err != nil {
		return err
	}

	if err := loadKernelModules(modelContext); err != nil {
		return err
	}

	loader := NewLoader(c.config, c.cluster, assetStore, nodeTags)
	loader.Builders = append(loader.Builders, &model.DirectoryBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.UpdateServiceBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.VolumesBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.DockerBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.ProtokubeBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.CloudConfigBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.FileAssetsBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.HookBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.NodeAuthorizationBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.KubeletBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.KubectlBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.EtcdBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.LogrotateBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.ManifestsBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.PackagesBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.SecretBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.FirewallBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.NetworkBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.SysctlBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.KubeAPIServerBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.KubeControllerManagerBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.KubeSchedulerBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &model.EtcdManagerTLSBuilder{NodeupModelContext: modelContext})
	if c.cluster.Spec.Networking.Kuberouter == nil {
		loader.Builders = append(loader.Builders, &model.KubeProxyBuilder{NodeupModelContext: modelContext})
	} else {
		loader.Builders = append(loader.Builders, &model.KubeRouterBuilder{NodeupModelContext: modelContext})
	}
	if c.cluster.Spec.Networking.Calico != nil || c.cluster.Spec.Networking.Cilium != nil {
		loader.Builders = append(loader.Builders, &model.EtcdTLSBuilder{NodeupModelContext: modelContext})
	}

	if c.cluster.Spec.Networking.LyftVPC != nil {

		loader.TemplateFunctions["SubnetTags"] = func() (string, error) {
			tags := map[string]string{
				"Type": "pod",
			}
			if len(c.cluster.Spec.Networking.LyftVPC.SubnetTags) > 0 {
				tags = c.cluster.Spec.Networking.LyftVPC.SubnetTags
			}

			bytes, err := json.Marshal(tags)
			if err != nil {
				return "", err
			}
			return string(bytes), nil
		}

		loader.TemplateFunctions["NodeSecurityGroups"] = func() (string, error) {
			// use the same security groups as the node
			ids, err := evaluateSecurityGroups(c.cluster.Spec.NetworkID)
			if err != nil {
				return "", err
			}
			bytes, err := json.Marshal(ids)
			if err != nil {
				return "", err
			}
			return string(bytes), nil
		}
	}

	taskMap, err := loader.Build(c.ModelDir)
	if err != nil {
		return fmt.Errorf("error building loader: %v", err)
	}

	for i, image := range c.config.Images {
		taskMap["LoadImage."+strconv.Itoa(i)] = &nodetasks.LoadImageTask{
			Sources: image.Sources,
			Hash:    image.Hash,
		}
	}
	if c.config.ProtokubeImage != nil {
		taskMap["LoadImage.protokube"] = &nodetasks.LoadImageTask{
			Sources: c.config.ProtokubeImage.Sources,
			Hash:    c.config.ProtokubeImage.Hash,
		}
	}

	var cloud fi.Cloud
	var keyStore fi.Keystore
	var secretStore fi.SecretStore
	var target fi.Target
	checkExisting := true

	switch c.Target {
	case "direct":
		target = &local.LocalTarget{
			CacheDir: c.CacheDir,
			Tags:     nodeTags,
		}
	case "dryrun":
		assetBuilder := assets.NewAssetBuilder(c.cluster, "")
		target = fi.NewDryRunTarget(assetBuilder, out)
	case "cloudinit":
		checkExisting = false
		target = cloudinit.NewCloudInitTarget(out, nodeTags)
	default:
		return fmt.Errorf("unsupported target type %q", c.Target)
	}

	context, err := fi.NewContext(target, nil, cloud, keyStore, secretStore, configBase, checkExisting, taskMap)
	if err != nil {
		klog.Exitf("error building context: %v", err)
	}
	defer context.Close()

	var options fi.RunTasksOptions
	options.InitDefaults()

	err = context.RunTasks(options)
	if err != nil {
		klog.Exitf("error running tasks: %v", err)
	}

	err = target.Finish(taskMap)
	if err != nil {
		klog.Exitf("error closing target: %v", err)
	}

	return nil
}

func evaluateSpec(c *api.Cluster) error {
	var err error

	c.Spec.Kubelet.HostnameOverride, err = evaluateHostnameOverride(c.Spec.Kubelet.HostnameOverride)
	if err != nil {
		return err
	}

	c.Spec.MasterKubelet.HostnameOverride, err = evaluateHostnameOverride(c.Spec.MasterKubelet.HostnameOverride)
	if err != nil {
		return err
	}

	if c.Spec.KubeProxy != nil {
		c.Spec.KubeProxy.HostnameOverride, err = evaluateHostnameOverride(c.Spec.KubeProxy.HostnameOverride)
		if err != nil {
			return err
		}
		c.Spec.KubeProxy.BindAddress, err = evaluateBindAddress(c.Spec.KubeProxy.BindAddress)
		if err != nil {
			return err
		}
	}

	if c.Spec.Docker != nil {
		err = evaluateDockerSpecStorage(c.Spec.Docker)
		if err != nil {
			return err
		}
	}

	return nil
}

func evaluateSecurityGroups(vpcId string) ([]string, error) {
	config := aws.NewConfig()
	config = config.WithCredentialsChainVerboseErrors(true)

	s, err := session.NewSession(config)
	if err != nil {
		return nil, fmt.Errorf("error starting new AWS session: %v", err)
	}
	s.Handlers.Send.PushFront(func(r *request.Request) {
		// Log requests
		klog.V(4).Infof("AWS API Request: %s/%s", r.ClientInfo.ServiceName, r.Operation.Name)
	})

	metadata := ec2metadata.New(s, config)

	region, err := metadata.Region()
	if err != nil {
		return nil, fmt.Errorf("error querying ec2 metadata service (for az/region): %v", err)
	}

	sgNames, err := metadata.GetMetadata("security-groups")
	if err != nil {
		return nil, fmt.Errorf("error querying ec2 metadata service (for security-groups): %v", err)
	}
	svc := ec2.New(s, config.WithRegion(region))

	result, err := svc.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{
		Filters: []*ec2.Filter{
			{
				Name:   aws.String("group-name"),
				Values: aws.StringSlice(strings.Fields(sgNames)),
			},
			{
				Name:   aws.String("vpc-id"),
				Values: []*string{aws.String(vpcId)},
			},
		},
	})

	if err != nil {
		return nil, fmt.Errorf("error looking up instance security group ids: %v", err)
	}
	var sgIds []string
	for _, group := range result.SecurityGroups {
		sgIds = append(sgIds, *group.GroupId)
	}

	return sgIds, nil

}

func evaluateHostnameOverride(hostnameOverride string) (string, error) {
	if hostnameOverride == "" || hostnameOverride == "@hostname" {
		return "", nil
	}
	k := strings.TrimSpace(hostnameOverride)
	k = strings.ToLower(k)

	if k == "@aws" {
		// We recognize @aws as meaning "the local-hostname from the aws metadata service"
		vBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/local-hostname")
		if err != nil {
			return "", fmt.Errorf("error reading local hostname from AWS metadata: %v", err)
		}

		// The local-hostname gets it's hostname from the AWS DHCP Option Set, which
		// may provide multiple hostnames separated by spaces. For now just choose
		// the first one as the hostname.
		domains := strings.Fields(string(vBytes))
		if len(domains) == 0 {
			klog.Warningf("Local hostname from AWS metadata service was empty")
			return "", nil
		}

		domain := domains[0]
		klog.Infof("Using hostname from AWS metadata service: %s", domain)

		return domain, nil
	}

	if k == "@digitalocean" {
		// @digitalocean means to use the private ipv4 address of a droplet as the hostname override
		vBytes, err := vfs.Context.ReadFile("metadata://digitalocean/interfaces/private/0/ipv4/address")
		if err != nil {
			return "", fmt.Errorf("error reading droplet private IP from DigitalOcean metadata: %v", err)
		}

		hostname := string(vBytes)
		if hostname == "" {
			return "", errors.New("private IP for digitalocean droplet was empty")
		}

		return hostname, nil
	}

	return hostnameOverride, nil
}

func evaluateBindAddress(bindAddress string) (string, error) {
	if bindAddress == "" {
		return "", nil
	}
	if bindAddress == "@aws" {
		vBytes, err := vfs.Context.ReadFile("metadata://aws/meta-data/local-ipv4")
		if err != nil {
			return "", fmt.Errorf("error reading local IP from AWS metadata: %v", err)
		}

		// The local-ipv4 gets it's IP from the AWS.
		// For now just choose the first one.
		ips := strings.Fields(string(vBytes))
		if len(ips) == 0 {
			klog.Warningf("Local IP from AWS metadata service was empty")
			return "", nil
		}

		ip := ips[0]
		klog.Infof("Using IP from AWS metadata service: %s", ip)

		return ip, nil
	}

	if net.ParseIP(bindAddress) == nil {
		return "", fmt.Errorf("bindAddress is not valid IP address")
	}
	return bindAddress, nil
}

// evaluateDockerSpec selects the first supported storage mode, if it is a list
func evaluateDockerSpecStorage(spec *api.DockerConfig) error {
	storage := fi.StringValue(spec.Storage)
	if strings.Contains(fi.StringValue(spec.Storage), ",") {
		precedence := strings.Split(storage, ",")
		for _, opt := range precedence {
			fs := opt
			if fs == "overlay2" {
				fs = "overlay"
			}
			supported, err := kernelHasFilesystem(fs)
			if err != nil {
				klog.Warningf("error checking if %q filesystem is supported: %v", fs, err)
				continue
			}

			if !supported {
				// overlay -> overlay
				// aufs -> aufs
				module := fs
				if err = modprobe(fs); err != nil {
					klog.Warningf("error running `modprobe %q`: %v", module, err)
				}
			}

			supported, err = kernelHasFilesystem(fs)
			if err != nil {
				klog.Warningf("error checking if %q filesystem is supported: %v", fs, err)
				continue
			}

			if supported {
				klog.Infof("Using supported docker storage %q", opt)
				spec.Storage = fi.String(opt)
				return nil
			}

			klog.Warningf("%q docker storage was specified, but filesystem is not supported", opt)
		}

		// Just in case we don't recognize the driver?
		// TODO: Is this the best behaviour
		klog.Warningf("No storage module was supported from %q, will default to %q", storage, precedence[0])
		spec.Storage = fi.String(precedence[0])
		return nil
	}

	return nil
}

// kernelHasFilesystem checks if /proc/filesystems contains the specified filesystem
func kernelHasFilesystem(fs string) (bool, error) {
	contents, err := ioutil.ReadFile("/proc/filesystems")
	if err != nil {
		return false, fmt.Errorf("error reading /proc/filesystems: %v", err)
	}

	for _, line := range strings.Split(string(contents), "\n") {
		tokens := strings.Fields(line)
		for _, token := range tokens {
			// Technically we should skip "nodev", but it doesn't matter
			if token == fs {
				return true, nil
			}
		}
	}

	return false, nil
}

// modprobe will exec `modprobe <module>`
func modprobe(module string) error {
	klog.Infof("Doing modprobe for module %v", module)
	out, err := exec.Command("/sbin/modprobe", module).CombinedOutput()
	outString := string(out)
	if err != nil {
		return fmt.Errorf("modprobe for module %q failed (%v): %s", module, err, outString)
	}
	if outString != "" {
		klog.Infof("Output from modprobe %s:\n%s", module, outString)
	}
	return nil
}

// loadKernelModules is a hack to force br_netfilter to be loaded
// TODO: Move to tasks architecture
func loadKernelModules(context *model.NodeupModelContext) error {
	err := modprobe("br_netfilter")
	if err != nil {
		// TODO: Return error in 1.11 (too risky for 1.10)
		klog.Warningf("error loading br_netfilter module: %v", err)
	}
	// TODO: Add to /etc/modules-load.d/ ?
	return nil
}