text:
package com.ojcoleman.ahni.experiments;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.math3.util.MultidimensionalCounter;
import org.apache.log4j.Logger;
import org.jgapcustomised.Chromosome;

import com.anji_ahni.integration.Activator;
import com.ojcoleman.ahni.evaluation.BulkFitnessFunctionMT;
import com.ojcoleman.ahni.evaluation.novelty.Behaviour;
import com.ojcoleman.ahni.evaluation.novelty.RealVectorBehaviour;
import com.ojcoleman.ahni.event.AHNIEvent;
import com.ojcoleman.ahni.event.AHNIEventListener;
import com.ojcoleman.ahni.experiments.mr2d.EnvironmentDescription;
import com.ojcoleman.ahni.hyperneat.Properties;
import com.ojcoleman.ahni.nn.BainNN;
import com.ojcoleman.ahni.util.ArrayUtil;
import com.ojcoleman.ahni.util.DoubleVector;
import com.ojcoleman.ahni.util.NiceWriter;
import com.ojcoleman.ahni.util.Point;
import com.ojcoleman.ahni.util.Range;

/**
 * A fitness function that generates MDP environments to assess agents against.
 */
public class MDP extends BulkFitnessFunctionMT implements AHNIEventListener {
	private static final long serialVersionUID = 1L;
	private static Logger logger = Logger.getLogger(BulkFitnessFunctionMT.class);
	private static final NumberFormat nf = new DecimalFormat("0.00");

	/**
	 * The initial number of states in the generated environments.
	 */
	public static final String STATE_COUNT_INITIAL = "fitness.function.mdp.states.initial";
	/**
	 * The amount to increase the number of states in the generated environments when the current size has been
	 * sufficiently mastered (see {@link #DIFFICULTY_INCREASE_PERFORMANCE}. If the value is followed by an "x" then the
	 * value is considered a factor (and so should be > 1).
	 */
	public static final String STATE_COUNT_INCREASE_DELTA = "fitness.function.mdp.states.delta";
	/**
	 * The maximum amount to increase the number of states in the generated environments to.
	 */
	public static final String STATE_COUNT_MAX = "fitness.function.mdp.states.maximum";
	/**
	 * The initial number of actions available in the generated environments.
	 */
	public static final String ACTION_COUNT_INITIAL = "fitness.function.mdp.actions.initial";
	/**
	 * The amount to increase the available number of actions in the generated environments when the current size has
	 * been sufficiently mastered (see {@link #DIFFICULTY_INCREASE_PERFORMANCE}. If the value is followed by an "x" then
	 * the value is considered a factor (and so should be > 1).
	 */
	public static final String ACTION_COUNT_INCREASE_DELTA = "fitness.function.mdp.actions.delta";
	/**
	 * The maximum amount to increase the available number of actions in the generated environments to.
	 */
	public static final String ACTION_COUNT_MAX = "fitness.function.mdp.actions.maximum";
	/**
	 * The performance indicating when the environment size/difficulty should be increased as the current size has been
	 * sufficiently mastered.
	 */
	public static final String DIFFICULTY_INCREASE_PERFORMANCE = "fitness.function.mdp.difficulty.increase.performance";
	/**
	 * The proportion of actions that will map to some other state. This is evaluated probabilistically for all states
	 * and actions when generating an environment.
	 */
	public static final String ACTION_MAP_RATIO = "fitness.function.mdp.action.map.ratio";
	/**
	 * The proportion of state transitions that will yield a reward value greater than 0.
	 */
	public static final String TRANSITION_REWARD_RATIO = "fitness.function.mdp.transition.reward.ratio";
	/**
	 * The randomness of state transitions. A value of 0 will make state transitions deterministic (purely determined by
	 * the action performed), a value of 1 will make transitions completely envRandom (action performed will be
	 * ignored).
	 */
	public static final String TRANSITION_RANDOMNESS = "fitness.function.mdp.transition.randomness";
	/**
	 * The number of environments to evaluate candidates against. Increasing this will provide a more accurate
	 * evaluation but take longer.
	 */
	public static final String ENVIRONMENT_COUNT = "fitness.function.mdp.environment.count";
	/**
	 * The fraction of environments that should be replaced with new environments per generation. This is evaluated
	 * probabilistically.
	 */
	public static final String ENVIRONMENT_CHANGE_RATE = "fitness.function.mdp.environment.replacerate";
	/**
	 * The number of trials per environment. If not set or set to <= 0 then this will be set to the grid size if
	 * fitness.function.mdp.grid is true and fitness.function.mdp.single_reward_state is true, otherwise to
	 * fitness.function.mdp.environment.count if fitness.function.mdp.environment.replacerate is 0, otherwise to
	 * fitness.function.mdp.states.maximum * fitness.function.mdp.actions.maximum .
	 */
	public static final String TRIAL_COUNT = "fitness.function.mdp.trial.count";
	/**
	 * The number of steps in the environment per trial. If not set or set to <= 0 then this will be set depending on
	 * the number of trials. If the number of trials is 1 then it will be set to (actionCount * stateCount * stateCount)
	 * / trialCount, if the number of trials > 1 then it will be set to stateCount.
	 */
	public static final String STEPS_PER_TRIAL = "fitness.function.mdp.trial.steps";

	/**
	 * If true enables novelty search for which behaviours are defined by the current state for each step of each trial
	 * of each environment. Default is false.
	 */
	public static final String NOVELTY_SEARCH = "fitness.function.mdp.noveltysearch";
	/**
	 * If set to an integer > 0 then this many environments will be used to characterise an agents behaviour for novelty
	 * search. Defaults to fitness.function.mdp.environment.count.
	 */
	public static final String NOVELTY_SEARCH_ENV_COUNT = "fitness.function.mdp.noveltysearch.envs.count";
	/**
	 * If true then makes novelty search the only objective.  Performance values are still calculated.
	 * Default is false. If true then fitness.function.mdp.noveltysearch is also forced to true.
	 */
	public static final String NOVELTY_SEARCH_ONLY = "fitness.function.mdp.noveltysearch.only";

	/**
	 * Seed to use to generate and simulate environments.
	 */
	public static final String ENV_RANDOM_SEED = "fitness.function.mdp.environment.randomseed";

	/**
	 * Whether to include the previously performed action in the input to the agent. Default is false.
	 */
	public static final String INPUT_INCLUDE_PREVIOUS_ACTION = "fitness.function.mdp.input.include.previous.action";
	/**
	 * Whether to include the previous state in the input to the agent. Default is false.
	 */
	public static final String INPUT_INCLUDE_PREVIOUS_STATE = "fitness.function.mdp.input.include.previous.state";
	/**
	 * Whether to include an input that indicates whether the agent should be exploring to learn about the environment
	 * or exploiting the knowledge its learnt. Default is false.
	 */
	public static final String INPUT_INCLUDE_EXPL = "fitness.function.mdp.input.include.expl";

	/**
	 * Whether to generate environments where the states are organised in a grid. The number of states is forced to
	 * (ceil(sqrt(state_count)))^2. The number of actions is forced to 4 and each action will move the agent to a
	 * neighbouring state. The input to the agent is the row and column index of the current state (1-of-N encoding for
	 * each). The environments are forced to be deterministic (no transition randomness). The grid wraps around (is a
	 * toroidal grid). Default is false.
	 */
	public static final String GRID_ENVIRONMENT = "fitness.function.mdp.grid";

	/**
	 * Whether to make the grid toroidal (wrap around at edges). Default is false.
	 */
	public static final String GRID_ENVIRONMENT_WRAP = "fitness.function.mdp.grid.wrap";

	/**
	 * Whether there should be a single state which when reached yields a reward value of 1 (rather than any transition
	 * to any state yielding a randomly generated reward value according to
	 * fitness.function.mdp.transition.reward.ratio.
	 */
	public static final String SINGLE_REWARD_STATE = "fitness.function.mdp.single_reward_state";

	private int environmentCount;
	private double environmentReplaceProb;
	int trialCount;
	private int stateCount;
	private int actionCount;
	int stateCountMax;
	private int actionCountMax;
	private double transitionRandomness;
	private double mapRatio;
	private double transitionRewardRatio;
	private int stepsForReward;
	ArrayList<Environment> environments;
	ArrayList<Environment> nsEnvironments;
	private ArrayList<Environment> genEnvironments;
	private int environmentCounter = 0;
	private int environmentMasteredTrialCount = 3;
	private int stepsPerTrial;
	private boolean noveltySearchEnabled = false;
	private boolean noveltySearchOnly = false;
	private long envRandomSeed;
	private Random envRandom;
	private boolean includePrevAction;
	private boolean includePrevState;
	private boolean includeExpl;
	private boolean gridEnvs, gridWrap;
	private int gridSize, gridSizeMax; // Only if gridEnvs == true;
	private boolean singleRewardState;

	// Indexes into agent input array.
	private int currentStateIndex = 0;
	private int previousStateIndex = -1;
	private int previousActionIndex = -1;
	private int explIndex = -1;
	private int rewardIndex = -1;

	@Override
	public void init(Properties props) {
		this.props = props;

		environmentCount = props.getIntProperty(ENVIRONMENT_COUNT);
		environmentReplaceProb = props.getDoubleProperty(ENVIRONMENT_CHANGE_RATE);
		actionCount = props.getIntProperty(ACTION_COUNT_INITIAL);
		stateCount = props.getIntProperty(STATE_COUNT_INITIAL);
		actionCountMax = props.getIntProperty(ACTION_COUNT_MAX);
		stateCountMax = props.getIntProperty(STATE_COUNT_MAX);
		trialCount = props.getIntProperty(TRIAL_COUNT, 0);

		singleRewardState = props.getBooleanProperty(SINGLE_REWARD_STATE, false);
		gridEnvs = props.getBooleanProperty(GRID_ENVIRONMENT, false);
		gridWrap = props.getBooleanProperty(GRID_ENVIRONMENT_WRAP, false);
		adustStateCountForEnvType();

		transitionRandomness = props.getDoubleProperty(TRANSITION_RANDOMNESS);
		Range.checkUnitRange(transitionRandomness, TRANSITION_RANDOMNESS);
		mapRatio = props.getDoubleProperty(ACTION_MAP_RATIO);
		Range.checkUnitRange(mapRatio, ACTION_MAP_RATIO, false, true);
		transitionRewardRatio = props.getDoubleProperty(TRANSITION_REWARD_RATIO);
		Range.checkUnitRange(transitionRewardRatio, TRANSITION_REWARD_RATIO, false, true);

		determineStepsPerTrial();

		envRandomSeed = props.getLongProperty(ENV_RANDOM_SEED, System.currentTimeMillis());
		logger.info("MDP random seed is " + envRandomSeed);
		envRandom = new Random(envRandomSeed);

		includePrevAction = props.getBooleanProperty(INPUT_INCLUDE_PREVIOUS_ACTION, false);
		includePrevState = props.getBooleanProperty(INPUT_INCLUDE_PREVIOUS_STATE, false);
		includeExpl = props.getBooleanProperty(INPUT_INCLUDE_EXPL, false);

		if (gridEnvs) {
			if (actionCount != 4 || actionCountMax != 4) {
				actionCount = 4;
				actionCountMax = 4;
				logger.warn("MDP: forcing initial and maximum action counts to 4 for grid environment.");
			}
			if (mapRatio != 1) {
				mapRatio = 1;
				logger.warn("MDP: forcing fitness.function.mdp.action.map.ratio to 1 for grid environment.");
			}
		}

		environments = new ArrayList<Environment>();
		for (int e = 0; e < environmentCount; e++) {
			Environment newEnv = new Environment();
			if (newEnv.setUp(environmentCounter, environments)) {
				environments.add(newEnv);
				environmentCounter++;
			}
		}
		if (environments.size() != environmentCount) {
			environmentCount = environments.size();
			logger.warn("Could not generate specified number of MDP environments, number of environments set to " + environmentCount);
		}

		noveltySearchOnly = props.getBooleanProperty(NOVELTY_SEARCH_ONLY, false);
		noveltySearchEnabled = noveltySearchOnly || props.getBooleanProperty(NOVELTY_SEARCH, false);
		if (noveltySearchEnabled) {
			int nsEnvCount = props.getIntProperty(NOVELTY_SEARCH_ENV_COUNT, 0);

			// If the same environments aren't used throughout evolution.
			if (environmentReplaceProb > 0 || nsEnvCount > 0) {
				if (nsEnvCount <= 0)
					nsEnvCount = environmentCount;
				// Create a set of environments that don't change over the course of evolution to test novelty on.
				nsEnvironments = new ArrayList<Environment>();
				for (int e = 0; e < nsEnvCount; e++) {
					Environment newEnv = new Environment();
					// If possible, generate environments of varying difficulty.
					// for (int i = 1; i < e && nsEnvironments[e].increaseDifficultyPossible(); i++) {
					// nsEnvironments[e].increaseDifficulty();
					// }
					if (newEnv.setUp(nsEnvironments.size(), nsEnvironments)) {
						nsEnvironments.add(newEnv);
					}
				}
				if (nsEnvironments.size() != nsEnvCount) {
					nsEnvCount = nsEnvironments.size();
					logger.warn("Could not generate specified number of MDP environments for novelty search, number of environments for novelty search set to " + nsEnvCount);
				}
				logger.info("Created " + nsEnvCount + " environments for novelty search.");
			}

			if (nsEnvCount == 0) nsEnvCount = environments.size();

			logger.info("Novelty search behaviours have dimensionality " + (nsEnvCount * trialCount * stepsPerTrial));
		}

		if (trialCount <= 0) {
			if (gridEnvs && singleRewardState)
				trialCount = gridSize;
			else if (environmentReplaceProb == 0)
				trialCount = environmentCount;
			else
				trialCount = actionCountMax * stateCountMax;
			logger.info("MDP trial count set to " + trialCount);
		}

		((Properties) props).getEvolver().addEventListener(this);

		super.init(props);
	}

	private void determineStepsPerTrial() {
		stepsPerTrial = props.getIntProperty(STEPS_PER_TRIAL, 0);
		if (stepsPerTrial <= 0) {
			if (gridEnvs && singleRewardState) {
				// Enough steps to reach any state in the grid (Manhattan distance).
				stepsPerTrial = 2 * gridSizeMax - 1;
			} else if (!gridEnvs && singleRewardState) {
				// Enough steps to reach any state.
				stepsPerTrial = stateCountMax - 1;
			} else if (environmentReplaceProb > 0) {
				if (trialCount == 1) {
					// Enough steps to try every action in every state at least once then exploit the info gained.
					// The last term should be same as stepsForReward below for single trial.
					stepsPerTrial = actionCount * stateCount * stateCount + stateCount * 2;
				} else {
					// Enough steps to try every action in every state at least once then exploit the info gained.
					stepsPerTrial = (actionCount * stateCount * stateCount) / (trialCount - 1);
				}
			} else {
				// Somewhat arbitrary, probably always want it to be >= stateCount
				stepsPerTrial = stateCount*actionCount*3;
			}
			logger.info("MDP steps per trial set to " + stepsPerTrial);
		}

		// If trialCount > 1 then the reward received during the entire last trial will be used.
		stepsForReward = trialCount == 1 ? stateCount * 2 : stepsPerTrial;
		logger.info("MDP number of final steps contributing to fitness set to " + stepsForReward);
	}

	/**
	 * Make sure stateCount meets requirements of environment type (eg grid environments).
	 */
	private void adustStateCountForEnvType() {
		if (gridEnvs) {
			int initStateCount = stateCount;
			gridSize = (int) Math.ceil(Math.sqrt(stateCount));
			stateCount = gridSize * gridSize;
			if (stateCount != initStateCount) {
				logger.warn("MDP: forcing state count to " + stateCount + " for grid environment.");
			}

			initStateCount = stateCountMax;
			gridSizeMax = (int) Math.ceil(Math.sqrt(stateCountMax));
			stateCountMax = gridSizeMax * gridSizeMax;
			if (stateCountMax != initStateCount) {
				logger.warn("MDP: forcing maximum state count to " + stateCountMax + " for grid environment.");
			}
		}
	}

	@Override
	public void initialiseEvaluation() {
		// Create (some) new environments every generation.
		for (int i = 0; i < environments.size(); i++) {
			if (environmentReplaceProb > envRandom.nextDouble()) {
				Environment newEnv = new Environment();
				if (newEnv.setUp(environmentCounter++, environments)) {
					environments.set(i, newEnv);
				} else {
					logger.warn("Could not replace existing MDP environment with a newly generated one.");
				}
			}
		}
	}

	@Override
	protected void evaluate(Chromosome genotype, Activator substrate, int evalThreadIndex, double[] fitnessValues, Behaviour[] behaviours) {
		if (nsEnvironments == null) {
			// Evaluate fitness and behaviour on same environments.
			_evaluate(genotype, substrate, null, false, false, fitnessValues, behaviours, environments);
		} else {
			// Evaluate fitness on changing environments and behaviour on fixed novelty search environments.
			_evaluate(genotype, substrate, null, false, false, fitnessValues, null, environments);
			_evaluate(genotype, substrate, null, false, false, null, behaviours, nsEnvironments);
		}
	}

	@Override
	public void evaluate(Chromosome genotype, Activator substrate, String baseFileName, boolean logText, boolean logImage) {
		_evaluate(genotype, substrate, baseFileName, logText, logImage, null, null, environments);
	}

	public void _evaluate(Chromosome genotype, Activator substrate, String baseFileName, boolean logText, boolean logImage, double[] fitnessValues, Behaviour[] behaviours, ArrayList<Environment> environments) {
		super.evaluate(genotype, substrate, baseFileName, logText, logImage);
		int environmentCount = environments.size();
		double randomCompare = 0;
		int solvedCount = 0;
		// Random testRandom = new Random(System.currentTimeMillis());

		int[][][] behaviour = behaviours != null && behaviours.length > 0 ? new int[environments.size()][trialCount][environments.get(0).getStepsPerTrial()] : null;

		int imageScale = 128;

		try {
			NiceWriter logOutput = !logText ? null : new NiceWriter(new FileWriter(baseFileName + ".txt"), "0.00");

			double[] input = new double[substrate.getInputDimension()[0]];
			double[] avgRewardForEachTrial = new double[trialCount];
			for (Environment env : environments) {

				if (logText) {
					logOutput.put("\n\nBEGIN EVALUATION ON ENVIRONMENT " + env.id + "\n");
					logOutput.put(env).put("\n");
				}

				// Reset substrate to initial state to begin learning new environment.
				substrate.reset();

				double trialReward = 0;
				int consecutivePerfectTrialCount = 0;
				for (int trial = 0; trial < trialCount; trial++) {
					// Create an RNG instance that is the same for a given trial in a given environment so that the
					// environment behaviour is exactly the same for each agent and across runs if necessary.
					Random envTrialRandom = new Random((envRandomSeed + env.id * trialCount + trial) * 10);
					if (logText) {
						logOutput.put("\n  BEGIN TRIAL " + (trial + 1) + " of " + trialCount + "\n");
					}

					BufferedImage image = null;
					Graphics2D g = null;
					if (logImage && gridEnvs) {
						image = new BufferedImage(gridSize * imageScale, gridSize * imageScale, BufferedImage.TYPE_3BYTE_BGR);
						g = image.createGraphics();
						g.setColor(Color.WHITE);
						g.fillRect(0, 0, gridSize * imageScale, gridSize * imageScale);
						if (singleRewardState) {
							State rewardState = env.getRewardState();
							g.setColor(Color.GREEN);
							g.fillRect(rewardState.x * imageScale, rewardState.y * imageScale, imageScale, imageScale);
						}
					}

					State currentState = env.states[0];
					Transition transition = null;
					trialReward = 0;
					double[] output = null;
					double[] previousOutput = new double[substrate.getOutputDimension()[0]];
					int prevAction = -1;
					State prevState = null;
					boolean rewardCountsTowardFitness = false;

					// The network can perform a number of steps equal to the number of states times two.
					int step = 0;

					for (step = 0; step < env.getStepsPerTrial(); step++) {
						// If we're doing multiple trials then count reward for last trial,
						// or if we're doing a single long trial then only include reward for last half,
						// or if there's a single reward state then include reward as we'll exit if the agent found
						// the reward state.
						rewardCountsTowardFitness = (trialCount > 1 && trial == trialCount - 1) || (trialCount == 1 && step >= stepsPerTrial - stepsForReward);

						// Set up the inputs to the network.
						Arrays.fill(input, 0);
						input[currentStateIndex + currentState.id] = 1;
						if (includePrevState && prevState != null) {
							input[previousStateIndex + prevState.id] = 1;
						}
						prevState = currentState;
						if (includePrevAction && prevAction >= 0) {
							input[previousActionIndex + prevAction] = 1;
						}
						if (includeExpl && rewardCountsTowardFitness) {
							input[explIndex] = 1;
						}
						if (transition != null) {
							// Set reward signal from previous transition.
							input[rewardIndex] = transition.reward;
						}

						// Ask the network what it wants to do next, and let it know the reward for the previous state
						// transition.
						output = substrate.next(input);
						// The action to perform is the one corresponding to the output with the highest output value.
						int action = ArrayUtil.getMaxIndex(output);
						prevAction = action;
						// int action = testRandom.nextInt(actionCount);

						if (logText) {
							boolean outputChanged = step > 0 && !ArrayUtils.isEquals(output, previousOutput);
							logOutput.put("    Agent is at " + currentState.id + "\n");

							String inputStr = "    Input: CS=";
							int inputIdx = 0;
							for (; inputIdx < stateCount; inputIdx++)
								inputStr += (int) input[inputIdx];
							if (includePrevState) {
								inputStr += "  PS=";
								int endIdx = inputIdx + stateCount;
								for (; inputIdx < endIdx; inputIdx++)
									inputStr += (int) input[inputIdx];
							}
							if (includePrevAction) {
								inputStr += "  PA=";
								int endIdx = inputIdx + actionCount;
								for (; inputIdx < endIdx; inputIdx++)
									inputStr += (int) input[inputIdx];
							}
							if (includeExpl) {
								inputStr += "  Ex=";
								inputStr += (int) input[inputIdx++];
							}
							inputStr += "  R=";
							inputStr += input[inputIdx++];
							logOutput.put(inputStr + "  (" + ArrayUtil.toString(input, ", ", nf) + ")\n");

							//logOutput.put("    Input: " + ArrayUtil.toString(input, ", ", nf) + "\n");

							logOutput.put("    Output: " + ArrayUtil.toString(output, ", ", nf) + (outputChanged ? " [changed]" : "") + " (Action: " + action + ")\n");
							logOutput.put("    Current reward: " + nf.format(trialReward) + "\n\n");
							System.arraycopy(output, 0, previousOutput, 0, output.length);
						}
						if (logImage && gridEnvs) {
							float c = ((float) step / env.getStepsPerTrial()) * 0.75f;
							int size = ((env.getStepsPerTrial() - step) * (imageScale / 2)) / env.getStepsPerTrial() + imageScale / 2 - 2;
							int offset = (imageScale - size) / 2;
							g.setColor(new Color(0, c, c));
							g.fillOval(currentState.x * imageScale + offset, currentState.y * imageScale + offset, size, size);
						}

						// If a transition is defined for the current state and specified action.
						transition = currentState.getNextTransition(action, envTrialRandom);
						if (transition != null) {
							currentState = transition.nextState;
							// Add reward to record if reward counts toward fitness,
							// or if there's a single reward state then include reward as we'll exit if the agent found
							// the reward state.
							if (rewardCountsTowardFitness || singleRewardState) {
								trialReward += transition.reward;
							}
						}

						if (behaviour != null) {
							behaviour[env.id][trial][step] = currentState.id;
						}

						if (singleRewardState && currentState.id == env.rewardState) {
							break;
						}

						// If the maximum reward has been reached, end the trial.
						// if (trialReward > env.getMaxReward() * 0.99) {
						// break;
						// }
					}

					if (logText) {
						logOutput.put("    Agent is at " + currentState.id + "\n");
						logOutput.put("    Current reward: " + nf.format(trialReward) + "\n\n");
					}

					if (logImage && gridEnvs) {
						float c = ((float) step / env.getStepsPerTrial());
						int size = ((env.getStepsPerTrial() - step) * (imageScale / 2)) / env.getStepsPerTrial() + imageScale / 2 - 2;
						int offset = (imageScale - size) / 2;
						g.setColor(new Color(0, c, c));
						g.fillOval(currentState.x * imageScale + offset, currentState.y * imageScale + offset, size, size);

						File outputfile = new File(baseFileName + ".env_ " + env.id + ".trial_" + trial + ".png");
						ImageIO.write(image, "png", outputfile);
					}

					// If last trial
					if (trial == trialCount - 1) {
						// Ratio of reward received versus reward received by random agent.
						randomCompare += trialReward / env.getRandomReward();
					}

					avgRewardForEachTrial[trial] += trialReward / env.getMaxReward();

					// If environmentMasteredTrialCount perfect trials have been executed then we can probably assume
					// this environment has been mastered [this won't work until we use Q-learning or similar to
					// determine optimal reward.]
					// if (trialReward > 0.99) {
					// consecutivePerfectTrialCount++;
					// if (consecutivePerfectTrialCount == environmentMasteredTrialCount) {
					// solvedCount++;
					// // Fill in reward values for trials we're skipping.
					// for (int t = trial+1; t < trialCount; t++) {
					// avgRewardForEachTrial[t] += trialReward;
					// envReward += trialReward;
					// perf += trialReward / env.getRandomReward();
					// }
					// if (logText) {
					// logOutput.put("  ENVIRONMENT MASTERED.\n\n");
					// }
					// break; // breaks out of: for (int trial = 0; trial < trialCount; trial++)
					// }
					// } else {
					// consecutivePerfectTrialCount = 0;
					// }
				}

				// If the agent got 99% of the maximum reward last trial
				if (trialReward / env.getMaxReward() > 0.99) {
					solvedCount++;
				}
			}

			randomCompare /= environmentCount;
			for (int trial = 0; trial < trialCount; trial++) {
				avgRewardForEachTrial[trial] /= environmentCount;
			}
			if (logText) {
				logOutput.put("\n\nReward for each trial averaged over all environments:\n");
				logOutput.put(Arrays.toString(avgRewardForEachTrial));
				logOutput.close();
			}

			double fitness = 0;
			if (getEnvOptimalRewardCalcType().equals(EnvOptimalRewardCalcType.NOT_SUPPORTED)) {
				// Use comparison to random agent if optimal reward not available for comparison.
				// Fitness is 10% of ratio of reward received versus reward received by random agent.
				fitness = randomCompare > 10 ? 1 : randomCompare * 0.1 * 0.99;
			} else {
				// Average of final trial from each environment.
				fitness = avgRewardForEachTrial[trialCount - 1] * 0.1;
				genotype.setPerformanceValue("1VSOptimal", fitness);
			}
			if (fitness == 0)
				fitness = Double.MIN_VALUE;

			if (fitnessValues != null && fitnessValues.length > 0)
				fitnessValues[0] = fitness;

			genotype.setPerformanceValue("0VSRandom", randomCompare > 10 ? 1 : randomCompare * 0.1 * 0.99);
			genotype.setPerformanceValue("2Solved", (double) solvedCount / environmentCount);

			if (behaviours != null && behaviours.length > 0) {
				behaviours[0] = new MDPBehaviour(this, behaviour);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean evaluateGeneralisation(Chromosome genotype, Activator substrate, String baseFileName, boolean logText, boolean logImage, double[] fitnessValues) {
		if (props.getEvolver().getGeneration() > 0) {
			if (genEnvironments == null) {
				// Test on twice as many environments as used for fitness evaluations.
				genEnvironments = new ArrayList<Environment>();
				for (int i = 0; i < environmentCount*2; i++) {
					Environment newEnv = new Environment();
					if (newEnv.setUp(genEnvironments.size(), genEnvironments)) {
						genEnvironments.add(newEnv);
					}
				}
			}
			_evaluate(genotype, substrate, baseFileName, logText, logImage, fitnessValues, null, genEnvironments);
			return true;
		}
		return false;
	}

	private boolean increaseDifficulty() {
		boolean increasedDifficulty = false;
		if (stateCount < props.getIntProperty(STATE_COUNT_MAX)) {
			String deltaString = props.getProperty(STATE_COUNT_INCREASE_DELTA).trim().toLowerCase();
			boolean isFactor = deltaString.endsWith("x");
			double delta = Double.parseDouble(deltaString.replaceAll("x", ""));
			if (delta >= 1) {
				int initStateCount = stateCount;
				if (!isFactor) {
					stateCount += (int) Math.round(delta);
				} else if (delta > 1) {
					stateCount = Math.max(1, (int) Math.round(stateCount * delta));
				}

				adustStateCountForEnvType();
				increasedDifficulty = initStateCount != stateCount;

				if (increasedDifficulty) {
					determineStepsPerTrial();
				}
			}
		}

		if (actionCount < props.getIntProperty(ACTION_COUNT_MAX)) {
			String deltaString = props.getProperty(ACTION_COUNT_INCREASE_DELTA).trim().toLowerCase();
			boolean isFactor = deltaString.endsWith("x");
			double delta = Double.parseDouble(deltaString.replaceAll("x", ""));
			if (delta >= 1) {
				if (!isFactor) {
					actionCount += (int) Math.round(delta);
					increasedDifficulty = true;
				} else if (delta > 1) {
					actionCount = Math.max(1, (int) Math.round(actionCount * delta));
					increasedDifficulty = true;
				}
			}
		}

		if (increasedDifficulty) {
			reportedEnvOptimalRewardCalcType = null;
		}

		return increasedDifficulty;
	}

	@Override
	public int noveltyObjectiveCount() {
		return noveltySearchEnabled ? 1 : 0;
	}

	@Override
	public int fitnessObjectivesCount() {
		return noveltySearchOnly ? 0 : 1;
	}

	@Override
	public String[] objectiveLabels() {
		String[] labels = new String[fitnessObjectivesCount() + noveltyObjectiveCount()];
		int i = 0;
		if (!noveltySearchOnly) labels[i++] = "Fitness";
		if (noveltySearchEnabled) labels[i++] = "Novelty";
		return labels;
	}

	@Override
	public boolean fitnessValuesStable() {
		return false; // environmentReplaceProb == 0;
	}

	// The method to use to determine the (approx) optimal reward per step in an environment.
	enum EnvOptimalRewardCalcType {
		NOT_SUPPORTED, APPROXIMATE, EXACT
	}

	static EnvOptimalRewardCalcType reportedEnvOptimalRewardCalcType;

	private synchronized EnvOptimalRewardCalcType getEnvOptimalRewardCalcType() {
		if (reportedEnvOptimalRewardCalcType == null) {
			if (transitionRandomness > 0) {
				reportedEnvOptimalRewardCalcType = EnvOptimalRewardCalcType.NOT_SUPPORTED;
				logger.info("Calculating optimal reward for non-deterministic environments not currently supported.");
			} else {
				// If it looks like we can calculate an exact optimal value (no more than a million steps to try).
				if (Math.pow(actionCount, stepsPerTrial + 1) <= 1024 * 1024) {
					reportedEnvOptimalRewardCalcType = EnvOptimalRewardCalcType.EXACT;
					logger.info("Calculating exact optimal reward for environments.");
				} else {
					reportedEnvOptimalRewardCalcType = EnvOptimalRewardCalcType.APPROXIMATE;
					logger.info("Calculating approximate optimal reward for environments.");
				}
			}
		}
		return reportedEnvOptimalRewardCalcType;
	}

	class Environment {
		static final double MIN_REWARD = 0.0;
		static final int MAX_SETUP_RETRIES = 100;

		public int id;
		private double maxReward, randomReward;
		private State[] states;
		private int[] optimalStateSequence;
		private int[] optimalActionSequence;
		private int rewardState = -1; // Only used if singleRewardState == true.
		private int envStateCount;
		private int envActionCount;
		private int envStepsPerTrial;
		private int envStepsForReward;

		public int getStateCount() {
			return envStateCount;
		}

		public int getActionCount() {
			return envActionCount;
		}

		public int getStepsPerTrial() {
			return envStepsPerTrial;
		}

		public int getStepsForReward() {
			return envStepsForReward;
		}

		private boolean setUp(int id, ArrayList<Environment> otherEnvs) {
			this.id = id;
			envStateCount = stateCount;
			envActionCount = actionCount;
			envStepsPerTrial = stepsPerTrial;
			envStepsForReward = stepsForReward;

			// Create an RNG instance that is the same given the same seed and environment ID,
			// so we can reproduce the same environments in different runs.
			Random envSetupRandom = new Random(id * 1000 + envRandomSeed);

			// Only used if singleRewardState == true.
			if (singleRewardState) {
				rewardState = envSetupRandom.nextInt(envStateCount);
			}

			double overallPrimaryNextStateProb = 1 - transitionRandomness + transitionRandomness * (1.0 / envActionCount);
			double primaryNextStateProbVariance = 1 - overallPrimaryNextStateProb;

			boolean atLeastOneNonZeroReward = false;
			int retries = 0;
			do {
				if (gridEnvs) {
					// Create environment where states organised in a grid with transitions only to neighbouring states.

					// Create states.
					states = new State[envStateCount];
					State[][] stateGrid = new State[gridSize][gridSize];
					for (int x = 0, s = 0; x < gridSize; x++) {
						for (int y = 0; y < gridSize; y++, s++) {
							states[s] = new State(s, x, y);
							stateGrid[x][y] = states[s];
						}
					}
					// Create transitions.
					for (int x = 0; x < gridSize; x++) {
						for (int y = 0; y < gridSize; y++) {
							// If there's a single reward state, and this is it, don't add transitions away from it.
							if (stateGrid[x][y].id != rewardState) {
								for (int actionID = 0; actionID < 4; actionID++) {
									Action action = new Action(actionID);

									int xt = x + (actionID == 0 ? -1 : (actionID == 2 ? 1 : 0));
									int yt = y + (actionID == 1 ? -1 : (actionID == 3 ? 1 : 0));

									// If we're not wrapping and action would lead to out of bounds.
									if (!gridWrap && (xt < 0 || xt >= gridSize))
										continue;
									if (!gridWrap && (yt < 0 || yt >= gridSize))
										continue;

									if (xt < 0)
										xt += gridSize;
									else if (xt >= gridSize)
										xt -= gridSize;

									if (yt < 0)
										yt += gridSize;
									else if (yt >= gridSize)
										yt -= gridSize;

									State nextState = stateGrid[xt][yt];

									double reward = rewardForTransition(nextState, envSetupRandom);
									atLeastOneNonZeroReward |= reward > MIN_REWARD;

									Transition tran = new Transition(1, nextState, reward);
									action.addTransition(tran);
									stateGrid[x][y].addAction(action);
								}
							}
						}
					}
				} else {
					// Create completely random environment.
					// Create states.
					states = new State[envStateCount];
					for (int s = 0; s < envStateCount; s++) {
						states[s] = new State(s);
					}

					atLeastOneNonZeroReward = false;
					for (int stateID = 0; stateID < envStateCount; stateID++) {
						for (int actionID = 0; actionID < envActionCount; actionID++) {
							// If a mapping should be created for this action.
							if (mapRatio > envSetupRandom.nextDouble()) {
								Action action = new Action(actionID);

								double primaryNextStateProb = overallPrimaryNextStateProb + (2 * primaryNextStateProbVariance * envSetupRandom.nextDouble() - primaryNextStateProbVariance);
								int primaryNextState = envSetupRandom.nextInt(envStateCount);
								while (primaryNextState == stateID)
									primaryNextState = envSetupRandom.nextInt(envStateCount);

								double reward = rewardForTransition(states[primaryNextState], envSetupRandom);
								atLeastOneNonZeroReward |= reward > MIN_REWARD;

								Transition tran = new Transition(primaryNextStateProb, states[primaryNextState], reward);
								action.addTransition(tran);

								if (transitionRandomness > 0) {
									// Actions map probabilistically to (any possible) next state.
									// Generate list of probabilities for transitions to non-primary state;
									double[] tranProb = new double[envStateCount];
									do {
										for (int nextStateID = 0; nextStateID < envStateCount; nextStateID++) {
											if (nextStateID != primaryNextState && transitionRandomness > envSetupRandom.nextDouble()) {
												tranProb[nextStateID] = envSetupRandom.nextDouble();
											}
										}
									} while (ArrayUtil.sum(tranProb) == 0);
									ArrayUtil.normaliseSum(tranProb);
									ArrayUtil.multiply(tranProb, 1 - primaryNextStateProb);

									for (int nextStateID = 0; nextStateID < envStateCount; nextStateID++) {
										if (nextStateID != primaryNextState) {
											reward = rewardForTransition(states[nextStateID], envSetupRandom);
											atLeastOneNonZeroReward |= reward > MIN_REWARD;

											tran = new Transition(tranProb[nextStateID], states[nextStateID], reward);
											action.addTransition(tran);
										}
									}
								}

								states[stateID].addAction(action);
							}
						}
					}
				}

				// System.err.println(toString());
				//
				// for (int stateID = 0; stateID < stateCount; stateID++) {
				// System.err.println(stateID);
				// for (int actionID = 0; actionID < actionCount; actionID++) {
				// System.err.println("\t" + actionID);
				// int[] counts = new int[stateCount];
				// for (int i = 0; i < 1000; i++) {
				// counts[states[stateID].getNextState(actionID, envRandom).id]++;
				// }
				// for (int nextStateID = 0; nextStateID < stateCount; nextStateID++) {
				// System.err.println("\t\t" + counts[nextStateID]);
				// }
				// }
				// }

				if (retries > MAX_SETUP_RETRIES) {
					break;
				}
				retries++;
			} while (!atLeastOneNonZeroReward || !allStatesReachableFromAnyState() || equivalentEnvironmentExists(otherEnvs));

			if (retries > MAX_SETUP_RETRIES) {
				return false;
			}

			// } while (!atLeastOneNonZeroReward);

			// TODO: ensure non-zero reward can be received when starting from first state using a TD-learning method.
			// (and use the best policy found to determine the maximum reward value so we can accurately measure
			// performance).

			// For now set max reward to theoretical upper bound. Reward values are in range (0, 1).
			// If we're doing a single long trial then only reward from the last half of it is included.

			// maxReward = stepsForReward;

			//if (getEnvOptimalRewardCalcType().equals(EnvOptimalRewardCalcType.NOT_SUPPORTED)) {
				// Determine reward received by a random agent, for comparison.
				randomReward = calcRandomReward(envSetupRandom);
				randomReward *= envStepsForReward;
			//} else {
				maxReward = calcOptimalReward();
				if (!singleRewardState) {
					maxReward *= envStepsForReward;
				}
			//}

			return true;
		}

		private boolean equivalentEnvironmentExists(ArrayList<Environment> otherEnvs) {
			for (Environment other : otherEnvs) {
				if (this.isEquivalent(other))
					return true;
			}
			return false;
		}

		/**
		 * Returns true iff the given environment is equal to this environment.
		 */
		public boolean isEquivalent(Environment e) {
			if (envStateCount != e.envStateCount || envActionCount != e.envActionCount || envStepsPerTrial != e.envStepsPerTrial)
				return false;

			for (int stateID = 0; stateID < envStateCount; stateID++) {
				if (!states[stateID].isEquivalent(e.states[stateID]))
					return false;
			}
			return true;
		}

		public State getRewardState() {
			if (rewardState != -1) {
				return states[rewardState];
			}
			return null;
		}

		private double rewardForTransition(State nextState, Random envSetupRandom) {
			if (singleRewardState) {
				if (nextState.id == rewardState) {
					return 1;
				}
			} else {
				// return (transitionRewardRatio > envSetupRandom.nextDouble()) ? envSetupRandom.nextDouble() :
				// MIN_REWARD;
				return (transitionRewardRatio > envSetupRandom.nextDouble()) ? envSetupRandom.nextInt(2) : MIN_REWARD;
			}
			return MIN_REWARD;
		}

		// Make sure all states are reachable and that there are no dead ends.
		private boolean allStatesReachableFromAnyState() {
			if (gridEnvs) {
				return true;
			}

			HashSet<Integer> toExplore = new HashSet<Integer>();
			HashSet<Integer> nextToExplore = new HashSet<Integer>();

			for (int si = 0; si < envStateCount; si++) {
				boolean[] covered = new boolean[envStateCount];
				toExplore.clear();
				nextToExplore.clear();

				toExplore.add(si);
				covered[si] = true;
				int coveredCount = 1;

				while (!toExplore.isEmpty()) {
					for (Integer s : toExplore) {
						for (Action a : states[s].getActions()) {
							for (Transition t : a.getTransitions()) {
								if (!covered[t.nextState.id]) {
									nextToExplore.add(t.nextState.id);
									covered[t.nextState.id] = true;
									coveredCount++;
								}
							}
						}
					}

					HashSet<Integer> t = toExplore;
					toExplore = nextToExplore;
					nextToExplore = t;
					nextToExplore.clear();
				}

				if (coveredCount != envStateCount)
					return false;
			}
			return true;
		}

		// Determine reward received by a random agent, for comparison.
		// Returns a value in range (0, 1), representing average reward for a single step.
		private double calcRandomReward(Random random) {
			// Determine reward received by a random agent, for comparison.
			double randomReward = 0;
			State currentState = states[0];
			for (int step = 0; step < 1000; step++) {
				int action = random.nextInt(envActionCount);

				// If a transition is defined for the current state and specified action.
				Transition transition = currentState.getNextTransition(action, random);
				if (transition != null) {
					currentState = transition.nextState;
					randomReward += transition.reward;
				}
			}
			randomReward /= 1000;
			return randomReward;
		}

		// Determine the reward received by an optimal agent, for comparison.
		// Returns a value in range (0, 1), representing average reward for a single step.
		private double calcOptimalReward() {
			if (singleRewardState) {
				return 1;
			}

			if (getEnvOptimalRewardCalcType().equals(EnvOptimalRewardCalcType.EXACT)) {
				double optReward = 0;
				optimalStateSequence = new int[envStepsPerTrial + 1];
				optimalActionSequence = new int[envStepsPerTrial];
				MultidimensionalCounter mc = new MultidimensionalCounter(ArrayUtil.newArray(envStepsPerTrial, envActionCount));
				MultidimensionalCounter.Iterator mci = mc.iterator();
				// Try every combination of action sequences of length stepsPerTrial starting from start state.
				while (mci.hasNext()) {
					mci.next();
					State currentState = states[0];
					double reward = 0;
					int[] stateSequence = new int[envStepsPerTrial];
					for (int step = 0; step < envStepsPerTrial; step++) {
						int action = mci.getCount(step);
						// If a transition is defined for the current state and specified action.
						Transition transition = currentState.getNextTransition(action, random);
						if (transition != null) {
							currentState = transition.nextState;
							stateSequence[step] = currentState.id;
							reward += transition.reward;
						}
					}
					// Average over steps taken.
					reward /= envStepsPerTrial;
					if (reward > optReward) {
						optReward = reward;
						System.arraycopy(mci.getCounts(), 0, optimalActionSequence, 0, envStepsPerTrial);
						System.arraycopy(stateSequence, 0, optimalStateSequence, 1, envStepsPerTrial);
					}
				}
				return optReward;
			} else if (getEnvOptimalRewardCalcType().equals(EnvOptimalRewardCalcType.APPROXIMATE)) {
				// Since every state is reachable from every other state and we're using deterministic transitions,
				// the optimal sequence of actions will be of length in range [2, stateCount] (shortest loop to longest
				// loop). So just try every permutation of actions of length [2, stateCount]. Since the start state may
				// not be in this loop and the number of steps per trial might not be a factor of the loop length
				// this will only give an approximate optimal reward value.
				double optReward = 0;
				for (int sequenceLength = 2; sequenceLength <= envStateCount; sequenceLength++) {
					MultidimensionalCounter mc = new MultidimensionalCounter(ArrayUtil.newArray(sequenceLength, envActionCount));
					for (int startState = 0; startState < envStateCount; startState++) {
						MultidimensionalCounter.Iterator mci = mc.iterator();
						while (mci.hasNext()) {
							mci.next();
							State currentState = states[startState];
							double reward = 0;
							int[] stateSequence = new int[sequenceLength + 1];
							stateSequence[0] = startState;
							for (int step = 0; step < sequenceLength; step++) {
								int action = mci.getCount(step);
								// If a transition is defined for the current state and specified action.
								Transition transition = currentState.getNextTransition(action, random);
								if (transition != null) {
									currentState = transition.nextState;
									stateSequence[step + 1] = currentState.id;
									reward += transition.reward;
								}
							}

							// We can only include this sequence if it forms a loop (which can then be repeated).
							if (currentState.id == startState) {
								// Average over steps taken.
								reward /= sequenceLength;
								if (reward > optReward) {
									optReward = reward;
									optimalStateSequence = new int[sequenceLength + 1];
									optimalActionSequence = new int[sequenceLength];
									System.arraycopy(stateSequence, 0, optimalStateSequence, 0, sequenceLength + 1);
									System.arraycopy(mci.getCounts(), 0, optimalActionSequence, 0, sequenceLength);
								}
							}
						}
					}
				}
				return optReward;
			}
			optimalActionSequence = null;
			return 1; // Assume maximum possible value.
		}

		public double getMaxReward() {
			return maxReward;
		}

		public double getRandomReward() {
			return randomReward;
		}

		public String toString() {
			StringBuilder sb = new StringBuilder();
			//sb.append("Random reward: " + nf.format(randomReward) + "\n\n");
			//sb.append("(Approx) optimal reward: " + nf.format(maxReward) + "\n");
			if (optimalStateSequence != null) {
				//sb.append("\tState sequence: " + ArrayUtil.toString(optimalStateSequence, "\t", null) + "\n");
				//sb.append("\tAction sequence:  " + ArrayUtil.toString(optimalActionSequence, "\t  ", null) + "\n");
			}
			if (gridEnvs && singleRewardState) {
				sb.append("Goal state: " + rewardState);
			} else {
				for (int s = 0; s < envStateCount; s++) {
					sb.append(states[s] + "\n");
				}
			}
			return sb.toString();
		}
	}

	private class State {
		final int id;
		final int x, y;
		// Available actions.
		private final ArrayList<Action> actions;

		public State(int id) {
			this.id = id;
			x = id;
			y = 0;
			actions = new ArrayList<Action>();
		}

		public boolean isEquivalent(State s) {
			if (actions.size() != s.actions.size()) return false;
			for (int actionID = 0; actionID < actions.size(); actionID++) {
				if (!actions.get(actionID).isEquivalent(s.actions.get(actionID)))
					return false;
			}
			return true;
		}

		public State(int id, int x, int y) {
			this.id = id;
			this.x = x;
			this.y = y;
			actions = new ArrayList<Action>();
		}

		public void addAction(Action a) {
			actions.add(a);
		}

		public Transition getNextTransition(int actionID, Random r) {
			// Search for the specified action in the list of allowed actions.
			for (Action a : actions) {
				if (a.id == actionID) {
					return a.getNextTransition(r);
				}
			}
			// If this action is not allowed then the state doesn't change.
			return null;
		}

		public List<Action> getActions() {
			return Collections.unmodifiableList(actions);
		}

		public String toString() {
			StringBuilder sb = new StringBuilder();
			sb.append("State " + id + (gridEnvs ? "(" + x + ", " + y + ")" : "") + ", actions:\n");
			for (Action a : actions) {
				sb.append(a + "\n");
			}
			return sb.toString();
		}

	}

	// An action performed in some State.
	private class Action {
		final int id;
		// Probabilities for transitioning to each available state.
		final ArrayList<Transition> transitions;
		final DoubleVector probSum;
		private boolean transitionsOrdered = false;

		public Action(int id) {
			this.id = id;
			transitions = new ArrayList<Transition>();
			probSum = new DoubleVector();
		}

		public boolean isEquivalent(Action a) {
			if (!transitionsOrdered) {
				orderTransitions();
			}
			if (transitions.size() != a.transitions.size()) return false;
			for (int tranID = 0; tranID < transitions.size(); tranID++) {
				if (!transitions.get(tranID).isEquivalent(a.transitions.get(tranID)))
					return false;
			}
			return true;
		}

		private void orderTransitions() {
			Collections.sort(transitions);
			probSum.clear();
			for (Transition t : transitions) {
				probSum.add(getTotalProbSum() + t.probability);
			}
		}

		public void addTransition(Transition t) {
			transitions.add(t);
			probSum.add(getTotalProbSum() + t.probability);
		}

		public Transition getNextTransition(Random r) {
			if (transitions.size() == 1)
				return transitions.get(0);

			int index = probSum.binarySearchIP(r.nextDouble() * getTotalProbSum());
			return transitions.get(index);
		}

		private double getTotalProbSum() {
			return probSum.isEmpty() ? 0 : probSum.get(probSum.size() - 1);
		}

		public List<Transition> getTransitions() {
			return Collections.unmodifiableList(transitions);
		}

		public String toString() {
			StringBuilder sb = new StringBuilder();
			sb.append("\tAction " + id + ", transitions:\n");
			for (Transition t : transitions) {
				sb.append("\t\t" + t + "\n");
			}
			return sb.toString();
		}
	}

	private class Transition implements Comparable {
		final double probability;
		final State nextState;
		final double reward;

		public Transition(double probability, State nextState, double reward) {
			this.probability = probability;
			this.nextState = nextState;
			this.reward = reward;
		}

		public boolean isEquivalent(Transition t) {
			return probability == t.probability && nextState.id == t.nextState.id && reward == t.reward;
		}

		public String toString() {
			return nextState.id + ", " + nf.format(probability) + ", " + nf.format(reward);
		}

		@Override
		public int compareTo(Object otherTransition) {
			State otherNextState = ((Transition) otherTransition).nextState;
			if (nextState.id > otherNextState.id) return 1;
			if (nextState.id < otherNextState.id) return -1;
			return 0;
		}
	}

	@Override
	public void ahniEventOccurred(AHNIEvent event) {
		if (event.getType() == AHNIEvent.Type.GENERATION_END) {
			Chromosome bestPerforming = event.getEvolver().getBestPerformingFromLastGen();
			if (bestPerforming.getPerformanceValue() >= props.getDoubleProperty(DIFFICULTY_INCREASE_PERFORMANCE)) {
				if (increaseDifficulty())
					logger.info("Increased difficulty. State/action counts are now " + stateCount + " / " + actionCount);
			}
		}
	}

	private int getInputSize() {
		return stateCountMax + (includePrevState ? stateCountMax : 0) + (includePrevAction ? actionCountMax : 0) + (includeExpl ? 1 : 0) + 1;
	}

	@Override
	public int[] getLayerDimensions(int layer, int totalLayerCount) {
		if (layer == 0) { // Input layer.
			// Current state plus previously performed action plus reinforcement signal.
			return new int[] { getInputSize(), 1 };
		} else if (layer == totalLayerCount - 1) { // Output layer.
			// Action to perform next.
			return new int[] { actionCountMax, 1 };
		}
		return null;
	}

	@Override
	public Point[] getNeuronPositions(int layer, int totalLayerCount) {
		Point[] positions = null;

		if (gridEnvs) {
			if (layer == 0) { // Input layer.
				positions = new Point[getInputSize()];
				int posIndex = 0;
				// Current state.
				for (int x = 0; x < gridSizeMax; x++) {
					for (int y = 0; y < gridSizeMax; y++) {
						positions[posIndex++] = new Point((double) x / (gridSizeMax - 1), (double) y / (gridSizeMax - 1), 0);
					}
				}
				// if (includePrevAction || includePrevState) {
				// double horizFactor = includePrevAction && includePrevState ? 1.0 / 3 : 0.5;
				// int horizPos = 1;
				// if (includePrevState) {
				// for (int i = 0; i < stateCountMax; i++) {
				// positions[posIndex++] = new Point((double) i / (stateCountMax - 1), horizPos * horizFactor, 0);
				// }
				// horizPos++;
				// }
				// if (includePrevAction) {
				// for (int i = 0; i < actionCountMax; i++) {
				// positions[posIndex++] = new Point((double) i / (actionCountMax - 1), horizPos * horizFactor, 0);
				// }
				// }
				// }

				// if (includeExpl) {
				// // Exploration/Exploitation signal, at top-left.
				// positions[posIndex++] = new Point(0, 1, 0);
				// }

				// Reinforcement signal, behind state input layer.
				positions[stateCountMax] = new Point(0.5, 0.5, -0.5);
			} else if (layer == totalLayerCount - 1) { // Output layer.
				positions = new Point[actionCountMax];

				// int xt = x + (actionID == 0 ? -1 : (actionID == 2 ? 1 : 0));
				positions[0] = new Point(0, 0.5, 1);
				positions[2] = new Point(1, 0.5, 1);

				// int yt = y + (actionID == 1 ? -1 : (actionID == 3 ? 1 : 0));
				positions[1] = new Point(0.5, 0, 1);
				positions[3] = new Point(0.5, 1, 1);
			}
		} else {
			if (layer == 0) { // Input layer.
				positions = new Point[getInputSize()];
				int posIndex = 0;
				// Current state.
				for (int i = 0; i < stateCountMax; i++) {
					// Horizontal along bottom.
					positions[posIndex++] = new Point((double) i / (stateCountMax - 1), 0, 0);
				}
				if (includePrevAction || includePrevState) {
					double horizFactor = includePrevAction && includePrevState ? 1.0 / 3 : 0.5;
					int horizPos = 1;
					if (includePrevState) {
						previousStateIndex = posIndex;
						for (int i = 0; i < stateCountMax; i++) {
							positions[posIndex++] = new Point((double) i / (stateCountMax - 1), horizPos * horizFactor, 0);
						}
						horizPos++;
					}
					if (includePrevAction) {
						previousActionIndex = posIndex;
						for (int i = 0; i < actionCountMax; i++) {
							positions[posIndex++] = new Point((double) i / (actionCountMax - 1), horizPos * horizFactor, 0);
						}
					}
				}

				if (includeExpl) {
					explIndex = posIndex;
					// Exploration/Exploitation signal, at top-left.
					positions[posIndex++] = new Point(0, 1, 0);
				}

				rewardIndex = posIndex;
				// Reinforcement signal, at top-right.
				positions[posIndex++] = new Point(1, 1, 0);
			} else if (layer == totalLayerCount - 1) { // Output layer.
				positions = new Point[actionCountMax];
				// Action to perform next.
				for (int i = 0; i < actionCountMax; i++) {
					// Horizontal along middle.
					positions[i] = new Point((double) i / (actionCountMax - 1), 0.5, 1);
				}
			}
		}
		return positions;
	}
}


text:
import numpy as np
import pandas as pd
from pandas import DataFrame

STATS_COLUMNS = ['c00100', 'c04100', 'c04470', 'c04800', 'c05200',
                 'c09600', 'c07100', 'c09200', '_refund', '_ospctax',
                 'c10300', 'e00100', 's006']

TABLE_COLUMNS = ['c00100', 'c04100', 'c04470', 'c04800', 'c05200',
                 'c09600', 'c07100', 'c09200', '_refund', '_ospctax',
                 'c10300']

def extract_array(f):
    """
    A sanity check decorator. When combined with numba.vectorize
    or guvectorize, it provides the same capability as dataframe_vectorize
    or dataframe_guvectorize
    """
    def wrapper(*args, **kwargs):
        arrays = [arg.values for arg in args]
        return f(*arrays)
    return wrapper

def expand_1D(x, inflate, inflation_rates, num_years):
    """
    Expand the given data to account for the given number of budget years.
    If necessary, pad out additional years by increasing the last given
    year at the provided inflation rate.
    """

    assert len(inflation_rates) == num_years

    if isinstance(x, np.ndarray):
        if len(x) >= num_years:
            return x
        else:
            ans = np.zeros(num_years, dtype='f8')
            ans[:len(x)] = x
            if inflate:
                extra = []
                cur = x[-1]
                for i in range(1, num_years - len(x) + 1):
                    inf_idx = i + len(x) - 1
                    cur *= (1. + inflation_rates[inf_idx])
                    extra.append(cur)
            else:
                extra = [float(x[-1]) for i in
                         range(1, num_years - len(x) + 1)]

            ans[len(x):] = extra
            return ans.astype(x.dtype, casting='unsafe')

    return expand_1D(np.array([x]), inflate, inflation_rates, num_years)

def expand_2D(x, inflate, inflation_rates, num_years):
    """
    Expand the given data to account for the given number of budget years.
    For 2D arrays, we expand out the number of rows until we have num_years
    number of rows. For each expanded row, we inflate by the given inflation
    rate.
    """

    if isinstance(x, np.ndarray):
        if x.shape[0] >= num_years:
            return x
        else:
            ans = np.zeros((num_years, x.shape[1]))
            ans[:len(x), :] = x
            if inflate:
                extra = []
                cur = x[-1]
                for i in range(1, num_years - len(x) + 1):
                    inf_idx = i + len(x) - 1
                    cur = np.array(cur*(1. + inflation_rates[inf_idx]))
                    extra.append(cur)
            else:
                extra = [x[-1, :] for i in
                     range(1, num_years - len(x) + 1)]

            ans[len(x):, :] = extra
            return ans.astype(x.dtype, casting='unsafe')

    return expand_2D(np.array([x]), inflate, inflation_rates, num_years)

def expand_array(x, inflate, inflation_rates, num_years):
    """
    Dispatch to either expand_1D or expand2D depending on the dimension of x

    Parameters
    ----------
    x : value to expand

    inflate: Boolean
        As we expand, inflate values if this is True, otherwise, just copy

    inflation_rate: float
        Yearly inflation reate

    num_years: int
        Number of budget years to expand

    Returns
    -------
    expanded numpy array
    """
    try:
        if len(x.shape) == 1:
            return expand_1D(x, inflate, inflation_rates, num_years)
        elif len(x.shape) == 2:
            return expand_2D(x, inflate, inflation_rates, num_years)
        else:
            raise ValueError("Need a 1D or 2D array")
    except AttributeError as ae:
        raise ValueError("Must pass a numpy array")

def count_gt_zero(agg):
    return sum([1 for a in agg if a > 0])

def count_lt_zero(agg):
    return sum([1 for a in agg if a < 0])

def weighted_count_lt_zero(agg, col_name):
    return agg[agg[col_name] < 0]['s006'].sum()

def weighted_count_gt_zero(agg, col_name):
    return agg[agg[col_name] > 0]['s006'].sum()

def weighted_count(agg):
    return agg['s006'].sum()

def weighted_mean(agg, col_name):
    return float((agg[col_name]*agg['s006']).sum()) / float(agg['s006'].sum())

def weighted_sum(agg, col_name):
    return (agg[col_name]*agg['s006']).sum()

def weighted_perc_inc(agg, col_name):
    return float(weighted_count_gt_zero(agg, col_name)) / float(weighted_count(agg))

def weighted_perc_dec(agg, col_name):
    return float(weighted_count_lt_zero(agg, col_name)) / float(weighted_count(agg))

def weighted_share_of_total(agg, col_name, total):
    return float(weighted_sum(agg, col_name)) / float(total)

def groupby_weighted_decile(df):
    """

    Group by each 10% of AGI, weighed by s006

    """

    #First, sort by AGI
    df.sort('c00100', inplace=True)
    #Next, do a cumulative sum by the weights
    df['cumsum_weights'] = np.cumsum(df['s006'].values)
    #Max value of cum sum of weights
    max_ = df['cumsum_weights'].values[-1]
    #Create 10 bins and labels based on this cumulative weight
    bins = [0] + list(np.arange(1,11)*(max_/10.0))
    labels = [range(1,11)]
    # Groupby weighted deciles
    decile_bins = list(range(1, 11))
    df['wdecs'] = pd.cut(df['cumsum_weights'], bins, labels)
    return df.groupby('wdecs')

def groupby_income_bins(df, bins=None, right=True):
    """

    Group by income bins of AGI

    bins: iterable of scalars
            AGI income breakpoints. Follows pandas convention. The
            breakpoint is inclusive if right=True

    right : bool, optional
            Indicates whether the bins include the rightmost edge or not.
            If right == True (the default), then the bins [1,2,3,4]
            indicate (1,2], (2,3], (3,4].

    """

    if not bins:
        bins = [-1e14, 0, 9999, 19999, 29999, 39999, 49999, 74999, 99999,
                200000, 1e14]

    # Groupby c00100 bins
    df['bins'] = pd.cut(df['c00100'], bins, right=right)
    return df.groupby('bins')

def means_and_comparisons(df, col_name, gp, weighted_total):
    """

    Using grouped values, perform aggregate operations
    to populate
    df: DataFrame for full results of calculation
    col_name: the column name to calculate against
    gp: grouped DataFrame
    """

    # Who has a tax cut, and who has a tax increase
    diffs = gp.apply(weighted_count_lt_zero, col_name)
    diffs = DataFrame(data=diffs, columns=['tax_cut'])
    diffs['tax_inc'] = gp.apply(weighted_count_gt_zero, col_name)
    diffs['count'] = gp.apply(weighted_count)
    diffs['mean'] = gp.apply(weighted_mean, col_name)
    diffs['tot_change'] = gp.apply(weighted_sum, col_name)
    diffs['perc_inc'] = gp.apply(weighted_perc_inc, col_name)
    diffs['perc_cut'] = gp.apply(weighted_perc_dec, col_name)
    diffs['share_of_change'] = gp.apply(weighted_share_of_total,
                                        col_name, weighted_total)

    return diffs

def results(c):
    outputs = [getattr(c, col) for col in STATS_COLUMNS]
    return DataFrame(data=np.column_stack(outputs), columns=STATS_COLUMNS)

def create_distribution_table(calc, groupby):
    res = results(calc)
    if groupby == "weighted_deciles":
        gp = groupby_weighted_decile(res)
    elif groupby == "agi_bins":
        gp = groupby_income_bins(res)
    else:
        err = "groupby must be either 'weighted_deciles' or 'agi_bins'"
        raise ValueError(err)

    return gp[TABLE_COLUMNS].mean()

def create_difference_table(calc1, calc2, groupby):
    res1 = results(calc1)
    res2 = results(calc2)
    if groupby == "weighted_deciles":
        gp = groupby_weighted_decile(res2)
    elif groupby == "agi_bins":
        gp = groupby_income_bins(res2)
    else:
        err = "groupby must be either 'weighted_deciles' or 'agi_bins'"
        raise ValueError(err)

    # Difference in plans
    # Positive values are the magnitude of the tax increase
    # Negative values are the magnitude of the tax decrease
    res2['tax_diff'] = res2['_ospctax'] - res1['_ospctax']

    diffs = means_and_comparisons(res2, 'tax_diff', gp,
                                 (res2['tax_diff']*res2['s006']).sum())
    return diffs

redpajama_set_name: RedPajamaGithub


text:
/* tslint:disable */
/* eslint-disable */

import { ReaderFragment } from "relay-runtime";
import { FragmentRefs } from "relay-runtime";
export type ArtistToolTip_artist = {
    readonly name: string | null;
    readonly slug: string;
    readonly formatted_nationality_and_birthday: string | null;
    readonly href: string | null;
    readonly blurb: string | null;
    readonly internalID: string;
    readonly carousel: {
        readonly images: ReadonlyArray<{
            readonly resized: {
                readonly url: string | null;
                readonly width: number | null;
                readonly height: number | null;
            } | null;
        } | null> | null;
    } | null;
    readonly genes: ReadonlyArray<{
        readonly name: string | null;
    } | null> | null;
    readonly " $refType": "ArtistToolTip_artist";
};
export type ArtistToolTip_artist$data = ArtistToolTip_artist;
export type ArtistToolTip_artist$key = {
    readonly " $data"?: ArtistToolTip_artist$data;
    readonly " $fragmentRefs": FragmentRefs<"ArtistToolTip_artist">;
};

const node: ReaderFragment = (function(){
var v0 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "name",
  "storageKey": null
};
return {
  "argumentDefinitions": [],
  "kind": "Fragment",
  "metadata": null,
  "name": "ArtistToolTip_artist",
  "selections": [
    (v0/*: any*/),
    {
      "alias": null,
      "args": null,
      "kind": "ScalarField",
      "name": "slug",
      "storageKey": null
    },
    {
      "alias": "formatted_nationality_and_birthday",
      "args": null,
      "kind": "ScalarField",
      "name": "formattedNationalityAndBirthday",
      "storageKey": null
    },
    {
      "alias": null,
      "args": null,
      "kind": "ScalarField",
      "name": "href",
      "storageKey": null
    },
    {
      "alias": null,
      "args": null,
      "kind": "ScalarField",
      "name": "blurb",
      "storageKey": null
    },
    {
      "alias": null,
      "args": null,
      "kind": "ScalarField",
      "name": "internalID",
      "storageKey": null
    },
    {
      "alias": null,
      "args": null,
      "concreteType": "ArtistCarousel",
      "kind": "LinkedField",
      "name": "carousel",
      "plural": false,
      "selections": [
        {
          "alias": null,
          "args": null,
          "concreteType": "Image",
          "kind": "LinkedField",
          "name": "images",
          "plural": true,
          "selections": [
            {
              "alias": null,
              "args": [
                {
                  "kind": "Literal",
                  "name": "height",
                  "value": 200
                }
              ],
              "concreteType": "ResizedImageUrl",
              "kind": "LinkedField",
              "name": "resized",
              "plural": false,
              "selections": [
                {
                  "alias": null,
                  "args": null,
                  "kind": "ScalarField",
                  "name": "url",
                  "storageKey": null
                },
                {
                  "alias": null,
                  "args": null,
                  "kind": "ScalarField",
                  "name": "width",
                  "storageKey": null
                },
                {
                  "alias": null,
                  "args": null,
                  "kind": "ScalarField",
                  "name": "height",
                  "storageKey": null
                }
              ],
              "storageKey": "resized(height:200)"
            }
          ],
          "storageKey": null
        }
      ],
      "storageKey": null
    },
    {
      "alias": null,
      "args": null,
      "concreteType": "Gene",
      "kind": "LinkedField",
      "name": "genes",
      "plural": true,
      "selections": [
        (v0/*: any*/)
      ],
      "storageKey": null
    }
  ],
  "type": "Artist"
};
})();
(node as any).hash = '9f94e02d04bc29a5b45226a719183668';
export default node;


text:
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="theme" content="hugo-academic">
  <meta name="generator" content="Hugo 0.27" />
  <meta name="author" content="Aziz Khan, PhD">
  <meta name="description" content="Research Scientist">

    <link rel="stylesheet" href="/css/highlight.min.css">

  <link rel="stylesheet" href="/css/bootstrap.min.css">
  <link rel="stylesheet" href="/css/font-awesome.min.css">
  <link rel="stylesheet" href="/css/academicons.min.css">
  <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lato:400,700%7CMerriweather%7CRoboto+Mono">
  <link rel="stylesheet" href="/css/hugo-academic.css">

  <link rel="alternate" href="https://asntech.github.io/index.xml" type="application/rss+xml" title="Aziz Khan">
  <link rel="feed" href="https://asntech.github.io/index.xml" type="application/rss+xml" title="Aziz Khan">

  <link rel="icon" type="image/png" href="/img/icon.png">
  <link rel="apple-touch-icon" type="image/png" href="/img/apple-touch-icon.png">

  <link rel="canonical" href="https://asntech.github.io/post/welcome/">

  <title>Welcome to my new website using Hugo framework | Aziz Khan - Research Scientist, Stanford Cancer Institute, Stanford University</title>

      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
              data-target=".navbar-collapse" aria-expanded="false">
        Toggle navigation

      </button>
      Aziz Khan

            Home

            Publications

            Talks & Posters

            Resources

            Blog

            Activities

            Contact

Welcome to my new website using Hugo framework

    <time datetime="2016-04-20 12:00:00 +0000 UTC" itemprop="datePublished">
      Wed, Apr 20, 2016
    </time>

    academic,

    hugo

This is a welcome post about my new website using Academic Theme and the Hugo

Time to make Venn diagrams UpSet →

Please enable JavaScript to view the comments powered by Disqus.
comments powered by Disqus

      © 2020 Aziz Khan ·

      Powered by the Academic
      theme for Hugo.


text:
package de.fraunhofer.fokus.fuzzing.fuzzino.request.impl;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

import de.fraunhofer.fokus.fuzzing.fuzzino.FuzzinoTest;
import de.fraunhofer.fokus.fuzzing.fuzzino.request.IntegerSpecification;
import de.fraunhofer.fokus.fuzzing.fuzzino.request.RequestFactory;
import de.fraunhofer.fokus.fuzzing.fuzzino.request.StringSpecification;

public class StringSpecificationImplTest extends FuzzinoTest {

	public static final int MIN_LENGTH_2 = 2;
	public static final int MAX_LENGTH_3 = 3;
	public static final StringSpecification STRING_SPEC_2_3;
	static {
		STRING_SPEC_2_3 = RequestFactory.INSTANCE.createStringSpecification();
		STRING_SPEC_2_3.setMinLength(MIN_LENGTH_2);
		STRING_SPEC_2_3.setMaxLength(MAX_LENGTH_3);
	}

	public static final int MIN_LENGTH_3 = 3;
	public static final int MAX_LENGTH_4 = 4;
	public static final StringSpecification STRING_SPEC_3_4;
	static {
		STRING_SPEC_3_4 = RequestFactory.INSTANCE.createStringSpecification();
		STRING_SPEC_3_4.setMinLength(MIN_LENGTH_3);
		STRING_SPEC_3_4.setMaxLength(MAX_LENGTH_4);
	}

	@Test
	public void test_createNegativeNumberSpec_2_3() {
		IntegerSpecification numberSpec = STRING_SPEC_2_3.createNegativeNumberSpec();

		long expectedMinValue = -99;
		long actualMinValue = numberSpec.getMin();
		assertTrue("Wrong minValue: was " + actualMinValue + " instead of " + expectedMinValue,
				   actualMinValue == expectedMinValue);

		long expectedMaxValue = -1;
		long actualMaxValue = numberSpec.getMax();
		assertTrue("Wrong maxValue: was " + actualMaxValue + " instead of " + expectedMaxValue,
				   actualMaxValue == expectedMaxValue);
	}

	@Test
	public void test_createPositiveNumberSpec_2_3() {
		IntegerSpecification numberSpec = STRING_SPEC_2_3.createPositiveNumberSpec();

		long expectedMinValue = 10;
		long actualMinValue = numberSpec.getMin();
		assertTrue("Wrong minValue: was " + actualMinValue + " instead of " + expectedMinValue,
				   actualMinValue == expectedMinValue);

		long expectedMaxValue = 999;
		long actualMaxValue = numberSpec.getMax();
		assertTrue("Wrong maxValue: was " + actualMaxValue + " instead of " + expectedMaxValue,
				   actualMaxValue == expectedMaxValue);
	}

	@Test
	public void test_createNegativeNumberSpec_3_4() {
		IntegerSpecification numberSpec = STRING_SPEC_3_4.createNegativeNumberSpec();

		long expectedMinValue = -999;
		long actualMinValue = numberSpec.getMin();
		assertTrue("Wrong minValue: was " + actualMinValue + " instead of " + expectedMinValue,
				   actualMinValue == expectedMinValue);

		long expectedMaxValue = -10;
		long actualMaxValue = numberSpec.getMax();
		assertTrue("Wrong maxValue: was " + actualMaxValue + " instead of " + expectedMaxValue,
				   actualMaxValue == expectedMaxValue);
	}

	@Test
	public void test_createPositiveNumberSpec_3_4() {
		IntegerSpecification numberSpec = STRING_SPEC_3_4.createPositiveNumberSpec();

		long expectedMinValue = 100;
		long actualMinValue = numberSpec.getMin();
		assertTrue("Wrong minValue: was " + actualMinValue + " instead of " + expectedMinValue,
				   actualMinValue == expectedMinValue);

		long expectedMaxValue = 9999;
		long actualMaxValue = numberSpec.getMax();
		assertTrue("Wrong maxValue: was " + actualMaxValue + " instead of " + expectedMaxValue,
				   actualMaxValue == expectedMaxValue);
	}

}


text:
#region Copyright and License
// Copyright 2010..2012 Alexander Reinert
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ARSoft.Tools.Net.Dns.DynamicUpdate
{
	/// <summary>
	///   <para>Dynamic DNS update message</para> <para>Defined in
	///                                             <see cref="!:http://tools.ietf.org/html/rfc2136">RFC 2136</see>
	///                                           </para>
	/// </summary>
	public class DnsUpdateMessage : DnsMessageBase
	{
		/// <summary>
		///   Creates a new instance of the DnsUpdateMessage class
		/// </summary>
		public DnsUpdateMessage()
		{
			OperationCode = OperationCode.Update;
		}

		private List<PrequisiteBase> _prequisites;
		private List<UpdateBase> _updates;

		/// <summary>
		///   Gets or sets the zone name
		/// </summary>
		public string ZoneName
		{
			get { return Questions.Count > 0 ? Questions[0].Name : null; }
			set { Questions = new List<DnsQuestion>() { new DnsQuestion(value, RecordType.Soa, RecordClass.Any) }; }
		}

		/// <summary>
		///   Gets or sets the entries in the prerequisites section
		/// </summary>
		public List<PrequisiteBase> Prequisites
		{
			get { return _prequisites ?? (_prequisites = new List<PrequisiteBase>()); }
			set { _prequisites = value; }
		}

		/// <summary>
		///   Gets or sets the entries in the update section
		/// </summary>
		public List<UpdateBase> Updates
		{
			get { return _updates ?? (_updates = new List<UpdateBase>()); }
			set { _updates = value; }
		}

		internal override bool IsTcpUsingRequested
		{
			get { return false; }
		}

		internal override bool IsTcpResendingRequested
		{
			get { return false; }
		}

		internal override bool IsTcpNextMessageWaiting
		{
			get { return false; }
		}

		protected override void PrepareEncoding()
		{
			AnswerRecords = (Prequisites != null ? Prequisites.Cast<DnsRecordBase>().ToList() : new List<DnsRecordBase>());
			AuthorityRecords = (Updates != null ? Updates.Cast<DnsRecordBase>().ToList() : new List<DnsRecordBase>());
		}

		protected override void FinishParsing()
		{
			Prequisites =
				AnswerRecords.ConvertAll<PrequisiteBase>(
					record =>
					{
						if ((record.RecordClass == RecordClass.Any) && (record.RecordDataLength == 0))
						{
							return new RecordExistsPrequisite(record.Name, record.RecordType);
						}
						else if (record.RecordClass == RecordClass.Any)
						{
							return new RecordExistsPrequisite(record);
						}
						else if ((record.RecordClass == RecordClass.None) && (record.RecordDataLength == 0))
						{
							return new RecordNotExistsPrequisite(record.Name, record.RecordType);
						}
						else if ((record.RecordClass == RecordClass.Any) && (record.RecordType == RecordType.Any))
						{
							return new NameIsInUsePrequisite(record.Name);
						}
						else if ((record.RecordClass == RecordClass.None) && (record.RecordType == RecordType.Any))
						{
							return new NameIsNotInUsePrequisite(record.Name);
						}
						else
						{
							return null;
						}
					}).Where(prequisite => (prequisite != null)).ToList();

			Updates =
				AuthorityRecords.ConvertAll<UpdateBase>(
					record =>
					{
						if (record.TimeToLive != 0)
						{
							return new AddRecordUpdate(record);
						}
						else if ((record.RecordType == RecordType.Any) && (record.RecordClass == RecordClass.Any) && (record.RecordDataLength == 0))
						{
							return new DeleteAllRecordsUpdate(record.Name);
						}
						else if ((record.RecordClass == RecordClass.Any) && (record.RecordDataLength == 0))
						{
							return new DeleteRecordUpdate(record.Name, record.RecordType);
						}
						else if (record.RecordClass == RecordClass.Any)
						{
							return new DeleteRecordUpdate(record);
						}
						else
						{
							return null;
						}
					}).Where(update => (update != null)).ToList();
		}
	}
}


text:
package client

import (
	"context"
	"fmt"
	"os"
	"time"

	"google.golang.org/grpc"
)

const (
	// ConnectorSocketName is the path used when communicating to the connector process
	ConnectorSocketName = "/tmp/telepresence-connector.socket"

	// DaemonSocketName is the path used when communicating to the daemon process
	DaemonSocketName = "/var/run/telepresence-daemon.socket"
)

// SocketExists returns true if a socket is found at the given path
func SocketExists(path string) bool {
	s, err := os.Stat(path)
	return err == nil && s.Mode()&os.ModeSocket != 0
}

// WaitUntilSocketVanishes waits until the socket at the given path is removed
// and returns when that happens. The wait will be max ttw (time to wait) long.
// An error is returned if that time is exceeded before the socket is removed.
func WaitUntilSocketVanishes(name, path string, ttw time.Duration) (err error) {
	giveUp := time.Now().Add(ttw)
	for giveUp.After(time.Now()) {
		_, err = os.Stat(path)
		if err != nil {
			if os.IsNotExist(err) {
				err = nil
			}
			return err
		}
		time.Sleep(250 * time.Millisecond)
	}
	return fmt.Errorf("timeout while waiting for %s to exit", name)
}

// WaitUntilSocketAppears waits until the socket at the given path comes into
// existence and returns when that happens. The wait will be max ttw (time to wait) long.
// An error is returned if that time is exceeded before the socket is removed.
func WaitUntilSocketAppears(name, path string, ttw time.Duration) (err error) {
	giveUp := time.Now().Add(ttw)
	for giveUp.After(time.Now()) {
		_, err = os.Stat(path)
		if err == nil {
			return
		}
		if !os.IsNotExist(err) {
			return err
		}
		time.Sleep(250 * time.Millisecond)
	}
	return fmt.Errorf("timeout while waiting for %s to start", name)
}

// SocketURL returns the URL that corresponds to the given unix socket filesystem path.
func SocketURL(socket string) string {
	// The unix URL scheme was implemented in google.golang.org/grpc v1.34.0
	return "unix:" + socket
}

// DialSocket dials the given unix socket and returns the resulting connection
func DialSocket(c context.Context, socketName string) (*grpc.ClientConn, error) {
	return grpc.DialContext(c, SocketURL(socketName), grpc.WithInsecure(), grpc.WithNoProxy())
}


text:
/*
 * CLFieldsCommon.h - get/set/free routines common to certs and CRLs
 */

#include "CLFieldsCommon.h"
#include "clNameUtils.h"
#include "clNssUtils.h"
#include "AppleX509CLSession.h"
#include <Security/cssmapple.h>
#include <Security/oidscert.h>
#include <Security/nameTemplates.h>
#include <Security/certExtensionTemplates.h>
#include <Security/SecAsn1Templates.h>

/*
 * Table to map an OID to the info needed to decode the
 * associated extension
 */
typedef struct {
	const CSSM_OID 			&oid;
	unsigned				nssObjLen;
	const SecAsn1Template	*templ;
} NssExtenInfo;

static const NssExtenInfo nssExtenInfo[] = {
	{ CSSMOID_KeyUsage,
	  sizeof(CSSM_DATA),
	  kSecAsn1KeyUsageTemplate },
	{ CSSMOID_BasicConstraints,
	  sizeof(NSS_BasicConstraints),
	  kSecAsn1BasicConstraintsTemplate },
	{ CSSMOID_ExtendedKeyUsage,
	  sizeof(NSS_ExtKeyUsage),
	  kSecAsn1ExtKeyUsageTemplate },
	{ CSSMOID_SubjectKeyIdentifier,
	  sizeof(CSSM_DATA),
	  kSecAsn1SubjectKeyIdTemplate },
	{ CSSMOID_AuthorityKeyIdentifier,
	  sizeof(NSS_AuthorityKeyId),
	  kSecAsn1AuthorityKeyIdTemplate },
	{ CSSMOID_SubjectAltName,
	  sizeof(NSS_GeneralNames),
	  kSecAsn1GeneralNamesTemplate },
	{ CSSMOID_IssuerAltName,
	  sizeof(NSS_GeneralNames),
	  kSecAsn1GeneralNamesTemplate },
	{ CSSMOID_CertificatePolicies,
	  sizeof(NSS_CertPolicies),
	  kSecAsn1CertPoliciesTemplate },
	{ CSSMOID_NetscapeCertType,
	  sizeof(CSSM_DATA),
	  kSecAsn1NetscapeCertTypeTemplate },
	{ CSSMOID_CrlDistributionPoints,
	  sizeof(NSS_CRLDistributionPoints),
	  kSecAsn1CRLDistributionPointsTemplate },
	{ CSSMOID_CertIssuer,
	  sizeof(NSS_GeneralNames),
	  kSecAsn1GeneralNamesTemplate },
	{ CSSMOID_AuthorityInfoAccess,
	  sizeof(NSS_AuthorityInfoAccess),
	  kSecAsn1AuthorityInfoAccessTemplate },
	{ CSSMOID_SubjectInfoAccess,
	  sizeof(NSS_AuthorityInfoAccess),
	  kSecAsn1AuthorityInfoAccessTemplate },
	/* CRL extensions */
	{ CSSMOID_CrlNumber,
	  sizeof(CSSM_DATA),
	  kSecAsn1IntegerTemplate },
	{ CSSMOID_IssuingDistributionPoint,
	  sizeof(NSS_IssuingDistributionPoint),
	  kSecAsn1IssuingDistributionPointTemplate },
	{ CSSMOID_HoldInstructionCode,
	  sizeof(CSSM_OID),
	  kSecAsn1ObjectIDTemplate },
	{ CSSMOID_CrlReason,
	  sizeof(CSSM_DATA),
	  kSecAsn1EnumeratedTemplate },
	{ CSSMOID_DeltaCrlIndicator,
	  sizeof(CSSM_DATA),
	  kSecAsn1IntegerTemplate },
	{ CSSMOID_InvalidityDate,
	  sizeof(CSSM_DATA),
	  kSecAsn1GeneralizedTimeTemplate },
	{ CSSMOID_QC_Statements,
	  sizeof(NSS_QC_Statements),
	  kSecAsn1QC_StatementsTemplate },
	{ CSSMOID_NameConstraints,
	  sizeof(NSS_NameConstraints),
	  kSecAsn1NameConstraintsTemplate },
	{ CSSMOID_PolicyMappings,
	  sizeof(NSS_PolicyMappings),
	  kSecAsn1PolicyMappingsTemplate },
	{ CSSMOID_PolicyConstraints,
	  sizeof(NSS_PolicyConstraints),
	  kSecAsn1PolicyConstraintsTemplate },
	{ CSSMOID_InhibitAnyPolicy,
	  sizeof(CSSM_DATA),
	  kSecAsn1IntegerTemplate },
};

#define NUM_NSS_EXTEN_INFOS	(sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))

/*
 * Returns true if we find the OID.
 */
bool clOidToNssInfo(
	const CSSM_OID			&oid,
	unsigned				&nssObjLen,		// RETURNED
	const SecAsn1Template	*&templ)		// RETURNED
{
	for(unsigned dex=0; dex<NUM_NSS_EXTEN_INFOS; dex++) {
		const NssExtenInfo &info = nssExtenInfo[dex];
		if(clCompareCssmData(&info.oid, &oid)) {
			nssObjLen = info.nssObjLen;
			templ = info.templ;
			return true;
		}
	}
	return false;
}

/*
 * Common code to pass info from a DecodedExten back to app.
 * Called from getField*().
 */
void getFieldExtenCommon(
	void 				*cdsaObj,			// e.g. CE_KeyUsage
											// NULL for berEncoded
	const DecodedExten	&decodedExt,
	CssmOwnedData		&fieldValue)
{
	CSSM_X509_EXTENSION_PTR cssmExt;
	Allocator &alloc = fieldValue.allocator;
	CssmData &fdata = fieldValue.get();

	cssmExt = (CSSM_X509_EXTENSION_PTR)alloc.
		malloc(sizeof(CSSM_X509_EXTENSION));
	fdata.Data = (uint8 *)cssmExt;
	fdata.Length = sizeof(CSSM_X509_EXTENSION);
	decodedExt.convertToCdsa(cdsaObj, cssmExt, alloc);
}

/*
 * Common code for top of setField* and freeField*().
 */
CSSM_X509_EXTENSION_PTR verifySetFreeExtension(
	const CssmData &fieldValue,
	bool berEncoded)		// false: value in value.parsedValue
							// true : value in BERValue
{
	if(fieldValue.length() != sizeof(CSSM_X509_EXTENSION)) {
		clFieldLog("Set/FreeExtension: bad length : exp %d got %d",
			(int)sizeof(CSSM_X509_EXTENSION), (int)fieldValue.length());
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
	CSSM_X509_EXTENSION_PTR cssmExt =
		reinterpret_cast<CSSM_X509_EXTENSION_PTR>(fieldValue.data());
	if(berEncoded) {
		if(cssmExt->BERvalue.Data == NULL) {
			CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
		}
	}
	else {
		if(cssmExt->value.parsedValue == NULL) {
			CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
		}
	}
	return cssmExt;
}

/*
 * Common free code for all extensions. Extension-specific code must
 * free anything beyond cdsaExt->Value.parsedValue, then we free everything
 * else (except the extension struct itself, which is freed by
 * DecodedCert::freeCertFieldData()).
 * The value union may contain a parsed value, or a CSSM_X509EXT_TAGandVALUE;
 * wed ont' care, we just free it.
 */
void freeFieldExtenCommon(
	CSSM_X509_EXTENSION_PTR	exten,
	Allocator			&alloc)
{
	alloc.free(exten->extnId.Data);
	alloc.free(exten->BERvalue.Data);		// may be NULL
	alloc.free(exten->value.parsedValue);   // may be NULL
}

/*
 * One common free for extensions whose parsed value doesn't go any deeper
 * than cssmExt->value.parsedValue.
 */
void freeFieldSimpleExtension (
	CssmOwnedData		&fieldValue)
{
	CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue,
		false);
	freeFieldExtenCommon(cssmExt, fieldValue.allocator);
}

/***
 *** Common code for get/set subject/issuer name (C struct version)
 *** Format = CSSM_X509_NAME
 *** class Name from sm_x501if
 ***/
bool getField_RDN_NSS (
	const NSS_Name 		&nssName,
	CssmOwnedData		&fieldValue)	// RETURNED
{
	/* alloc top-level CSSM_X509_NAME */
	Allocator &alloc = fieldValue.allocator;
	fieldValue.malloc(sizeof(CSSM_X509_NAME));
	CSSM_X509_NAME_PTR cssmName = (CSSM_X509_NAME_PTR)fieldValue.data();

	CL_nssNameToCssm(nssName, *cssmName, alloc);
	return true;
}

void freeField_RDN  (
	CssmOwnedData		&fieldValue)
{
	if(fieldValue.data() == NULL) {
		return;
	}
	if(fieldValue.length() != sizeof(CSSM_X509_NAME)) {
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
	Allocator &alloc = fieldValue.allocator;
	CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue.data();
	CL_freeX509Name(x509Name, alloc);

	/* top-level x509Name pointer freed by freeCertFieldData() */
}

/***
 *** Common code for Issuer Name, Subject Name (normalized and encoded
 *** version)
 *** Format = CSSM_DATA containing the DER encoding of the normalized name
 ***/
bool getField_normRDN_NSS (
	const CSSM_DATA		&derName,
	uint32				&numFields,		// RETURNED (if successful, 0 or 1)
	CssmOwnedData		&fieldValue)	// RETURNED
{
	if(derName.Data == NULL) {
		/* This can happen during CertGetAllTemplateFields() because
		 * the normalized fields are only set up during cert/CRL decode */
		return false;
	}

	/*
	 * First make a temp decoded copy which we'll be manipulating.
	 */
	SecNssCoder coder;
	NSS_Name decodedName;

	memset(&decodedName, 0, sizeof(decodedName));
	PRErrorCode prtn = coder.decodeItem(derName, kSecAsn1NameTemplate, &decodedName);
	if(prtn) {
		/*
		 * Actually should never happen since this same bag of bits successfully
		 * decoded when the cert as a whole was decoded...
		 */
		clErrorLog("getField_normRDN decode error\n");
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);

	}

	/* normalize */
	CL_normalizeX509NameNSS(decodedName, coder);

	/* encode result */
	prtn = SecNssEncodeItemOdata(&decodedName, kSecAsn1NameTemplate, fieldValue);
	if(prtn) {
		clErrorLog("getField_normRDN encode error\n");
		CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
	}
	numFields = 1;
	return true;
}

/***
 *** Common code for Time fields - Validity not before, Not After,
 ***    This Update, Next Update
 *** Format: CSSM_X509_TIME
 ***/
bool getField_TimeNSS (
	const NSS_Time 	&nssTime,
	unsigned		index,			// which occurrence (0 = first)
	uint32			&numFields,		// RETURNED
	CssmOwnedData	&fieldValue)	// RETURNED
{
	if(!tbsGetCheck(nssTime.item.Data, index)) {
		return false;
	}
	Allocator &alloc = fieldValue.allocator;
	fieldValue.malloc(sizeof(CSSM_X509_TIME));
	CSSM_X509_TIME *cssmTime =
		(CSSM_X509_TIME *)fieldValue.data();
	if(CL_nssTimeToCssm(nssTime, *cssmTime, alloc)) {
		numFields = 1;
		return true;
	}
	else {
		return false;
	}
}

void setField_TimeNSS (
	const CssmData	&fieldValue,
	NSS_Time		&nssTime,
	SecNssCoder		&coder)
{
	CSSM_X509_TIME *cssmTime =
		(CSSM_X509_TIME *)fieldValue.data();
	CL_cssmTimeToNss(*cssmTime, nssTime, coder);
}

void freeField_Time (
	CssmOwnedData		&fieldValue)
{
	CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)fieldValue.data();
	if(cssmTime == NULL) {
		return;
	}
	if(fieldValue.length() != sizeof(CSSM_X509_TIME)) {
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
	CL_freeCssmTime(cssmTime, fieldValue.allocator);
}

/***
 *** TBS AlgId, Signature AlgId
 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
 ***/
void getField_AlgIdNSS (
	const CSSM_X509_ALGORITHM_IDENTIFIER 	&srcAlgId,
	CssmOwnedData							&fieldValue)	// RETURNED
{
	Allocator &alloc = fieldValue.allocator;
	fieldValue.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
	CSSM_X509_ALGORITHM_IDENTIFIER *destAlgId =
		(CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
	CL_copyAlgId(srcAlgId, *destAlgId, alloc);
}

void setField_AlgIdNSS (
	const CssmData		&fieldValue,
	CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
	SecNssCoder			&coder)
{
	CSSM_X509_ALGORITHM_IDENTIFIER *srcAlgId =
		(CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
	/* allocator for this coder */
	ArenaAllocator areanAlloc(coder);
	CL_copyAlgId(*srcAlgId, dstAlgId, areanAlloc);
}

void freeField_AlgId (
	CssmOwnedData		&fieldValue)
{
	CSSM_X509_ALGORITHM_IDENTIFIER *cssmAlgId =
		(CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
	if(cssmAlgId == NULL) {
		return;
	}
	if(fieldValue.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
	Allocator &alloc = fieldValue.allocator;
	alloc.free(cssmAlgId->algorithm.Data);
	alloc.free(cssmAlgId->parameters.Data);
	memset(cssmAlgId, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
}

/*
 * Routines for common validity checking for certificateToSign fields.
 *
 * Call from setField*: verify field isn't already set, optionally validate
 * input length
 */
void tbsSetCheck(
	void				*fieldToSet,
	const CssmData		&fieldValue,
	uint32				expLength,
	const char			*op)
{
	if(fieldToSet != NULL) {
		/* can't add another */
		clErrorLog("setField(%s): field already set", op);
		CssmError::throwMe(CSSMERR_CL_INVALID_NUMBER_OF_FIELDS);
	}
	if((expLength != 0) && (fieldValue.length() != expLength)) {
		clErrorLog("setField(%s): bad length : exp %d got %d",
			op, (int)expLength, (int)fieldValue.length());
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
}

/*
 * Call from getField* for unique fields - detect missing field or
 * index out of bounds.
 */
bool tbsGetCheck(
	const void	*requiredField,
	uint32		reqIndex)
{
	if((requiredField == NULL) ||  (reqIndex != 0)) {
		return false;
	}
	else {
		return true;
	}
}

/***
 *** unknown extensions
 *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
 ***              some extension struct we don't know about.
 *** NSS format   CSSM_DATA
 *** OID 		  CSSMOID_X509V3CertificateExtensionCStruct
 ***/

void setFieldUnknownExt(
	DecodedItem	&cert,
	const CssmData &fieldValue)
{
	CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
	SecNssCoder &coder = cert.coder();
	CSSM_DATA *rawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
	coder.allocCopyItem(cssmExt->BERvalue, *rawExtn);
	cert.addExtension(NULL, cssmExt->extnId, cssmExt->critical,
		true, NULL /* no template */, rawExtn);
}

bool getFieldUnknownExt(
	DecodedItem 		&cert,
	unsigned			index,			// which occurrence (0 = first)
	uint32				&numFields,		// RETURNED
	CssmOwnedData		&fieldValue)
{
	uint8 noOidDataLikeThis[2] = {1, 2};	// a dummy argument
	CSSM_OID noOidLikeThis = {2, noOidDataLikeThis};
	const DecodedExten *decodedExt =
		cert.DecodedItem::findDecodedExt(noOidLikeThis,
		true, index, numFields);
	if(decodedExt == NULL) {
		return false;
	}
	getFieldExtenCommon(NULL, *decodedExt, fieldValue);
	return true;
}

void freeFieldUnknownExt (
	CssmOwnedData		&fieldValue)
{
	CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
	Allocator &alloc = fieldValue.allocator;
	freeFieldExtenCommon(cssmExt, alloc);		// frees extnId, parsedValue, BERvalue
}

/* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
void setField_ReadOnly (
	DecodedItem			&item,
	const CssmData		&fieldValue)
{
	clErrorLog("Attempt to set a read-only field");
	CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
}

bool getField_Unimplemented (
	DecodedItem			&item,
	unsigned			index,			// which occurrence (0 = first)
	uint32				&numFields,		// RETURNED
	CssmOwnedData		&fieldValue)	// RETURNED
{
	clErrorLog("Attempt to get an unimplemented field");
	CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
}


text:
/**
 *
  Package: MAG - VistA Imaging
  WARNING: Per VHA Directive 2004-038, this routine should not be modified.
  Date Created: Feb 20, 2012
  Site Name:  Washington OI Field Office, Silver Spring, MD
  Developer:  VHAISWWERFEJ
  Description:

        ;; +--------------------------------------------------------------------+
        ;; Property of the US Government.
        ;; No permission to copy or redistribute this software is given.
        ;; Use of unreleased versions of this software requires the user
        ;;  to execute a written test agreement with the VistA Imaging
        ;;  Development Office of the Department of Veterans Affairs,
        ;;  telephone (301) 734-0100.
        ;;
        ;; The Food and Drug Administration classifies this software as
        ;; a Class II medical device.  As such, it may not be changed
        ;; in any way.  Modifications to this software may result in an
        ;; adulterated medical device under 21CFR820, the use of which
        ;; is considered to be a violation of US Federal Statutes.
        ;; +--------------------------------------------------------------------+

 */
package gov.va.med.imaging.datasource;

import gov.va.med.imaging.core.interfaces.exceptions.ConnectionException;
import gov.va.med.imaging.core.interfaces.exceptions.MethodException;
import gov.va.med.imaging.datasource.annotations.SPI;

/**
 * @author VHAISWWERFEJ
 *
 */
@SPI(description="Defines the interface to acquire user authentication tokens.")
public interface UserAuthorizationDataSourceSpi
extends VersionableDataSourceSpi
{
	/**
	 * Returns a full security string that allows access to a remote VistA site.
	 *  An example of this string is: VISTA IMAGING VIX^XUSBSE1072-388709_4^660^9200
	 *
	 * @param applicationName
	 * @return
	 * @throws MethodException
	 * @throws ConnectionException
	 */
	public abstract String getUserToken(String applicationName)
	throws MethodException, ConnectionException;

}


text:
layout: page
title: TINFormatError
number: 143
categories: [AvaTax Error Codes]
disqus: 0
---

## Summary

The U.S. Taxpayer Identification Number you provided is not in a recognized format.

## Example

```json
{
  "code": "TINFormatError",
  "target": "Unknown",
  "details": [
    {
      "code": "TINFormatError",
      "number": 143,
      "message": "Taxpayer ID Number (TIN) is not in the correct format.",
      "description": "The TIN is a nine digit number. Acceptable formats: 123456789, 12-3456789, 123-456-789, and 123-45-6789.",
      "faultCode": "Client",
      "helpLink": "http://developer.avalara.com/avatax/errors/TINFormatError",
      "severity": "Error"
    }
  ]
}
```

## Explanation

In the United States, a Taxpayer Identification Number is a nine digit number that is either an Employer Identification Number (in the case of a company) or a Social Security Number (in the case of an individual).

Recognized TIN/EIN/SSN numbers are in the format:

12-3456789 (generally an Employer ID number)

123-45-6789 or 123-456-789 (generally a Social Security Number)

You may also provide a number with no dashes if desired.

If you do not have an employer identification number, you may request one from the IRS online: https://www.irs.gov/businesses/small-businesses-self-employed/apply-for-an-employer-identification-number-ein-online


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using Castle.Core.Logging;
using Raven.Client;
using Xemio.ImageUploader.Entities;

namespace Xemio.ImageUploader.Infrastructure.Controllers
{
    /// <summary>
    /// Base class for all api controllers handling the session management.
    /// </summary>
    public abstract class BaseController : ApiController
    {
        #region Properties
        /// <summary>
        /// Gets the document session.
        /// </summary>
        public IAsyncDocumentSession DocumentSession { get; private set; }
        /// <summary>
        /// Gets or sets the logger.
        /// </summary>
        public ILogger Logger { get; set; }
        /// <summary>
        /// Gets the current user.
        /// </summary>
        public Task<User> CurrentUser
        {
            get
            {
                return this.DocumentSession.LoadAsync<User>(Thread.CurrentPrincipal.Identity.Name);
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="BaseController"/> class.
        /// </summary>
        /// <param name="documentSession">The document session.</param>
        protected BaseController(IAsyncDocumentSession documentSession)
        {
            this.DocumentSession = documentSession;
            this.Logger = NullLogger.Instance;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Executes asynchronously a single HTTP operation.
        /// </summary>
        /// <param name="controllerContext">The controller context for a single HTTP operation.</param>
        /// <param name="cancellationToken">The cancellation token assigned for the HTTP operation.</param>
        public async override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
        {
            var response = await base.ExecuteAsync(controllerContext, cancellationToken);

            using (this.DocumentSession)
            {
                await this.DocumentSession.SaveChangesAsync();
            }

            return response;
        }
        #endregion
    }
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
  <display-name>A simple web application</display-name>

  <!-- Welcome page list -->
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>