<?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>Model Metrics &#187; Tom Gersic</title>
	<atom:link href="http://www.modelmetrics.com/author/tgersic/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.modelmetrics.com</link>
	<description>Model Metrics Blog</description>
	<lastBuildDate>Sat, 31 Dec 2011 14:18:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Using XMLHttpRequest2 in iOS 5 or Android OS 3 to download binary files using HTML5/Phonegap</title>
		<link>http://www.modelmetrics.com/tomgersic/using-xmlhttprequest2-in-ios-5-to-download-binary-files-using-html5phonegap/</link>
		<comments>http://www.modelmetrics.com/tomgersic/using-xmlhttprequest2-in-ios-5-to-download-binary-files-using-html5phonegap/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 06:58:08 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=7600</guid>
		<description><![CDATA[One of the things&#160;added to Safari and UIWebView&#160;in iOS5 is support for&#160;XMLHttpRequest 2, which according to W3C adds new features &#34;such as cross-origin requests, progress events, and the handling of byte streams for both sending and receiving&#34;. As part of the last bit of that, it&#39;s now possible to set the responseType to&#160;arraybuffer, which is [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things&nbsp;<a href="http://www.mobilexweb.com/blog/ios-5-iphone-and-ipad-html5">added to Safari and UIWebView</a>&nbsp;in iOS5 is support for&nbsp;<a href="http://dev.w3.org/2006/webapi/XMLHttpRequest-2/">XMLHttpRequest 2</a>, which according to W3C adds new features &quot;such as cross-origin requests, progress events, and the handling of byte streams for both sending and receiving&quot;. As part of the last bit of that, it&#39;s now possible to set the responseType to&nbsp;<a href="https://developer.mozilla.org/en/JavaScript_typed_arrays">arraybuffer</a>, which is &quot;used to represent a generic, fixed-length binary data buffer&quot;.&nbsp;<a href="http://www.html5rocks.com/en/tutorials/file/xhr2/">More info here</a>. This is useful if you want to download binary such as image or audio data from a remote location, and potentially manipulate it before presenting it to the user.</p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">This has many possible applications for file transfer, but for instance, if you&#39;re writing an HTML5 / PhoneGap app for iOS 5, and you want to download an attached file from the current version (v23.0) of the&nbsp;<a href="http://wiki.developerforce.com/page/Chatter_API">Chatter REST API</a>, you need to send a GET request to:</p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080">https://test.salesforce.com/services/data/v23.0/chatter/files/[PUT THE FILE ID HERE]/content?versionNumber=1</span></p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">But, you have to include a few headers for authentication&hellip;</p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080">setRequestHeader(&quot;Authorization&quot;, &quot;OAuth &quot; + oauthToken);<br />
	</span></p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080">setRequestHeader(&#39;X-User-Agent&#39;, &#39;salesforce-toolkit-rest-javascript/v23.0&#39;);</span></p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">&hellip;so it&#39;s not like you can just dump the GET request into the src of an &lt;img&gt; tag. So, what you can do now in iOS 5 is send off an&nbsp;XMLHttpRequest with a responseType of &quot;arraybuffer&quot;, and use this data to write to a HTML5 Canvas object.</p>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">Here&#39;s the XMLHttpRequest:</p>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; var request = new XMLHttpRequest(); &nbsp; &nbsp;&nbsp;</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.open(&quot;GET&quot;, url, true);</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.responseType = &quot;arraybuffer&quot;;</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.setRequestHeader(that.authzHeader, &quot;OAuth &quot; + that.sessionId);</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.setRequestHeader(&#39;X-User-Agent&#39;, &#39;salesforce-toolkit-rest-javascript/&#39; + that.apiVersion);</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.onreadystatechange = function() {</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; // continue if the process is completed</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; if (request.readyState == 4) {</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // continue only if HTTP status is &quot;OK&quot;</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (request.status == 200) {</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // retrieve the response</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callback(request.response);</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch(e) {</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // display error message</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; alert(&quot;Error reading the response: &quot; + e.toString());</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; }</span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;line-height: normal;text-align: left"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px">&nbsp; &nbsp; request.send();</span></span></span></div>
<p style="margin-top: 0px;margin-right: 0px;margin-bottom: 10px;margin-left: 0px;padding-top: 10px;padding-right: 3px;padding-bottom: 5px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">And here&#39;s the body of the callback that handles Base64 encoding the arraybuffer and writing that data to a Canvas using the Data URI Scheme:</p>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;text-align: left">
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>function(response){</tt></span></span></span></div>
<div style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; var imageCanvas = $(&#39;#&#39;+value.id);</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; var cxt = imageCanvas[0].getContext(&quot;2d&quot;);</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt><br />
			</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; var myImage = new Image();</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt><br />
			</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; myImage.src = &quot;data:&quot;+value.mimeType+&quot;;base64,&quot;+base64ArrayBuffer(response);</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt><br />
			</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; imageCanvas[0].width=myImage.width;</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; imageCanvas[0].height=myImage.height;</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt><br />
			</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>&nbsp; &nbsp; cxt.drawImage(myImage,0,0,myImage.width,myImage.height);</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-family: 'courier new', courier, monospace"><span style="margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial;font-size: 10px"><tt>}</tt></span></span></span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial"><span style="color:#000080"><br />
			</span></div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">For the Base64 encoding, I used this handy function that I found&nbsp;<a href="http://pastebin.com/23PLrQ1Q">over on PasteBin</a>.</div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">&nbsp;</div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">Note, I haven&#39;t tested it, but this should (<a href="http://caniuse.com/xhr2">probably</a>) work on Android OS 3.0 (Honeycomb) as well.</div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">&nbsp;</div>
<div style="line-height: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;border-top-width: 0px;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-style: initial;border-color: initial">If you&#39;re interested in doing all this with <a href="https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/">ForceTK</a>, take a look at this <a href="https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/pull/9">Pull Request</a>&nbsp;over on GitHub.</div>
</p></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/using-xmlhttprequest2-in-ios-5-to-download-binary-files-using-html5phonegap/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dreamforcenger Hunt!</title>
		<link>http://www.modelmetrics.com/general/dreamforcenger-hunt/</link>
		<comments>http://www.modelmetrics.com/general/dreamforcenger-hunt/#comments</comments>
		<pubDate>Mon, 29 Aug 2011 14:55:43 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>
		<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=7352</guid>
		<description><![CDATA[Dreamforcenger Hunt is an Android GPS based scavenger hunt for Dreamforce 2011. You can play during the week of Dreamforce, and win a great&#160;Samsung Galaxy Tab 10.1. The game is open now through&#160;Noon, PST, on Friday, September 2.&#160;The app uses Database.com, oAuth 2.0, the SFDC REST API, and a custom Apex Webservice. We will be [...]]]></description>
			<content:encoded><![CDATA[<p><img align="right" alt="" height="333" src="http://www.modelmetrics.com/wp-content/uploads/small(2).png" style="margin:10px" width="200" />Dreamforcenger Hunt is an Android GPS based scavenger hunt for Dreamforce 2011. You can play during the week of Dreamforce, and <strong>win a great&nbsp;<a href="http://www.samsung.com/global/microsite/galaxytab/10.1/index.html">Samsung Galaxy Tab 10.1</a></strong>. The game is open now through&nbsp;Noon, PST, on Friday, September 2.&nbsp;The app uses Database.com, oAuth 2.0, the SFDC REST API, and a custom Apex Webservice. We will be digging through the code in the&nbsp;<a href="https://dreamevent.my.salesforce.com/a0930000009YIOt">Application Development with Android</a>&nbsp;session, so I hope to see you there.</p>
<p>The code for this app will be released on Github.</p>
<p>To play, you must first register at <a href="http://bit.ly/dreamforcenger">http://bit.ly/dreamforcenger</a>.</p>
<p>You can then download and log into the Dreamforcenger Hunt app, which is available in the Android Marketplace:</p>
<p><a href="http://market.android.com/details?id=com.modelmetrics.dreamforcengerhunt"> <img alt="Available in Android Market" src="http://www.android.com/images/brand/60_avail_market_logo2.png" /> </a></p>
<p><strong>Rules of the Game</strong></p>
<p>1. Dreamforcenger Hunt is played by registering and installing the Dreamforcenger Hunt app on your Android phone. This app is available in the Android Market. In the app, you will find a list of clues for scavenger hunt locations around San Francisco. To find a location, you will have to go to that location, and click the &quot;Geotag It!&quot; button. If you have found the item, the app will tell you so, and it will be marked as found in Database.com for your user.</p>
<p>2. The person that finds the most scavenger hunt items will win the prize, a <a href="http://www.samsung.com/global/microsite/galaxytab/10.1/index.html">Samsung Galaxy Tab 10.1</a></p>
<p>3. To be eligible to win, you don&#39;t need to attend the <a href="https://dreamevent.my.salesforce.com/a0930000009YIOt">Application Development with Android</a>&nbsp;session, but you do need to be a <a href="http://dreamforce.com">Dreamforce 2011</a> attendee.</p>
<p>4. Employees of Model Metrics and Salesforce.com may participate in the scavenger hunt, but are ineligible to win the prize.</p>
<p>5. In the event of a tie, the winner will be chosen at random from among the tied users.</p>
<p>6. Additional hunt locations may be added after the game begins, so if you find all of them, don&#39;t assume more won&#39;t be added.</p>
<p>7. The game ends at Noon, PST, on Friday, September 2. A winner will be chosen at that time. The winner may pick the prize up in person, or if that is impossible, the prize will be mailed to the winner at a later date.</p>
<p>8. You must register with your real name and email address. Accounts that use obviously fake names or email addresses will be deactivated.</p>
<p>9. Any attempts to hack the system will result in an ineligibility to win the prize. Please play fair.</p>
<p>10. Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/general/dreamforcenger-hunt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>oAuth 2.0 for Salesforce.com</title>
		<link>http://www.modelmetrics.com/tomgersic/oauth-2-0-for-salesforce-com/</link>
		<comments>http://www.modelmetrics.com/tomgersic/oauth-2-0-for-salesforce-com/#comments</comments>
		<pubDate>Sun, 21 Aug 2011 21:06:11 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=7324</guid>
		<description><![CDATA[At this point in time, we&#39;ve implemented the oAuth 2.0 User-Agent flow and the Refresh Token flow for iOS, Android, and Flex/AS3. I figure that makes us as much an expert at doing this as anybody, so I thought I&#39;d take a moment to describe some of the details. First off, the reason you want [...]]]></description>
			<content:encoded><![CDATA[<p>At this point in time, we&#39;ve implemented the oAuth 2.0 User-Agent flow and the Refresh Token flow for iOS, Android, and Flex/AS3. I figure that makes us as much an expert at doing this as anybody, so I thought I&#39;d take a moment to describe some of the details. First off, the reason you want to use oAuth 2.0 when developing apps for mobile devices&#8230; no token. We&#39;ve been developing mobile apps for Salesforce.com for the last 4 or so years, and the need to provide a username, password, and token has always been a pain point. Since it&#39;s a 24 character alpha-numeric string, this was especially problematic back before iPhones had copy/paste functionality (&quot;is that a l, an I or a 1?&quot;). With oAuth 2.0, you can finally get rid of having to worry about the token.</p>
<p>oAuth 2.0 is a popular universal specification for authentication to various web services. If you&#39;ve used a mobile app that logs into Facebook, Twitter, LinkedIn, or Chatter, you&#39;ve probably used it. for Salesforce.com provides four different authentication flows:</p>
<ul>
<li>Web Server</li>
<li>User-Agent</li>
<li>Refresh Token</li>
<li>Username/Password</li>
</ul>
<p>A combination of the User-Agent flow and Refresh Token flow are recommended for mobile applications, so that&#39;s what I&#39;ll demonstrate here.</p>
<p>First off, you should understand both flows from a high level:</p>
<p><img alt="" height="396" src="http://www.modelmetrics.com/wp-content/uploads/Login_oAuth2.png" width="600" /></p>
<p>&nbsp;</p>
<p><strong>Salesforce Configuration</strong></p>
<p class="MsoNormal"><span>Both the User-Agent flow and the Refresh Token flow require a Remote Access Application be set up in the target SFDC org. This is configured under Setup=&gt;Develop=&gt;Remote Access. Required fields are Application, Contact Email, and Callback URL. There are a variety of rules about what the Callback URL can be, but the simplest way to do this is to have it be:&nbsp;</span><span style="font-size:9.5pt;font-family:Arial;color:black">https://login.salesforce.com/services/oauth2/success</span></p>
<p><!--StartFragment--></p>
<p class="MsoNormal"><span>Once saved, SFDC will generate and display a Consumer Key and a Consumer Secret. Both of these will be needed by the application for login.</span></p>
<p><!--EndFragment-->
<p><img alt="" height="235" src="http://www.modelmetrics.com/wp-content/uploads/Screen shot 2011-08-21 at 3_56_54 PM.png" width="568" /></p>
<p><strong>User-Agent Flow</strong></p>
<p>The User-Agent flow involves the use of a webview within the application. The app passes a special Salesforce.com URL to that webview, which renders a login view.&nbsp;</p>
<p class="MsoNormal">First, the user will be asked to log in, and then they will be asked to confirm that they would like to provide access to Salesforce.com using this application:</p>
<p class="MsoNormal"><img alt="" height="300" src="http://www.modelmetrics.com/wp-content/uploads/Screen shot 2011-08-21 at 3_53_20 PM.png" width="392" /></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal">The URL passed to SFDC in order to render this login view is in this format:</p>
<p class="MsoNormal"><span style="color:blue">https://login.salesforce.com/services/oauth2/authorize?</span></p>
<p class="MsoNormal"><span style="color:blue">response_type=token&amp;</span></p>
<p class="MsoNormal"><span style="color:blue">display=touch&amp;</span></p>
<p class="MsoNormal"><span style="color:blue">client_id=[CONSUMER KEY FROM REMOTE ACCESS]&amp;</span></p>
<p class="MsoNormal"><span style="color:blue">redirect_uri=https%3A%2F%2Flogin.salesforce.com%2Fservices%2Foauth2%2Fsuccess</span></p>
<p class="MsoNormal">Upon successful login, SFDC will redirect the webview to the URL specified as the redirect_uri (which must be the same as the Callback URL specified in the Remote Access Application setup). After the Callback URL will be a hash tag and then a series of parameters returned by Salesforce:</p>
<p class="MsoNormal"><b>access_token</b>=[ACCESS TOKEN (Session Id)]</p>
<p class="MsoNormal">&amp;<b>refresh_token</b>=[REFRESH TOKEN]</p>
<p class="MsoNormal">&amp;<b>instance_url</b>=https%3A%2F%2Fna1.salesforce.com</p>
<p class="MsoNormal">&amp;<b>id</b>=https%3A%2F%2Flogin.salesforce.com%2Fid%[ORG ID]%[USER ID]</p>
<p class="MsoNormal">&amp;<b>issued_at</b>=1312403866216</p>
<p class="MsoNormal">&amp;<b>signature</b>=[SIGNATURE]</p>
<p class="MsoNormal">The Access Token specified here is the Session ID that will be used for all subsequent calls to the API. The Refresh Token must be saved securely to disk, as it will be used in conjunction with the Consumer Key and Consumer Secret to get a new Access Token from SFDC when the current on expires. The Org Id, User Id, Issued At Time (number of milliseconds since the Unix Epoch), and Signature should be saved as well.</p>
<p class="MsoNormal"><strong>Refresh Token Flow</strong></p>
<p class="MsoNormal">At some point in time, your Access Token will expire. This may come as a shock, so be sure to prepare your friends and family. The app will learn that the session ID has expired when it attempts to access the API and the response is either:</p>
<ul>
<li>SOAP API: HTTP 500 Internal Server Error, with a faultCode: &lt;faultcode&gt;sf:INVALID_SESSION_ID&lt;/faultcode&gt;</li>
<li>REST API: HTTP 401 Unauthorized</li>
</ul>
<p><img alt="" height="198" src="http://www.modelmetrics.com/wp-content/uploads/DreamforcengerHunt_401.png" width="502" /></p>
<p class="MsoNormal">The amount of time a session ID remains valid is configured under Security Controls =&gt; Session Settings<span>&nbsp; </span>in SFDC Setup. When it expires, the app will have to use the Refresh Token flow to request another Access Token from SFDC. To do this, the application will send a POST request to SFDC including the Refresh Token, the Consumer Key, and the Consumer Secret. SFDC will respond with a new Access Token.</p>
<p class="MsoNormal"><b>NOTE: At no time does the application store the Username or Password of the individual logging into the app.</b></p>
<p class="MsoNormal">&nbsp;</p>
<p class="MsoNormal"><img alt="" height="303" src="http://www.modelmetrics.com/wp-content/uploads/DreamforcengerHunt_RefreshTokenFlow.png" width="543" /></p>
<p class="MsoNormal">So, that&#39;s it. I hope you&#39;ve enjoyed this foray into the world of oAuth 2.0 and Salesforce.com.</p>
<p><!--EndFragment--><!--EndFragment-->
<p>&nbsp;</p>
<p><!--EndFragment-->
<p>&nbsp;</p>
<p><!--EndFragment--><!--EndFragment--></p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/oauth-2-0-for-salesforce-com/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Setting Up and Using DiffDog for Salesforce.com Deployment Validation</title>
		<link>http://www.modelmetrics.com/general/setting-up-and-using-diffdog-for-salesforce-com-deployment-validation/</link>
		<comments>http://www.modelmetrics.com/general/setting-up-and-using-diffdog-for-salesforce-com-deployment-validation/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 02:15:21 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>
		<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=7154</guid>
		<description><![CDATA[There are a few different ways to deploy metadata from org to org with Salesforce.com. The three main options are to use Eclipse, to use Ant (the &#34;Force.com Migration Tool&#34;), or to use Change Sets. The first two are completely manual to set up (although Ant, obviously, is able to be run over and over [...]]]></description>
			<content:encoded><![CDATA[<p><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">There are a few different ways to deploy metadata from org to org with Salesforce.com. The three main options are to use Eclipse, to use Ant (the &quot;Force.com Migration Tool&quot;), or to use Change Sets. The first two are completely manual to set up (although Ant, obviously, is able to be run over and over again). Change Sets have a lot of promise, because they do handy things like searching for dependencies, but as of this writing, they are still prone to missing important bits, especially with profiles, so you can&#39;t rely on them to produce a perfect deploy from one org to another. Consequently, it&#39;s important to be able to quickly validate that a deployment was successful, and that everything that you meant to deploy from one org to another actually did get deployed.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">Enter DiffDog&#8230;</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">DiffDog is a great tool for validating that the metadata between two orgs is identical, and, when used in conjunction with Eclipse, it can be used to push changes from one org to another. It can be used to compare any of the metadata types that are able to be checked out using Eclipse: Objects, Page Layouts, Profiles, Workflow, Reports, etc. The main benefit with this tool over other diff tools is that it allows for the comparison of XML files with ignoring the order of XML nodes. This is important because the metadata between two orgs is XML based, and can be functionally identical, but rendered in different orders. Because of this, with a regular flat-file diff tool, you will get lots of false positives. DiffDog can be configured to properly compare XML files, thus eliminating these false positives. This post describes some optimal settings for use with SFDC, and the process for comparing orgs and deploying changes.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">To start with, download the tool from Altova:&nbsp;</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="external free" href="http://www.altova.com/download/diffdog/diff_merge_tool_professional.html" rel="nofollow" title="http://www.altova.com/download/diffdog/diff_merge_tool_professional.html">http://www.altova.com/download/diffdog/diff_merge_tool_professional.html</a></span></p>
<p><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a id="License" name="License"></a></span></p>
<h2><span class="Apple-style-span" style="font-family: sans-serif;line-height: 19px">Setup</span></h2>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">Once you&#39;ve downloaded the app and registered it, go to the Tools menu, choose &quot;Comparison Options&quot;, and select the XML tab. This part is important: you want to make sure the comparison ignores the order of child nodes. This basically means that XML nodes can be rendered in any order and still be considered identical. Click the &quot;Ignore order of child nodes&quot; box in the Order section. All of the other options should be default, but double-check to make sure they match this screenshot.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog1.jpg" title="File:DiffDog1.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog1.jpg" border="0" height="452" src="http://modelmetricssoftware.com/wiki/images/6/61/DiffDog1.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="654" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	Additionally, if &quot;quick&quot; diff is turned on for folder comparison (it will be by default), make sure to turn it off:</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	<img alt="" height="184" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog2.jpg" width="503" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">You want to do extension-based comparison (EXT):</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="126" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog3.jpg" width="396" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	</span></p>
<p><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a id="Check_Out_the_Orgs" name="Check_Out_the_Orgs"></a></span></p>
<h2><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><span class="mw-headline">Check Out the Orgs</span></span></h2>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">You will now have to check out the metadata objects that you want to compare from both SFDC orgs using Eclipse. Let&#39;s assume one org is a sandbox and one is production. Note that if you want to compare profiles, you will need to select all of the metadata types for everything that you want to compare profile permissions for. For instance, if you want to compare Field-Level Security on Custom Objects, you will need to check out Profile metadata AND Custom Object metadata. SFDC only sends the profile metadata for the metadata types that you have checked out. If you try to do only profiles, the files will be practically empty.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog4.jpg" title="File:DiffDog4.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog4.jpg" border="0" height="780" src="http://modelmetricssoftware.com/wiki/images/4/46/DiffDog4.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="660" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	The metadata from the two orgs that you checked out will be located in your Workspace directory. You can generally figure out where this is by right-clicking on one of the files in Eclipse, and selecting &quot;Properties&quot;.</span></p>
<p><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a id="Using_DiffDog" name="Using_DiffDog"></a></span></p>
<h2><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><span class="mw-headline">Using DiffDog</span></span></h2>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">You&#39;ll then want to pick a metadata type and open the two org&#39;s folders for that type in DiffDog. For instance, to compare Objects, select &quot;Compare Directories&quot; from the File Menu&#8230;</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog5.jpg" title="File:DiffDog5.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog5.jpg" border="0" height="415" src="http://modelmetricssoftware.com/wiki/images/3/31/DiffDog5.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="262" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	&#8230;and then select a metadata folder for each org. I&#39;d suggest putting your sandbox org on the left and your production org on the right so that you&#39;re moving changes from left to right, but you can do it either way.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="380" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog6.jpg" width="456" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	<a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog7.jpg" title="File:DiffDog7.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog7.jpg" border="0" height="634" src="http://modelmetricssoftware.com/wiki/images/9/9b/DiffDog7.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="412" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">Once you&#39;ve done this, DiffDog will initiate a high-level diff of all files in the directories, and will display something like this. Lines displayed in black are identical, lines displayed in Red have differences, and lines in blue are missing in one org or the other.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="266" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog8.jpg" width="543" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">If you need to move an entire object over, you can do that here by clicking on the blue name and pressing the &quot;Copy from left to right&quot; or &quot;Copy from right to left&quot; button, depending on which direction you want to go.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog9.jpg" title="File:DiffDog9.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog9.jpg" border="0" height="80" src="http://modelmetricssoftware.com/wiki/images/8/83/DiffDog9.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="295" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	If you want to inspect the differences between two files, double-click on one, and it will launch a flat file-based diff that looks something like this:</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="375" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog10.jpg" width="600" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	This is not what you want. You want to select the &quot;Grid View&quot; tab at the bottom left of the window. This launches the grid-based diff tool that will show you differences between the two metadata objects:</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="296" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog11.jpg" width="400" /><br />
	</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	Differences are highlighted in light green, and the &quot;current difference&quot; is highlighted in a darker green. To move a change from one org to another, you&#39;ll have to click on the box in the grid in the org you want to move FROM, and then click the &quot;Make current difference&quot; button in the top toolbar (or hit Alt-Enter) to highlight it in dark green.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog12.jpg" title="File:DiffDog12.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog12.jpg" border="0" height="68" src="http://modelmetricssoftware.com/wiki/images/5/54/DiffDog12.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="331" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	Once you&#39;ve done this you can copy the change over with the &quot;Copy from Left to Right&quot; button:</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a class="image" href="http://modelmetricssoftware.com/wiki/index.php/File:DiffDog13.jpg" title="File:DiffDog13.jpg" rel="shadowbox[post-7154];player=img;"><img alt="File:DiffDog13.jpg" border="0" height="80" src="http://modelmetricssoftware.com/wiki/images/0/0a/DiffDog13.jpg" style="border-top-style: none;border-right-style: none;border-bottom-style: none;border-left-style: none;border-width: initial;border-color: initial;vertical-align: middle;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px" width="295" /></a></span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><br />
	</span></p>
<p><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><a id="Deploying_Your_Changes" name="Deploying_Your_Changes"></a></span></p>
<h2><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><span class="mw-headline">Deploying Your Changes</span></span></h2>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px">You&#39;ll then want to save (Ctrl-S or File=&gt;Save). This will save your changes locally. Note that they have not yet been deployed to SFDC. To do this, you&#39;ll have to go back to Eclipse. Find the file (or group of files) that you saved in your Eclipse project, right click on it, and select &quot;Refresh&quot;. This will cause Eclipse to attempt to deploy your changes to SFDC. This could result in one or more errors, so be sure to watch the Problems tab for any errors. If you&#39;re deploying to Production, this step can take some time if the org has a lot of Apex code, because all tests will be re-run when you deploy. A minute or so is common. 10-15 minutes isn&#39;t unheard of.</span></p>
<p style="margin-top: 0.4em;margin-right: 0px;margin-bottom: 0.5em;margin-left: 0px;line-height: 1.5em"><span class="Apple-style-span" style="font-family: sans-serif;font-size: 13px;line-height: 19px"><img alt="" height="431" src="http://www.modelmetrics.com/wp-content/uploads/DiffDog14.jpg" width="420" /><br />
	</span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/general/setting-up-and-using-diffdog-for-salesforce-com-deployment-validation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The day the cloud stood still. Lessons learned roundup&#8230;</title>
		<link>http://www.modelmetrics.com/general/the-day-the-cloud-stood-still-lessons-learned-roundup/</link>
		<comments>http://www.modelmetrics.com/general/the-day-the-cloud-stood-still-lessons-learned-roundup/#comments</comments>
		<pubDate>Wed, 27 Apr 2011 02:08:55 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>
		<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=6804</guid>
		<description><![CDATA[The&#160;well-publisized outage&#160;of EBS on multiple availability zones in the US-EAST-1 Region of AWS last week kicked off some excellent blog posts from companies who, through robust architectural choices, managed to weather the storm quite well. It lasted&#160;five days, it&#39;s been called the&#160;worst cloud computing disaster&#160;ever, and Amazon&#39;s&#160;communications strategy didn&#39;t exactly shine, but it has presented [...]]]></description>
			<content:encoded><![CDATA[<p>The&nbsp;<a href="http://gigaom.com/cloud/more-than-100-sites-went-down-with-ec2-including-your-paas-provider/"><span class="s1">well-publisized outage</span></a>&nbsp;of EBS on multiple availability zones in the US-EAST-1 Region of AWS last week kicked off some excellent blog posts from companies who, through robust architectural choices, managed to weather the storm quite well. It lasted&nbsp;<a href="http://www.eweek.com/c/a/Cloud-Computing/Final-Thoughts-on-the-FiveDay-AWS-Outage-236462/"><span class="s1">five days</span></a>, it&#39;s been called the&nbsp;<a href="https://www.benjenonline.com/blog/index.php/2011/04/26/amazon-ec2-outage-hobbles-websites-worst-cloud-computing-disaster/"><span class="s1">worst cloud computing disaster</span></a>&nbsp;ever, and Amazon&#39;s&nbsp;<a href="http://www.theregister.co.uk/2011/04/25/rightscale_analyses_amazon_outage/"><span class="s1">communications strategy didn&#39;t exactly shine</span></a>, but it has presented an opportunity to learn from the companies that are hosting their sites on the AWS cloud better than many of their peers.&nbsp;<title></title></p>
<p class="p2">This is just a round-up of some of these posts, and the advice given. They&#39;ve been edited down, of course, so be sure to read each of these articles for the whole story:</p>
<p class="p2"><a href="http://stu.mp/2011/04/the-cloud-is-not-a-silver-bullet.html"><b>The Cloud is Not a Silver Bullet</b></a><span class="s2"><b>&nbsp;&#8211;&nbsp;Joe Stump, CTO of SimpleGeo</b></span></p>
<ul class="ul1">
<li class="li1"><i>Everything needs to be automated. Spinning up new instances, expanding your clusters, backups, restoring from backups, metrics, monitoring, configurations, deployments, etc. should all be automated.</i></li>
<li class="li1"><i>You must build share-nothing services that span AZs at a minimum. Preferably your services should span regions as well, which is technically more difficult to implement, but will increase your availability by an order of magnitude.</i></li>
<li class="li1"><i>An avoidance of relying on ACID services. It&rsquo;s not that you can&rsquo;t run MySQL, PostgreSQL, etc. on the cloud, but the ephemeral and distributed nature of the cloud make this a much more difficult feature to sustain.</i></li>
<li class="li1"><i>Data must be replicated across multiple types of storage. If you run MySQL on top of RDS, you should be replicating to slaves on EBS, RDS multi-AZ slaves, ephemeral drives, etc. Additionally, snapshots and backups should span regions. This allows entire components to disappear and you to either continue to operate or restore quickly even if a major AWS service is down.</i></li>
<li class="li1"><i>Application-level replication strategies. To truly go multi-region, or to span across cloud services, you&rsquo;ll very likely have to build replication strategies into your application rather than relying those inherent in your storage systems.</i></li>
</ul>
<p class="p2"><span class="s3"><a href="http://don.blogs.smugmug.com/2011/04/24/how-smugmug-survived-the-amazonpocalypse/"><b>How SmugMug survived the Amazonpocalypse</b></a></span><span class="s2"><b>&nbsp;&#8211;&nbsp;Don MacAskill, CEO of SmugMug</b></span></p>
<ul class="ul1">
<li class="li1"><i>Spread across as many AZs as you can. Use all four.</i></li>
<li class="li1"><i>If your stuff is truly mission critical (banking, government, health, serious money maker, etc), spread across as many Regions as you can.</i></li>
<li class="li1"><i>Beyond mission critical? Spread across many providers.</i></li>
<li class="li1"><i>Since spreading across multiple Regions and providers adds crazy amounts of extra complexity, and complex systems tend to be less stable, you could be shooting yourself in the foot unless you really know what you&rsquo;re doing.</i></li>
<li class="li1"><i>Build for failure. Each component (EC2 instance, etc) should be able to die without affecting the whole system as much as possible.</i></li>
<li class="li1"><i>Understand your components and how they fail. Use any component, such as EBS, only if you fully understand it. For mission-critical data using EBS, that means RAID1/5/6/10/etc locally, and some sort of replication or mirroring across AZs, with some sort of mechanism to get eventually consistent and/or re-instantiate after failure events.</i></li>
<li class="li1"><i>Try to componentize your system. Why take the entire thing offline if only a small portion is affected?</i></li>
<li class="li1"><i>Test your components. I regularly kill off stuff on EC2 just to see what&rsquo;ll happen.</i></li>
</ul>
<p class="p2"><span class="s3"><a href="http://www.randomhacks.net/articles/2011/04/25/aws-outage-timeline-and-recovery-strategy-downtimes"><b>AWS outage timeline &amp; downtimes by recovery strategy</b></a></span><span class="s2"><b>&nbsp;&#8211;&nbsp;Eric Kidd, Randomhacks.net</b></span></p>
<p class="p2">Eric took an interesting look at various potential strategies, and how long a company would have been offline during the EBS outage:</p>
<ul class="ul1">
<li class="li1"><i>Rely on a single EBS volume with no snapshots: 3.5 days</i></li>
<li class="li1"><i>Deploy into a single availability zone, with EBS snapshots: over 12 hours</i></li>
<li class="li1"><i>Rely on multi-AZ RDS databases to fail over to another availability zone: longer than 14 hours for some users.</i></li>
<li class="li1"><i>Run in 3 AZs, at no more than 60% capacity in each: This is the approach taken by Netflix, which sailed through this outage without no known downtime</i></li>
<li class="li1"><i>Replicate data to another AWS region or cloud provider: This is still the gold standard for sites which require high uptime guarantees.</i></li>
</ul>
<p class="p1"><span class="s1"><a href="http://broadcast.oreilly.com/2011/04/the-aws-outage-the-clouds-shining-moment.html"><b>The AWS Outage: The Cloud&#39;s Shining Moment</b></a></span><b>&nbsp;&#8211;&nbsp;George Reese,&nbsp;Founder of Valtira and enStratus</b></p>
<p class="p2"><i>The Amazon model is the &quot;design for failure&quot; model. Under the &quot;design for failure&quot; model, combinations of your software and management tools take responsibility for application availability. The actual infrastructure availability is entirely irrelevant to your application availability. 100% uptime should be achievable even when your cloud provider has a massive, data-center-wide outage&#8230;</i></p>
<p class="p2"><i>There are several requirements for &quot;design for failure&quot;:</i></p>
<ul class="ul1">
<li class="li1"><i>Each application component must be deployed across redundant cloud components, ideally with minimal or no common points of failure</i></li>
<li class="li1"><i>Each application component must make no assumptions about the underlying infrastructure&mdash;it must be able to adapt to changes in the infrastructure without downtime</i></li>
<li class="li1"><i>Each application component should be partition tolerant&mdash;in other words, it should be able to survive network latency (or loss of communication) among the nodes that support that component</i></li>
<li class="li1"><i>Automation tools must be in place to orchestrate application responses to failures or other changes in the infrastructure (full disclosure, I am CTO of a company that sells such automation tools, enStratus)</i></li>
</ul>
<p class="p2"><span class="s1"><a href="http://agilesysadmin.net/ec2-outage-lessons"><b>Today&rsquo;s EC2 / EBS Outage: Lessons learned</b></a></span><b>&nbsp;&#8211;&nbsp;Stephen Nelson-Smith, Technical Director of Atalanta Systems</b></p>
<ul class="ul1">
<li class="li1"><i>Expect downtime&#8230;What matters is how you respond to downtime</i></li>
<li class="li1"><i>Use amazon&rsquo;s built-in availability mechanisms</i></li>
<li class="li1"><i>Think about your use of EBS:</i>
<ul class="ul2">
<li class="li1"><i>EBS is not a SAN</i></li>
<li class="li1"><i>EBS is multi-tenant&#8230;Consider using lots of volumes and building up your own RAID 10 or RAID 6 from EBS volumes.</i></li>
<li class="li1"><i>Don&rsquo;t use EBS snapshots as a backup&#8230;Although they are available to different availabilty zones in a given region, you can&rsquo;t move them between regions.</i></li>
<li class="li1"><i>Consider not using EBS at all</i></li>
</ul>
</li>
<li class="li1"><i>Consider building towards a vendor-neutral architecture&#8230;Cloud abstraction tools like Fog, and configuration management frameworks such as Chef make the task easier.</i></li>
<li class="li1"><i>Have a DR plan, and practice it</i></li>
<li class="li1"><i>Infrastructure as code is hugely relevant&#8230;one of the great enablers of the infrastructure as code paradigm is the ability to rebuild the business from nothing more than a source code repository, some new compute resource (virtual or physical) and an application data backup.</i></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/general/the-day-the-cloud-stood-still-lessons-learned-roundup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>It&#8217;s not broken. You&#8217;re just doing it wrong.</title>
		<link>http://www.modelmetrics.com/tomgersic/its-not-broken-youre-just-doing-it-wrong/</link>
		<comments>http://www.modelmetrics.com/tomgersic/its-not-broken-youre-just-doing-it-wrong/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 05:09:27 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=6776</guid>
		<description><![CDATA[Okay, so the title is a bit harsh. I was intrigued by the rather excellent post over at the blog Il y a du th&#233; renvers&#233; au bord de la table, [Rant] Web development is just broken. Yoric makes the argument that web developers are forced to deal with too many &#34;nightmares&#34; that have very [...]]]></description>
			<content:encoded><![CDATA[<p>Okay, so the title is a bit harsh.</p>
<p class="p1">I was intrigued by the rather excellent post over at the blog <b>Il y a du th&eacute; renvers&eacute; au bord de la table</b>, <a href="http://dutherenverseauborddelatable.wordpress.com/2011/04/18/rant-web-development-is-just-broken/"><span class="s1">[Rant] Web development is just broken</span></a>. Yoric makes the argument that web developers are forced to deal with too many &quot;nightmares&quot; that have very little to do with programming. First you have to decide on a programming language. Should you use PHP, C#, Java, Ruby, Perl, or Python? Then you have to choose a web server and OS. Windows/IIS or *nix and Apache? OSX? BSD? Solaris? If you go with Linux, which distro do you choose? Is it worth it to pay for Red Hat, or will Fedora do? What about Ubuntu? Then you have to choose a DBMS, of course. Do you want Oracle? Well, can you afford Oracle? Then there&#39;s MySQL, SQLServer, or PostgreSQL. Or maybe one of the NoSQL databases like MongoDB, CouchDB, or Cassandra. And then you probably want to choose a server-side framework. Rails? Spring? Zend? And a client-side framework, of course, so you don&#39;t have to worry too much about all the differences between the JS engines in each different browser. JQuery? Prototype? Scriptaculous?</p>
<p class="p1">And then, once everything is selected, it all has to be configured to work together without (too many) security holes. But, of course, how much does the average developer really know about configuring a secure Linux environment with Apache? Or setting up a secure IIS? And even if the developer does know a lot about configuring all of this, wouldn&#39;t it be more productive to have him or her focused on developing actual application features rather mucking around in Apache2.conf or php.ini, or trying to figure out why their package manager can&#39;t find the right package for some random server component? How do I configure CPAN, again? Do I really need the Multiverse, or will the Universe do? Then, of course, you&#39;ll probably want an ORM, and you&#39;ll need to decide on how you want to glue all the bits and pieces together.</p>
<p class="p1">Not to mention keeping all of that up to date and working as new releases get rolled out&#8230; oh, and what about scaling up to meet the increased demand if you start to get really popular and get bought by Conde Nast?</p>
<p class="p1">Great points. Couldn&#39;t agree more.&nbsp;Anybody guess where I&#39;m going with this?&nbsp;</p>
<p class="p1">Tired of worrying about infrastructure?&nbsp;You want to start coding now? Great, take a look at&nbsp;<a href="http://aws.amazon.com/elasticbeanstalk/"><span class="s1">Elastic Beanstalk</span></a>,&nbsp;<a href="http://www.heroku.com/"><span class="s1">Heroku</span></a>, or Force.com&nbsp;<a href="http://www.vmforce.com/"><span class="s1">VMForce</span></a>&nbsp;(yeah, I know, &quot;coming soon&quot;). No infrastructure setup required. You still have to choose a language and a platform, I guess, but that seems unavoidable. You have to make <i>some</i> choices in life. However, you don&#39;t have to care about which OS or web server to use, and you don&#39;t have to manage updates of server software. AWS might all be running in VMWare within a virtualized Windows 98 stack based on a billion hand-built Commodore 64s for all I care. As long as it works. And the DBMS is a service too&#8230; you don&#39;t have to set it up, you just pick whichever one you want. When VMForce is launched, you&#39;ll have database.com as a DBMS. With Elastic Beanstalk, you have RDS or SimpleDB. With Heroku, you have PostgreSQL out of the box, with a ton of other choices available, but you don&#39;t set them up yourself, you just add them to your account, and they get set up for you.</p>
<p class="p1">What about security? Does your data center have 24-hour manned security, including foot patrols and perimeter inspections? Well,&nbsp;<a href="http://trust.salesforce.com/trust/security/"><span class="s1">Salesforce does</span></a>. Is your server certified by PCI, ISO, SAS70, and HIPAA? Well,&nbsp;<a href="http://aws.amazon.com/security/"><span class="s1">AWS is</span></a>, and&nbsp;<a href="http://policy.heroku.com/security"><span class="s1">Heroku is hosted on AWS</span></a>, and they have their own operations team that monitors the system 24/7.&nbsp;Even Multi-Factor Authentication is&nbsp;<a href="http://aws.amazon.com/mfa/"><span class="s1">just another service</span></a>&nbsp;at AWS. And if somebody finds a security flaw in any of these platforms, it&#39;s not your problem. Somebody else can figure it out and fix it, hopefully before you even know about it. Of course, it&#39;s still important to write secure code, sanitize user inputs, parameterize SQL queries, etc., but at least that&#39;s all in _your_ code. You can focus on writing good code, and not on whether or not you accidentally configured an Apache mod incorrectly, or accidentally allowed anonymous FTP access to your web server, or if your version of PHP has a buffer overrun bug that will allow some random hacker to drop your User table.</p>
<p class="p1">You&#39;ll probably still need to glue some things together, and if you&#39;re doing web development, you&#39;ll still want a client-side framework so you don&#39;t have to worry too much about all the various inconsistencies between browsers, but with the infrastructure headaches out of the picture, it&#39;s easier to just start coding.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/its-not-broken-youre-just-doing-it-wrong/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>iOS Enterprise MDM Configuration Capabilities</title>
		<link>http://www.modelmetrics.com/general/ios-enterprise-mdm-configuration-capabilities/</link>
		<comments>http://www.modelmetrics.com/general/ios-enterprise-mdm-configuration-capabilities/#comments</comments>
		<pubDate>Wed, 06 Apr 2011 15:38:01 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[general]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=6721</guid>
		<description><![CDATA[Thought I&#39;d put together an easy to reference list of the various things that can be configured by an enterprise Mobile Device Management administrator for iOS: Password Required No Repeating/Ascending/Descending Characters Require Alphanumeric Minimum Password length Minimum number of non-alphanumeric characters required Maximum password age (1-730 days) Auto-lock (1-5 minutes) Password History (1-50 Passwords) Grace [...]]]></description>
			<content:encoded><![CDATA[<p>Thought I&#39;d put together an easy to reference list of the various things that can be configured by an enterprise Mobile Device Management administrator for iOS:<title></title></p>
<p class="p1"><b>Password</b></p>
<ul>
<li>Required</li>
<li>No Repeating/Ascending/Descending Characters</li>
<li>Require Alphanumeric</li>
<li>Minimum Password length</li>
<li>Minimum number of non-alphanumeric characters required</li>
<li>Maximum password age (1-730 days)</li>
<li>Auto-lock (1-5 minutes)</li>
<li>Password History (1-50 Passwords)</li>
<li>Grace Period for Device Lock (amount of time the device can be locked without prompting for a password on unlock)</li>
<li>Maximum number of failed attempts (before all data on device will be erased)</li>
</ul>
<p class="p1"><b>Restrictions</b></p>
<ul>
<li>Allow installing apps</li>
<li>Allow use of camera
<ul>
<li>Allow FaceTime</li>
</ul>
</li>
<li>Allow Screen Capture</li>
<li>Allow Automatic Sync while Roaming</li>
<li>Allow voice dialing</li>
<li>Allow In App Purchase</li>
<li>Allow Multiplayer Gaming</li>
<li>Allow Adding Game Center Friends</li>
<li>Force Encrypted Backups</li>
<li>Applications
<ul>
<li>Allow use of YouTube</li>
<li>Allow use of iTunes Music Store</li>
<li>Allow use of Safari
<ul>
<li>Enable autofill</li>
<li>Force fraud warning</li>
<li>Enable JavaScript</li>
<li>Block Pop-ups</li>
<li>Accept Cookes: Always, Never, From Visited Sites</li>
<li>Allow Explicit Music &amp; Podcasts</li>
</ul>
</li>
<li>Allowed Content Ratings
<ul>
<li>Movies: Don&#39;t Allow Movies, G, PG-13, R, NC-17, Allow All Movies</li>
<li>TV: Don&#39;t Allow TV Shows, TV-Y, TV-Y7, TV-G, TV-PG, TV-14, TV-MA, Allow All TV Shows</li>
<li>Apps: Don&#39;t Allow Apps, 4+, 9+, 12+, 17+, Allow All Apps</li>
</ul>
</li>
</ul>
</li>
</ul>
<p class="p1"><b>Wi-Fi</b></p>
<ul>
<li>Service Set Identifier (SSID)</li>
<li>Hidden Network (if target network is set to not broadcast)</li>
<li>Security Type: Any (Personal), None, WEP, WPA/WPA2, WEP Enterprise, WPA/WPA2 Enterprise, Any (Enterprise)</li>
<li>Password</li>
</ul>
<p class="p1"><b>VPN</b></p>
<p class="p2">&nbsp;</p>
<ul>
<li>Connection Name</li>
<li>Connection Type: L2TP, PPTP, IPSec (Cisco), Cisco AnyConnect, Juniper SSL, F5 SSL, Custom SSL</li>
<li>Server Hostname or IP Address</li>
<li>Account</li>
<li>User Authentication: Password, RSA SecurID</li>
<li>Shared Secret</li>
<li>Send All Traffic (Route all network traffic through VPN)</li>
<li>Proxy Setup</li>
</ul>
<p class="p1"><b>Email</b></p>
<ul>
<li>Account Description</li>
<li>Account Type: IMAP, POP</li>
<li>User Display Name</li>
<li>Email Address</li>
<li>Mail Server and Port</li>
<li>Authentication Type: None, Password, MD5 Challenge-Response, NTLM, HTTP MD5 Digest</li>
<li>Password</li>
<li>Use SSL</li>
</ul>
<p class="p1"><b>Exchange ActiveSync</b></p>
<ul>
<li>Account Name</li>
<li>Exchange ActiveSync Host (Exchange Server)</li>
<li>Use SSL</li>
<li>Domain</li>
<li>User</li>
<li>Email Address</li>
<li>Password</li>
<li>Past Days of Mail to Sync: No Limit, 1 Day, 3 Days, 1 Week, 2 Weeks, 1 Month</li>
<li>Authentication Credential Name</li>
<li>Authentication Credential</li>
<li>Include Authentication Credential Passphrase</li>
</ul>
<p class="p1"><b>LDAP</b></p>
<ul>
<li>Display Name</li>
<li>Account Username</li>
<li>Account Password</li>
<li>Account Hostname</li>
<li>Use SSL</li>
<li>Search Settings</li>
</ul>
<p class="p1"><b>CalDAV</b></p>
<ul>
<li>Account Description</li>
<li>Account Hostname and Port</li>
<li>Principal URL</li>
<li>Account Username</li>
<li>Account Password</li>
<li>Use SSL</li>
</ul>
<p class="p1"><b>CardDAV</b></p>
<ul>
<li>Account Description</li>
<li>Account Hostname and Port</li>
<li>Principal URL</li>
<li>Account Username</li>
<li>Account Password</li>
<li>Use SSL</li>
</ul>
<p class="p1"><b>Subscribed Calendar</b></p>
<ul>
<li>Description</li>
<li>URL</li>
<li>Username</li>
<li>Password</li>
<li>Use SSL</li>
</ul>
<p class="p1"><b>Web Clips (web pages saved to the home screen as bookmarks)</b></p>
<ul>
<li>Label</li>
<li>URL</li>
<li>Removable (yes/no)</li>
<li>Icon</li>
<li>Precomposed Icon</li>
<li>Full Screen</li>
</ul>
<p class="p1"><b>Credentials</b></p>
<ul>
<li>Specify PKCS1 and PKCS12 certificates needed to authenticate access to your network</li>
</ul>
<p class="p1"><b>SCEP</b></p>
<ul>
<li>URL for SCEP server</li>
<li>Name</li>
<li>Subject (representation of X.500 name)</li>
<li>Subject Alternative Name Type (None, RFC 822 Name, DNS Name, Uniform Resource Identifier)</li>
<li>Subject Alternative Name Value</li>
<li>NT Principal Name</li>
<li>Challenge</li>
<li>Key Size: 1024, 2048</li>
<li>Use as digital signature</li>
<li>Use for key encipherment</li>
<li>Fingerprint (hex string)</li>
</ul>
<p class="p1"><b>MDM</b></p>
<ul>
<li>MDM Server URL</li>
<li>Check in URL</li>
<li>Topic (Push notification topic for management messages)</li>
<li>Identity: Add credentials in Credentials payload, SCEP</li>
<li>Sign Messages: yes/no</li>
<li>Access Rights granted to remote administrators:
<ul>
<li>Query Device for:
<ul>
<li>Device Information
<ul>
<li>&nbsp;</li>
<li>unique device identifier (UDID)</li>
<li>device name</li>
<li>iOS version</li>
<li>device model name and hardware version</li>
<li>serial number</li>
<li>overall and available storage capacity</li>
<li>IMEI number</li>
<li>the modem firmware version</li>
<li>SIM card ICCID</li>
<li>and MAC addresses for integrated Wi-Fi and Bluetooth</li>
<li>carrier currently being used</li>
<li>the carrier specified by the current installed SIM card</li>
<li>the version of the carrier settings (APN) data</li>
<li>assigned phone number</li>
<li>whether or not data roaming is currently allowed</li>
<li>list of configuration profiles installed</li>
<li>list installed security certificates and expiry dates</li>
<li>list of enforced restrictions</li>
<li>hardware encryption capability</li>
<li>whether an unlock passcode is set</li>
<li>installed applications (with App identifier, name, version, and size)</li>
<li>a list of any application provisioning profiles with expiration dates.</li>
</ul>
</li>
</ul>
</li>
<li>General Settings</li>
<li>Security Settings</li>
<li>Network Settings</li>
<li>Restrictions</li>
<li>Configuration Profiles</li>
<li>Applications</li>
<li>Provisioning Profiles</li>
</ul>
</li>
<li>Add / Remove:
<ul>
<li>Configuration Profiles</li>
<li>Provisioning Profiles</li>
</ul>
</li>
<li>Security
<ul>
<li>Change device password</li>
<li>Remote Wipe</li>
</ul>
</li>
<li>Apple Push Notification Service
<ul>
<li>Use Development APNS Server</li>
</ul>
</li>
</ul>
<p class="p1"><b>Advanced</b></p>
<ul>
<li>Access Point Name (APN): The name of the GPRS access point</li>
<li>Access Point User Name</li>
<li>Access Point Password</li>
<li>Proxy Server and Port</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/general/ios-enterprise-mdm-configuration-capabilities/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Some Thoughts on Gamification</title>
		<link>http://www.modelmetrics.com/tomgersic/some-thoughts-on-gamification/</link>
		<comments>http://www.modelmetrics.com/tomgersic/some-thoughts-on-gamification/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 02:23:53 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>
		<category><![CDATA[bunchball]]></category>
		<category><![CDATA[game dynamics]]></category>
		<category><![CDATA[gamification]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=6641</guid>
		<description><![CDATA[There seems to be a lot of industry buzz lately around the concept of &#34;gamification&#34;, and the idea is basically one of applying game mechanics to the world of business to motivate employees or customers. Bunchball&#160;has done a really nice job with their Gamification 101 white paper of illustrating how gamification can work in a [...]]]></description>
			<content:encoded><![CDATA[<p>There seems to be a lot of industry buzz lately around the concept of &quot;gamification&quot;, and the idea is basically one of applying game mechanics to the world of business to motivate employees or customers. <a href="http://www.bunchball.com/">Bunchball</a>&nbsp;has done a really nice job with their <a href="http://www.bunchball.com/gamification/g101-banner.shtml">Gamification 101</a> white paper of illustrating how gamification can work in a variety of circumstances, and why you should be using it in your business. It&#39;s a good read, and a good place to get started learning the concepts. Some examples of gamification that they give are frequent flyer programs, where customers earn points and &quot;level up&quot; to different statuses over time, and Starbucks&#39; use of the Foursquare to check in and win &quot;trophies or badges&quot;. Another good resource is the Gamification Encyclopedia at <a href="http://gamification.org/wiki/Encyclopedia">Gamification.org</a>.</p>
<p><strong>Mechanics, Dynamics, and Aesthetics (MDA)</strong></p>
<p>So what makes a game? Bunchball discuss the terms &quot;game mechanics&quot; and &quot;game dynamics&quot; in their white paper, and those terms come from a game design approach called MDA (Mechanics, Dynamics, Aesthetics), described by Hunicke, LeBlanc, and Zubek in their article <a href="http://www.cs.northwestern.edu/~hunicke/MDA.pdf">MDA: A Formal Approach to Game Design and Game Research</a>. The idea is basically that a game designer creates various rules for a game (Mechanics). These rules then work together (in sometimes unexpected ways) to create a system (Dynamics). And a player experiences these Dynamics through the Aesthetics of the game, which they categorize into things like &quot;Challenge&quot;, &quot;Discovery&quot;, or &quot;Narrative&quot;. So, the game designer sets up the game by manipulating the Mechanics, and the player experiences the game through the Aesthetics. Put simply, if the designer can directly manipulate something by changing the rules of the game, it is part of the game mechanics. Dynamics are manipulated indirectly by the designer, and aesthetics are experienced by the player. Game design is complicated, then, because the experience of the player is two steps removed from the rules set forth by the designer.</p>
<p><a href="http://www.modelmetrics.com/wp-content/uploads/2011/03/MDA.png" rel="shadowbox[post-6641];player=img;"><img alt="" class="alignnone size-full wp-image-6647" height="173" src="http://www.modelmetrics.com/wp-content/uploads/2011/03/MDA.png" width="530" /></a></p>
<p>A simple example can be illustrated with the game of Poker. The mechanics of the game involve dealing cards, anteing, and betting. The dynamics of the game have emerged over time to include things like bluffing. And the aesthetics of the game include things like fellowship (it&#39;s a good game to play with friends) and challenge (your opponents present many obstacles to winning).</p>
<p><strong>Success!</strong></p>
<p>So what makes a game fun? Every game uses game mechanics, but <a href="http://en.wikipedia.org/wiki/Atari_video_game_burial">many have been utter failures</a>. What makes a gamification strategy successful? It&#39;s easy to throw together leader boards, loyalty programs, and point systems, but how do you actually drive behavior with gamification? And what exactly is a game anyway? It&#39;s one of those things that you know when you see it, but how do you actually define it? Chris Crawford offers an interesting definition of &quot;game&quot; in his book, <a href="http://www.amazon.com/Chris-Crawford-Game-Design/dp/0131460994">Chris Crawford on Game Design</a>, Basically, if there is no <strong>competition</strong> (either amongst players or against some form of AI), then what you have is a puzzle, not a game. Additionally, if you have no influence over how your opponent is performing, then that competition isn&#39;t a game either. By this definition, solitaire is a puzzle, because there is no competition. A drag race is a competition, but not a game, because you can&#39;t slow the other car down in any way. However, a race where you are allowed to run your opponent off the road is a game.</p>
<p>So, does a successful gamification strategy need to follow this definition? Does there need to be competition, and should employees or customers be able to alter other&#39;s ability to perform? Perhaps not, but competition is likely to be important in any successful gamification strategy.</p>
<p><strong>Pitfalls</strong></p>
<p>So, what are some pitfalls of game design? If some players are able to get too far ahead of the pack, does it create a disincentive for the rest of the players? How can you reward top players without discouraging everyone else? Consider Monopoly: The game starts out fun for everyone, but as one or more players start buying up all the property, the &quot;poorer&quot; players get less and less interested in completing a game that they have very little chance of winning. How could the mechanics of Monopoly be adjusted to keep everyone engaged? It&#39;s important to consider positive and negative <strong>feedback loops</strong> in the game. Monopoly has a strong positive feedback loop. The more property a player has, the more money they make from other players, which they use to purchase more and more property. To cancel this out, one could adjust the game mechanics to include, say, theft. This could introduce a negative feedback loop by making players who are doing well more likely to have property stolen by players on the poverty side of the equation.</p>
<p>Frequent flyer programs have a similar problem. People who fly frequently form loyalties to airlines because they have so many points built up that they are able to reap the benefits of the program. People&nbsp;with few points have little incentive to be loyal to any specific airline because they are a long way from &quot;leveling up&quot; and seeing any tangible benefit from the program. The airlines probably don&#39;t care as much about these infrequent flyers, but they may be missing out on nurturing loyalties in people who may become more frequent flyers in the future. These &quot;players&quot; could be incentivized to by being entered in a drawing each time they fly, or randomly getting free drinks or being upgraded to first class when seats are available.</p>
<p><strong>Overall</strong></p>
<p>Overall, I think it&#39;s really exciting that business leaders are starting to consider employee and customer motivation from the perspective of the game designer, and it&#39;s nice to see some formalized thought being put forward that takes some lessons from &quot;regular&quot; game designers and researchers. It will be interesting to see what innovative groups like Bunchball come up with over time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/some-thoughts-on-gamification/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cloud to Cloud: Using AWS Simple Email Service from Force.com</title>
		<link>http://www.modelmetrics.com/tomgersic/cloud-to-cloud-using-aws-simple-email-service-from-force-com/</link>
		<comments>http://www.modelmetrics.com/tomgersic/cloud-to-cloud-using-aws-simple-email-service-from-force-com/#comments</comments>
		<pubDate>Fri, 25 Feb 2011 13:13:13 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=6512</guid>
		<description><![CDATA[Amazon released a really interesting service not too long ago called Simple Email Service (SES). It allows you to send individual or bulk emails without having to rely on your own mail servers. This is important because sending (legitimate) mass emails while staying off spam blacklists like Spamhaus&#160;is no simple task, and you don&#39;t want [...]]]></description>
			<content:encoded><![CDATA[<p>Amazon released a really interesting service not too long ago called <a href="http://aws.amazon.com/ses/#pricing">Simple Email Service (SES)</a>. It allows you to send individual or bulk emails without having to rely on your own mail servers. This is important because sending (legitimate) mass emails while staying off spam blacklists like <a href="http://www.spamhaus.org/">Spamhaus</a>&nbsp;is no simple task, and you don&#39;t want all of your company emails to start being blocked by ISPs that subscribe to those blacklists. If you have all of your customer data in Salesforce.com, you&#39;ll be able to email some of them with Salesforce&#39;s standard email capabilities, but they have pretty <a href="http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm?SearchType=Stem">strict governor limits</a>&nbsp;(1,000 emails per SFDC License) when it comes to sending external emails, so mass emailing is often not a possibility without a third-party provider.</p>
<p><strong>Reasons why you may want to consider using SES</strong></p>
<ol>
<li>Ever receive an email from Amazon.com? Yeah, so has everybody else. They know a thing or two about sending out mass emails.</li>
<li>Their pricing is ridiculously competitive. Other mass email services start out around $15 per thousand emails. Amazon charges $0.10 per thousand. Of course, other services offer more in the way of campaign management, point-and-click setup, and analytics, but if you&#39;re just sending emails, it&#39;s hard to beat the price.</li>
<li>It&#39;s relatively easy to use. Emails are sent through simple RESTful API calls.</li>
</ol>
<p>&nbsp;</p>
<p><strong>Getting set up</strong></p>
<p>So assuming you&#39;re already an AWS member, first off you have to <a href="http://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?ie=UTF8&amp;productCode=AmazonSES">sign up for SES</a>. That will get you set up with a developer account relatively quickly, and you can test sending emails to a few email addresses with the&nbsp;ses-send-email.pl script that comes with the <a href="http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/index.html?InitialSetup.Scripts.html">AWS SES Developer Tools</a>. If you want to actually start sending out mass emails, you have to then request production access from Amazon.</p>
<p><strong>Sending emails from Force.com</strong></p>
<p>First off, <a href="http://mm-tom.s3.amazonaws.com/blog/Force.com_SES.zip">download the Apex code here</a>.</p>
<p>Then, take a look through the files:</p>
<p><strong><a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=AWS.cls">AWS.cls</a></strong></p>
<p>This is a top-level abstract class that has a few methods in it that you&#39;ll need for any AWS functions. This includes the code to generate a signature from the current Date/Time and your AWS Secret Key:</p>
<p><span style="color:#006400"><span class="s1">public</span> string signature(String awsNow, String secret) {</span><title></title></p>
<p class="p1"><span style="color:#006400">&nbsp;&nbsp; &nbsp; system.assert( secret != <span class="s1">null</span> ,<span class="s2">&#39; missing S3.secret key&#39;</span>);</span></p>
<p class="p1"><span style="color:#006400">&nbsp;&nbsp; &nbsp; Blob bsig = Crypto.generateMac(<span class="s2">&#39;HmacSHA256&#39;</span>, Blob.valueOf(awsNow), Blob.valueOf(secret)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span></p>
<p class="p1"><span style="color:#006400"><span class="s1">&nbsp;&nbsp; &nbsp; return</span> EncodingUtil.base64Encode(bsig);&nbsp;</span></p>
<p><span style="color:#006400">}&nbsp;</span></p>
<p>And the code to generate the authorization header using that signature:</p>
<p>&nbsp;</p>
<p><span style="color:#006400">public string headerForAmazonAuthorization(String accessKey, String signature)</span></p>
<p><span style="color:#006400">{</span></p>
<p><span style="color:#006400">return &#39;AWS3-HTTPS AWSAccessKeyId=&#39;+accessKey+&#39;, Algorithm=HmacSHA256, Signature=&#39;+signature;</span></p>
<p><span style="color:#006400">}</span></p>
<p><strong><a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=SES.cls">SES.cls</a></strong></p>
<p>Being an abstract class, AWS.cls is then subclassed by <a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=SES.cls">SES.cls</a>. This includes the method to actually send an email by setting the HTTP headers and body, and sending the request to the SES endpoint. To use this, you just need to send in a List of recipient addresses, your from: address, a subject, and a body for the email. The response from AWS is then written to the debug log, so you can see any error messages sent back by Amazon.&nbsp;</p>
<p><strong><a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=SESEmail.cls">SESEmail.cls</a></strong></p>
<p>The SESEmail class defines a single SES Email message with multiple recipients, a sender, a subject, and a body, and it takes care of URL Encoding all of that and setting up the Body of the request to Amazon.</p>
<p><strong><a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=AWSKeys.cls">AWSKeys.cls&nbsp;</a></strong></p>
<p>So this one I didn&#39;t actually write. I got it from the <a href="http://aws.amazon.com/solutions/global-solution-providers/salesforce/">Force.com AWS Toolkit</a>. Mostly it just reads your AWS Access Key and Secret Key from a custom object. The authentication code in that toolkit is a bit out of date for the current version of the AWS API, and I did modify this class to be a singleton so a DML statement doesn&#39;t get kicked off every time you query for your AWS Keys. If you&#39;re using this, you&#39;ll probably also want to make the&nbsp;AWSKey__c SObject private so your entire org doesn&#39;t have access to your AWS keys, but I&#39;ll leave that as an exercise for the reader.</p>
<p><strong><a href="http://modelmetricssoftware.com/tom/highlight_code.php?filename=SESController.cls">SESController.cls</a></strong></p>
<p>Last, and I&#39;ll be honest, least, is a dummy VF Page and controller that connects the dots and sends off emails using SES. The page is a pretty simple page that calls the controller:</p>
<p><span style="color:#006400">&lt;apex:page controller=&quot;SESController&quot; action=&quot;{!constructor}&quot; &gt;</span></p>
<p>And sends an email to a List of recipients:</p>
<p>&nbsp;</p>
<p><span style="color:#006400">AWSKeys awsKey = AWSKeys.getInstance(AWSCredentialName);</span></p>
<p><span style="color:#006400">SES sesEmail = new SES(awsKey.key,awsKey.secret);</span></p>
<p>&nbsp;</p>
<p><span style="color:#006400">List&lt;String&gt; recipients = new List&lt;String&gt;();</span></p>
<p><span style="color:#006400">recipients.add(&#39;nobody@modelmetrics.com&#39;);&nbsp;</span></p>
<p><span style="color:#006400">String sender = &#39;nobody@modelmetrics.com&#39;;</span></p>
<p><span style="color:#006400">String subject = &#39;Test message&#39;;</span></p>
<p><span style="color:#006400">String body = &#39;This is the body of the message&#39;;</span></p>
<p>&nbsp;</p>
<p><span style="color:#006400">sesEmail.sendEmail(recipients,sender,subject,body);</span></p>
<p>&nbsp;</p>
<p>That&#39;s it. Relatively easy. Adding test classes is left as an exercise for the reader <img src='http://www.modelmetrics.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/cloud-to-cloud-using-aws-simple-email-service-from-force-com/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Importing a Flex 3 AIR project into Flash Builder 4</title>
		<link>http://www.modelmetrics.com/tomgersic/importing-a-flex-3-air-project-into-flash-builder-4/</link>
		<comments>http://www.modelmetrics.com/tomgersic/importing-a-flex-3-air-project-into-flash-builder-4/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 15:57:11 +0000</pubDate>
		<dc:creator>Tom Gersic</dc:creator>
				<category><![CDATA[Tom's Blog]]></category>

		<guid isPermaLink="false">http://www.modelmetrics.com/?p=4508</guid>
		<description><![CDATA[I&#160;had some issues over the weekend trying to import an Flex Builder 3 AIR&#160;project into Flash Builder 4. This post gives a good description of how it is supposed to work, and I&#160;assume that it does work for Flex web projects, but it didn&#8217;t work for me with an AIR&#160;project. Every time I&#160;imported the AIR&#160;project, [...]]]></description>
			<content:encoded><![CDATA[<p>I&nbsp;had some issues over the weekend trying to import an Flex Builder 3 AIR&nbsp;project into Flash Builder 4. <a href="http://www.adobe.com/devnet/flex/articles/flexbuilder3_to_flashbuilder4.html">This post</a> gives a good description of how it is supposed to work, and I&nbsp;assume that it does work for Flex web projects, but it didn&#8217;t work for me with an AIR&nbsp;project. Every time I&nbsp;imported the AIR&nbsp;project, Flash Builder 4 interpreted it as a Flex Web project, so of course it didn&#8217;t actually build. I was migrating from an OSX&nbsp;Flex Builder 3 to a Windows Flash Builder 4, so that may also have been an issue, I&#8217;m not sure. </p>
<p>Anyway, the way I&nbsp;finally got it working was to create a new AIR&nbsp;Desktop project in Flash Builder 4 and copy the entire src folder over from the Flex Builder 3 project. The only thing that you can&#8217;t copy is the app.xml file, as it seems to be in a slightly different format in FB4, and the project won&#8217;t build.</p>
<p><strong>SVN</strong></p>
<p>This causes some problems if you want to continue a development effort using SVN, and other members of your team are using Flex Builder 3, because the actual project can&#8217;t be shared between the two versions of the IDE. However, the src folder can be shared without issue, so if you check just that folder out into your new&nbsp;Flash Builder 4 Project shell, and over-write the app.xml file you&#8217;ll be good to go, just don&#8217;t accidentally commit the app.xml file to the repository, or you&#8217;ll break the build for everybody else.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.modelmetrics.com/tomgersic/importing-a-flex-3-air-project-into-flash-builder-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

