<?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>scot hacker's scripts and utils</title>
	<atom:link href="http://birdhouse.org/software/feed/" rel="self" type="application/rss+xml" />
	<link>http://birdhouse.org/software</link>
	<description>Scot Hacker's Misc Scripts and Utils</description>
	<lastBuildDate>Sun, 08 Nov 2009 20:10:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>django-treedata: A web app for municipal tree tracking</title>
		<link>http://birdhouse.org/software/2009/11/django-treedata/</link>
		<comments>http://birdhouse.org/software/2009/11/django-treedata/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 19:22:04 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=98</guid>
		<description><![CDATA[Recently I was invited to participate in the California Data Camp and DataSF App Contest hosted by California Watch and spot.us. The unconference would feature lots of discussion about making use of publicly available data sets to improve quality of life. The App Contest challenged developers to choose one of the many data sets available [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I was invited to participate in the<a href="http://datacamp.eventbrite.com/"> California Data Camp and DataSF App Contest</a> hosted by <a href="http://www.centerforinvestigativereporting.org/projects/californiawatch/">California Watch</a> and <a href="http://spot.us/">spot.us</a>. The unconference would feature lots of discussion about making use of publicly available data sets to improve quality of life. The App Contest challenged developers to choose one of the many data sets available at <a href="http://datasf.org/">DataSF.org</a> and build something cool with it in a relatively short period of time. Here&#8217;s a <a href="http://datasf.org/showcase/">showcase</a> of existing apps built on those data sets.</p>
<p>The <a href="http://multimedia.journalism.berkeley.edu/">Knight Digital Media Center</a> (where I work) invited me to take part, and I chose a database of <a href="http://datasf.org/story.php?title=street-tree-list">64,000 San Francisco trees and plants</a>. The goal of the project was to:</p>
<ul>
<li>Make it easy for citizens to explore and discover the huge number of plant species and individual trees maintained by the city</li>
<li>Make it easy for citizens to &#8220;flag&#8221; a tree as needing maintenance, water, food, etc.</li>
<li>Make it easy for citizens to request a tree at a particular location</li>
<li>Provide data visualization tools to let citizens explore and understand the plant variety visually</li>
<li>Make it easy to see what a given species will look like in 5,10,15,20 years when requesting a tree</li>
<li>Ideally, a future version of the app would include ecology data on all species, listing the water consumption and carbon offset of each</li>
</ul>
<p>I decided to build the project on Django, of course. Put a total of around 15 hours into the project, about half of which was spent massaging and cleaning the provided data, which had multiple pieces of information stuffed into single fields, non-standard date formats, and was completely non-relational. Cities implementing django-treedata &#8220;fresh,&#8221; without having to be compatible with an existing data entry system, won&#8217;t have to worry about data conversion/format issues.</p>
<p>Once the data was clean, the rest was pretty straightforward Django stuff. The one non-standard aspect is the external &#8220;lastcount&#8221; script, which counts the number of instances of each species and stores the result on a field in the Species model. Doing this in real time for such a large number of trees turned out to be very computationally expensive, so the script needs to be run from a crontab periodically.</p>
<p>Because dev time was so limited, all of it went into data cleaning and building out the models and views. We&#8217;ve put ZERO work into design considerations, so please don&#8217;t crucify us for that. The CSS is built on top of the excellent <a href="http://960.gs/">960 Grid</a> framework, so layout will be easy. Some of the data visualization is done via the excellent <a href="http://code.google.com/apis/chart/">Google Charts API</a>.</p>
<p>Much to our surprise, the django-treedata app won the competition!</p>
<p>Please note that the project has only been run in a development environment and has never been publicly deployed &#8211; the project as it stands should be considred a starting point for cities to built on. The <a href="http://code.google.com/p/django-treedata/source/browse/trunk/README.TXT">readme</a> explains more. The project is completely open source and is released under the very liberal <a href="http://www.opensource.org/licenses/bsd-license.php">BSD</a> license &#8211; do with it as you will.</p>
<p>Thanks also to J-School webmaster for Chuck Harris for his contributions to the project</p>
<p><span id="more-98"></span></p>
<h3>Screenshots</h3>

<a href='http://birdhouse.org/software/2009/11/django-treedata/caretakers/' title='caretakers'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/caretakers-150x150.png" class="attachment-thumbnail" alt="" title="caretakers" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/details/' title='details'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/details-150x150.png" class="attachment-thumbnail" alt="" title="details" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/paginated-table/' title='paginated-table'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/paginated-table-150x150.png" class="attachment-thumbnail" alt="" title="paginated-table" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/popular-species/' title='popular-species'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/popular-species-150x150.png" class="attachment-thumbnail" alt="" title="popular-species" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/rx/' title='rx'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/rx-150x150.png" class="attachment-thumbnail" alt="" title="rx" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/treeadmin/' title='treeadmin'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/treeadmin-150x150.png" class="attachment-thumbnail" alt="" title="treeadmin" /></a>
<a href='http://birdhouse.org/software/2009/11/django-treedata/treewordle/' title='treewordle'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2009/11/treewordle-150x150.png" class="attachment-thumbnail" alt="" title="treewordle" /></a>

<h3>Download</h3>
<p>django-treedata is available on <a href="http://code.google.com/p/django-treedata">Google Code</a>, via svn.</p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2009/11/django-treedata/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Populate Mailman Lists from Django Projects</title>
		<link>http://birdhouse.org/software/2009/09/listgen/</link>
		<comments>http://birdhouse.org/software/2009/09/listgen/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 08:19:51 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=67</guid>
		<description><![CDATA[Django projects can end up with complex sets of Users, Groups, and multiple profile types representing different types of people. For example a school site might have Students, Parents, Teachers, Staff, and Alumni. The mailing lists for that school will live completely outside of the Django project, but there&#8217;s a good chance you&#8217;d like to [...]]]></description>
			<content:encoded><![CDATA[<p>Django projects can end up with complex sets of Users, Groups, and multiple profile types representing different types of people. For example a school site might have Students, Parents, Teachers, Staff, and Alumni. The mailing lists for that school will live completely outside of the Django project, but there&#8217;s a good chance you&#8217;d like to be able to populate list membership from your membership database rather than maintaining lists by hand. And you&#8217;d like to be able to use any combination of criteria to populate your lists (Group membership,  profile types, join date, privileges, etc.)</p>
<p>Since Mailman is installed on so many web hosts by default, there&#8217;s a good chance you&#8217;re using it, and have lots of overlapping and non-overlapping groups subscribed to various lists. I recently went through the process of integrating a bunch of  Mailman lists with the membership representing a school intranet built in Django and thought I&#8217;d document it for anyone going through a similar process.</p>
<p>Once everything is set up, you&#8217;ll never need to use the Mailman interface to manage lists again &#8211; everything will be automated and self-maintaining.<br />
<span id="more-67"></span><strong> </strong></p>
<p><strong>Manual Overrides / Prerequisites<br />
</strong></p>
<ul>
<li>The simple queries are easy. But in the real world you end up in situations where, say, the Maintenance person needs to be able to write to the Teachers list but not receive mail from it. Or maybe teachers need to be able to write to the Board, but not be privy to the Board&#8217;s list traffic.</li>
<li>Some people may fit a particular group query but not want to receive mail from lists for those groups (because maybe their spouse handles that stuff).</li>
<li>Some people don&#8217;t match a particular query group but need to be made into regular list members anyway.  For example you might want to have the principal be on all mailing lists, even though he&#8217;s not a parent of any child enrolled in a class.</li>
</ul>
<p>The key to making some of this happen is a feature of Mailman called &#8220;nomail&#8221; mode, which allows certain subscriber addresses to send to a list but not receive mail from it. This recipe interfaces with Mailman from the command line, using the <code>add_members</code> command. But here&#8217;s the rub &#8211; the official Mailman distribution&#8217;s <code>add_members</code> command is missing the option to add a person to a list in nomail mode (grrrr). However, the version of <code>add_members</code> that comes with OS X Server <em>does</em> include this option. I have no idea why Mailman hasn&#8217;t seen fit to integrate Apple&#8217;s changes into the official distro, since it&#8217;s insanely useful.  But since <code>add_members</code> is just a Python script, you can replace the version of <code>add_members</code> that comes with the official distro with Apple&#8217;s version and it&#8217;ll work fine on any server platform.</p>
<p>Because the Mailman command-line scripts must be run as root, you must be the administrator of the server this recipe runs on.</p>
<p>To handle all the exceptions and special cases your organization probably has, you&#8217;re going to need two tweaks to your apps/models. First, on your Profile model(s), create a new field for people who don&#8217;t want to be on the lists at all:</p>
<pre>no_lists = models.BooleanField(default=False,
     help_text="When checked, this parent will NOT be subscribed
     to the mailing lists they normally would be.")</pre>
<p>You can now check this box in any user profile for people who show up in group queries but don&#8217;t wish to receive mail from any of the organization&#8217;s lists.</p>
<p>You&#8217;re also going to need an additional model to store the exceptions &#8211; additional people to add to lists, either in yesmail or nomail mode:</p>
<pre>class ListExtra(models.Model):
    """
    Extra email addresses to be added to mailing lists.
    """
    list = models.SlugField()
    addresses = models.TextField(blank=True,
         help_text='Add addresses here, one per line.')

    def __unicode__(self):
        return u'%s' % (self.list)</pre>
<p><img src="http://birdhouse.org/software/wp-content/uploads/2009/09/extras.jpg" alt="extras" title="extras"  class="alignright size-full wp-image-86" / > Once the model has been created and you&#8217;ve run syncdb, create a record for each list you want to track, e.g. &#8220;teachers&#8221; for the list &#8220;teachers@ourschool.org&#8221; .  Do not enter real teachers here &#8211; they&#8217;ll come from ORM queries on the regular User table.  Instead, this is where you&#8217;ll add <em>non</em>-teachers  who should be regular members of the teachers@ mailing list anyway. Add such people&#8217;s addresses to the field one-per-line.</p>
<p>If you have the need to let certain people write to the teachers list but NOT receive mail from it, create an additional record called &#8220;teachers-nomail&#8221;.</p>
<p><strong>How It Works</strong></p>
<p>This recipe is really two scripts &#8211; one in Python and the other bash &#8211; that I end up running from a single shell alias as needed. The two scripts I use can be downloaded at the end of this post and are well commented.</p>
<p>The Python script (listgen.py) interacts with the Django ORM, extracting list memberships out into text files. The bash script (listgen.sh) iterates through that set of text files and, for each, quickly unsubscribes the entire membership and then re-subscribes them from the text files generated by the python script. On my server, the whole process unsubs and resubs 14 lists covering 125 people in  5 seconds flat, so there&#8217;s no real danger of anyone freaking out because they were temporarily unsubscribed.  And  listgen.sh makes sure that subs and unsubs occur without notifying users of list membership changes, so they don&#8217;t get scary messages.</p>
<p><code>listgen.py</code> sets up the Django environment for the given project, defines a function for processing query results into text files, then iterates through a list of mailing list names (without the domain name). For each, it runs a Django ORM query. Then it excludes from that queryset anyone who has opted out of all lists.</p>
<p>Next, it looks for a corresponding ListExtras record and extracts the &#8220;extra&#8221; addresses it contains. Finally, it looks for a corresponding &#8220;nomail&#8221; ListExtra record (e.g. <code>teachers-nomail</code>). It then removes any duplicate members and passes the final query data to the file processing function and writes text files to a directory on the server.</p>
<p><code>listgen.sh</code> iterates through an array of all mailing lists and, for each, unsbuscribes all members (without sending unsub messages). It then locates the text file corresponding to the current list and subscribes all regular members in yesmail mode. Finally, it looks for a corresponding <code>listname-nomail.txt</code> file and subscribes the addresses it contains in nomail mode.</p>
<p><strong>Deployment</strong></p>
<p>The scripts I&#8217;m using are linked below.</p>
<p>First, check to see whether the version of <code>add_members</code> on your server supports the <code>-e</code> flag (for nomail mode). If it does not, rename the <code>add_members</code> script on your server to <code>-old</code> and put the replacement <code>add_members</code> script in its place. Run &#8220;<code>locate add_members</code>&#8221; if not sure where to put it. If it complains when you try to run it, make sure its first line matches the python path shown on other scripts in the same dir.</p>
<p>Put <code>listgen.py</code> in a &#8220;scripts&#8221; directory in your Django project.</p>
<p>Put <code>listgen.sh</code> somewhere where root can get to it.</p>
<p>You&#8217;ll need to modify the list of mailing lists in each script, as well as the most important bit &#8211; the Django ORM queries in <code>listgen.py</code>. This will probably take quite a bit of testing and experimentation &#8211; make sure you&#8217;re working with test data until everything is humming &#8211; users will get righteously pissed if you break their lists.</p>
<p>You&#8217;ll also need to make sure the two scripts agree on the filesystem location for the output  (for the generated files that <code>listgen.py</code> creates and <code>listgen.sh</code> reads).  By default this will be a dir at <code>myproject/scripts/listgen</code>. You&#8217;ll need to edit the python path vars at the top of listgen.py.</p>
<p>During testing you&#8217;ll probably want to just run <code>listgen.py</code> and not <code>listgen.sh</code> &#8212; then you can study the text file output without actually altering the lists. When you&#8217;re confident <code>listgen.py</code> is doing the right thing, add the <code>listgen.sh</code> step.</p>
<p>Once it&#8217;s all working, create an alias for root that runs both scripts, something like:</p>
<pre>
alias schoollist='python /path/to/scripts/listgen.py; \
/bin/sh /root/scripts/for_customers/school/listgen.sh'</pre>
<p>You <em>could</em> set this up to run as a cron job, but there&#8217;s a good reason not to: Mailman keeps track of bad addresses with its bounce processing feature, which counts the number of times a message has bounced from a bad address and then unsubscribes that user and alerts the list administrator. If you run listgen.sh every night, every member will always be &#8220;new&#8221; as far as Mailman is concerned and bounce thresholds will never be reached.  You&#8217;ll never be informed when/if you have bad addresses in your Django system. To address this, I wrote a Django signal handler that sends me email whenever a User object has been updated. I then run the <code>schoollist</code> command whenever I know something has changed (after the system stabilizes this shouldn&#8217;t happen very often).</p>
<p><strong>The Scripts</strong></p>
<p><a href="http://birdhouse.org/software/wp-content/uploads/2009/09/add_members.txt">add_members</a> (copied from OS X Server&#8217;s Mailman distro, but works on any platform)<strong></strong></p>
<p><a href="http://birdhouse.org/software/wp-content/uploads/2009/09/listgen.py.txt">listgen.py</a> (put in a scripts dir inside your Django project)</p>
<p><a href="http://birdhouse.org/software/wp-content/uploads/2009/09/listgen.sh.txt">listgen.sh</a> (put somewhere root can access easily)<strong><br />
</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2009/09/listgen/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Django-Todo</title>
		<link>http://birdhouse.org/software/2008/09/django-todo/</link>
		<comments>http://birdhouse.org/software/2008/09/django-todo/#comments</comments>
		<pubDate>Sun, 14 Sep 2008 08:11:13 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=39</guid>
		<description><![CDATA[django-todo is a multi-user, multi-group task management and assignment system for the Django web application framework.
Designed as a &#8220;pluggable&#8221; application ready to import into existing Django projects.
You must already have a  login/authorization system installed and working in your project before installing django-todo.
This version supports drag and drop task prioritization, email notification to task assignees, and [...]]]></description>
			<content:encoded><![CDATA[<p>django-todo is a multi-user, multi-group task management and assignment system for the <a href="http://www.djangoproject.com/">Django</a> web application framework.</p>
<p>Designed as a &#8220;pluggable&#8221; application ready to import into existing Django projects.</p>
<p>You must already have a  login/authorization system installed and working in your project before installing django-todo.</p>
<p>This version supports drag and drop task prioritization, email notification to task assignees, and lots more. Feedback welcome.</p>
<p>The code is <a href="http://code.google.com/p/django-todo/">hosted on Google Code</a> and can be checked out via svn.</p>
<p><span id="more-39"></span></p>
<p><strong>Screenshots</strong></p>

<a href='http://birdhouse.org/software/2008/09/django-todo/django-todo-edittask/' title='django-todo-edittask'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/django-todo-edittask-150x150.png" class="attachment-thumbnail" alt="" title="django-todo-edittask" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/django-todo-listlists/' title='django-todo-listlists'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/django-todo-listlists-150x150.png" class="attachment-thumbnail" alt="" title="django-todo-listlists" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/django-todo-login/' title='django-todo-login'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/django-todo-login-150x150.png" class="attachment-thumbnail" alt="" title="django-todo-login" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/django-todo-mytasks/' title='django-todo-mytasks'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/django-todo-mytasks-150x150.png" class="attachment-thumbnail" alt="" title="django-todo-mytasks" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/incomplete/' title='incomplete'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/incomplete-150x150.png" class="attachment-thumbnail" alt="" title="incomplete" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/datepicker/' title='datepicker'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/datepicker-150x150.png" class="attachment-thumbnail" alt="" title="datepicker" /></a>
<a href='http://birdhouse.org/software/2008/09/django-todo/main/' title='main'><img width="150" height="150" src="http://birdhouse.org/software/wp-content/uploads/2008/09/main-150x150.png" class="attachment-thumbnail" alt="" title="main" /></a>

]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2008/09/django-todo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Cleancats</title>
		<link>http://birdhouse.org/software/2008/04/cleancats/</link>
		<comments>http://birdhouse.org/software/2008/04/cleancats/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 08:12:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=34</guid>
		<description><![CDATA[This is a very crude mass category deletion script for WordPress. I recently inherited a WordPress site with more than 6000 categories. After deleting a ton of old posts, we were left with more than 4000 unused categories, and I needed a way to remove them quickly. Couldn&#8217;t find a plugin up to the task, [...]]]></description>
			<content:encoded><![CDATA[<p>This is a very crude mass category deletion script for WordPress. I recently inherited a WordPress site with more than 6000 categories. After deleting a ton of old posts, we were left with more than 4000 unused categories, and I needed a way to remove them quickly. Couldn&#8217;t find a plugin up to the task, so wrote this. Very crude, but effective. Not a plugin, but a small WP companion script. See instructions in the comment at top of script.</p>
<p><strong><a href='http://birdhouse.org/software/wp-content/uploads/2008/04/cleancatsphp.txt'>Download Cleancats</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2008/04/cleancats/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WP-Create</title>
		<link>http://birdhouse.org/software/2008/04/wp-create/</link>
		<comments>http://birdhouse.org/software/2008/04/wp-create/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 21:26:19 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=28</guid>
		<description><![CDATA[Super fast way to install WordPress for clients, via subversion. Yes, users can often self-install via Fantastico or similar programs, but what guarantee do you have that they&#8217;ll upgrade as soon as new releases become available? Letting users run old versions of web software is a great way to get hacked. Take control of users&#8217; [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Super</strong> fast way to install WordPress for clients, via subversion. Yes, users can often self-install via Fantastico or similar programs, but what guarantee do you have that they&#8217;ll upgrade as soon as new releases become available? Letting users run old versions of web software is a great way to get hacked. Take control of users&#8217; installations by checking them out via svn (with this script) and managing them with <a href="http://birdhouse.org/software/2007/07/wp-mass-upgrade/">wp-mass-upgrade.</a></p>
<p>This script performs the following tasks:</p>
<ul>
<li>Gather installation info</li>
<li>Create install dir and check out a copy of WordPress</li>
<li>Create database, db user, set db privs via external .sql file</li>
<li>Create WP config file</li>
<li>Create upload dir and set filesystem permissions</li>
<li>Generate array line for wp-mass-upgrade.sh</li>
</ul>
<p>Final setup is done via browser.</p>
<p><strong><a href='http://birdhouse.org/software/wp-content/uploads/2008/04/wp-create.txt'>Download wp-create 1.0</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2008/04/wp-create/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>WP Workflow Docs</title>
		<link>http://birdhouse.org/software/2008/01/wp-workflow-docs/</link>
		<comments>http://birdhouse.org/software/2008/01/wp-workflow-docs/#comments</comments>
		<pubDate>Wed, 23 Jan 2008 05:30:33 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=25</guid>
		<description><![CDATA[A dirt-simple WordPress plugin that lets you provide workflow docs to your authors and editors from within the WP admin interface.

Instructions: Unpack this folder to your plugins directory and activate it. Click on the Dashboard and you&#8217;ll see a new tab called &#8220;NGNO Docs.&#8221; Within that, you&#8217;ll find documentation I wrote for my authors  [...]]]></description>
			<content:encoded><![CDATA[<p>A dirt-simple WordPress plugin that lets you provide workflow docs to your authors and editors from within the WP admin interface.</p>
<p><span id="more-25"></span></p>
<p><strong>Instructions:</strong> Unpack this folder to your plugins directory and activate it. Click on the Dashboard and you&#8217;ll see a new tab called &#8220;NGNO Docs.&#8221; Within that, you&#8217;ll find documentation I wrote for <em>my</em> authors  for  <em>one particular site</em>. In order for this to be useful, you&#8217;ll need to replace  the HTML it contains with your  own by editing the file <code>docs.html</code>.</p>
<p>You&#8217;ll want to remove the image files I&#8217;ve included and, if desired, add your own. Note: I found it tricky to get image paths working &#8211; you&#8217;ll need to embed images like this:</p>
<p><code>img src="../wp-content/plugins/wp-workflow-docs/more-result.gif"</code></p>
<p>You can change the plugin name and tab name by editing the plugin file itself &#8211; it&#8217;s a tiny plugin and it will be pretty obvious where to do this in the file. Then de-activate and re-activate it to see the new tab name.</p>
<p><strong><a href="http://birdhouse.org/software/wp-content/uploads/2008/04/wp-workflow-docs.zip">Download wp-workflow-docs</a></strong></p>
<p>Contributions / improvements welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2008/01/wp-workflow-docs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FuturePost</title>
		<link>http://birdhouse.org/software/2007/12/futurepost/</link>
		<comments>http://birdhouse.org/software/2007/12/futurepost/#comments</comments>
		<pubDate>Tue, 18 Dec 2007 05:27:40 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=24</guid>
		<description><![CDATA[A WordPress plugin aimed primarily at events sites, where you want to be able to timestamp posts in the future but have them appear immediately (by default, WordPress will not display a future timestamped post until its go-live date rolls around). This plugin sets the post_status field to &#8220;publish&#8221; rather than &#8220;future&#8221; when publishing a [...]]]></description>
			<content:encoded><![CDATA[<p>A WordPress plugin aimed primarily at events sites, where you want to be able to timestamp posts in the future but have them appear immediately (by default, WordPress will not display a future timestamped post until its go-live date rolls around). This plugin sets the post_status field to &#8220;publish&#8221; rather than &#8220;future&#8221; when publishing a post, even if its timestamp is in the future. Written by Ryan Boren &#8211; I&#8217;m just hosting it.</p>
<h4><span id="more-24"></span></h4>
<p><strong>Instructions:</strong> Place future-post.php in your plugins directory and activate it. Write a post with a future timestamp and hit publish. Notice that it goes live on your site immediately.</p>
<p><strong>Note:</strong> This seemingly simple plugin was graciously written by the magical <a title="boren.nu" href="http://boren.nu/">Ryan Boren</a> when I was facing a deadline. He doesn&#8217;t have time to maintain/host it, so I agreed to.</p>
<p><strong><a href="http://wordpress.org/extend/plugins/the-future-is-now/">Download version 1.0</a></strong></p>
<p>Contributions / improvements welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2007/12/futurepost/feed/</wfw:commentRss>
		<slash:comments>69</slash:comments>
		</item>
		<item>
		<title>gpx2ipod</title>
		<link>http://birdhouse.org/software/2007/11/gpx2ipod/</link>
		<comments>http://birdhouse.org/software/2007/11/gpx2ipod/#comments</comments>
		<pubDate>Sun, 11 Nov 2007 08:38:57 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[Geo]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=19</guid>
		<description><![CDATA[Designed for Mac users with an iPod but no PDA who want to do paperless geocaching complete with descriptions, log entries and hints. Uses the iPod&#8217;s &#8220;Notes&#8221; feature to display complete cache description pages. gpx2ipod is built on top of gpsbabel.
Note: I&#8217;m not likely to continue development of gpx2ipod, for two reasons: 1) MacCaching finally [...]]]></description>
			<content:encoded><![CDATA[<p>Designed for Mac users with an iPod but no PDA who want to do paperless geocaching complete with descriptions, log entries and hints. Uses the iPod&#8217;s &#8220;Notes&#8221; feature to display complete cache description pages. gpx2ipod is built on top of <a title="GPSBabel: convert, upload, download data from GPS and Map programs" href="http://www.gpsbabel.org/">gpsbabel</a>.</p>
<p><strong>Note:</strong> I&#8217;m not likely to continue development of gpx2ipod, for two reasons: 1) <a href="http://www.maccaching.com/">MacCaching</a> finally grew the ability to store cache metadata in the iPod&#8217;s &#8220;Notes&#8221; feature rather than in the address book (which was the whole impetus behind my developing gpx2ipod to begin with), and 2) I switched to a <a href="https://buy.garmin.com/shop/shop.do?pID=11022">Garmin Colorado</a> a few months ago, which displays description, logs, and hints directly in the GPS. I no longer need to offload that data to the iPod, so my itch has been scratched. Do with this software what you will!</p>
<p><span id="more-19"></span></p>
<h2>Overview</h2>
<p>Mac-based paperless caching for people who own an iPod but not a PDA.<br />
Batch-converts a pile of .gpx files to plain text for use with the iPod&#8217;s &#8220;Notes&#8221; feature.<br />
<em>Super</em>-fast &#8212; cut your geocaching prep time to a few minutes.</p>
<p>gpx2ipod handles both individual and Pocket Query (multiple-cache).gpx files.<br />
Cache files will display alphabetically on the iPod for easy access in the field.</p>
<p>gpx2ipod can inject generated text files directly into your iPod (most users) or into a local &#8220;output&#8221; folder (you might not have an iPod but might still want the text files for other purposes).</p>
<p>gpx2ipod is a Terminal application (shell script), but can be run painlessly with a double-click &#8212; no shell experience required.</p>
<p>gpx2ipod is available either with or without the <a title="GPSBabel: convert, upload, download data from GPS and Map	programs" href="http://www.gpsbabel.org/">gpsbabel</a> command-line binary bundled. gpsbabel is licenced under the GPL, and thus so is gpx2ipod. See LICENSE for info.</p>
<h2>Who this is for</h2>
<ul>
<li>You&#8217;re a Mac user who has an iPod but not a PDA.</li>
<li>You want to do paperless geocaching.</li>
<li>You want complete descriptions, log entries and hints while out on the trail.</li>
<li>Your iPod has this great &#8220;Notes&#8221; feature, but you haven&#8217;t found any OS X software to get GPX files into a format you can read in the iPod&#8217;s Notes reader. <a title="Welcome « MacCaching Free GeoCache Manager for Mac OS X" href="http://www.maccaching.com/">MacCaching</a> is wonderful, but it outputs to the iPod&#8217;s &#8220;Contacts&#8221; system, which means no logs and no choice of whether to encrypt hints. It also intermingles hundreds of geocache data files with your existing pile of Contacts &#8211; very messy. GPSBabel+ has a similar &#8220;Export to v-card feature&#8221; with similar problems. The iPod&#8217;s &#8220;Notes&#8221; feature seems a much better choice to me.</li>
</ul>
<h2>Requirements</h2>
<p>Mac OS X. This script will not run on Windows or Linux (with modifications, gpx2ipod could be made to run under <a title="Cygwin Information and Installation" href="http://www.cygwin.com/">Cygwin</a> or Linux).</p>
<p>A copy of the free and open source <a href="http://www.gpsbabel.org/">gpsbabel</a> (<strong>version 1.3.4 or higher</strong>). Thanks to all contributors to gpsbabel for your hard work on this amazing workhorse! Huge thanks also to Robert Lipe, who added gpsbabel&#8217;s ability to split multi-location files into individual files, so gpx2ipod wouldn&#8217;t be stuck with the 99-split limitation in the Unix &#8220;<code>cut</code>&#8221; command.</p>
<p>An iPod with Storage Mode enabled. Storage Mode lets you use your iPod as a hard drive. If your iPod does not show up as disk volume on the Desktop when plugged in, go to iTunes and select &#8220;Enable disk use,&#8221; then click Apply.</p>
<h2>Installation</h2>
<p>Unzip this folder and drag it into your Applications folder (or wherever you like). Then drag the gpx2ipod <strong>folder</strong> icon from your Applications folder into your Dock for quick access.</p>
<ul>
<li><strong>If you downloaded gpx2ipod <em>with</em> gpsbabel:</strong>You&#8217;re good to go! Skip to Usage.</li>
<li><strong>If you downloaded gpx2ipod <em>without</em> gpsbabel:</strong>gpx2ipod requires the <a title="GPSBabel: convert, upload, download data from GPS and Map programs" href="http://www.gpsbabel.org/">gpsbabel</a> command line application, (<strong>version 1.3.4 or higher</strong>). When you install GPSBabel (probably into your Applications folder), you&#8217;ll see two files: GPSBabel+, which is a graphical application, and gpsbabel itself, which is a command-line application. There are two ways to make gpsbabel available to gpx2ipod:<strong>The easy way</strong>: Select the file &#8220;gpsbabel&#8221; in that folder and copy it (don&#8217;t move it!) to the <code>bin</code> folder inside the gpx2ipod folder.<strong>The hard (but better) way</strong>: If you&#8217;re comfortable at the command line and prefer not to duplicate the binary, you can create a symlink instead, for example:
<p><code>ln -s "/Applications/GPS Babel/gpsbabel" /Users/[yourlogin]/Desktop/gpx2ipod/bin/gpsbabel</code></p>
<p>Modify that command to match your setup. Note: Mac aliases won&#8217;t work &#8211; you&#8217;ll need a proper symlink.</li>
</ul>
<h2>Usage</h2>
<ol>
<li>Download .gpx files from <a title="Geocaching - The Official Global GPS Cache Hunt Site" href="http://www.geocaching.com/">geocaching.com</a> and move or copy them into the &#8220;input&#8221; folder. You can mix and match individual .gpx files and Pocket Query (multi-cache) files in the same input folder. gpx2ipod includes a &#8220;samples&#8221; folder for testing &#8211; copy some or all of these into the &#8220;input&#8221; folder and let &#8216;er rip.</li>
<li>Double-click the <code>gpx2ipod</code> &#8220;squid&#8221; and let it do its thing.</li>
<li style="list-style-type: none; list-style-image: none; list-style-position: outside;">
<ul>
<li>If this is the first time you&#8217;ve run gpx2ipod, you&#8217;ll be asked to set a few preferences, such as whether you want to include log files, whether to encrypt hints, whether to copy the original .gpx files into an &#8220;archive&#8221; folder, and (most importantly) the system path to your iPod (the script will let you choose your iPod from a list). For the yes/no questions, use 0 for &#8220;no&#8221; and 1 for &#8220;yes.&#8221;</li>
<li>If the gpsbabel binary can&#8217;t be found, or is an old version, the script will tell you and then halt.</li>
<li>If the iPod you selected during Setup can&#8217;t be found, you&#8217;ll be given the option to mount it now, or, alternatively, to have generated files sent to an &#8220;output&#8221; folder instead.</li>
</ul>
</li>
<li>When everything&#8217;s in order, gpx2ipod will crunch through all those .gpx files, spit out text files optimally formatted for iPod use, and copy them into the Notes folder on your iPod. On future runs of gpx2ipod, your last-used preferences will be displayed as the script launches. Hit [Return] to accept the settings, or C to change them.</li>
<li>Go geocaching! You&#8217;ll find the cache entries on the iPod in Extras &gt; Notes.</li>
</ol>
<h2>Limitations</h2>
<p>This version does not load .gpx files into your GPSr &#8211; it just generates text files for use on the iPod. A future version may load the same files into the GPSr.</p>
<h2>History</h2>
<p>v1.3 &#8211; 9/15/2007<br />
Now retains character formatting for international character sets. Default is UTF-8, but any character set supported by gpsbabel can be selected in preferences. Tested against Swedish .gpx samples (see GCY7XZ-Swedish_chars.gpx in Samples folder). Many thanks to Bengt Bäverman for excellent contributions on this feature.</p>
<p>v1.2 &#8211; 9/15/2007<br />
Bug fix for other cache name characters that would generate illegal filenames.</p>
<p>v1.1 &#8211; 9/08/2007<br />
No longer generates errors when encountering caches with slashes in their names. Now works properly when installed in a path containing a space (such as &#8220;/Applications/GPS Apps&#8221;).</p>
<p>v1.0 &#8211; 8/03/2007<br />
Renamed project to &#8220;gpx2ipod.&#8221; Now requires gpsbabel 1.3.4 or higher, taking advantage of new gpsbabel &#8220;splitoutput&#8221; feature in order to overcome the <code>cut</code> command&#8217;s 99-split limit (thanks Robert Lipe!). Now double-clickable &#8211; much better user experience. Now copies generated files directly to iPod. Now stores user preferences in a config file. Now optionally copies original .gpx files into an &#8220;archive&#8221; folder for future use.</p>
<p>v0.2 &#8211; 7/17/2007<br />
Now handles both individual .gpx files and Pocket Query (multiple-cache) .gpx files.</p>
<p>v0.1 &#8211; 7/14/2007<br />
Original version</p>
<h2>Download</h2>
<p><strong><a href="http://birdhouse.org/software/wp-content/uploads/2008/04/gpx2ipod_min.dmg">Download without GPSBabel</a></strong></p>
<p><strong><a href="http://birdhouse.org/software/wp-content/uploads/2008/04/gpx2ipod.dmg">Download with GPSBabel</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2007/11/gpx2ipod/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>WP Mass Upgrade</title>
		<link>http://birdhouse.org/software/2007/07/wp-mass-upgrade/</link>
		<comments>http://birdhouse.org/software/2007/07/wp-mass-upgrade/#comments</comments>
		<pubDate>Thu, 12 Jul 2007 05:23:53 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=22</guid>
		<description><![CDATA[Designed for hosts with lots of individual WordPress blogs to manage. If all blogs are managed via subversion, this script can iterate through all of them and upgrade each to the latest version in seconds.
Here at Birdhouse Hosting, we use this system every time WordPress is updated, and are able to bump 100+ WordPress installations [...]]]></description>
			<content:encoded><![CDATA[<p>Designed for hosts with lots of individual WordPress blogs to manage. If all blogs are <a title="Installing/Updating WordPress with Subversion « WordPress Codex" href="http://codex.wordpress.org/Installing/Updating_WordPress_with_Subversion">managed via subversion</a>, this script can iterate through all of them and upgrade each to the latest version in seconds.</p>
<p>Here at <a href="http://hosting.birdhouse.org/">Birdhouse Hosting</a>, we use this system every time WordPress is updated, and are able to bump 100+ WordPress installations to the next version in three minutes flat.</p>
<p>Designed to be used in conjunction with <a href="http://birdhouse.org/software/2008/04/wp-create/">WP-Create</a>, which is the fastest way to set up fresh WP installations via svn.</p>
<p><strong><a href="http://birdhouse.org/software/wp-content/uploads/2008/04/wp-mass-upgrade.txt">Download wp-mass-upgrade</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2007/07/wp-mass-upgrade/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>WP-Digest</title>
		<link>http://birdhouse.org/software/2006/12/wp-digest/</link>
		<comments>http://birdhouse.org/software/2006/12/wp-digest/#comments</comments>
		<pubDate>Sun, 10 Dec 2006 16:04:27 +0000</pubDate>
		<dc:creator>shacker</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://birdhouse.org/software/?p=8</guid>
		<description><![CDATA[Sends periodic email notifications of new WordPress blog entries (in either plain text or HTML mode) to a separate subscribers mailing list. Maintains cache file recording ID of last-sent post. On subsequent runs, sends all posts created since the previous run.
Currently driving weekly email updates from birdhouse.org and other sites.
About
Sends periodic email notifications of new [...]]]></description>
			<content:encoded><![CDATA[<p>Sends periodic email notifications of new WordPress blog entries (in either plain text or HTML mode) to a separate subscribers mailing list. Maintains cache file recording ID of last-sent post. On subsequent runs, sends all posts created since the previous run.</p>
<p>Currently driving weekly <a href="http://birdhouse.org/blog">email updates</a> from birdhouse.org and other sites.</p>
<h3><span id="more-8"></span>About</h3>
<p>Sends periodic email notifications of new WordPress blog entries, either in plain text or as formatted HTML, to a separate subscribers mailing list. Records ID of last-sent post. On subsequent runs, sends all posts created since the previous run. Mail is sent to a single email address, which is most likely a separate subscribers mailing list.</p>
<p>The first time WP-Digest is run, it operates on the last n entries made in your blog. After the first run, it will save the ID of your last blog entry in a cache file. On subsequent runs, it will operate on however many entries have been made since the previous run. You can manually control the value of n by changing $MinPosts in conf.php.</p>
<h3>Requirements</h3>
<p>This script is desgined to be run on Unix/Linux/OS X servers. It may work on Windows servers as well, but has not been tested in that environment. Of course you&#8217;ll need to use some alternative to cron if working under Windows.</p>
<p>This script requires access to the lynx web browser installed on your server. To determine whether you have it, type:</p>
<p><code>which lynx</code></p>
<p>If the system returns &#8220;Command not found&#8221; then you don&#8217;t have it, and should ask your sysadmin to install it. This script is designed to be run at regular intervals via crontab.</p>
<p>See included readme.txt for setup instructions.</p>
<h3>History</h3>
<p>2.0: Now sends your choice of plain text or HTML-formatted (multipart) email.</p>
<p>1.2: Completely new architecture, now based on lynx for improved formatting options and an end to problems with incorrectly formatted characters and error messages in output generated by 3rd party plugins when run via cron.</p>
<p>1.1: Bug fixes</p>
<p>1.0: Started as a port of mtblogmail, but quickly turned into a complete rewrite in order to take advantage of the WordPress APIs.</p>
<h3>Download</h3>
<p><strong><a href="http://birdhouse.org/software/wp-content/uploads/2008/04/wp-digest.tgz">Download wp-digest</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://birdhouse.org/software/2006/12/wp-digest/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
