<?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>Bluefin Engineering</title>
	<atom:link href="http://www.bluefinengineering.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.bluefinengineering.com</link>
	<description>Mobile, Web, Cloud</description>
	<lastBuildDate>Tue, 04 Jun 2013 15:07:35 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Burpee&#8217;s Seeds for Schools Program</title>
		<link>http://www.bluefinengineering.com/blog/burpees-seeds-for-schools-program</link>
		<comments>http://www.bluefinengineering.com/blog/burpees-seeds-for-schools-program#comments</comments>
		<pubDate>Tue, 04 Jun 2013 15:07:08 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=686</guid>
		<description><![CDATA[We are excited to announce the release of the Burpee&#8 [...]]]></description>
				<content:encoded><![CDATA[<p>We are excited to announce the release of the Burpee&#8217;s Seeds for Schools application.</p>
<p><a href="http://www.burpee.com/schools">http://www.burpee.com/schools</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/burpees-seeds-for-schools-program/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Artimys Guardian Service</title>
		<link>http://www.bluefinengineering.com/blog/the-artimys-guardian-service</link>
		<comments>http://www.bluefinengineering.com/blog/the-artimys-guardian-service#comments</comments>
		<pubDate>Mon, 13 May 2013 16:41:38 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=631</guid>
		<description><![CDATA[Bluefin Engineering is proud to announce the release of [...]]]></description>
				<content:encoded><![CDATA[<p>Bluefin Engineering is proud to announce the release of <a href="http://www.artimys.com">The Artimys Guardian Service</a>.</p>
<p><a href="http://www.artimys.com"><img src="http://www.bluefinengineering.com/wp-content/uploads/2012/07/logo.png" alt="Artimys Guardian Service" width="278" height="65" class="size-full wp-image-629" /></a></p>
<p><strong>The Artimys Guardian Service</strong></p>
<p>
The Artimys Guardian Service gives parents peace of mind knowing their children are getting the best possible protection from the dangers of the Internet. Using sophisticated natural language and information processing, the Artimys Guardian Service constantly analyzes your child’s electronic chats to immediately detect the insidious and clever techniques of online sexual predators, bullies and the warning signs of suicide.
</p>
<p>
Effectively a full-time expert guarding over your children, the accuracy of the Artimys Guardian Service has been shown to be greater than the accuracy of trained human experts. And the Artimys Guardian is adaptive; constantly learning new patterns. As pedophiles adjust and find new ways to access children, the Artimys Guardian Service acclimates and becomes better at spotting them. Likewise, the Artimys Guardian adapts to bullies&#8217; methods and the ever changing language of teens.
</p>
<p>
The Artimys Guardian Service provides an unparalleled level of protection and is the best protection you can provide for your children.
</p>
<p><a href="http://www.artimys.com?to=info">info@artimys.com</a> for general inquiries<br />
<a href="http://www.artimys.com?to=bixdev">bizdev@artimys.com</a> to partner with Artimys Language Technologies</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/the-artimys-guardian-service/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Custom PHP Disqus Comments Data Sync for Server-Side SEO</title>
		<link>http://www.bluefinengineering.com/blog/custom-php-disqus-comments-data-sync-se</link>
		<comments>http://www.bluefinengineering.com/blog/custom-php-disqus-comments-data-sync-se#comments</comments>
		<pubDate>Mon, 25 Mar 2013 11:11:57 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=614</guid>
		<description><![CDATA[I had to add Disqus comments to a custom PHP web applic [...]]]></description>
				<content:encoded><![CDATA[<p>I had to add Disqus comments to a custom PHP web application.  Adding the Disqus comments was easy because all you have to do is copy/paste the Disqus JavaScript into your page.  But if you want the comments to be crawl-able you must render them server-side.  To do this you must have a local copy of the comments in your database.  Here is how I solved this using PHP, crontab, and MySql.  </p>
<h3>Prerequisites</h3>
<ul>
<li>Disqus <strong>shortname</strong> &#8211; <a href="https://disqus.com/admin/signup/">Disqus Account</a></li>
<li>Disqus <strong>API Secret</strong> &#8211; <a href="http://disqus.com/api/applications/">Disqus API Account</a></li>
<li><a href="https://github.com/disqus/disqus-php">Disqus PHP Library</a></li>
</ul>
<h3>Database Tables</h3>
<p>I created two database tables <strong>disqus_thread</strong> and <strong>disqus_comment</strong>.  A Disqus thread is equivalent to a unique page with Disqus comments.  The &#8216;title&#8217; is the <em>disqus_identifier</em>.</p>
<pre class="brush: sql; title: ; notranslate">
create table `disqus_thread`
(
	`id` int not null,
	`title` varchar(2000) not null,
    `created` int(10) unsigned NOT NULL,
	 unique key(`id`),
	 index(`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

create table `disqus_comment`
(
	`id` int not null,
	`thread_id` int not null,
	`author_name` varchar(200),
	`comment` text not null,
    `created` int(10) unsigned NOT NULL,
	 unique key(`id`),
	 index (`thread_id`),
	 index (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
</pre>
<h3>Disqus Sync Script</h3>
<p>The sync script will fetch all new comments from Disqus and store them.  It then checks for missing threads.  If it finds any it fetches them from Disqus and stores them as well.  We only care about the threads that have comments.  When someone visits a page Disqus will create a thread even though there are no comments yet.  To limit the size of our DB we only store threads with comments.<br />
<strong>config.php</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
define('DB_NAME', 'your-db-name');
define('DB_USER', 'your-db-user');
define('DB_PASSWORD', 'your-db-password');
define('DB_HOST', 'your-db-host.com');

define('DISQUS_FETCH_LIMIT', 100);
define('DISQUS_FETCH_ORDER', 'asc');
define('DISQUS_API_SECRET', 'your-api-secret');
define('DISQUS_FORUM_SHORTNAME', 'your-shortname');
?&gt;
</pre>
<p><strong>sync-disqus-comments.php</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

error_reporting(0);
set_time_limit(60*10); // 10 minutes

/**
 * Sync the latest Disqus comments.
 */
require('config.php');
require('disqusapi/disqusapi.php');

try {
    $db_connect = 'mysql:host='.DB_HOST.';port=3306;dbname='.DB_NAME;
    $dbh = new PDO($db_connect, DB_USER, DB_PASSWORD);

    $threads = $dbh-&gt;prepare(&quot;insert into disqus_thread (id, title, created) values (:id, :title, :created)&quot;);
    $comments = $dbh-&gt;prepare(&quot;insert into disqus_comment (id, thread_id, author_name, comment, created) values (:id, :thread_id, :author_name, :comment, :created)&quot;);

    $disqus = new DisqusAPI(DISQUS_API_SECRET, 'json', '3.0');

    $params = array('forum' =&gt; DISQUS_FORUM_SHORTNAME, 'order' =&gt;  DISQUS_FETCH_ORDER, 'limit' =&gt; DISQUS_FETCH_LIMIT);

    //
    // Fetch comments ..
    //
    $res = $dbh-&gt;query(&quot;select max(created) as max from disqus_comment&quot;)-&gt;fetch();
    if (!empty($res['max'])) {
        $params['since'] = $res['max'];
    }

    do {
        $posts = $disqus-&gt;posts-&gt;list($params);
        $cursor = $posts-&gt;cursor;

        $params['cursor'] = $cursor-&gt;next;

        foreach ($posts as $post) {
            $comments-&gt;bindValue(':id', $post-&gt;id);
            $comments-&gt;bindValue(':author_name', $post-&gt;author-&gt;name);
            $comments-&gt;bindValue(':comment', $post-&gt;raw_message);
            $comments-&gt;bindValue(':thread_id', $post-&gt;thread);
            $comments-&gt;bindValue(':created', strtotime($post-&gt;createdAt.&quot;+0000&quot;));  //Since Disqus returns GMT add +0000 to the time string.
            $comments-&gt;execute();
        }
    } while ($cursor-&gt;more);

    unset($params['since']);
    unset($params['cursor']);

    //
    // Fetch threads
    //
    $unknownThreads = array();
    $unknownThreadsQuery = $dbh-&gt;prepare(&quot;select c.thread_id from disqus_comment c where (select count(*) from disqus_thread where id=c.thread_id)=0&quot;);
    $unknownThreadsQuery-&gt;execute();
    while( $row = $unknownThreadsQuery-&gt;fetchObject() ) {
        $unknownThreads[] = $row-&gt;thread_id;
    }

    if (!empty($unknownThreads)) {
        $params['thread'] = $unknownThreads;

        do {
            $posts = $disqus-&gt;threads-&gt;list($params);

            // Create cursor to paginate through resultset
            $cursor = $posts-&gt;cursor;

            // Update our arguments with the cursor and the next position
            $params['cursor'] = $cursor-&gt;next;

            foreach ($posts as $post) {
                $threads-&gt;bindValue(':id', $post-&gt;id);
                $threads-&gt;bindValue(':title', $post-&gt;title);
                $threads-&gt;bindValue(':created', strtotime($post-&gt;createdAt.&quot;+0000&quot;)); //Since Disqus returns GMT add +0000 to the time string.
                $threads-&gt;execute();
            }
        } while ($cursor-&gt;more);
        // End forum threads
    }




} catch (DisqusAPIError $e) {
    echo $e-&gt;getMessage();
    echo PHP_EOL;
    exit;
}

?&gt;
</pre>
<p><strong>Cron Job</strong><br />
We run the sync script every hour.  Here is the crontab command.</p>
<pre class="brush: plain; title: ; notranslate">
0 * * * * /usr/bin/php /var/analysis/sync-disqus-comments.php &gt; /dev/null 2&gt;&amp;1
</pre>
<h3>Front-end UI</h3>
<p>Here is the code to display the Disqus comments.  All the server-side comments rendered within <strong>&lt;div id=&#8221;disqus_thread&#8221;&gt;</strong> will be replaced with the client-side Disqus comments.</p>
<pre class="brush: php; title: ; notranslate">
        &lt;h3&gt;User reviews of &lt;?php echo($domain); ?&gt;&lt;/h3&gt;
        &lt;div id=&quot;disqus_thread&quot;&gt;
            &lt;?php
                $commentsQuery = fetch_analysis_page_comments($domain);
                while( $row = $commentsQuery-&gt;fetchObject() ){
                    ?&gt;
                        &lt;div&gt;
                            &lt;p&gt;Author: &lt;?php echo($row-&gt;author_name); ?&gt;&lt;/p&gt;
                            &lt;p&gt;Comment: &lt;?php echo($row-&gt;comment); ?&gt;&lt;/p&gt;
                        &lt;/div&gt;
                    &lt;?php
                }
            ?&gt;
        &lt;/div&gt;
        &lt;script type=&quot;text/javascript&quot;&gt;
            /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
            var disqus_shortname = '&lt;?php echo(DISQUS_FORUM_SHORTNAME); ?&gt;'; // required: replace example with your forum shortname
            var disqus_identifier = '&lt;?php echo($domain); ?&gt;';

            /* * * DON'T EDIT BELOW THIS LINE * * */
            (function() {
                var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
                dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
                (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
            })();
        &lt;/script&gt;
        &lt;noscript&gt;Please enable JavaScript to view the &lt;a href=&quot;http://disqus.com/?ref_noscript&quot;&gt;comments powered by Disqus.&lt;/a&gt;&lt;/noscript&gt;
        &lt;a href=&quot;http://disqus.com&quot; class=&quot;dsq-brlink&quot;&gt;comments powered by &lt;span class=&quot;logo-disqus&quot;&gt;Disqus&lt;/span&gt;&lt;/a&gt;
</pre>
<p><strong>fetch_analysis_page_comments($)</strong></p>
<pre class="brush: php; title: ; notranslate">
function fetch_analysis_page_comments($domain) {
    $db_connect = 'mysql:host='.DB_HOST.';port=3306;dbname='.DB_NAME;
    $dbh = new PDO($db_connect, DB_USER, DB_PASSWORD);

    $commentsQuery = $dbh-&gt;prepare(&quot;select * from disqus_comment where thread_id = (select id from disqus_thread where title=:domain)&quot;);
    $commentsQuery-&gt;bindValue(':domain', $domain);
    $commentsQuery-&gt;execute();
    return $commentsQuery;
}
</pre>
<p>In our case the <strong>$domain</strong> variable is the Disqus <strong>disqus_identifier</strong>.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/custom-php-disqus-comments-data-sync-se/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LESS CSS Eclipse Builder</title>
		<link>http://www.bluefinengineering.com/blog/less-css-eclipse-builder</link>
		<comments>http://www.bluefinengineering.com/blog/less-css-eclipse-builder#comments</comments>
		<pubDate>Fri, 01 Mar 2013 18:31:20 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=577</guid>
		<description><![CDATA[How to automatically compile your LESS CSS files within [...]]]></description>
				<content:encoded><![CDATA[<p>How to automatically compile your LESS CSS files within your eclipse project.</p>
<p>I&#8217;m using a Mac so there will be slight changes for other Operating Systems.</p>
<h2>Step 1</h2>
<p>Download and install <a href="http://lesscss.org/" title="LESS CSS">LESS CSS</a>.</p>
<h2>Step 2</h2>
<p>Create the less.xml ant task and add it as an Eclipse Builder.</p>
<p>Add the following ant build file to the base of your Eclipse project.<br />
<strong>less.xml</strong></p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project name=&quot;lesscss&quot; default=&quot;less&quot; basedir=&quot;.&quot;&gt;
	&lt;property name=&quot;dir.project&quot;
		value=&quot;/Users/rgfindley/Documents/work/workspace-juno/marineweather&quot; /&gt;
	&lt;property name=&quot;dir.css&quot; value=&quot;${dir.project}/war/static/css&quot; /&gt;
	&lt;property name=&quot;lessc&quot; value=&quot;/usr/local/bin/lessc&quot; /&gt;
	&lt;property name=&quot;pathToNode&quot; value=&quot;/usr/local/bin&quot; /&gt;

	&lt;target name=&quot;less&quot; description=&quot;Compile LESS files&quot;&gt;
		&lt;antcall target=&quot;lessfile&quot;&gt;
			&lt;param name=&quot;file.name&quot; value=&quot;test&quot; /&gt;
		&lt;/antcall&gt;
		&lt;antcall target=&quot;lessfile&quot;&gt;
			&lt;param name=&quot;file.name&quot; value=&quot;test2&quot; /&gt;
		&lt;/antcall&gt;
	&lt;/target&gt;

	&lt;target name=&quot;lessfile&quot;&gt;
		&lt;exec executable=&quot;${lessc}&quot; failonerror=&quot;true&quot;&gt;
			&lt;env key=&quot;PATH&quot; value=&quot;${env.PATH}:${pathToNode}&quot; /&gt;
			&lt;arg line=&quot;-x ${dir.css}/${file.name}.less ${dir.css}/${file.name}.css&quot; /&gt;
		&lt;/exec&gt;
	&lt;/target&gt;
&lt;/project&gt;
</pre>
<p>Change the properties to match your project configuration.  Ideally the ant task would compile all *.less files and compile them.  If anyone improves this script please let me know.</p>
<p>If you are getting the following error: &#8220;env: node: No such file or directory&#8221;.</p>
<p>Make sure you have the following: &#8220;&lt;env key=&#8221;PATH&#8221; value=&#8221;${env.PATH}:${pathToNode}&#8221; /&gt;&#8221; in your lessc &lt;exec&gt; call.</p>
<h2>Step 3</h2>
<p>Now add the Eclipse Builder to your project.</p>
<p>Project->Properties->Builders->New&#8230;<br />
My project is called &#8216;marineweather&#8217;.  So replace that with your project name.<br />
Here are the LESS CSS builder settings.</p>
<p><img src="http://www.bluefinengineering.com/wp-content/uploads/2013/03/LESS1-877x1024.png" alt="LESS1" width="550" height="642" class="alignleft size-large wp-image-585" /><br />
<img src="http://www.bluefinengineering.com/wp-content/uploads/2013/03/LESS2-877x1024.png" alt="LESS2" width="550" height="642" class="alignleft size-large wp-image-586" /><br />
<img src="http://www.bluefinengineering.com/wp-content/uploads/2013/03/LESS3-877x1024.png" alt="LESS3" width="550" height="642" class="alignleft size-large wp-image-587" /></p>
<div class="clear"></div>
<h2>Step 4</h2>
<p>Create the test LESS CSS file.<br />
<strong>test.less</strong></p>
<pre class="brush: css; title: ; notranslate">
@color: #4D926F;

#header {
  color: @color;
}
h2 {
  color: @color;
}
</pre>
<h2>That&#8217;s it</h2>
<p>Now every time you edit your LESS CSS files the corresponding *.css files will be generated.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/less-css-eclipse-builder/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Open Source AWS Image Server</title>
		<link>http://www.bluefinengineering.com/blog/open-source-aws-image-server</link>
		<comments>http://www.bluefinengineering.com/blog/open-source-aws-image-server#comments</comments>
		<pubDate>Tue, 11 Dec 2012 19:21:13 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=570</guid>
		<description><![CDATA[Bluefin Engineering is proud to announce that it has st [...]]]></description>
				<content:encoded><![CDATA[<p>Bluefin Engineering is proud to announce that it has started a new open source project.  </p>
<p><a href="http://rgfindl.github.com/bluefin_aws_image_server/">Bluefin AWS Image Server</a>.<br />
Open Source on-the-fly image server. Resize your S3 images on the fly using ImageMagick, then cache them using CloudFront.</p>
<p>After uploading your full size image to S3 you can request a resized image to place on your page.</p>
<p>For more information please visit the <a href="http://rgfindl.github.com/bluefin_aws_image_server/">GitHub Project</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/open-source-aws-image-server/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Burpee&#8217;s Backyard Application</title>
		<link>http://www.bluefinengineering.com/blog/burpees-backyard-application</link>
		<comments>http://www.bluefinengineering.com/blog/burpees-backyard-application#comments</comments>
		<pubDate>Sat, 10 Nov 2012 03:02:24 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=562</guid>
		<description><![CDATA[Bluefin Engineering has just released a new application [...]]]></description>
				<content:encoded><![CDATA[<p>Bluefin Engineering has just released a new application for <a href="http://www.burpe.com">burpee.com</a> called <a href="http://www.burpee.com/community/">Burpee&#8217;s Backyard</a>.</p>
<p><a href="http://www.burpee.com/community/"><img src="http://www.bluefinengineering.com/wp-content/uploads/2012/07/burpee-fb-icon-150x150.jpg" alt="" title="Burpee Community" width="150" height="150" class="alignright size-thumbnail wp-image-559" /></a></p>
<blockquote><p>More than ever, gardening is about sharing.  With family, friends, community.  Even a single gardener tending a single potted tomato is part of a larger growing community of people who value a connection to the soil and some moments in the sun.  If you&#8217;ve ever admired a flower or picked a fresh tomato, you&#8217;re part of a shared gardening experience.  And this forum is for you. </p></blockquote>
<p>The application was developed using Java/J2EE (Servlets and JSP&#8217;s) and <a href="http://tuckey.org/urlrewrite/">Tuckey&#8217;s UrlRewrite</a>.  The application is hosted by <a href="http://aws.amazon.com/">AWS Cloud</a> using the following tools.</p>
<p><strong>Burpee&#8217;s Backyard Web Application</strong></p>
<ul>
<li>Elastic Beanstalk</li>
<ul>
<li>EC2 (Tomcat 7)</li>
<li>Elastic Load Balancer</li>
</ul>
<li>RDS Mulit-AZ (MySql)</li>
<li>S3 + Cloudfront (Uploaded files, images, etc…)</li>
<li>Cloudfront (static files, images, js, css)</li>
<li>SQS (async tasks)</li>
<li>SES (email)</li>
</ul>
<p><strong>Burpee&#8217;s Backyard Image Server</strong><br />
The image server generated on-the-fly image sizes.  The source image are stored in S3.  The images are then cached by Cloudfront.</p>
<ul>
<li>EC2</li>
<ul>
<li>Auto Scaling Group</li>
<li>Linux, Apache, PHP, Imagemagick</li>
</ul>
<li>Cloudfront</li>
<li>S3</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/burpees-backyard-application/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Marine Weather Web Application</title>
		<link>http://www.bluefinengineering.com/marineweather/marine-weather-web-application</link>
		<comments>http://www.bluefinengineering.com/marineweather/marine-weather-web-application#comments</comments>
		<pubDate>Fri, 19 Oct 2012 19:18:06 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Marine Weather]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=551</guid>
		<description><![CDATA[Marine Weather by Bluefin is now available on the web.  [...]]]></description>
				<content:encoded><![CDATA[<p>Marine Weather by Bluefin is now available on the web.  Our application provides easy access to many marine weather products.  Forecasts, Live Stations, Tide Predictions, Current Predictions, and Sun Rise/Set times.</p>
<p>Our application is the #1 mobile application available on all Android and iOS devices.  The application covers the United States, United Kingdom, and Australia.  </p>
<p><a href="http://www.marineweatherbybluefin.com">http://www.marineweatherbybluefin.com</a></p>
<p><a href="http://www.bluefinengineering.com/wp-content/uploads/2012/10/marine-weather-web-app.jpg"><img src="http://www.bluefinengineering.com/wp-content/uploads/2012/10/marine-weather-web-app-300x135.jpg" alt="" title="marine-weather-web-app" width="300" height="135" class="alignleft size-medium wp-image-553" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/marineweather/marine-weather-web-application/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bluefin becomes an Amazon Consulting Partner</title>
		<link>http://www.bluefinengineering.com/blog/bluefin-becomes-an-amazon-consulting-partner</link>
		<comments>http://www.bluefinengineering.com/blog/bluefin-becomes-an-amazon-consulting-partner#comments</comments>
		<pubDate>Mon, 24 Sep 2012 20:26:14 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=546</guid>
		<description><![CDATA[Bluefin Engineering is proud to be one of Amazon&#8217; [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.bluefinengineering.com/wp-content/uploads/2012/09/AWS_Logo_Consulting_Partner.png"><img src="http://www.bluefinengineering.com/wp-content/uploads/2012/09/AWS_Logo_Consulting_Partner-300x129.png" alt="" title="AWS_Logo_Consulting_Partner" width="300" height="129" class="alignleft size-medium wp-image-547" /></a></p>
<p>Bluefin Engineering is proud to be one of Amazon&#8217;s Consulting Partners.  Bluefin Engineering has been building applications for the cloud for over a year now.  All of our current development will be hosted in the cloud.</p>
<p>Here is our amazon profile page <a href="https://aws.amazon.com/solution-providers/si/bluefin-engineering">https://aws.amazon.com/solution-providers/si/bluefin-engineering</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/blog/bluefin-becomes-an-amazon-consulting-partner/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reprojecting NOAA Ridge radar images for Google Maps using Amazon EC2, CloudFront, and PHP</title>
		<link>http://www.bluefinengineering.com/marineweather/reprojecting-noaa-ridge-radar-images-for-google-maps-using-amazon-ec2-cloudfront-php</link>
		<comments>http://www.bluefinengineering.com/marineweather/reprojecting-noaa-ridge-radar-images-for-google-maps-using-amazon-ec2-cloudfront-php#comments</comments>
		<pubDate>Fri, 31 Aug 2012 16:48:17 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Marine Weather]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=502</guid>
		<description><![CDATA[First I would like to thank Ken and his blog post &#822 [...]]]></description>
				<content:encoded><![CDATA[<blockquote><p>First I would like to thank Ken and his blog post &#8220;<a href="http://egb13.net/2009/03/using-gdalwarp/">Using gdalwarp</a>&#8220;.  Ken took the time to answer my questions about gdalwarp and was a huge help.</p></blockquote>
<p>I needed to display <a href="http://radar.weather.gov/GIS.html" title="NOAA Ridge radar images">NOAA Ridge Radar</a> images on Google maps.  The problem is that the radar images have a different <a href="http://en.wikipedia.org/wiki/Map_projection">projection</a> (representation of the globe on a flat map) than Google maps.</p>
<p>NOAA Ridge Radar: <a href="http://www.srh.noaa.gov/jetstream/doppler/radarfaq.htm#projection">Un-projected</a><br />
Google Maps: <a href="http://en.wikipedia.org/wiki/Mercator_projection">Mercator Projection</a></p>
<p>Here is how I reprojected the images on the fly using Amazon <a href="http://aws.amazon.com/ec2/">EC2</a>, <a href="http://aws.amazon.com/cloudfront/">CloudFront</a>, and PHP.</p>
<p>First I had to install gdal and ImageMagick on my EC2 instance.  I explained this in a <a href="/blog/installing-gdal-on-amazon-linux-ami">previous post</a>.</p>
<p>Next I created a PHP script to warp the image on the fly.  <a href="http://aws.amazon.com/cloudfront/">CloudFront</a> caches the request. If the same image is requested CloudFront will return its cached version and our server won&#8217;t be touched.  This improves performance and reduces the load on the server.</p>
<p><strong>radarImage.php</strong></p>
<pre class="brush: php; title: ; notranslate">


function noCacheError() {
	header('Cache-Control: max-age=0'); 
	exit;
}

try {

	$name = $_GET['image']; //pacnorthwest_20120817_0118_N0Ronly.gif, NCR/AHG/AHG_20120817_0912_NCR.gif
	if (strlen($name) &lt;= 0)
		noCacheError();
	
	//
	// Setup the params
	//
	$url = &quot;http://www.srh.noaa.gov/ridge/Conus/RadarImg/&quot;;
	if (strpos($name, &quot;/&quot;)) {
		$urlPostfix = substr($name, 0, 8);
		$name = substr($name, 8);
		$url = &quot;http://www.srh.noaa.gov/ridge/RadarImg/&quot;.$urlPostfix;
	} 
	
	$prefix = strtolower(substr($name, 0, strpos($name, &quot;_&quot;)));
	$tmpName=$prefix.&quot;_radaronly.gif&quot;;
	$gfw=$prefix.&quot;_radaronly.gfw&quot;;
	$tiffName=$prefix.&quot;_radaronly.tiff&quot;;
	
	//
	// Make the temp dir.
	//
	exec(&quot;/php_scripts/mk_tmp_warp_dir.sh \&quot;&quot;.$name.&quot;\&quot;&quot;);
	
	//
	// Fetch the radar image from noaa and place it in the temp dir.
	//
	$img = &quot;/php_scripts/tmp/&quot;.$name.&quot;/&quot;.$tmpName;
	file_put_contents(&quot;/php_scripts/tmp/&quot;.$name.&quot;/&quot;.$tmpName, file_get_contents($url.$name));
	
	//
	// Warp the image and convert it to a png
	//
	exec(&quot;/php_scripts/warpimage.sh \&quot;&quot;.$url.&quot;\&quot; \&quot;&quot;.$name.&quot;\&quot; \&quot;&quot;.$tmpName.&quot;\&quot; \&quot;&quot;.$gfw.&quot;\&quot; \&quot;&quot;.$tiffName.&quot;\&quot;&quot;);
	
	//
	// Send the image to the http response
	//
	header('Content-Type: image/png');
	header('Cache-Control: max-age=86400'); 
	readfile(&quot;/php_scripts/tmp/&quot;.$name.&quot;/&quot;.$name.&quot;.png&quot;);
	
	//
	// Remove the temp dir.
	//
	exec(&quot;rm -fR /php_scripts/tmp/&quot;.$name);
} catch (Exception $e) {
	noCacheError();
}

exit;
</pre>
<p>Here are the bash scripts:<br />
<strong>mk_tmp_warp_dir.sh</strong></p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh

# Vars
dir=$1

# Make temp dir
mkdir /php_scripts/tmp/$dir
chmod 777 /php_scripts/tmp/$dir
</pre>
<p><strong>warpimage.sh</strong></p>
<pre class="brush: bash; title: ; notranslate">

#!/bin/sh

#
# Capture vars
#
url=$1
name=$2
tmpName=$3
gfw=$4
tiffName=$5
dir=$2

#
# Copy the world file into the temp dir
#
cp /php_scripts/gfw/$gfw /php_scripts/tmp/$dir/$gfw
chmod 777 /php_scripts/tmp/$dir/$gfw

#
# warp the radar gif using the world file to Google Maps projection
#
/usr/local/bin/gdalwarp -dstalpha -ts 840 800 -s_srs EPSG:4326 -t_srs &quot;+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +
wktext +no_defs&quot; /php_scripts/tmp/$dir/$tmpName /php_scripts/tmp/$dir/$tiffName

#
# Convert the tiff to a transparent png
#
/usr/bin/convert /php_scripts/tmp/$dir/$tiffName -transparent white /php_scripts/tmp/$dir/$name.png
</pre>
<p><strong>File structure on the server</strong></p>
<pre class="brush: bash; title: ; notranslate">
[ec2-user@ /]$ ls -alR /php_scripts/ | cat
/php_scripts/:
total 24
drwxrwxrwx  4 root root 4096 Aug 21 19:40 .
dr-xr-xr-x 25 root root 4096 Aug 31 03:28 ..
drwxrwxrwx  2 root root 4096 Aug 17 10:39 gfw
-rwxrwxrwx  1 root root  103 Aug 17 12:41 mk_tmp_warp_dir.sh
drwxrwxrwx 35 root root 4096 Aug 31 16:41 tmp
-rwxrwxrwx  1 root root  691 Aug 17 12:47 warpimage.sh

/php_scripts/gfw:
total 80
drwxrwxrwx 2 root root 4096 Aug 17 10:39 .
drwxrwxrwx 4 root root 4096 Aug 21 19:40 ..
-rwxrwxrwx 1 root root  459 Aug 17 09:47 abc_radaronly.gfw
-rwxrwxrwx 1 root root   98 Aug 16  2005 acg_radaronly.gfw
-rwxrwxrwx 1 root root   98 Aug 16  2005 aec_radaronly.gfw
-rwxrwxrwx 1 root root   98 Aug 16  2005 ahg_radaronly.gfw
-rwxrwxrwx 1 root root   97 Aug 16  2005 aih_radaronly.gfw
-rwxrwxrwx 1 root root   97 Aug 16  2005 akc_radaronly.gfw
-rwxrwxrwx 1 root root  136 Aug 16 20:16 alaska_radaronly.gfw
-rwxrwxrwx 1 root root  115 Aug 16 20:16 centgrtlakes_radaronly.gfw
-rwxrwxrwx 1 root root  119 Aug 16 20:16 hawaii_radaronly.gfw
-rwxrwxrwx 1 root root  100 Aug 16  2005 hki_radaronly.gfw
-rwxrwxrwx 1 root root  100 Aug 16  2005 hkm_radaronly.gfw
-rwxrwxrwx 1 root root  100 Aug 16  2005 hmo_radaronly.gfw
-rwxrwxrwx 1 root root   94 Aug 16  2005 hwa_radaronly.gfw
-rwxrwxrwx 1 root root  115 Aug 16 20:16 northeast_radaronly.gfw
-rwxrwxrwx 1 root root  117 Aug 16 20:16 pacnorthwest_radaronly.gfw
-rwxrwxrwx 1 root root  119 Aug 16 20:16 pacsouthwest_radaronly.gfw
-rwxrwxrwx 1 root root  117 Aug 16 20:16 southeast_radaronly.gfw
-rwxrwxrwx 1 root root  117 Aug 16 20:16 southmissvly_radaronly.gfw

</pre>
<p>I downloaded the world files (*.gfw) here: <a href="http://radar.weather.gov/ridge/Conus/RadarImg/">http://radar.weather.gov/ridge/Conus/RadarImg/</a><br />
Example: <a href="http://radar.weather.gov/ridge/Conus/RadarImg/alaska.gfw">http://radar.weather.gov/ridge/Conus/RadarImg/alaska.gfw</a></p>
<p>The following website is a good resource to find gdalwarp projection parameters: <a href="http://spatialreference.org/">http://spatialreference.org/</a></p>
<p>Here is the one I used for Google maps: <a href="http://spatialreference.org/ref/sr-org/7094/">http://spatialreference.org/ref/sr-org/7094/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/marineweather/reprojecting-noaa-ridge-radar-images-for-google-maps-using-amazon-ec2-cloudfront-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Marine Weather gets a new look</title>
		<link>http://www.bluefinengineering.com/marineweather/marine-weather-gets-a-new-look</link>
		<comments>http://www.bluefinengineering.com/marineweather/marine-weather-gets-a-new-look#comments</comments>
		<pubDate>Fri, 31 Aug 2012 16:29:31 +0000</pubDate>
		<dc:creator>Randy Findley</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Marine Weather]]></category>

		<guid isPermaLink="false">http://www.bluefinengineering.com/?p=521</guid>
		<description><![CDATA[Marine Weather gets a new look. Thanks for the awesome  [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.marineweatherbybluefin.com"><img src="http://www.bluefinengineering.com/wp-content/uploads/2012/08/MarineWeatherUI1-300x202.png" alt="" title="Marine Weather UI" width="300" height="202" class=" size-medium wp-image-523" /></a></p>
<p><a href="http://marineweatherbybluefin.com">Marine Weather</a> gets a new look.  Thanks for the awesome design <a href="http://www.behance.net/jessicafleming">Jessica Fleming</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bluefinengineering.com/marineweather/marine-weather-gets-a-new-look/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
