<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2titles.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemtitles.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>TechKnack</title><link>http://techknack.net</link><description>The rantings of a techie</description><language>en</language><generator>http://wordpress.org/?v=2.6.2</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/TechKnack" type="application/rss+xml" /><feedburner:emailServiceId>TechKnack</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/TechKnack" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.addtoany.com/?linkname=TechKnack&amp;linkurl=http%3A%2F%2Ffeeds.feedburner.com%2FTechKnack&amp;type=feed" src="http://www.addtoany.com/addfr-b.gif">Add to Any Feed Reader</feedburner:feedFlare><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>PHP Socket Implementation and Webpage Downloader</title><link>http://feedproxy.google.com/~r/TechKnack/~3/epCtim0OfUg/</link><category>php</category><category>web</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Thu, 18 Jun 2009 21:09:12 PDT</pubDate><guid isPermaLink="false">http://techknack.net/?p=294</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>This post reveals two handy PHP constructs I&#8217;ve been using for a while now: a Socket class and a webpage-downloading function.</p>
<p>The files:</p>
<ul>
<li>Socket.php (<a href="/examples/source_highlighted.php?file=phpwebpage/Socket.php">highlighted</a>; <a href="/examples/source_plaintext.php?file=phpwebpage/Socket.php">plaintext</a>)</li>
<li>webpage.php (<a href="/examples/source_highlighted.php?file=phpwebpage/webpage.php">highlighted</a>; <a href="/examples/source_plaintext.php?file=phpwebpage/webpage.php">plaintext</a>)</li>
</ul>
<p>What good is a full-on Socket class and function, you may ask, when you can simply run file_get_contents with allow_url_fopen turned on?  Well, consider that you want to send specific headers to the server, to POST data for example.  Also, there are other uses for a Socket class than webpage downloading; I use this Socket implementation in a PHP-based IRC bot that I run (by the name of ecode on the Freenode network).  You can use the socket to interact with many different servers.</p>
<h3>Socket</h3>
<p>The Socket class essentially encapsulates PHP&#8217;s socket_* functions, making it easy and straightforward to make a TCP connection with a server.  The socket is given a timeout period in microseconds; while I&#8217;m not 100% sure what this means, I do know that it emulates a sort of &#8220;busy wait&#8221; while waiting for content, allowing applications to do processing while waiting for data to come in through the pipe.</p>
<p>To use the socket, include the Socket.php file and create a variable to hold a new Socket.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">require_once</span><span class="br0">&#40;</span><span class="st0">&quot;Socket.php&quot;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$s</span> = <span class="kw2">new</span> Socket<span class="br0">&#40;</span><span class="nu0">1000</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>The Socket will automatically set up the outgoing TCP socket for usage.  The parameter passed to the new socket (1000 in this case) is the microsecond timeout &#8212; this can be left blank if you wish.</p>
<p>Once created, the socket can connect to any service through the connect() function.  The function takes two arguments: host and port.  Both parameters are optional to allow reuse of the connection; if called without parameters, the Socket will establish a new connection using a host and port from the last connection.  The host is the address you would ping to see if the servers are up &#8212; for example, either google.com or 74.125.67.100, the Socket doesn&#8217;t care which as long as it&#8217;s a server it can connect to.  The port is optional: if you specify a port number, that will be used; if no port number is specified, it attempts to extract a port number from the host (for example, if you used google.com:80); failing that, it will use the last port number specified (default of 80).</p>
<p>Once connected, you can use the send() and get() functions to &#8212; you guessed it &#8212; send() and get() data.  The send function takes a string parameter, the message to be sent, sends the message through socket_write, and returns the value returned by socket_write (the number of bytes successfully sent through the socket).  The get function takes an array parameter to specify fetching options: line (boolean) and length (integer).  If line is set to true, then get will fetch one character at a time until a newline (\n) is encountered and return the line along with any trailing carriage returns (\r) and newlines (\n).  If length is specified as greater than 0, get will fetch one character at a time until the specified number of characters have been read.  If neither is specified, the function will read and return the next 512 characters.  Of course, all cases will terminate if the end of data has been reached.</p>
<p>As a quick example, this portion uses the previously created socket to download the HTTP response headers from google.com&#8217;s homepage:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$s</span>-&gt;<span class="me1">connect</span><span class="br0">&#40;</span><span class="st0">&quot;www.google.com&quot;</span>, <span class="nu0">80</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$get</span>;<br />
&nbsp; &nbsp; <span class="re0">$s</span>-&gt;<span class="me1">setVerbose</span><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$s</span>-&gt;<span class="me1">send</span><span class="br0">&#40;</span><span class="st0">&quot;GET / HTTP/1.1&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$s</span>-&gt;<span class="me1">send</span><span class="br0">&#40;</span><span class="st0">&quot;Host: www.google.com&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$s</span>-&gt;<span class="me1">send</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="re0">$response</span> = <span class="st0">&quot;&quot;</span>;<br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$response</span>, <span class="st0">&quot;<span class="es0">\r</span><span class="es0">\n</span><span class="es0">\r</span><span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>===<span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$response</span> .= <span class="re0">$s</span>-&gt;<span class="me1">get</span><span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">&quot;line&quot;</span>=&gt;true<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>The Socket supports logging and verbosity functions.  The setLog function takes a boolean (true/false for logging) and a string (filename to log to).  The setVerbose function takes only a boolean (true/false &#8212; default false &#8212; for printing out extra information to the console).</p>
<p>Finally, when you&#8217;re finished with the connection, you can call the disconnect() function to cleanly sever the connection.</p>
<h3>webpage()</h3>
<p>The webpage function takes three parameters: a url, a headers array, and a &#8220;headers only&#8221; flag.  The url is simple enough; this is the full url that you want to fetch, including both the host name and the file path (and, optionally, a port number after the hostname).  The headers array goes two ways; you can pass in headers to send and you&#8217;ll get back any headers received.  The headers only flag specifies whether or not to fetch the content of the page; if not, it saves the time of downloading that content, and leaves you with only the response headers.</p>
<p>The headers parameter is two-way, as I mentioned.  You can pass in an associative array of header-name => header-value pairs, which will be formatted properly and sent to the server along with the HTTP request.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="re0">$h</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;User-Agent&quot;</span> =&gt; <span class="st0">&quot;PHP-webscraper/1.0 php/5&quot;</span>,<br />
&nbsp; &nbsp; <span class="st0">&quot;Authorization&quot;</span> =&gt; <span class="st0">&quot;Basic &quot;</span>.<a href="http://www.php.net/base64_encode"><span class="kw3">base64_encode</span></a><span class="br0">&#40;</span><span class="st0">&quot;username:password&quot;</span><span class="br0">&#41;</span><br />
<span class="br0">&#41;</span>;<br />
<span class="re0">$page</span> = webpage<span class="br0">&#40;</span><span class="st0">&quot;http://twitter.com/statuses/mentions.json&quot;</span>, <span class="re0">$h</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>The above will send the User-Agent, for identification, and Authorization, to login, headers to the Twitter API, fetching any tweets that mention the user name &#8220;username&#8221; (using the password &#8220;password&#8221;).  The response will be in JSON, and will require extra processing, but this will get you the data.  For more information on HTTP headers, check out the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">HTTP 1.1 RFC, section 14</a>.</p>
<p>Once the page is received from the server, the headers array you passed in will be overwritten by the server&#8217;s response headers, which you can then examine with external code.  With this method, you can also pass in a simple empty array, which will then be populated with the response headers.</p>
<p>The third parameter to the webpage function is simple enough.  Pass true if you want to receive only the server&#8217;s response headers, cutting off the response once those have been received; a blank string will be returned from the function.  Pass false (or no third parameter) if you wish to receive the entire page, the contents of which will be returned as a string.</p>
<p>With these two files (and, of course, the PHP constructs they define), you can download any webpage you would have access to with your browser, provided you are able to use sockets on your server.  Need to scrape some data from a page?  Download that page and apply some regexes to the content.  HTTP Auth required?  No problem, send an extra header with your creds.  The function could also be modified to POST data to a page, or even download and save images and other media; however, those functions will be left as an exercise for the reader.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=epCtim0OfUg:dMXz3OOn4HA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=epCtim0OfUg:dMXz3OOn4HA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=epCtim0OfUg:dMXz3OOn4HA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=epCtim0OfUg:dMXz3OOn4HA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=epCtim0OfUg:dMXz3OOn4HA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=epCtim0OfUg:dMXz3OOn4HA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=epCtim0OfUg:dMXz3OOn4HA:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/epCtim0OfUg" height="1" width="1"/>]]></content:encoded><description>This post reveals two handy PHP constructs I&amp;#8217;ve been using for a while now: a Socket class and a webpage-downloading function.
The files:

Socket.php (highlighted; plaintext)
webpage.php (highlighted; plaintext)

What good is a full-on Socket class and function, you may ask, when you can simply run file_get_contents with allow_url_fopen turned on?  Well, consider that you want to send [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/php-socket-implementation-and-webpage-downloader/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/php-socket-implementation-and-webpage-downloader/</feedburner:origLink></item><item><title>“Selective Top” Bash Script</title><link>http://feedproxy.google.com/~r/TechKnack/~3/dGLIpNTMzfg/</link><category>linux</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Fri, 29 May 2009 15:05:18 PDT</pubDate><guid isPermaLink="false">http://techknack.net/?p=292</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In my daily work on linux, I constantly have several tabs open in my console app for various CLI activites.  Normally, when I log in to a session, Yakuake auto-starts and I immediately open four tabs in it.  Tab four becomes a system monitor through the use of the &#8220;top&#8221; command, tab one becomes an SSH window to my home server, and the other two are open for whatever.</p>
<p>Occasionally, I&#8217;ll want to keep an eye on specific processes and their resource usage, but they won&#8217;t show up in my &#8220;top&#8221; screen, no matter how I sort the fields.  At this point, I have to use &#8220;ps&#8221; to find the PID (process ID) of each process I want to watch and add each PID to the end of the &#8220;top&#8221; command (using the -p switch for each PID), just to watch a few specific processes.</p>
<p>This little process is well-defined and repeating.  Just the kind of task computers were designed to handle.  I wrote a bash script which takes any number of arguments &#8212; all of them names of processes you want to watch &#8212; finds all related PIDs, and tacks them on to a top command.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="re3">#!/bin/bash</span></p>
<p><span class="re2">ps=</span><span class="st0">&quot;&quot;</span></p>
<p><span class="kw1">for</span> p <span class="kw1">in</span> $*; <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="re2">ps=</span><span class="st0">&quot;$ps `ps -e | grep $p | awk &#8216;{print $1}&#8217; | sort -n | sed &#8217;s/^/-p /&#8217; | tr &#8216;<span class="es0">\n</span>&#8216; &#8216; &#8216;`&quot;</span><br />
<span class="kw1">done</span></p>
<p><span class="kw1">while</span> <span class="br0">&#91;</span> `<span class="kw3">echo</span> <span class="st0">&quot;$ps&quot;</span> | <span class="kw2">grep</span> -c <span class="st0">&quot; &nbsp;&quot;</span>` -ne <span class="nu0">0</span> <span class="br0">&#93;</span>; <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="re2">ps=</span>`<span class="kw3">echo</span> <span class="st0">&quot;$ps&quot;</span> | <span class="kw2">sed</span> <span class="st0">&#8217;s/ &nbsp;/ /&#8217;</span>`<br />
<span class="kw1">done</span><br />
<span class="re2">ps=</span>`<span class="kw3">echo</span> <span class="st0">&quot;$ps&quot;</span> | <span class="kw2">sed</span> <span class="st0">&#8217;s/<span class="es0">\(</span>^<span class="es0">\s</span>*<span class="es0">\)</span><span class="es0">\|</span><span class="es0">\(</span><span class="es0">\s</span>*$<span class="es0">\)</span>//&#8217;</span>`</p>
<p><span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="st0">&quot;$ps&quot;</span> <span class="br0">&#93;</span>; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;No processes found.&quot;</span><br />
<span class="kw1">else</span><br />
&nbsp; &nbsp; top <span class="re1">$ps</span><br />
<span class="kw1">fi</span><br />
&nbsp;</div>
<p><em>Please only use the above as a reference!</em>  The script uses a lot of single quotes, which WordPress likes to convert to &#8220;smart&#8221; quotes.  To see the script as it should be, you can <a href="/examples/bash/btm.txt">view the script as a text file</a>.</p>
<p>The first chunk (&#8221;for p in $*&#8230;&#8221;) iterates over all the arguments, pulling out all the associated PIDs.  The second block (&#8221;while&#8230;&#8221;) replaces multiple spaces with single spaces within the extracted process list, and trims any whitespace off of the beginning and end, to prepare the string for the test at the end.  The last part (&#8221;if [ -z&#8230;&#8221;) checks if the process list is empty or not (if it&#8217;s all spaces, it&#8217;s &#8220;not&#8221;).  If it is empty, the script alerts you and exits &#8212; you won&#8217;t get an empty top list (or full, since there are no arguments passed).  If it&#8217;s not empty, we can assume we found some PIDs, so we tack that on to the top command and take you straight there.</p>
<p>If you want to use this, just stick it in an executable file in your path (see &#8220;echo $PATH&#8221; at the command line); I simply named mine &#8220;btm&#8221;, but it doesn&#8217;t matter what you call it.  If you have any command line arguments you like to pass on to top, you can stick them between &#8220;top&#8221; and &#8220;$ps&#8221; in the &#8220;else&#8221; part of the script.  Once it&#8217;s all set up, just call the script with the process names you want to watch:</p>
<div class="dean_ch" style="white-space: wrap;">$ btm rsync firefox thunderbird</div>
<p>Keep in mind that this will only work with processes that are currently running &#8212; once that rsync job is done, it&#8217;ll disappear from the list, but no new rsync jobs will show up unless you re-run the script.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=dGLIpNTMzfg:nzDaYGIlNOs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=dGLIpNTMzfg:nzDaYGIlNOs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=dGLIpNTMzfg:nzDaYGIlNOs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=dGLIpNTMzfg:nzDaYGIlNOs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=dGLIpNTMzfg:nzDaYGIlNOs:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=dGLIpNTMzfg:nzDaYGIlNOs:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=dGLIpNTMzfg:nzDaYGIlNOs:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/dGLIpNTMzfg" height="1" width="1"/>]]></content:encoded><description>In my daily work on linux, I constantly have several tabs open in my console app for various CLI activites.  Normally, when I log in to a session, Yakuake auto-starts and I immediately open four tabs in it.  Tab four becomes a system monitor through the use of the &amp;#8220;top&amp;#8221; command, tab one [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/selective-top-bash-script/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/selective-top-bash-script/</feedburner:origLink></item><item><title>Conky Transparency Fix for KDE4</title><link>http://feedproxy.google.com/~r/TechKnack/~3/v1nbSwUFRkU/</link><category>linux</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Thu, 07 May 2009 18:31:42 PDT</pubDate><guid isPermaLink="false">http://techknack.net/?p=290</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I love the feeling of power that comes from doing something that google couldn&#8217;t help with <img src='http://techknack.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>In this case, I&#8217;ve spent the past couple days messing with Conky (yes, it is as addicting as they say).  A google search will tell you what it is, and another will show you all the cool things it can do.  One thing that absolutely irked me, though, was the lack of transparency under KDE4.  Basically, my options were:</p>
<ol>
<li>Use &#8220;own_window_type override&#8221;, which seemed to allow transparency, but conky would crash unless I set use_xft to no.  So I got true transparency, but no sexy fonts.</li>
<li>Use &#8220;own_window_type normal&#8221;, and use sexy fonts with use_xft set to true, but using the &#8220;pseudo-transparency&#8221; that conky uses would use the wrong wallpaper.</li>
<li>Use #2 above, but set own_window_transparency to no, and use a solid color background.</li>
</ol>
<p>While I was tweaking conky, I was using #3.  Not the best I could hope for, but the best I could get without any help.  And good enough for development.</p>
<p>When I asked google for help, I found out several things:</p>
<ol>
<li>Conky uses the wallpaper set on the &#8220;root window&#8221; for its pseudo-transparency.</li>
<li>KDE4/Plasma uses its own desktop-drawing to draw the wallpaper.</li>
<li>KDE4/Plasma does not update the root window&#8217;s wallpaper when it updates the desktop&#8217;s wallpaper.</li>
<li>The latest and greatest KDE4 versions are phasing out DCOP support in favor of DBUS.  DCOP, coupled with a program called &#8220;feh&#8221;, is what many workarounds to this issue have used.</li>
<li>The DBUS interface to KDE4 is not yet fully developed, and, as such, has no way to get the current desktop wallpaper.</li>
<li>A method has been pieced together that <a href="http://bbs.archlinux.org/viewtopic.php?pid=549405">greps the user&#8217;s appletsrc file</a> to get the user-set wallpaper:
<div class="dean_ch" style="white-space: wrap;">
feh &#8211;bg-scale <span class="st0">&quot;`grep &#8216;wallpaper=&#8217; ~/.kde4/share/config/plasma-appletsrc | tail &#8211;bytes=+11`&quot;</span><br />
&nbsp;</div>
</li>
<li>Nobody seems to have hacked together anything that works for those of us who use the slideshow feature of KDE4.</li>
</ol>
<p>Figures. Anyway, after some more digging around, I&#8217;ve created a script which fixes the problem for slideshow-users:</p>
<pre>
#!/bin/bash
# kde4bg - by Andrew Rowls <andrew @techknack.net>

SLIDEPATH=`grep slidepaths ~/.kde/share/config/plasma-appletsrc | tail --lines=1 | tail --bytes=+12`
WALL=`ls --sort=time --time=atime "$SLIDEPATH" | head --lines=1`
feh --bg-scale "$SLIDEPATH/$WALL"
</andrew></pre>
<p>Part one (SLIDEPATH) greps your appletsrc file for the directory(ies) set as your slidepath.  In the appletsrc file, this is probably a comma-separated list of directories, but I only wrote the script to handle one directory.  Also, you may have noticed that I used the directory ~/.kde rather than ~/.kde4.  I looked at the ctimes (modification times) of those files (basically, the times KDE4 last modified them).  The ctime for ~/.kde4/share/config/plasma-appletsrc was about 5 days earlier than ~/.kde/share/config/plasma-appletsrc .  A little further digging, and I found that the &#8220;kde4 version&#8221; had an old path to my slideshow directory, while the &#8220;kde version&#8221; had the current (ie, correct) path.  If your KDE4 installation still uses ~/.kde4, change the directory appropriately.</p>
<p>Part two (WALL) gets the last-accessed file in that slidepath.  Basically, every time Plasma changes the wallpaper, it has to *access* the image file, read it into memory, and display it.  As long as the access times (read: wallpaper switches) are at least a minute apart, the current wallpaper will bubble to the top so we can grab its name.  This, of course, assumes that 1) only your slideshow images are in your slidepath directory and 2) you don&#8217;t go messing with those image files very often.</p>
<p>Finally, part three uses feh to set the root window&#8217;s wallpaper, giving it the full path to the image file.</p>
<p>Now, every time you run this script, it will find the last-accessed (presumably by Plasma itself) file and set it as the background, at which point Conky can use that image for its pseudo-transparency.  Since the script has to be manually run, you could put it on cron or as a part of Conky&#8217;s updating, like this:</p>
<pre>
${texeci 3 /path/to/kde4bg}
</pre>
<p>That&#8217;ll execute the script every 3 seconds from conky.  You could put it as every 1 second, but I noticed that, when I tried it, the cpu usage would get a little carried away.  3 seconds is enough to keep cpu usage down while keeping the &#8220;transparency&#8221; sufficiently up-to-date.</p>
<p>Quick disclaimer: This was just a quick throw-together script, written based on my needs.  The main issue with it right now is it only supports one slide directory.  In KDE4, you can set multiple directories, but I really don&#8217;t know what that would do to the script.  Probably just confuse it, but then it wouldn&#8217;t work.</p>
<p>Enjoy.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=v1nbSwUFRkU:YaRda1Frw-8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=v1nbSwUFRkU:YaRda1Frw-8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=v1nbSwUFRkU:YaRda1Frw-8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=v1nbSwUFRkU:YaRda1Frw-8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=v1nbSwUFRkU:YaRda1Frw-8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=v1nbSwUFRkU:YaRda1Frw-8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=v1nbSwUFRkU:YaRda1Frw-8:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/v1nbSwUFRkU" height="1" width="1"/>]]></content:encoded><description>I love the feeling of power that comes from doing something that google couldn&amp;#8217;t help with  
In this case, I&amp;#8217;ve spent the past couple days messing with Conky (yes, it is as addicting as they say).  A google search will tell you what it is, and another will show you all the cool [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/conky-transparency-fix-for-kde4/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/conky-transparency-fix-for-kde4/</feedburner:origLink></item><item><title>PHP Templating: Variable Date</title><link>http://feedproxy.google.com/~r/TechKnack/~3/2Oaj-Aiuv2I/</link><category>blogs</category><category>design</category><category>php</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Sat, 28 Mar 2009 18:38:55 PDT</pubDate><guid isPermaLink="false">http://techknack.net/?p=282</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In building a template system, you may want some way to inject date info using a timestamp (perhaps generated through mktime() ) and date().  But you don&#8217;t want the format to be dependent on the template parser, but rather specified through the variable in the template itself.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="re0">$template</span> = <a href="http://www.php.net/preg_replace"><span class="kw3">preg_replace</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;#<span class="es0">\%</span>date(<span class="es0">\:</span><span class="es0">\s</span>*(.*?))?<span class="es0">\%</span>#ei&quot;</span>,<br />
&nbsp; &nbsp; <span class="st0">&quot;date((&#8217;<span class="es0">\\</span>2&#8242;!=<span class="es0">\&quot;</span><span class="es0">\&quot;</span>?&#8217;<span class="es0">\\</span>2&#8242;:<span class="es0">\$</span>date_format), <span class="es0">\$</span>timestamp)&quot;</span>,<br />
&nbsp; &nbsp; <span class="re0">$template</span><br />
<span class="br0">&#41;</span>;</div>
<p>This falls on the &#8220;advanced&#8221; side of intermediate, I would think, so here&#8217;s an explanation:</p>
<p>This is a standard preg_replace($pattern, $replacement, $source_string).  What we want to do is replace the variable %date% in $template with a date string generated from $timestamp.  But %date% is too limiting; within the template, we&#8217;d like to write something like %date: F j, Y% to get a date like &#8220;March 12, 2009,&#8221; or any other format.</p>
<p>The regular expression is like so: <strong>#\%date(\:\s*(.*?))?\%#ei</strong>.  The &#8220;hashes&#8221; (#) here act as delimiters for the regex; the <em>e</em> and <em>i</em> after the second hash turn on &#8220;eval&#8217;d replacement&#8221; and &#8220;case-insensitivty&#8221;, respectively (<a href="http://us.php.net/manual/en/reference.pcre.pattern.modifiers.php">learn more about PCRE regex modifiers at php.net</a>).  So the regex to deal with is <strong>\%date(\:\s*(.*?))?\%</strong>.  The <strong>\%</strong> are the markers for our template variables; <strong>date</strong> is the name of the variable to look for.  <strong>(\:\s*(.*?))?</strong> matches zero or one instances of our &#8220;variable modifier&#8221;: a colon, followed by any amount of whitespace (including none), followed by any number of any characters (where the extra <strong>?</strong> makes the <strong>.*</strong> &#8220;non-greedy&#8221;; it&#8217;ll stop &#8220;eating&#8221; characters when it reaches the next percent sign).  For preg_replace, this will place our date() format in &#8220;\\2&#8243; if it is present; if it is not present, &#8220;\\2&#8243; will not be set.</p>
<p>The replacement is as follows: <strong>&#8220;date((&#8217;\\2&#8242;!=\&#8221;\&#8221;?&#8217;\\2&#8242;:\$date_format), \$timestamp)&#8221;</strong>.  preg_replace will insert the matched date format from the regex into every occurrence of &#8220;\\2&#8243; in the replacement string, and then run eval() on the resulting string to get the replacement value (all thanks to the <em>e</em> modifier in the regex).  Assuming our regex matched &#8220;F j, Y&#8221; as the match, we&#8217;ll get <strong>&#8220;date((&#8217;F j, Y&#8217;!=\&#8221;\&#8221;?&#8217;F j, Y&#8217;:\$date_format), \$timestamp)&#8221;</strong>.  The <strong>(&#8217;F j, Y&#8217;!=\&#8221;\&#8221;?&#8217;F j, Y&#8217;:\$date_format)</strong> part chooses the date format; if the match is not set (ie, an empty string), use whatever is in the variable $date_format; else, if the date format was matched, use it.  This allows us to use %date% in the template, to default to a server-side specified format.</p>
<p>And there it is.  You can now put &#8220;%date: F j, Y%&#8221; in your template, and it will be expanded to &#8220;March 12, 2009&#8243; (depending on the actual date, of course <img src='http://techknack.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).  That is, if your templating system works in the first place&#8230;</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=2Oaj-Aiuv2I:1N2BLh-IWAE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=2Oaj-Aiuv2I:1N2BLh-IWAE:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=2Oaj-Aiuv2I:1N2BLh-IWAE:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=2Oaj-Aiuv2I:1N2BLh-IWAE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=2Oaj-Aiuv2I:1N2BLh-IWAE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=2Oaj-Aiuv2I:1N2BLh-IWAE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=2Oaj-Aiuv2I:1N2BLh-IWAE:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/2Oaj-Aiuv2I" height="1" width="1"/>]]></content:encoded><description>In building a template system, you may want some way to inject date info using a timestamp (perhaps generated through mktime() ) and date().  But you don&amp;#8217;t want the format to be dependent on the template parser, but rather specified through the variable in the template itself.

$template = preg_replace&amp;#40;
&amp;#160; &amp;#160; &amp;#34;#\%date(\:\s*(.*?))?\%#ei&amp;#34;,
&amp;#160; &amp;#160; &amp;#34;date((&amp;#8217;\\2&amp;#8242;!=\&amp;#34;\&amp;#34;?&amp;#8217;\\2&amp;#8242;:\$date_format), \$timestamp)&amp;#34;,
&amp;#160; [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/php-templating-variable-date/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/php-templating-variable-date/</feedburner:origLink></item><item><title>A Method for CSS Variables</title><link>http://feedproxy.google.com/~r/TechKnack/~3/7faDE9aVREA/</link><category>css</category><category>php</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Thu, 19 Mar 2009 14:33:57 PDT</pubDate><guid isPermaLink="false">http://techknack.net/?p=279</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Jay Salvat at <a href="http://net.tutsplus.com">nettuts</a> has written an article on <a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/">adding variables to your css files</a>.  I like the approach, which includes caching the results, though the code presented is not 100% secure, as <a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/#comment-45724">commenter Pelle</a> has noted.</p>
<p>As for the most popular response, having apache run css files as php code, there are a few issues that come to mind that the article&#8217;s approach takes care of: caching, cleanliness, and portability.</p>
<p>Caching, as the author notes, reduces the number of CPU cycles the server must devote to php processing of the css files.  The parser also implements HTTP features for determining if the file has been modified and needs reloading.  Simply setting the server to parse CSS files, you may or may not lose these features, depending on your server settings.</p>
<p>The method is also clean; using a parsing class lets you put simple variable assignments directly in the CSS file.  Associating CSS with the PHP parser requires you to use the PHP tags and all the appropriate PHP markers ( &lt;?php $var = &#8220;whatever&#8221;; ?&gt; ); if you miss a semicolon, a quote, a dollar sign, or any other part of the required &#8220;PHP syntax&#8221;, your css file at best will contain a php error or warning message, making the code invalid, or at worst will not display at all, giving a blank css file.  The parser Jay gives, while requiring a syntax of its own, is much simpler to use.</p>
<p>Jay&#8217;s solution is portable; the only server configuration necessary is enabling apache&#8217;s mod_rewrite module, which should be enabled anyway.  If that is done, you can move the .htaccess and enhanced_css.php files to any server, and it will work without further server config.</p>
<p>As commenter Pelle notes, however, if someone knows you&#8217;re using this method and they know the path to your enhanced_css.php file, they could use it maliciously.  Jay responds with a quick fix that makes sure the class only parses files ending with &#8220;css&#8221;, but I believe that further security could be provided, though I&#8217;ve not taken the time to analyze the code enough to make suggestions.</p>
<p><a href="http://net.tutsplus.com/tutorials/html-css-techniques/how-to-add-variables-to-your-css-files/#comment-45795">Chris Pratt</a> made a suggestion of changing the parser to hunt out <a href="http://disruptive-innovations.com/zoo/cssvariables/#mozTocId992035">CSS variables as proposed by Daniel Glazman and David Hyatt</a>.  I thought this would be a good idea; the syntax proposed in that doument is much more like the CSS3 stuff we&#8217;re slowly getting used to, such as :not() and attr().</p>
<p>For those interested, you could read <a href="http://www.w3.org/People/Bos/CSS-variables">why some think CSS variables are harmful</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=7faDE9aVREA:u2Q_FcVGxa0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=7faDE9aVREA:u2Q_FcVGxa0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=7faDE9aVREA:u2Q_FcVGxa0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=7faDE9aVREA:u2Q_FcVGxa0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=7faDE9aVREA:u2Q_FcVGxa0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=7faDE9aVREA:u2Q_FcVGxa0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=7faDE9aVREA:u2Q_FcVGxa0:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/7faDE9aVREA" height="1" width="1"/>]]></content:encoded><description>Jay Salvat at nettuts has written an article on adding variables to your css files.  I like the approach, which includes caching the results, though the code presented is not 100% secure, as commenter Pelle has noted.
As for the most popular response, having apache run css files as php code, there are a few [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/a-method-for-css-variables/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/a-method-for-css-variables/</feedburner:origLink></item><item><title>Make Windows Act Like Linux</title><link>http://feedproxy.google.com/~r/TechKnack/~3/mi4Wv3YnhIY/</link><category>linux</category><category>windows</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Thu, 26 Feb 2009 12:23:11 PST</pubDate><guid isPermaLink="false">http://techknack.net/?p=262</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As I use Win7 more and more, there are things that I notice it doesn&#8217;t do that linux did do.  Virtual desktops, certain programs minimizing to the systray, clipboard history.  Small things, things that you normally would take for granted if you had them, but things that become very noticeable when they&#8217;re suddenly missing.  Fortunately, there are lots of little, independently developed programs that provide some of the little pieces of functionality that linux enthusiasts grow used to.</p>
<p>Before I begin listing off links, I feel the need to put a disclaimer.  I realize that the title for this post will make many laugh.  It makes me laugh.  Why, after all, would you want to make Windows act like Linux when you can have the real deal for free?  The answer is just that: Linux is not free, not in the modern sense.  The switch from windows to linux is a shift in the way your world works.  It&#8217;s often a shift for the better, but the shift itself almost always takes time &#8212; time to get used to a new ideology, time to figure things out, time to make things work just the way you want them to.  Time that many people don&#8217;t have.</p>
<p>Truth is, there is simply no way to make Windows akin to Linux in any way, shape, or form.  They are two different environments, two different philosophies.  However, thanks to third-party developers and a fairly open distribution platform (I&#8217;m looking at you, Apple), it&#8217;s possible to bring some functionality to the Windows desktop.  You can&#8217;t change its personality, but you can change its behavior.  This list is meant to bring some linux-y goodness to those without the time to jump in head first.</p>
<p>Now, with that out of the way, the list:</p>
<ul>
<li><b>Clipboard history</b>: something so small, so unnoticeable until you need it, and so nice to have when you do need it.  <a href="http://clipx.org/">ClipX</a>; 131K download; 252K footprint (no plugins, 25 items, text only).</li>
<li><b>Virtual desktops</b>: Most linux distros come with virtual desktops or workspaces.  Once you learn to work with them, you can&#8217;t work without them.  <a href="http://virtuawin.sourceforge.net/">VirtuaWin</a>; 385K download; 1.3M footprint (four desktops).  Won&#8217;t give you the Compiz cube, but you shouldn&#8217;t be expecting that anyways <img src='http://techknack.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> .</li>
<li><b>Window snapping</b>: a nice feature for those who like to work with non-maximized windows in the corners of their desktops.  <a href="http://ivanheckman.com/allsnap/">AllSnap</a>; 69.4K download; just over 1M footprint (portable version via startup folder, desktop snapping only)</li>
<li><b>Systray minimization</b>: I got used to Amarok minimizing to the systray, and I wanted Windows Media Player to do the same.  <a href="http://www.teamcti.com/trayit/trayit.htm">TrayIt!</a>; 327K download; just over 1M footprint (one window rule for WMP).</li>
<li><b>Launchy/Gnome-Do/Program Launcher</b>: I never had much luck with launchy under linux, so I ended up using Gnome-Do for app launching.  Win7, however, seems to do fine with its Start Menu searchbar.  No download, native footprint.</li>
<li><b>Wallpaper rotater</b>: while not strictly functional, it is nice to be able to choose a number of images to auto-rotate through as a wallpaper.  Win7 has this built in.  No download, native footprint.</li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=mi4Wv3YnhIY:kE-gntpZAWw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=mi4Wv3YnhIY:kE-gntpZAWw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=mi4Wv3YnhIY:kE-gntpZAWw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=mi4Wv3YnhIY:kE-gntpZAWw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=mi4Wv3YnhIY:kE-gntpZAWw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=mi4Wv3YnhIY:kE-gntpZAWw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=mi4Wv3YnhIY:kE-gntpZAWw:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/mi4Wv3YnhIY" height="1" width="1"/>]]></content:encoded><description>As I use Win7 more and more, there are things that I notice it doesn&amp;#8217;t do that linux did do.  Virtual desktops, certain programs minimizing to the systray, clipboard history.  Small things, things that you normally would take for granted if you had them, but things that become very noticeable when they&amp;#8217;re suddenly [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/make-windows-act-like-linux/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/make-windows-act-like-linux/</feedburner:origLink></item><item><title>Linux-to-Windows Program Replacements</title><link>http://feedproxy.google.com/~r/TechKnack/~3/-m4CoGAvIu0/</link><category>linux</category><category>windows</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Mon, 23 Feb 2009 12:21:57 PST</pubDate><guid isPermaLink="false">http://techknack.net/?p=226</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>For the past couple of weeks, I&#8217;ve been using the Windows 7 beta.  A shocker, I know, but I&#8217;ve been able to find replacements for most of the software I use everyday in Linux.  The biggest hangups I&#8217;ve found so far are 1) lack of package manager (PLEASE, Microsoft, implement something to this effect!), and 2) lack of some SSHfs capabilities.  I used SSHfs extensively under linux, and WinSCP just doesn&#8217;t cut it.</p>
<p>Moving from a well-established Linux environment to a squeaky-clean Windows environment is bound to be a bumpy experience without first determining suitable replacements for all the programs that one uses on a daily basis.  After my initial move-in, I was rather ad-hoc in finding replacements.  Now that I&#8217;ve found suitable replacements for my most-used programs, perhaps this list can help those of you looking to make n experimental switch.</p>
<ul>
<li><b>BitTorrent</b>: I do a lot of torrenting, so a good replacement for KTorrent is necessary.  uTorrent has so far served my purposes for the odd torrent, while I continue to use my <a href="http://techknack.net/torrent-management-system-with-rtorrent-and-bash/">automated torrent system</a> on my home server for TV shows and such.</li>
<li><b>IM client with AIM and IRC</b>: I sit on IRC channels all day long these days, occasionally throwing in a word or two, but mainly gleaning whatever knowledge I can from the chatter.  Also, I have an AIM account that is my main real-time online point-of-access.  I&#8217;ve gotten used to Kopete, but it&#8217;s lacking in just the right areas so as to make me dissatisfied with it.  Recently I&#8217;ve installed Pidgin (under Kubuntu), and I&#8217;ve found that it has its own quirks that I&#8217;m dissatisfied with, perhaps more so than with Kopete.  The release of kDE4-only Kubuntu 8.10 has further disappointed me: Kopete lost its IRC capabilities, and I was forced to use Konversation for IRC, but it has been an exceptional IRC program.  Here on Windows, the options are rather scarce &#8212; Pidgin is available, but suffers from the aforementioned shortcomings.  I&#8217;ve heard great things about Digsby, but it doesn&#8217;t seem to support IRC at the moment.  However, as I was forced to split my chatting between two programs on linux, doing the same on windows isn&#8217;t too bad a compromise.  I use Digsby for AIM, and <a href="http://www.silverex.org/">YChat</a>, which seems to be a branch of XChat, for IRC.  I am not completely satisfied with YChat as a Konversation replacement, because it has no auto-login, auto-identification, or auto-join features that work on Win7 (seems to be a dll issue here), but it works well enough.</li>
<li><b>Desktop Feed Reader</b>: My primary feed reader for feeds of interest to me is Google Reader, and that isn&#8217;t going to change.  However, I also use a desktop feed reader to toss temporary feeds like ebay and craigslist search results into.  On linux I&#8217;ve grown accustomed to using Akregator, simply because it&#8217;s included with Kubuntu.  Here on Windows, however, FeedDemon has taken the role quite nicely.</li>
<li><b>Music/Video playback</b>, a la Amarok/Kaffeine: I love my music.  And I love my video, whether it be downloaded TV shows or a DVD.  And I have to have some way to play them.  Regarding music, my needs are not outrageous &#8212; I just need some way to organize my music, fetch album info from the net, and perhaps display album art for me.  I don&#8217;t care for song ratings or anything fancy like that.  Windows Media Player works well in regards to both audio and video, and even works with my Inspiron&#8217;s front-side music player controls.</li>
<li><b>Gimp or PhotoShop</b>: Being in web development, I do occasionally do graphics editing.  For this, I need Gimp at the least, though I would like to try PhotoShop.  I&#8217;m going to attempt to install PS CS4 at some point, but I&#8217;m afraid I won&#8217;t have the free disk space for it.  Bummer.</li>
<li><b>Advanced text editor</b>: On Kubuntu, I used Kate for text editing (HTML, CSS, PHP, etc files).  My requirements here are syntax highlighting, tabs, and sessions.  Code collapsing is a nice feature, but not required.  I will likely use Notepad++ on Windows, though I haven&#8217;t done much development lately to really test its workflow yet.</li>
<li><b>Firefox, Thunderbird, and Sunbird</b>: I&#8217;m sorry, there is no replacement for these three <img src='http://techknack.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</li>
<li><b>Office software</b>: On Linux, I got by fine using OpenOffice.  However, since I have free access to Office 2007, I am using that.  Sorry, OSS radicals.</li>
<li><b>Filezilla</b>: Again, no replacement.</li>
<li><b>PDF Viewer/Printer</b>: Another thing that comes stock with Kubuntu.  Foxit is good for PDF viewing, and <a href="http://www.acrosoftware.com/Products/CutePDF/writer.asp">CutePDF</a> works for a printer.</li>
<li><b>File manager</b>: Requirements in this area include all the things I&#8217;ve come to expect from Konqueror: tabbed interface (with spring-loaded tabs, no less), session management, and easy switching amongst various folder views (icons, details, etc).  CubicExplorer fits the bill quite nicely, though I still find myself opening Windows Explorer for short filemanaging stints.</li>
<li><b>SSHfs</b>: This was rather high on my priority list, as I have my web development folders, which reside on my server, mounted locally as SSHfs shares.  This means that, whenever I have internet access, I can simply open, edit, and save the files at home as if they were on my local machine.  Unfortunately, no SSHfs for Windows seems to exist.  I had heard things about Novell&#8217;s netdrive.exe, but it doesn&#8217;t support sftp.  Dokan&#8217;s SSHfs looked promising, but, alas, would not install on a Windows 7 environment (even in Vista compatibility mode).  For now, I have to resort to WinSCP for SSH-based editing, but it doesn&#8217;t come near the convenience of SSHfs.</li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=-m4CoGAvIu0:hG16KYya0XM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=-m4CoGAvIu0:hG16KYya0XM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=-m4CoGAvIu0:hG16KYya0XM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=-m4CoGAvIu0:hG16KYya0XM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=-m4CoGAvIu0:hG16KYya0XM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=-m4CoGAvIu0:hG16KYya0XM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=-m4CoGAvIu0:hG16KYya0XM:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/-m4CoGAvIu0" height="1" width="1"/>]]></content:encoded><description>For the past couple of weeks, I&amp;#8217;ve been using the Windows 7 beta.  A shocker, I know, but I&amp;#8217;ve been able to find replacements for most of the software I use everyday in Linux.  The biggest hangups I&amp;#8217;ve found so far are 1) lack of package manager (PLEASE, Microsoft, implement something to this [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/linux-to-windows-program-replacements/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/linux-to-windows-program-replacements/</feedburner:origLink></item><item><title>Windows 7 and — My Computer!</title><link>http://feedproxy.google.com/~r/TechKnack/~3/fIS5Uf_Yjz8/</link><category>windows</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Fri, 20 Feb 2009 12:21:43 PST</pubDate><guid isPermaLink="false">http://techknack.net/?p=225</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><i>Disclaimer: I never have gotten a chance to experiment with Vista, so I apologize if some of the &#8220;new features&#8221; I rant about here are actually old features carried over from Vista.</i></p>
<p>So I liked what I saw when I installed <a href="http://techknack.net/windows-7-and-virtualbox/">Windows 7 on VirtualBox</a>.  And I didn&#8217;t get to see Aero, and I kinda missed out on &#8220;testing&#8221; Vista, <i>and</i> I had an old XP install (which I never use anymore thanks to Kubuntu) taking 12GB of space.  Can you really blame me for wanting to dive in?</p>
<p>Yes, I have installed Windows 7 (beta-build 7000) using an ISO I had gotten earlier off the torrents and one of the <a href="http://lifehacker.com/5128404/microsoft-extends-windows-7-beta-availability-until-january-24th?t=9963041#viewcomments">available activation keys</a>.  So I&#8217;m presumably set for now through August.  (And if anyone&#8217;s wondering, the 7000 build ISO from the torrents and the 7000 build ISO from Microsoft have the same MD5 checksum &#8212; we checked).</p>
<p>The machine I installed on has a 60GB hard drive (of which Windows 7 has one 12GB partition to work with), 4GB of RAM (of which only 3.25 are available for 32-bit use, which is still nothing to sneeze at), and a 2.0 GHz Intel Core Duo processor.  12GB was the smallest I could shrink my Windows XP partition after I had decided that I wouldn&#8217;t be using it anymore, so that&#8217;s the reason I have so little space.  The installation took around 20 minutes from DVD boot to usable desktop, though I probably spent a good few hours hunting down program replacements.  After the install, I was left with a paltry 1.27 GB to install programs on, or so the Disc Properties dialog told me.</p>
<p>After the install process, I was pleased to find that sound, battery life, and wifi all worked perfectly without any driver frustration caused to me.  I was only a little confused when Windows asked about my &#8220;Location&#8221; when I first connected to a wifi network.  Since the main two networks I connect to are secured networks, I simply chose &#8220;homegroup&#8221; as my location.  And I&#8217;m still not sure what exactly the benefit of setting &#8220;Locations&#8221; up would be.</p>
<p>My Synaptic touchpad, however, was a bit trickier.  While it did work after the install, the edge-scroll feature wouldn&#8217;t work.  After some googling, I downloaded <a href="http://www.synaptics.com/support/drivers">Synaptic&#8217;s driver</a> for Vista, ran it in Vista compatibility mode, rebooted the computer, and enjoyed edge scrolling.  Even after tweaking the settings, though, it&#8217;s not quite as sensitive as I&#8217;m used to under Linux, but it works well enough.</p>
<p>Another pleasant surprise is that no desktop icons are forced on the user.  Normally, IE, My Computer, and usually a few other icons are irremovably (except through registry hacks, of course) placed on the user&#8217;s desktop.  Here, however, there are NO compulsory icons &#8212; they can all be easily disabled through the Personalize section.</p>
<p>One unpleasant surprise I came across was that Windows 7 replaced Grub with its own bootloader.  This was easily remedied by reinstalling grub.</p>
<p>Overall, it was a rather painless install process (dare I say easier than linux?).  One thing I can say I will miss is the ability to search for and install programs from the linux repositories.  There&#8217;s just something about &#8220;sudo aptitude install&#8221;-ing a program that trumps &#8220;google, download, install&#8221; any day.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=fIS5Uf_Yjz8:ScwzJpj3KYo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=fIS5Uf_Yjz8:ScwzJpj3KYo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=fIS5Uf_Yjz8:ScwzJpj3KYo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=fIS5Uf_Yjz8:ScwzJpj3KYo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=fIS5Uf_Yjz8:ScwzJpj3KYo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=fIS5Uf_Yjz8:ScwzJpj3KYo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=fIS5Uf_Yjz8:ScwzJpj3KYo:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/fIS5Uf_Yjz8" height="1" width="1"/>]]></content:encoded><description>Disclaimer: I never have gotten a chance to experiment with Vista, so I apologize if some of the &amp;#8220;new features&amp;#8221; I rant about here are actually old features carried over from Vista.
So I liked what I saw when I installed Windows 7 on VirtualBox.  And I didn&amp;#8217;t get to see Aero, and I kinda [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/windows-7-and-my-computer/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/windows-7-and-my-computer/</feedburner:origLink></item><item><title>A Couple Little PHP Array Tricks</title><link>http://feedproxy.google.com/~r/TechKnack/~3/ej4JIZ7Ja7U/</link><category>asides</category><category>php</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Sat, 14 Feb 2009 11:52:51 PST</pubDate><guid isPermaLink="false">http://techknack.net/?p=252</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>To delete an item from an array:</p>
<div class="dean_ch" style="white-space: wrap;">
<a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>However, this will break a &#8220;for ($i=0; $i&lt;count(); $i++)&#8221; loop.  To maintain sequential indexes:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="re0">$array</span> = <a href="http://www.php.net/array_values"><span class="kw3">array_values</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>This will reset the indexes; beware, though, the items may not be in the same order afterwards.</p>
<p>To select a random item from an associative list:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="re0">$array</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st0">&quot;one&quot;</span>=&gt;<span class="nu0">1</span>,<br />
&nbsp; &nbsp; <span class="st0">&quot;two&quot;</span>=&gt;<span class="nu0">2</span>,<br />
&nbsp; &nbsp; <span class="st0">&quot;three&quot;</span>=&gt;<span class="nu0">3</span><br />
<span class="br0">&#41;</span>;<br />
<span class="re0">$keys</span> = <a href="http://www.php.net/array_keys"><span class="kw3">array_keys</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span>;<br />
<span class="re0">$index</span> = <span class="re0">$keys</span><span class="br0">&#91;</span><a href="http://www.php.net/rand"><span class="kw3">rand</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>%<a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$keys</span><span class="br0">&#41;</span><span class="br0">&#93;</span>;<br />
<span class="re0">$random</span> = <span class="re0">$array</span><span class="br0">&#91;</span><span class="re0">$index</span><span class="br0">&#93;</span>;</p>
<p><span class="co1">// or, more compactly:</span></p>
<p><span class="re0">$k</span> = <a href="http://www.php.net/array_keys"><span class="kw3">array_keys</span></a><span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span>;<br />
<span class="re0">$random</span> = <span class="re0">$array</span><span class="br0">&#91;</span><span class="re0">$k</span><span class="br0">&#91;</span><a href="http://www.php.net/rand"><span class="kw3">rand</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>%<a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$k</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
&nbsp;</div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=ej4JIZ7Ja7U:zGAH2K-FD_8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=ej4JIZ7Ja7U:zGAH2K-FD_8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=ej4JIZ7Ja7U:zGAH2K-FD_8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=ej4JIZ7Ja7U:zGAH2K-FD_8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=ej4JIZ7Ja7U:zGAH2K-FD_8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=ej4JIZ7Ja7U:zGAH2K-FD_8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=ej4JIZ7Ja7U:zGAH2K-FD_8:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/ej4JIZ7Ja7U" height="1" width="1"/>]]></content:encoded><description>Maintaining array indexes after deleting an element; selecting a random element from an associative array.</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/a-couple-little-php-array-tricks/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/a-couple-little-php-array-tricks/</feedburner:origLink></item><item><title>Rounded Corners at the Src</title><link>http://feedproxy.google.com/~r/TechKnack/~3/JqOnsltxCSE/</link><category>php</category><category>web</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">eternicode</dc:creator><pubDate>Sun, 08 Feb 2009 14:57:57 PST</pubDate><guid isPermaLink="false">http://techknack.net/?p=242</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>CSS-based rounded corner solutions are excellent for website layouts, but it&#8217;s just downright silly to envelope a single img tag with two to four extraneous divs just to get some nice rounded corners on that one image.  PHP (with its GD library) is excellent for this purpose.</p>
<p><img alt="Example image without rounded corners." src="http://th00.deviantart.com/fs26/300W/i/2008/094/b/a/Warped_by_eternicode.png" style="float:left;" /><img alt="Example image using the PHP rounded corners script." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs26/300W/i/2008/094/b/a/Warped_by_eternicode.png" title="Example image using the PHP rounded corners script." style="float:right" /></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Warped-81839030">Warped</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a> (me).</p>
<p>My PHP script can take any jpg, png, or static gif image (supplied through the &#8220;src&#8221; GET variable) and apply rounded corners to them.  The space left by the corners is transparent, and so blends in with any background you may have applied to your content section.</p>
<p>Using GET variables, you can control various aspects of the output image.  Using &#8220;rad&#8221; or &#8220;radius&#8221;, you can increase and decrease the size of the corners.  The default value for the radius is 20, which I&#8217;ve found to be reasonable for most images.</p>
<p><img alt="Original image." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs23/300W/i/2007/350/4/4/Let_It_Shine_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using radius option." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th00.deviantart.com/fs23/300W/i/2007/350/4/4/Let_It_Shine_by_eternicode.png&#038;radius=40" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Let-It-Shine-71549321">Let It Shine</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>Using &#8220;width&#8221; or &#8220;height&#8221;, you can scale down the image to meet your needs &#8212; the specified width or height will be taken as the maximum width or height, in pixels, and the aspect ratio will be maintained.  If both height and width are given, the smallest result of the two possible outputs will be used.</p>
<p><img alt="Original image." src="http://th04.deviantart.com/fs24/300W/i/2007/350/4/3/Minty_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using width option with value of 300." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th04.deviantart.com/fs24/300W/i/2007/350/4/3/Minty_by_eternicode.png&#038;width=250" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Minty-72269137">Minty</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>There is also a &#8220;squarification&#8221; option, which will reduce either the width or height (whichever is largest) to produce a squared image.  If &#8220;squared&#8221; is specified as true, radius and scaling will take effect as normal, using the new squared aspect ratio in place of the old ratio.</p>
<p><img alt="Original image." src="http://th02.deviantart.com/fs17/300W/i/2007/218/8/3/Convergence_by_eternicode.png" style="float:left;" /><img alt="Image with rounded corners, using squared option." src="http://techknack.net/examples/phprounded/irrcos.php?src=http://th02.deviantart.com/fs17/300W/i/2007/218/8/3/Convergence_by_eternicode.png&#038;squared=true" style="float:right"/></p>
<p style="clear:both; font-style:italic;">Image: <a href="http://eternicode.deviantart.com/art/Convergence-61635157">Convergence</a> by <a href="http://eternicode.deviantart.com/">~eternicode</a>.</p>
<p>The final option, which was kind of an afterthought, is the &#8220;format&#8221; option &#8212; you can choose either &#8220;png&#8221; or &#8220;gif&#8221; as the output format.  I only added this because with png format, in IE6, the method I used would produce magenta-colored corners, rather than transparent colors.  Supplying a gif output fixes this problem for IE6, though the png option is generally preferred.</p>
<p>The source of the script is very well documented, but feel free to ask questions if I missed something.<br />
<a href="http://techknack.net/examples/phprounded/">The example directory.</a><br />
<a href="http://techknack.net/examples/phprounded/irrcos.php?src=Rekindled_by_eternicode.jpg">Active script</a> using a local image, for your experimentation (any other image can be specified through &#8220;src&#8221;).<br />
<a href="http://techknack.net/examples/phprounded/source_highlighted.php">Highlighted script source.</a><br />
<a href="http://techknack.net/examples/phprounded/source_plaintext.php">Plain text script source.</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TechKnack?a=JqOnsltxCSE:7RutN0BZQ8M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechKnack?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=JqOnsltxCSE:7RutN0BZQ8M:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=JqOnsltxCSE:7RutN0BZQ8M:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=JqOnsltxCSE:7RutN0BZQ8M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=JqOnsltxCSE:7RutN0BZQ8M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TechKnack?a=JqOnsltxCSE:7RutN0BZQ8M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechKnack?i=JqOnsltxCSE:7RutN0BZQ8M:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechKnack/~4/JqOnsltxCSE" height="1" width="1"/>]]></content:encoded><description>CSS-based rounded corner solutions are excellent for website layouts, but it&amp;#8217;s just downright silly to envelope a single img tag with two to four extraneous divs just to get some nice rounded corners on that one image.  PHP (with its GD library) is excellent for this purpose.

Image: Warped by ~eternicode (me).
My PHP script can [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://techknack.net/rounded-corners-at-the-src/feed/</wfw:commentRss><feedburner:origLink>http://techknack.net/rounded-corners-at-the-src/</feedburner:origLink></item></channel></rss>
