<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Beaver Creek Consulting</title>
	<atom:link href="http://beavercreekconsulting.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://beavercreekconsulting.com/blog</link>
	<description>Delivering Results in Application Development</description>
	<lastBuildDate>Thu, 06 May 2010 17:33:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Health Care Reform Calculator Available with iTunes</title>
		<link>http://beavercreekconsulting.com/blog/2010/05/health-care-reform-calculator-available-with-itunes/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/05/health-care-reform-calculator-available-with-itunes/#comments</comments>
		<pubDate>Thu, 06 May 2010 17:30:23 +0000</pubDate>
		<dc:creator>mrath</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Health Care Reform Bill]]></category>
		<category><![CDATA[ipad health care app]]></category>
		<category><![CDATA[iphone App health care]]></category>
		<category><![CDATA[ipod touch app]]></category>
		<category><![CDATA[ipodtouch health care]]></category>
		<category><![CDATA[iTunes health care]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/2010/05/health-care-reform-calculator-available-with-itunes/</guid>
		<description><![CDATA[We just launched the Health Care Reform App for the iPhone, iPod Touch and the iPad. We designed a calculator which lets people know how this bill affects them. After users download this App from the iTunes store, they can use an easy-to-use interface which provides results based on individual scenarios.
The Health Reform Calculator App [...]]]></description>
			<content:encoded><![CDATA[<p>We just launched the Health Care Reform App for the iPhone, iPod Touch and the iPad. We designed a calculator which lets people know how this bill affects them. After users download this App from the iTunes store, they can use an easy-to-use interface which provides results based on individual scenarios.</p>
<p>The Health Reform Calculator App comes at a time when the country is asking questions as to how the changes will affect them based on factors such as their income, their state of residence and existing insurance plans. Instead of having people pour through websites or read through the entire bill, we wanted to provide answers that mean something to each and every person. It was designed to be intuitive. After users enter several factors regarding their personal situation, the results from the calculator will show how the bill will impact life. More specifically, it estimates what it could mean for health coverage and taxes based on income, current insurance status and location.</p>
<p>It&#8217;s exciting to see that the iTunes approved the App since their approval process goes through a series of strict standards. We are selling the <a href="http://itunes.apple.com/us/app/health-reform-calculator/id370160682?mt=8">Health Care Reform Calculator</a> for 99 cents and look forward to receiving your feedback!</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/05/health-care-reform-calculator-available-with-itunes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RIM Places Contacts Cleaner on Best Blackberry App List</title>
		<link>http://beavercreekconsulting.com/blog/2010/05/rim-places-contacts-cleaner-on-best-blackberry-app-list/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/05/rim-places-contacts-cleaner-on-best-blackberry-app-list/#comments</comments>
		<pubDate>Wed, 05 May 2010 01:22:55 +0000</pubDate>
		<dc:creator>mrath</dc:creator>
				<category><![CDATA[BlackBerry]]></category>
		<category><![CDATA[app world]]></category>
		<category><![CDATA[berry review]]></category>
		<category><![CDATA[best blackberry app]]></category>
		<category><![CDATA[contacts cleaner]]></category>
		<category><![CDATA[picks]]></category>
		<category><![CDATA[RIM]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/2010/05/rim-places-contacts-cleaner-on-best-blackberry-app-list/</guid>
		<description><![CDATA[Alongside of nationally known brands like CBS and The Sierra Club, our Contacts Cleaner App was chosen by RIM as a top 9 Best Blackberry App. RIM is the company behind the award-winning Blackberry smartphone. Two weeks ago, they created this list of the top Blackberry App picks that people will enjoy while they are [...]]]></description>
			<content:encoded><![CDATA[<p>Alongside of nationally known brands like CBS and The Sierra Club, our Contacts Cleaner App was chosen by RIM as a top 9 Best Blackberry App. RIM is the company behind the award-winning Blackberry smartphone. Two weeks ago, they created this list of the top Blackberry App picks that people will enjoy while they are experiencing spring fever. This is a cute theme and it could be that Blackberry wants to target the audience that seeks fun from their smartphones.</p>
<p><a href="http://www.berryreview.com/2010/04/13/rim-app-picks-spring-into-spring-with-blackberry/">Berry Review </a>summarized this top 9 list beautifully and it’s a huge honor that in their opening paragraph, the author states, “I have to wholeheartedly agree with their choice of Contacts Cleaner.”  The article highlights how RIM often puts together lists of the best Apps for a season. By using the theme of the spring season, Contacts Cleaner is a great choice for “spring cleaning”.</p>
<p>It’s been an exciting few months with our iPhone App making the list of best iPhone Apps just last month. Sharing that list with the likes of Digg and Bing really put that App on the map! Now, we have another reason to celebrate!</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/05/rim-places-contacts-cleaner-on-best-blackberry-app-list/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beaver Creek Consulting’s iPhone App Makes Best App of the Week</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting%e2%80%99s-iphone-app-makes-best-app-of-the-week-2/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting%e2%80%99s-iphone-app-makes-best-app-of-the-week-2/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 01:04:10 +0000</pubDate>
		<dc:creator>mrath</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bar code scanner]]></category>
		<category><![CDATA[barcode scanner]]></category>
		<category><![CDATA[Beaver Creek Consulting]]></category>
		<category><![CDATA[beaver creek consulting iphone app]]></category>
		<category><![CDATA[best app]]></category>
		<category><![CDATA[Best iphone app]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=57</guid>
		<description><![CDATA[It has been a whirlwind.  Right after the launch of our Food Essentials Scanner iPhone App, we have been getting immediate sales and people have been writing positive reviews.  There isn’t a better honor than to get the Best iPhone App of the Week by Business Insider from Silicon Alley Insider. Beaver Creek Consulting made this [...]]]></description>
			<content:encoded><![CDATA[<p>It has been a whirlwind.  Right after the launch of our Food Essentials Scanner iPhone App, we have been getting immediate sales and people have been writing positive reviews.  There isn’t a better honor than to get the <a href="http://www.businessinsider.com/best-iphone-apps-of-the-week-2010-3#foodessentials-scanner-5">Best iPhone App of the Week</a> by Business Insider from Silicon Alley Insider. Beaver Creek Consulting made this list alongside of Digg and Bing &#8211; some of the biggest players on the Internet.</p>
<p>We’ve , also, been seeing  bloggers embrace the Food Essentials Scanner App.  One blogger who calls herself, The iPhone Mom wrote a wonderful review of the App stating that it’s the best App that she’s seen for those who suffer from food allergies.  After reading her <a href="http://www.theiphonemom.com/foodessentials-scanner">blog</a> , you find out that she liked that ability to customize the App.   While we weren’t sure if this would be a hit, it’s nice to see that someone who has a small child finds this to be of use.  She turned on the ability to see dairy ingredients and was able to make appropriate choices. </p>
<p>We’ve seen great success with our Blackberry App products and it’s extremely rewarding to have such instant success with our first Apple App.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting%e2%80%99s-iphone-app-makes-best-app-of-the-week-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beaver Creek Consulting Announces the Launch of the Food Essentials Scanner App</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting-announces-the-launch-of-the-food-essentials-scanner-app/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting-announces-the-launch-of-the-food-essentials-scanner-app/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 00:32:41 +0000</pubDate>
		<dc:creator>mrath</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[apple scanner]]></category>
		<category><![CDATA[beaver creek consulting iphone app]]></category>
		<category><![CDATA[beavercreekconsulting iphone app]]></category>
		<category><![CDATA[food essentials app]]></category>
		<category><![CDATA[nutrition app]]></category>
		<category><![CDATA[nutrition scanner iphone]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting-announces-the-launch-of-the-food-essentials-scanner-app/</guid>
		<description><![CDATA[Washington, D.C. – March 12, 2010. – Beaver Creek Consulting today announced the immediate availability of the Food Essentials Scanner App which is available on the iTunes store.  The App scans bar codes on food products allowing people to better understand what is in the ingredients.  When people scan the bar codes of [...]]]></description>
			<content:encoded><![CDATA[<p>Washington, D.C. – March 12, 2010. – Beaver Creek Consulting today announced the immediate availability of the Food Essentials Scanner App which is available on the iTunes store.  The App scans bar codes on food products allowing people to better understand what is in the ingredients.  When people scan the bar codes of products, they will learn more than what is on the nutrition label.  Important things like allergens, additives, nutrient properties suddenly become apparent by using this App.</p>
<p>“We’re excited that we created an App which allows people to use their iPhone as a scanning device,” says Marty Kube, President and CEO of Beaver Creek Consulting.  “By tying in iPhone’s capabilities  with our software solutions, we have created one of the most compelling iPhone Apps  that will provide the best user experience for a mobile device.”</p>
<p>The Food Essentials Scanner App can either scan bar codes on food products or can be used as a search tool where users type in product using keywords.   With over 30,000 ingredients listed in the database, the App can easily be customized to solve an individual’s nutritional needs.  </p>
<p>Beaver Creek Consulting released this App for $4.99.  It must be compatible with the iPhone with an operating system of OS3.1 or later.  It can be downloaded on the App Store under the Healthcare and Fitness category. </p>
<p>Beaver Creek Consulting is a software development and consulting firm which provides solutions in both the commercial and government sectors. Our experience in working with Fortune 500 companies has given us the breadth of knowledge that spans design, implementation and consulting services.  To find out more, please visit http://beavercreekconsulting.com/</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/beaver-creek-consulting-announces-the-launch-of-the-food-essentials-scanner-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacts Cleaner V2.0</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-v2-0/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-v2-0/#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:05:15 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[BlackBerry]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=49</guid>
		<description><![CDATA[We are pleased to announce the release of version 2.0 of Contacts Cleaner.  The two major improvements made in this version are faster processing of the address book and improved matching of duplicate contacts.
Since releasing Contacts Cleaner I have been surprised by the number of address books that have 10,000 or more contacts in them, [...]]]></description>
			<content:encoded><![CDATA[<p>We are pleased to announce the release of version 2.0 of Contacts Cleaner.  The two major improvements made in this version are faster processing of the address book and improved matching of duplicate contacts.</p>
<p>Since releasing Contacts Cleaner I have been surprised by the number of address books that have 10,000 or more contacts in them, often with the majority of the contacts being duplicates.  It has been a challenge to find and merge duplicates in a reasonable amount of time given the modest processing power of a phone.  I&#8217;m on the 4th version of the find and merge algorithm, and this version seems to be pretty darn good.   The customer feedback on processing speed for version 2.0 has been overwhelmingly positive.</p>
<p>With respect to duplicate matching, one constant source of duplicates is Google Sync.  To make matters worse, Google Sync tend to put the first and last name in the last name field of a contact.  With version 2.0,  we have changed the duplicate match algorithm to correctly recognize these cases of duplicates.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-v2-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacts Cleaner Support Page</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-support-page/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-support-page/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 02:33:33 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[BlackBerry]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=43</guid>
		<description><![CDATA[If you are having issues with Contacts Cleaner, or just want to know more about how it works, please visit our users guide at:
http://beavercreekconsulting.com/contacts-cleaner/user-guide.html
We recently made several updates to the FAQ and you will find answers for the most common questions.
]]></description>
			<content:encoded><![CDATA[<p>If you are having issues with Contacts Cleaner, or just want to know more about how it works, please visit our users guide at:</p>
<p><a title="Contacts Cleaner support page" href="http://beavercreekconsulting.com/contacts-cleaner/user-guide.html">http://beavercreekconsulting.com/contacts-cleaner/user-guide.html</a></p>
<p>We recently made several updates to the FAQ and you will find answers for the most common questions.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-support-page/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacts Cleaner Matching Algorithm</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-the-matching-algorithm/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-the-matching-algorithm/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 05:44:38 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[BlackBerry]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=36</guid>
		<description><![CDATA[One of the key ingredients of Contacts Cleaner is identification of duplicate contacts.  We have put a lot of effort into the algorithm, and concluded that less is more.
Most folks love Contacts Cleaner.  There are  a lot of really messed up address books out there.  I heard from a customer today who had 13,000 contacts, [...]]]></description>
			<content:encoded><![CDATA[<p>One of the key ingredients of <a title="Contacts Cleaner" href="http://beavercreekconsulting.com/contacts-cleaner/index.html">Contacts Cleaner</a> is identification of duplicate contacts.  We have put a lot of effort into the algorithm, and concluded that <a title="Less is more" href="http://en.wikipedia.org/wiki/Minimalism">less is more</a>.</p>
<p>Most folks <a title="Love it" href="http://beavercreekconsulting.com/contacts-cleaner/user-guide.html#love-it">love Contacts Cleaner</a>.  There are  a lot of really messed up address books out there.  I heard from a customer today who had 13,000 contacts, of which 10,000 were duplicates.  Bummer Dude!  This person needs a simple solution which will fix the mess that is their address book.  Contacts Cleaner to the rescue!</p>
<p>We have settled on a lights out, robust, and repeatable algorithm that will tame the chaos which is your address book.  Contacts Cleaner &#8220;just works&#8221;.  It will make you address book better without bothering you.  Contacts Cleaner is not perfect, but it is better!</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-the-matching-algorithm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacts Cleaner FAQ</title>
		<link>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-faq/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-faq/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 18:51:20 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[BlackBerry]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=34</guid>
		<description><![CDATA[I just updated the FAQ for Contacts Cleaner.  I went back through the customer support tickets and extracted common issues to create the new FAQ entries.  If you are having issues with Contacts Cleaner, do check out the FAQ.  Chances are good you&#8217;ll find an answer.
]]></description>
			<content:encoded><![CDATA[<p>I just updated the <a title="Contacts Cleaner FAQ" href="http://beavercreekconsulting.com/contacts-cleaner/user-guide.html#faq">FAQ</a> for <a title="Contacts Cleaner on BlackBerry App World" href="http://appworld.blackberry.com/webstore/content/5598">Contacts Cleaner</a>.  I went back through the customer support tickets and extracted common issues to create the new FAQ entries.  If you are having issues with Contacts Cleaner, do check out the FAQ.  Chances are good you&#8217;ll find an answer.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/03/contacts-cleaner-faq/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacts Cleaner 1.0</title>
		<link>http://beavercreekconsulting.com/blog/2010/02/contacts-cleaner/</link>
		<comments>http://beavercreekconsulting.com/blog/2010/02/contacts-cleaner/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 03:52:53 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[BlackBerry]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=30</guid>
		<description><![CDATA[Beaver Creek Consulting is pleased to announce the release of their new product, Contacts Cleaner.  Contacts Cleaner is a BlackBerry App that removes duplicate contacts from your address book.  Contacts Cleaner is available from BlackBerry App World, as well as popular BlackBerry sites such as CrackBerry and BBGeeks.
]]></description>
			<content:encoded><![CDATA[<p>Beaver Creek Consulting is pleased to announce the release of their new product, Contacts Cleaner.  Contacts Cleaner is a BlackBerry App that removes duplicate contacts from your address book.  Contacts Cleaner is available from <a href="http://appworld.blackberry.com/webstore/content/5598">BlackBerry App World</a>, as well as popular BlackBerry sites such as <a title="Contacts Cleaner at CrackBerry" href="http://software.crackberry.com/product.asp?id=49094&amp;n=Contacts-Cleaner">CrackBerry</a> and <a href="http://store.bbgeeks.com/product.asp?id=49094&amp;n=Contacts-Cleaner">BBGeeks</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2010/02/contacts-cleaner/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP PEAR on GoDaddy</title>
		<link>http://beavercreekconsulting.com/blog/2009/05/php-pear-on-godaddy/</link>
		<comments>http://beavercreekconsulting.com/blog/2009/05/php-pear-on-godaddy/#comments</comments>
		<pubDate>Mon, 04 May 2009 00:36:14 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Simply Schedules]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=21</guid>
		<description><![CDATA[Today I moved the server side components of SimplySchedules.com to my hosting service for the first time.  Yahoo &#8212; the launch is getting closer!
The sever side is done in PHP due to the extreme cost effectiveness of hosted LAMP.  I used a few modules from the most excellent PEAR collection.  All good, except when I [...]]]></description>
			<content:encoded><![CDATA[<p>Today I moved the server side components of <a title="Simply Schedules - easy web based project schedules" href="http://simplyschedules.com">SimplySchedules.com</a> to my hosting service for the first time.  Yahoo &#8212; the launch is getting closer!</p>
<p>The sever side is done in <a href="http://en.wikipedia.org/wiki/Php">PHP</a> due to the extreme cost effectiveness of hosted <a href="http://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP</a>.  I used a few modules from the most excellent <a href="http://en.wikipedia.org/wiki/PEAR">PEAR</a> collection.  All good, except when I installed the code at <a href="http://www.godaddy.com/default.aspx">GoDaddy.com</a>, I was missing the PEAR modules.</p>
<p>The PEAR modules are a lot of code, so I was very happy to find <a href="http://abbyandwin.net/blog/2008/06/16/installing-pear-on-godaddy-shared-accounts/">this</a> clear and concise blog posting that explained how to <a href="http://abbyandwin.net/blog/2008/06/16/installing-pear-on-godaddy-shared-accounts/">install PEAR at GoDaddy</a>.  Basically, you install an installer on your web account and then use a web based front end to install your selected PEAR components.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2009/05/php-pear-on-godaddy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Scripting Approaches For Java Application Test Automation</title>
		<link>http://beavercreekconsulting.com/blog/2009/04/scripting-approaches-for-java-application-test-automation/</link>
		<comments>http://beavercreekconsulting.com/blog/2009/04/scripting-approaches-for-java-application-test-automation/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 22:07:33 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=20</guid>
		<description><![CDATA[Next week I&#8217;m presenting at the Northern Virginia Test Automation Interest Group.  The group&#8217;s focus is test automation and I&#8217;m talking about how to automate scripting of Java applications with an eye towards testing.
Full, disclosure, I&#8217;m a scripting FanBoy; this is an opportunity to talk about exposing scripting interfaces for Java applications so I&#8217;m jumping [...]]]></description>
			<content:encoded><![CDATA[<p>Next week I&#8217;m presenting at the <a href="http://www.novataig.net/">Northern Virginia Test Automation Interest Group</a>.  The group&#8217;s focus is test automation and I&#8217;m talking about how to automate scripting of Java applications with an eye towards testing.</p>
<p>Full, disclosure, I&#8217;m a scripting <a href="http://en.wikipedia.org/wiki/Fanboy">FanBoy</a>; this is an opportunity to talk about exposing scripting interfaces for Java applications so I&#8217;m jumping on the opportunity to do so.  It just happens that doing so is a a great route to test automation and I get to talk on and on about scripting.</p>
<p>I&#8217;m covering <a href="http://groovy.codehaus.org/">groovy</a>, <a href="http://www.mozilla.org/rhino/">Rhino</a>, and <a href="https://javacc.dev.java.net/">JavaCC</a>.  The meeting announcement is <a href="http://www.novataig.net/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2009/04/scripting-approaches-for-java-application-test-automation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clearing and Busting the GWT Hosted Mode Cache</title>
		<link>http://beavercreekconsulting.com/blog/2009/02/clearing-and-busting-the-gwt-hosted-mode-cache/</link>
		<comments>http://beavercreekconsulting.com/blog/2009/02/clearing-and-busting-the-gwt-hosted-mode-cache/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 20:48:47 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Joomla]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Simply Schedules]]></category>
		<category><![CDATA[Spring]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=19</guid>
		<description><![CDATA[We&#8217;ve chosen to use GWT for Beaver Creek Consulting&#8217;s latest product (Simply Schedules).  The back end is a REST API with JSON payloads.
I was having trouble with the hosted mode browser.  A list of application objects for a luser are loaded with a request to the server such as:
GET /app/luser/items
The issue is that as the [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve chosen to use GWT for Beaver Creek Consulting&#8217;s latest product (<a title="Simply Schedules" href="http://simplyschedules.com/">Simply Schedules</a>).  The back end is a REST API with JSON payloads.</p>
<p>I was having trouble with the hosted mode browser.  A list of application objects for a <a title="Looser User" href="http://en.wikipedia.org/wiki/Luser">luser</a> are loaded with a request to the server such as:</p>
<p>GET /app/luser/items</p>
<p>The issue is that as the application runs, the list of items on the server changes.  Next time I tried to load the list of items from the server, the hosted browser sees the same URL and decides to use the cached response.</p>
<p>This <a title="How to clear the GWt cache" href="http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/da550bf5cc987029">post</a> on the GWT forum recommended clearing the IE (if you are on windows) cache.  I needed something more permanent as the cache issue is part of the normal operation of the client (this is to say it modifies the items).</p>
<p>The correct answer is to not clear the cache, but to bust the cache.  A little bit of <a title="Google cache Bustin'" href="http://www.google.com/search?q=cache+busting+random+number">research</a> shows that appending a query parameter with a random number or a timestamp will do the trick.  For the above example, I used the current timestamp:</p>
<p>GET /app/luser/items?cache-buster=1233516109751</p>
<p>The timestamp is generated in &#8220;Java&#8221; on the client:</p>
<pre class="brush: java">
String url = &quot;/app/luser/items?cache-buster=&quot; + new java.util.Date().getTime();
</pre>
<p>It&#8217;s quite likely that you don&#8217;t even need to name the parameter, just append the time stamp:</p>
<p>GET /app/luser/items?1233516109751</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2009/02/clearing-and-busting-the-gwt-hosted-mode-cache/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>You can have Perl 5 when you peel my cold dead hands off of it.</title>
		<link>http://beavercreekconsulting.com/blog/2009/02/you-can-have-perl-5-when-you-peel-my-cold-dead-hand-off-of-it/</link>
		<comments>http://beavercreekconsulting.com/blog/2009/02/you-can-have-perl-5-when-you-peel-my-cold-dead-hand-off-of-it/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 14:50:58 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=18</guid>
		<description><![CDATA[I started working with Perl in 2000 and along with C++ Perl is the language I cut my teeth on as a professional developer.
5.8 has been my favorite release.   With Perl 6 taking a while to be production ready I&#8217;ve been planning on using 5.8 forever.  Well, it turns out forever isn&#8217;t that long.  The [...]]]></description>
			<content:encoded><![CDATA[<p>I started working with Perl in 2000 and along with C++ Perl is the language I cut my teeth on as a professional developer.</p>
<p>5.8 has been my favorite release.   With <a title="Perl 6 is ready to go?" href="http://weblog.infoworld.com/fatalexception/archives/2008/10/perl_6_isnt_vap.html">Perl 6 taking a while to be production ready</a> I&#8217;ve been planning on using 5.8 forever.  Well, it turns out forever isn&#8217;t that long.  The <a title="The end of Perl 5.8" href="http://www.nntp.perl.org/group/perl.perl5.porters/2008/11/msg141328.html">end of Perl 5.8</a> has been announced.  The good news is that Perl 5 will continue as Perl 5.10.</p>
<p>Maybe I&#8217;ll never upgrade to Perl 6.  Perhaps this point is moot, as I&#8217;m using Perl less and less these days.  I&#8217;ve been turning to Groovy.</p>
<p>But &#8212; when I need something complicated <strong>done right now</strong>, my goto is Perl 5.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2009/02/you-can-have-perl-5-when-you-peel-my-cold-dead-hand-off-of-it/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MapQuest Proxy for Jaxer</title>
		<link>http://beavercreekconsulting.com/blog/2009/01/mapquest-proxy-for-jaxer/</link>
		<comments>http://beavercreekconsulting.com/blog/2009/01/mapquest-proxy-for-jaxer/#comments</comments>
		<pubDate>Sat, 17 Jan 2009 01:19:06 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Jaxer]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=16</guid>
		<description><![CDATA[If you&#8217;re a MapQuest developer chances are you&#8217;re pretty handy with JavaScript on the client.  It&#8217;s been the sad case that you leave these skills behind when you switch over to server side programming.   Well, happy day, things are changing as support for Server Side JavaScript (SSJS) takes off.  With SSJS [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re a MapQuest developer chances are you&#8217;re pretty handy with JavaScript on the client.  It&#8217;s been the sad case that you leave these skills behind when you switch over to server side programming.   Well, happy day, things are changing as support for Server Side JavaScript (<a href="http://en.wikipedia.org/wiki/SSJS">SSJS</a>) takes off.  With SSJS you can  break out your JavaScript Ninja skills on the server side.  I&#8217;ve been looking at the <a href="http://www.aptana.com/jaxer">Jaxer</a> SSJS platform and worked up this example to show off some of the possibilities.</p>
<p>With the MapQuest JavaScript <a href="http://developer.mapquest.com/downloads">API</a> one can get tiled maps on a page with only client JavaScript.  As soon as you use other MapQuest Services such geocoding, routing, or search, you need to supply a proxy on the web server.  The proxy is need to allow the MapQuest client library to call home while avoiding the browser&#8217;s same-domain security policy.</p>
<p>The example I&#8217;m presenting here is an implementation of such a proxy for the Jaxer platform.  I think a SSJS proxy is an illuminating and useful example.  It&#8217;s a useful example since you need a proxy for putting MapQuest and Jaxer together.  Also, it&#8217;s an illuminating example since it is a typical server side task, fetching data from a different source.  The source could be files, in database, RSS feeds, or, as in this case, a server in a different domain.  MapQuest (MQ) supplies proxies in common languages such PHP, Java, etc., so this example will also allow comparison of the SSJS implementation to implementations in other languages.</p>
<p>The example consists of two HTML pages, one of which is served to the client and one which runs on the Jaxer server and acts as the proxy.</p>
<p><strong>The Client Side</strong></p>
<p>The client page is a hello world type of example for MapQuest – create a tiled map, geocode an address, and place a Point of Interest marker at the geocoded address. The complete source code for this example is available <a title="Source code for the example" href="http://beavercreekconsulting.com/downloads/jaxer-mapquest-proxy.zip">here</a>. Here&#8217;s a screenshot of the client page in action:</p>
<p><img src="http://beavercreekconsulting.com/img/mqproxy-screenshoot.png" alt="" /></p>
<p>The text boxes on the right are a debug log provided the MQ client library that shows interaction between the MQ client library and the proxy.   Specifically, the box labeled “Request URL” is address where the MapQuest client library is configured to find the proxy.  The Request XML box shows the data the client library is sending, which in this case is a request for geocoding per the MQ API (see the MQ XML Interface <a href="http://developer.mapquest.com/Library/SDK_Documentation/Protocols">Reference</a>).  The &#8220;Response XML&#8221; is the XML returned by the MapQuest geocoding service via the proxy.</p>
<p>Here&#8217;s the startMap() method that is called when the client page loads:</p>
<pre class="brush: html">
&lt;script src=&quot;http://btilelog.access.mapquest.com/tilelog/transaction?transaction=script&amp;amp;amp;amp;amp;amp;key=your-MQ-key=true&amp;amp;amp;amp;amp;amp;v=5.3.s&amp;amp;amp;amp;amp;amp;ipkg=controls1&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;lib/mapquest/mqcommon.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;lib/mapquest/mqutils.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;lib/mapquest/mqobjects.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;lib/mapquest/mqexec.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
var g_proxyServerName = &#039;localhost&#039;;
var g_proxyServerPort = &#039;8000&#039;;
var g_proxyServerPath = &#039;jaxer-mapquest/proxy.html&#039;

var g_serverName = &#039;geocode.dev.mapquest.com&#039;;
var g_serverPort = &#039;80&#039;;
var g_serverPath = &#039;mq&#039;;

var g_geoExec = new MQExec(g_serverName, g_serverPath, g_serverPort, g_proxyServerName, g_proxyServerPath, g_proxyServerPort);

function startMap(){
var g_mqMap = new MQA.TileMap(document.getElementById(&#039;mapWindow&#039;), 2, new MQA.LatLng(40, -95), &quot;map&quot;);

var address = new MQAddress();
address.setCity(&#039;Gobles&#039;);
address.setState(&#039;MI&#039;);
address.setCountry(&#039;USA&#039;);

var gaCollection = new MQLocationCollection(&quot;MQGeoAddress&quot;);
g_geoExec.geocode(address, gaCollection);
var mqAddress = gaCollection.get(0);

var poi = new MQA.Poi(mqAddress.getMQLatLng());
poi.setInfoTitleHTML(&#039;Hello World&#039;);
poi.setInfoContentHTML(&#039;From Gobles, MI&#039;);
g_mqMap.addPoi(poi);
}
&lt;/script&gt;
</pre>
<p>The MQExec object interacts with the proxy.  The location of the proxy on localhost is specified as well as the details of the proxied MapQuest server (geocode.dev.mapquest.com).  When the MQ client library needs to call home for geocoding services (via <code>g_geoExec.geocode()</code>), it will form a GET or POST with the request details and send the request to <code>http://localhost:8000/jaxer-mapquest/proxy.html</code>.</p>
<p><strong>The Server Side</strong></p>
<p>The sever side proxy is implemented in a page named proxy.html.  The page receives the post from the MQ client library, extracts the data, forwards it along to the MQ server, and then returns the MQ response back to the client.</p>
<p>The HTML page, proxy.html, is processed by the Jaxer server.  We&#8217;ll use a slightly different processing model than the typical Jaxer page <a href="http://www.aptana.com/node/150">lifecycle</a>.  In the typical lifecycle a page is parsed on the Jaxer server into a DOM model, scripts that are tagged to be ran on the server are invoked, client side proxies are mixed-in for scripts that are tagged to be proxied, and then the page is serialized and sent off to the client.  In this case, we use server side scripts to overwrite the the DOM on the server side prior to the serialization for returning the page to the client.</p>
<p>This is a handy Jaxer technique.  Since you set the content type and the response content you can pull stunts like serializing arbitrary JavaScript objects and returning them as JSON to the client.  In this case, I&#8217;m overwriting the HTML page and returning the content and content type from the map quest server (XML).  To me, this technique is the more similar to a J2EE <a href="http://java.sun.com/products/servlet/">Servlet</a> than the typical Jaxer lifecycle, which feels more like a <a href="http://en.wikipedia.org/wiki/JavaServer_Pages">JSP</a>.</p>
<p>The proxy.html page consist primarily of JavaScript that get executes in the server context.  The server side script execution is triggered with a <code>onserverload</code> tag:</p>
<pre class="brush: html">
&lt;body onserverload=&quot;BCC.mqproxy.proxify();&quot;&gt;
</pre>
<p>The <code>proxify()</code> method shows the general steps that the proxy executes:</p>
<pre class="brush: javascript">
proxify: function(){
parseClientRequest();
makeMQRequest();
replyToClient();
}
</pre>
<p>In order to overwrite the page&#8217;s DOM with arbitrary content, one calls the <code>Jaxer.Response.setContent()</code> method.  In this case, we&#8217;ll overwrite the page&#8217;s entire DOM with the response and content type obtained from the MQ response.  The property <code>Jaxer.response</code> is an instance of <code>Jaxer.Response</code> that points to the current response:</p>
<pre class="brush: javascript">
var replyToClient = function(){
Jaxer.response.headers[&#039;Content-Type&#039;] = mqResponse.headers[&#039;Content-Type&#039;];
Jaxer.response.setContents(mqResponse.text);
}
</pre>
<p>And that&#8217;s all it takes to send back arbitrary content from a Jaxer HTML page.</p>
<p>Before we can reply to the client, this page has to parse the client request and call the server at MapQuest.  The following function reads the data posted by the client from Jaxer.request (an instance of Jaxer.Request):</p>
<pre class="brush: javascript">
var parseClientRequest = function(){
getMqServerUrlParams();
if (Jaxer.request.method == &#039;POST&#039;) {
getPostData();
}
else {
getUrlParms();
}
};
</pre>
<p>The MQ client sends the target server, port and path as URL parameters and the getMQServerUrlParams() method picks these off.   Jaxer makes the parsed URL available as a property of the request object:</p>
<pre class="brush: javascript">
var serverParams = {
sname: &#039;&#039;,
sport: &#039;&#039;,
spath: &#039;&#039;
};

var getMqServerUrlParams = function(){
logger.debug(&#039;getMqServerUrlParams&#039;);
for (param in serverParams) {
serverParams[param] = Jaxer.request.parsedUrl.queryParts[param];
logger.debug(&#039;getMqServerUrlParams: &#039; + param + &#039;: &#039; + serverParams[param]);
}
};
</pre>
<p>The remainder of the request data comes in as either other URL parameters or as POSTed XML.  In the case of XML data, the proxy needs to add a couple of XML elements for a client ID and password.  Here&#8217;s the routine to get the XML from the request, parse it, modify the DOM and serialize back to XML:</p>
<pre class="brush: javascript">

// Fetch the XML form data and add credentials
var getPostData = function(){
logger.debug(&#039;getPostData&#039;);
logger.debug(&#039;getPostData: postdata:          &#039; + Jaxer.request.postData);

var doc = new DOMParser().parseFromString(Jaxer.request.postData, &#039;text/xml&#039;);
if (doc.documentElement.nodeName == &quot;parsererror&quot;) {
throw new Error(&quot;People we have an issue: XML parse error&quot;);
}
var authenticalNodeList = doc.documentElement.getElementsByTagName(&quot;Authentication&quot;);
if (authenticalNodeList.length &gt; 0) {
authenticatedRequest = true;
var authenticalNode = authenticalNodeList[0];

// add password
var passwordEl = doc.createElement(&#039;Password&#039;);
var passwordTextEl = doc.createTextNode(mqPassword);
authenticalNode.appendChild(passwordEl).appendChild(passwordTextEl);

// add client ID
var clientIdEl = doc.createElement(&#039;ClientId&#039;);
var clientIdTextEl = doc.createTextNode(mqClientId);
authenticalNode.appendChild(clientIdEl).appendChild(clientIdTextEl);
}

// back to a string
postData = new XMLSerializer().serializeToString(doc);
logger.debug(&#039;getPostData: fixed up postdata: &#039; + postData);
};
</pre>
<p>Notice that there is no cross-browser monkey business to get a parser and serializer.  On the server side, Jaxer uses Mozilla so you can count the available features.   This example also makes use of the Jaxer.Log facility which lets you write to server side logs and specify the level of logging detail.</p>
<p>The last code snippet show how to place a synchronous server side HTTP request with Jaxer.Web.send().  The URL is assembled and a POST or GET is made per the client request:</p>
<pre class="brush: javascript">
var makeMQRequest = function(){
mqUrl = &#039;http://&#039; + serverParams.sname + &#039;:&#039; + serverParams.sport + &#039;/&#039; + serverParams.spath;
sendOptions.extendedResponse = true;
if (Jaxer.request.method == &#039;POST&#039;) {
if (authenticatedRequest == true) {
mqUrl += &#039;/mqserver.dll?e=5&#039;;
}
sendOptions.contentType = &#039;application/x-www-form-urlencoded&#039;;
}
else { // GET
var urlQParams = &#039;&#039;;
for (p in urlParams) {
urlQParams += p + &#039;=&#039; + urlParams[p];
}
if (urlParams.length &gt; 0) {
mqUrl += &#039;?&#039; + urlQParams;
}
}
// Call home
mqResponse = Jaxer.Web.send(mqUrl, Jaxer.request.method, postData, sendOptions);
};
</pre>
<p><strong>Wrap up</strong></p>
<p>This example shows how to proxy web content in other domains using Jaxer.  The same basic approach can be used to access other server side resources (files, database, etc).</p>
<p>I&#8217;m a big fan of scripting languages, and JavaScript is my current favorite.  I&#8217;ve been using it not only in web browsers but also as domain specific language in a Business Process Modeling application I&#8217;m working with.  I&#8217;m at the peak of my JavaScript skills, so, I&#8217;m really happy to be able to break out JavaScript on the server side.</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2009/01/mapquest-proxy-for-jaxer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Perl Syntax Highlighter</title>
		<link>http://beavercreekconsulting.com/blog/2008/12/perl-syntax-highlighter/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/12/perl-syntax-highlighter/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 05:10:33 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=17</guid>
		<description><![CDATA[SyntaxHighlighter is turning out to be the web standard for displaying source code in blogs.  I&#8217;ve developed a brush for that most excellent, yet recently neglected language, Perl.  This contribution has not yet been included in the SyntaxHighlighter distribution, so I&#8217;m also posting the source code here.  Enjoy!
I&#8217;ve posted the full source [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/syntaxhighlighter/">SyntaxHighlighter</a> is turning out to be the web standard for displaying source code in blogs.  I&#8217;ve developed a brush for that most excellent, yet recently neglected language, <a href="http://www.perl.org/">Perl</a>.  This contribution has not yet been included in the SyntaxHighlighter distribution, so I&#8217;m also posting the source code here.  Enjoy!</p>
<p>I&#8217;ve posted the <a href="http://code.google.com/p/syntaxhighlighter/issues/detail?id=113">full source code</a> for the brush to the syntaxhighlighter site.  This brush is based on a couple of earlier Perl brushes:</p>
<p><a href="http://opticalgarbage.com/sh/js/shBrushPerl.js">http://opticalgarbage.com/sh/js/shBrushPerl.js</a></p>
<p><a href="http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js">http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js</a></p>
<pre class="brush: javascript">

/**
* Perl brush for Code Syntax Highlighter
* by Marty Kube, http://beavercreekconsulting.com/
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, version 3 of the License.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.
*/
dp.sh.Brushes.Perl = function()
{
var funcs =
&#039;abs accept alarm atan2 bind binmode chdir chmod chomp chop chown chr &#039; +
&#039;chroot close closedir connect cos crypt defined delete each endgrent &#039; +
&#039;endhostent endnetent endprotoent endpwent endservent eof exec exists &#039; +
&#039;exp fcntl fileno flock fork format formline getc getgrent getgrgid &#039; +
&#039;getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr &#039; +
&#039;getnetbyname getnetent getpeername getpgrp getppid getpriority &#039; +
&#039;getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid &#039; +
&#039;getservbyname getservbyport getservent getsockname getsockopt glob &#039; +
&#039;gmtime grep hex index int ioctl join keys kill lc lcfirst length link &#039; +
&#039;listen localtime lock log lstat map mkdir msgctl msgget msgrcv msgsnd &#039; +
&#039;oct open opendir ord pack pipe pop pos print printf prototype push &#039; +
&#039;quotemeta rand read readdir readline readlink readpipe recv rename &#039; +
&#039;reset reverse rewinddir rindex rmdir scalar seek seekdir select semctl &#039; +
&#039;semget semop send setgrent sethostent setnetent setpgrp setpriority &#039; +
&#039;setprotoent setpwent setservent setsockopt shift shmctl shmget shmread &#039; +
&#039;shmwrite shutdown sin sleep socket socketpair sort splice split sprintf &#039; +
&#039;sqrt srand stat study substr symlink syscall sysopen sysread sysseek &#039; +
&#039;system syswrite tell telldir time times tr truncate uc ucfirst umask &#039; +
&#039;undef unlink unpack unshift utime values vec wait waitpid warn write&#039;;

var keywords =
&#039;bless caller continue dbmclose dbmopen die do dump else elsif eval exit &#039; +
&#039;for foreach goto if import last local my next no our package redo ref &#039; +
&#039;require return sub tie tied unless untie until use wantarray while&#039;;

this.regexList = [
{ regex: new RegExp(&#039;#[^!].*$&#039;, &#039;gm&#039;), css: &#039;comment&#039; },  // comments
{ regex: new RegExp(&#039;^\\s*#!.*$&#039;, &#039;gm&#039;), css: &#039;preprocessor&#039; }, //shebang
{ regex: dp.sh.RegexLib.DoubleQuotedString, css: &#039;string&#039; },
{ regex: dp.sh.RegexLib.SingleQuotedString, css: &#039;string&#039; },
{ regex: new RegExp(&#039;(\\$|@|%)\\w+&#039;, &#039;g&#039;), css: &#039;vars&#039; },
{ regex: new RegExp(this.GetKeywords(funcs), &#039;gmi&#039;), css: &#039;func&#039; },
{ regex: new RegExp(this.GetKeywords(keywords), &#039;gm&#039;), css: &#039;keyword&#039; }
];

this.CssClass = &#039;dp-perl&#039;;
this.Style =
&#039;.dp-perl .vars { color: #996600; }&#039; +
&#039;.dp-perl .func { color: #006666; }&#039;;
}

dp.sh.Brushes.Perl.prototype  = new dp.sh.Highlighter();
dp.sh.Brushes.Perl.Aliases  = [&#039;perl&#039;, &#039;Perl&#039;];
</pre>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/12/perl-syntax-highlighter/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JoomlaPack Rocks!</title>
		<link>http://beavercreekconsulting.com/blog/2008/12/joomlapack-rocks/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/12/joomlapack-rocks/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 01:53:29 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[Joomla]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Simply Schedules]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=15</guid>
		<description><![CDATA[I&#8217;ve been working on Beaver Creek Consulting&#8217;s latest product (Simply Schedules) and had a chance to use JoomlaPack.  Story short &#8212; it rocks.
I&#8217;m using Joomla for this site as I&#8217;ve decided that a CMS is the way to go.
I spent many hours configuring the site.  I did all of this work live on my shared [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on Beaver Creek Consulting&#8217;s latest product (<a title="Simply Schedules" href="http://simplyschedules.com">Simply Schedules</a>) and had a chance to use <a title="JoomlaPack.net" href="http://www.joomlapack.net/">JoomlaPack</a>.  Story short &#8212; it rocks.</p>
<p>I&#8217;m using <a href="http://www.joomla.org/">Joomla</a> for this site as I&#8217;ve decided that a <a title="Wikipedia on CMS" href="http://en.wikipedia.org/wiki/Content_management_system">CMS</a> is the way to go.</p>
<p>I spent many hours configuring the site.  I did all of this work live on my shared hosting account.  Late today, after many hours of trial and tribulations, the site started to look good enough that I was happy with it.  My next thought was, I need a back up!</p>
<p>Joomla keeps stuff on the file system of the web server and in a MySql database.  That&#8217;s a pain to back up.</p>
<p>So, I found JoomlaPack, which you can just install in as a Joomla 1.5 component and then create a complete backup of the file system and database.</p>
<p>After I made the backup, I used <a title="Joomla kick Start" href="http://www.joomlapack.net/help-support-documentation/joomlapack-20-stable-documentation/kickstart-beforeusing.html">kickstart</a> to restore to my local development server.   No Problems!</p>
<p>I have to say that JoomlaPack is a great tool.  You can backup your production site, restore production in case of serious issues, and use JoomlaPack to move your site between environments and/or servers.</p>
<p>Rock away JoomlaPack!</p>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/12/joomlapack-rocks/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Hibernate Annotations for a One-To-Many Mapping Featuring a Many Side, Composite, Primary Key having a Composite, Foreign, Sub-Key</title>
		<link>http://beavercreekconsulting.com/blog/2008/10/hibernate-annotations-for-a-one-to-many-mapping/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/10/hibernate-annotations-for-a-one-to-many-mapping/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 02:53:11 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=13</guid>
		<description><![CDATA[Sure, that&#8217;s a honking title, but it is what&#8217;s needed to describe a Hibernate mapping that recently required some head scratching on my part to figure out.  I&#8217;ve been off of Hibernate (as in off of the wagon) for a while now as I&#8217;ve been busy writing stored procedures.  Now that I&#8217;ve fallen [...]]]></description>
			<content:encoded><![CDATA[<p>Sure, that&#8217;s a honking title, but it is what&#8217;s needed to describe a Hibernate mapping that recently required some head scratching on my part to figure out.  I&#8217;ve been off of <a href="http://beavercreekconsulting.com/blog/wp-admin/hibernate.org">Hibernate</a> (as in off of the wagon) for a while now as I&#8217;ve been busy writing stored procedures.  Now that I&#8217;ve fallen back on the wagon, and am working on a Spring/Hibernate project, I&#8217;ve started to recall what a joy/pain Hibernate can be.</p>
<p>This project has a legacy database so I had to map the database objects as is.  The relationship is between a parent and child table (or master/detail set of tables), which I&#8217;m going to refer to as Parent and Child, respectively:</p>
<p><img src="http://beavercreekconsulting.com/img/blog-hibernate-20081014-tables.png" alt="Parent and Child Tables" /></p>
<p>As the title of this post indicates Parent has a composite primary key.  The interesting, and tricky to handle in Hibernate item is the primary key of the child table.  This is also a composite key, and a sub-key of the Child primary key is a foreign key to Parent.  The DDL for this relationship gives an exact picture of the relationship:</p>
<pre class="brush: sql">
create table parent (
  id      integer,
  version integer,
  constraint parent_pk primary key (id, version)
);

create table child (
  id      integer,
  parent_id integer,
  parent_version integer,
  constraint child_pk
    primary key (id, parent_id, parent_version),
  constraint child_fk
    foreign key (parent_id, parent_version)
    references parent (id, version)
);
</pre>
<p>Two fields from Child (parent_id and parent_version ) point back to the owning Parent (id, version).  There are a couple of aspects that make this harder to model from the Hibernate perspective.  All of the keys involved are composite, so you have to use <a href="http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entity-mapping-identifier">embedded objects</a> to represent each key.</p>
<p>Secondly, there is no separation between the link to the parent and the existence of a child instance.  Hibernate is most easy to deal with when these are two different items.  That is why you see <a href="http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entity-mapping-association-collection-onetomany">recommendations</a> 1) against unidirectional OneToMany relationships with a foreign key on the owned entity, and 2) and that you use a join table in these cases.  The join table lets you separate the existence of a child (a record in the child table) from the existence of the relationship to parent (a record in the join table).  In this case, since the foreign key (the link) is part of the primary key (existence), these two concept are not separated and we need to just deal with it.</p>
<p>Against the above recommendation, one has to go with a OneToMany with no join table.  I didn&#8217;t invent how to model this, the canonical posting for relationships with composite keys are <a href="http://boris.kirzner.info/blog/archives/2008/07/19/hibernate-annotations-the-many-to-many-association-with-composite-key/">here</a> and <a href="http://java-aap.blogspot.com/2006/04/hibernate-annotations-composite.html">here</a>.   However, those posting don&#8217;t deal with the combined primary and foreign key and when both keys are composite so there is some extra detail here.   I&#8217;ve packaged the example up as an Eclipse project and the complete source code is available <a href="http://beavercreekconsulting.com/downloads/hib-example.zip">here</a>.</p>
<p>Because the keys are composite, the Java object model has embedded objects that represent the primary key values, as shown in following class diagram:</p>
<p><img src="http://beavercreekconsulting.com/img/blog-hibernate-20081014-class-diagram.png" alt="Parent and Child Class Diagram"/></p>
<p>The main domain objects are named Parent and Child, which would also hold all of the additional attributes in a real application (I&#8217;m showing only key values here for clarity).  The primary key objects are  ParentPrimaryKey and ChildPrimaryKey.  An important point to note here is the representation of the foreign key in ChildPrimaryKey.  ChildPrimaryKey holds a reference to the owning Parent as an instance variable (named parentForeignKey).</p>
<p>Moving on to the annotations and the coding tasks that need to be applied to each of classes, we start with Parent:</p>
<pre class="brush: java">
package com.beavercreekconsulting.example;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = &quot;parent&quot;)
public class Parent {

  @Id
  ParentPrimaryKey primaryKey = new ParentPrimaryKey();

  @OneToMany(mappedBy = &quot;primaryKey.parentForeignKey&quot;,
    fetch=FetchType.EAGER)
  private List children;

  public ParentPrimaryKey getPrimaryKey() {
    return primaryKey;
  }

  public void setPrimaryKey(ParentPrimaryKey primaryKey) {
    this.primaryKey = primaryKey;
  }

  public List getChildren() {
    return children;
  }

  public void setChildren(List children) {
    this.children = children;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
      + ((children == null) ? 0 : children.hashCode());
    result = prime * result
      + ((primaryKey == null) ? 0 : primaryKey.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    final Parent other = (Parent) obj;
    if (children == null) {
        if (other.children != null) return false;
    } else if (!children.equals(other.children)) return false;
    if (primaryKey == null) {
      if (other.primaryKey != null) return false;
    } else if (!primaryKey.equals(other.primaryKey)) return false;
    return true;
  }
}
</pre>
<p>The Entity and Table annotations are straightforward <a href="http://java.sun.com/developer/technicalArticles/J2EE/jpa/">JPA</a> annotations.  The Id annotation on the primaryKey instance variable indicates that an embedded object will be used for the primary key.</p>
<p>The @OneToMany annotation with the mappedBy element indicates a bidirectional relationship with the Many side as the owner.</p>
<p>Annotation of the ParentPrimaryKey is straightforward:</p>
<pre class="brush: java">
package com.beavercreekconsulting.example;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class ParentPrimaryKey implements Serializable {

  private static final long serialVersionUID = -2912693560354598053L;

  @Column(name = &quot;id&quot;)
  Integer id;

  @Column(name = &quot;version&quot;)
  Integer version;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public Integer getVersion() {
    return version;
  }

  public void setVersion(Integer version) {
    this.version = version;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    result = prime * result + ((version == null) ? 0 : version.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    final ParentPrimaryKey other = (ParentPrimaryKey) obj;
    if (id == null) {
      if (other.id != null) return false;
    } else if (!id.equals(other.id)) return false;
    if (version == null) {
      if (other.version != null) return false;
    } else if (!version.equals(other.version)) return false;
    return true;
  }
}
</pre>
<p>The embeddable class needs to implement  Serializable, so I added Eclipse generated serialVersionUID, hashCode() and equals().</p>
<p>The ChildPrimaryKey class is pretty similar to ParentPrimaryKey:</p>
<pre class="brush: java">
package com.beavercreekconsulting.example;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;

@Embeddable
public class ChildPrimaryKey implements Serializable {

  private static final long serialVersionUID = -452758257162645576L;

  @Column(name=&quot;id&quot;)
  Integer id;

  @ManyToOne
  Parent parentForeignKey;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public Parent getParentForeignKey() {
    return parentForeignKey;
  }

  public void setParentForeignKey(Parent parentForeignKey) {
    this.parentForeignKey = parentForeignKey;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    result = prime * result
      + ((parentForeignKey == null) ? 0 : parentForeignKey.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    final ChildPrimaryKey other = (ChildPrimaryKey) obj;
    if (id == null) {
      if (other.id != null)
        return false;
    } else if (!id.equals(other.id))
      return false;
    if (parentForeignKey == null) {
      if (other.parentForeignKey != null)
        return false;
    } else if (!parentForeignKey.equals(other.parentForeignKey))
      return false;
    return true;
  }
}
</pre>
<p>The main annotations are @Column on the id field and @OneToMany on the parentForeignKey field.  This class also needs to implement java.io.Serializable, so I added serialVersionUID, hashCode() and equals().  Eclipse pointed out that the hashCode() method might not work correctly due to it&#8217;s dependence on parentForeignKey unless Parent also implements hashCode(), so I added that to Parent.</p>
<p>The final class, Child has the most complicated annotations.  The goal of the annotations is to point the persistence layer to the embedded primary key object for the purposes of object identification.  Here is a quick check list of the annotation that need to be applied:</p>
<ol>
<li>The instance variable that points to the primary key object should be annotated with @EmbeddedId.</li>
<li>Supply getters and setters for for primary key fields that are annotated with @Transient and delegate the setting and getting to the embedded primary key class.</li>
<li>Use @AssociationOverrides to point the values of the embedded class.  The name of the association to override has the form of &lt;instance-var-name&gt;.&lt;embedded-class-property&gt;.</li>
<li>Use an @AssociationOverride for each instance variable involved.  You are noting the fields of this class and how they will be mapped into the parent.</li>
<li>For the composite foreign key, use @JoinColumn to point from the database field back to the mapped attribute in the parent object.</li>
</ol>
<p>I do hope the above points help you to map your object in the unfortunate event that you have to deal with a similar situation.  If nothing else, just copy-n-paste-n-edit from the following code:</p>
<pre class="brush: java">
package com.beavercreekconsulting.example;

import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = &quot;child&quot;)
@AssociationOverrides( {
  @AssociationOverride(name = &quot;primaryKey.id&quot;,
    joinColumns = @JoinColumn(name = &quot;id&quot;)),
  @AssociationOverride(name = &quot;primaryKey.parentForeignKey&quot;,
    joinColumns = {
      @JoinColumn(name = &quot;parent_id&quot;,
        referencedColumnName = &quot;id&quot;),
      @JoinColumn(name = &quot;parent_version&quot;,
        referencedColumnName = &quot;version&quot;) }) })
public class Child {

  @EmbeddedId
  ChildPrimaryKey primaryKey = new ChildPrimaryKey();

  public ChildPrimaryKey getPrimaryKey() {
    return primaryKey;
  }

  public void setPrimaryKey(ChildPrimaryKey primaryKey) {
    this.primaryKey = primaryKey;
  }

  @Transient
  public Integer getId() {
    return getPrimaryKey().getId();
  }

  public void setId(Integer id) {
    getPrimaryKey().setId(id);
  }

  @Transient
  public Parent getParentForeignKey() {
    return getPrimaryKey().getParentForeignKey();
  }

  public void setParentForeignKey(Parent foreignKey) {
    getPrimaryKey().setParentForeignKey(foreignKey);
  }
}
</pre>
<p>The final section of code I have is an Example class which does a set of CRUD operations with this mapping.  I&#8217;ve used Spring in the example since I&#8217;m starting to believe this is Hibernate&#8217;s natural environment:</p>
<pre class="brush: java">
package com.beavercreekconsulting.example;

import java.util.Arrays;
import java.util.List;
import java.util.Random;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* Main entry point for example
*/
public class Example {

  HibernateTemplate hibernateTemplate;

  public static void main(String[] args) {
    ClassPathResource resource = new ClassPathResource(&quot;beans.xml&quot;);
    BeanFactory bf = new XmlBeanFactory(resource);
    Example example = (Example) bf.getBean(&quot;example&quot;);
    example.go();
  }

  @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  private void go() {
    create();
    read();
    update();
    delete();
    hibernateTemplate.flush();
  }

  private void update() {
    List parents = hibernateTemplate.find(&quot;from Parent&quot;);
    for (Parent p : parents) {
        Child c = new Child();
        c.setParentForeignKey(p);
        c.setId(new Random().nextInt());
        p.getChildren().add(c);
        hibernateTemplate.save(c);
    }
  }

  private void read() {
    List parents = hibernateTemplate.find(&quot;from Parent&quot;);
  }

  private void delete() {
  List parents = hibernateTemplate.find(&quot;from Parent&quot;);
  for (Parent p : parents) {
    for (Child c : p.getChildren()) {
      hibernateTemplate.delete(c);
    }
    hibernateTemplate.delete(p);
    }
  }

  void create() {
    ParentPrimaryKey ppk = new ParentPrimaryKey();
    ppk.setId(new Random().nextInt());
    ppk.setVersion(new Random().nextInt());
    Parent p = new Parent();
    p.setPrimaryKey(ppk);
    hibernateTemplate.save(p);

    Child c = new Child();
    p.setChildren(Arrays.asList(c));
    c.setParentForeignKey(p);
    c.setId(new Random().nextInt());
    hibernateTemplate.save(c);
  }

  public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
    this.hibernateTemplate = hibernateTemplate;
  }

  public HibernateTemplate getHibernateTemplate() {
    return hibernateTemplate;
  }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/10/hibernate-annotations-for-a-one-to-many-mapping/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Jaxer 1.0 RC Support for REST and RPC</title>
		<link>http://beavercreekconsulting.com/blog/2008/10/jaxer-10-rc-support-for-rest-and-rpc/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/10/jaxer-10-rc-support-for-rest-and-rpc/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 03:29:09 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Jaxer]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=12</guid>
		<description><![CDATA[Jaxer 1.0 RC is out and getting ready to go.  To me, the big news is that server side APIs such as REST and RPC protocols have been promoted to first class citizens.
Up to now, the Jaxer application server has been HTML template oriented.  Jaxer is a Server Side JavaScript (SSJS) port of [...]]]></description>
			<content:encoded><![CDATA[<p>Jaxer <a href="http://www.aptana.com/jaxer/download ">1.0 RC</a> is out and getting ready to go.  To me, the big news is that server side APIs such as <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> and <a href="http://en.wikipedia.org/wiki/Remote_procedure_call">RPC</a> protocols have been promoted to first class citizens.</p>
<p>Up to now, the Jaxer application server has been HTML template oriented.  Jaxer is a Server Side JavaScript (SSJS) port of <a href="http://www.mozilla.org/">Mozilla</a>, and of course, that&#8217;s a really cool thing.  If you&#8217;re a JavaScript Ninja, you finally have an application server which speaks your native language.</p>
<p>However, up to 1.0 RC, the server side <a href="http://www.aptana.com/node/275">processing model</a> has been page/template oriented.  On the server side, you&#8217;ve had to provide a concrete HTML page on the server to trigger Jaxer processing.   With the 1.0 RC, you can now map an URL to JavaScript files that provide the HTTP response.   This feature makes is easier to provide REST or RPC interfaces on top of server side JavaScript code.</p>
<p>The configuration I&#8217;ve been using is Apache and the standalone Jaxer server.    Jaxer comes bundled with Aptana&#8217;s <a href="http://aptana.com/studio">Studio</a> IDE which is the easiest configuration for getting started on Jaxer.   However, you&#8217;ll have to come to terms with deploying Jaxer under <a href="http://httpd.apache.org/">Apache</a> when you go to production (OK, sure, you can deploy to Aptana&#8217;s <a href="http://aptana.com/cloud">Cloud</a> which deploys direct from Studio, but that&#8217;s another beta topic).</p>
<p>Recent releases (prior to 1.0) have allowed you to interrupt the normal template processing of page and substitute arbitrary content and content types to be returned to the <a href="http://forums.aptana.com/viewtopic.php?t=5412&amp;highlight=content+type">client</a>.  In order to make this work, you&#8217;ve had to provide a file that Apache is configured to hand off to the Jaxer processor.</p>
<p>I&#8217;m working on an Jaxer application that responds to REST URLs.  Here is the approach I was using for releases prior to 1.0.  I wrote Apache <a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html">mod_rewrite</a> rule to hit a front controller, where the front controller is an HTML page that Jaxer processes.  I added the following to my httpd.conf file:</p>
<pre class="brush: html">
RewriteEngine on
RewriteRule /world.* /world/index.html
</pre>
<p>My plan is that index.html will respond to REST URLs for POST, GET, PUT, and DELTE request such as :</p>
<p>http://&lt;host&gt;/world/&lt;entity&gt;/&lt;id&gt;</p>
<p>The one issue I ran into was that the Apache configuration that tells Apache to hand off a request to Jaxer for filtering needs a file extension and a content type.  The above URL has no file extension.  My solution was to place the font controller file in it&#8217;s own directory and set Jaxer filter handling to all content in the specified directory (in my httpd.conf file):</p>
<pre class="brush: html">
&lt;Directory &quot;c:/opt/xampp/htdocs/world&quot;&gt;
JaxerFilter *
JaxerFilterContentType text/html
Order Deny,Allow
Deny from all
Allow from all
&lt;/Directory&gt;
</pre>
<p>The good news is that the 1.0 RC allows direct <a href="http://www.aptana.com/docs/index.php/Migrating_from_Jaxer_beta">specification </a>of JavaScript files to handle REST type URLs<a href="http://www.aptana.com/docs/index.php/Migrating_from_Jaxer_beta"></a>.  Tricks like the  above rewrite rules won&#8217;t be need for REST.  This is a big change as server side code stands alone, without a HTML page template.  To me, this is the difference between a <a href="http://www.devx.com/tips/Tip/25217">Servlet and a JSP</a>.</p>
<p>With the 1.0 RC it appears that you can match URLs to execution of server side JavaScript files, which feels much more like a J2EE web.xml file which matches URLs to invocation of server side code (servlets).</p>
<p>I&#8217;m working up some examples of all this with 1.0 RC which aren&#8217;t quite baked yet.  If you&#8217;re in a hurry to make REST work with 1.0, here are the files to look at from the standalone <a href="http://www.aptana.com/jaxer/download">release</a>:</p>
<pre>
jaxer\confs\jaxer-*.httpd.conf
jaxer\default_local_jaxer\conf\configApps.js
jaxer\framework\extensions\serviceDispatcher.js
</pre>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/10/jaxer-10-rc-support-for-rest-and-rpc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jaxer, E4X and Prototype</title>
		<link>http://beavercreekconsulting.com/blog/2008/08/jaxer-e4x-and-prototype/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/08/jaxer-e4x-and-prototype/#comments</comments>
		<pubDate>Mon, 04 Aug 2008 13:50:00 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Jaxer]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=10</guid>
		<description><![CDATA[The ECMAScript for XML standard a.k.a “E4X” is a cool addition to JavaScript that provides for native support of XML.  E4X adds nifty features such as simplified XML traversal and XML literals to the language.  E4X is supported in Mozilla and Adobe JavaScript implementations.  The lack of support in IE hinders the [...]]]></description>
			<content:encoded><![CDATA[<p>The ECMAScript for XML standard a.k.a “<span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://www.ecma-international.org/publications/standards/Ecma-357.htm">E4X”</a></span></span> is a cool addition to JavaScript that provides for native support of XML.  E4X adds nifty features such as simplified XML traversal and XML literals to the language.  E4X is supported in Mozilla and Adobe JavaScript <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://en.wikipedia.org/wiki/E4x#Implementations">implementations</a></span></span>.  The lack of support in <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://www.w3schools.com/e4x/e4x_browsers.asp">IE</a></span></span> hinders the widespread adoption of E4X.  However, E4x is supported on Aptana <a href="http://aptana.com/jaxer">Jaxer</a>.</p>
<p>I&#8217;ve been using Jaxer for web development lately.  Jaxer is a web application server which uses JavaScript on the server side.  The server-side JavaScript implementation is based on Mozilla, and E4X is supported.  So, if you&#8217;re using Jaxer, there is nothing holding you back from using E4X on the server side.</p>
<p>With this in mind, I&#8217;ve cooked up an example intended to whet your appetite for E4X.  The source code is shown below.  The example executes a query against a database and renders each returned row as a HTML table.  I&#8217;m using E4X for two tasks: storing configuration data and filling in a HTML template.</p>
<p>Note how various scripts or functions are tagged with <code>runat='server'</code>. This is how Jaxer knows which scripts to process on the server and which not to.  All of the scripts in this example run on the server.  The execution of the scripts is started by the <code>onserverload</code> attribute of the body tag.  This is the server-side equivalent to the <code>onload</code> attribute in the browser context.</p>
<p>For the configuration example, I stored SQL statements in an XML document.  I needed a select query to execute against the database, and then of course I realized I needed some DDL to create the table and some more SQL to insert records.  I decided to store all of my queries as E4X XML literals in JavaScript embedded in my HTML page.  The embedded XML is seen only on the Jaxer Server, and not in the client browser.  On lines 12-37 I used an <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Processing_XML_with_E4X#Creating_an_XML_object">XML literal</a></span></span> to declare an XML document containing 3 SQL statements.</p>
<p>A couple of points to note.  First I embedded this configuration into a HTML page.  With the Jaxer server-side facilities for accessing the file system, one could store the XML in a file and share the configuration across HTML pages.  Second, with a CDATA section (lines 27-29), I don&#8217;t have to worry about escaping my SQL to make valid XML.</p>
<p>IMHO, the coolest E4X feature is simplified DOM access.  The code to pull out a particular SQL statement by id is:</p>
<pre class="brush: javascript">
var sqlToRun = sqlStatements.sql.(@id == &#039;select-persons-no-heavier-than&#039;);
</pre>
<p>After executing the select query, I render each row as a little HTML table.  On line 50 I access each record via the <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://www.aptana.com/reference/jaxer/api/Jaxer.DB.ResultSet.html">Jaxer.DB.ResultSet</a></span></span> API.  I create a table for each record with an XML literal on lines 52-69.  One nice feature of E4X is the ability to execute arbitrary JavaScript code within the XML literal.  For example, line 67:</p>
<pre class="brush: javascript">
&lt;td&gt;{(dbRecord.weight_kg / 0.454).toFixed(2)}&lt;/td&gt;
</pre>
<p>reads a JavaScript object property, divides by .45, renders the number with 2 decimal places, and then places that value in the <code>td</code> tag.  Finally on line 74, I insert the table into the page&#8217;s DOM tree.  The insert is done with Prototype’s <code>Element.insert</code> method which takes a string or DOM Node as an argument and inserts the content into the page&#8217;s DOM tree.</p>
<p>Don&#8217;t forget, that all of the scripts tags (for prototype.js as well) have a <code>runat=”server”</code> attribute, so all of this action happens on the Jaxer server before the page is render as text and sent to the client.</p>
<p>One interesting point is that I used Prototype on the server side.  My usage was pretty modest here; I take it as a good sign that the server side JavaScript environment closely matches the JavaScript environment in a browser.</p>
<p>I’m pretty happy with this example code.  I think the templating of HTML turned out to be very transparent and easy to understand code.  Several factors contribute to clean code: XML literals avoid cluttering the code with quoted string and also allow value interpolation, and insertion of the XML strings into the DOM tree with Prototype.  This is a nice illustration of the handy features that are available in the Jaxer server side programming environment.</p>
<pre class="brush: javascript">
 &lt;html&gt;
     &lt;head&gt;
   &lt;title&gt;Jaxer E4X Example&lt;/title&gt;

     /*
    * All of the JavaScript is running on the server due to the
    * runat=&quot;server&quot; attribute of the script tags
    */
     &lt;script runat=&quot;server&quot; src=&quot;lib/prototype/prototype.js&quot;&gt;&lt;/script&gt;
     &lt;script runat=&quot;server&quot;&gt;

   // An XML literal holding template SQL
     var sqlStatements =
       &lt;sql-statements&gt;
         &lt;sql id=&#039;create-table&#039;&gt;
           create table if not exists person (
             id      integer,
             first_name  varchar(20),
             last_name   varchar(20),
             birth_date  datetime,
             weight_kg   decimal(5,2),
             height_m    decimal(5,2),
             constraint person_pk primary key(id)
           );
         &lt;/sql&gt;
         &lt;sql id=&#039;insert-person&#039;&gt;
           insert into person
             (id, first_name, last_name, birth_date, weight_kg, height_m)
           values
             (?, ?, ?, ?, ?, ?)
         &lt;/sql&gt;
         &lt;sql id=&#039;select-persons-no-heavier-than&#039;&gt;
           &lt;![CDATA[
             select * from person where weight_kg &lt;= ?
           ]]&gt;
         &lt;/sql&gt;
       &lt;/sql-statements&gt;;

     // Called on server side page load.
     // Triggered by the onserverload attribute of the body tag
       function showPersonDetails() {

     // Find a SQL statement by name
         var sqlToRun = sqlStatements.sql.(@id == &#039;select-persons-no-heavier-than&#039;);

     // Execute the SQL with the Jaxer.DB API
         var resultSet = Jaxer.DB.execute(sqlToRun, 200);

     // For each record returned from the DB...
     resultSet.rows.forEach(function(dbRecord, index) {
       // Create some markup using a XML Literal and value interpolation
           var tbl =
           &lt;table border=&#039;1&#039;&gt;
             &lt;tr&gt;
               &lt;td colspan=&quot;2&quot;&gt;Person Detail&lt;/td&gt;
             &lt;/tr&gt;
             &lt;tr&gt;
               &lt;td&gt;First name:&lt;/td&gt;
               &lt;td&gt;{dbRecord.first_name}&lt;/td&gt;
             &lt;/tr&gt;
             &lt;tr&gt;
               &lt;td&gt;First name:&lt;/td&gt;
               &lt;td&gt;{dbRecord.last_name}&lt;/td&gt;
             &lt;/tr&gt;
             &lt;tr&gt;
               &lt;td&gt;Weight in pounds:&lt;/td&gt;
               &lt;td&gt;{(dbRecord.weight_kg / 0.454).toFixed(2)}&lt;/td&gt;
             &lt;/tr&gt;
           &lt;/table&gt;;

           tbl += &lt;br/&gt;;

       // add the new markup to the page DOM
           $(&#039;person-details&#039;).insert(tbl.toXMLString());
     });
       }

     &lt;/script&gt;
   &lt;/head&gt;
   &lt;body onserverload=&quot;showPersonDetails();&quot;&gt;
       &lt;div id=&#039;person-details&#039;&gt;
       &lt;/div&gt;
   &lt;/body&gt;
 &lt;/html&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/08/jaxer-e4x-and-prototype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jaxer CRUD</title>
		<link>http://beavercreekconsulting.com/blog/2008/08/jaxer-crud/</link>
		<comments>http://beavercreekconsulting.com/blog/2008/08/jaxer-crud/#comments</comments>
		<pubDate>Mon, 04 Aug 2008 01:18:48 +0000</pubDate>
		<dc:creator>martykube</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Jaxer]]></category>

		<guid isPermaLink="false">http://beavercreekconsulting.com/blog/?p=9</guid>
		<description><![CDATA[Aptana&#8217;s Jaxer is a Web Application platform that uses JavaScript on the server side.  I&#8217;m starting to develop a real taste for the JavaScript language, so Jaxer is a nice place to try out new modes of JavaScript programming.
Server side programming for Web Applications typically involves a good bit of interaction with a database. [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://aptana.com/">Aptana&#8217;s</a></span></span> <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://aptana.com/jaxer">Jaxer</a></span></span> is a Web Application platform that uses JavaScript on the server side.  I&#8217;m starting to develop a real taste for the JavaScript language, so Jaxer is a nice place to try out new modes of JavaScript programming.</p>
<p>Server side programming for Web Applications typically involves a good bit of interaction with a database.  As a Java developer, I typically use <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://java.sun.com/javase/technologies/database/">JDBC</a></span></span> or an Object Relational Mapping (ORM) framework such as <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://www.hibernate.org/">Hibernate</a></span></span> for database interaction.  If you look around, you&#8217;ll find JavaScript lacks such established API/Frameworks for DB interaction  (though it looks like some JavaScript ORMs are being actively <a title="JavaScript ORM" href="http://forums.aptana.com/viewforum.php?f=42">developed</a>).   At this point in time, things are pretty much DIY.</p>
<p>With this in mind, I&#8217;ve worked up some code example for <span style="color: #000080;"><span style="text-decoration: underline;"><a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a></span></span> operations using the Jaxer database API.  This is a simple example, intended to help folks climb up the Jaxer learning curve.  The complete source code for the example is at the bottom of this post.</p>
<p>The example reads and writes from elements on a HTML page and also a database table.  In the example, there are HTML tables which describe a person, and likewise, I&#8217;ve created a table in the database that has the same attributes (with slightly different names, just to keep this real.  The table DDL is in the example code).  Here&#8217;s a screen shot of the example:</p>
<p><img src="http://beavercreekconsulting.com/img/jaxer-crud-screenshot.png" alt="Jaxer CRUD Example screenshoot" width="489" height="526" /></p>
<p>The flow of the example is:</p>
<p>1) Read attributes from the first (from the top) HTML table and then create a corresponding record in the database.</p>
<p>2) Read the same attributes back from the database and then populate the next HTML table</p>
<p>3) Read attributes from the third HTML table and update the database</p>
<p>4) Delete the record from the database.</p>
<p>Line 108 also shows an interesting capability of Jaxer:  The script block there is set to runat=”server-proxy”. This tells Jaxer to run these scripts at the server, but let them be callable from the browser.  So when I click the CRUD button on the client, it calls runExample on line 14, which in turn calls the four CRUD functions which run at the server.  I&#8217;m actually calling a function on the server directly from the client!  Note too that this example uses blocking calls from the browser to the Jaxer server.  It is very easy to change this code to the Jaxer asynchronous API, which is likely topic for my next post.</p>
<p>Without further ado &#8211; the code:</p>
<pre class="brush: javascript">
 &lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot; &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;
 &lt;html&gt;
   &lt;head&gt;
     &lt;title&gt;Jaxer CRUD&lt;/title&gt;
     &lt;script type=&quot;text/javascript&quot; src=&quot;prototype.js&quot;&gt;&lt;/script&gt;

     /*
      *  Scripts that run in the client browser
      */
     &lt;script runat=&#039;client&#039;&gt;
       //
       //  Run the example on button click
       //
       function runExample() {
         // server side method that creates a table if needed
         createTable();
         // Do the CRUD operations
         createPerson();
         readPerson();
         updatePerson();
         deletePerson();
       }

       // Create a person in the DB based on properties read from a HTML table
       function createPerson() {
         // pull properties from HTML table
         var p = objectFromTable(&#039;create-table&#039;);
         // write to DB via server proxy call
         createPerson_Server(p);
       }

       // Read a person from the DB and write to a HTML table
       function readPerson() {
         // read the person from the DB via a server proxy method
         var p = readPerson_Server(1);
         // populate the HTML table
         tableFromObject(&#039;read-table&#039;, p);
       }

       // Update a person in the DB based on properties read from an HTML table
       function updatePerson() {
         // read the person properties from an HTML table
         var p = objectFromTable(&#039;update-table&#039;);
         // update the DB via a server proxy call
         updatePerson_Server(p);
       }

       // Delete a person in the DB
       function deletePerson() {
         // Server call to delete in the DB
         deletePerson_Server(1);
       }

       //
       // Utility functions
       //

       // populate an object from values in a HTML table
       function objectFromTable(tableId) {
         var o = {};
         var propNames = $$(&#039;#&#039; + tableId + &#039; th&#039;);
         var props = $$(&#039;#&#039; + tableId + &#039; td&#039;);
         var propNum = 0;
         propNames.each(function(item) {
           o[item.innerHTML] = props[propNum++].innerHTML;
         });
         o.birthDate = dateFromStr(o.birthDate);
         return o;
       }

       // populate a HTML table from values in an object
       function tableFromObject(tableId, anObject) {
         anObject.birthDate = strFromDate(anObject.birthDate);
         var propNames = $$(&#039;#&#039; + tableId + &#039; th&#039;);
         var props = $$(&#039;#&#039; + tableId + &#039; td&#039;);
         var propNum = 0;
         propNames.each(function(item) {
           props[propNum++].innerHTML = anObject[item.innerHTML];
         });
       }

       // convert from string &#039;yyyy-mm-dd&#039; to JS Date
       function dateFromStr(dateStr) {
         if(dateStr) {
           var dateParts = dateStr.split(&#039;-&#039;);
           var date = new Date();
           date.setFullYear(dateParts[0]);
           date.setMonth(dateParts[1] - 1);
           date.setDate(dateParts[2]);
         }
         return date;
       }

       // convert from JS Date to string &#039;yyyy-mm-dd&#039;
       function strFromDate(aDate) {
         var str = &#039;&#039;;
         if(aDate) {
           str +=  (aDate.getFullYear() +  (aDate.getMonth() + 1) + aDate.getDate());
         }
         return str;
       }
     &lt;/script&gt;

     /*
      *  Scripts that run on the server.
      *  Jaxer generated stubs are used to call these from the client.
      */
     &lt;script runat=&#039;server-proxy&#039;&gt;

       //
       // Server side persistence functions
       //

       // Write a new object to the DB
       function createPerson_Server(person) {
         // execute insert statement, binding to properties of passed in person
         Jaxer.DB.execute(
           &#039;insert into person ( &#039;+
             &#039;  id, first_name, last_name, birth_date, weight_kg, height_m &#039; +
           &#039; ) values (?, ?, ?, ?, ?, ?);&#039;,
           person.id, person.firstName,
           person.lastName, person.birthDate,
           person.weightInKilograms, person.heightInMeters
         );
       }

       // Read an existing record and return a JavaScript object
       function readPerson_Server(id) {
         // execute query and receive returned a Jaxer.DB.ResultSet
         var resultSet = Jaxer.DB.execute(&#039;select * from person where id = ?;&#039;, id);
         // select the first row since weonly care about 1 person
         var aRow = resultSet.rows[0];
         // map DB column names to front end column names
         var person = {
           id: aRow.id,
           firstName: aRow.first_name,
           lastName: aRow.last_name,
           birthDate: aRow.birth_date,
           weightInKilograms: aRow.weight_kg,
           heightInMeters: aRow.height_m
         };
         // return to client for display
         return person;
       }

       // From a JS Object, update a row in the DB
       function updatePerson_Server(person) {
         // Update all fields for the given primary key value
         Jaxer.DB.execute(
           &#039;update person set  &#039;+
             &#039;  first_name = ?, last_name = ?, birth_date = ?, weight_kg = ?, height_m = ? &#039; +
           &#039; where id = ?;&#039;,
           person.firstName, person.lastName, person.birthDate,
           person.weightInKilograms, person.heightInMeters,
           person.id
         );
       }

       // Delete a record in the DB
       function deletePerson_Server(id) {
         Jaxer.DB.execute(&#039;delete from person where id = ?;&#039;, id);
       }

       //  Create a table if the table is not already in the DB
       function createTable(){
         Jaxer.DB.execute(
           &#039;create table if not exists person (   &#039; +
           &#039; id      integer,   &#039; +
           &#039; first_name  varchar(20),   &#039; +
           &#039; last_name   varchar(20),   &#039; +
           &#039; birth_date  datetime,   &#039; +
           &#039; weight_kg   decimal(5,2),   &#039; +
           &#039; height_m    decimal(5,2),   &#039; +
           &#039; constraint person_pk primary key(id)); &#039;
         );
       }
     &lt;/script&gt;
     &lt;style&gt;
       .big-cap {
         color: blue;
         font-size:larger;
         font-style:italic;
       }
       body {
         font-family:Arial;
         font-size: 10pt;
       }
     &lt;/style&gt;
   &lt;/head&gt;
   &lt;body&gt;
     &lt;h3&gt;&lt;span class=&quot;big-cap&quot;&gt;C&lt;/span&gt;reate a person from this table&lt;/h3&gt;
     &lt;table border=&quot;1&quot; style=&quot;text-align: center&quot; id=&quot;create-table&quot;&gt;
       &lt;tr&gt;
         &lt;th&gt;id&lt;/th&gt;
         &lt;th&gt;firstName&lt;/th&gt;
         &lt;th&gt;lastName&lt;/th&gt;
         &lt;th&gt;birthDate&lt;/th&gt;
         &lt;th&gt;weightInKilograms&lt;/th&gt;
         &lt;th&gt;heightInMeters&lt;/th&gt;
       &lt;/tr&gt;
       &lt;tr&gt;
         &lt;td&gt;1&lt;/td&gt;
         &lt;td&gt;John&lt;/td&gt;
         &lt;td&gt;Doe&lt;/td&gt;
         &lt;td&gt;1975-11-20&lt;/td&gt;
         &lt;td&gt;90.7&lt;/td&gt;
         &lt;td&gt;1.82&lt;/td&gt;
       &lt;/tr&gt;
     &lt;/table&gt;
     &lt;hr/&gt;
     &lt;h3&gt;&lt;span class=&quot;big-cap&quot;&gt;R&lt;/span&gt;ead a person and populate this table&lt;/h3&gt;
     &lt;table border=&quot;1&quot; style=&quot;text-align: center&quot; id=&quot;read-table&quot;&gt;
       &lt;tr&gt;
         &lt;th&gt;id&lt;/th&gt;
         &lt;th&gt;firstName&lt;/th&gt;
         &lt;th&gt;lastName&lt;/th&gt;
         &lt;th&gt;birthDate&lt;/th&gt;
         &lt;th&gt;weightInKilograms&lt;/th&gt;
         &lt;th&gt;heightInMeters&lt;/th&gt;
       &lt;/tr&gt;
       &lt;tr&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
       &lt;/tr&gt;
     &lt;/table&gt;
     &lt;hr/&gt;
     &lt;h3&gt;&lt;span class=&quot;big-cap&quot;&gt;U&lt;/span&gt;pdate a person from this table&lt;/h3&gt;
     &lt;table border=&quot;1&quot; style=&quot;text-align: center&quot; id=&quot;update-table&quot;&gt;
       &lt;tr&gt;
         &lt;th&gt;id&lt;/th&gt;
         &lt;th&gt;firstName&lt;/th&gt;
         &lt;th&gt;lastName&lt;/th&gt;
         &lt;th&gt;birthDate&lt;/th&gt;
         &lt;th&gt;weightInKilograms&lt;/th&gt;
         &lt;th&gt;heightInMeters&lt;/th&gt;
       &lt;/tr&gt;
       &lt;tr&gt;
         &lt;td&gt;1&lt;/td&gt;
         &lt;td&gt;Jane&lt;/td&gt;
         &lt;td&gt;Smith&lt;/td&gt;
         &lt;td&gt;1978-1-1&lt;/td&gt;
         &lt;td&gt;89.2&lt;/td&gt;
         &lt;td&gt;1.76&lt;/td&gt;
       &lt;/tr&gt;
     &lt;/table&gt;
     &lt;hr/&gt;
     &lt;h3&gt;&lt;span class=&quot;big-cap&quot;&gt;D&lt;/span&gt;elete person with id = 1&lt;/h3&gt;
     &lt;hr/&gt;
     &lt;button onclick=&quot;runExample();&quot;&gt;Crud&lt;/button&gt;
   &lt;/body&gt;
 &lt;/html&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://beavercreekconsulting.com/blog/2008/08/jaxer-crud/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
