Josef Dochterman
Web Developer
Resume Here
spirit2change@gmail.com
Cell 323 877 9394

Portfolio

Educational HTML5 Canvas/WebGL Video Games

Demonstrations of educational video games are available in person only. Please schedule a meeting with me to review them.

Features include:

  • Animated, interactive sprites with physics motion.
  • Drag and drop items.
  • Music, speech and sound effects.
  • Image viewer and text overlay editor with touch screen zoom and pan.
  • Educational games for mobile devices.


Educational Games for Children

Below are screenshots of educational children's games made with JavaScript, HTML5 & CSS. They run on iPad and desktop browsers.


Features:
  • Drag and drop toys
  • Simulated 3D scene panning

Features:
  • Modular and configurable game engine
  • Matching cards fly into place

Features:
  • Finger paint letters
  • Animated bee, spider and paint brush

Commercial Website Development

Website front ends developed in JavaScript, HTML & CSS.


Desktop View (click for large)
ViSalus Sciences Product Marketing

Desktop View (click for large)
ViSalus Sciences Product Marketing

Desktop View (click for large)
ViSalus Sciences Product Marketing

Mobile View (click for large)
ViSalus Sciences Product Marketing

Panasonic Business to business marketing

JavaScript Functors (Function Objects) Demo

One meaning of the word functor is a function object. This is an object which may be invoked as if it were a function.

The following code will create a functor:


function makeFunctor(data, fn)
{
	var newFn = function(){return fn.apply(newFn, arguments);};
	for(var k in data){newFn[k] = data[k];}
	return newFn;
}
		

Basic Functor Demo

The following code is a basic demonstration of a functor:

function basicFunctorDemo()
{
	var adder = makeFunctor({a: 0, b: 0}, function(){return this.a + this.b;});
	
	alert('The result of adder() is: ' + adder());
	
	adder.a = 2;
	adder.b = 3;
	
	alert('The new result of adder() is: ' + adder());
}
			

Using Functors to Solve Problems with Iteratively Creating Event Handler Functions

The Problem

These three buttons are initialized with the following code. There is an error because each event handler function uses the variable i, however i is declared in the scope of initButtonArea1, and will therefore have the same value within each of the event handler functions. Each button will say "Performing action #3" instead of performing separate actions as desired.

function initButtonArea1()
{
	var buttonAreaElt = document.getElementsByClassName('functorsArea')[0].getElementsByClassName('buttonArea')[0];
	var btnElts = buttonAreaElt.getElementsByTagName('button');
	
	for(var i=0; i < 3; ++i)
	{
		btnElts[i].addEventListener('click', function(){alert('Performing action #' + i);});
	}
}
				

The Solution with Functors

Using a functor solves this issue, because each functor has its own copy of i. These buttons work as expected.

function initButtonArea2()
{
	var buttonAreaElt = document.getElementsByClassName('functorsArea')[0].getElementsByClassName('buttonArea')[1];
	var btnElts = buttonAreaElt.getElementsByTagName('button');
	
	for(var i=0; i < 3; ++i)
	{
		btnElts[i].addEventListener('click', 
			makeFunctor(
				{i: i},
				function(){alert('Performing action #' + this.i);}
			)
		);
	}
}
				

JavaScript "Watcher" Demo

A Watcher is a JavaScript object which was invented for callback based programming.

Suppose you have three processes, P1, P2, and P3, and you want to begin running P1 and P2, then run P3 only after P1 and P2 have completed. A Watcher can accomplish this task by "watching" P1 and P2. When they are complete, the Watcher will begin P3. In application, P1 and P2 might represent AJAX calls, or sound and animation sequences.

In this demo, P1 and P2 will take a random amount of time to complete. When complete, their boxes will reach the far right side of the view area near the word "Done". P3 should begin moving to the right only after P1 and P2 have reached the far right.



Done
P1
P2
P3
Console output:

A Watcher is used as follows:


		
function WatcherDemo()
{
	this.running = false;
}

WatcherDemo.prototype.startProcess = function(processNum, callback)
{
	var elt = document.getElementById('watcher-div' + processNum);
	var durationMs = 1250 + Math.round(Math.random() * 3000);
	elt.style.transitionProperty = 'left';
	elt.style.transitionDuration = durationMs + 'ms';
	elt.style.left = '200px';
	var result = 'P' + processNum + ' result in ' + durationMs + 'ms time';
	
	if(callback){
		setTimeout(function(){callback(result);}, durationMs);
	}
}

WatcherDemo.prototype.step1 = function()
{
	var cbThis = this;
	this.watcher = new Watcher();
	this.startProcess(1, this.watcher.makeCallback('myP1Key')); // 'myP1Key' is an arbitrary key to identify the callback
	this.startProcess(2, this.watcher.makeCallback('myP2Key'));
	this.watcher.start(function(){cbThis.step2();});
}

WatcherDemo.prototype.step2 = function()
{
	var cbThis = this;
	var conElt = document.getElementById('watcher-consoleArea');
	conElt.innerHTML += 'Step 2:<br>';
	conElt.innerHTML += this.watcher.getCallbackArgs('myP1Key')[0] + '<br>'; // log the result of P1
	conElt.innerHTML += this.watcher.getCallbackArgs('myP2Key')[0] + '<br>'; // log the result of P2
	conElt.innerHTML += 'Starting P3<br>';
	this.startProcess(3, function(){cbThis.step3();});
}

WatcherDemo.prototype.step3 = function()
{
	var conElt = document.getElementById('watcher-consoleArea');
	conElt.innerHTML += 'Done';
	this.running = false;
	document.getElementById('watcher-startBtn').disabled = false;
}
		

Above, in step1, a watcher object is created, and used to create two callbacks. Each callback is assigned a key string to identify it later. step2 is invoked by the watcher after processes 1 and 2 are completed. Within step2, the arguments of the callbacks are retrieved through the watcher's getCallbackArgs(callbackKeyStr) method which returns the arguments array.

Below is the source code for the Watcher class:



/*
	events: calls event doneEvent(callbackArgs), where callbackArgs 
		is an array of argument arrays corresponding to each watched callback's arguments.
*/
function Watcher()
{
	this._callbacks = [];
	this._callbacksDone = [];
	this._callbackArgs = []; // array of argument arrays which are returned by callbacks
	this._callbackArgsByKey = {}; // map of callbackKeyStr to callback arguments array
	this._started = false;
}

/*
	Create a watched callback. 
	callbackKeyStr - an optional arbitrary string used to identify the newly created callback.
*/
Watcher.prototype.makeCallback = function(callbackKeyStr)
{
	if(arguments.length < 1){callbackKeyStr = '' + this._callbacks.length;}
	
	var callback = Utils.makeFunctor(
		{watcher: this, index: this._callbacks.length, callbackKeyStr: callbackKeyStr},
		function(){this.watcher._onCallback(this.index, this.callbackKeyStr, arguments);}
	);

	this._callbacks.push(callback);
	this._callbacksDone.push(false);
	this._callbackArgs.push([]);
	return callback;
}

/*
	Begin waiting for all watched callbacks to be called.
	callback will receive an array of argument arrays corresponding to each watched callback's arguments.
*/
Watcher.prototype.start = function(callback)
{
	this._started = true;
	Utils.addListener(this, 'doneEvent', callback);
	this._checkIfDone();
}

/*
	After all watched callbacks are complete, this method will retrieve the arguments for a watched callback.
	callbackKeyStr - the key string of the watched callback for which to retrieve arguments.
*/
Watcher.prototype.getCallbackArgs = function(callbackKeyStr)
{
	return this._callbackArgsByKey[callbackKeyStr];
}

/*
	returns true if all watched callbacks have been called
*/
Watcher.prototype.isCallbacksDone = function()
{
	for(var i=0; i < this._callbacksDone.length; ++i)
	{
		if(!this._callbacksDone[i]){return false;}
	}
	
	return true;
}

Watcher.prototype._onCallback = function(index, callbackKeyStr, args)
{
	this._callbacksDone[index] = true;
	this._callbackArgs[index] = args;
	this._callbackArgsByKey[callbackKeyStr] = args;
	this._checkIfDone();
}

Watcher.prototype._checkIfDone = function()
{
	if(!this._started || !this.isCallbacksDone()){return false;}
	if(this.doneEvent){this.doneEvent.apply(null, [this._callbackArgs]);}
	return true;
}

		
 

PHP MVC Unit Testing Code Sample

This code sample is an illustration of a controller that fits within an imaginary mini MVC framework, and a unit test for that controller.
 
The source files may be downloaded here.
 
PHP version 5.6 and PHPUnit 3.7.21 were used. The following command will run the tests:

phpunit --bootstrap ./src/MyController.php ./tests/MyControllerTest

Class MyController: the subject of the test

The MyController class is a simple controller which displays a "welcome" view to users who are not logged in, and a "dashboard" to users who are logged in. This controller is intended to be an illustration for the purpose of demonstrating unit testing, and fits within an imaginary MVC framework. The unit test for this controller is further below. MyController uses Dependency Injection and Factory design patterns to allow unit testing.
 

MyController.php

<?php

require_once 'MySession.php';
require_once 'UserDAO.php';
require_once 'ViewFactory.php';
require_once 'WelcomeView.php';
require_once 'DashboardView.php';

/**
	this class illustrates a controller within a mini mvc system.
*/
class MyController
{
	protected $userDAO; // used to access user data
	protected $mySession; // used to access data associated with the current logged in session
	protected $view; // the view which should be rendered after the controller finishes execution

	/**
		returns the controller's desired view object
		(for example, so that the view may be rendered by the ioc container that instantiated this controller)
	*/
	public function getView()
	{
		return $this->view;
	}
	
	/**
		call this to inject the UserDAO dependency
	*/
	public function setUserDAO($userDAO)
	{
		$this->userDAO = $userDAO;
	}

	/**
		call this to inject the MySession dependency
	*/
	public function setMySession($mySession)
	{
		$this->mySession = $mySession;
	}
	
	/**
		call this to inject the ViewFactory dependency
	*/
	public function setViewFactory($viewFactory)
	{
		$this->viewFactory = $viewFactory;
	}
	
	/**
		this is the controller's main logic.
		a requirement of this mini mvc framework is that main() must set $this->view to the desired view,
		and initialize that view with any needed variables.
		all dependencies must be injected before main() may be called.
	*/
	public function main()
	{
		// check the session to see if the user is logged in
		$loggedInUserId = $this->mySession->getUserId();

		if($loggedInUserId === null)
		{	// nobody is logged in, so show the WelcomeView
			$this->view = $this->viewFactory->getView('WelcomeView');
			$this->view->init();
		}
		else
		{	// a user is logged in, so show the DashboardView
			$userData = $this->userDAO->getUser($loggedInUserId);
			
			$this->view = $this->viewFactory->getView('DashboardView');
			$this->view->init(array(
				'userName' => $userData->userName,
				'userAge' => $userData->userAge
			));
		}
	}
}
		

Class MyControllerTest: The Unit Test for MyController

The following unit test for PHPUnit will test MyController for the case of no user logged in, and then for the cases of two different users logged in.

MyControllerTest.php

<?php

/**
	unit tests for MyController.
	this class illustrates how unit testing may be done 
	in an mvc framework using dependency injection and factory design patterns
*/
class MyControllerTest extends PHPUnit_Framework_TestCase
{
	private $myController;

	/**
		perform any operations needed to prepare for a test
	*/
	protected function setUp()
	{
		$this->myController = new MyController();		
	}

	/**
		provides an array of data for each test to run with testMain
	*/
	public function testMainProvider()
	{
		// userId, userName, userAge
		return array(
			array(null, null, null), // test with nobody logged in
			array(1111, 'Mr. Smith', 31), // test with a user logged in
			array(1112, 'Ms. Jones', 27), // test with a different user logged in
		);
	}
 
	/**
		test the main() method of the controller
		@dataProvider testMainProvider
	*/
	public function testMain($userId, $userName, $userAge)
	{
		//// mock MySession
		$mySessionMock = $this->getMockBuilder('MySession')
			->disableOriginalConstructor()
			->getMock();
		
		// the MySession object will provide the userId for a logged in user,
		// or null if nobody is logged in
		$mySessionMock->expects($this->once())
			->method('getUserId')
			->will($this->returnValue($userId));
		
		//// mock UserDAO
		// the data object to pass to the controller
		$userData = (object) array(
			'userName' => $userName,
			'userAge' => $userAge
		);
		
		$userDAOMock = $this->getMockBuilder('UserDAO')
			->disableOriginalConstructor()
			->getMock();
		
		if($userId === null)
		{
			$userDAOMock->expects($this->exactly(0))
				->method('getUser');
		}
		else
		{
			$userDAOMock->expects($this->once())
				->method('getUser')
				->will($this->returnValue($userData));
		}
		
		//// mock ViewFactory
		$viewFactoryMock = $this->getMockBuilder('ViewFactory')
			->disableOriginalConstructor()
			->getMock();
		
		// the ViewFactory expects a different view to be requested 
		// by the controller depending on the value of userId
		if($userId === null)
		{	// userId is null, so we expect a WelcomeView to be requested by the controller
			$expectedViewClassName = 'WelcomeView';
			$expectedViewMock = $this->getMockBuilder('WelcomeView')
				->disableOriginalConstructor()
				->getMock();
			
			$expectedViewMock->expects($this->once())
				->method('init');
		}
		else
		{	// userId is not null, so we expect a DashboardView to be requested by the conroller
			$expectedViewClassName = 'DashboardView';
			$expectedViewMock = $this->getMockBuilder('DashboardView')
				->disableOriginalConstructor()
				->getMock();
			
			// check the view was passed the correct user information
			$expectedViewMock->expects($this->once())
				->method('init')
				->with($this->callback(
					function($subject) use ($userName, $userAge) {
						return $subject['userName'] === $userName 
							&& $subject['userAge'] === $userAge;
					}
				));
		}
		
		$viewFactoryMock->expects($this->once())
			->method('getView')
			->with($this->equalTo($expectedViewClassName))
			->will($this->returnValue($expectedViewMock));
		
		//// Dependency Inject
		$this->myController->setMySession($mySessionMock);
		$this->myController->setUserDAO($userDAOMock);
		$this->myController->setViewFactory($viewFactoryMock);
		
		//// Run Functionality
		$this->myController->main();

		//// Assertions
		// check the controller responds with the correct view
		$this->assertEquals($expectedViewMock, $this->myController->getView());
    }
 
}