<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2.1" -->
<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/"
	>

<channel>
	<title>Bad CTK</title>
	<link>http://blog.charcoalphile.com</link>
	<description>On Databases, Recovery, Tech</description>
	<pubDate>Fri, 26 Sep 2008 16:10:31 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2.1</generator>
	<language>en</language>
			<item>
		<title>PostgreSQL: Handling Ratings, Without Aggregates</title>
		<link>http://blog.charcoalphile.com/2008/09/26/postgresql-handling-ratings-without-aggregates/</link>
		<comments>http://blog.charcoalphile.com/2008/09/26/postgresql-handling-ratings-without-aggregates/#comments</comments>
		<pubDate>Fri, 26 Sep 2008 16:10:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PostgreSQL]]></category>

		<category><![CDATA[SQL]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/09/26/postgresql-handling-ratings-without-aggregates/</guid>
		<description><![CDATA[This is something you shouldn&#8217;t have to learn the hard way: How to create a ratings system without using aggregate functions. Specifically, what I&#8217;m talking about by an aggregate, is the AVG() SQL function. The problem with using AVG(), is it reads every row in the table, which works well when you&#8217;re not dealing with [...]]]></description>
			<content:encoded><![CDATA[<p>This is something you shouldn&#8217;t have to learn the hard way: How to create a ratings system without using aggregate functions. Specifically, what I&#8217;m talking about by an aggregate, is the AVG() SQL function. The problem with using AVG(), is it reads every row in the table, which works well when you&#8217;re not dealing with very many rows, but as your data grows, the query speed progressively slows down. This is because aggregate functions essentially perform a sequential scan on the table. The solution for this, is to store the average for each individual item in a table, and use simple math calculations for updates.</p>
<p>Such a table may look something like this:</p>
<pre style="padding: 8px; background: #f1f1f1; border-left: 4px solid #d1d1d1;">
CREATE TABLE item_ratings (
    item_id INTEGER NOT NULL PRIMARY KEY,
    rating DOUBLE PRECISION,
    votes INTEGER NOT NULL DEFAULT 0
);

CREATE INDEX item_ratings_rating_key ON item_ratings (rating);
CREATE INDEX item_ratings_votes_key ON item_ratings (votes);
</pre>
<p>There&#8217;s a number of options for adding the initial entry, that updates will eventually be done on, such as doing it in code or via a trigger/rule. For the sake of simplicity, lets say there&#8217;s already a blank entry for item #1.</p>
<pre style="padding: 8px; background: #f1f1f1; border-left: 4px solid #d1d1d1;">
INSERT INTO item_ratings (item_id, rating, votes) VALUES (1, 0, 0);
</pre>
<p>Now, instead of adding a new entry for each vote cast, you simply update the previous entry. Lets say someone casts a vote, giving it a 4 star rating. That would be handled as such:</p>
<pre style="padding: 8px; background: #f1f1f1; border-left: 4px solid #d1d1d1;">
UPDATE item_ratings SET
    rating = ((rating * votes) + 4) / (votes + 1),
    votes = (votes + 1)
    WHERE item_id = 1;

SELECT * FROM item_ratings WHERE item_id = 1;
 item_id | rating | votes
---------+--------+-------
      1          4        1
</pre>
<p>That&#8217;s pretty much it. Now all ratings are stored per item, instead of generated by an aggregate. This can save major headaches when dealing with large datasets, since AVG() in PostgreSQL tends to be slow when working with such datasets.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/09/26/postgresql-handling-ratings-without-aggregates/feed/</wfw:commentRss>
		</item>
		<item>
		<title>My Qwest Internet Nightmare Part III</title>
		<link>http://blog.charcoalphile.com/2008/08/23/my-qwest-internet-nightmare-part-iii/</link>
		<comments>http://blog.charcoalphile.com/2008/08/23/my-qwest-internet-nightmare-part-iii/#comments</comments>
		<pubDate>Sat, 23 Aug 2008 17:50:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Internet]]></category>

		<category><![CDATA[Qwest]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/08/23/my-qwest-internet-nightmare-part-iii/</guid>
		<description><![CDATA[I’m experiencing a number of different issues. For one, the connection speed is wildly inconsistent. Sometimes I get 5mbps, other times I get under 1mbps. The connection is always dropping, and reconnecting. Sometimes it spends 30+ minutes disconnecting and reconnecting, before it finally gets a stable connection. Large downloads are constantly being interrupted because of [...]]]></description>
			<content:encoded><![CDATA[<p><span style="letter-spacing: 0px">I’m experiencing a number of different issues. For one, the connection speed is wildly inconsistent. Sometimes I get 5mbps, other times I get under 1mbps. The connection is always dropping, and reconnecting. Sometimes it spends 30+ minutes disconnecting and reconnecting, before it finally gets a stable connection. Large downloads are constantly being interrupted because of the connection dropping.</span></p>
<p><span style="letter-spacing: 0px"></span></p>
<p><span style="letter-spacing: 0px">This is crazy. I’m giving them another angry phone call on Monday.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/08/23/my-qwest-internet-nightmare-part-iii/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Aggressive Caching With Memcached</title>
		<link>http://blog.charcoalphile.com/2008/08/17/aggressive-caching-with-memcached/</link>
		<comments>http://blog.charcoalphile.com/2008/08/17/aggressive-caching-with-memcached/#comments</comments>
		<pubDate>Sun, 17 Aug 2008 18:21:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/08/17/aggressive-caching-with-memcached/</guid>
		<description><![CDATA[There&#8217;s many different methods to use caching, with memcached. I call this one the Aggressive approach.
The basic logic is this: if you don&#8217;t even touch the database, you will be able to serve far more requests, than if you did. The biggest downside is, you can&#8217;t really do things too dynamically, and really, this only [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s many different methods to use caching, with memcached. I call this one the Aggressive approach.</p>
<p>The basic logic is this: if you don&#8217;t even touch the database, you will be able to serve far more requests, than if you did. The biggest downside is, you can&#8217;t really do things too dynamically, and really, this only works well for flat pages (ie., it&#8217;s not for anything that displays content, based on the user).</p>
<p>In my case, I added the following code (shown as pseudo code) to the main/controller/dispatch script:</p>
<pre style="padding:8px; background:#f1f1f1; border-left: 3px solid #d1d1d1;">

$memcache = new Memcache;
$memcache->connect(...);
$data = $memcache->get($_SERVER['REQUEST_URI'])

if ($data) {
    echo $data;
    die();
 } 

$db = new PDO(...);
ob_start();
ob_implicit_flush(false);
...
... do whatever ...
...
$data = ob_get_contents();
$memcache->set($_SERVER['REQUEST_URI'], $data, 0, 3600);
ob_end_flush(); 
</pre>
<p>One of the biggest downsides to this approach, is figuring out how to delete cached objects when something’s updated. If you have a single table that holds the pages that you’re caching, however, you can just add a hook that deletes the cached object, by URI, when anything is written that would affect it.</p>
<p>This really doesn’t work well for anything super dynamic, but it’s great for increasing performance in areas that would otherwise waste resources.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/08/17/aggressive-caching-with-memcached/feed/</wfw:commentRss>
		</item>
		<item>
		<title>My Qwest Internet Nightmare Part II</title>
		<link>http://blog.charcoalphile.com/2008/08/13/my-qwest-internet-nightmare-part-ii/</link>
		<comments>http://blog.charcoalphile.com/2008/08/13/my-qwest-internet-nightmare-part-ii/#comments</comments>
		<pubDate>Wed, 13 Aug 2008 21:17:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Internet]]></category>

		<category><![CDATA[Qwest]]></category>

		<category><![CDATA[Rantings]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/08/13/my-qwest-internet-nightmare-part-ii/</guid>
		<description><![CDATA[Qwest finally got my Internet working, *phew*, after an agonizing 13 days. Now a new problem has reared it&#8217;s ugly head: My internet connection is ridiculously slow. I mean seriously slow. My gateway shows the downlink speed at 1100kbps. At my old apartment, it was usually around 6900. What&#8217;s worse: my actual connection speed is slower than [...]]]></description>
			<content:encoded><![CDATA[<p>Qwest finally got my Internet working, *phew*, after an agonizing 13 days. Now a new problem has reared it&#8217;s ugly head: My internet connection is ridiculously slow. I mean seriously slow. My gateway shows the downlink speed at 1100kbps. At my old apartment, it was usually around 6900. What&#8217;s worse: my actual connection speed is slower than what the gateway displays.</p>
<p><a href="http://speedtest.net">SpeedTest.net</a> gives me an average of ~800kbps, just barely faster than my uplink speed! The meter jumped wildly between 1200kbps and 200kbps, during the test. This is absolutely ridiculous. I haven&#8217;t called yet, but I&#8217;m hoping it will end up being a simple fix. This whole experience has left me dismayed and flabbergasted. This is the first time I&#8217;ve ever considered Comcast as a serious alternative.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/08/13/my-qwest-internet-nightmare-part-ii/feed/</wfw:commentRss>
		</item>
		<item>
		<title>My Qwest Internet Nightmare</title>
		<link>http://blog.charcoalphile.com/2008/08/09/my-qwest-internet-nightmare/</link>
		<comments>http://blog.charcoalphile.com/2008/08/09/my-qwest-internet-nightmare/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 21:53:35 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Internet]]></category>

		<category><![CDATA[Qwest]]></category>

		<category><![CDATA[Rantings]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/08/09/my-qwest-internet-nightmare/</guid>
		<description><![CDATA[So, when it came time to move, I called Qwest to have them transfer my services. They were supposed to be setup when I arrived, and guess what&#8230; They weren&#8217;t. Not only that, but I had to wait on the phone for 2 hours, just to schedule them to come by, at their convenience, to [...]]]></description>
			<content:encoded><![CDATA[<p>So, when it came time to move, I called Qwest to have them transfer my services. They were supposed to be setup when I arrived, and guess what&#8230; They weren&#8217;t. Not only that, but I had to wait on the phone for 2 hours, just to schedule them to come by, at their convenience, to fix the problem, while listening to &#8220;Your call is important to us&#8221;&#8230; Yeah right, more like your money is important to us.</p>
<p>Not only that, but it took them a week just to show up. Not only that, when they finally got around to hooking everything up, they routed me to the wrong ISP. And so here I am, waiting 10 days, and counting, for them to fix the problem. The only reason they can get away with this, is because they are a monopoly.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/08/09/my-qwest-internet-nightmare/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Lack Of Solutions To Deter SSH Brute Force Attacks</title>
		<link>http://blog.charcoalphile.com/2008/07/17/lack-of-solutions-to-deter-ssh-brute-force-attacks/</link>
		<comments>http://blog.charcoalphile.com/2008/07/17/lack-of-solutions-to-deter-ssh-brute-force-attacks/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 18:43:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/07/17/lack-of-solutions-to-deter-ssh-brute-force-attacks/</guid>
		<description><![CDATA[I&#8217;ve been really discouraged by the overall lack of decent solutions for minimizing SSH brute force attacks. There&#8217;s the typical and obvious one&#8217;s, that just about every article states, like setting AllowUsers/DenyUsers, and setting PermitRootLogin = no. The problem with those, is while they may strengthen security, they don&#8217;t stop bots from trying to brute [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been really discouraged by the overall lack of decent solutions for minimizing SSH brute force attacks. There&#8217;s the typical and obvious one&#8217;s, that just about every article states, like setting AllowUsers/DenyUsers, and setting PermitRootLogin = no. The problem with those, is while they may strengthen security, they don&#8217;t stop bots from trying to brute force your server, which does nothing from a performance standpoint. Since having multiple bots trying to brute force your server can cause server load to go through the roof, this can be very important.</p>
<p>Disabling passwords, and only accepting key based logins can make you more secure, however, it still doesn&#8217;t deal with performance issues. And also, if you have a drive failure, and loose your SSH key, how do you login? If nobody else can make you a new key pair, and login to copy it over, then you&#8217;re locked out of your own server. Also, how do you login from someone else&#8217;s computer?</p>
<p>You can move SSH to a different port, but then you have to update the config for all your users. This can be a big pain in the ass to handle, but it can solve both the security and performance issues with brute force attacks. Overall it&#8217;s pretty weak, though, since some bots have started probing other ports, like 2222, to see if SSH is running on it. It surely wouldn&#8217;t work for anything big.</p>
<p>Then there&#8217;s log-based learning, like fail2ban. I have a problem with this too, as log injection attacks can be used to trick the learning daemon into causing a denial of service attack. Overall, this is a pretty weak solution too. There&#8217;s already been proof-of-concept log injection attacks for just about every log based learning daemon, and there&#8217;s sure to by more in the future.</p>
<p>And on to iptables based solutions. By filtering at firewall level, you can see clients that are trying to connect to SSH. By far, the biggest weakness of this setup is it can&#8217;t determine if a login was successful or not, it can only see SYN packets. If you have it setup to block clients that try to connect 3 or more times in a minute, then three successful logins would cause a legitimet client to be blocked. While it may sound absurd that a client would login that frequently, it isn&#8217;t when you consider that tab-completion is available in SSH and SCP, and for each tab-completion event, SSH logs in then back out; the limit can easily be exhausted, and cause legit clients to be blocked.</p>
<p>There really needs to be a better solution. It seems like the only real way to solve this, is to build some kind of configurable adaptive firewall into SSH, itself, to detect and deny brute force attacks.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/07/17/lack-of-solutions-to-deter-ssh-brute-force-attacks/feed/</wfw:commentRss>
		</item>
		<item>
		<title>PostgreSQL Quick Tip: Indexing Large Columns</title>
		<link>http://blog.charcoalphile.com/2008/07/14/postgresql-quick-tip-indexing-large-columns/</link>
		<comments>http://blog.charcoalphile.com/2008/07/14/postgresql-quick-tip-indexing-large-columns/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 17:44:26 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PostgreSQL]]></category>

		<category><![CDATA[SQL]]></category>

		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/07/14/postgresql-quick-tip-indexing-large-columns/</guid>
		<description><![CDATA[When working with large columns, you can run into some indexing issues. For instance, there&#8217;s a limit on how many characters a btree index entry can use, which poses problems for indexing text fields, since inserts and updates will fail if they use more characters than the index can use. Also, you can run into [...]]]></description>
			<content:encoded><![CDATA[<p>When working with large columns, you can run into some indexing issues. For instance, there&#8217;s a limit on how many characters a btree index entry can use, which poses problems for indexing text fields, since inserts and updates will fail if they use more characters than the index can use. Also, you can run into performance and disk consumption issues with large columns. The solution for this is to index columns using the hashtext() function. so, ie:</p>
<pre style="padding: 8px; background: #f1f1f1; border-left: 4px solid #c1c1c1;">
CREATE INDEX table1_column1_hash ON table1 hashtext(column1);
</pre>
<p>Then in your queries, do:</p>
<pre style="padding: 8px; background: #f1f1f1; border-left: 4px solid #c1c1c1;">
SELECT * FROM table1 WHERE hashtext(column1) = hashtext('foo');
</pre>
<p>There&#8217;s some issues with this solution, mainly being that you can only have exact matches for the column, so you can&#8217;t do range scans or LIKE queries, however, if you need searching features you should probably be using full text searching, which is available in PostgreSQL 8.2+.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/07/14/postgresql-quick-tip-indexing-large-columns/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Speeding Up PHP Applications</title>
		<link>http://blog.charcoalphile.com/2008/07/04/speeding-up-php-applications/</link>
		<comments>http://blog.charcoalphile.com/2008/07/04/speeding-up-php-applications/#comments</comments>
		<pubDate>Fri, 04 Jul 2008 18:06:41 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/07/04/speeding-up-php-applications/</guid>
		<description><![CDATA[Since everyone else seems to have a list of how to speed up PHP Apps, I thought it was about time I made one. Here&#8217;s some basic rules for speeding up PHP Applications:

Avoid including large files/classes. The more PHP has to process, the slower it is. A lot of frameworks have needlessly large classes. It&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Since everyone else seems to have a list of how to speed up PHP Apps, I thought it was about time I made one. Here&#8217;s some basic rules for speeding up PHP Applications:</p>
<ul>
<li>Avoid including large files/classes. The more PHP has to process, the slower it is. A lot of frameworks have needlessly large classes. It&#8217;s recommended that you split things up into smaller &#8220;modules&#8221; and include them as needed. Also, only include what you need. PHP has to process everything, even the stuff you don&#8217;t use. With some sites, I&#8217;ve seen the number requests per second increase, 4 times, simply by moving away from needlessly large frameworks and unneeded includes.</li>
<li>Use PHP&#8217;s built-in functions whenever you can. PHP has a lot of functions for working with strings, arrays, etc. A lot of times, they can save you headaches, and improve performance over user created functions.</li>
<li>Avoid Regular Expressions. Instead, use functions like str_replace, in place of preg_replace, or strstr, in place of preg_match, when possible.</li>
<li>Be careful of the way you reference objects. PHP is known to have trouble with garbage collection under certain situations, such as when you&#8217;re dealing with classes that are circular-referenced. These types of situations usually go unnoticed, until PHP start exceeding it&#8217;s memory limit.</li>
<li>Avoid functions like file_get_contents(), and file_put_contents(), when working with large files&#8230; Unless you <em>want</em> to run out of memory.</li>
<li>Use memcached, aggressively if possible. Hmm, lets see, 100 requests/second vs 1000 requests/second&#8230; On the same server. It&#8217;s a no brainer.</li>
<li>Don&#8217;t <strong>ever</strong> use persistent connections. They may seem like a good idea, and they may appear to make your app faster in benchmarks, but it will severely cripple your ability to handle high traffic&#8230; Let me explain, persistent connections and connection pooling aren&#8217;t the same. Persistent connections are <strong>per user</strong>, and users will often end up with 2 or 3 persistent connections open for them. Nobody else can use these connections; this leads to your server running out of database connections with a relatively small number of users (think 40-60). If you really need this functionality, use an actual connection pooler.</li>
<li>Avoid making your database grumpy; most bottlenecks are related to the database. This typically means avoiding sequential scans, aggregate functions, etc. With MySQL, avoid complex JOINs, as well as date range scans, and &#8220;WHERE column IN (SELECT &#8230;)&#8221; queries. With PostgreSQL, avoid &#8220;SELECT COUNT(*)&#8221;, and keep the total number of queries to a minimum.</li>
<li>Get more servers. Single servers can only handle so many requests per second. When you get to a point where your server is struggling under the load, and there&#8217;s no clear bottlenecks, the only thing you can do is scale to your needs.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/07/04/speeding-up-php-applications/feed/</wfw:commentRss>
		</item>
		<item>
		<title>PHP PDO and Bytea/Blob Columns</title>
		<link>http://blog.charcoalphile.com/2008/06/27/php-pdo-and-byteablob-columns/</link>
		<comments>http://blog.charcoalphile.com/2008/06/27/php-pdo-and-byteablob-columns/#comments</comments>
		<pubDate>Fri, 27 Jun 2008 18:42:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PostgreSQL]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/06/27/php-pdo-and-byteablob-columns/</guid>
		<description><![CDATA[I&#8217;ve searched high and low, but haven&#8217;t found any solid documentation on how to work with BLOB/BYTEA columns with PDO. Here&#8217;s what I&#8217;ve figured out.
By default, when using the query method, PDO will return a Resource ID for binary objects. The Resource ID must be used together with fread(). So, ie:


$c = $db->query('SELECT blob FROM [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve searched high and low, but haven&#8217;t found any solid documentation on how to work with BLOB/BYTEA columns with PDO. Here&#8217;s what I&#8217;ve figured out.</p>
<p>By default, when using the query method, PDO will return a Resource ID for binary objects. The Resource ID must be used together with fread(). So, ie:</p>
<pre style="border-left: 4px solid #c1c1c1; padding: 8px; background: #f1f1f1 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">

$c = $db->query('SELECT blob FROM table WHERE id = 21');
$res = $c->fetch(PDO::FETCH_ASSOC);
$buf = null;

while (!feof($res['blob'])) {
    $buf .= fread($res['blob'], 2048);
}

fclose($res['blob']);
</pre>
<p>You can also fetch binary objects as a string, by binding the column with PDO::PARAM_STR:</p>
<pre style="border-left: 4px solid #c1c1c1; padding: 8px; background: #f1f1f1 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial">
$buf = null;
$st = $db->query('SELECT blob FROM table WHERE id = 21');
$st->bindColumn('blob', $buf, PDO::PARAM_STR);
$st->fetch();
</pre>
<p>It&#8217;s hard to believe there&#8217;s no documentation on this. I <em>really</em> hope I just missed it; this would be a pretty big thing to have no documentation on.</p>
<p><em>Update</em>:  <a href="http://us3.php.net/manual/en/pdo.lobs.php">The documentation is here</a>, hidden by obscurity. It sounds like it&#8217;s talking about handling external large objects, and not internal blob columns, inside the table.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/06/27/php-pdo-and-byteablob-columns/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Python Daemon Skeleton</title>
		<link>http://blog.charcoalphile.com/2008/06/23/python-daemon-skeleton/</link>
		<comments>http://blog.charcoalphile.com/2008/06/23/python-daemon-skeleton/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 21:55:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.charcoalphile.com/2008/06/23/python-daemon-skeleton/</guid>
		<description><![CDATA[I was bored, and I&#8217;ve been learning Python, so I decided to write a Unix Daemon Skeleton, complete with comments explaining why things are done the way they&#8217;re done. It&#8217;s attached at the bottom of this entry.
I&#8217;ve also been playing around with GUI programming in Python, with wxWidgets, on my MacBook Pro. Hopefully that will [...]]]></description>
			<content:encoded><![CDATA[<p>I was bored, and I&#8217;ve been learning Python, so I decided to write a Unix Daemon Skeleton, complete with comments explaining why things are done the way they&#8217;re done. It&#8217;s attached at the bottom of this entry.</p>
<p>I&#8217;ve also been playing around with GUI programming in Python, with wxWidgets, on my MacBook Pro. Hopefully that will turn up something useful; I&#8217;ve been considering writing a project management tool, to simplify some operations.</p>
<p><a href="http://blog.charcoalphile.com/wp-content/uploads/2008/06/daemonskeleton.py" title="Daemon Skeleton">Python Daemon Skeleton</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.charcoalphile.com/2008/06/23/python-daemon-skeleton/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
