<?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/"
	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>Jeff Crouse &#187; tool</title>
	<atom:link href="http://www.jeffcrouse.info/tag/tool/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jeffcrouse.info</link>
	<description>Portfolio and news</description>
	<lastBuildDate>Mon, 28 Nov 2011 18:01:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
	<copyright>CreativeCommons Attribution-Noncommercial-Share Alike 2.5 </copyright>
	<managingEditor>jeff@jeffcrouse.info (Jeff Crouse)</managingEditor>
	<webMaster>jeff@jeffcrouse.info (Jeff Crouse)</webMaster>
	<category>mashup</category>
	<ttl>1440</ttl>
	<image>
		<url>http://4u.jeffcrouse.info/gs/podcast.jpg</url>
		<title>Jeff Crouse</title>
		<link>http://www.jeffcrouse.info</link>
		<width>144</width>
		<height>144</height>
	</image>
	<itunes:new-feed-url>http://www.jeffcrouse.info/category/music/feed/</itunes:new-feed-url>
	<itunes:subtitle>Musical treats from Jeff Crouse</itunes:subtitle>
	<itunes:summary>Musical treats from Jeffish</itunes:summary>
	<itunes:keywords></itunes:keywords>
	<itunes:category text="Music" />
	<itunes:category text="Arts" />
	<itunes:category text="Comedy" />
	<itunes:author>Jeff Crouse</itunes:author>
	<itunes:owner>
		<itunes:name>Jeff Crouse</itunes:name>
		<itunes:email>jeff@jeffcrouse.info</itunes:email>
	</itunes:owner>
	<itunes:block>no</itunes:block>
	<itunes:explicit>no</itunes:explicit>
	<itunes:image href="http://4u.jeffcrouse.info/gs/podcast.jpg" />
		<item>
		<title>Earthify</title>
		<link>http://www.jeffcrouse.info/events/earthify/</link>
		<comments>http://www.jeffcrouse.info/events/earthify/#comments</comments>
		<pubDate>Fri, 02 Feb 2007 23:41:44 +0000</pubDate>
		<dc:creator>Jeff</dc:creator>
				<category><![CDATA[Events]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[screenscraping]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.jeffcrouse.info/?p=47</guid>
		<description><![CDATA[Earthify takes Craigslist posts and maps them onto Google Earth.]]></description>
			<content:encoded><![CDATA[<p><img class="size-thumbnail wp-image-983 alignleft" style="margin-right: 10px;" title="earthify" src="http://beta.jeffcrouse.info/wp-content/uploads/2008/10/earthify-150x150.jpg" alt="" width="150" height="150" />Earthify takes a page of Craigslist posts and maps them on Google Earth. It has been tested with both search result pages and browse pages in several categories. The results are divided into &#8220;Earthifyable Listings&#8221; and &#8220;Un-Earthifyable Listings&#8221;, the un-earthifyable ones being those that could not be located based on the location provided by the user. In my tests, the listings are Earthifyable more often than not, but it really depends on how much information is in the posting.</p>
<p><span id="more-2587"></span></p>
<pre class="brush: php; title: ; notranslate">

/**
*	Represents one Craigslist page.
*	Can either be a page of results or a single listing page.
*/
class Craigslist extends PlacemarkSource {

private $url;

private $type;

const url_pattern = &quot;/craigslist/i&quot;;

private $regexes = array(
/**
*	This should match the URL of any single Craigslist listing page.
*	They will look like
*	http://montreal.craigslist.org/sub/298262212.html
*	http://newyork.craigslist.org/brk/sys/299139631.html
*/
'single_listing_url' =&gt; &quot;/craigslist.[a-z]{2,3}/(.+).html/i&quot;,

/**
*	This should match the URL of any page with multiple Craigslist pages
*	These pages may look like :
*	http://newyork.craigslist.org/search/bik/brk?query=&amp;amp;amp;amp;amp;amp;amp;minAsk=min&amp;amp;amp;amp;amp;amp;amp;maxAsk=200&amp;amp;amp;amp;amp;amp;amp;hasPic=1
*	OR
*	http://montreal.craigslist.org/sub/
*	http://newyork.craigslist.org/que/bik/
*	BUT NOT
*	http://montreal.craigslist.org/sub/298262212.html
*	http://newyork.craigslist.org/brk/sys/299139631.html
*/
'multiple_listing_page_url' =&gt; &quot;/craigslist.[a-z]{2,3}/i&quot;,

/**
*	This should match the URL of any Craigslist listing feed.
*	These pages should looke like:
*	http://philadelphia.craigslist.org/apa/index.rss
*	http://philadelphia.craigslist.org/search/apa?query=&amp;amp;amp;amp;amp;amp;amp;minAsk=&amp;amp;amp;amp;amp;amp;amp;maxAsk=200&amp;amp;amp;amp;amp;amp;amp;bedrooms=&amp;amp;amp;amp;amp;amp;amp;addTwo=purrr&amp;amp;amp;amp;amp;amp;amp;addThree=wooof&amp;amp;amp;amp;amp;amp;amp;hasPic=1&amp;amp;amp;amp;amp;amp;amp;format=rss
*/
'feed_url' =&gt; &quot;/craigslist.[a-z]{2,3}/(.+)(index.|format=)?(rss)/i&quot;,

/**
*	This Regex should match 1) URLs of listing pages 2) Titles of listings
*/
'get_listings' =&gt; &quot;/&lt;p&gt;(.*?)&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;/a&gt;&lt;font size=&quot;-1&quot;&gt; ((.*?))&lt;/font&gt;(.*?)?&lt;/p&gt;/i&quot;,

/**
*	In the pages of most Craigslist listings, the city that you are exploring is in a link at the top.
*	&lt;a href=&quot;http://philadelphia.craigslist.org&quot;&gt;philadelphia craigslist&lt;/a&gt;
*	or
*	&lt;a href=&quot;/&quot;&gt; new york craigslist&lt;/a&gt;
*/
'city_in_title' =&gt; &quot;/&lt;a href=&quot;(.+)?&quot;&gt;(.*?) craigslist&lt;/a&gt;/i&quot;
);

/*
*	The constructor for a Craigslist listing.
*	Most times, if you are parsing an entire page of listings, you will know the city
*	for every posting and the title along with the url before you construct them.  So if you
*	provide them, the constructor will go faster.
*/
function Craigslist($_url, $limit=null) {

$this-&gt;url = $_url;
$this-&gt;limit = $limit;

// First we will figure out what kind of page we are dealing with.
if(preg_match($this-&gt;regexes['single_listing_url'], $this-&gt;url)) {

$this-&gt;type = &quot;single&quot;; // an actual listing page.

} else if(preg_match($this-&gt;regexes['feed_url'], $this-&gt;url)) {

$this-&gt;type = &quot;feed&quot;;	// A feed of listings

} else if(preg_match($this-&gt;regexes['multiple_listing_page_url'], $this-&gt;url)) {

$this-&gt;type = &quot;multiple&quot;;  //  a search results or browse page

}
}

/**
*	Takes a relative URL from the current page and turns it into a full URL.
*/
function unrelativize($relative_url) {
$u = parse_url($this-&gt;url);
if(substr($relative_url, 0, 1) == '/') {
return &quot;http://&quot;.$u['host'].$relative_url;
} else {
return &quot;http://&quot;.$u['host'].dirname($u['path']).$relative_url;
}
}

/*
function parsePlacemarks() {
foreach($this-&gt;placemarks as $p) {
$p-&gt;parse();
}
}
*/

function getPlacemarks() {

switch($this-&gt;type) {

// It is a single listing, so just parse the current page.
case 'single':
$this-&gt;placemarks[] = new CraigsListing($this-&gt;url);
break;

// If if is a page of many listings, get all of the URLs.
case 'multiple':
$content = HttpClient::quickGet($this-&gt;url);

// The city appears in a link at the top.
preg_match($this-&gt;regexes['city_in_title'], $content, $matches);
$city = $matches[2];

//assert('$city!=null');

preg_match_all($this-&gt;regexes['get_listings'], $content, $matches);
$listing_urls = $matches[2];
$titles = $matches[3];
$locations = $matches[4];

foreach(array_keys($listing_urls) as $i) {
$listing_urls[$i] = $this-&gt;unrelativize($listing_urls[$i]);
}

if(count($listing_urls) == 0) {
trigger_error(&quot;Earthify couldn't find any listings on the page you provided.&quot;);
}

// Loop through all of the matches and make placemarks from them.
$max = isset($this-&gt;limit)
? min(count($listing_urls), $this-&gt;limit)
: count($listing_urls);

for($i=0; $i&lt;$max; $i++) {
// Check to make sure the link exists first
if(HttpClient::url_exists($listing_urls[$i])) {
$listing = new CraigsListing($listing_urls[$i]);
$listing-&gt;setTitle($titles[$i]);
$listing-&gt;setCity($city);
$this-&gt;placemarks[] = $listing;
} else {
trigger_error(&quot;{$listing_urls[$i]} returned a 200 or 302 status, which means that it doesn't exist.&quot;, E_USER_WARNING);
}
}
break;

// If this is the RSS feed from a particular kind Craigslist page, just parse the RSS
case 'feed':
$content = HttpClient::quickGet($this-&gt;url);

$xml = new SimpleXMLElement($content);

// The city name appears in the channel title.
preg_match(&quot;/&lt;title&gt;craigslist | (.*?) in (.+)&lt;/title&gt;/&quot;, $content, $matches);
$city = $matches[2];

//assert('$city!=null');

// Loop through all of the matches and make placemarks from them.
$max = isset($this-&gt;limit)
? min(count($xml-&gt;item), $this-&gt;limit)
: count($xml-&gt;item);

for($i=0; $i&lt;$max; $i++) {

$link =  (string)$xml-&gt;item[$i]-&gt;link;

// Check to make sure the URL exists first.
if(HttpClient::url_exists($link)) {
$listing = new CraigsListing($link);
$listing-&gt;title = (string)$xml-&gt;item[$i]-&gt;title;
$listing-&gt;city = $city;
$this-&gt;placemarks[] = $listing;
} else {
trigger_error(&quot;{$listing_urls[$i]} returned a 200 or 302 status, which means that it doesn't exist.&quot;, E_USER_WARNING);
}
}
break;
}

return $this-&gt;placemarks;
} // end getPlacemarks()
}
</pre>
<pre class="brush: php; title: ; notranslate">
/**************************
*
*	Serializer.php
*	Turns an array of Placemark objects into an Earthify KML script.
*
*	Written by Jeff Crouse at Eyebeam
*	February 8, 2007
*
***************************/
class KMLSerializer {

public static function serialize($placemarks) {

// Create the XML document and the root tag (kml)
$dom = new DomDocument('1.0', 'utf-8');
$root = $dom-&gt;createElement(&quot;kml&quot;);
$dom-&gt;appendChild($root);

// Create the Document tag
$doc = $dom-&gt;createElement(&quot;Document&quot;);
$root-&gt;appendChild($doc);

// Add a Earthify tag to the document tag.
$doc-&gt;appendChild($dom-&gt;createElement(&quot;name&quot;, &quot;Earthify&quot;));

// Make two folders within the document.  One for locatable items, one for lost ones
$found = $dom-&gt;createElement('Folder');
$found-&gt;appendChild($dom-&gt;createElement(&quot;name&quot;, &quot;Earthifyable Listings&quot;));
$doc-&gt;appendChild($found);

$lost = $dom-&gt;createElement('Folder');
$lost-&gt;appendChild($dom-&gt;createElement(&quot;name&quot;, &quot;Un-Earthifyable Listings&quot;));
$lost-&gt;appendChild($dom-&gt;createElement(&quot;description&quot;, &quot;Items whose coordinates could not be geocoded.&quot;));
$doc-&gt;appendChild($lost);

// Loop through all of the listings and add them to the document.
foreach($placemarks as $placemark) {
if($placemark instanceof Placemark) {

// Make the placemark tag in which all of this shit will go.
$placemark_dom = $dom-&gt;createElement(&quot;Placemark&quot;);
$placemark_dom-&gt;setAttribute(&quot;id&quot;, $placemark-&gt;getId());

// Make the name tag for the Placemark
$name = $dom-&gt;createElement(&quot;name&quot;, htmlspecialchars($placemark-&gt;getTitle()));
$placemark_dom-&gt;appendChild($name);

// Make the description tag for the placemark.
$description = $dom-&gt;createElement(&quot;description&quot;);
$cdata = $dom-&gt;createCDATASection($placemark-&gt;description());
$description-&gt;appendChild( $cdata );
$placemark_dom-&gt;appendChild($description);

// If we can't find any coordinates, add this item to the &quot;lost&quot; folder.
if($placemark-&gt;getCoords()) {
// Make the Point element for the placemark
$point = $dom-&gt;createElement(&quot;Point&quot;);
$coords = $dom-&gt;createElement(&quot;coordinates&quot;, $placemark-&gt;getCoords());
$point-&gt;appendChild($coords);
$placemark_dom-&gt;appendChild($point);

// Add the placemark to the &quot;Found&quot; folder
$found-&gt;appendChild($placemark_dom);
} else {
$lost-&gt;appendChild($placemark_dom);

}
} else {
trigger_error(&quot;KMLSerializer received something that wasn't a Placemark.&quot;, E_WARNING);
}
}

return $dom-&gt;saveXML();
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.jeffcrouse.info/events/earthify/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Switchboard</title>
		<link>http://www.jeffcrouse.info/projects/switchboard/</link>
		<comments>http://www.jeffcrouse.info/projects/switchboard/#comments</comments>
		<pubDate>Tue, 23 May 2006 18:56:16 +0000</pubDate>
		<dc:creator>Jeff</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[processing]]></category>
		<category><![CDATA[tool]]></category>

		<guid isPermaLink="false">http://www.jeffcrouse.info/?p=307</guid>
		<description><![CDATA[Web services library for Processing.]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-310" title="switchboard" src="http://beta.jeffcrouse.info/wp-content/uploads/2008/08/switchboard.png" alt="" width="128" height="128" /></p>
<p>Switchboard is an open-source conceptual level interface to a library of data mining tools and web services, including Google, Yahoo, Amazon, Del.icio.us, Flickr, and many more. This library was created as part of my masters thesis at Georgia Tech. It is written in Java and packaged for the <a href="http://www.processing.org">Processing</a> environment.<span id="more-307"></span></p>

]]></content:encoded>
			<wfw:commentRss>http://www.jeffcrouse.info/projects/switchboard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

