<?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>CODESERV.US</title>
	<atom:link href="http://codeserv.us/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://codeserv.us/blog</link>
	<description>A Higher Education Web Application Developer&#039;s Web Log</description>
	<lastBuildDate>Mon, 20 Apr 2009 17:27:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>AWStats on CentOS</title>
		<link>http://codeserv.us/blog/2009/04/20/awstats-on-centos/</link>
		<comments>http://codeserv.us/blog/2009/04/20/awstats-on-centos/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 17:27:39 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[awstats]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[redhat]]></category>
		<category><![CDATA[rpm]]></category>
		<category><![CDATA[rpmforge]]></category>
		<category><![CDATA[workaround]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=139</guid>
		<description><![CDATA[I spent some time this morning installing the awstats rpm on a CentOS 5.2 server and ran into a little issue with the provided apache configuration that took me some time to resolve.  Once installed and configured, viewing the directory url resulted in the error

attempt to invoke directory as script: /var/www/awstats/

I&#8217;m not going to [...]]]></description>
			<content:encoded><![CDATA[<p>I spent some time this morning installing the awstats rpm on a CentOS 5.2 server and ran into a little issue with the provided apache configuration that took me some time to resolve.  Once installed and configured, viewing the directory url resulted in the error<br />
<code><br />
attempt to invoke directory as script: /var/www/awstats/<br />
</code><br />
I&#8217;m not going to repeat the installation and configuration process here since there is plenty of information out there.  Instead, I&#8217;ll point out two links that were most helpful (especially the latter which includes a workaround for the issue above): </p>
<p>First look <a href="http://geekzine.org/2009/01/26/how-to-add-rpmforge-repository-to-centos-52/">here</a> on how to add the RPMForge repository.</p>
<p>Next go <a href="http://www.yetanotherguide.com/programming/awstats-howto">here</a> to learn how to install and configure awstats with the workaround.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2009/04/20/awstats-on-centos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>University Web Hosting?</title>
		<link>http://codeserv.us/blog/2009/04/02/university-web-hosting/</link>
		<comments>http://codeserv.us/blog/2009/04/02/university-web-hosting/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 15:00:36 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Business Logic]]></category>
		<category><![CDATA[Ed Tech]]></category>
		<category><![CDATA[departments]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[frustration]]></category>
		<category><![CDATA[learning management system]]></category>
		<category><![CDATA[limitations]]></category>
		<category><![CDATA[resources]]></category>
		<category><![CDATA[schools]]></category>
		<category><![CDATA[web hosting]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=133</guid>
		<description><![CDATA[My department has spent a lot of time over the last couple months looking at the web hosting services that we provide and trying to determine what they should look like.  Never mind the fact that the core group of us feel we should be focusing on tools in support of teaching and learning&#8230;apparently [...]]]></description>
			<content:encoded><![CDATA[<p>My department has spent a lot of time over the last couple months looking at the web hosting services that we provide and trying to determine what they <strong>should</strong> look like.  Never mind the fact that the core group of us feel we should be focusing on tools in support of teaching and learning&#8230;apparently just providing and supporting Blackboard is enough in that arena.  It is our job, now, to recommend and ultimately, I assume, provide a solution (think set of services/applications) to meet an ill-defined set of web content needs across the University.  So, I&#8217;ve spent the majority of my time recently toying with applications like Drupal and Wordpress as we collectively try to decide what combination we&#8217;re willing to support, <strong>why</strong> and how we plan on doing so.</p>
<p>I&#8217;m becoming increasingly frustrated with the amount of time I&#8217;m spending administering systems and applications and discussing how to meet such a broad set of needs with a limited (read manageable) set of systems.  I haven&#8217;t been doing any development, and it appears that time left for development will become less and less as I spend more time dealing with the above.</p>
<p>It occurs to me that web hosting providers offer, more or less, everything our stakeholders may need&#8230;beyond what we&#8217;ll ever be able to provide and manage.  Why, then, am I doing backflips to support a similar, albeit lacking, environment?  Wouldn&#8217;t our time be better spent working on support of the configuration, integration and extension of some common set of these solutions, and let our clients choose the solution that best meets their web hosting needs?  We, then, can focus on institutional services such as learning management systems, financials, event calendars, student portal, etc.</p>
<p><strong>Update</strong>: I&#8217;ve been discussing this with my colleagues and keep flip-flopping on the issue.  We trade some control with local hosting for what I believe may be ease of use and administration with external hosting.  Locally we have ultimate choice in architecture and range of applications, but are limited in what we can do by staffing.</p>
<p>The clearest path (right now, anyway) is to focus on the departments and schools most in need of web hosting support and try to meet their needs with a limited set of locally supported solutions.  Beyond that, clients will need to consider securing their own resources and solutions and, possibly, looking into external web hosting providers.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2009/04/02/university-web-hosting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blackboard Learning Environment Connector for Sakai</title>
		<link>http://codeserv.us/blog/2009/02/02/blackboard-learning-environment-connector-for-sakai/</link>
		<comments>http://codeserv.us/blog/2009/02/02/blackboard-learning-environment-connector-for-sakai/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 19:32:01 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Ed Tech]]></category>
		<category><![CDATA[blackboard]]></category>
		<category><![CDATA[connector]]></category>
		<category><![CDATA[contrib]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[learning]]></category>
		<category><![CDATA[learning environment connector]]></category>
		<category><![CDATA[lec]]></category>
		<category><![CDATA[oscelot]]></category>
		<category><![CDATA[project ng]]></category>
		<category><![CDATA[sakai]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=123</guid>
		<description><![CDATA[With last week&#8217;s release of Blackboard Learn Release 9, the first release in the new Project NG series, people can begin to explore my implementation of the Learning Environment Connector API to integrate Sakai 2.5.3+ with Blackboard.
The integration consists of two parts, a Building Block portion contributed to the OSCELOT community found here
http://projects.oscelot.org/gf/project/bb-sakai-lec/ under the [...]]]></description>
			<content:encoded><![CDATA[<p>With last week&#8217;s release of <a href="http://www.blackboard.com/release9/" target="_blank">Blackboard Learn Release 9</a>, the first release in the new <a href="http://www.blackboard.com/sites/projectng/">Project NG</a> series, people can begin to explore my implementation of the Learning Environment Connector API to integrate <a href="http://sakaiproject.org/" target="_blank">Sakai</a> 2.5.3+ with Blackboard.</p>
<p>The integration consists of two parts, a Building Block portion contributed to the OSCELOT community found here<br />
<a href="http://projects.oscelot.org/gf/project/bb-sakai-lec/" target="_blank">http://projects.oscelot.org/gf/project/bb-sakai-lec/</a> under the Apache License, Version 2.0,<br />
and a Sakai project contributed to the Sakai community here<br />
<a href="http://confluence.sakaiproject.org/confluence/display/BBLEC" target="_blank">http://confluence.sakaiproject.org/confluence/display/BBLEC</a> under the Educational Community License, Version 2.0.  Combined, the two enhancements enable the integration of Sakai user, course and enrollment data into Blackboard and allows the users to access their Sakai course data from within the Blackboard user interface.</p>
<p>While the initial release of the connector implementation should still be considered beta, we&#8217;ve successfully tested and demonstrated the implementation and plan to begin further testing by the end of February.  Hopefully we&#8217;ll have the integration running in production locally for the start of the next Fall semester.</p>
<p>For further details, including screenshots, please visit either of the links above.  I&#8217;m looking forward to hearing your feedback! </p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2009/02/02/blackboard-learning-environment-connector-for-sakai/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cell Phone Backup with BitPim</title>
		<link>http://codeserv.us/blog/2009/01/16/cell-phone-backup-with-bitpim/</link>
		<comments>http://codeserv.us/blog/2009/01/16/cell-phone-backup-with-bitpim/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 20:37:12 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[bitpim]]></category>
		<category><![CDATA[bluetooth]]></category>
		<category><![CDATA[cell]]></category>
		<category><![CDATA[cell phone]]></category>
		<category><![CDATA[intrepid]]></category>
		<category><![CDATA[phone]]></category>
		<category><![CDATA[rfcomm]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=100</guid>
		<description><![CDATA[Ed Garay recently tweeted about a friend&#8217;s cell phone loss and wondered how often people backup their cell phone data.  Immediately I thought &#8220;not enough&#8221; as I tried to remember back to the last time I made a backup of my own cell phone data.  It turns out the last time I did [...]]]></description>
			<content:encoded><![CDATA[<p>Ed Garay recently <a href="http://twitter.com/garay/status/1124561869">tweeted</a> about a friend&#8217;s cell phone loss and wondered how often people backup their cell phone data.  Immediately I thought &#8220;not enough&#8221; as I tried to remember back to the last time I made a backup of my own cell phone data.  It turns out the last time I did so was back when I got the new phone several months ago.  At the time I had used <a href="http://www.bitpim.org/">BitPim</a> to transfer my contacts from my old phone to my new phone and everything worked well.  My phone data had certainly changed since then, so, thanks to Ed&#8217;s reminder, I decided to immediately backup my data.  This post details the experience backing up my LG VX8350 using BitPim on Ubuntu 8.10.</p>
<p>The first step was to install BitPim.  Fortunately, a package is available for Intrepid and can be installed from a terminal as easy as<br />
<code><br />
$ sudo apt-get install bitpim<br />
</code></p>
<p>In order to connect with the phone, I used the &#8220;Bluetooth Device Wizard&#8221; (found in the &#8220;Bluetooth Preferences&#8221; dialog) to pair my computer with my phone.  This required that I set discovery mode to &#8220;On&#8221; in my phone so that I could select it from the list of devices found by the wizard.  With the phone&#8217;s discovery mode still set to &#8220;On&#8221;, I probed the service settings using &#8217;sdptool&#8217; from a terminal as follows<br />
<code><br />
$ sdptool browse [bdaddr]<br />
</code><br />
substituting my phone&#8217;s hardware address for &#8220;[bdaddr]&#8221; above.</p>
<p>Next I attached the phone to a comm port using the following command<br />
<code><br />
$ sudo rfcomm bind /dev/rfcomm0 [bdaddr] [channel]<br />
</code><br />
where &#8220;[bdaddr]&#8221; is the same as my phone address as described above, and &#8220;[channel]&#8221; is the channel number used by the &#8220;BT DIAG&#8221; service as displayed in the output of the &#8217;sdptool&#8217; query.</p>
<p>The next step was to start up bitpim and find my phone.  Using the &#8220;Find Phone&#8221; feature never seemed to work for me, so I had to manually setup the phone in the &#8220;Settings&#8221; dialog.  I selected my phone type from the drop-down (in this case &#8220;LG-VX8350&#8243;) and used the &#8220;Browse&#8221; dialog to select the &#8220;/dev/rfcomm0&#8243; port that I bound the phone to above.</p>
<p>Since I set my phone to always prompt when it receives a pairing request, I had to accept another pairing request from bitpim.  Once accepted, I was able to send/retrieve data from my computer to my phone.  I made sure to copy all of my important data, just in case I lose my phone as Ed warned in his tweet.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2009/01/16/cell-phone-backup-with-bitpim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Firefox Add-ons</title>
		<link>http://codeserv.us/blog/2009/01/03/my-firefox-add-ons/</link>
		<comments>http://codeserv.us/blog/2009/01/03/my-firefox-add-ons/#comments</comments>
		<pubDate>Sat, 03 Jan 2009 21:41:59 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Web 2.0 and Beyond]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=110</guid>
		<description><![CDATA[I thought I&#8217;d post a list of the Firefox add-ons I&#8217;m currently using and some reasoning why.  If you have any suggestions of similar alternatives that you prefer, please share them!
The list:

del.icio.us &#8211; Provides basic integration with del.icio.us so I can update my tags easily from within the browser (no need to navigate to [...]]]></description>
			<content:encoded><![CDATA[<p>I thought I&#8217;d post a list of the <a href="http://www.mozilla.com/en-US/firefox/" title="Firefox web browser" target="_blank">Firefox</a> add-ons I&#8217;m currently using and some reasoning why.  If you have any suggestions of similar alternatives that you prefer, please share them!</p>
<p>The list:</p>
<ul>
<li><a href="http://delicious.com/" title="Delicious Bookmarks" target="_blank">del.icio.us</a> &#8211; Provides basic integration with del.icio.us so I can update my tags easily from within the browser (no need to navigate to del.icio.us to manage these).</li>
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/1806" title="DOM Inspector" target="_blank">DOM Inspector</a> &#8211; Inspect the DOM of HTML, XUL, and XML pages, including the mail chrome.  I use this primarily for tweaking/developing javascript.</li>
<li><a href="http://sogame.awardspace.com/" title="Dummy Lipsum" target="_blank">Dummy Lipsum</a> &#8211; Use to generate dummy text.  This is great when you need to test/view pages as they would appear with realistic content.</li>
<li><a href="http://www.foxmarks.com/" title="Foxmarks Bookmark Synchronizer" target="_blank">Foxmarks Bookmark Synchronizer</a> &#8211; Foxmarks is a free add-on for your Firefox browser that syncs and backs up your bookmarks and passwords across multiple computers and more.  Since I have a few computers that I work with, this service makes it easy to keep my bookmarks synchronized.</li>
<li><a href="http://livehttpheaders.mozdev.org/" title="mozdev.org - livehttpheaders" target="_blank">LiveHTTPHeaders</a> &#8211; Great for viewing HTTP request/response headers.  This is a handy utility when doing web development.</li>
<li><a href="http://noscript.net/" title="NoScript = JavaScript/Java/Flash blocker for a safer Firefox experience!">NoScript</a> &#8211; Preemptively blocks script execution until you approve, creating a whitelist of trusted web sites from which script execution is allowed.  This makes for a safer browsing experience by blocking unknown third party and cross site scripting.</li>
<li><a href="http://www.chrisfinke.com/addons/opml-support/" title="OPML Support" target="_blank">OPML Support</a> &#8211; Adds OPML support for importing/exporting links in the OPML format using the Firefox bookmark manager.  I used this a couple times when importing my live bookmarks into Wordpress.</li>
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/7263" title="Sage Too">Sage Too</a> &#8211;  I think this is a great feed reader for viewing my live bookmarks.</li>
<li><a href="http://sioc-project.org/firefox" title="Semantic Radar for Firefox" target="_blank">Semantic Radar</a> &#8211; Exposes Semantic Web metadata published on web pages, providing a convenient means for viewing and sharing discovery of the data with the community.  I&#8217;m using this to get a better understanding how Semantic Web metadata is being published and used.</li>
<li><a href="http://twitterfox.net/" title="TwitterFox" target="_blank">TwitterFox</a> &#8211; This extension adds a tiny icon on the status bar which notifies you when your friends update their tweets. Also it has a small text input field to update your tweets.  Similar to the del.icio.us integration described above, this allows me to keep up with twitter from within my browser without having to navigate directly there.</li>
<li><a href="http://chrispederick.com/work/user-agent-switcher/" title="User Agent Switcher" target="_blank">User Agent Switcher</a> &#8211; The User Agent Switcher extension adds a menu and a toolbar button to switch the user agent of the browser.  This is useful to testing (and in some cases circumventing) browser-specific functionality on various sites.</li>
<li><a href="http://chrispederick.com/work/web-developer/" title="Web Developer">Web Developer</a> &#8211; The Web Developer extension adds a menu and a toolbar to the browser with various web developer tools.  I find I use these tools extensively when I have to do UI tweaks&#8230;definitely a must have.</li>
</ul>
<p>Thanks to all of the developers of these add-ons for their generous contributions!  They&#8217;ve helped to increase my productivity.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2009/01/03/my-firefox-add-ons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aquarium Update</title>
		<link>http://codeserv.us/blog/2008/11/06/aquarium-update-7/</link>
		<comments>http://codeserv.us/blog/2008/11/06/aquarium-update-7/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 20:39:05 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Planted Aquaria]]></category>
		<category><![CDATA[aquarium]]></category>
		<category><![CDATA[planted]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=85</guid>
		<description><![CDATA[Haven&#8217;t updated in awhile.  As you can see there has been some significant growth and aquascaping changes since the last update.  I removed the Telanthera rosefolia since it never seemed to adapt well to the environment, slowly dying off.  The Aponogeton was moved to the 30 gallon bottom tank.  Also removed [...]]]></description>
			<content:encoded><![CDATA[<p>Haven&#8217;t updated in awhile.  As you can see there has been some significant growth and aquascaping changes since the last update.  I removed the Telanthera rosefolia since it never seemed to adapt well to the environment, slowly dying off.  The Aponogeton was moved to the 30 gallon bottom tank.  Also removed was the Amazon sword since it grew extremely large and was casting a shadow over most of the tank, resulting in the Glosso and Baby Tears growing upward.  You can see the Red Rubin has grown quite large.  I removed the Cabomba since it was growing too tall and stringy in favor of the bushier red myrio.  Although I liked the Madagascar Lace plant, I removed it as well.  My goal is to keep the bushier, leafier plants that fill up more of the tank than those plants with large, broad leaves that tend to overcast the shorter carpet plants.  You can see that the Glosso and Baby Tears have really started to fill in the foreground.</p>
<p>Since the last update, what appears to be a Cryptocoryne wendtii began to grow out of the substrate on the right.  I&#8217;m not sure where it came from (I didn&#8217;t plant it), so I&#8217;m assuming it came from a bulb that had been added to the substrate sometime ago.  It&#8217;s a nice surprise addition.  </p>
<p><a href="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top_left.jpg"><img src="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top_left-150x150.jpg" alt="Top tank left 11/6/2008" title="Top tank left 11/6/2008" width="150" height="150" class="size-thumbnail wp-image-87" /></a><a href="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top.jpg"><img src="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top-150x150.jpg" alt="Top tank 11/6/2008" title="Top tank 11/6/2008" width="150" height="150" class="size-thumbnail wp-image-87" /></a><a href="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top_right.jpg"><img src="http://codeserv.us/blog/wp-content/uploads/2009/01/110608_top_right-150x150.jpg" alt="Top tank right 11/6/2008" title="Top tank right 11/6/2008" width="150" height="150" class="size-thumbnail wp-image-87" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2008/11/06/aquarium-update-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blackboard/Sakai Learning Environment Connector</title>
		<link>http://codeserv.us/blog/2008/08/23/blackboardsakai-learning-environment-connector/</link>
		<comments>http://codeserv.us/blog/2008/08/23/blackboardsakai-learning-environment-connector/#comments</comments>
		<pubDate>Sat, 23 Aug 2008 18:51:07 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Ed Tech]]></category>
		<category><![CDATA[blackboard]]></category>
		<category><![CDATA[cle]]></category>
		<category><![CDATA[learning environment connector]]></category>
		<category><![CDATA[learning management system]]></category>
		<category><![CDATA[lec]]></category>
		<category><![CDATA[project ng]]></category>
		<category><![CDATA[sakai]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=59</guid>
		<description><![CDATA[I haven&#8217;t posted an update in awhile since I&#8217;ve been &#8220;heads down&#8221; working on the integration between the Sakai CLE and Blackboard learning environments.  It&#8217;s a lot to do in a short amount of time, but things are going well&#8230;I have good help.  More updates/details regarding the project to follow once the connector [...]]]></description>
			<content:encoded><![CDATA[<p>I haven&#8217;t posted an update in awhile since I&#8217;ve been &#8220;heads down&#8221; working on the integration between the Sakai CLE and Blackboard learning environments.  It&#8217;s a lot to do in a short amount of time, but things are going well&#8230;I have good help.  More updates/details regarding the project to follow once the connector is released alongside Blackboard 9, the first release of the new <a href="http://blackboard.com/projectng/">Project NG series</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2008/08/23/blackboardsakai-learning-environment-connector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VPN Gnome Panel Applet</title>
		<link>http://codeserv.us/blog/2008/05/15/vpn-gnome-panel-applet/</link>
		<comments>http://codeserv.us/blog/2008/05/15/vpn-gnome-panel-applet/#comments</comments>
		<pubDate>Thu, 15 May 2008 19:20:52 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Ed Tech]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[applet]]></category>
		<category><![CDATA[gnome]]></category>
		<category><![CDATA[gnomeapplet]]></category>
		<category><![CDATA[ipsec]]></category>
		<category><![CDATA[l2tp]]></category>
		<category><![CDATA[panel]]></category>
		<category><![CDATA[pygtk]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[subprocess]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=57</guid>
		<description><![CDATA[As part of the effort to support linux users connecting to our IPSEC/L2TP based VPN, I developed my first ever gnome panel applet written in Python (another first for me).  I have a functional bash script that can be used to connect to/disconnect from the VPN, but I wanted an easier way for users [...]]]></description>
			<content:encoded><![CDATA[<p>As part of the effort to support linux users connecting to our IPSEC/L2TP based VPN, I developed my first ever gnome panel applet written in Python (another first for me).  I have a functional bash script that can be used to connect to/disconnect from the VPN, but I wanted an easier way for users to interact with the script.  As a result, I developed the applet to display connection status, prompt for connection credentials and to manage the connection process so users don&#8217;t have to open a terminal and work at the command line.</p>
<p>The vpn shell script indicates status through a <code>/var/lock/subsys/VPN</code> file.  The applet below constantly polls status by checking for the existence of this file (see the <code>status_timeout</code> method).  Once the user has clicked on the applet icon, and entered the appropriate credentials, if necessary, the vpn shell script is invoked accordingly using the <code>Popen</code> object from the <code>subprocess</code> module.</p>
<p>This is (roughly) the python script implementing the vpn gnome panel applet:</p>
<pre><code>
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')

import gtk
import gnomeapplet
import sys
import gobject
import subprocess
import os
import time
import logging

class VPN_Applet(gnomeapplet.Applet):

    applet = None
    image_file = "/usr/local/share/vpn/applet/images/vpn.png"
    image_file_hover = "/usr/local/share/vpn/applet/images/vpn_hover.png"
    proc_file = "/var/lock/subsys/VPN"
    username = ""
    passwd = ""
    title = "VPN Applet"
    cancel = False
    logging.basicConfig(level=logging.DEBUG)

    def __init__(self, applet, iid):
        logging.debug("__init__")

        self.applet = applet
        size = self.applet.get_size() - 2
        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.image_file, size, size)
        image = gtk.Image()
        image.set_from_pixbuf(pixbuf)
        tooltips = gtk.Tooltips()
        tooltips.set_tip(image, "Click to connect to VPN\nStatus: Disconnected")
        # Status update timeout (check every 3 seconds)
        gobject.timeout_add(3000, self.status_timeout, image, tooltips)
        self.applet.add(image)
        self.applet.connect("button-press-event", self.button_press)
        self.applet.connect("change-size", self.change_size, image)
        self.applet.connect("change-background", self.change_background)
        self.applet.connect("enter-notify-event", self.enter_notify, image)
        self.applet.connect("leave-notify-event", self.leave_notify, image)
        self.applet.show_all()

    def check_connected(self):
        if (os.path.exists(self.proc_file)):
            return True
        else:
            return False

    def status_timeout(self, image, tooltips):
        logging.debug("status_timeout")
        if (self.check_connected()):
            txt = "disconnect from"
            status = "Connected"
        else:
            txt = "connect to"
            status = "Disconnected"
        tooltips.set_tip(image, "Click to " + txt + " VPN\nStatus: " + status)
        return True

    def do_image(self, image_file, image):
        logging.debug("do_image")

        size = self.applet.get_size() - 2
        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(image_file, size, size)
        image.set_from_pixbuf(pixbuf)        

    def change_size(self, applet, new_size, image):
        logging.debug("change_size")

        self.do_image(self.image_file, image)

    def change_background(self, applet, type, color, pixmap):
        logging.debug("change_background")

        applet.set_style(None)
        applet.modify_style(gtk.RcStyle())
        if (type == gnomeapplet.COLOR_BACKGROUND):
            applet.modify_bg(gtk.STATE_NORMAL, color)
        elif (type == gnomeapplet.PIXMAP_BACKGROUND):
            applet.get_style().bg_pixmap[gtk.STATE_NORMAL] = pixmap

    def enter_notify(self, applet, event, image):
        logging.debug("enter_notify")

        self.do_image(self.image_file_hover, image)

    def leave_notify(self, applet, event, image):
        logging.debug("leave_notify")

        self.do_image(self.image_file, image)

    def button_press(self, button, event):
        logging.debug("button_press")

        if (event.button == 1):
            logging.debug("create dialog")
            self.setup_dialog()
            if (not(self.cancel)):
                if (not(self.check_connected())):
                    # Prompt for username/password
                    # Continue prompting until they are non-empty or user cancels
                    while ((self.username == "" or self.passwd == "") and not(self.cancel)):
                        self.username_prompt()
                    # If the user doesn't want to cancel, complete the connection
                    if (not(self.cancel)):
                        logging.debug("gksudo vpn start")
                        args = "-n '" + self.username + "' -p '" + self.passwd + "'"
                        proc = subprocess.Popen("gksudo -D '" + self.title + "' \"vpn " + args + " start\"",
                                                stdout=subprocess.PIPE,
                                                stderr=subprocess.STDOUT,
                                                shell=True)
                        self.show_progress_bar(proc)
                    # Clear username/password here
                    self.username=""
                    self.passwd=""
                else:
                    logging.debug("gksudo vpn stop")
                    proc = subprocess.Popen("gksudo -D \"" + self.title + "\" \"vpn stop\"",
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.STDOUT,
                                            shell=True)
                    self.show_progress_bar(proc)

    def setup_dialog(self):
        logging.debug("setup_dialog")

        vpn_dialog = gtk.Dialog(title=self.title,
                                flags=(gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR),
                                buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                         gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        # Test here for vpn connection status and prompt accordingly
        if (self.check_connected()):
            txt = "disconnect from"
        else:
            txt = "connect to"
        vpn_dialog.connect("response", self.dialog_response)
        dialog_label = gtk.Label("Would you like to " + txt + " the Virtual Private Network?")
        dialog_label.set_line_wrap(True)
        vpn_dialog.vbox.pack_start(dialog_label, padding=10)
        vpn_dialog.show_all()
        vpn_dialog.run()

    def dialog_response(self, dialog, response_id):
        logging.debug("dialog_response")

        dialog.destroy()
        if (response_id == gtk.RESPONSE_ACCEPT):
            self.cancel = False
        else:
            self.cancel = True

    def show_progress_bar(self, proc):
        logging.debug("show_progress_bar")

        if (self.check_connected()):
            txt = "Disconnecting from "
        else:
            txt = "Connecting to "
        progress_dialog = gtk.Dialog(title=self.title,
                                     flags=(gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR))
        progress_dialog.set_deletable(False)
        label = gtk.Label(txt + "VPN")
        progress_dialog.vbox.pack_start(label, padding=10)
        progress_bar = gtk.ProgressBar()
        progress_bar.set_pulse_step(0.1)
        progress_dialog.vbox.pack_start(progress_bar, padding=10)
        gobject.timeout_add(250, self.progress_bar_timeout, progress_dialog,
                            proc, progress_bar, label)
        progress_dialog.show_all()
        progress_dialog.run()

    def progress_bar_timeout(self, progress_dialog, proc, progress_bar, label):
        logging.debug("progress_bar_timeout")

        progress_bar.pulse()
        if (proc.poll() != None):
            if (self.check_connected()):
                txt = "Connected to "
            else:
                txt = "Disconnected from "
            label.set_text(txt + "VPN.  Click the 'OK' button below to continue.")
            label.set_line_wrap(True)
            progress_dialog.vbox.remove(progress_bar)
            scrolled_window = gtk.ScrolledWindow()
            text_view = gtk.TextView()
            text_view.set_editable(False)
            text_view.set_cursor_visible(False)
            text_view.set_size_request(400, 200)
            buffer = text_view.get_buffer()
            buffer.set_text(proc.stdout.read())
            scrolled_window.add(text_view)
            progress_dialog.vbox.pack_start(scrolled_window)
            progress_dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
            progress_dialog.connect("response", self.dialog_response)
            progress_dialog.show_all()
            return False
        else:
            return True

    def username_changed(self, username):
        logging.debug("username_changed")
        self.username = username.get_text()

    def passwd_changed(self, passwd):
        logging.debug("passwd_changed")
        self.passwd = passwd.get_text()

    def username_prompt_activate(self, entry, dialog):
        logging.debug("username_prompt_activate")
        dialog.response(gtk.RESPONSE_ACCEPT)

    def username_prompt(self):
        logging.debug("username_prompt")

        username_prompt = gtk.Dialog(title=self.title,
                                  flags=(gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR),
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                          gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        username = gtk.Entry(32)
        username.connect("changed", self.username_changed)
        username.connect("activate", self.username_prompt_activate, username_prompt)
        passwd = gtk.Entry(32)
        passwd.set_visibility(False)
        passwd.connect("changed", self.passwd_changed)
        passwd.connect("activate", self.username_prompt_activate, username_prompt)
        prompt = gtk.Label("Please enter your username and password:")
        prompt.set_line_wrap(True)
        table = gtk.Table(3, 2)
        table.attach(prompt, 0, 2, 0, 1, xpadding=5, ypadding=5)
        username_label = gtk.Label("Username (required):")
        table.attach(username_label, 0, 1, 1, 2, xpadding=5, ypadding=5)
        table.attach(username, 1, 2, 1, 2, xpadding=5, ypadding=5)
        passwd_label = gtk.Label("Password (required):")
        table.attach(passwd_label, 0, 1, 2, 3, xpadding=5, ypadding=5)
        table.attach(passwd, 1, 2, 2, 3, xpadding=5, ypadding=5)
        username_prompt.vbox.pack_start(table)
        username_prompt.connect("response", self.dialog_response)
        username_prompt.set_deletable(False)
        username_prompt.show_all()
        username_prompt.run()

gobject.type_register(VPN_Applet)

def vpn_factory(applet, iid):
    VPN_Applet(applet, iid)
    return gtk.TRUE

# run it in a gtk window
if len(sys.argv) > 1 and sys.argv[1] == "run-in-window":
    main_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    main_window.set_title("VPN Applet")
    main_window.connect("destroy", gtk.mainquit)
    main_window.set_default_size(36, 36)
    app = gnomeapplet.Applet()
    vpn_factory(app, None)
    app.reparent(main_window)
    main_window.show_all()
    gtk.main()
    sys.exit()

if __name__ == '__main__':
    gnomeapplet.bonobo_factory("OAFIID:GNOME_VPN_Applet_Factory",
                               VPN_Applet.__gtype__,
                               "VPN Applet", "0.5", vpn_factory)
</code></pre>
<p>While there is plenty of Python and PyGTK documentation and examples, there is very little documentation on developing gnome applets using Python.  Hopefully the code above will be helpful, in addition to the following links:</p>
<p><a href="http://library.gnome.org/devel/panel-applet/stable/PanelApplet.html" target="_blank" title="GNOME Documentation Library - PanelApplet">GNOME Documentation Library &#8211; PanelApplet</a><br />
<a href="http://www.pygtk.org/docs/pygtk/" target="_blank" title="PyGTK 2.0 Reference Manual">PyGTK 2.0 Reference Manual</a><br />
<a href="http://www.pygtk.org/pygtk2tutorial/index.html" target="_blank" title="PyGTK 2.0 Tutorial">PyGTK 2.0 Tutorial</a><br />
<a href="http://pygtk.org/articles/applets_arturogf/index.html" target="_blank" title="Gnome applets with Python">Gnome applets with Python</a><br />
<a href="http://www.python.org/doc/tut/" target="_blank" title="Python Tutorial">Python Tutorial</a><br />
<a href="http://docs.python.org/lib/module-subprocess.html" target="_blank" title="subprocess - Subprocess Management">subprocess &#8211; Subprocess Management</a></p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2008/05/15/vpn-gnome-panel-applet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu IPSEC/L2TP VPN Client</title>
		<link>http://codeserv.us/blog/2008/05/15/ubuntu-ipsecl2tp-vpn-client/</link>
		<comments>http://codeserv.us/blog/2008/05/15/ubuntu-ipsecl2tp-vpn-client/#comments</comments>
		<pubDate>Thu, 15 May 2008 18:22:55 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Ed Tech]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[gibbon]]></category>
		<category><![CDATA[gutsy]]></category>
		<category><![CDATA[hardy]]></category>
		<category><![CDATA[heron]]></category>
		<category><![CDATA[ipsec]]></category>
		<category><![CDATA[l2tp]]></category>
		<category><![CDATA[openswan]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=56</guid>
		<description><![CDATA[I&#8217;ve recently been tasked on implementing a linux vpn client for our IPSEC/L2TP based vpn.  This task would have been extremely difficult if not for the efforts of Jacco de Leeuw (for his &#8220;Using Linux as an L2TP/IPsec VPN client&#8221; documentation) and Scott Myron et al. from Indiana University (&#8220;Linux L2TP over IPsec VPN [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been tasked on implementing a linux vpn client for our IPSEC/L2TP based vpn.  This task would have been extremely difficult if not for the efforts of Jacco de Leeuw (for his <a href="http://www.jacco2.dds.nl/networking/linux-l2tp.html" target="_blank" title="Using Linux as an L2TP/IPsec VPN client">&#8220;Using Linux as an L2TP/IPsec VPN client&#8221;</a> documentation) and Scott Myron et al. from Indiana University (<a href="https://iuware.iu.edu/title.aspx?id=763" target="_blank" title="Linux L2TP over IPsec VPN Script for IU">&#8220;Linux L2TP over IPsec VPN Script for IU&#8221;</a>).</p>
<p>I&#8217;m still waiting on a public revision control system in order to share our current implementation.  In the meantime, I just wanted to share a couple issues I faced with the default Ubuntu (7.10/8.04) Openswan package (2.4.6):</p>
<p><strong>Bad route fix</strong></p>
<p><strong>Update &#8211; This is not necessary.  See the comment added by Alucard below regarding &#8220;leftnexthop&#8221;.</strong></p>
<p>After bringing up the ipsec connection<br />
<code><br />
~# ipsec setup start<br />
~# ipsec auto --up VPN<br />
</code><br />
I still cannot reach the vpn server (there is no route).  After further investigation the route added by this version of openswan is incorrect.  So I get something like the following<br />
<code><br />
~# ip route show<br />
...<br />
xxx.xxx.xxx.xxx dev eth0  scope link<br />
...<br />
default via yyy.yyy.yyy.yyy dev eth0<br />
...<br />
~# ping xxx.xxx.xxx.xxx<br />
PING xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) 56(84) bytes of data.<br />
From zzz.zzz.zzz.zzz icmp_seq=1 Destination Host Unreachable<br />
From zzz.zzz.zzz.zzz icmp_seq=2 Destination Host Unreachable<br />
From zzz.zzz.zzz.zzz icmp_seq=3 Destination Host Unreachable<br />
...<br />
</code><br />
where xxx.xxx.xxx.xxx is the ip of the vpn server, yyy.yyy.yyy.yyy is the gateway ip and zzz.zzz.zzz.zzz is the local ip.<br />
To fix this, I remove the bad route and add a new route through the gateway as follows:<br />
<code><br />
~# ip route del xxx.xxx.xxx.xxx<br />
~# route add -host xxx.xxx.xxx.xxx gw yyy.yyy.yyy.yyy<br />
</code><br />
The result is<br />
<code><br />
~# ip route show<br />
...<br />
xxx.xxx.xxx.xxx via yyy.yyy.yyy.yyy dev eth0<br />
...<br />
default via yyy.yyy.yyy.yyy dev eth0<br />
...<br />
~# ping xxx.xxx.xxx.xxx<br />
PING xxx.xxx.xxx.xxx (xxx.xxx.xxx.xxx) 56(84) bytes of data.<br />
64 bytes from xxx.xxx.xxx.xxx: icmp_seq=1 ttl=126 time=9.46 ms<br />
64 bytes from xxx.xxx.xxx.xxx: icmp_seq=2 ttl=126 time=20.3 ms<br />
...<br />
</code></p>
<p><strong>NAT Traversal</strong></p>
<p>The 2.4.6 Openswan version provided in Ubuntu (7.10/8.04) does not support NAT traversal.  For more information, read Jacco&#8217;s <a href="http://www.jacco2.dds.nl/networking/openswan-l2tp.html#NAT" target="_blank" title="NAT Traversal">NAT Traversal</a> documentation.</p>
<p>Here are (roughly) the steps I used to build/install a patched version of Openswan 2.4.12 with NAT-T support:</p>
<p>1 &#8211; Download the openswan source:</p>
<p><code>~$ wget http://openswan.org/download/openswan-2.4.12.tar.gz</code></p>
<p>2 &#8211; Unpack the source:</p>
<p><code>~$ tar xzvf openswan-2.4.12.tar.gz</code></p>
<p>3 &#8211; Move into source directory:</p>
<p><code>~$ cd openswan-2.4.12/</code></p>
<p>4 &#8211; Get the patch:</p>
<p><code>~$ wget http://www.jacco2.dds.nl/networking/patches/openswan-allow_MS_bad_proposal.patch</code></p>
<p>5 &#8211; Patch the source:</p>
<p><code>~$ patch -p0 &lt; openswan-allow_MS_bad_proposal.patch</code></p>
<p>6 &#8211; Install build dependencies:</p>
<p><code>~$ sudo apt-get -y install build-essential man2html libgmp3c2 libgmp3-dev</code></p>
<p>7 &#8211; Make the programs and install (as root)</p>
<p><code>~$ make programs<br />
~$ sudo make install</code></p>
<p>Using the documentation referenced above, along with these workarounds, you should be able to connect an Ubuntu 7.10/8.04 client to an IPSEC/L2TP VPN.  Hope that helps!</p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2008/05/15/ubuntu-ipsecl2tp-vpn-client/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Aquarium Update</title>
		<link>http://codeserv.us/blog/2008/04/12/aquarium-update-6/</link>
		<comments>http://codeserv.us/blog/2008/04/12/aquarium-update-6/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 19:18:20 +0000</pubDate>
		<dc:creator>jmpease</dc:creator>
				<category><![CDATA[Planted Aquaria]]></category>
		<category><![CDATA[aquarium]]></category>
		<category><![CDATA[planted]]></category>

		<guid isPermaLink="false">http://codeserv.us/blog/?p=79</guid>
		<description><![CDATA[A couple days after the last update I did the aquascaping I described.  I&#8217;m making another change today, but wanted to post some pictures of the current setup beforehand.  As you can see, the current arrangement is off balance with a significant overgrowth on the left side compared to the right.  My [...]]]></description>
			<content:encoded><![CDATA[<p>A couple days after the last update I did the aquascaping I described.  I&#8217;m making another change today, but wanted to post some pictures of the current setup beforehand.  As you can see, the current arrangement is off balance with a significant overgrowth on the left side compared to the right.  My plan is to try and balance this out some by spreading out the Telanthera rosefolia and moving all of the Ludwigia repens in a single grouping a little off-right of center.  I also trimmed down the Cabomba quite a bit.  The Glosso has started to take hold to carpet the right front of the tank near the Red melon sword.  Once the new arrangement has settled in I&#8217;ll post some more pics.<br />
<a href='http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top.jpg'><img src="http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top-150x150.jpg" alt="Top tank 4/12/08" title="Top tank 4/12/08" width="150" height="150" class="alignnone size-thumbnail wp-image-50" /></a><a href='http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top_left.jpg'><img src="http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top_left-150x150.jpg" alt="Top tank left 4/12/08" title="Top tank left 4/12/08" width="150" height="150" class="alignnone size-thumbnail wp-image-51" /></a><a href='http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top_right.jpg'><img src="http://codeserv.us/blog/wp-content/uploads/2008/04/41208_top_right-150x150.jpg" alt="Top tank right 4/12/08" title="Top tank right 4/12/08" width="150" height="150" class="alignnone size-thumbnail wp-image-52" /></a><a href='http://codeserv.us/blog/wp-content/uploads/2008/04/41208_bottom.jpg'><img src="http://codeserv.us/blog/wp-content/uploads/2008/04/41208_bottom-150x150.jpg" alt="Bottom tank 4/12/08" title="Bottom tank 4/12/08" width="150" height="150" class="alignnone size-thumbnail wp-image-49" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://codeserv.us/blog/2008/04/12/aquarium-update-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
