text:
//
// SAGE2 application: usc_biodigital
// by: Mark Utting <utting@usc.edu.au>
//     Svetlana Mandler
//     Levi Kotzur <lkotzur@usc.edu.au>
//
// This app extends BioDigital Human to support timed quizzes.
// The widgets have the following behaviour:
//    "post" / "ante" loads .json file and starts to load that model.
//    "start" should be done after model is fully loaded.
//                (cannot find a way to automate this in the API).
//           It matches .json body part names to the model body part IDs.
//           It displays the quiz panel and the items.
//           It starts the clock timer and sets misses to zero.
//    "stop" stops the counter, leaving display unchanged.
//           And prevents users answering more questions.
//
// Copyright (c) 2016

"use strict";

/* global HumanAPI */
var IFRAME_ID = 'embedded-human';
var PAN_STEP = 1.0;

var usc_biodigital = SAGE2_App.extend({
	init: function(data) {
		// Create div into the DOM
		this.SAGE2Init("div", data);
		this.data = data;
		this.defaultTool = "highlight"; // default tool
		this.tool = this.defaultTool;

		// load the BioDigital HumanAPI
		var s = document.createElement('script');
		s.type = 'text/javascript';
		s.src = 'https://developer.biodigital.com/builds/api/2/human-api.min.js';
		var l = document.createElement("link");
		l.type = "text/css";
		l.href = this.resrcPath + "css.css";
		l.rel = "stylesheet";
		document.head.appendChild(l);
		document.body.appendChild(s);

		// Set the DOM id
		this.element.id = "div_" + "usc_biodigital";
		//console.log('usc_biodigital> id=', this.id, 'init element=', this.element,
		//    'w=', this.element.clientWidth, 'h=', this.element.clientHeight);

		// generate the widget interface of the usc_biodigital
		this.addWidgetButtons();

		// Set the background to black
		this.element.style.backgroundColor = '#87CEEB';

		/*var iframe = document.createElement('iframe');
		iframe.src = this.state.value;
		iframe.id = IFRAME_ID + this.id;
		iframe.width =  '100%';
		iframe.height =  '100%';
		iframe.setAttribute("style", "float:left");*/
		var iframe_id = IFRAME_ID + this.id;
		//this.element.appendChild(iframe);
		// we display a blank page until quizSetup chooses a quiz model.
		//var source = `${this.state.value}&dk=${this.state.dk}`;
		var source = "about:blank";
		//console.log("developer key", source);
		this.element.innerHTML = `
			<link type="text/css" href="${this.resrcPath}css.css" rel="stylesheet"></link>

Clock
					00:
					00
					Misses:
						00

Last selected:

SLICE Project 2017

Mark Utting, Svetlana Mandler, Levi Kotzur, Jacqui Blake, Dion Keetley

`;

		// DOM Elements
		this.quizResponseDOM = document.getElementById("quizResponse_" + this.id);
		this.quizPanelDOM = document.getElementById("quizPanel_" + this.id);
		this.quizRestartBtnDOM = document.getElementById("quizRestartBtn_" + this.id);
		this.quizTargetDOM = document.getElementById("quizTarget_" + this.id);
		this.quizSelDOM = document.getElementById("quizLastSelected_" + this.id);
		this.quizListDOM = document.getElementById("quizList_" + this.id);
		this.quizClockDOM = document.getElementById("quizClock_" + this.id);
		this.quizMissesDOM = document.getElementById("misses_" + this.id);
		this.quizMinDOM = document.getElementById("min_" + this.id);
		this.quizSecDOM = document.getElementById("sec_" + this.id);
		this.humanIframe = document.getElementById(iframe_id);

		this.setQuizState("Quiz Unknown");
		this.isQuizShowing = false;
		this.window = 0.0;
		this.interval = 0; // not a valid timer ID.
		this.fontSize = this.element.clientHeight * 0.015;
		this.missed = -1;
		this.numQuestions = 0;
		this.correctAnswers = 0;

		// audio
		this.soundCorrect = new Audio(this.resrcPath + "correct_sound.wav");
		this.soundIncorrect = new Audio(this.resrcPath + "incorrect_sound.wav");

		// initialise our own object state.
		this.currentZoom = 0.3;

		// move and resize callbacks
		this.resizeEvents = "continuous"; // onfinish
		// this.moveEvents   = "continuous";

		// SAGE2 Application Settings
		//
		// Control the frame rate for an animation application
		this.maxFPS = 2.0;
		// Set up the default quiz
		this.quizSetup();
		this.invariant();
	},

	// private helper function
	getQuizState: function() {
		// currently, we use this visible-on-screen field for the quiz state.
		return this.quizResponseDOM.innerHTML;
	},

	// private helper function
	setQuizState: function(state) {
		this.quizResponseDOM.innerHTML = state;
		console.log(this.id + " STATE: " + state);
	},

	// This checks the invariant properties of the current quiz state.
	invariant: function() {
		var i = 0;
		var qState = this.getQuizState();
		switch (qState) {
			case "Quiz Unknown":
				// only at the very start of the program.
				this.assertEquals(0, this.interval);
				break;

			case "Quiz Loaded":
				// the quiz name and item names (but maybe not IDs) are known.
				this.assertTrue(typeof(this.state.quizName) == "string", "quizName");
				this.assertEquals(7, this.QUIZ_OBJECTS.length);
				this.assertEquals(this.numQuestions, this.QUIZ_OBJECTS.length);
				break;

			case "Quiz Starting":
				// all quiz details are known, including item IDs.
				this.assertEquals(7, this.QUIZ_OBJECTS.length); // ONLY FOR LFS122 QUIZZES
				this.assertEquals(this.numQuestions, this.QUIZ_OBJECTS.length);
				this.assertEquals(0, this.missed);
				this.assertEquals(0, this.correctAnswers);
				this.assertEquals(0, this.interval); // no timer running
				for (i = 0; i < this.QUIZ_OBJECTS.length; i++) {
					var obj = this.QUIZ_OBJECTS[i];
					this.assertTrue(!obj.id, "id=" + obj.id); // id is not known
					this.assertTrue(!obj.found, "Q[" + i + "].found");  // found is false/undef
					var liId = obj.id + this.id;
					var li = document.getElementById(liId);
					if (li) {
						this.assertTrue(li.style.color !== "green", "li.style.color"); // not green
					}
				}
				break;

			case "Quiz Started":
			case "Anterior Quiz":
			case "Posterior Quiz":
				// quiz is running, with timer ticking.
				this.assertTrue(this.interval !== 0, "interval"); // timer is running
				this.checkQuizItems();
				break;

			case "Quiz Stopped":
				// quiz has stopped (but still displayed) and timer is stopped.
				this.assertEquals(0, this.interval);
				this.checkQuizItems();
				break;

			case "Quiz Finished":
				this.assertEquals(this.numQuestions, this.correctAnswers);
				this.assertEquals(0, this.interval);
				this.assertEquals(this.quizListDOM.innerHTML, "Success!");
				break;

			default:
				this.showError("Illegal quiz state: " + qState);
		}
	},

	// private helper function for assertions.
	assertTrue: function(truth, msg) {
		if (!truth) {
			this.showError("incorrect " + msg);
		}
	},

	// private helper function for assertions.
	assertEquals: function(expected, actual) {
		if (expected !== actual) {
			this.showError("Expected " + expected + " !== " + actual);
		}
	},

	showError: function (msg) {
		var err = "ASSERT ERROR: " + msg;
		console.log(err);
		// we also show error messages on the quiz panel (temporarily?)
		this.quizTargetDOM.innerHTML = err;
		// and (in development mode) we throw an exception:
		throw err;
	},

	// private helper function to check quiz items in Quiz Started/Stopped state.
	checkQuizItems: function() {
		var i = 0;
		var countFound = 0;
		// console.log(this.QUIZ_OBJECTS);
		for (i = 0; i < this.QUIZ_OBJECTS.length; i++) {
			var quizItem = this.QUIZ_OBJECTS[i];
			this.assertTrue(typeof(quizItem.id) === "string", "id=" + quizItem.id); // id is known
			var liId = quizItem.id + this.id;
			var li = document.getElementById(liId);
			this.assertTrue(li != null, "li");  // list item is created
			if (quizItem.found) {
				countFound++;
				this.assertEquals("green", li.style.color); // found items are green
			} else {
				this.assertTrue(li.style.color !== "green"); // others are not green
			}
		}
		this.assertEquals(this.correctAnswers, countFound); // correct number found
		this.assertEquals("highlight", this.tool);
	},

	addWidgetButtons: function() {

		// adding widget buttons
		// this.controls.addButton({type: "reset", position: 1, identifier: "Reset", label: "Reset"});
		this.controls.addButton({type: "quizAnte", position: 4, identifier: "Ante", label: "Ante"});
		this.controls.addButton({type: "quizPost", position: 10, identifier: "Post", label: "Post"});
		this.controls.addButton({type: "quizStart", position: 7, identifier: "Start", label: "Start"});

		/*
		this.controls.addButton({type: "play", position: 1, identifier: "PlayButton", label: "Play"});
		this.controls.addButton({type: "play-pause", position: 2, identifier: "play-pause"});
		this.controls.addButton({type: "next", position: 6, identifier: "Next"});
		this.controls.addButton({type: "prev", position: 7, identifier: "Prev"});

		// adding radio options
		this.viewTypeRadioButton = this.controls.addRadioButton({identifier: "ViewType",
			label: "View",
			options: ["Norm", "X-ray", "Iso"],
			default: "Norm"
		});

		//Would like to add pan in future
		this.pointerTypeRadioButton = this.controls.addRadioButton({identifier: "PointerType",
			label: "Pointer",
			options: ["Sel", "Dis", "Spin"],
			default: "Sel"
		});

		this.modelTypeRadioButton = this.controls.addRadioButton({identifier: "ModelType",
			label: "Model",
			options: ["Heart", "Male", "Quiz"],
			default: "Quiz"
		});

		this.modelTypeRadioButton = this.controls.addRadioButton({identifier: "QuizType",
			label: "Quiz",
			options: ["Ante", "Post"],
			default: "Ante"
		});
		*/

		this.controls.finishedAddingControls();
		//console.log(this.controls.addButtonType);
		this.enableControls = true;
	},

	/**
	* To enable right click context menu support this function needs to be present.
	*
	* Must return an array of entries. An entry is an object with three properties:
	*	description: what is to be displayed to the viewer.
	*	callback: String containing the name of the function to activate in the app. It must exist.
	*	parameters: an object with specified datafields to be given to the function.
	*		The following attributes will be automatically added by server.
	*			serverDate, on the return back, server will fill this with time object.
	*			clientId, unique identifier (ip and port) for the client that selected entry.
	*			clientName, the name input for their pointer. Note: users are not required to do so.
	*			clientInput, if entry is marked as input, the value will be in this property. See pdf_viewer.js for example.
	*		Further parameters can be added. See pdf_view.js for example.
	*/
	getContextEntries: function() {
		var entries = [];

		var entry   = {};
		// label of them menu
		entry.description = "Start quiz: " + this.state.quizName;
		// callback
		entry.callback = "quizStart";
		// parameters of the callback function
		entry.parameters     = {};
		entries.push(entry);

		entry = {};
		entry.description = "Reset";
		entry.callback = "reset";
		entry.parameters = {};
		entries.push(entry);

		/*entry = {};
		entry.description = "Load saved location";
		entry.callback = "loadDefault";
		entry.parameters = {};
		entries.push(entry);*/

		entries.push({description: "separator"});

		return entries;
	},

	// private helper function that pads out a given number to two digits.
	checkTime: function(i) {
		if (i < 10) {
			i = "0" + i;
		}
		return i;
	},

	// private helper function to start the clock ticking.
	startClock: function () {
		var _this = this;
		var totalSeconds = 0;
		var min = 0;
		var sec = 0;

		this.interval = setInterval(function () {
			totalSeconds += 1;

			min = Math.floor(totalSeconds / 60);
			sec = parseInt(totalSeconds % 60);

			//document.getElementById("hour" + self.id).textContent = ("Time: " + Math.floor(totalSeconds / 3600) + " : ");
			_this.quizMinDOM.textContent = _this.checkTime(min);
			_this.quizSecDOM.textContent = _this.checkTime(sec);

			// Stop clock at timelimit
			if (min === _this.quizTimeLimit) {
				_this.pauseClock();
				_this.setQuizState("Quiz Stopped");
				_this.invariant();
			}
		}, 1000);
	},

	// private helper function to stop the clock.
	pauseClock: function () {
		//console.log(this.interval);
		if (this.interval !== 0) {
			clearInterval(this.interval);
			this.interval = 0;
		}
	},

	// private helper function
	quizSetup: function() {
		var _this = this;
		// this.quizBeenSetup = true;
		//reads quiz .json file and adds items to quizList
		var quizPath = this.resrcPath + this.state.quizName + ".json";

		var xhr = new XMLHttpRequest();
		xhr.onreadystatechange = function() {
			if (xhr.readyState === 4) {
				if (xhr.status === 200 || xhr.status === 0) {
					var obj = JSON.parse(xhr.responseText);

					_this.window = obj.window;
					_this.numQuestions = obj.number;
					_this.quizTimeLimit = obj.timeLimitMin;

					_this.quizTargetDOM.innerHTML = "Find all these items:";

					_this.QUIZ_OBJECTS = obj.questions;
					_this.model = obj.model + _this.state.dk;
					_this.humanIframe.src = _this.model;

					_this.setQuizState("Quiz Loaded");
				}
			}
			_this.invariant();
		};

		xhr.open("GET", quizPath, true);
		xhr.setRequestHeader("Content-Type", "text/plain");
		xhr.send(null);
	},

	quizStart: function() {
		// if the quiz is not showing, we show the quiz panel and fire off on(human.ready).
		// otherwise, we do nothing, because we are waiting for on(human.ready).
		if (!(this.isQuizShowing)) {
			var _this = this;
			this.isQuizShowing = true;
			this.correctAnswers = 0;
			this.missed = 0;
			this.resetQuizItems();

			this.quizPanelDOM.style.fontSize = this.fontSize + "px";
			this.quizResponseDOM.style.fontSize = this.fontSize * 1.05 + "px";
			this.quizTargetDOM.style.fontSize = this.fontSize + "px";
			this.quizTargetDOM.innerHTML = "Find all these items:";
			this.quizSelDOM.style.fontSize = this.fontSize + "px";
			this.quizListDOM.style.fontSize = this.fontSize + "px";
			this.quizListDOM.style.color = "black";
			this.quizListDOM.innerHTML = "";
			this.quizMinDOM.textContent = "00";
			this.quizSecDOM.textContent = "00";
			this.quizMissesDOM.innerHTML = this.checkTime(this.missed);
			this.quizPanelDOM.style.display = "block";

			// disable labels + tooltips + annotations
			// this.human.send("labels.setEnabled", {enable: false});
			this.getHumanAPI().send("tooltips.setEnabled", {enable: false});
			this.getHumanAPI().send("annotations.setShown", {enable: false});
			this.getHumanAPI().send("ui.setDisplay", { all: false, info: false });
			this.getHumanAPI().send("camera.info", function(camera) {
				// console.log("Gathering camera info:");
				// console.log(JSON.stringify(camera));
				_this.currentZoom = camera.zoom;
			});

			console.log("on human ready...  " + this.id);
			this.getHumanAPI().on("human.ready", function() {
				// get a list of objects
				console.log("got human ready...  ", _this);
				// this.send("scene.info", _this.onHumanReady);
				this.send("scene.info", function (data){
					_this.onHumanReady(data);
				});
			});
			this.setQuizState("Quiz Starting");
			this.invariant();
		}
	},

	onHumanReady: function(data) {
		var _this = this;
		console.log("got scene.info...  ", _this);
		var sceneObjects = {};
		var i = 0;
		for (i = 0; i < _this.QUIZ_OBJECTS.length; i++) {
			var quizObject = _this.QUIZ_OBJECTS[i];
			quizObject.count = 0;
			quizObject.found = false;
		}
		// get global objects
		sceneObjects = data.objects;
		console.log("body parts: " + Object.keys(sceneObjects).length);
		for (var s in sceneObjects) {
			if (sceneObjects.hasOwnProperty(s)) {
				var object = sceneObjects[s];
				// for each of our quiz objects, find matching scene object
				for (i = 0; i < _this.QUIZ_OBJECTS.length; i++) {
					quizObject = _this.QUIZ_OBJECTS[i];
					var objectFound = _this.matchNames(object.name, quizObject.name);
					if (objectFound) {
						if (object.shown) {
							quizObject.count++;
							quizObject.id = object.objectId;
							// console.log(quizObject, object);
						}
					}
				}
			}
		}
		for (i = 0; i < _this.QUIZ_OBJECTS.length; i++) {
			quizObject = _this.QUIZ_OBJECTS[i];
			if (quizObject.count !== 1) {
				console.log("ambiguous/unknown item: ", quizObject);
			}
		}
		// start quiz
		for (i = 0; i < _this.QUIZ_OBJECTS.length; i++) {

			var liId = _this.QUIZ_OBJECTS[i].id + _this.id;
			console.log(liId);
			var li = document.createElement('li');
			li.setAttribute('id', liId);

			li.appendChild(document.createTextNode(_this.QUIZ_OBJECTS[i].name + "\n"));
			_this.quizListDOM.appendChild(li);
		}
		_this.startClock();
		_this.changeTool("highlight");
		_this.setQuizState("Quiz Started"); // or _this.state.quizName
		_this.invariant();
	},

	// private helper function, for Quiz
	// returns if a names match or contains b as a substring
	matchNames: function(a, b) {
		return a === b || a.trim().toLowerCase().indexOf(b.trim().toLowerCase()) > -1;
	},

	/*Not currently used
	btnAnnotateClick: function(){
		this.parent.tool = "annotate"; // select
		console.log('usc_biodigital> Annotate Button');
		this.parent.human.send("input.enable");
		this.parent.changeTool();
	},*/

	// private helper function
	changeTool: function(tool) {
		var oldTool = this.tool;
		this.getHumanAPI().send("scene.pickingMode", tool);
		this.tool = tool;
		this.getHumanAPI().on("scene.pickingModeUpdated", function(event) {
			console.log("changed tool to " + event.pickingMode + " (from " + oldTool + ")");
		});
	},

	load: function(date) {
		console.log('usc_biodigital> Load with state value', this.state.value);
		this.refresh(date);
		this.invariant();
	},

	draw: function(date) {
	},

	resize: function(date) {
		// Called when window is resized
		var w = this.element.clientWidth;
		var h = this.element.clientHeight;
		this.fontSize = this.element.clientHeight * 0.015;
		this.quizPanelDOM.style.fontSize = this.fontSize + "px";
		this.quizResponseDOM.style.fontSize = this.fontSize + "px";
		this.quizTargetDOM.style.fontSize = this.fontSize + "px";
		this.quizSelDOM.style.fontSize = this.fontSize + "px";
		this.quizListDOM.style.fontSize = this.fontSize + "px";

		this.humanIframe.width = w;
		//this.quizSetup();

		this.humanIframe.setAttribute("style", "width:" + w + "px");
		this.humanIframe.setAttribute("style", "height:" + h + "px");
		this.refresh(date);
		this.invariant();
	},

	move: function(date) {
		// Called when window is moved (set moveEvents to continuous)
		this.refresh(date);
		this.invariant();
	},

	quit: function() {
		// Make sure to delete stuff (timers, ...)
		this.pauseClock();
	},

	// private helper function to handle clicks on body parts during a quiz
	submitClick: function(object) {
		// Object is the ID of the body part clicked on
		// check if quiz selection matches user selection
		var isCorrectOut = false;

		for (var i = 0; i < this.QUIZ_OBJECTS.length; i++) {
			var quizItem = this.QUIZ_OBJECTS[i];
			if (this.matchNames(object, quizItem.id)) {
				isCorrectOut = true;
				if (!quizItem.found) {
					var listItem = document.getElementById(quizItem.id + this.id);
					listItem.style.color = "green";
					this.correctAnswers++;
					quizItem.found = true;
					this.soundCorrect.play();
				}
			}
		}
		if (!isCorrectOut) {
			this.missed++;
			this.quizMissesDOM.innerHTML = this.checkTime(this.missed);
			this.soundIncorrect.play();
		}
	},

	/* private helper function to reset 'found' and 'id' fields of quiz items. */
	resetQuizItems: function() {
		if (this.QUIZ_OBJECTS) {
			for (var i = 0; i < this.QUIZ_OBJECTS.length; i++) {
				var quizItem = this.QUIZ_OBJECTS[i];
				quizItem.found = false;
				quizItem.id = null;
			}
		}
	},

	// hides the quiz panel and goes to state: Quiz Unknown.
	reset: function() {
		// this.getHumanAPI().send("scene.reset");
		this.changeTool(this.defaultTool);
		// this.pointerTypeRadioButton.value = "Sel";
		// this.viewTypeRadioButton.value = "Norm";
		this.isQuizShowing = false;
		this.quizPanelDOM.style.display = "none";
		this.quizListDOM.innerHTML = "";
		this.humanIframe.width = this.element.clientWidth;
		this.pauseClock();
		var displayConfig = { all: false, info: false };
		this.getHumanAPI().send("ui.setDisplay", displayConfig);
		this.resetQuizItems();
		this.setQuizState("Quiz Unknown");
		this.invariant();
	},

	restartAllQuiz: function() {
		if (isMaster) {
			// This is an experiment hack, for up to 10 BioDigital Human apps.
			// It relies on the current SAGE2 app ID convention: app_NNN.
			// It will only work if not too many other apps have been created.
			// Is there a nicer way of finding all the running apps?

			//console.log("restartAllQuiz.");
			//for (var i = 0; i < 10; i++) {
			//	console.log("broadcast quizStart() to app_" + i);
			//	broadcast({app: "app_" + i, func: "quizStart", data: {}});
			//}
		}
		/*
		var i;
		var dom;
		this.isQuizShowing = false;
		for (i = 0; i++; i < 10) {
			// TODO: do we need to add '_' before number?
			dom = document.getElementById("quizPanel_app_" + i);
			dom.innerHTML = "none";
			dom = document.getElementById("quizList_app_" + i);
			dom.innerHTML = "";

			// Get this code working to do the following on all open apps
			// this.pauseClock();
			// var displayConfig = { all: false, info: false };
			// this.getHumanAPI().send("ui.setDisplay", displayConfig);
		}
		// this.setQuizState("Quiz Unknown");
		// this.invariant();
		*/
	},

	// private helper function
	toCamelCase: function(str) {
		return str.split("_").map(function(word, index) {
			// If it not the first word only upper case the first char and lowercase the rest.
			return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
		}).join(" ");
	},

	// private helper function
	// gets the BioDigital API, and creates it if necessary.
	getHumanAPI: function() {
		if (!('human' in this)) {
			// NOTE: we append this.id so that each instance has a unique id.
			// Otherwise the second, third,... instances do not respond to events.
			this.human = new HumanAPI(IFRAME_ID + this.id);
			console.log('CREATED human:', this.human, 'this.id=', this.id);
			//var _this = this;
			//this.human.send("camera.info", function(camera) {
			//	_this.currentZoom = camera.zoom;
			//});

			// Removing Navigation from Biodigital UI
			var displayConfig = { all: false, info: false };
			this.human.send("ui.setDisplay", displayConfig);
		}
		// } else if ('human' in this && !(this.quizBeenSetup)){
		// 	this.human.on("human.ready", function() {
		// 		_this.quizSetup();
		// 	});
		// };
		return this.human;
	},

	event: function(eventType, position, user_id, data, date) {
		// console.log('usc_biodigital> eventType, pos, user_id, data, dragging',
		// 		eventType, position, user_id, data, this.dragging);
		var _this = this;

		if (eventType === "pointerMove") {
			if (this.tool ==  "default" && this.dragging) {
				// move (orbit camera)
				var dx = (position.x - this.dragFromX) * -1;
				var dy = (position.y - this.dragFromY) * 200 / this.element.clientHeight;
				this.getHumanAPI().send('camera.orbit', { yaw: dx});
				this.dragFromX = position.x;
				this.getHumanAPI().send("camera.pan", {y: dy});
				this.dragFromY = position.y;
				this.refresh(date);
			}
			// All other events check the invariant.
			// But pointer moves are common and usually boring, so we skip the invariant.
			return;
		}

		if (eventType === "pointerPress" && (data.button === "left")) {

		// TODO: startQuiz here if not already running?

			//console.log("TEST x:" + position.x + " y: " + position.y);
			//console.log(this.element.clientHeight);
			var posY = position.y;
			var posX = position.x;
			// click
			if (this.tool ==  "default") {
				this.dragging = true;
				this.dragFromX = position.x;
				this.dragFromY = position.y;
			// 	console.log("You got the Quiz Restart button");
			} else {
				this.getHumanAPI().send("scene.pick", { x: posX, y: posY}, function (hit) {
					if (hit && _this.interval != 0) {
						var obj = JSON.parse(JSON.stringify(hit));
						var str = obj.objectId;
						// console.log("Hit: " + JSON.stringify(hit));
						_this.submitClick(str);
						// console.log("Hit Submited " + str);
						var str1 = str.split("-");
						var str2 = str1[1].substring(0, str1[1].length - 3);
						_this.quizSelDOM.innerHTML = _this.toCamelCase(str2);
						var nm = str + _this.id;
						var el = document.getElementById(nm);
						if (el == null) {
							hit = null;
						} else {
							//el.style.backgroundColor = "purple";
							// finish quiz
							if (_this.correctAnswers == _this.numQuestions && _this.interval != 0) {
								// var quizClock = _this.interval;
								_this.pauseClock();
								_this.quizListDOM.style.fontSize = (_this.fontSize * 2) + "px";
								_this.quizListDOM.style.color = "green";
								_this.quizListDOM.innerHTML = "Success!";
								// var misses = document.createElement("li");
								// misses.style.color = "red";
								// misses.appendChild(document.createTextNode("Misses: "+_this.missed));
								// _this.quizListDOM.appendChild(misses);
								//Send the Quiz data to MongoDB Database
								console.log("score = " + _this.correctAnswers);

								// code for database connection
								// var xhr = new XMLHttpRequest();
								// xhr.open('GET', 'http://localhost:3000?id=blank+,+score=3+,+quizClock='+quizClock);
								// xhr.onreadystatechange = function () {
								// 	var DONE = 4; // readyState 4 means the request is done.
								// 	var OK = 200; // status 200 is a successful return.
								// 	if (xhr.readyState === DONE) {
								// 		if (xhr.status === OK) 	{
								// 			console.log(xhr.responseText); // 'This is the returned text.'
								// 		} else {
								// 			console.log('error'+xhr.responseText);
								// 		}
								// 	} else {
								// 		console.log('Error: ' + xhr.status); // An error occurred during the request.
								// 	}
								// }
								// xhr.send(null);
								_this.setQuizState("Quiz Finished");
							}
						}
					}
					_this.invariant();
				});
				// todo is this needed?
				_this.getHumanAPI().send("scene.pick", {x: posX, y: posY, triggerActions: true});
			}
		} else if (eventType === "pointerRelease" && (data.button === "left")) {
			// click release

			this.dragging = false;
		} else if (eventType === "pointerScroll") {
			// Scroll events for zoom
			this.zoomInOut((data.wheelDelta / 10000.0) * -1);
			this.refresh(date);
		} else if (eventType === "keyboard") {
			if (data.character === "r") {
				this.getHumanAPI().send('camera.reset');
				this.refresh(date);
			}
			else if (data.character === "s") {
				this.reset(); // clear old found and id flags
				this.quizStart(); // go straight to Start without reloading quiz or model.
			}
			else if (data.character === "a") {
				this.restartAllQuiz();
			}
		} else if (eventType === "specialKey") {
			if (data.code === 37 && data.state === "down") {
				// left
				this.getHumanAPI().send('camera.pan', { x: -PAN_STEP, y: 0.0 });
				// console.log('usc_biodigital> camera.pan left');
				this.refresh(date);
			} else if (data.code === 38 && data.state === "down") {
				// up
				this.getHumanAPI().send('camera.pan', { x: 0.0, y: -PAN_STEP });
				// console.log('usc_biodigital> camera.pan up');
				this.refresh(date);
			} else if (data.code === 39 && data.state === "down") {
				// right
				this.getHumanAPI().send('camera.pan', { x: PAN_STEP, y: 0.0 });
				// console.log('usc_biodigital> camera.pan right');
				this.refresh(date);
			} else if (data.code === 40 && data.state === "down") {
				// down
				this.getHumanAPI().send('camera.pan', { x: 0.0, y: PAN_STEP });
				// console.log('usc_biodigital> camera.pan down');
				this.refresh(date);
			}
		} else if (eventType === "pointerDblClick") {
			//Add code to switch between pointer options
		} else if (eventType === "widgetEvent") {
			//console.log(data.identifier);
			switch (data.identifier) {
				case "Reset":
					console.log("usc_biodigital> Reset Widget");
					this.reset();
					break;

				case "Quiz":
					console.log("usc_biodigital> Quiz started!");
					this.quizSetup();
					break;

				case "PlayButton":
					console.log('usc_biodigital> Play Widget');
					this.getHumanAPI().send("timeline.play", { loop: true });
					break;

				case "play-pause":
					console.log('usc_biodigital> Pause Widget');
					this.getHumanAPI().send("timeline.pause", { loop: true });
					break;

				case "Next":
					console.log('usc_biodigital> Next Widget');
					this.getHumanAPI().send("timeline.nextChapter");
					break;

				case "Prev":
					console.log('usc_biodigital> Previous Widget');
					this.getHumanAPI().send("timeline.previousChapter");
					break;

				case "Ante":
					console.log("usc_biodigital> Starting Anterior Quiz");
					this.state.quizName = "quiz_anterior";
					this.reset();
					this.quizSetup();
					break;

				case "Post":
					console.log("usc_biodigital> Starting Posterior Quiz");
					this.state.quizName = "quiz_posterior";
					this.reset();
					this.quizSetup();
					break;

				case "Start":
					console.log("usc_biodigital> Starting the quiz");
					this.reset(); // clear old found and id flags
					this.quizStart(); // go straight to Start without reloading quiz or model.
					break;

				case "ViewType":
					// console.log(data.value);
					switch (data.value) {
						case "Norm":
							console.log('usc_biodigital> Normal Option');
							this.getHumanAPI().send("scene.disableXray");
							this.getHumanAPI().send("scene.selectionMode", "highlight");
							break;

						case "X-ray":
							console.log('usc_biodigital> XRay Option');
							this.getHumanAPI().send("scene.enableXray");
							this.getHumanAPI().send("scene.selectionMode", "highlight");
							break;

						case "Iso":
							console.log('usc_biodigital> Isolate Option');
							this.getHumanAPI().send("scene.selectionMode", "isolate");
							break;

						default:
							console.log("Error: unknown ViewType option");
							break;

					}
					break;

				case "PointerType":
					switch (data.value) {
						case "Sel":
							console.log('usc_biodigital> Select Option');
							this.changeTool("highlight");
							break;

						case "Dis":
							console.log('usc_biodigital> Dissect Option');
							this.changeTool("dissect");
							break;

						case "Spin":
							console.log('usc_biodigital> Spin Option');
							this.changeTool("default");
							break;

						default:
							console.log("Error: unknown PointerType option");
							break;
					}
					break;

				case "ModelType":
					switch (data.value) {
						case "Heart":
							console.log("usc_biodigital> Reinitalising with heart model");
							this.humanIframe.src = "https://human.biodigital.com/widget" +
								"?be=1to1&pre=false&background=255,255,255,51,64,77&dk=" +
								this.state.dk;
							this.reset();
							this.pointerTypeRadioButton.value = "Spin";
							break;

						case "Male":
							console.log("usc_biodigital> Reinitalising with male model");
							this.humanIframe.src = "https://human.biodigital.com/widget" +
								"?be=1ud8&pre=false&background=255,255,255,51,64,77&dk=" +
								this.state.dk;
							this.reset();
							this.pointerTypeRadioButton.value = "Spin";
							break;

						case "Quiz":
							console.log("usc_biodigital> Reinitalising with quiz model");
							this.humanIframe.src = "https://human.biodigital.com/widget" +
								"?be=1fLs&pre=false&background=255,255,255,51,64,77&dk=" +
								this.state.dk;
							this.reset();
							this.pointerTypeRadioButton.value = "Spin";
							break;

						default:
							console.log("Error: unknown ModelType option");
							break;
					}
					break;

				case "QuizType":
					switch (data.value) {
						case "Ante":
							console.log("usc_biodigital> Starting Anterior Quiz");
							this.state.quizName = "quiz_anterior";
							this.quizSetup();
							break;

						case "Post":
							console.log("usc_biodigital> Starting Posterior Quiz");
							this.state.quizName = "quiz_posterior";
							this.quizSetup();
							break;

						default:
							console.log("Error: unkown QuizType option");
							break;
					}
					break;

				default:
					console.log("Error: unkown widget");
					console.log(eventType, position, user_id, data, date);
			}
			this.refresh(date);
		}
		this.invariant();
	},

	zoomInOut: function(delta) {
		// Zoom IN (positive delta) or OUT (negative delta)
		// Zoom levels are from 0.0 .. 1.0, so use small delta values!
		this.currentZoom = Math.max(0.0, Math.min(1.0, this.currentZoom + delta));
		this.getHumanAPI().send('camera.zoom', this.currentZoom);
		//console.log('usc_biodigital> scroll to zoom', this.currentZoom);
		this.invariant();
	}
});


The Penthouse is steeped in glamour which is celebrated and heightened in every detail, from parquet flooring to the bespoke cornicing, as well as benefiting from a private roof terrace and direct lift access.
A unique and newly refurbished duplex apartment in the heart of Fitzrovia. This Two / Three bedroom apartment has been meticulously designed throughout and is a hidden gem in one of London's most vibrant postcodes.
A recently refurbished one bedroom apartment situated on the second floor (with lift) in a modern development of 9 apartments located in the heart of Soho close to the Soho Hotel..


text:
Clinical & Translational Science Institute Degree Programs | NYU Langone Health
Clinical & Translational Science Institute Education Clinical & Translational Science Institute Degree Programs
Clinical & Translational Science
Services for Investigators
MS in Clinical Investigation
Certificate & Training Programs
Online Learning Programs
Career Development Programs
Community Engagement & Population Health Research Program
sIRB Alliance
Clinical & Translational Science Institute Degree Programs
The Clinical and Translational Science Institute offers a variety of master's-level science programs for students at NYU Grossman School of Medicine who are interested in pursuing translational and clinical research.
As a master of science in clinical investigation (MSCI) candidate, you prepare for a career in translational research by working closely with distinguished faculty and research mentors to gain foundational knowledge in research methods that support the development of new drugs and devices. We offer several different concentrations in the two-year program.
Students who pursue the translational research concentration learn about research methodologies and develop the skills to successfully conduct independent translational research.
Health Innovations and Therapeutics
In our health innovations and therapeutics concentration, students learn how to accelerate the movement of scientific knowledge into the clinic and bridge the ever-narrowing gap between basic science and the innovations that bring it into practical use.
Learn more about the translational research and health innovations and therapeutics concentrations in our MS in Clinical Investigation program.
Comparative Effectiveness Research
Offered through NYU Langone's Department of Population Health, the concentration in comparative effectiveness research is for researchers who wish to explore the way disease treatment and prevention strategies affect particular patient populations in specific circumstances. Learn more about the comparative effectiveness concentration.
MD/MS in Translational Research
This five-year, dual degree program is designed for medical students who wish to earn their medical degree and the MS with a concentration in translational research at the same time. Learn more about the MD/MS in Translational Research.
Related Bioinformatics Degrees
Several bioinformatics programs at NYU Langone's Sackler Institute of Graduate Biomedical Sciences complement our dual degree and MSCI programs in translational and clinical research.
In the one-year MS in Biomedical Informatics program, students learn to create novel computational methods to solve challenging problems in biomedical research. Learn more about the MS in Biomedical Informatics.
Systems and Computational Biomedicine PhD Training Program
In the three-year Systems and Computational Biomedicine PhD Training Program, doctoral candidates are trained to design and implement methods for capturing, storing, and retrieving clinical and population-level data for translational research. Learn more about the Systems and Computational Biomedicine PhD Training Program.

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Can SES SMTP User Credentials be reused for multiple EC2 instances, or does it get tied to one instance after it has been used? I have been trying to send emails using sendmail configured with AWS's SES. I've had some trouble with one instance. Then after some trouble shooting and fixing things around, I had an smtp credentials generated from AWS IAM. I put that in my /etc/mail/authinfo and followed the necessary steps. Once I did this, I was able to send mail through SES.
I tried using the same smtp credentials on another instance using AWS SES and Sendmail linking (literally followed the same procedure). However, I keep on this error in /var/mail/my_user_name
530 Authentication required
554 5.0.0 Service unavailable

So, the question is, can the SES smtp user credentials be reused for multiple instances? In other words, does it get tied to an IP/Instance once its been used?
I am on connecting via an EC2 ubuntu instance and have all the required sudo privileges.

redpajama_set_name: RedPajamaStackExchange


Television advertising seems to be increasingly trying to sell by associating their products with good emotions. Using positive emotions has probably always been integral to advertising, but lately, it seems to me that advertisers are saying nothing about the quality or price of their goods or services. A good example is the recent Fedex campaign. The gist of the campaign is that FedEx delivers comfort, or love, hope, encouragement, support and so on. The campaign says nothing about FedEx delivering on time, at a competitive price, and without damage to the delivered item.
It is also probably true that both UPS and the good, old U.S.Post Office deliver just as much comfort, love, hope, encouragement, and support as FedEx.
This trend in its modern manifestation may have started with the Nike slogan Just Do It. The strong implication was that one could just do it better if one were wearing Nike shoes; and one could do it much, much better in an expensive pair of Air Jordans.
Automobile advertising uses the same approach. If you buy a particular make and model of car, you can be just like Matthew McConaughey, sitting on a beach drinking whiskey and looking cool, or thinking profound thoughts on a road trip through a scenic desert.
On the Shores Of Gitche Gumee * . . .
September 27, 2018 by Steven C SorensenLeave a Comment on On the Shores Of Gitche Gumee * . . .
. . . actually, Lake Superior; the western shore of the Chequamegon Peninsula in Bayfield County, Wisconsin between Port Wing and Cornucopia. This stretch of shoreline has crescent-shaped, sandy beaches separated by rocky headlands and occasional sloughs where streams enter Lake Superior.
It's one of my favorite places. I hope these photos give an idea of why I like the area so much. Yesterday, the water was tan and cloudy. I think it was because of suspended sand blown to this side of the lake by northwesterly winds.
I don't know the names of any of these mushrooms. My friend and bartender Nick assures me that the best book for learning how to identify mushrooms is Mushrooms Demystified by David Arora. I've ordered the book, so maybe in the future I'll be able to add captions to such photos.
Moments of happiness often pass by quickly; sometimes so fleetingly that you miss them. Catch them if you can and savour them.
Happiness rolled over him, he felt suddenly warm. Perhaps, he thought, paradise goes by in an instant. When you're not looking.
The queerest thing it was, to hear such misery and, just for a moment, to know the joy of a fresh draft of air in the lungs, to feel a vague and, perhaps, traitorous promise.
These are the best shots from my last week of shooting.
I recently spent three days in a hotel while waiting for the carpet in my apartment to be replaced. The hotel was an hour closer to some of my favorite photography sites, so I went out with my camera gear rather than spending the evening cooped up in a hotel room. Here are some of the shots I captured.
A fly trapped in the sap exuded by an Easter Lily's stigma. Taken at the Como Park Conservatory in St. Paul, Minnesota.
Fly trapped in the sap exuded by an Easter Lily's stigma.
I'm on my sofa watching the season opener for the Minnesota Twins. They are in Baltimore where it's 68° and sunny. It's also sunny here in Stillwater but only 38°.
This is the earliest opening day ever. The season usually doesn't open until a week into April. I think it's being done to give the players more days off during the season.
If you can't watch or attend a game today, you could check out John Fogerty's* song about baseball, Centerfield.
And you can tell that one goodbye!
I'm ill; have been for two months. Lying in bed with my CPAP mask helping my lungs do their job.
I can feel the congestion, like a sore throat in my lungs; feel the tiredness that is sometimes overwhelming.
My bedroom is a pleasant room.
It's spring even though it snowed overnight. Now it's early afternoon and the snow has melted.
Windows are wide open. I can feel the cool, fresh spring air.
I hear the birds: a woodpecker hammering, sparrows chattering, a cardinal loudly defending his territory.
Out of my other ear I'm listening to My Top Rated iTunes playlist.
I actually live down by the river and behind the levee. I haven't been down there lately 'cause I can't lick this bronchitis. So I just keep doin' what I can.
Enjoy the good moments when they come.
I changed this site's theme after leaning I was using an unsupported theme. Imagine my surprise when I found out – just now – that the new theme I selected and customized is also an out-of-date theme. Frustrating!
This is my least-favorite time of year. Once the calendar tells me it's spring, I expect blues skies and warm air. I usually get winter storms. I never learn that here in Minnesota we can't expect winter to leave for good until well into April.
So, to counter any depression-type blues caused by the lingering winter, I've posted some photos featuring blue-skies-type blues.
WordPress tells me that they no longer support the theme I've used for years for this blog. So I have to switch. While I'm in the midst of re-designing, the blog may sometimes not look or behave well. I hope to get everything straightened out before too long.
Mavis Staples gives the lyrics much greater emotional impact.
Buddy Guy takes the lead on "Skin Deep", a song in similar vein produced by Playing For Change. He's joined by more than 50 other musicians spread across the U.S. in this song that tells us that "Underneath We Are All the Same." The video starts with a quote from Martin Luther King.
Darkness cannot drive out darkness.
This is very, very ugly. Dodge Ram Trucks using an inspirational, Martin Luther King speech to sell trucks in a Super Bowl commercial. What's next, using the Sermon on the Mount to sell mini-vans?
Different perspectives – same flower, a gerbera daisy.
Hey, Joe, how are you?
I'm fine, thanks, What about you?
Now that the two have gotten the preliminaries out of the way, they can proceed to having a good talk.
I've lately been trying to find another way to answer the question "How are you?"; some version of which is heard in just about every meeting of two people. If I took the time to answer the question truthfully it would take twenty minutes and be boring and depressing. Does anyone actually want to know the truth? My niece says she does.
My most recent ploy is to use phrases borrowed from song lyrics. Here are the two phrases I've tried thus far.
If it gets any worse, I'll be in a hearse.
This hasn't worked so well. It just invites more questions, and I quickly have to admit that I'm not serious, and that I just wanted to use the lyric in a conversation.
The second line is from Ghost Woman Blues ² from the album Smart Flesh by The Low Anthem.
I ain't no lamp, but my wick is burning low.
This also doesn't work so well. It just causes worry on the part of the other person and a desire to know more about why I'm so down; not to mention tons of advice on what I should do to fight off my black dogs of depression and insomnia.
I can try it but somehow I don't think it will work.
I've compiled my favorite photos from December in a video that is available on YouTube.
Amazon just sent me, "a valued member of Amazon Prime", an e-mail telling me they are raising the price for Prime from $10.99 to $12.99. Two dollars a month doesn't seem like much, but it's an 18% increase. How does Amazon justify an 18% increase when inflation has been negligible for years and Amazon has been raking in the profits? Jeff Bezos, the founder of Amazon, is now the richest person in the world. Money Magazine estimates his net worth at a paltry $90.6 billion.
. . . the core of the Frightful Five's indomitability. They have each built several enormous technologies that are central to just about everything we do with computers. In tech jargon, they own many of the world's most valuable "platforms" — the basic building blocks on which every other business, even would-be competitors, depend.
These platforms are inescapable; you may opt out of one or two of them, but together, they form a gilded mesh blanketing the entire economy.
So why is [many expletives deleted] Amazon demanding from me, just an old schmuck on a fixed income, an extra two dollars a month?
Should I cancel or just roll over in a submissive posture and accept the increase?
Any reasonably coherent answers will be appreciated.
The first beautiful place is next to a glacier in the Arctic, with beautiful music done by Ludovico Einaudi. The video was put together by Greenpeace and voicesforthearctic.org. Notice how Ludovico gasps in surprise at the beginning of the video when startled by falling ice . No trick photography in this video – He is there.
Then there is Plitvice Lakes National Park in Croatia. 2CELLOS, Luka Sulic and Stjepan Hauser, perform a Mumford & Sons song.
Enjoy this beautiful music and then do everything you can to help protect the wonderful places on our beautiful planet, the only one we've got.
Countries, societies, people all over the world want to value, treasure, and protect our beautiful, natural places whether in the Arctic, a National Park in Croatia, or Bears Ears National Monument in Utah . We in the United States have a president and an administration that do not share these values. They want to remove protections so that our natural heritage can be exploited for financial gain by a few grasping individuals and corporations. Don't let them steal what is ours.
I've compiled my favorite photos from November in a video that is available on YouTube.
Sorry, this isn't about the Disney movie, it's about my day out in the cold working on my project to photograph the Chippewa River from source to end. It was cold: 2° F with a wind chill of -10°. I was not uncomfortable because I dressed for the weather. (I recently purchased what I suspect was the last pair of XXL long johns in Stillwater. I admit my outfit was not very fashionable, but it worked.) The only problem was my hands. I had to take off my choppers to take photos. In areas exposed to the wind, I could only manage two or three shots until my hands became too numb to operate the camera.
When I stood still, all I could hear was the wind hissing through the dry grass and the river ice occasionally booming and popping. When I walked, I heard the fresh snow squeaking beneath my boots and the old, frozen boards of the bridge deck creaking and snapping under my weight. I didn't see another soul all afternoon.
Some of the lyrics from the song "Give God the Blues" by Shawn Mullins off the album Mercyland: Hymns For the Rest Of Us.
The entire Mercyland album is well worth checking out. It's a compilation with various artists: Emmy Lou Harris, The Civil Wars, The North Mississippi Allstars, The Carolina Chocolate Drops, and others, all providing hymns a bit different from those you hear in church.
I've been swamped in pessimism lately; pessimism that threatens to become cynicism. The problem is that I don't want to be either a pessimist or a cynic, but I thought that all the evidence I was seeing or hearing about the world today suggested that pessimism was justified. Is it? Even if it is justified, would it be possible to somehow escape the clutches of pessimism?
I talked to my good friend Nick, the potter and bartender. He wisely pointed out that pessimism leads nowhere and produces nothing except despair. He helped me realize that even though intellectually I was wallowing in pessimism, I'm living as if I were an optimist – doing new things, seeking new challenges, always trying to develop my skills and educate myself.
Then, I stumbled across three things this morning.
I've been meaning to weigh in on the latest raft of pieces about the decline of American democracy, the decline of Western liberalism, the decline of globalism, and the decline of everything else in the era of Trump. In a nutshell, I'm far more optimistic than most of the people writing about this. Unfortunately, I haven't really thought the whole thing through rigorously enough to make a little essay out of it.
After watching that video, how can one possibly remain a pessimist, much less a cynic?
Change is gonna come from each one of us. As Red Green would say, "We're all in this together." Stay positive and keep the faith.
Happy New Year and best wishes to all during 2018.
A few years ago I took a photo of two, left-hand-turn signs in a field of fresh snow against a cloudless blue sky. It's one of my favorite photos. In the intervening years, left-hand-turn signs have continued to grab my attention until now I have a small gallery of such photos.
The day before yesterday I finished "In a Dark, Dark Wood", the scary thriller by Ruth Ware*. Yesterday I unexpectedly found myself in a dark wood.
My hike took longer than expected, and I forgot that daylight savings time ended recently. It gets dark very early these days.
So I'm trudging through a dark wood. There is absolutely no wind, and no creatures are stirring, not even a mouse. They have all gone south or into hibernation for the winter or have bedded down for the evening. I can hear a jet far up in the sky but nothing else. It's actually a beautiful evening. More than once I stop to enjoy the quiet and the beauty of the color left behind by the setting sun, color that shows brightly in the crisp, clear evening air.
I was in the Dunnville Bottoms in the floodplain of the Chippewa River in Western Wisconsin. Here are some scenes from the dark, dark woods in the bottoms, mostly oak forests with many old, gnarly, spooky oaks.
I thought the book was neither scary nor thrilling, just an average, somewhat entertaining who-done-it.
* Lyrics from Stormy Weather written in 1933 by Harold Arlen and Ted Koehler and since covered many, many times.


text:
<!DOCTYPE html>

    <title>MP Home Page</title>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">

    <link rel="shortcut icon" href="favicon.ico">

    <link rel='stylesheet' type='text/css'
          href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600&subset=cyrillic,latin'>

    <link rel="stylesheet" href="<?= base_url(); ?>css/bootstrap.min.css">
    <link rel="stylesheet" href="<?= base_url(); ?>css/style.css">
    <link rel="stylesheet" href="<?= base_url(); ?>css/style-custom.css">
    <link rel="stylesheet" href="<?= base_url(); ?>css/app.css">
    <link rel="stylesheet" href="<?= base_url(); ?>css/admin.css">

                            Home

Bills

                            Budget »

2015/2016

2014/2015

Committees

Petitions

MPs

Q.F.O.A

                            Publications »

Blog

Analyses

Reports

                            Projects »

#MakeUrBudgetUg

Digital Outreach

Strengthening Accountability

                <select>
                    <option selected="selected" value="">Menu Selection</option>
                    <option value="http://localhost/pwug/">Home</option>
                    <option value="http://localhost/pwug/bills">Bills</option>
                    <option value="http://parliamentwatch.ug/budget/budget-process-201516/">Budget</option>
                    <option value="http://parliamentwatch.ug/budget/budget-process-201516/">2015/2016</option>
                    <option value="http://parliamentwatch.ug/budget-landing/">2014/2015</option>
                    <option value="http://localhost/pwug/committees">Committees</option>
                    <option value="http://parliamentwatch.ug/motions/">Petitions</option>
                    <option value="http://parliamentwatch.ug/mps">MPs</option>
                    <option value="http://parliamentwatch.ug/question">Q.F.O.A</option>
                    <option value="#">Publications</option>
                    <option value="http://localhost/pwug/category/editorial-analysis/">Blog</option>
                    <option value="http://localhost/pwug/category/analyses/">Analyses</option>
                    <option value="http://projects.parliamentwatch.ug">Reports</option>
                    <option value="#">Projects</option>
                    <option value="http://localhost/pwug/makeurbudgetug/">#MakeUrBudgetUg</option>
                    <option value="http://localhost/pwug/digital-outreach-2/">Digital Outreach</option>
                    <option value="http://projects.parliamentwatch.ug/">Strengthening Accountability</option>
                </select>

                        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                                data-target="#bs-example-navbar-collapse-1">
                            Toggle navigation

                        </button>

                            Administration Panel

Visit Site

                                    Manage MP's

Create/Manage

List Selection

                                    Manage Bills

Create/Manage

List Selection

                                    Manage Committees

Create/Manage

List Selection

                <form action="#" method="get">

                        <input class="form-control" id="system-search" name="q" placeholder="Search for" required>

                        <button type="submit" class="btn btn-default"></button>

                </form>

                        Full Name
                        Date of Appointment
                        Twitter Address
                        Date of Birth
                        Phone Number
                        Position
                        Constituency
                        Party
                        Office
                        Marital Satus

About Us

Parliament Watch Uganda is a virtual tracker that monitors the
                        Parliament of Uganda on a regular basis and provides both relevant data and expert
                        analysis.

Information

                                Hansards of Parliament

                                Opportunities

                                Subscribe to our
                                    Newsletter

                                Newsletter Archives

Disclaimer

Parliament Watch Uganda is an independent Non Governmental
                        Organisation
                        and this is not a Government Website.

<![endif]-->

redpajama_set_name: RedPajamaGithub


text:
module RubyFeatures
  module Lazy

    ACTIVE_SUPPORT_LAZY_TARGETS = %w(
      action_view action_controller action_mailer
      active_record active_job
      i18n
    ).map(&:to_sym).freeze

    class << self
      def apply(target, &block)
        if RubyFeatures.active_support_available?
          target_namespace = RubyFeatures::Utils.underscore(target.split('::').first).to_sym

          if ACTIVE_SUPPORT_LAZY_TARGETS.include?(target_namespace)
            return ActiveSupport.on_load target_namespace, yield: true, &block
          end
        end

        yield
      end
    end

  end
end


What can I do in this situation, given I want to change the contract? Also, does the agency have the right to remove me from a project that the end client wants me to complete, purely on the basis of me not signing the contract? And what should I do if the agency says they won't change the contract?
Expert's Answer: Sadly this is a fairly common situation. The majority of contracts issued by small and medium-sized agencies have developed over the years to include IR35-friendly clauses. However, there are a handful of large agencies that issue their standard terms which contain unhelpful and damaging wording. More often than not, the large agency will flatly refuse to amend the contract, usually issuing a response along the lines of 'thousands of other contractors have accepted the contract without question, so why can't you?'.
Another issue is that the majority of agencies claim that their contracts are IR35-friendly. In your case, they appear the agency appears to have gone one step further, saying the contract has been 'verified by HMRC.' However unless this can be supported by evidence, then such a claim must be treated with caution. This sort of claim is a real problem in itself: unsuspecting contractors on the agency's books will undoubtedly assume that their entire arrangement falls outside of IR35, without stopping to consider their actual working practices. This could prove to be a very costly mistake!
Having said all of this, a poor contract that the agency won't change doesn't necessarily mean the contractor has no hope of being 'outside IR35'. It certainly doesn't make life easy – the contract is the Revenue's first port of call and hypothetical things (like having a genuine right of substitution) are difficult to prove if the contractual wording suggests otherwise. However, the working practices always make up the bulk of HMRC's attack and the contractor's defence. If you've got a brilliant contract but in reality your client treats you like an employee, HMRC will say the contract isn't worth the paper it's written on. Conversely, if your contract is not so good, but you are genuinely working and treated like a contractor, you should be ok.
This is a massive simplification of course and an IR35 enquiry can be arduous. Yet the key to success in an IR35 investigation is having an end client that understands the issues and doesn't 'put their foot in it' when questioned by the Revenue. The fact is; there are many contractors working under poor contracts, when in reality they are working like genuine businesses and, despite the contract, we would still be reasonably confident of successfully defending them in an IR35 case.
However in your circumstances, if you choose not to sign the contract, you probably will be removed from the project, even if the end client wants you there. You should also be aware that, typically, the client will have signed a contract with the agency that prevents the client from engaging you directly, so you should consider your options carefully, or seek professional advice tailored to your full circumstances.