<?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>Mission Data Blog &#187; Systems Integration</title>
	<atom:link href="http://www.missiondata.com/blog/category/systems-integration/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.missiondata.com/blog</link>
	<description>Louisville-based Web Development &#038; Software Engineering</description>
	<lastBuildDate>Tue, 18 May 2010 14:24:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>rails fixtures with models using set_table_name</title>
		<link>http://www.missiondata.com/blog/systems-integration/80/rails-fixtures-with-models-using-set_table_name/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/80/rails-fixtures-with-models-using-set_table_name/#comments</comments>
		<pubDate>Mon, 23 Apr 2007 03:13:47 +0000</pubDate>
		<dc:creator>darrend</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/uncategorized/80/rails-fixtures-with-models-using-set_table_name/</guid>
		<description><![CDATA[If you have a model that uses set_table_name you may hit a snag when trying to use fixtures and unit tests. The solution is twofold: name the fixture file using the legacy table name, and use the set_fixture_class method in your unit test. I coudn&#8217;t find this method mentioned in Agile Web Development with Rails, [...]]]></description>
			<content:encoded><![CDATA[<p>If you have a model that uses <tt>set_table_name</tt> you may hit a snag when trying to use fixtures and unit tests. The solution is twofold: name the fixture file using the legacy table name, and use the <tt>set_fixture_class</tt> method in your unit test. I coudn&#8217;t find this method mentioned in <em>Agile Web Development with Rails</em>, and there&#8217;s only a brief mention on the <a href="http://wiki.rubyonrails.com/rails/pages/HowToUseLegacySchemas">rubyonrails.com site</a>. Still, some web searches turned up the answers.</p>
<p>Here is a simple example:</p>
<p><span id="more-80"></span></p>
<p>We&#8217;ll start with a table named <code>libris_book</code> that contains book entries. The name <em>libris_book</em> won&#8217;t really fly with the Rails pluralized table name approach. It&#8217;s easy, however, to fix that disconnect in the model:</p>
<pre><code>class Book &lt; ActiveRecord::Base
  set_table_name 'libris_book'
end</code></pre>
<p>Let&#8217;s take a look at our data:</p>
<pre><code class="console">~/src/libris$ script/console
Loading development environment.
&gt;&gt; Book.count
=&gt; 1230</code></pre>
<p>Good enough. Now, we&#8217;ll be good little coders and write some unit tests using fixtures. We&#8217;ll create a fixture file and our test class:<br />
<br />
<tt>books.yml</tt></p>
<pre><code>test_book:
  title: Life in Lawrenceburg
  author: Darren Day</code></pre>
<p><tt>book_test.rb</tt></p>
<pre><code>require File.dirname(__FILE__) + '/../test_helper'

class BookTest &lt; Test::Unit::TestCase
  fixtures :books

  def test_fixtures
    assert_equal(2,Book.count)
    test_book = books(:test_book)
  end
end</code></pre>
<p>Looks good, but it won&#8217;t work!</p>
<pre><code class="console">~/src/libris$ rake test
(in /home/darrend/src/libris)
/usr/local/bin/ruby -Ilib:test "/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rb" "test/unit/book_test.rb"
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader
Started
E
Finished in 0.01133 seconds.

  1) Error:
test_fixtures(BookTest):
ActiveRecord::StatementInvalid: Mysql::Error: Table 'libris_test.books' doesn't exist: DELETE FROM books
...</code></pre>
<p>Ugh. That doesn&#8217;t look pretty. After some <a href="http://www.google.com/search?q=set_table_name+fixtures">googling around</a> the following comes together</p>
<ul>
<li>Rename <tt>books.yml</tt> to <tt>libris_book.yml</tt>. The fixture yaml file has to share the same name as the database table name.
<li>Change the <tt>fixtures</tt> declaration to <code>fixtures :libris_book</code>.
<li> Use <tt>set_fixture_class</tt> to connect the fixture to the model class.
</ul>
<p>Here is our new and improved <tt>book_test.rb</tt> file:</p>
<pre><code>require File.dirname(__FILE__) + '/../test_helper'

class BookTest &lt; Test::Unit::TestCase
  set_fixture_class :libris_book =&gt; Book
  fixtures :libris_book

  def test_fixtures
    assert_equal(2,Book.count)
    test_book = libris_book(:test_book)
  end
end</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/80/rails-fixtures-with-models-using-set_table_name/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to Create and Overlay KML on a Google Map Using Google&#8217;s My Maps</title>
		<link>http://www.missiondata.com/blog/systems-integration/72/how-to-overlay-kml-on-a-google-map/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/72/how-to-overlay-kml-on-a-google-map/#comments</comments>
		<pubDate>Fri, 06 Apr 2007 14:33:48 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[gis]]></category>

		<guid isPermaLink="false">http://www.missiondata.com/blog/gis/72/how-to-overlay-kml-on-a-google-map/</guid>
		<description><![CDATA[A few days ago Google made their &#8220;My Maps&#8221; announcment and since then there has been nothing but buzz buzz buzz about it. So I figured I would take a minute to show how someone can use this new tool from Google to create their own embedded maps for their site.

The first step is to [...]]]></description>
			<content:encoded><![CDATA[<p>A few days ago Google made their <a href="http://googleblog.blogspot.com/2007/04/map-making-so-easy-caveman-could-do-it.html">&#8220;My Maps&#8221; announcment</a> and since then there has been nothing but <a href="http://radar.oreilly.com/archives/2007/04/google_launches_mymaps.html">buzz</a> <a href="http://mashable.com/2007/04/05/google-mymaps/">buzz</a> <a href="http://www.gearthblog.com/blog/archives/2007/04/my_maps_new_google_m.html">buzz</a> about it. So I figured I would take a minute to show how someone can use this new tool from Google to create their own embedded maps for their site.</p>
<p><span id="more-72"></span></p>
<p>The first step is to create your new map. Go to <a href="http://maps.google.com/">Google Maps</a> and click on the new &#8220;My Maps&#8221; tab.</p>
<p><img alt="Web Hosting, Web Development, and Software Development in Louisville Ky" src="http://www.missiondata.com/blog/wp-content/uploads/2007/04/ss6.jpg"/> <br/></p>
<p>Now you create your map. You can create polygons, lines or just points and include whatever you want in the descriptions because it will all be included in the KML.</p>
<p>Once you have completed your map you want to go to click on the KML link at the top right to save the KML for this map to disk.</p>
<p><img alt="Web Hosting, Web Development, and Software Development in Louisville Ky"  src="http://www.missiondata.com/blog/wp-content/uploads/2007/04/ss5.jpg"/> <br/></p>
<p>Just last month Google added <a href="http://googlemapsapi.blogspot.com/2007/03/kml-and-georss-support-added-to-google.html">support for KML overlays</a> to their map API. It isn&#8217;t very well documented on the <a href="http://www.google.com/apis/maps/documentation/reference.html#GGeoXml">GGeoXml documentation</a> page but there is only one real issue you have to know about. The main thing to understand is that the KML file must sit on a public webserver somewhere and when you reference it Google needs to be able to access it. For example if you are testing on your local box and you put something like &#8220;http://localhost/mykml.kml&#8221; in for the URL it will not work. After you get past that the path to using your saved KML file is easy. Here is a full example:</p>
<pre>
<code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
  &lt;head&gt;
    &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"/&gt;

    &lt;title&gt;Example of KML overlay on a Google Map&lt;/title&gt;

    &lt;script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;key=ABQIAAAAcktFen-Z7CQCe0dxIKmxeRReUzuwBhfUVuhk2aRjVRv1avb-hhQdlkzQnQ1P5PComj1CZx2jeOOyIw" type="text/javascript"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;

    //&lt;![CDATA[

    function load()
    {
      if (GBrowserIsCompatible())
      {
        var map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(38.256270, -85.701762), 11);
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        map.addOverlay(new GGeoXml("http://www.missiondata.com/blog/examples/missiondatahq.kml"));
      }
    }

    //]]&gt;
    &lt;/script&gt;

  &lt;/head&gt;

  &lt;body onload="load()" onunload="GUnload()"&gt;
    &lt;div id="map" style="margin-right: 10px; float: left; width: 500px; height: 400px;"&gt;&lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code>
</pre>
<p>Notice that you have to zoom and center to somewhere since that isn&#8217;t controled by the KML file but other than that it makes creating embedded maps very simple.</p>
<p>And here are the results from the example:</p>
<p><iframe SRC="/blog/examples/googlemap_loadkml.html" width="500px" height="400px" scrolling="no" frameborder="0"></iframe></p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/72/how-to-overlay-kml-on-a-google-map/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>S3 Streaming With PHP</title>
		<link>http://www.missiondata.com/blog/systems-integration/49/s3-streaming-with-php/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/49/s3-streaming-with-php/#comments</comments>
		<pubDate>Sat, 25 Nov 2006 18:45:24 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/linux/49/s3-streaming-with-php/</guid>
		<description><![CDATA[Steven pointed out that someone was looking for a way to stream to S3 using PHP and said I should figure out how to get it going. Since he made a patch to let you stream data with Ruby using S3 I figured I should do one for PHP. There may be better ways of [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blogs.missiondata.com/author/steveny/">Steven</a> pointed out that someone was looking for a way to <a href="http://developer.amazonwebservices.com/connect/thread.jspa?threadID=12829&#038;tstart=0">stream to S3 using PHP</a> and said I should figure out how to get it going. Since he made a patch to let you <a href="http://blogs.missiondata.com/ruby/29/streaming-data-to-s3-with-ruby/">stream data with Ruby using S3</a> I figured I should do one for PHP. There may be better ways of doing this but since I&#8217;ve already done it with C using curl I figured that would be the fastest way.<br />
<span id="more-49"></span></p>
<p>First you will want to get the <a href="http://developer.amazonwebservices.com/connect/servlet/JiveServlet/download/24-12470-46948-845/s3.php">S3 PHP library from Amazon</a>. Then you add the following to the file:</p>
<pre>
<code>/**
 * putObjectStream -- Streams data to a bucket.
 *
 * Takes ($bucket, $key, $streamFunction, $contentType, $contentLength [,$acl, $metadataArray, $md5])
 *
 *
 * - [str] $bucket: the bucket into which file will be written
 * - [str] $key: key of written file
 * - [str] $streamFunction: function to call for data to stream
 * - [str] $contentType: file content type
 * - [str] $contentLength: file content length
 * - [str] $acl: access control policy of file (OPTIONAL: defaults to 'private')
 * - [str] $metadataArray: associative array containing user-defined metadata (name=&gt;value) (OPTIONAL)
 * - [bool] $md5: the MD5 hash of the object (OPTIONAL)
*/
function putObjectStream($bucket, $key, $streamFunction, $contentType, $contentLength, $acl, $metadataArray, $md5){
        sort($metadataArray);
        $resource = "$bucket/$key";
        $resource = urlencode($resource);
        $httpDate = gmdate("D, d M Y G:i:s T");

        $curl_inst = curl_init();

        curl_setopt ($curl_inst, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt ($curl_inst, CURLOPT_LOW_SPEED_LIMIT, 1);
        curl_setopt ($curl_inst, CURLOPT_LOW_SPEED_TIME, 180);
        curl_setopt ($curl_inst, CURLOPT_NOSIGNAL, 1);
        curl_setopt ($curl_inst, CURLOPT_READFUNCTION, $streamFunction);
        curl_setopt ($curl_inst, CURLOPT_URL, $this-&gt;serviceUrl . $resource);
        curl_setopt ($curl_inst, CURLOPT_UPLOAD, true);
        curl_setopt ($curl_inst, CURLINFO_CONTENT_LENGTH_UPLOAD, $contentLength);

        $header[] = "Date: $httpDate";
        $header[] = "Content-Type: $contentType";
        $header[] = "Content-Length: $contentLength";
        $header[] = "Expect: ";
        $header[] = "Transfer-Encoding: ";
        $header[] = "x-amz-acl: $acl";

        $MD5 = "";
        if($md5){
                $MD5 = $this-&gt;hex2b64(md5_file($filePath));
                $header[] = "Content-MD5: $MD5";
        }

        $stringToSign="PUT\n$MD5\n$contentType\n$httpDate\nx-amz-acl:$acl\n";
        foreach($metadataArray as $current){
                if($current!=""){
                        $stringToSign.="x-amz-meta-$current\n";
                        $header = substr($current,0,strpos($current,':'));
                        $meta = substr($current,strpos($current,':')+1,strlen($current));
                        $header[] = "x-amz-meta-$header: $meta";
                }
        }

        $stringToSign.="/$resource";

        $signature = $this-&gt;constructSig($stringToSign);

        $header[] = "Authorization: AWS $this-&gt;accessKeyId:$signature";

        curl_setopt($curl_inst, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl_inst, CURLOPT_RETURNTRANSFER, 1);

        $result = curl_exec ($curl_inst);

        $this-&gt;responseString = $result;
        $this-&gt;responseCode = curl_getinfo($curl_inst, CURLINFO_HTTP_CODE);

        curl_close($curl_inst);
}</code>
</pre>
<p>Now you have an updated s3.php you are ready to start streaming. Be aware that the content length value needs to be correct. If it is not the correct size your upload will be either truncated (too short) or it will hang (too long). If it hangs the S3 service will timeout after a small amount of time and give you an error.</p>
<p>Here are two examples of how to use it. First with a file:</p>
<pre>
<code>&lt;?php

include 's3.php';

class MyClass
{
  var $data;

  function stream_function($handle, $fd, $length)
  {
    return fread($this-&gt;data, $length);
  }
}

$my_class_inst = new MyClass();

$fsize = filesize("/tmp/largefile.tar.gz");

$my_class_inst-&gt;data = fopen("/tmp/largefile.tar.gz", "r");

$s3_inst = new s3("access key", "private key");
$s3_inst-&gt;putObjectStream("abucket", "largefile.tar.gz", array($my_class_inst, "stream_function"), "application/x-gzip", $fsize, "public-read", array(), null);

print "Response String: " . $s3_inst-&gt;responseString . "\n";
print "Response Code: " . $s3_inst-&gt;responseCode . "\n";
print "Parsed XML: " . $s3_inst-&gt;parsed_xml . "\n";

fclose($my_class_inst-&gt;data);

?&gt;</code>
</pre>
<p>Another example of streaming some random text:</p>
<pre>
<code>&lt;?php

include 's3.php';

class MyClass
{
  var $data;

  function stream_function($handle, $fd, $length)
  {
    return $this-&gt;data;
  }
}

$my_class_inst = new MyClass();

$my_class_inst-&gt;data = "A test string";
$size = strlen($my_class_inst-&gt;data);

$s3_inst = new s3("access key", "private key");
$s3_inst-&gt;putObjectStream("bucketname", "test.txt", array($my_class_inst, "stream_function"), "text/html", $size, "public-read", array(), null);

print "Response String: " . $s3_inst-&gt;responseString . "\n";
print "Response Code: " . $s3_inst-&gt;responseCode . "\n";
print "Parsed XML: " . $s3_inst-&gt;parsed_xml . "\n";

?&gt;</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/49/s3-streaming-with-php/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Creating S3 URLs that expire using PHP</title>
		<link>http://www.missiondata.com/blog/systems-integration/57/creating-s3-urls-that-expire-using-php/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/57/creating-s3-urls-that-expire-using-php/#comments</comments>
		<pubDate>Thu, 01 Jun 2006 11:50:24 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=57</guid>
		<description><![CDATA[After reading this post on the S3 forum I realized that other people are thinking about doing some of the same stuff I have. paolonew was looking for a way to for a way to create URLs to S3 objects that expired. I did this a while back when I was thinking about how to [...]]]></description>
			<content:encoded><![CDATA[<p>After reading <a href="http://developer.amazonwebservices.com/connect/thread.jspa?threadID=10726&#038;tstart=0">this post on the S3 forum</a> I realized that other people are thinking about doing some of the same stuff I have. paolonew was looking for a way to for a way to create URLs to S3 objects that expired. I did this a while back when I was thinking about how to host objects that I wanted to protect with some outside scheme. The confusion on the forum seemed to be about the timestamps used to expire the URL. For PHP it is fairly easy.</p>
<p>To clear up the expiration time issue I think these two steps are needed:</p>
<p>1) Keep in mind that the HTTP header dates <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html">must</a> be in GMT.<br />
2) The PHP function <a href="http://us3.php.net/manual/en/function.time.php">time()</a> returns the seconds since the epoch January 1 1970 00:00:00 GMT). Notice here this is in GMT as well.<br />
3) The HTTP Date header you see in a response from an S3 server is the time on that server. The machine you use to sign your request should be synced with that time. I think a good guess is that all the Amazon servers are synced with the atomic clock.</p>
<p>There isn&#8217;t much to securing a URL after you have that tucked away. Here is an example that will sign a URL so that it is valid for 60 seconds:</p>
<pre>
<code>&lt;?php

require_once('Crypt/HMAC.php');

echo getS3Redirect("/test.jpg") . "\\n";

function getS3Redirect($objectName)
{
  $S3_URL = "http://s3.amazonaws.com";
  $keyId = "your key";
  $secretKey = "your secret";
  $expires = time() + 60;
  $bucketName = "/your bucket";

  $stringToSign = "GET\\n\\n\\n$expires\\n$bucketName$objectName";
  $hasher =&amp; new Crypt_HMAC($secretKey, "sha1");
  $sig = urlencode(hex2b64($hasher-&gt;hash($stringToSign)));

  return "$S3_URL$bucketName$objectName?AWSAccessKeyId=$keyId&amp;Expires=$expires&amp;Signature=$sig";
}

function hex2b64($str)
{
    $raw = '';
    for ($i=0; $i &lt; strlen($str); $i+=2)
    {
        $raw .= chr(hexdec(substr($str, $i, 2)));
    }
    return base64_encode($raw);
}

?&gt;</code>
</pre>
<p>The hex2b64 function was pulled from the amazon S3 PHP example library.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/57/creating-s3-urls-that-expire-using-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Good Techcrunch review of mapping apis</title>
		<link>http://www.missiondata.com/blog/systems-integration/45/good-techcrunch-review-of-mapping-apis/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/45/good-techcrunch-review-of-mapping-apis/#comments</comments>
		<pubDate>Tue, 18 Apr 2006 14:06:21 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[gis]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=45</guid>
		<description><![CDATA[Techcrunch has a good review by Frank Gruber of the look and feel of mapping services. I think it is notable that ESRI&#8217;s service is not included in the review. I think it is at least as good as the mapquest service. I may have to find time to redo my review of the acuracy [...]]]></description>
			<content:encoded><![CDATA[<p>Techcrunch has a good <a href="http://www.techcrunch.com/2006/04/17/comparing-the-mapping-services/">review</a> by <a href="http://www.somewhatfrank.com/">Frank Gruber</a> of the look and feel of mapping services. I think it is notable that <a href="http://www.esri.com/software/arcgis/about/gis-webservices.html">ESRI&#8217;s service</a> is not included in the review. I think it is at least as good as the mapquest service. I may have to find time to redo my <a href="http://blogs.missiondata.com/?p=18">review</a> of the acuracy of each again and a more technical evaluation of each.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/45/good-techcrunch-review-of-mapping-apis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Approximating a circle with a polygon</title>
		<link>http://www.missiondata.com/blog/systems-integration/44/approximating-a-circle-with-a-polygon/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/44/approximating-a-circle-with-a-polygon/#comments</comments>
		<pubDate>Tue, 18 Apr 2006 02:36:18 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[gis]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=44</guid>
		<description><![CDATA[I recently had an opportunity to use ESRI&#8217;s ArcSDE again. It is a spatial database interface and in this instance I was using the java api. I wanted to change what used to be a query using a rectangle into a query using a circle. For some reason parts of the java api for ArcSDE [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had an opportunity to use ESRI&#8217;s <a href="http://www.esri.com/software/arcgis/arcsde/index.html">ArcSDE</a> again. It is a spatial database interface and in this instance I was using the java api. I wanted to change what used to be a query using a rectangle into a query using a circle. For some reason parts of the java api for ArcSDE require a C library or something. I gave up pretty quickly on trying to make their arc function work since the documentation wasn&#8217;t very clear on how it worked. Instead I decided to figure out how to approximate a circle with a polygon and use that instead. Here is the result of that research.</p>
<p><span id="more-44"></span></p>
<p>First it helps to have a little background. Most people are familiar with <a href="http://en.wikipedia.org/wiki/Latitude">latitude</a> and <a href="http://en.wikipedia.org/wiki/Longitude">longitude</a> but you may not be familiar with their exact definitions. I have included the links to the wikipedia pages for both so you can research them more if you want. The main things to know are: latitude runs north/south and each degree of latitude is about 111 km; longitude runs east/west and is 111 km times the cosine of the latitude. The next thing that is helpful to know is the <a href="http://en.wikipedia.org/wiki/Earth_radius">radius of the earth</a>: 6,378.135 km in this case I&#8217;ll just use the equatorial radius.</p>
<p>Now that we have the earth taken care of we need to go back to basics. We start by looking at the definition of a <a href="http://en.wikipedia.org/wiki/Circle">circle</a> and <a href="http://en.wikipedia.org/wiki/Unit_circle">the unit circle</a>. The mathematical definition of a circle is the important part here. The following equations will play an important part: x = a + r cos(t) and y = b + r sin(t) where a,b are the center of the circle, x,y are points of the unit circle, r is the radius of the circle, and t is the angle of a line from the origin to x,y in radians. It helps to think of the circle as broken up into triangles.</p>
<p>The last thing to keep in mind is that latitude and longitude are in degrees but when working with cos and sin you need to use radians and not degrees. The conversion between radians and degrees is easy: radians = degrees * (PI / 180) and degrees = radians * (180 / PI).</p>
<p>So now for the main formula in pseudocode:</p>
<pre>
<code> earths_radius = 3963 // number of miles in the radius of the earth
 longitude = 80          // longitude of the center of the circle
 latitude = 90            // latitude of the center of the circle
 points = 32              // number of points in the polygon
 circle_radius = 1       // miles of radius

 // find the raidus in lat/lon, units per latitude, units per longitude
 r_latitude = radius_to_degrees(circle_radius / earths_radius)
 r_longitude = r_latitude / cos(degrees_to_radius(latitude))

 // create a point for each edge, we need one extra point to connect the
 // end to the begining
 for point_count = 0 to points + 1
 {
    theta = PI * (point_count / (points / 2))    // find the angle for the current triangle
    circle_x = lng + (r_longitude * cos(theta))  // center a + radius x * cos(theta)
    circle_y = lat + (r_latitude * sin(theta))     // center b + radius y * sin(theta)

    // circle_x, circle_y represents a point on the circle
 }</code>
</pre>
<p>That is all there is to it. In this example I just picked 32 points for the circle but you may want more or less depending on how large your radius is and how closely you want to approximate the circle. One thing to note about this function is that it produces the points in a counter-clockwise direction.</p>
<p>Now for an example using google maps to display a circle around a point with a radius of one mile:</p>
<h3>Missiondata World HQ, Louisville, Ky</h3>
<p><iframe SRC="/blog/examples/googlemap_circle.html" width="500px" height="400px" scrolling="no" frameborder="0"></iframe></p>
<p>And here is the javascript source you need to do it:</p>
<pre>
<code>var d2r = Math.PI / 180;   // degrees to radians
var r2d = 180 / Math.PI;   // radians to degrees
var earthsradius = 3963; // 3963 is the radius of the earth in miles

var hqpoint = new GPoint(-85.578852, 38.215601);
var map = new GMap(document.getElementById("map"));

map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(hqpoint, 4);
map.addOverlay(new GMarker(hqpoint));

drawCircle(-85.578852, 38.215601, map);

function drawCircle(lng, lat, map)
{
   var points = 32;
   var radius = 1;             // radius in miles

   // find the raidus in lat/lon
   var rlat = (radius / earthsradius) * r2d;
   var rlng = rlat / Math.cos(lat * d2r);

   var extp = new Array();
   for (var i=0; i &lt; points+1; i++) // one extra here makes sure we connect the
   {
      var theta = Math.PI * (i / (points/2));
      ex = lng + (rlng * Math.cos(theta)); // center a + radius x * cos(theta)
      ey = lat + (rlat * Math.sin(theta)); // center b + radius y * sin(theta)
      extp.push(new GPoint(ex, ey));
   }

   map.addOverlay(new GPolyline(extp, "#000000", 2));
}</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/44/approximating-a-circle-with-a-polygon/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Streaming data to S3 with ruby</title>
		<link>http://www.missiondata.com/blog/systems-integration/29/streaming-data-to-s3-with-ruby/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/29/streaming-data-to-s3-with-ruby/#comments</comments>
		<pubDate>Wed, 29 Mar 2006 18:56:49 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=29</guid>
		<description><![CDATA[One of the downsides of the ruby S3 example code is that it doesn&#8217;t support streaming of data (it loads the entire file into memory).  It turns out, however, that all that is needed to stream data is a tweak to the &#8216;request&#8217; method in Net::HTTP.

  require 'net/http'
require 'S3'
require 'pp'

#
# Replace the request [...]]]></description>
			<content:encoded><![CDATA[<p>One of the downsides of the ruby S3 example code is that it doesn&#8217;t support streaming of data (it loads the entire file into memory).  It turns out, however, that all that is needed to stream data is a tweak to the &#8216;request&#8217; method in Net::HTTP.</p>
<pre>
  <code>require 'net/http'
require 'S3'
require 'pp'

#
# Replace the request method in Net::HTTP to sniff the body type
# and set the stream if appropriate
#
module Net
  class HTTP
    alias __request__ request

    def request(req, body = nil, &amp;block)
      if body != nil &amp;&amp; body.respond_to?(:read)
        req.body_stream = body
        return __request__(req, nil, &amp;block)
      else
        return __request__(req, body, &amp;block)
      end
    end
  end
end

#
# Connect to s3 using the ruby API provided by Amazon
#
conn = S3::AWSAuthConnection.new("[PUBLIC]", "[PRIVATE]", false)

#
# Stream a testfile to S3
#
open("testfile") do |stream|
  pp response = conn.put('BUCKET_NAME',
                         "testfile",
                         stream,
                         {
                           "x-amz-acl" =&gt; "public-read",
                           "Content-Type" =&gt; "text/plain",
                           "Content-Length" =&gt;  FileTest.size("testfile").to_s
                         }
                        )
end

#
# Send a testfile in memory to S3
#
pp response = conn.put('BUCKET_NAME',
                       "testfile",
                       File.read('testfile'),
                       {
                         "x-amz-acl" =&gt; "public-read",
                         "Content-Type" =&gt; "text/plain"
                       }
                      )

  </code>
</pre>
<p>A few notes about the code</p>
<ul>
<li> When streaming you have to supply the &#8216;Content-Length&#8217; header
<li> I had an error about S3.rb calling strip on non-strings, I changed line 49 to &#8216;interesting_headers[lk] = value.to_s.strip&#8217;
<li> Make sure you replace PUBLIC, PRIVATE, and BUCKET_NAME with appropriate values
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/29/streaming-data-to-s3-with-ruby/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Offloading web traffic using Amazon&#8217;s S3 service</title>
		<link>http://www.missiondata.com/blog/systems-integration/27/offloading-web-traffic-using-amazons-s3-service/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/27/offloading-web-traffic-using-amazons-s3-service/#comments</comments>
		<pubDate>Tue, 28 Mar 2006 17:43:45 +0000</pubDate>
		<dc:creator>steveny</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=27</guid>
		<description><![CDATA[We have a couple of fairly high traffic sites that have large images designed to be used for desktop backgrounds.  To save a bit of bandwidth, we decided to give Amazon&#8217;s S3 webservice a spin.
Signing up was fairly painless.  They required a credit card (so they could bill us $.15/G storage and $.20/G [...]]]></description>
			<content:encoded><![CDATA[<p>We have a couple of fairly high traffic sites that have large images designed to be used for desktop backgrounds.  To save a bit of bandwidth, we decided to give <a href='http://aws.amazon.com/s3'>Amazon&#8217;s S3 webservice</a> a spin.</p>
<p>Signing up was fairly painless.  They required a credit card (so they could bill us $.15/G storage and $.20/G transfer).  After I signed up I quickly received an email that contained a link to my public and secret keys.  </p>
<p>This is a fairly new service and the client tools are just getting started.  For my purposes of uploading several images, I decided to use <a href='http://www.jroller.com/page/silvasoftinc'>jSh3ll</a> to &#8216;browse&#8217; my S3 storage and a custom ruby script to upload a large amount of files.</p>
<p>After downloading and installing jSh3ll, I created my first bucket:<br />
<span id="more-27"></span></p>
<pre>
<code class='console'>jSh3ll&gt; bucket www.hpnotiq.com
Bucket set to 'www.hpnotiq.com'
jSh3ll&gt; createbucket
Created bucket 'www.hpnotiq.com'</code>
</pre>
<p>I then hacked out a quick ruby script using <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=135&#038;categoryID=47">the example ruby S3 library</a> to upload all the image files I wanted to store on S3.</p>
<pre>
  <code>#!/usr/bin/env ruby

require 'S3'
require 'pp'

conn = S3::AWSAuthConnection.new("&lt;YOUR PUBLIC KEY&gt;", "&lt;YOUR PRIVATE KEY&gt;", false)

Dir["images/*.jpg"].each do |filename|
  basename = filename.split('/')[-1]
  pp response = conn.put('www.hpnotiq.com',
                         "images/wallpapers/#{basename}",
                         File.new(filename).read,
                         {
                           "x-amz-acl" =&gt; "public-read",
                           "Content-Type" =&gt; "image/jpeg"
                         }
                        )
end
  </code>
</pre>
<p>A few notes about the code:</p>
<ul>
<li> We decided to use the domain name for the bucket and the directory+file for the object id
<li> The S3 ruby libraries don&#8217;t stream, so the whole file is loaded into memory and put on the server
<li> The hash at the end sets some headers for the &#8216;put&#8217;.  The first tells S3 that this file can be read publicly.  The second is the content type for the file(which will be set in the header when the file is downloaded)
</ul>
<p>Back to JSh3ll to see what&#8217;s there:</p>
<pre>
  <code class='console'>jSh3ll&gt; list
Item list for bucket 'www.hpnotiq.com'
key=images/wallpapers/blackdrink_1024.jpg, owner=steveny, size=75625 bytes, last modified=Tue Mar 28 11:54:57 EST 2006
key=images/wallpapers/blackdrink_800.jpg, owner=steveny, size=47251 bytes, last modified=Tue Mar 28 11:54:59 EST 2006
key=images/wallpapers/bottle_1024.jpg, owner=steveny, size=56590 bytes, last modified=Tue Mar 28 11:55:00 EST 2006
  </code>
</pre>
<p>Now that all the files are on the service, I just needed to write an apache rewrite rule to redirect people to the images&#8217; new location:</p>
<pre>
  <code>RewriteEngine on
RewriteRule ^/images/wallpapers/(.*)$ http://s3.amazonaws.com/www.hpnotiq.com/images/wallpapers/$1 [R,L]
  </code>
</pre>
<p>Bringing up my browser and looking at the headers, we can see where the request gets redirected to s3.amazonaws.com and the Content-Type is set correctly:</p>
<pre>
  <code>GET /images/wallpapers/blackdrink_1024.jpg HTTP/1.1

Host: www.hpnotiq.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7)
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.x 302 Found
Date: Tue, 28 Mar 2006 17:49:27 GMT
Server: Apache
Location: http://s3.amazonaws.com/www.hpnotiq.com/images/wallpapers/blackdrink_1024.jpg
Content-Length: 326
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

----------------------------------------------------------

http://s3.amazonaws.com/www.hpnotiq.com/images/wallpapers/blackdrink_1024.jpg

GET /www.hpnotiq.com/images/wallpapers/blackdrink_1024.jpg HTTP/1.1
Host: s3.amazonaws.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20051010 Firefox/1.0.7 (Ubuntu package 1.0.7)
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.x 200 OK
x-amz-id-2: GxsekKOL2jdljb5K6/RWPlswvBhbNjYrP8klHs2IXGqwZcjzRQ3FIsEhPo/L/Gfe
x-amz-request-id: 6E6912FF565D7B04
Date: Tue, 28 Mar 2006 17:49:29 GMT
Last-Modified: Tue, 28 Mar 2006 16:54:57 GMT
Etag: "a58c016d36905ba89cf17ea99a574cb3"
Content-Type: image/jpeg
Content-Length: 75625
Server: AmazonS3
  </code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/27/offloading-web-traffic-using-amazons-s3-service/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>GIS Geocoding experiments</title>
		<link>http://www.missiondata.com/blog/systems-integration/18/gis-geocoding-experiments/</link>
		<comments>http://www.missiondata.com/blog/systems-integration/18/gis-geocoding-experiments/#comments</comments>
		<pubDate>Thu, 09 Mar 2006 03:39:31 +0000</pubDate>
		<dc:creator>carsonm</dc:creator>
				<category><![CDATA[Systems Integration]]></category>
		<category><![CDATA[gis]]></category>

		<guid isPermaLink="false">http://blogs.missiondata.com/?p=18</guid>
		<description><![CDATA[I&#8217;ve been evaluating a couple different mapping software packages recently and the other day I noticed that the same addresses geocoded (for those who don&#8217;t know what geocoding is you can find out more about it here) to different locations. They are mostly the same but I figured it was interesting enough to do some [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been evaluating a couple different mapping software packages recently and the other day I noticed that the same addresses geocoded (for those who don&#8217;t know what geocoding is you can find out more about it <a title="here" href="http://en.wikipedia.org/wiki/Geocoding">here</a>) to different locations. They are mostly the same but I figured it was interesting enough to do some more digging and see how different mapping services compared.I looked at the following services. Some of them are commercial services with open apis (ESRI and mapquest) and some of them are non-commercial services with open apis (yahoo and google although google does not have a geocoding api).</p>
<ul>
<li><a title="http://www.esri.com/software/awspublicservices/index.html" href="http://www.esri.com/software/awspublicservices/index.html">http://www.esri.com/software/awspublicservices/index.html</a></li>
<li><a title="http://developer.yahoo.com/maps/index.html" href="http://developer.yahoo.com/maps/index.html"> http://developer.yahoo.com/maps/index.html</a></li>
<li><a title="http://www.mapquest.com/openapi" href="http://www.mapquest.com/openapi"> http://www.mapquest.com/openapi</a></li>
<li><a title="http://maps.google.com" href="http://maps.google.com"> http://maps.google.com</a></li>
</ul>
<p>For google I viewed the resulting values for latitude and longitude that were generated from a search for the address. For yahoo and ESRI I used their REST geocoding apis and for mapquest I used their java api to their commercial service since their openapi service is only in beta currently.I took 5 addresses located at different points in the US and one in Canada and mapped the returned latitude and longitude from each service. Here are the results:<br />
<span id="more-18"></span></p>
<p>Missiondata, 2300 Hurstbourne Village Drive, Suite 1100, Louisville, KY, 40299<br />
mapquest: 38.215303, -85.578698<br />
google: 38.215601, -85.578852<br />
yahoo: 38.215496, -85.578669<br />
esri: 38.216273, -85.579028</p>
<p><img id="image19" alt="Missiondata Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/md.gis.jpg" /></p>
<p>Googleplex, 1600 Amphitheatre Parkway, Mountain View, CA, 94043<br />
mapquest: 37.4238,   -122.0901<br />
google: 37.422845, -122.085035<br />
yahoo: 37.42386,  -122.090332<br />
esri: 37.42386,  -122.090332</p>
<p><img id="image20" alt="Googleplex Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/google.gis.jpg" /></p>
<p>IBM New York, 590 Madison Ave, New York, NY, 10022<br />
mapquest: 40.7623,   -73.972399<br />
google: 40.762267, -73.972535<br />
yahoo: 40.762245, -73.972644<br />
esri: 40.762245, -73.972644</p>
<p><img id="image21" alt="IBM NY Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/ibm.gis.jpg" /></p>
<p>Lockheed Martin, 6304 Spine Rd, Boulder, CO, 80301<br />
mapquest: 40.0672,   -105.206711<br />
google: 40.067084, -105.206555<br />
yahoo: 40.067063, -105.20654<br />
esri: 40.067063, -105.20654</p>
<p><img id="image22" alt="Lockheed Martin Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/lm.gis.jpg" /></p>
<p>Red Hat Canada, 2323 Yonge Street, Suite #300, Toronto, Ontario M4P 2C9, Canada<br />
yahoo: none<br />
mapquest: 43.708137, -79.3985<br />
google: 37.062500, -95.677068<br />
esri: 79.398592, -43.7081</p>
<p><img id="image24" alt="Redhat Canada Mapquest Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/canada.mapquest.jpg" /><br />
<img id="image23" alt="Redhat Canada Google Results" src="http://blogs.missiondata.com/wp-content/uploads/2006/03/canada.google.jpg" /></p>
<p>For the most part all of the services provide very similar results for geocoding in the US. From the limited number of locations I tested it seems that the larger cities have a more reliable set of outputs. In NY for example they almost completely stack on top of each other. I find it interesting too that in 4 out of 6 cases yahoo came back with the exact same results as ESRI provided.</p>
<p>The last thing to notice of course is that the results for Canada are not as good. First off I couldn&#8217;t get yahoo&#8217;s service to work with a Canadian address for some reason. Also notice that the ESRI latitude and longitude results are swapped. And viewing the results from google for latitude and longitude gave me some wildly incorrect values but the map was actually correct (thus the two maps). The only completely reliable service for Canada was mapquest and google (although google doesn&#8217;t do geocoding) with ESRI coming in next just because the results were swapped. All in all I think all 3 did a good job.</p>
<p>I&#8217;m not sure why google hasn&#8217;t produced something in the way of geocoding yet. I think they have the mapping nailed down but their lack of geocoding will put them at somewhat of a disadvantage at some point since the other 3 services are in the open now and both ESRI and mapquest already have commercial versions of their services that people use widely.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.missiondata.com/blog/systems-integration/18/gis-geocoding-experiments/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
