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.

My work

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.

Chris Barrett

Portfolio

CRM screenshot
Commodities Risk Management

http://crm.doit.wisc.edu
Commodities Risk Management is a grant funded project to develop a simulation of the commodities market. This prototype is live and under development, but will be used in the classroom during the spring semester. The UI in this app is almost 100% javascript courtesy of the Dojo toolkit.

birdie publishing screenshot
Birdie Publishing

www.birdiepublishing.com
Birdie Publishing is a small publishing firm in the craft/resale niche market. The site is mostly written using the Dojo Toolkit, including a small online catalog and a smart form to get listed in their guides. The catalog is completely dynamic, using data in the database.


Malaria screenshot
Malaria - The Game

Malaria Game*note this is an older prototype
Malaria The game was a functioning prototype that will be used to teach nursing students about the effects and deterrents to catching Malaria.

VC screenshot
VirtualCase - Moodle Module

Private
The VirtualCase Moodle module was built for the University of Wisconsin School of Pharmacy. VirtualCase is a clinical environment simulation, it uses a dynamic branching tree to allow the student to traverse a decision making process. This module was written in PHP with some front end YUI JavaScript.

Code Samples

Apparently prettifier doesn't like IE7, sorry!
//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

Technology list

Languages

  • Javascript (Dojo, YUI, jquery)
    PHP
    Ruby
    Python
    Perl
    Java
    ColdFusion
    PL/SQL
    C++

Databases

  • mysql
    sql server
    oracle
    db2
    hsqldb
  • Servers

  • Apache
    Node
    Tomcat
    Jetty
    IIS

Frameworks

  • ZendFramework
    Rails
    CodeIgnitor
  • Moodle
    Drupal
    WordPress
    SugarCRM
  • VCS

  • SVN
    CVS
    Git

Work Experience

(click on the timeline to view my past work experience)

May 2011-Present

SitePen, Inc.

Software Engineer
  • Develop and support enterprise level web apps with Dojo
  • Write and update Dojo documentation
  • Write and update Dojo tutorials
  • Contribute to dgrid, part of the Dojo Foundation
  • Develop and maintain internal business applications

Sept 2008-May 2011

University of Wisconsin-Madison Madison, WI
DoIT – Academic Technology

Academic Technology Developer

Learning Solutions

  • Green dollar unit
  • Multiple projects of $50k - $100k each
  • Malaria: the game. PHP/mysql
  • VirtualCase – A Moodle module that simulates a clinical environment. PHP/mysql with YUI elements
  • Commodities Risk Management – a simulation of the commodities market. ZF/mysql/Dojo

Shared Development Group

  • Loaned for six months to SDG
  • Worked on Ruby, Python, and Java apps
  • Optimized Tomcat instance for Djatoka Image Server

Jan 2007-Sept 2008

University of Wisconsin-Madison Health Services
Madison, WI

Web Developer
  • Supported SHIP (Student Health Insurance Program) Online
  • Develop enhancements and debug using JSP and Java
  • Oracle back-end
  • Integrated Crystal Reports 10 report interface
  • Research and advise on future web technology trends
  • Business analysis and development in ColdFusion 8 for an internal Web App.
  • Database design in MySql 5
  • Future planning for development of new web portal

Feb 2006 –Jan 2007

dChron, inc.
Burlington, WI

Java Developer
  • Involved in all aspects of the development life cycle for dChron’s dComm (data communication software).
  • Developed in Java, using Eclipse’s SDK
  • Developed both www.dchron.com and www.timetrakmidwest.com
  • Database experience with Hypersonic DB

May 2004 – Feb 2006

Northwestern Mutual
Milwaukee, WI

Systems Specialist
  • Certification in Oracle’s PL/SQL, 9i, 10g
  • Supported the largest and most complex system at Northwestern Mutual
  • Debugged extensively in both Oracle and VB
  • Worked on many small projects from design to implementation and support
  • Supported nightly processing
  • Primary contact between our team and business clients
  • Supported Actuate reports and processing for the system

Fall 2003

Earthly Elements
Madison, WI

Web Site Developer
  • Contracted through Earthly Elements to develop website
  • Used Html, Macromedia’s Flash, and JavaScript.
  • Was posted at www.earthlyelements.com

Spring 2003

Western Racine County Health Department
Burlington, WI

Web Site Developer
  • Contracted through Aurora Healthcare to create a website for the health department.
  • Used Html, Macromedia’s Flash, and JavaScript
  • Posted at http://www.wrchd.org (not responsible for current design theme)

2002

Runzheimer Int’l
Rochester, WI

Information Technology Intern
  • Duties included web-based application design and implementation using ASP. Used Microsoft’s SQL Server.
  • Created procedures using SQL to move data from Excel and Access to the mainframe using COBOL.

My blog

10 February 2012

Top bar menu animation

Coming Soon!

26 January 2012

How-to: Work experience timeline

Creating a work experience timeline with Dojox Charting!

14 December 2011

Presenting at web-5 conf!

I'll be presenting on two topics at the Web-5 conf in Beziers, France in April!

Get in touch

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.