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 JavaScript, and also many server-side solutions.
As a software engineer for Flexion, Inc., I develop enterprise level JavaScript web applications. I have implemented solutions most recently with Backbone.js but also with the Dojo Toolkit and even home grown frameworks.
I was a contributor to the Dojo Foundation project dGrid, and wrote documentation and tutorials for the toolkit. I also contributed to a toolkit called Mulberry which is used to develop mobile apps with JavaScript.
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.
© 2014 Christopher Barrett