Top bar menu animation
Coming Soon!
Hello my name is Chris, I'm a software engineer based in Madison, WI USA.
I love all things Dojo, JavaScript, and also many server-side solutions.
As a software engineer for Sitepen, Inc., I develop enterprise level JavaScript web applications using the Dojo Toolkit, as well as contribute to the Dojo Foundation project dGrid, write documentation and tutorials for the toolkit.
During my tenure as a Academic Technologist at UW-Madison I developed several games and simulations, as well as integrated the djatoka image server into the Forward library portal. Before that, I supported and developed a health insurance application, and even before that I worked for a startup in the time and attendance industry. To view my full work history, click "Work Timeline" up above.




//function settradeaction is part of the DataController, every function in
//DataController is either called via XHRPost or XHRGet, it is the
//primary mechanism with which the front end javascript talks to the backend php
public function settradeAction() {
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
if($this->getRequest()->isXmlHttpRequest()) {
$sessionId = $this->_namespace->sId;
$profileId = $this->_namespace->profileId;
$tradingDate = $this->_namespace->date;
$currentDate = time();
$realDate = $this->_namespace->vdList[$tradingDate];
$formData = $this->getRequest()->getPost();
$json = stripslashes($formData['data']);
$dojoData = new Zend_Dojo_data();
$dojoData->fromJson($json);
$trade = new Model_Trade();
foreach ($dojoData as $item) {
//echo $item['title'] . ': ' . $item['description'] . "\n";
$long = $item['longForm'];
$short = (0-$item['shortForm']);
$margin = $item['marginReq'];
$monthId = $item['month'];
$price = $item['price'];
$commodityId = $item['commodityId'];
$quantity = $long + $short;
if((abs($margin) >0 || $monthId == 13)
&& abs($price) >0 && $quantity != 0) {
//then a trade needs to be processed
$trade->saveTrade((int)$sessionId,
(int)$commodityId,
(int)$monthId,
(int)$realdate,
(int)$tradingDate,
(int)$quantity,
$price,$margin, $profileId);
}
}
$rules = Model_ProfileRulesFactory::Create($profileId, $sessionId, $tradingDate,$realDate);
$rules->lastCall();
...
return "sucess";
}
}
/////////////////////////////////////
//end of controller example//////////
/////////////////////////////////////
//saveTrade is part of the trade model
public function saveTrade($sessionId,$commodityId,$monthId,$realDate,
$tradingDate,$quantity,$price,$margin,$profileId) {
//function saveTrade saves an user input trade
//(buy or sell, long or short - or cash trade) and updates all related records
// saves to assets, marginaccount, moneymarketaccount, orders, transactions
// saves to financialtransfer and transactionlog
//need to check if player has enough money to do this trade
$rules = Model_ProfileRulesFactory::Create($profileId, $sessionId, $tradingDate,$realDate);
$yay = $rules->saveTrade($commodityId,$monthId,$quantity);
if($yay) {
$log = new Model_TransactionLog();
if($quantity > 0) {
$log->saveLog($commodityId, $monthId, $price, self::B, $quantity, $tradingDate, $sessionId);
}
else {
$log->saveLog($commodityId, $monthId, $price, self::S, $quantity, $tradingDate, $sessionId);
}
$transaction = new Model_Transactions();
$transfer = new Model_FinancialTransfer();
//so we need to retrieve the list of current assets, and then
//determine which to buy and sell based off of transaction date
//update priceOut, quantity, and margin
$commodity = new Model_Commodities();
$commodity->find($commodityId);
$brokerFee = $commodity->getBrokerFee();
//inventory gets handled in the profilerules
/***Save Assets data **/
$contractSize = $commodity->getContractSize();
$marginReq = $commodity->getMargin();
$assets = $transaction->getPositionsByCommodity($sessionId, $commodityId,$monthId);
$totalReturn = 0;
//need to iterate through current assets of same commodity, month to alter position
foreach($assets as $transaction) {//asset is a model_transaction object
$oldQuantity = $transaction->getQuantity();
if(($oldQuantity < 0 && $quantity < 0) || ($oldQuantity > 0 && $quantity > 0)) {
//just add a new record, not an offset
$newTrans = new Model_Transactions();
$newTrans->setMonthId($monthId);
$newTrans->setCommodityId($commodityId);
$newTrans->setPriceIn($price);
$newTrans->setQuantity($quantity);
$newTrans->setTransactionDate($tradingDate);
$newTrans->setSessionId($sessionId);
$newTrans->setMargin($margin);
$newTrans->save();
$fee = $quantity * ($brokerFee/2) * -1;
//divided in half because the other half will be taken out when the position is offset
$transfer->saveMoneyMarket($fee, $sessionId, self::BROKER_FEE, $tradingDate);
$transfer->saveMoneyMarket((0-$margin), $sessionId, self::MARGIN_REQ, $tradingDate);
//increasing the margin requirements
$transfer->saveMarginAccount($margin, $sessionId, self::FROM_MM, $tradingDate);
$quantity = 0;
$totalReturn = 0;
break;
}
...
}
}
//This is a chunk of code that is called on each row of the pending grid.
//I needed a more powerful way of manipulating the data shown beyond normal formatter functions
dojo.declare("dojox.grid.formatterScopeObj", null, {
store: null,
margins: {},
totalMargin: 0,
constructor: function(kwArgs){
this.store = kwArgs.store;
//this.margins = [];
this.totalMargin = 0;
},
fmtBuySell: function(item) {
var long1 = store.getValue(item,"longForm");
var short1 = store.getValue(item,"shortForm");
var val = long1 - short1;
if(val > 0) {
return "B";
}
else {
return "S";
}
},
determinePosition: function(pendingItem,pendingMargin){
var identity = this.store.getIdentity(pendingItem);
var pendingPosition = this.fmtBuySell(pendingItem);//should be a B or S
var gotItem = function(item)
{
if(item == null)
{
return;
}
var position = positionStore.getValue(item,"position");
if(position == "Long" && pendingPosition == "S" || position == "Short" && pendingPosition == "B")
{
pendingMargin *= -1;//as in a reduction in margin
}
};
positionStore.fetchItemByIdentity({identity: identity, onItem: gotItem});
return pendingMargin;
},
updateMarginTotal: function(margin) {
if(typeof(margin)!== 'undefined')
{
this.totalMargin = margin;
}
var total = "Margin Change: " + dojo.currency.format(this.totalMargin, {currency: "USD"});
dijit.byId("marginTotal").set("content",total);
},
fmtMargin: function(item){
var identity = this.store.getIdentity(item);
var margin = 0;
var long1 = this.store.getValue(item,"longForm");
var short1 = 0;
short1 -= this.store.getValue(item,"shortForm");
var amount = short1 + long1;
if(!this.margins[identity]){
margin = this.store.getValue(item, "margin");
var marginReq = margin * Math.abs(amount);
if(amount != 0)
{
this.margins[identity] = amount;
marginReq = this.determinePosition(item,marginReq);
}
this.store.setValue(item, "marginReq", marginReq);
this.totalMargin +=marginReq;
this.updateMarginTotal();
}
else
{
if(this.margins[identity]==amount)
{//nothing changed
margin = this.store.getValue(item,'marginReq');
}
else
{//something has changed, need to rerun calculations
var margin = this.store.getValue(item,"marginReq");
margin2 = this.totalMargin - margin;
this.updateMarginTotal(margin2);
delete this.margins[identity];
this.fmtMargin(item);
}
}
return dojo.currency.format(margin, {currency: "USD"});
},
fmtCommodity: function(item)
{
if(this.store !== store)
{
console.log("stores do not match! ");
}
var long1 = this.store.getValue(item,"longForm");
var short1 = 0;
short1 -= this.store.getValue(item,"shortForm");
var commodity = this.store.getValue(item,"commodity");
var month = this.store.getValue(item,"monthName");
if(month != "Cash"){
month = month.substring(0,3);
}
var amount = short1 + long1;
return amount + " " + month + " " + commodity;
},
fmtItem: function(value, idx){
if(!this.store.isItem(value)){
return " ";
}
}
});
....
var pendingLayout = [{field:"_item",formatter: "fmtBuySell", width:"10%",name: "B/S"},
{field:"_item",formatter: "fmtCommodity", width:"10%",name: "Commodity"},
{field:"_item",formatter: "fmtMargin", width:"10%",name: "Margin"}
];
var formatObj = new dojox.grid.formatterScopeObj({store:store});
pendingGrid = new dojox.grid.DataGrid({selectionMode:"none",formatterScope: formatObj,query:"{!(shortForm:0 AND longForm:0) AND !price:0}", style:"height: 300px; width: 100%;", store:store,escapeHTMLInData:"false",id:"pendGrid",structure:pendingLayout},pos3);
dijit.byId("pendingGridPane").set("content",pendingGrid);
pendingGrid.startup();
#this is a test RoR app that uses the djatoka gem for the djatoka image viewer
class DjatokaController < ApplicationController
def index
@formats = [['image/jpeg','image/jpeg'],['image/gif','image/gif'],['image/png','image/png'],['image/jp2','image/jp2'],['image/pnm','image/prm'],['image/tiff','image/tiff'],['image/bmp','image/bmp']]
@rotates = [['None','0'],['90','90'],['180','180'],['270','270']]
@levels = [[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9],[10,10],['MAX','MAX']]
@tags = [['djatoka_smallbox_image_tag','djatoka_smallbox_image_tag'],
['djatoka_bottom_right_square_image_tag','djatoka_bottom_right_square_image_tag'],
['djatoka_top_left_square_image_tag','djatoka_top_left_square_image_tag'],
['djatoka_square_image_tag','djatoka_square_image_tag'],
['djatoka_image_tag','djatoka_image_tag']]
if !params[:resolver]
@default_pid = '1711.dl:2HZ3TEVNP3UA786'
@rftid = 'http://memory.loc.gov/gmd/gmd433/g4330/g4330/np000066.jp2' #default image
@resolver = 'http://depot-test.library.wisc.edu/adore-djatoka/resolver' #default server
@format = 'image/jpeg' #default image format
@rotate = 0 #rotate works in 90 degree increments
@level = 1 # 1-10 or "MAX"
@region = "" #four numbers delimited by commas, no spaces
@region1 = 0
@region2 = 0
@region3 = 0
@region4 = 0
@scale = 75 #as a default, it scales the height of the image to the value provided
@clevel = 0 #don't think this works, may need some certain type of jp2 image that has "layers"
@tag = "djatoka_image_tag"
else
@rftid = params[:rftid]
@pid = @rftid.match('1711.dl(%3A|:)[^/]+') ? @rftid.match('1711.dl(%3A|:)[^/]+')[0] : nil
@rftid = "http://depot-test.library.wisc.edu/repository/fedora/#{@pid}/datastreams/JP2/content" if @pid
@resolver = params[:resolver]
@format = params[:format]
@rotate = params[:rotate]
@level = params[:level]
@region1 = params[:region1]
@region2 = params[:region2]
@region3 = params[:region3]
@region4 = params[:region4]
@scale = params[:scale]
#@clevel = params[:clevel]
@tag = params[:tag]
# if(location.href.match('1711.dl(%3A|:)[^/]+'))
# @titleUrl = 'http://' + host + '/fedora/objects/' + pid + '/methods/1711.dl:SDefineUWDCObject/getTitle';
# else
# @titleUrl = 'http://' + host + '/title/' + pid;
if @region3 != "0" && @region4 != "0"
@region = "#{@region1},#{@region2},#{@region3},#{@region4}"
end #if
end #if
end #index
end #class
#End of controller
#Start of view
<!DOCTYPE html>
<html>
<head>
<title>Djatoka Gem Test App</title>
<%= csrf_meta_tag %>
</head>
<body>
<h1>Test us out some djatoka</h1>
<div id="container1" style="width:100%;"
<div id="image" style="width:50%;float:left;border: 1px;">
<%
# Available helpers:
# djatoka_smallbox_image_tag ( rft_id,params {}) params can be both djatoka query and image tag parameters
# djatoka_bottom_right_square_image_tag ()
# djatoka_top_left_square_image_tag ()
# djatoka_square_image_tag ()
# djatoka_image_tag ()
#with available parameters being: :scale, :class, :resolver, :format, :rotate, :clayer(doesn't work?), :region, :level
%>
<% if !@scale.nil? %>
<%= send(@tag.to_sym, @rftid, :scale => @scale,
:class => 'djatoka_image',
:alt => 'djatoka supplied image',
:id => 'djatokaImage',
:resolver => @resolver,
:format => @format,
:rotate => @rotate )%>
<% else %>
<%= send(@tag.to_sym, @rftid,
:class => 'djatoka_image',
:alt => 'djatoka supplied image',
:id => 'djatokaImage',
:resolver => @resolver,
:format => @format,
:rotate => @rotate )%>
<% end %>
URL: <%= @resolver %>?url_ver=Z39.88-2004
&svc_id=info:lanl-repo/svc/getRegion
&svc_val_fmt=info:ofi/fmt:kev:mtx:jpeg2000
&rft_id=<%= @rftid %>
&svc.scale=<%= @scale %>
&svc.format=<%= @format %>
&svc.rotate=<%= @rotate %>
&svc.level=<%= @level %>
&svc.region=<%= @region %>
</div>
<div id="form" style="width:50%;float:right;">
<h1>Configure Image</h1>
<%= form_tag :action =>'index', :id => 'djatokaForm' %>
<%= label_tag 'rftid' %>
<%= text_field_tag 'rftid', @rftid, "size" => 75 %>
<%= label_tag 'resolver' %>
<%= text_field_tag 'resolver', @resolver, "size" => 75 %>
<%= label_tag 'scale' %>
<%= text_field_tag 'scale', @scale, "size" => 20 %>
<%= label_tag 'format' %>
<%= select_tag 'format', options_for_select(@formats, @format) %>
<%= label_tag 'rotate' %>
<%= select_tag 'rotate', options_for_select(@rotates,@rotate) %>
<%= label_tag 'level' %>
<%= number_field_tag 'level', @level, :in => 1...10 %>
<%= label_tag 'region' %>
<%= number_field_tag 'region1', @region1 %>
<%= number_field_tag 'region2', @region2 %>
<%= number_field_tag 'region3', @region3 %>
<%= number_field_tag 'region4', @region4 %>
<%= label_tag 'Image Tag Format' %>
<%= select_tag 'tag', options_for_select(@tags,@tag) %>
<%= submit_tag 'Load' %>
#Quick load testing python script
#load tests a RoR app loading Jp2 images from the djatoka image server
from net.grinder.plugin.http import HTTPRequest
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
import os
#
# tag initialization of this module
grinder.logger.output( '[ test_runner.py ]' )
#
# initialize data sources for tests
data_dir = './data'
imgpids = open( ( '%s/imgpids.txt' % data_dir ), 'r' ).readlines()
#ipidx = 0
#
# define base test runner to be subclassed by all actual tests
class TestRunner:
def __init__( self ):
# initialize base parameters
self.site_url = 'http://%s' % os.environ['SERVICE_NAME']
self.url = '%s' % os.environ['URL']
self.scale = '%s' % os.environ['SCALE']
self.tag = '%s' % os.environ['IMAGE_TAG']
self.rotate = '%s' % os.environ['ROTATE']
self.format = '%s' % os.environ['FORMAT']
self.test = Test( 1, 'djatoka-image-basic' )
self.req = self.test.wrap( HTTPRequest() )
self.rsp = None
self.ipidx = 0
return
def __call__( self ):
# run a query and report result only if verified
grinder.statistics.delayReports = 1
self.rsp = self.req.GET( self.test_query() )
if self.rsp.statusCode == 200:
grinder.statistics.forLastTest.setSuccess( 1 )
else:
print self.rsp.statusCode
return
def next_pid( self ):
pid = imgpids[self.ipidx].rstrip( '\n' )
self.ipidx = self.ipidx + 1
return pid
def test_query( self ):
#new url is http://depot-test.library.wisc.edu/TIRIS/content/reference/*.jp2
#http://depot-test.library.wisc.edu/adore-djatoka/resolver?url_ver=Z39.88-2004&rft_id=http://depot-test.library.wisc.edu/TIRIS/content/reference/1984.01.001.01.jp2&svc_id=info:lanl-repo/svc/getRegion
url = '%s/%s/&rft_id=%s&svc.scale=%s&svc.format=%s&svc.rotate=%s' % ( self.site_url, self.url, self.next_pid(),self.scale,self.format,self.rotate )
grinder.logger.output( url )
return url
Coming Soon!
Creating a work experience timeline with Dojox Charting!
I'll be presenting on two topics at the Web-5 conf in Beziers, France in April!
Please fill out the form on the right to contact me, alternatively you can drop me an email chris@christopherbarrett.name
I am always open to discuss interesting opportunities.
© 2012 Christopher Barrett