<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-28350022</id><updated>2011-10-19T09:24:05.871-05:00</updated><category term='Unix'/><category term='Sprint Sucks'/><category term='DST'/><category term='cook country'/><category term='search engine'/><category term='donate'/><category term='lumni I likovski'/><category term='HTTP'/><category term='rhel'/><category term='Flash'/><category term='download'/><category term='taxes'/><category term='css'/><category term='social networking sites'/><category term='sutures'/><category term='chicago'/><category term='spam'/><category term='Nextel'/><category term='Solaris'/><category term='Sprint'/><category term='home ownership'/><category term='performance'/><category term='vim'/><category term='myspace'/><category term='Adobe'/><category term='scar'/><category term='facebook'/><category term='daylight savings time'/><category term='screen'/><category term='vi'/><category term='PHP header location redirect refresh 301 HTTP protocols'/><category term='brain tumor'/><category term='mysql'/><category term='PDF'/><category term='celebrityaccess'/><category term='music'/><category term='putty'/><category term='constantcontact'/><category term='Un*x'/><category term='Tips'/><category term='sloppy'/><category term='staples'/><category term='seo'/><category term='PHP'/><category term='OpenSolaris'/><category term='terminal'/><category term='html'/><category term='sucks'/><category term='optimization'/><category term='drupal'/><category term='search'/><category term='xdebug'/><category term='XSS'/><category term='profiling'/><title type='text'>Rich's Rants</title><subtitle type='html'>Wherein I occasionally rant on various topics including, but not limited to, PHP, Music, and whatever other Topics I find interesting at the moment, including my &lt;a href="http://richardlynch.blogspot.com/search/label/brain%20tumor"&gt;brain tumor&lt;/a&gt; surgery of August 2010.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>38</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28350022.post-3995530533229105078</id><published>2011-10-11T09:50:00.000-05:00</published><updated>2011-10-11T09:50:58.571-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='drupal'/><title type='text'>Drupal 6 Performance, Part 3</title><content type='html'>After weeks of no problems in STAGING and loadtests looking great, it turns out there's just one teensy little flaw in caching Drupal pages longer than a couple days...&lt;br /&gt;&lt;br /&gt;Drupal nukes the CSS/JS optimized/consolidated temp files every couple days.&lt;br /&gt;&lt;br /&gt;So the monitoring sees a nice valid HTML from an HTTP 200, but humans see a theme-less site.&lt;br /&gt;&lt;br /&gt;Worse, the thing corrects itself somehow, or our guys jump on it and flush the cache, and it's all good...&lt;br /&gt;&lt;br /&gt;For a couple days.&lt;br /&gt;&lt;br /&gt;Rinse, repeat.&lt;br /&gt;&lt;br /&gt;Digging into the Drupal caching source code even deeper, and I'm convinced:  This things wasn't architected; It just grew.&lt;br /&gt;&lt;br /&gt;It's a spaghetti code mess.&lt;br /&gt;&lt;br /&gt;I defy any Drupal core dev to correctly describe the caching "architecture" of D6 pages, CSS, JS, blocks, views, etc in any coherent way.&lt;br /&gt;&lt;br /&gt;I officially give up now.&lt;br /&gt;&lt;br /&gt;When the VP of Marketing complains the site is slow, I'll just say "Yes, it is. That's Drupal."&lt;br /&gt;&lt;br /&gt;We'll have to spider the silly thing after every cron job, actually, instead of doing that. Which sucks, but there it is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3995530533229105078?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3995530533229105078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3995530533229105078' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3995530533229105078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3995530533229105078'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2011/10/drupal-6-performance-part-3.html' title='Drupal 6 Performance, Part 3'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-771095284333961410</id><published>2011-09-14T10:01:00.004-05:00</published><updated>2011-09-14T10:20:44.243-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sloppy'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='seo'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='drupal'/><title type='text'>Drupal 6 Performance, Part 2</title><content type='html'>First, I was &lt;a href="http://richardlynch.blogspot.com/2011/09/drupal-6-performance.html"&gt;wrong&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I was wrong on two points.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Number 1 Mistake:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I thought that there would be a slow query in the mysql slow query log that, with an index, would magically make Drupal 6 faster.&lt;br /&gt;&lt;br /&gt;There wasn't.&lt;br /&gt;&lt;br /&gt;There were a few slow queries, but they had perfectly good indexes, and they were slow, as far as I can tell from the symptoms, due to thread contention, as described here:&lt;br /&gt;&lt;a href="http://www.facebook.com/notes/mysqlfacebook/using-pmp-to-double-mysql-throughput-part-1/404965725932"&gt;Facebook Doubles MySQL Throughput with PMP&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, there are three problems with the solution there.&lt;br /&gt;1) It would take me forever to figure out what those guys are really doing&lt;br /&gt;2) We'd never be able to run un-approved MySQL patches like that&lt;br /&gt;3) There's no way my VP of Marketing is pounding our server hard enough for this to be the problem I'm trying to solve.&lt;br /&gt;&lt;br /&gt;So as much as I'd love to dive in and follow in Domas' and Mark's footsteps, that's not going to happen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Number 2 Mistake:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In my previous article, I stated that I had attempted to eliminate some obvious candidates, and one of those was:&lt;br /&gt;&lt;a href="http://richardlynch.blogspot.com/2011/09/drupal-6-performance.html"&gt;"It only fails after a cache flush? No."&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I was wrong.&lt;br /&gt;&lt;br /&gt;So very very wrong.&lt;br /&gt;&lt;br /&gt;I had eliminated the manual cache flushes done by our team as a source of the problem.&lt;br /&gt;&lt;br /&gt;What I didn't know was that Drupal 6 (and 7) has a brain-dead hard-wired notion that a "Page" in cache_page should be flushed &lt;b&gt;every time cron runs&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Yes, there is a setting for cache_lifetime on your admin "Performance" page, but page_set_cache &lt;b&gt;ignores&lt;/b&gt; that silly little administrative option.&lt;br /&gt;(What actually &lt;b&gt;honors&lt;/b&gt; that setting is perhaps an even more &lt;i&gt;interesting&lt;/i&gt; architectural decision than flushing the Page cache every cron run.)&lt;br /&gt;&lt;br /&gt;This is apparently a known issue as described here:&lt;br /&gt;&lt;a href="http://www.metaltoad.com/blog/how-drupals-cron-killing-you-your-sleep-simple-cache-warmer"&gt;Drupals cron kills you&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that a couple high-profile Drupal community members who should know better make blatantly wrong statements in the Comments.&lt;br /&gt;&lt;br /&gt;I have broken the rules and patched Drupal core, and probably broken polls (we don't use them).&lt;br /&gt;&lt;br /&gt;In your includes/common.inc file, you can apply a patch like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;cat common.inc.patch_cache_page_honor_cache_lifetime &lt;br /&gt;--- common.inc.original 2011-09-13 09:37:30.000000000 -0500&lt;br /&gt;+++ common.inc  2011-09-13 09:39:04.000000000 -0500&lt;br /&gt;@@ -2701,7 +2701,7 @@&lt;br /&gt;         $data = gzencode($data, 9, FORCE_GZIP);&lt;br /&gt;       }&lt;br /&gt;       ob_end_flush();&lt;br /&gt;-      cache_set($base_root . request_uri(), $data, 'cache_page', CACHE_TEMPORARY, drupal_get_headers());&lt;br /&gt;+      cache_set($base_root . request_uri(), $data, 'cache_page', variable_get('cache_lifetime', CACHE_TEMPORARY), drupal_get_headers());&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Our Drupal pages now are cached honoring the cache_lifetime setting in Performance (as I expected for the past 18+ months) and we got consistent 100 requests per second across 15 multisites in loadtests last night, as we should.&lt;br /&gt;&lt;br /&gt;I probably should have run more nights of loadtests before posting this, but I wanted to get this typed up while it was fresh, and, really, now that I know what's going on, I'm pretty confident of this solution.&lt;br /&gt;&lt;br /&gt;Actually, I might just change that again to CACHE_PERMANENT, as caching a page only for a day when they change very seldom is just silly.  But that's probably just us.  Most Drupal users probably expect the behaviour of the patch above, based on the UI.&lt;br /&gt;&lt;br /&gt;Here's one site's zoomed in graph comparing the 13th (with Drupal pages at 0 for failing to respond at all to 90% of my ab -n 1000 -c 100) but on the 14th, similar pages get ~100 requests per second.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-J00n_7KuGsc/TnDANwqDR3I/AAAAAAAAAGg/Ekgw318WtdA/s1600/loadtest_patched.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="49" width="400" src="http://1.bp.blogspot.com/-J00n_7KuGsc/TnDANwqDR3I/AAAAAAAAAGg/Ekgw318WtdA/s400/loadtest_patched.png" /&gt;&lt;/a&gt;&lt;/div&gt;Note that the highest peaks in the above graph are static images and JS/CSS files, not Drupal pages.&lt;br /&gt;&lt;br /&gt;I'm expecting my loadtest graphs to get much smoother now, with no 0s littered everywhere.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-771095284333961410?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/771095284333961410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=771095284333961410' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/771095284333961410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/771095284333961410'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2011/09/drupal-6-performance-part-2.html' title='Drupal 6 Performance, Part 2'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-J00n_7KuGsc/TnDANwqDR3I/AAAAAAAAAGg/Ekgw318WtdA/s72-c/loadtest_patched.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2545923000542628152</id><published>2011-09-08T10:48:00.006-05:00</published><updated>2011-09-08T11:05:29.702-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sloppy'/><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='seo'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='drupal'/><title type='text'>Drupal 6 Performance</title><content type='html'>There are a lot of things I like about Drupal.&lt;br /&gt;&lt;br /&gt;Performance, however, is not one of them.&lt;br /&gt;&lt;br /&gt;Yes, I turned caching on.&lt;br /&gt;Yes, CSS and JS Optimization are on.&lt;br /&gt;Yes, I used YSlow.&lt;br /&gt;Yes, the GA code is at the bottom.&lt;br /&gt;Yes, the images are small.&lt;br /&gt;Yes, our custom HTML templates validate.&lt;br /&gt;Yes, I have fought off the business unit's demands to install modules recommended by SEO "experts" (cough, cough) which are completely inapplicable to our situation. (Example: When all your content is input by staff, you really don't need that spam detector in the cloud service module. If our staff start putting in Viagra ads, we'll just fire them.)&lt;br /&gt;&lt;br /&gt;And, yes, I have a problem.&lt;br /&gt;&lt;br /&gt;Well, several problems, actually, but if the preceding example didn't already clue you in that the business process is quite disfunctional, and that was only the tip of the iceberg, you haven't worked for enough large corporations, and there is nowhere near enough room in this blog post to pull that iceberg into view. I'll get back on focus now.&lt;br /&gt;&lt;br /&gt;Here's the thing: Most of the time, Drupal is hitting its built-in cache with an indexed query of the entire HTML page for an anonymous user.&lt;br /&gt;This is, naturally, quite acceptable, as it simply bootstraps a few too many PHP files (minor annoyance) and runs a single indexed query on a URL-&amp;gt;HTML relationship and spits out the page and exits.&lt;br /&gt;&lt;br /&gt;Unfortunately, my performance "pre-emptive monitoring. quasi-loadtest, and let's make sure none of these sites will make PRODUCTION fall over, and let's catch when the Drupal guy didn't turn caching on" ad hoc process, indicates that occasionally, some URL is performing abysmally [viz].&lt;br /&gt;&lt;br /&gt;I am not an expert in testing, nor Drupal, nor mysql. But I have spent 25+ years specializing in PHP applications, so know a little bit about all those things.  If my methodology is a bit "off", I am pretty confident the results are still "close enough".&lt;br /&gt;&lt;br /&gt;Specifics:&lt;br /&gt;&lt;br /&gt;I have 15 multisites same-codebase different-database D6 sites on a STAGING box, where business units QA (sort of) and approve (or not, or shouldn't have but did) before launch to PRODUCTION. Staging is a 2-tier setup, with 1 www node and 1 mysql node. We're running stock RHEL plus EPEL builds for the most part.  PHP 5.3, MySQL 5.1.  If you've done Drupal multisite, I haven't done anything particularly weird or interesting here.&lt;br /&gt;&lt;br /&gt;There are also a couple "baseline" sites, with just static HTML pages, "phpinfo();", and a "mysql_connect(); mysql_query('select version');" for comparison purposes with the real sites, just so I know that there's nothing inherently wrong with Apache, PHP, nor PHP-to-mysql.&lt;br /&gt;&lt;br /&gt;At night, while real people sleep, I spider each site on a configurable schedule, mostly weekly, and store all the URLs in a flat file per site. In addition, every 5 minutes, an ab loadtest fires for the "next" site in a queue for a randomly-selected URL from that site:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ab -n 1000 -c 100 $random_url_here&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Some of the URLs are images. Some are CSS/JS. Some are actual Drupal nodes.&lt;br /&gt;&lt;br /&gt;I record the ab result files, prepending a line to tell me which URL was requested.&lt;br /&gt;&lt;br /&gt;I also log the requests per second in a database table, counting a big fat 0 for any errors I can detect. For example, if there were &lt;strong&gt;any&lt;/strong&gt; non-2xx HTTP response codes, it's counted a complete failure in my book. If &lt;strong&gt;any&lt;/strong&gt; of the 1000 requests never came back, again, big fat 0. (This is where testing experts are probably crying in their coffee. Sorry.)&lt;br /&gt;&lt;br /&gt;I have some kludgy-hand made PHP|GD graphs.&lt;br /&gt;(Yes, I'm old-school and can visualize and draw a halfway decent graph in PHP code faster than I can fight your fancy new-fangled tools to get a really nice graph.  Sorry.)&lt;br /&gt;&lt;br /&gt;Here is what a sample site graph looks like:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-eRXNaPCc_o8/TmjbSWICupI/AAAAAAAAAD4/PUZPJ4QSjzE/s1600/loadtest.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="147" width="400" src="http://2.bp.blogspot.com/-eRXNaPCc_o8/TmjbSWICupI/AAAAAAAAAD4/PUZPJ4QSjzE/s400/loadtest.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;(The density on the left is because I used to run the loadtests all day every day, but scaled back to night-time in the middle of this process. Yes, testing experts everywhere are crying in their coffee. Sorry.)&lt;br /&gt;&lt;br /&gt;First thing to look at is the bottom center stats min/avg/max: 0/265/1010&lt;br /&gt;That means this site is getting a very acceptable "average" 265 requests per second across all the ab runs you see in the graph.&lt;br /&gt;And that 1010 means that one URL excelled and had 1,010 requests per second in an ab run.&lt;br /&gt;Alas, there is a 0 for that min, and that's the problem.&lt;br /&gt;&lt;br /&gt;In fact, looking at the green lines of the graph itself, you see a fair number of 0 data points.&lt;br /&gt;&lt;br /&gt;I won't bore you with hundreds of ab text outputs, nor the tedious process of matching them up with the dots on the graph, but here's the basic trend:&lt;br /&gt;Static CSS/JS and even images come in first place with the peaks in the hundreds of requests per second.&lt;br /&gt;Most Drupal URLs come in acceptable levels around 100 requests per second.&lt;br /&gt;Occasional Drupal URLs just plain bomb out with, for example, only 8 successful requests, and 992 failures and get the big fat 0.&lt;br /&gt;&lt;br /&gt;I have also attempted to eliminate the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The same URL fails all the time? No.&lt;/li&gt;&lt;li&gt;It only fails after a cache flush? No.&lt;/li&gt;&lt;li&gt;It only fails when a loadtest runs so long it concurs with another? No, I added code to insure only one loadtest at a time. (Testing experts crying over coffee. Sorry.)&lt;/li&gt;&lt;li&gt;Only certain sites? No.&lt;/li&gt;&lt;li&gt;MySQL hasn't been tuned? No. We tuned it.&lt;/li&gt;&lt;li&gt;APC isn't working? No. It's fine.&lt;/li&gt;&lt;li&gt;Uncached Drupal performance isn't &lt;strong&gt;that&lt;/strong&gt; bad. Yes. It is. I measured it with the same (sloppy) metrics above. A simple minimal setup with stock D6 and a few pages / modules falls over after 8 requests in heavy load, without caching.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So my theory, and I admit it's not really &lt;strong&gt;proven&lt;/strong&gt;, since I don't have the mad Drupal skillz to log the info to prove it, is that the setting in Performance "Minimum cache lifetime: &amp;lt;none&amp;gt;" does not, in fact, keep URLs in the cache indefinitely, and something in Drupal purges them, for reasons beyond my ken.&lt;br /&gt;&lt;br /&gt;NOTE:&lt;br /&gt;These are brochureware sites with a hundred nodes each, and a couple webforms.  There are the usual Drupal modules one would expect for that. Plus all the modules I was forced to add that they never actually figure out how to configure and use that the SEO "experts" (cough, cough) told them they need.&lt;br /&gt;&lt;br /&gt;A lot of Drupal experts have recommended PressFlow and varnish and so on. We are considering that.  But even a drop-in replacement isn't that easy to manage when we are rapid-fire launching a new multisite each week. We simply don't have the bandwidth for that right now.&lt;br /&gt;&lt;br /&gt;And, ultimately, I find it offensive that uncached Drupal falls over after 8 requests on a 2-tier php/mysql 6G RAM setup. (Assuming my theory is correct.)&lt;br /&gt;&lt;br /&gt;It's like somebody bolted a billboard to the back of our Maserati.&lt;br /&gt;&lt;br /&gt;Then tossed some kind of broadcast instant replay device named "cache" in front of the billboard to mask the problem.&lt;br /&gt;&lt;br /&gt;And are now recommeding &lt;em&gt;another&lt;/em&gt; broadcast replay device in front of the "cache" called "varnish".&lt;br /&gt;&lt;br /&gt;So am I just going to whine about it? No. I'm going to start analyzing queries in log_slow_queries from MySQL and whatever else I can find, and try to see if I can add some indexes to make uncached Drupal reasonably performant.&lt;br /&gt;&lt;br /&gt;Of course, real Drupal developers are all madly coding Drupal 8, since Drupal 7 was released a few months ago, and Drupal 6, to them, is just not worth patching, so my efforts will probably be largely irrelevant to the Drupal community at large. Sorry.&lt;br /&gt;&lt;br /&gt;You'll have to wait for the next blog post to see if that succeeds or not. I may even have to eat some crow if I can't make any improvement at all.&lt;br /&gt;&lt;br /&gt;Again, I do like a lot of things about Drupal.  Performance, however, and the architecture to make it performant, is not one of them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2545923000542628152?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2545923000542628152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2545923000542628152' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2545923000542628152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2545923000542628152'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2011/09/drupal-6-performance.html' title='Drupal 6 Performance'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-eRXNaPCc_o8/TmjbSWICupI/AAAAAAAAAD4/PUZPJ4QSjzE/s72-c/loadtest.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-3201329224711615753</id><published>2011-08-16T13:42:00.004-05:00</published><updated>2011-08-22T09:03:32.724-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='rhel'/><category scheme='http://www.blogger.com/atom/ns#' term='xdebug'/><category scheme='http://www.blogger.com/atom/ns#' term='optimization'/><category scheme='http://www.blogger.com/atom/ns#' term='profiling'/><title type='text'>Xdebug and RHEL 5.7</title><content type='html'>Much ado and misinformation about how to really profile or performance analyze PHP is all over the Internet.&lt;br /&gt;&lt;br /&gt;Rebuffs also exist to much of that misinformation all over the Internet.&lt;br /&gt;&lt;br /&gt;How to actually really set yourself up to properly profile PHP, not so much...&lt;br /&gt;&lt;br /&gt;So, here's an attempt to provide a step-by-step process, at least for RHEL 5.7&lt;br /&gt;&lt;br /&gt;If you run something else, you'll have to improvise a bit.&lt;br /&gt;&lt;br /&gt;It's not like I really picked RHEL, so that probably deserves some background...&lt;br /&gt;&lt;br /&gt;I'm mostly an old school compile from source guy for Apache, MySQL and PHP to get what I want.&lt;br /&gt;&lt;br /&gt;I used to use RedHat/Fedora for the base Linux / desktop, and then download source for Apache, PHP, MySQL.&lt;br /&gt;&lt;br /&gt;I switched to gentoo a few years ago, and admit I pretty much fail to update very often, but whatever.&lt;br /&gt;&lt;br /&gt;I only have to maintain a handful of boxes, and update when there is a real need.&lt;br /&gt;&lt;br /&gt;In my workplace, the sysadmin is a stock RHEL guy, but then he has to maintain hundreds of servers with puppet and monitor them with Nagios and...&lt;br /&gt;&lt;br /&gt;Well, let's just say I completely understand that need.&lt;br /&gt;&lt;br /&gt;And he HAS opened up to Dag's repos and a UIC or ULC or somesuch to get something I needed.&lt;br /&gt;&lt;br /&gt;Alas, when you want to do serious debugging, profiling, or performance analysis, that's not good enough.&lt;br /&gt;&lt;br /&gt;So I recently embarked on a task to build a "debug" desktop with the following goals:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;have debug builds of php, apache, and mysql&lt;/li&gt;&lt;li&gt;have xdebug&lt;/li&gt;&lt;li&gt;have kCacheGrind / valgrind / callgrind to visualize bottlenecks&lt;/li&gt;&lt;li&gt;this box is used for debug build, nothing else, no other users but me&lt;/li&gt;&lt;li&gt;stray no further from our stock build than I &lt;b&gt;have&lt;/b&gt; to&lt;/li&gt;&lt;/ul&gt;Of course, just installing the GUI is a pretty far straying, and I let RHEL push me into gnome rather than KDE. Not sure that was wise, but there it is.&lt;br /&gt;&lt;br /&gt;Still, I tried to have minimal impact on the build.&lt;br /&gt;&lt;br /&gt;Testing Experts/Pundits:&lt;br /&gt;Note that I'll exit X windows once I'm ready to really test, and then fire it up again to examine the results.  If having the X binaries on the box screws up my tests, so be it. I'm already replacing the &lt;b&gt;REAL&lt;/b&gt; binaries of the code with these debug-enhanced ones anyway, so at that level, it's not "the same" anyway. Having a separate desktop with all these tools on it just didn't seem practical in my case. Your needs may vary.&lt;br /&gt;&lt;br /&gt;I first attempted to get the debug builds of at least PHP, and hopefully Apache and MySQL, just in case.&lt;br /&gt;&lt;br /&gt;Everything seemed to work with yum, but I spun my wheels for hours checking phpinfo() configure line for --disable-debug and trusting its output about debug build.&lt;br /&gt;&lt;br /&gt;It turns out that the RHEL debug builds are actually &lt;b&gt;not&lt;/b&gt; built into the same binary files that ./configure --enable-debug would do. Instead, the debugging symbols are installed in separate binaries in /usr/lib/debug, and tools like gdb and strace and the all-important (to me) "httpd -X" just "know" to look in there and load those debug symbols in on top of the non-debug binaries in the usual places.&lt;br /&gt;&lt;br /&gt;That kind of blew my mind, but whatever, you know?&lt;br /&gt;&lt;br /&gt;And why the httpd startup scripts and PHP don't know to look there is beyond me, but I suppose if I really need to force them to do it, I could find a way... I doubt I'll need that, as you'll see shortly.&lt;br /&gt;&lt;br /&gt;Anyway, in order to actually &lt;b&gt;get&lt;/b&gt; these debug builds, you have to do something like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install --enable-repo=rhel-debuginfo httpd-debuginfo mysql-debuginfo php53-debuginfo&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Note that this installs &lt;b&gt;only&lt;/b&gt; the debugging symbol binaries into /usr/lib/debug. If you actually want to install the software itself, you still need to do these if you didn't already:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install httpd mysql php53&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You also want to install valgrind, which basically allows you to run your binaries under debugging conditions with a whole suite of tools.  We'll look at just one tool, callgrind, because a) it's the only one I know so far and b) it's the one that makes pretty pictures that make it blindingly obvious where your bottlenecks are in your code.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install valgrind&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Just to be sure you installed Apache and PHP, set up your usual PHP script for testing purposes:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;echo "&amp;lt;?php phpinfo();?&amp;gt;" &amp;gt; /var/www/html/index.php&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;(Or edit /var/www/html/index.php with your favorite editor.)&lt;br /&gt;&lt;br /&gt;Surf to http://localhost/ and see the PHP status page with lots of blue tables telling you everything you ever needed to know about your PHP install.&lt;br /&gt;&lt;br /&gt;Now to prove you can generate a callgrind script, to generate a visual representation of where your code spends all its time:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;/etc/init.d/httpd stop&lt;br /&gt;valgrind --tool=callgrind --dump-instr=yes -v /usr/sbin/httpd -X&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;(Someday, RHEL will catch up to the rest of the world and that httpd will change to apache or apache2...)&lt;br /&gt;&lt;br /&gt;Note that you are now running a single httpd instance/child/thread with debugging on full blast, instead of your usual high-performance httpd process.&lt;br /&gt;&lt;br /&gt;You &lt;b&gt;definitely&lt;/b&gt; do not want to do this on a production box, or even a shared dev box.&lt;br /&gt;&lt;br /&gt;You need to be doing this on a sandbox all your own.&lt;br /&gt;Really.&lt;br /&gt;If you can't figure out why, stop reading now and go do something else.&lt;br /&gt;&lt;br /&gt;Now, reload that phpinfo page in your browser.&lt;br /&gt;&lt;br /&gt;Finally, kill that httpd process.  Open another shell and do:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;strike&gt; killall -9 httpd&lt;/strike&gt;&lt;br /&gt;callgrind_control -k&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;If you kill the process, and it's built up a HUGE file of data, it just dies before it writes the data. Don't do that.&lt;br /&gt;&lt;br /&gt;Back in the shell where you did that valgrind command, it will have exited. It will also have dumped a file whose name starts with callgrind.out. and ends with the PID (process ID) of the httpd process that was started.&lt;br /&gt;&lt;br /&gt;You can just safely assume it's a random number, if you are not familiar with process IDs. Actually, if you're not familiar with process IDs, this article is way too advanced for you. Oh well.&lt;br /&gt;&lt;br /&gt;You can open that file up in an editor if you like.&lt;br /&gt;&lt;br /&gt;It won't make much sense, really, but it's kind of cool to see it.&lt;br /&gt;&lt;br /&gt;Don't &lt;b&gt;change&lt;/b&gt; anything in that file, for goodness' sake. We've worked very hard to build it.&lt;br /&gt;&lt;br /&gt;Since you can't read the silly thing, let's install some software that can: kCacheGrind:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install kdesdk&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Don't ask me how you're supposed to figure out that kCacheGrind comes as a part of the KDE SDK tool-suite. I used Google. A lot.&lt;br /&gt;&lt;br /&gt;Now you can run that tool to see how phpinfo() spends all its time:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;kcachegrind callgrind.out.*&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;You have to do this in the same shell/directory where you did the valgrind, just in case you didn't figure that out on your own.&lt;br /&gt;&lt;br /&gt;You ought to see something not unlike this:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MfRtARqRmMU/TkqwPhN8nMI/AAAAAAAAADw/WsoKNSdlAWo/s1600/kCacheGrind.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="256" src="http://3.bp.blogspot.com/-MfRtARqRmMU/TkqwPhN8nMI/AAAAAAAAADw/WsoKNSdlAWo/s320/kCacheGrind.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Whoa!&lt;br /&gt;What's all that, you ask?&lt;br /&gt;&lt;br /&gt;Focus on the big splotches of color. The bigger the rectangle, the more time PHP spent in that function.&lt;br /&gt;&lt;br /&gt;As you can see, PHP spent a lot of time calling various _dl_* functions, presumably loading up code binaries, or double-secret internal functions you should ignore for now.&lt;br /&gt;&lt;br /&gt;But you can also see a big chunk for good old &lt;a href="http://php.net/strlen"&gt;strlen&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now, obviously, you are not likely to jump in and edit PHP's strlen function and make it faster, but the point is that you now &lt;b&gt;know&lt;/b&gt; where PHP is spending all its time in your PHP script.&lt;br /&gt;&lt;br /&gt;Of course, with phpinfo() as the only function call, that's pretty boring.&lt;br /&gt;&lt;br /&gt;Install your favorite framework or large application project (Drupal, WordPress, Zend Framework) or your own home-brew MVC, and load a few test pages.&lt;br /&gt;&lt;br /&gt;Heck, just copy a whole site that you think is "too slow" onto this box in /var/www/html/ and fire it up and find out!&lt;br /&gt;&lt;br /&gt;But wait, you say, I'm just a PHP developer. I'm not going to be re-writing PHP internals!&lt;br /&gt;&lt;br /&gt;Well, guess what?&lt;br /&gt;&lt;br /&gt;This genius Derick Rethans has a tool called &lt;a href="http://xdebug.org/"&gt;Xdebug&lt;/a&gt; that you can use to do this same thing for &lt;b&gt;your&lt;/b&gt; PHP code.&lt;br /&gt;&lt;br /&gt;You'll have to compile it from source, because there are no packages for Xdebug yet.&lt;br /&gt;&lt;br /&gt;Or use PECL, if you've managed to install that.&lt;br /&gt;&lt;br /&gt;I have not installed PECL yet, so I just downloaded the "source" and did the usual:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;./configure&lt;br /&gt;make&lt;br /&gt;make install&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Oh yeah.  Something should be said here about libedit if you want readline-like abilities in the debugclient.&lt;br /&gt;&lt;br /&gt;I pretty much said "Meh." and went on with life, once I realized that I'd have to fight RHEL for another hour or two to get that.&lt;br /&gt;&lt;br /&gt;If you &lt;b&gt;need&lt;/b&gt; that feature in our PHP debugger, you're on your own. Sorry.&lt;br /&gt;&lt;br /&gt;Now, add a few settings anywhere you like in /etc/php.ini:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;; Added xdebug settings&lt;br /&gt;zend_extension="/root/installers/xdebug-2.1.2/modules/xdebug.so"&lt;br /&gt;&lt;br /&gt;; Disallow usage of @ to suppress errors&lt;br /&gt;xdebug.scream = 1&lt;br /&gt;&lt;br /&gt;; Turn on profiling&lt;br /&gt;xdebug.profiler_enable = 1&lt;br /&gt;&lt;br /&gt;; Dump the enormous files here&lt;br /&gt;xdebug.profiler_output_dir = "/tmp/xdebug"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And, so apache can dump the files there a couple shell commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;mkdir /tmp/xdebug&lt;br /&gt;chown apache /tmp/xdebug&lt;br /&gt;chmod 775 /tmp/xdebug&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You have to restart apache for the php.ini changes to take effect:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;/etc/init.d/httpd restart&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Oh. It wasn't started because we killed it and ran it with valgrind before.&lt;br /&gt;Oh well.&lt;br /&gt;&lt;br /&gt;Anyway, reload your phpinfo() page (or other) from http://localhost/index.php&lt;br /&gt;&lt;br /&gt;Now go look in your /tmp/xdebug directory for some callgrind.out.* files, and load them up into kCacheGrind.&lt;br /&gt;&lt;br /&gt;Voila! You now &lt;b&gt;know&lt;/b&gt; where your PHP code is spending all its time, just by looking for the "big" rectangles.&lt;br /&gt;&lt;br /&gt;kCacheGrind has a zillion options and tools to slice and dice your data, and different ways to show it off.&lt;br /&gt;&lt;br /&gt;It also can export the pretty pictures, if you have graphviz and kghostview.&lt;br /&gt;&lt;br /&gt;GraphViz is pretty easy. Snag the repo definitions from &lt;a href="http://www.graphviz.org/graphviz-rhel.repo"&gt;GraphViz RHEL Repo&lt;/a&gt; and put it in /etc/yum.repos.d/graphviz-rhel.repo file.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install graphviz&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Finding kGhostView was quite frustrating. It seems like RHEL is intent on stamping out KDE, and kGhostView in particular since 2002 or so. I found all kinds of rpms from that era, and not much after.&lt;br /&gt;&lt;br /&gt;So we turn to our friends at EPEL, and use their rpm which installs and maintains their repo definitions into /etc/yum.repos.d. Did you follow that?&lt;br /&gt;&lt;br /&gt;Just download the appropriate rpm from here:&lt;br /&gt;&lt;a href="http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F"&gt;EPEL rpm to expand yum&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now at this point, with EPEL installed, I pretty much opened myself up to straying &lt;b&gt;very&lt;/b&gt; far from RHEL, but all I want is kghostview so kCacheGrind can export pretty images:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;yum install kghostview&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Woof.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm pondering if I should now uninstall the EPEL stuff, just to stay on the straight and narrow, and let kghostview lag, or try to remember to only use EPEL in dire circumstances...&lt;br /&gt;&lt;br /&gt;Well, anyway, you probably don't care about that bit.&lt;br /&gt;&lt;br /&gt;You now should have a very powerful tool suite to &lt;b&gt;really&lt;/b&gt; find the bottlenecks in your PHP code, instead of trying some Voodoo Analysis to "optimize" things like changing all "" to '' or using a single (un-indexed) query instead of two (indexed) queries, because running more queries is slower, or...&lt;br /&gt;&lt;br /&gt;I know, I promised not to go there in the first paragraph, so I'll shut up now.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3201329224711615753?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3201329224711615753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3201329224711615753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3201329224711615753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3201329224711615753'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2011/08/xdebug-and-rhel-57.html' title='Xdebug and RHEL 5.7'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-MfRtARqRmMU/TkqwPhN8nMI/AAAAAAAAADw/WsoKNSdlAWo/s72-c/kCacheGrind.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-5440539462207813353</id><published>2010-11-10T21:30:00.003-06:00</published><updated>2010-11-12T10:17:24.570-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='music'/><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Like A Hole In The Head Benefit Concert</title><content type='html'>&lt;h1 style="font-size: x-large; text-align: center;"&gt;Like A Hole In The Head - RESCHEDULED&lt;/h1&gt;&lt;h2 style="font-size: x-large; text-align: center;"&gt;Benefit Concert&lt;/h2&gt;&lt;div style="text-align: left;"&gt;Some of my favorite bands on the planet have generously pulled together a benefit concert at &lt;a href="http://martyrslive.com/"&gt;Martyrs'&lt;/a&gt;, which has the best sound system in Chicago!&lt;/div&gt;&lt;br /&gt;&lt;div style="font-size: x-large; text-align: center;"&gt;MONDAY DEC 20 @ &lt;a href="http://martyrslive.com/"&gt;MARTYRS'&lt;/a&gt;&lt;/div&gt;&lt;div style="font-size: small; text-align: center;"&gt;3855 N Lincoln&lt;/div&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr align="center"&gt; &lt;td width="50%"&gt;&lt;a href="http://ulele.com/"&gt;&lt;img border="0" height="100" src="http://3.bp.blogspot.com/_BmA524o-X8w/TJogujS4A3I/AAAAAAAAACo/hYu_2m2-pD4/s200/ulele.jpg" /&gt;&lt;br /&gt;Ulele&lt;/a&gt;&lt;/td&gt; &lt;td width="50%"&gt;&lt;a href="http://www.myspace.com/suzybrackandthenewjacklords"&gt;&lt;img border="0" height="100" src="http://2.bp.blogspot.com/_BmA524o-X8w/TJoi-hej2bI/AAAAAAAAAC4/zpL7TgdTgp8/s200/suzybrack.jpg" /&gt;&lt;br /&gt;Suzy Brack &amp;amp; The New Jack Lords&lt;/a&gt;&lt;/td&gt;  &lt;/tr&gt;&lt;tr align="center"&gt; &lt;td&gt;&lt;a href="http://ellenrosner.com/"&gt;&lt;img border="0" height="100" src="http://2.bp.blogspot.com/_BmA524o-X8w/TJohkS5M91I/AAAAAAAAACw/k-lsgTktwFw/s200/smilyhappyelleninachair.jpg" /&gt;&lt;br /&gt;Ellen Rosner &amp;amp; The Bubbly Creak All Stars&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://ripleycaine.com/"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_BmA524o-X8w/TJojpE2hNFI/AAAAAAAAADA/489CX-DcKP4/s320/ripleycaine.jpg" height="100" /&gt;&lt;br /&gt;Ripley Caine&lt;/a&gt;&lt;/td&gt;  &lt;/tr&gt;&lt;tr align="center"&gt; &lt;td&gt;&lt;a href="http://jeffrefyaltergott.com"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_BmA524o-X8w/TJokigv6MOI/AAAAAAAAADI/HTyPKAh3N3Y/s320/jeffreyaltergott_left.jpg" height="100" /&gt;&lt;br /&gt;Jeffrey Altergott&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://www.myspace.com/persephonic"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_BmA524o-X8w/TJokquu4LKI/AAAAAAAAADQ/9ONCvWDU4d4/s320/persephonic.jpg" height="100" /&gt;&lt;br /&gt;Persephonic&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr align="center"&gt; &lt;td&gt;&lt;a href="http://alrosemusic.com"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_BmA524o-X8w/TJolEu6BNXI/AAAAAAAAADY/c1TkchU8xSE/s320/alrose.jpg" height="100" /&gt;&lt;br /&gt;Al Rose&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://jademaze.com"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_BmA524o-X8w/TJolNNEUs6I/AAAAAAAAADg/eikde8Kshms/s320/jademaze.jpg" height="100" /&gt;&lt;br /&gt;Jade Maze&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr align="center"&gt;&lt;td&gt;&lt;a href="http://www.myspace.com/loucarlozo"&gt;&lt;img border="0" src="http://c2.ac-images.myspacecdn.com/images01/112/m_81db94207312fc19c27080e4ac3ea79d.jpg" height="100" /&gt;&lt;br /&gt;Lou Carlozo&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td colspan="2"&gt;Silent Auction&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-5440539462207813353?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/5440539462207813353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=5440539462207813353' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5440539462207813353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5440539462207813353'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/like-hole-in-head-benefit-concert.html' title='Like A Hole In The Head Benefit Concert'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/TJogujS4A3I/AAAAAAAAACo/hYu_2m2-pD4/s72-c/ulele.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-8533453296034117926</id><published>2010-10-31T14:12:00.000-05:00</published><updated>2010-10-31T14:12:56.135-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>CONCERT POSTPONED</title><content type='html'>BENEFIT CONCERT POSTPONED!!!&lt;br /&gt;Due to a burst water pipe directly above the sound board at Martyrs', the Benefit Concert scheduled for MON NOV 1 has been postponed...&lt;br /&gt;We do not know the date yet, but stay tuned here to find out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-8533453296034117926?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/8533453296034117926/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=8533453296034117926' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8533453296034117926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8533453296034117926'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/10/concert-postponed.html' title='CONCERT POSTPONED'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2290450473228015067</id><published>2010-09-13T13:16:00.000-05:00</published><updated>2010-09-13T13:16:21.597-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Surgery</title><content type='html'>On August 31, 2010, I went into brain surgery.&lt;br /&gt;&lt;br /&gt;This is a "delayed" blog post about that.&lt;br /&gt;&lt;br /&gt;It got rather long, I'm afraid, which is why it took so long to get up here...&lt;br /&gt;&lt;br /&gt;Plus I've been kind of busy until now, where I have a 2-week lull between post-op and Radiation.&lt;br /&gt;&lt;br /&gt;But people seem more interested in the actual surgery than anything else, so here is a play-by-play of what I remember from it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s1600/mri_gps_map_head.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s200/mri_gps_map_head.jpg" width="153" /&gt;&lt;/a&gt;&lt;br /&gt;The day started early, with a 5:45am arrival for a brain-mapping &lt;a href="http://richardlynch.blogspot.com/2010/09/brain-surgery-survivor.html"&gt;GPS MRI scan&lt;/a&gt; &lt;br /&gt;and 7:30 surgery. I had been warned I might lose my hands for a week, as they were probably going to "nudge" my motor strip in that area when they cut out the tumor.&lt;br /&gt;&lt;br /&gt;After they put all those circular markers on my head, they scanned me, and then I guess dumped a map of my brain to the surgeon's computer.&lt;br /&gt;&lt;br /&gt;I was then wheeled into Pre-op which is a fancy word for hallway with curtains. &lt;br /&gt;Felt kind of like being in the wings of a particularly clean Theatre stage for any&lt;br /&gt;Old Troopers. I guess it makes sense for resource management, but it sure doesn't seem very nice.  I was lucky not to be too back-logged I guess. I imagine on a bad day, you could end up waiting there for hours and hours.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://www.nmff.org/phys_images/F88718.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="https://www.nmff.org/phys_images/F88718.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Dr James P. Chandler&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Then started the introductions. I had already met the surgeon &lt;a href="http://www.feinberg.northwestern.edu/neurosurgery/faculty-and-staff/chandler.htm"&gt;Dr Chandler&lt;/a&gt;, but was introduced to at least three anesthesiologist including &lt;a href="http://www.feinberg.northwestern.edu/anesthesiology/faculty/nmh/koht2.html"&gt;Dr. Koht&lt;/a&gt; and his two assistants, and the Chief Resident, &lt;a href="http://www.feinberg.northwestern.edu/neurosurgery/research/team/"&gt;Ryan Halpin&lt;/a&gt;, who turned out was my "coach" for the surgery (viz) and he seemed to be the one watching the heart and other squiggly lines monitor that I could also see. Though I daresay there were many others monitoring all kinds of stuff I never even saw.&lt;br /&gt;&lt;br /&gt;I think I got re-introduced to some doctors/nurses, and I'm told surgery started 2 hours late, but I didn't notice, so maybe that was their plan... Just keep me trying to remember names and faces and distract me :-)&lt;br /&gt;&lt;br /&gt;Anyway, they wheeled me in, hooked up an IV or two, and conked me out. They apparently locked down my head and connected some plumbing then, for which I'm quite thankful I was not awake. That probably seems normal enough for any surgery. Then they woke me up, still on the table!&lt;br /&gt;&lt;br /&gt;They had me move my fingers around and monitored stuff on their computers to make sure things looked right. They cut open my scalp and chopped a hole in my skull. Did I mention I was still awake?!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_BmA524o-X8w/THhjs1rJ0QI/AAAAAAAAABw/vSpVikfEfVU/s1600/tumor.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_BmA524o-X8w/THhjs1rJ0QI/AAAAAAAAABw/vSpVikfEfVU/s200/tumor.png" width="193" /&gt;&lt;/a&gt;So then I presume he moved the protective water balloon brain sac aside, and went in through the vein above that red arrow, or moved some brain bits aside...&lt;br /&gt;&lt;br /&gt;Then they had me touch each finger to my thumb and said they were getting signals on that.&lt;br /&gt;&lt;br /&gt;Then he hooked up a wire to my brain and made a nerve in my right wrist&amp;nbsp; twitch at 60 Hz and asked "Can you feel that?" Surreal!&lt;br /&gt;&lt;br /&gt;If you've ever gotten a light tremor from house current running through you for a few seconds, it was just like that.&amp;nbsp; Only direct from my brain. And on purpose. &lt;br /&gt;&lt;br /&gt;They also confirmed on some med computer that they were seeing the same signal.&lt;br /&gt;&lt;br /&gt;Repeated the process, for my right ankle. Then the left ankle. Each time they asked me "Can you feel that?", and confirmed signal with each other.&lt;br /&gt;&lt;br /&gt;They didn't do my left wrist, which was disconcerting, but I'm not sure I was able to voice that concern well.&lt;br /&gt;&lt;br /&gt;Then they warned me that they were going to do a few more that I wouldn't feel.&lt;br /&gt;&lt;br /&gt;There's not supposed to be any nerves inside the brain, but I WAS able to sense each probe in turn as a sort of cool prick. I told them all about it, apparently in more detail than they required: I believe this was the first time they politely told me to be quiet and focus on taking nice deep breaths.&lt;br /&gt;&lt;br /&gt;That would be Dr. Ryan Halpin, the "coach" and I have to say he has the patience of a saint. He managed to put up with me and keep me on task while I was halfway zonked out, which is a miracle.&lt;br /&gt;&lt;br /&gt;They ran through all the signals again, confirming I could feel the nerve twitching at 60Hz and seeing the signals on their computers. Apparently "measure twice, cut once" applies to brain surgery as well as lumber.&lt;br /&gt;&lt;br /&gt;Come to think of it, counting up MRIs (regular, functional, spectroscopic, and mapping) as well as CT scans and the probes, it was more like "measure 10X, cut once." Same principle at least, but I suppose a factor of 10 for Brain Surgery makes sense.&amp;nbsp; I mean, tossing a 2x4 out is one thing... :-)&lt;br /&gt;&lt;br /&gt;Then Dr Chandler cut out the actual tumor. I think this may have been another time I was politely told to shut up and breathe. It seemed like the actual tumor removal only took 10 minutes, but my time sense wasn't exactly perfect, eh?&lt;br /&gt;&lt;br /&gt;Finally they started putting things back together.  There's a chunk of skull held in by titanium plates and screws (Looking for a pic of these). No MRI or airport restrictions on those, which is nice.&lt;br /&gt;&lt;br /&gt;There is apparently some glue in there holding something together as well.&amp;nbsp; I wonder if they have a $10,000 hot glue gun just like my $20 one at home, or if it's some kind of packet like a condiment they use.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_BmA524o-X8w/TIF7bAt-SrI/AAAAAAAAACA/8ZHhstawwjM/s1600/sutures_staples_1708.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/_BmA524o-X8w/TIF7bAt-SrI/AAAAAAAAACA/8ZHhstawwjM/s200/sutures_staples_1708.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;Then the scalp was stapled shut, as you can see to the right: &lt;br /&gt;I kind of expected some stitches, but if I have any, I sure can't find them, even now that the staples are out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;At some point the doc asked for a 1x3, but the nurse only had a 2x2. They went back and forth a few times on that, which was disconcerting. I mean, who cares about the shape of the scar or whatever, but the wrong size screws or plate inside?... I didn't know exactly what stage of re-assembly we were in, so I tried to make a joke about lumber, but it fell flat. Oh well.  Tough crowd I guess.&lt;br /&gt;&lt;br /&gt;(Weeks later I found out it was just a gauze swab to wipe out some blood or something.  Whew!)&lt;br /&gt;&lt;br /&gt;They also didn't like when I broke into a song lyric with a trigger word/phrase somebody said; which anybody who knows me is a habit of mine.  Guess I don't sing any better while in "twilight" anesthesia. But I only did that once, so that's not so bad! A musician friend of mine tells me she had the whole operating room staff singing with her. That was definitely one of the times I was politely told to shut up and breathe deeply.&lt;br /&gt;&lt;br /&gt;Then they wheeled me out to post-op (read: hallway curtains) where I spent 2 hours needing to be there, and six more hanging around waiting for a room, thanks to construction... I've got a few pithy comments about post-op and a certain nurse, but will save those as I've already made this quite long.&lt;br /&gt;&lt;br /&gt;Anyway, that's all the bits I can remember from nearly 3 hours of brain surgery. I apologize if it's out of order, or I've managed to completely mess up what they did.  All I know is, it was surreal, but they got the tumor out, and over-delivered as my hands worked just fine, albeit with a bit of tingling and numbness now and then. I'm calling it a "win"&lt;br /&gt;&lt;br /&gt;Honestly, the only things I could have asked for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Advance notice that my main job would be deep breathing.&amp;nbsp; They had described the finger / nerve twitching process in advance. But perhaps the breathing thing is case-by-case. I probably could have kept more quiet and done more breathing if they had.&lt;/li&gt;&lt;li&gt;Check that left wrist, or tell me we don't need to.&lt;/li&gt;&lt;li&gt;Let me know what is going on when the doc asks for a 1x3 and they ain't got it, so I'm not worried about it.&lt;/li&gt;&lt;/ul&gt;Considering everything else going on, these seem awfully petty!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2290450473228015067?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2290450473228015067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2290450473228015067' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2290450473228015067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2290450473228015067'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/brain-surgery.html' title='Brain Surgery'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s72-c/mri_gps_map_head.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-8311182476395143273</id><published>2010-09-10T18:55:00.001-05:00</published><updated>2010-09-10T19:08:11.665-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Surgery Staples Removed</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_BmA524o-X8w/TIrCh6GxFOI/AAAAAAAAACY/wVo58ahHA4g/s1600/IMG00067-20100910-1211.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_BmA524o-X8w/TIrCh6GxFOI/AAAAAAAAACY/wVo58ahHA4g/s320/IMG00067-20100910-1211.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;I got my staples removed yesterday, so here's what it looks like today...&lt;br /&gt;&lt;br /&gt;So, what I've got going for me:&lt;br /&gt;I'm relatively young, in good health other than this cancer in my brain, and a wild guess estimate is 90% of it was in the tumor they already took out.&lt;br /&gt;I've got just about the most supportive family, friends, and workplace anybody could ask for.&lt;br /&gt;&lt;br /&gt;On the downside, if you lump me in with males up to age 90 with brain cancer, my "live expectancy" is a couple years...&lt;br /&gt;&lt;br /&gt;&amp;nbsp;But, hey, let's Do The Math:&lt;br /&gt;&lt;br /&gt;A guy 90 years old, already has not much more on "life expectancy"...&amp;nbsp; There's no numbers I can find breaking it down by decade or anything,&amp;nbsp; so let's assume it's some kind of curve, and I'm on the right end of the curve.&lt;br /&gt;&lt;br /&gt;It blew up fast, over the course of a couple months or even weeks, so there was not much more that could have been done for "early detection".&lt;br /&gt;&lt;br /&gt;The docs have caught it in time to get 90% out already, and will radiate and chemo the other 10%.&amp;nbsp; It will try to grow back, but we'll MRI it every couple months and catch it and chemo it some more, beating it back into submission.&amp;nbsp; So we have a game plan to keep this under control indefinitely.&lt;br /&gt;&lt;br /&gt;Do I expect to make it to 70+, like my dad, as I once did?&lt;br /&gt;&lt;br /&gt;No, not really.&amp;nbsp; I'll give it my best shot though!&lt;br /&gt;&lt;br /&gt;Maybe I'll only hit 65, like my Mom.&amp;nbsp; Still not a bad run.&lt;br /&gt;&lt;br /&gt;So what's my "life expectancy"?&amp;nbsp; I expect to get as much out of it as I can for as long as I can, same as anybody else!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-8311182476395143273?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/8311182476395143273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=8311182476395143273' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8311182476395143273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8311182476395143273'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/brain-surgery-staples-removed.html' title='Brain Surgery Staples Removed'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BmA524o-X8w/TIrCh6GxFOI/AAAAAAAAACY/wVo58ahHA4g/s72-c/IMG00067-20100910-1211.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-5602225574715117590</id><published>2010-09-09T09:54:00.000-05:00</published><updated>2010-09-09T09:54:21.676-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Radiation Setup CT Scan</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_BmA524o-X8w/TIjzc5M1J5I/AAAAAAAAACQ/cWrOwa25Bx4/s1600/IMG00061-20100909-0919.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_BmA524o-X8w/TIjzc5M1J5I/AAAAAAAAACQ/cWrOwa25Bx4/s320/IMG00061-20100909-0919.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;Radiation Setup CT Scan&lt;br /&gt;&lt;br /&gt;So they put this warm stretchy mesh mask on me, and it cools off to the shape of my head, and then they can use it every time after to get my head in exactly the same position.&lt;br /&gt;I suppose it's like getting a facial at the spa, though I don't have any experience to compare really. &lt;br /&gt;I'll be wearing this thing every week day for 6 weeks of radiation treatment, starting 9/27.&lt;br /&gt;I get to keep it at the end, but it's unfortunately too late for Halloween.&amp;nbsp; Oh well. :-)&lt;br /&gt;Meet with the surgeon this afternoon, so might blog more later... Or not.&lt;br /&gt;Much thanks for the prayers and support and donation.&lt;br /&gt;There's no way I could possibly thank everybody "enough", but that's most espeically true of my children and Love Of My Life and my sisters.&amp;nbsp; I'm not the easiest guy in the world to put up with, and this isn't helping, but they've been stellar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-5602225574715117590?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/5602225574715117590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=5602225574715117590' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5602225574715117590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5602225574715117590'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/radiation-setup-ct-scan.html' title='Radiation Setup CT Scan'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/TIjzc5M1J5I/AAAAAAAAACQ/cWrOwa25Bx4/s72-c/IMG00061-20100909-0919.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-456329928724889435</id><published>2010-09-08T09:48:00.002-05:00</published><updated>2010-09-09T11:03:06.974-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Tumor Pathology</title><content type='html'>&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_BmA524o-X8w/TIfnZG76HnI/AAAAAAAAACI/XoWd4pFQgr0/s1600/tumor_scatter.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_BmA524o-X8w/TIfnZG76HnI/AAAAAAAAACI/XoWd4pFQgr0/s320/tumor_scatter.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Tumor w/ Surrounding "Bad Stuff" in active tissue&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Brain Tumor Pathology&lt;br /&gt;&lt;span style="font-size: xx-small;"&gt;&lt;i&gt;(translated from Medical to English)&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Malignant.&lt;br /&gt;Grade 4 (worst)&lt;br /&gt;The surgeon got the main tumor out.&lt;br /&gt;But it's guaranteed to have a splatter effect of Bad Stuff mixed in surrounding brain tissue. &lt;br /&gt;Aggressive radiation/chemo (6wks/6months respectively) will maybe beat it back.&lt;br /&gt;Then, ongoing maintenance of MRI scans every couple months, and chemo when more tumors appear, for life.&lt;br /&gt;&lt;br /&gt;I guess that's not as bad as the old school movie "Go home and die" answer, but I think these days it's about as bad as it gets folks...&lt;br /&gt;&lt;br /&gt;On the other hand, the oncologist said that the odds of hearing benign were in the realm of "case study in a journal".&amp;nbsp; I do wish they had just told me that weeks ago. I've been living with a false hope of hearing "benign" and on the hook of not knowing for weeks... Oh well. &lt;br /&gt;&lt;br /&gt;I'm staying as positive as I can, but I'm in for a rough ride, and that's the breaks.&lt;br /&gt;&lt;br /&gt;Thanks for all your prayers, support, and donations.&lt;br /&gt;&lt;br /&gt;I'll try to post more on Friday 9/10. Tomorrow 9/9 is a CT scan with some kind of plastic fencing mask to map where the tumor used to be married with the old MRIs to program the linear accelerator for the radiation treatment.&amp;nbsp; Or, at least, that's my layman's understanding of what the doctor said...&lt;br /&gt;&lt;br /&gt;I think I get my staples out of my scalp tomorrow too.&amp;nbsp; That's good, as the changing Autumn weather is making them hot/cold expand/contract in an annoying way. That probably sounds silly/petty in the grand scheme of things, but there it is.&lt;br /&gt;&lt;br /&gt;Anyway, expect silence Thursday 9/9 from me, almost for sure.&amp;nbsp; I don't think they let me use my laptop from inside a CT scanner :-)&lt;br /&gt;&lt;br /&gt;I also want to thank my employer, &lt;a href="http://www.rasmussen.edu/"&gt;Rasmussen&lt;/a&gt; who have bent over backwards throughout this ordeal to keep me "employed" and "current" in insurance coverage. I don't know what I'd do without them. If you are looking for a good place to work in the online education industry, check out the openings and tell them I sent you:&lt;br /&gt;&lt;a href="http://www.pcrecruiter.net/pcrbin/regmenu.exe?uid=rasmussen%20college.rasmussen"&gt;Rasmussen Employment Opportunities&lt;/a&gt;&lt;br /&gt;They've done right by me, that's for sure!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-456329928724889435?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/456329928724889435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=456329928724889435' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/456329928724889435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/456329928724889435'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/brain-tumor-pathology.html' title='Brain Tumor Pathology'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BmA524o-X8w/TIfnZG76HnI/AAAAAAAAACI/XoWd4pFQgr0/s72-c/tumor_scatter.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-5374580110279019205</id><published>2010-09-04T21:28:00.000-05:00</published><updated>2010-09-04T21:28:19.345-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Surgical Staple Remover</title><content type='html'>Today I ran some errands.&amp;nbsp; Well, technically, the girls biked while I walked, as I can't drive for six months...&lt;br /&gt;&lt;br /&gt;I blogged yesterday about the "fancy" surgical staple remover...&lt;br /&gt;&lt;br /&gt;I brought it home for my daughters to practice with (not on my scalp, but an old deflated kickball)...&lt;br /&gt;&lt;br /&gt;Actually, I was gonna let the 12-yo future surgeon practice on one of mine, but Mama said "NO!" [shrug]&lt;br /&gt;&lt;br /&gt;Anyway, I looked at it, and it's got 3M etched on the handle and a quick Google finds...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/Precise-Disposable-Tweezer-Staple-Remover/dp/B0013YB6IC"&gt;&lt;img border="0" src="http://ecx.images-amazon.com/images/I/319AmP62W9L._SS500_.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;Yup, that's the thing!&lt;br /&gt;&lt;br /&gt;I have to wonder if the hospital will charge me (Blue Cross, really) the list price of $71.48 or the Amazon price of $6.50&lt;br /&gt;&lt;br /&gt;And they throw them away after each patient to avoid contamination.&amp;nbsp; Which is a Good Thing I suppose, but...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-5374580110279019205?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/5374580110279019205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=5374580110279019205' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5374580110279019205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5374580110279019205'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/surgical-staple-remover.html' title='Surgical Staple Remover'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-8461052360056560639</id><published>2010-09-03T17:54:00.000-05:00</published><updated>2010-09-03T17:54:12.181-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='staples'/><category scheme='http://www.blogger.com/atom/ns#' term='sutures'/><category scheme='http://www.blogger.com/atom/ns#' term='scar'/><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Dressing Off</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_BmA524o-X8w/TIF7bAt-SrI/AAAAAAAAACA/8ZHhstawwjM/s1600/sutures_staples_1708.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://2.bp.blogspot.com/_BmA524o-X8w/TIF7bAt-SrI/AAAAAAAAACA/8ZHhstawwjM/s400/sutures_staples_1708.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;So I've been walking around with a small white rectangle dressing stapled to my scalp, covering the sutures and more staples.&lt;br /&gt;They took the dressing off today, so I can post a photo of the actual future scar...&lt;br /&gt;I guess I should have posted a photo of the dressing, but it pretty much looked like a mini-pad stapled to a bald guy's head, so... :-v&lt;br /&gt;Yes, those silver things really are staples.&lt;br /&gt;They have a fancy set of pliers to remove them that bends them just so to pull them out the reverse of how they went in, so the ones on the dressing felt like getting a couple hairs plucked out.&amp;nbsp; I suppose these go deeper and will need a local or something, but I'll find that out next week...&lt;br /&gt;Tuesday I meet with the oncologist to see what we're really dealing with, and the endgame.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-8461052360056560639?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/8461052360056560639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=8461052360056560639' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8461052360056560639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8461052360056560639'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/dressing-off.html' title='Dressing Off'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_BmA524o-X8w/TIF7bAt-SrI/AAAAAAAAACA/8ZHhstawwjM/s72-c/sutures_staples_1708.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-3626787333074729821</id><published>2010-09-02T08:40:00.002-05:00</published><updated>2010-09-03T17:31:40.290-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='seo'/><category scheme='http://www.blogger.com/atom/ns#' term='search'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='search engine'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>SEO For Beginners</title><content type='html'>You're probably even more tired of my posts about Brain Tumor/Surgery than I am, so I'll go off on a "rant" on another topic :-)&lt;br /&gt;&lt;br /&gt;I still need to draw your attention to that Donate button over there... Okay, done.&lt;br /&gt;&lt;br /&gt;A Beginner's Guide To SEO:&lt;br /&gt;#1: CONTENT IS KING&lt;br /&gt;Put content on your site that people want, and make it easy to find/browse in your own navigation.&lt;br /&gt;If you have content people WANT, and people can find it, and search engines can read it (don't bury it in Flash) then you're all set.&lt;br /&gt;If not, you have no "game" and all the SEO in the world won't do squat for you.&lt;br /&gt;&lt;br /&gt;#2&lt;br /&gt;Follow some common-sense basics like using HTML/CSS properly, with valid markup, and a good TITLE tag matching an H1 tag relating to what's on the page.&lt;br /&gt;Put your important content first in the text, and use CSS to position it where you like.&lt;br /&gt;Try to use a decent domain name that you can shout to a roomful of drunk people that they'll remember, maybe, the next day.&lt;br /&gt;Even if your target audience is NOT rooms full of drunken people, it's still a good metric for the domain name.&lt;br /&gt;&lt;br /&gt;#3&lt;br /&gt;A META Description is good, if it matches the page/site content, and provides a consistent "brand" (theme/mission/image) you want to promote. You'd have to ask some Marketing drone whether it's a "brand" or an "image".&lt;br /&gt;META Keywords haven't been used by any major search engine in years: Anybody who says different is stupid or out-dated. Or both.&lt;br /&gt;&lt;br /&gt;#4&lt;br /&gt;Don't try to "game" the system with techniques that misrepresent your content. As soon as the search engine makers figure out what you and all the other idiots are doing, they DEDUCT points for it, and you lose, Game Over.&lt;br /&gt;Unless they just ban your site completely from the results, in which case you've just wasted your oh-so-precious domain name. GAME OVER!!!&lt;br /&gt;&lt;br /&gt;#5, #6, #7, #8, #9: See #1&lt;br /&gt;&lt;br /&gt;#10&lt;br /&gt;After you have done that, worry about tweaking the so-called SEO junk to improve your site that last 1%.&lt;br /&gt;Image ALT keywords, re-positioning&lt;br /&gt;&lt;br /&gt;PS&lt;br /&gt;I believe most SEO "experts" are charlatans, and I refuse to label myself an SEO expert.&lt;br /&gt;Make of that what you want...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3626787333074729821?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3626787333074729821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3626787333074729821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3626787333074729821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3626787333074729821'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/seo-for-beginners.html' title='SEO For Beginners'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-7582113366891311300</id><published>2010-09-01T19:38:00.002-05:00</published><updated>2010-09-11T01:11:14.971-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Surgery Survivor</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s1600/mri_gps_map_head.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s320/mri_gps_map_head.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;I made it!&lt;br /&gt;Even have fully functional hands.&lt;br /&gt;I feel about like you'd expect when somebody cuts a hole in one's head... :-)&lt;br /&gt;Thanks so much for the prayers of any flavor and donations.&lt;br /&gt;Followup appointments next week are still in pencil due to doctor schedule conflicts, but at lest one of them should tell me something some time next week, regarding malignant/benign and grade/scale or whatever.&lt;br /&gt;Had a screamer on the same floor last night, so didn't sleep much...&lt;br /&gt;Very tired, so I'll end this post here.&lt;br /&gt;Just know I'm alive, and recovering, and will know the Real Story next week...&lt;br /&gt;&lt;br /&gt;[EDIT: 2010-09-11]&lt;br /&gt;I added this photo from my sister's phone.&amp;nbsp; Those white circles were some kind of GPS markers for an MRI mapping that lets the surgeon match up the brain images of the tumor with what's actually in my head.&lt;br /&gt;Had I only known in advance, we probably could have gotten my brain on Google maps! :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-7582113366891311300?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/7582113366891311300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=7582113366891311300' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7582113366891311300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7582113366891311300'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/09/brain-surgery-survivor.html' title='Brain Surgery Survivor'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/TIsdCwVmWqI/AAAAAAAAACg/9u8tneKwYns/s72-c/mri_gps_map_head.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-1421708818910908602</id><published>2010-08-27T19:44:00.005-05:00</published><updated>2010-09-04T21:13:36.986-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Tumor</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_BmA524o-X8w/THhjs1rJ0QI/AAAAAAAAABw/vSpVikfEfVU/s1600/tumor.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5510263766061273346" src="http://3.bp.blogspot.com/_BmA524o-X8w/THhjs1rJ0QI/AAAAAAAAABw/vSpVikfEfVU/s320/tumor.png" style="cursor: pointer; float: right; height: 320px; margin: 0pt 0pt 10px 10px; width: 310px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is a side-view of the actual tumor.&lt;br /&gt;That darker gray splotch in the top center, shaped somewhat like a guitar pick, only not.&lt;br /&gt;I added a big red arrow, as I realized the the vein above could be mistaken for the tumor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-1421708818910908602?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/1421708818910908602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=1421708818910908602' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/1421708818910908602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/1421708818910908602'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/08/brain-tumor_27.html' title='Brain Tumor'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/THhjs1rJ0QI/AAAAAAAAABw/vSpVikfEfVU/s72-c/tumor.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2385377947770165056</id><published>2010-08-27T16:06:00.003-05:00</published><updated>2010-09-04T21:13:57.057-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Richard Lynch Medical Expenses Fund</title><content type='html'>In case somebody prefers a Real Bank to this new-fangled PayPal thingie, my sister set up a fund for me:&lt;br /&gt;&lt;br /&gt;Richard Lynch Medical Expenses Fund&lt;br /&gt;First Bank &amp;amp; Trust&lt;br /&gt;820 Church Street&lt;br /&gt;Evanston, IL 60201&lt;br /&gt;&lt;br /&gt;Any donations much appreciated...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2385377947770165056?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2385377947770165056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2385377947770165056' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2385377947770165056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2385377947770165056'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/08/richard-lynch-medical-expenses-fund.html' title='Richard Lynch Medical Expenses Fund'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2410713813411587981</id><published>2010-08-26T20:44:00.004-05:00</published><updated>2010-09-04T21:14:13.644-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Tumor</title><content type='html'>Quick Update:&lt;br /&gt;The neurosurgeon says the Functional MRI and MR Spectroscopy point towards a tumor rather than infection.&lt;br /&gt;Surgery on Tuesday.&lt;br /&gt;Don't know what time until Monday night, as they need to keep their schedule flexible until the day before.&lt;br /&gt;A biopsy for sure, and removal of as much as seems prudent, hopefully all of it.&lt;br /&gt;He can't say for sure until he's in there exactly what can come out and has to stay.&lt;br /&gt;Apparently I'll be conscious while he's operating, so he can double-check various brain bits aren't tied to anything important based on what twitches when he touches it or something.&lt;br /&gt;I'd rather just be knocked out and wake up healed, but I'm sure not gonna argue brain surgery.&lt;br /&gt;I'll probably/maybe have paralyzed hands for a week or so.&lt;br /&gt;Won't have biopsy results for 72 hours after surgery. Guess I'll have a race with the Doc to see if I can walk out of the hospital before he has answers. :-)&lt;br /&gt;Don't be surprised if this blog goes silent from 8/31 through 9/7, give or take...&lt;br /&gt;Thanks for your generous donations!&lt;br /&gt;I'll be swamped in bills soon, so it's much appreciated.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2410713813411587981?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2410713813411587981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2410713813411587981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2410713813411587981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2410713813411587981'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/08/brain-tumor.html' title='Brain Tumor'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-8831371004110321914</id><published>2010-08-24T13:52:00.005-05:00</published><updated>2010-08-24T15:33:40.751-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='donate'/><category scheme='http://www.blogger.com/atom/ns#' term='brain tumor'/><title type='text'>Brain Lesion</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BmA524o-X8w/THQrml1GOkI/AAAAAAAAABg/DcBGASL6KZE/s1600/Screen+shot+2010-08-24+at+3.24.30+PM.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 287px; height: 320px;" src="http://3.bp.blogspot.com/_BmA524o-X8w/THQrml1GOkI/AAAAAAAAABg/DcBGASL6KZE/s320/Screen+shot+2010-08-24+at+3.24.30+PM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5509076186170800706" /&gt;&lt;/a&gt;&lt;br /&gt;On Thursday August 12, I suffered a seizure.&lt;br /&gt;My daughters found me, got Mama, and they all saved my life.&lt;br /&gt;I was rushed to the hospital, where I suffered 3 convulsions before being stabilized in ICU.&lt;br /&gt;I regained consciousness on Saturday August 14th.&lt;br /&gt;After more blood/brain/body tests and scans than I want to list here, they found a lesion in my brain in the frontal(?) posterior lobe.&lt;br /&gt;Apparently, it's not called a tumor until they figure out if it's malignant or not.&lt;br /&gt;I've got a functional MRI, and an MRS (MRI Spectroscopy) in upcoming weeks.&lt;br /&gt;My employer is being incredibly gracious about discretionary rules, and bending over backwards to keep my insurance current.&lt;br /&gt;That said, there are deductibles and living expenses and possibly even a gap coming, depending on how much pressure I can exert on hospitals and labs to expedite things.&lt;br /&gt;I don't really like it, but I've added a "Donate" button over on the right; I'd appreciate any help you can give, whatever you can afford.&lt;br /&gt;I'm not a tax lawyer, but as far as I can figure, an individual like me can't be a non-profit, so it would have to fall under the generic "gift" category on your tax forms...&lt;br /&gt;I'll be in and out of labs and hospitals for a few weeks; I'm not allowed to drive for 6 months (or longer, if I suffer another seizure) and that's just the beginnings of how this complicates things.&lt;br /&gt;Thanks for all your prayers (of any flavor) and support!  I've had a lot of help already from friends and family, and it is much appreciated!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-8831371004110321914?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/8831371004110321914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=8831371004110321914' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8831371004110321914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8831371004110321914'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/08/brain-lesion.html' title='Brain Lesion'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BmA524o-X8w/THQrml1GOkI/AAAAAAAAABg/DcBGASL6KZE/s72-c/Screen+shot+2010-08-24+at+3.24.30+PM.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-269963365486172121</id><published>2010-06-01T09:41:00.002-05:00</published><updated>2010-06-01T09:46:20.289-05:00</updated><title type='text'>Sprint Sample Silliness</title><content type='html'>Only Sprint could deliver a camera phone, chock-full of Sample Pictures, which are LOCKED and you cannot DELETE, so you can't take more than ~6 pictures.&lt;br /&gt;&lt;br /&gt;And their tech support has no idea how to unlock/delete them.&lt;br /&gt;&lt;br /&gt;Innumerable forum threads asking how to delete them exist.&lt;br /&gt;&lt;br /&gt;And the only solution appears to be to download the phone OS, hack into it with a JavaLoader or by mounting it on your computer, finding some oddly-named .cod file, and deleting that file before you install the OS.&lt;br /&gt;&lt;br /&gt;But the name of the file is version-dependent, and deleting the wrong file gives you a dead phone.&lt;br /&gt;&lt;br /&gt;And, really, how tricky can it BE to give users an "unlock" button or just make the sample pictures not locked in the first place?!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-269963365486172121?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/269963365486172121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=269963365486172121' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/269963365486172121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/269963365486172121'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2010/06/sprint-sample-silliness.html' title='Sprint Sample Silliness'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-6950482186904173510</id><published>2009-10-30T09:58:00.002-05:00</published><updated>2009-10-30T10:06:29.888-05:00</updated><title type='text'>PHP, Frames, and Sessions</title><content type='html'>Any time you try to use frames and PHP sessions, you are likely to run into trouble.&lt;br /&gt;&lt;br /&gt;It's basically a &lt;a href="http://en.wikipedia.org/wiki/Race_Condition"&gt;race condition&lt;/a&gt; just waiting to blow up in your face:&lt;br /&gt;&lt;br /&gt;1. Frame A sends HTTP request, with no session Cookie&lt;br /&gt;2. PHP/server processes request, with no session Cookie, so creates NEW session&lt;br /&gt;3. Frame B sends HTTP request, with no session Cookie&lt;br /&gt;4. Frame A receives response, with session Cookie from Step 2.&lt;br /&gt;5. PHP/server processes request, with no session Cookie, so creates NEW session&lt;br /&gt;6. Frame B receives response, with different session Cookie from Step 5.&lt;br /&gt;&lt;br /&gt;See Step 4 the browser *gets* the cookie it needed in step 3 for there to be just ONE session?&lt;br /&gt;&lt;br /&gt;Your best bet is to initialize the session in a frame-less landing page, and then move forward with frames.  Once the user has the session Cookie, all the frames can "share" it.&lt;br /&gt;&lt;br /&gt;You'll have to redirect a session-less user to that frame-less page and back again, however, which uses up a lot of HTTP connections, and so is resource-intensive.&lt;br /&gt;&lt;br /&gt;Note that Frame A and Frame B steps could actually interleave in ANY order, really. Each request is completely independent of the other.&lt;br /&gt;&lt;br /&gt;And *some* orderings are actually going to "work", so you may not find this bug until your server gets busy enough that HTTP requests/responses start to lag a little bit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-6950482186904173510?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/6950482186904173510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=6950482186904173510' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6950482186904173510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6950482186904173510'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/10/php-frames-and-sessions.html' title='PHP, Frames, and Sessions'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-7887422307244817770</id><published>2009-10-27T21:34:00.002-05:00</published><updated>2009-10-27T21:36:11.914-05:00</updated><title type='text'>Tethercommute</title><content type='html'>Being in the job market, I'd like to make a modest proposal to HR and recruiters:&lt;br /&gt;&lt;br /&gt;Please label jobs where telecommute has geographical restrictions such as "same city" as "tethercommute".&lt;br /&gt;&lt;br /&gt;I realize, of course, that coining such a term is no guarantee that it will be accepted in wide usage, but I doubt that anybody is going to misinterpret it.&lt;br /&gt;&lt;br /&gt;Thanks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-7887422307244817770?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://l-i-e.com/resume.htm' title='Tethercommute'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/7887422307244817770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=7887422307244817770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7887422307244817770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7887422307244817770'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/10/tethercommute.html' title='Tethercommute'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-3428502846090906348</id><published>2009-10-26T09:03:00.004-05:00</published><updated>2009-10-26T09:51:51.102-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sprint'/><category scheme='http://www.blogger.com/atom/ns#' term='Sprint Sucks'/><category scheme='http://www.blogger.com/atom/ns#' term='Nextel'/><category scheme='http://www.blogger.com/atom/ns#' term='daylight savings time'/><category scheme='http://www.blogger.com/atom/ns#' term='DST'/><title type='text'>Dear Sprint; Please update your time servers.</title><content type='html'>As you may know, I hate daylight savings.  It doesn't save anything anymore, if it ever did.&lt;br /&gt;&lt;br /&gt;And it's a royal pain.&lt;br /&gt;&lt;br /&gt;It's particularly painful to me, since my cell phone is my alarm clock.&lt;br /&gt;&lt;br /&gt;And apparently, Sprint / Nextel has &lt;span style="font-weight:bold;"&gt;still&lt;/span&gt; not clued in to the fact that the &lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Energy_Policy_Act_of_2005#Change_to_daylight_saving_time"&gt;United States Congress has changed the dates on which clocks are changed&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is particularly irksome, since I have duly informed Sprint / Nextel of this fact twice a year, every year, since 2007.&lt;br /&gt;&lt;br /&gt;Yes, I know I could change the option to take my cell phone off of network server time, and rely on its internal time clock.  Unfortunately, the cell phone then lags a minute or two eventually, since it is not synched with a reliable time source.&lt;br /&gt;&lt;br /&gt;For $100+ a month, Sprint can find somebody with a clue to update the time zone data on their time servers!&lt;br /&gt;&lt;br /&gt;If anybody reads this post and has any contacts at Sprint that can resolve this, please feel free to contact me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3428502846090906348?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3428502846090906348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3428502846090906348' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3428502846090906348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3428502846090906348'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/10/dear-sprint-please-update-your-time.html' title='Dear Sprint; Please update your time servers.'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2934014089825900768</id><published>2009-06-03T11:53:00.003-05:00</published><updated>2009-07-07T10:06:32.329-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='facebook'/><title type='text'>Facebook Performance</title><content type='html'>I've been logging calls to Facebook API servers in my DEV environment for some weeks now.&lt;br /&gt;&lt;br /&gt;I'm pretty disappointed by the performance, overall:&lt;br /&gt;&lt;a href="http://l-i-e.com/fbapi_stats.htm"&gt;Facebook API Call Performance Stats&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I realize Facebook has scalability issues beyond my ken, but they also have resources beyond my ken as well...&lt;br /&gt;&lt;br /&gt;Facebook doesn't wait over 4 seconds for my server; Surely I shouldn't have to wait 30 seconds for theirs! :-)&lt;br /&gt;&lt;br /&gt;In fact, it's kind of pointless in the context of a canvas page for their servers to bother to respond at all after 4 seconds...&lt;br /&gt;&lt;br /&gt;User --A--&gt; Facebook server request canvas page --B--&gt; Request to my server --C--&gt; API Call to Facebook server.&lt;br /&gt;&lt;br /&gt;If C can detect that we are in the context of a canvas page, and Facebook already &lt;span style="font-weight:bold;"&gt;knows&lt;/span&gt; that B will not wait more than X seconds, they might as well issue an HTTP 408 Request Timeout or something similar after X seconds, because there's no real point in them giving me the info they aren't going to wait for...&lt;br /&gt;&lt;br /&gt;I went ahead and created a Feature Request in Facebook's Bugzilla. You can vote for it if you think it will help you.&lt;br /&gt;&lt;a href="http://bugs.developers.facebook.com/show_bug.cgi?id=5528"&gt;#5528&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2934014089825900768?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://l-i-e.com/fbapi_stats.htm' title='Facebook Performance'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2934014089825900768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2934014089825900768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2934014089825900768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2934014089825900768'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/06/facebook-performance.html' title='Facebook Performance'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-5532000516705955837</id><published>2009-05-14T13:05:00.002-05:00</published><updated>2009-05-14T13:07:52.917-05:00</updated><title type='text'>svn diff in vim</title><content type='html'>In the category of "How did I live without this?!" tools, I'm late to the party with this vim plugin from Brian Shire of Facebook / APC / PHP fame:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/ghewgill/vim-scmdiff/tree/master"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you use svn, git, cvs or similar, this plugin shows you a "diff" in vim.&lt;br /&gt;&lt;br /&gt;I don't know how often I quit vi or open another shell just to do a diff.&lt;br /&gt;&lt;br /&gt;Now, I don't have to!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-5532000516705955837?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://github.com/ghewgill/vim-scmdiff/tree/master' title='svn diff in vim'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/5532000516705955837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=5532000516705955837' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5532000516705955837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5532000516705955837'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/05/svn-diff-in-vim.html' title='svn diff in vim'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2892554492068052790</id><published>2009-02-14T17:44:00.003-06:00</published><updated>2009-02-14T17:51:56.023-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cook country'/><category scheme='http://www.blogger.com/atom/ns#' term='chicago'/><category scheme='http://www.blogger.com/atom/ns#' term='taxes'/><category scheme='http://www.blogger.com/atom/ns#' term='lumni I likovski'/><category scheme='http://www.blogger.com/atom/ns#' term='home ownership'/><title type='text'>Lumni I Likovski, Cook County Assessor's Office</title><content type='html'>&lt;p&gt;ADVERTISEMENT: &lt;a href="http://l-i-e.com/resume.htm"&gt;Hire Me&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;So the other day, I had to go down and file for a home owner's exemption on my house.&lt;br /&gt;&lt;br /&gt;I got my little queue ticket #96.  They were calling out #32, with 5 or 6 workstations.&lt;br /&gt;&lt;br /&gt;I had a half hour, max, to get this done, before I had to be elsewhere.&lt;br /&gt;&lt;br /&gt;This did not look good...&lt;br /&gt;&lt;br /&gt;Thank God for Lumni I. Likovski, Manager, Taxpayer Exemptions.&lt;br /&gt;&lt;br /&gt;He was out in the waiting area, checking for people who didn't need a full-blown computer workstation (such as myself) and doing "triage" to get us the forms we needed, get our questions answered, and get us out of there.&lt;br /&gt;&lt;br /&gt;He even cheerfully (and I stress cheerfully) photocopied my Driver's License for me, a requirement to hand in the form.&lt;br /&gt;&lt;br /&gt;It's not often in this day and age that you get excellent service/help like this, most especially from government staff.&lt;br /&gt;&lt;br /&gt;So I'm dedicating this blog post to LUMNI I LIKOVSKI down that at Cook County.  I owe you a beer!&lt;br /&gt;&lt;br /&gt;PS&lt;br /&gt;I tried to just send in a comment to his boss using their online form, but it blows up like this, every time I try to submit it:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Database Results Error&lt;br /&gt;Description: The conversion of char data type to smalldatetime data type resulted in an out-of-range smalldatetime value.&lt;br /&gt;Number: -2147217913 (0x80040E07)&lt;br /&gt;Source: Microsoft OLE DB Provider for SQL Server&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Maybe they should hire me to re-do their website? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2892554492068052790?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2892554492068052790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2892554492068052790' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2892554492068052790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2892554492068052790'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2009/02/lumni-i-likovski-cook-county-assessors.html' title='Lumni I Likovski, Cook County Assessor&apos;s Office'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-1399960509803286901</id><published>2008-07-21T21:28:00.002-05:00</published><updated>2008-07-21T21:32:31.990-05:00</updated><title type='text'>Webgrind ROCKS</title><content type='html'>Okay, so I'm a Linux guy through and through, and I'd love nothing more at my day job than to wipe the Doze desktop and throw Gentoo or Debian or FreeBSD or even Fedora on it...&lt;br /&gt;&lt;br /&gt;Shoot, I'd even be happy to dual boot the thing.&lt;br /&gt;&lt;br /&gt;But my current day job is the kinda job where I can't even surf to my own blog at work, because it's blocked.&lt;br /&gt;&lt;br /&gt;So, being stuck with Doze [shudder], I was Oh. My. God. happy to find this gem:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/webgrind/"&gt;Webgrind&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's kind of like kCacheGrind, only a lot less features and through a browser and dog-slow.&lt;br /&gt;&lt;br /&gt;But so what?!&lt;br /&gt;&lt;br /&gt;The POINT is, I can actually successfully profile my code with &lt;a href="http://xdebug.org/"&gt;Xdebug&lt;/a&gt; for the first time ever on Windows without jumping backwards through flaming hoops!&lt;br /&gt;&lt;br /&gt;Now if I could just get JIT debugger client to happen...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-1399960509803286901?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://code.google.com/p/webgrind/' title='Webgrind ROCKS'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/1399960509803286901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=1399960509803286901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/1399960509803286901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/1399960509803286901'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2008/07/webgrind-rocks.html' title='Webgrind ROCKS'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-4242204953694402239</id><published>2008-05-08T08:41:00.003-05:00</published><updated>2008-05-08T09:10:12.309-05:00</updated><title type='text'>G is smart!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; is smart.  I mean, &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; is really really smart.&lt;br /&gt;I ask &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; a lot of questions, and &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; often knows the answer.&lt;br /&gt;Of course, sometimes &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; doesn't.  Though that often turns out later to be that I just didn't ask the question the right way.&lt;br /&gt;Sometimes &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; gives me a lot of extra information.  But that's okay.  Sometimes &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt;'s extra information teaches me something. And sometimes it's strictly for entertainment value, which is also okay.&lt;br /&gt;And &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s1600-h/g.jpg"&gt;&lt;img style="display:inline; margin:0 0px 0px 0;cursor:pointer; cursor:hand; vertical-align: text-bottom;" src="http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s320/g.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5198002203323600978" /&gt;&lt;/a&gt; likes multi-color rainbow-y things, which is cool.&lt;br /&gt;&lt;br /&gt;Now, I've got just one question for you:  Am I talking about Google, or my girlfriend?&lt;br /&gt;&lt;br /&gt;Is Google an Artificial Intelligence?&lt;br /&gt;&lt;br /&gt;I'm serious here.&lt;br /&gt;&lt;br /&gt;Is Google's spidering, indexing, search, and response algorithms, in toto, an Artificial Intelligence?&lt;br /&gt;&lt;br /&gt;It doesn't know what I'm supposed to be doing Saturday night, for example.&lt;br /&gt;&lt;blockquote&gt;[Girlfriend interjects] Mother's Day dinner at Indie Cafe&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Hmmmm.  Now that she's added that, Google &lt;strong&gt;does&lt;/strong&gt; know what I'm supposed to be doing Saturday night!&lt;br /&gt;&lt;br /&gt;So clearly Google learns, and learns quickly...&lt;br /&gt;&lt;br /&gt;I dunno.&lt;br /&gt;&lt;br /&gt;I still think my girlfriend is smarter than Google...  But I'm not so sure Google isn't pretty smart.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-4242204953694402239?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/4242204953694402239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=4242204953694402239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/4242204953694402239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/4242204953694402239'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2008/05/g-is-smart.html' title='G is smart!'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_BmA524o-X8w/SCMDdrbNEFI/AAAAAAAAAAM/IJvTWKnxbnc/s72-c/g.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-5924271673211616265</id><published>2008-04-17T10:36:00.003-05:00</published><updated>2008-04-17T10:43:43.571-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vi'/><category scheme='http://www.blogger.com/atom/ns#' term='screen'/><category scheme='http://www.blogger.com/atom/ns#' term='Un*x'/><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><category scheme='http://www.blogger.com/atom/ns#' term='Unix'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenSolaris'/><category scheme='http://www.blogger.com/atom/ns#' term='terminal'/><category scheme='http://www.blogger.com/atom/ns#' term='Solaris'/><category scheme='http://www.blogger.com/atom/ns#' term='putty'/><title type='text'>Solaris vi input mode arrow keys fix</title><content type='html'>This blog post is not for you to read.&lt;br /&gt;&lt;br /&gt;It's for me.&lt;br /&gt;&lt;br /&gt;You see, every once in a awhile, I work for a client/employer who uses Solaris, OpenSolaris, Unix, or some other traditional Unix-like OS.&lt;br /&gt;&lt;br /&gt;They have their reasons, and they are good ones, and I'm fine with that.&lt;br /&gt;&lt;br /&gt;Alas, I then usually waste about an hour of their time (and they pay me for it) to Google for the hack that makes vi (my editor of choice) actually usable from a terminal program (putty, usually).&lt;br /&gt;&lt;br /&gt;To wit, the arrow keys in vi do not work in input mode under these OSes.&lt;br /&gt;&lt;br /&gt;This blog post is a reminder for ME to know what the heck to do next time this happens.&lt;br /&gt;&lt;br /&gt;So here is what I do:&lt;br /&gt;Open up ~/.exrc and type these things:&lt;br /&gt;set t_ku=[control-v][up-arrow]&lt;br /&gt;set t_kd=[control-v][down-arrow]&lt;br /&gt;set t_kr=[control-v][right-arrow]&lt;br /&gt;set t_kl=[control-v][left-arrow]&lt;br /&gt;&lt;br /&gt;Then make a symlink from .exrc to .vimrc&lt;br /&gt;ln -s ~/.exrc ~/.vimrc&lt;br /&gt;&lt;br /&gt;Finally, alias vi to vim, since this only works for vim:&lt;br /&gt;alias vi=vim&lt;br /&gt;&lt;br /&gt;Bonus Tip:&lt;br /&gt;To get vi/vim to use more than ONE LINE when you start up, use:&lt;br /&gt;TERM=putty screen&lt;br /&gt;&lt;br /&gt;I believe "screen" is magical pixie dust that gives you a whole screen of line instead of one line, and the TERM stuff obviously tells screen that you need that screen to go to putty.&lt;br /&gt;&lt;br /&gt;If "man screen" had been installed, perhaps I would have a better understanding of the magical pixie dust, but so it goes.&lt;br /&gt;&lt;br /&gt;:-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-5924271673211616265?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/5924271673211616265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=5924271673211616265' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5924271673211616265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/5924271673211616265'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2008/04/solaris-vi-input-mode-arrow-keys-fix.html' title='Solaris vi input mode arrow keys fix'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-2734912043984800126</id><published>2007-09-13T00:26:00.001-05:00</published><updated>2009-07-21T10:09:53.934-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adobe'/><category scheme='http://www.blogger.com/atom/ns#' term='sucks'/><category scheme='http://www.blogger.com/atom/ns#' term='spam'/><category scheme='http://www.blogger.com/atom/ns#' term='Flash'/><title type='text'>Adobe Spams</title><content type='html'>Update:&lt;br /&gt;Today, July 21, 2009, Adobe has once again resurrected the email I gave them in 2007, and has spammed it.&lt;br /&gt;&lt;br /&gt;I say again:  Adobe spams, boycott Adobe.&lt;br /&gt;&lt;br /&gt;For the record:&lt;br /&gt;&lt;br /&gt;I &lt;span style="font-weight:bold;"&gt;loathe&lt;/span&gt; Flash.&lt;br /&gt;&lt;br /&gt;I mean, even on Windows where it kind of sort of works, it sucks up WAY too much RAM, and WAY too much CPU, and crashes far too often.&lt;br /&gt;&lt;br /&gt;Not that anything really works well on Windows (other than their Marketing, Legal, and Bullying Departments) but Flash works particularly badly.&lt;br /&gt;&lt;br /&gt;On Linux?  Forget it.&lt;br /&gt;&lt;br /&gt;I gave up installing the damn thing, even on Windows, about a year ago, and you know what?&lt;br /&gt;&lt;br /&gt;I have found that there is not one site with any content worth getting that I am missing out, that I can't find elsewhere.&lt;br /&gt;&lt;br /&gt;Maybe your experience is different; Maybe you just can't live without uTube.&lt;br /&gt;&lt;br /&gt;Fine.&lt;br /&gt;&lt;br /&gt;But for me, no more Flash, ever again.&lt;br /&gt;&lt;br /&gt;Oh yeah, the &lt;span style="font-weight:bold;"&gt;real&lt;/span&gt; reason I hate Adobe is that they are spammers.&lt;br /&gt;&lt;br /&gt;They added me to their mailing list, unsolicited, and sent me commercial junk mail.&lt;br /&gt;&lt;br /&gt;So unless you want to support spammers, stop using their products.&lt;br /&gt;&lt;br /&gt;It's that simple.&lt;br /&gt;&lt;br /&gt;Thank you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-2734912043984800126?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/2734912043984800126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=2734912043984800126' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2734912043984800126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/2734912043984800126'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/09/adobe-spams.html' title='Adobe Spams'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-3293992259593813898</id><published>2007-07-17T18:24:00.000-05:00</published><updated>2007-07-17T18:27:33.115-05:00</updated><title type='text'>File Upload Progress Meter</title><content type='html'>Every week or two, somebody asks how to do a File Upload Progress Meter on the PHP-General mailing list...&lt;br /&gt;&lt;br /&gt;Why the BROWSER doesn't provide this feature everybody wants is beyond&lt;br /&gt;my ken.&lt;br /&gt;&lt;br /&gt;Surely the browser has some clue how many bytes are uploaded and how&lt;br /&gt;big the file was.&lt;br /&gt;&lt;br /&gt;How tricky could it be for Firefox/IE to poke those values into a&lt;br /&gt;couple variables somewhere?&lt;br /&gt;&lt;br /&gt;Instead we have a zillion JS hacks by developers generating tons of&lt;br /&gt;traffic back-n-forth to the server to ask it how many bytes it has&lt;br /&gt;received so far...&lt;br /&gt;&lt;br /&gt;In fact, why don't the browsers provide a NICE file upload progress meter in the first place, so web designers don't feel the need to re-invent the wheel?&lt;br /&gt;&lt;br /&gt;Or even (gasp) some nice hooks involving CSS and Web 2.0 or whatever so web designers can just do this without even needing to know any Javascript?&lt;br /&gt;&lt;br /&gt;This certainly would be way more useful than half the crap the browser wars have introduced in the past half decade that we've been needing this feature!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3293992259593813898?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3293992259593813898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3293992259593813898' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3293992259593813898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3293992259593813898'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/07/file-upload-progress-meter.html' title='File Upload Progress Meter'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-8656113182344899604</id><published>2007-07-12T23:18:00.001-05:00</published><updated>2007-07-12T23:46:15.526-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='celebrityaccess'/><category scheme='http://www.blogger.com/atom/ns#' term='facebook'/><category scheme='http://www.blogger.com/atom/ns#' term='social networking sites'/><category scheme='http://www.blogger.com/atom/ns#' term='constantcontact'/><category scheme='http://www.blogger.com/atom/ns#' term='myspace'/><title type='text'>Too Many "Friends"</title><content type='html'>Bear with me here, there's a fairly long prologue...&lt;br /&gt;&lt;br /&gt;So, here's the thing:&lt;br /&gt;&lt;br /&gt;In one of my alter egos, I'm a Talent Buyer at a music venue.&lt;br /&gt;&lt;br /&gt;Now, you may not know much about the internal workings of music venues, but, basically, a music venue has about 1000 bands pounding on the doors wanting to play for every available position.&lt;br /&gt;&lt;br /&gt;There's nothing we'd love more than for there to be way more fans out there, mind you, so we could actually accommodate about 100 of those artists, instead of just he 1.&lt;br /&gt;&lt;br /&gt;Do note that I said 100 of the 1000, not all of them...&lt;br /&gt;&lt;br /&gt;90% of everything is still crap.&lt;br /&gt;&lt;br /&gt;Anyway, at the email address we've set up specifically for artists to submit a demo, we tend to get a whole lot of friend-link requests to basically all the big social networking sites.&lt;br /&gt;&lt;br /&gt;Now, this is going to sound petty, but it's getting pretty dang annoying.&lt;br /&gt;&lt;br /&gt;Most of these friend link requests are coming from artists we don't work with.&lt;br /&gt;&lt;br /&gt;Many of them are coming from artists we simply can't work with, as they're not the 1 in a thousand.&lt;br /&gt;&lt;br /&gt;I daresay a lot of them are coming from the 900 we wouldn't want to work with, even if the the supply/demand went the other way, with way more fans than artists...&lt;br /&gt;&lt;br /&gt;Our website pretty clearly asks bands not to add us to their promotional mailing lists.  Do we really need to spell it out "and don't send us be-my-friend emails either"?&lt;br /&gt;&lt;br /&gt;Anyway, I'm thinking that all these social networking sites should just stop sending out emails on behalf of their users to non-users to invite them to join.&lt;br /&gt;&lt;br /&gt;If I want to join your social-networking site, and buy into the whole thing, then fine, I've agreed to get your emails.&lt;br /&gt;&lt;br /&gt;But I haven't!&lt;br /&gt;&lt;br /&gt;So, really, all these social-networking sites are just thinly-disguised spammers, when you get down to it.&lt;br /&gt;&lt;br /&gt;Or maybe there should be some kind of industry-standard minimum proof that the recipient might actually want these dang things, or that the sender actually has an existing relationship.&lt;br /&gt;&lt;br /&gt;Knowing an email address is not an existing relationship!&lt;br /&gt;&lt;br /&gt;Because it's gotten to the point where a new entrant in the social networking market, to me, just means yet another flurry of invites that I don't really want.&lt;br /&gt;&lt;br /&gt;Then I have to spend 20 minutes digging through their site for a place to contact them to say not only to ban that one user from sending me emails, but to ban ALL the users from ever sending me emails.&lt;br /&gt;&lt;br /&gt;I don't even want the dang things at my personal address anymore, really, from friends I actually know.  It's gotten that bad.&lt;br /&gt;&lt;br /&gt;I definitely don't want them from strangers to an email address that was set up for a very specific business purpose.&lt;br /&gt;&lt;br /&gt;Am I being too petty?&lt;br /&gt;&lt;br /&gt;I don't think so.&lt;br /&gt;&lt;br /&gt;We came up with guidelines for the robots, and that seems to have (mostly) worked out.&lt;br /&gt;&lt;br /&gt;Can't we come up with guidelines for these social networking / stay in touch sites?&lt;br /&gt;&lt;br /&gt;Here are some suggested starting points for guidelines:&lt;br /&gt;&lt;br /&gt;If I'm not a member of your site, don't email me more than one invite ever, period.&lt;br /&gt;&lt;br /&gt;If I didn't want to join when Lee invited me, I still don't want to join when Fran invites me, okay?&lt;br /&gt;&lt;br /&gt;The invite email should provide links including:&lt;br /&gt;&amp;nbsp; &amp;nbsp; ban this user from ever emailing me again&lt;br /&gt;&amp;nbsp; &amp;nbsp; ban all users from ever emailing me&lt;br /&gt;&amp;nbsp; &amp;nbsp; accept invitation&lt;br /&gt;&amp;nbsp; &amp;nbsp; decline invitation, but join site&lt;br /&gt;&lt;br /&gt;Perhaps there should also be a "do not social-network-invite" shared database maintained by the larger existing social networking sites, which other social networking sites could pay a reasonable fee on a per email basis to check against, and a person could register with that one place to not get any invites from any social networking site.&lt;br /&gt;&lt;br /&gt;Note that the fee should be large enough to make it prohibitive for spammers to just pay up to garner emails, that it should not actually hand out email addresses but return a YES/NO for a submitted address from the social networking site, but be cheap enough that any serious new social networking site would buy in as a matter of course.  Maybe there is no such price-point, but at least give it some thought.&lt;br /&gt;&lt;br /&gt;I sure don't want to keep contacting every johnny-come-lately social networking site to ask them to put a ban on their users sending me invites.  There are too many of them springing up like weeds.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-8656113182344899604?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/8656113182344899604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=8656113182344899604' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8656113182344899604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/8656113182344899604'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/07/too-many-friends.html' title='Too Many &quot;Friends&quot;'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-7455420510931327540</id><published>2007-07-11T16:24:00.000-05:00</published><updated>2007-07-11T16:31:14.505-05:00</updated><title type='text'>PHP in HTML</title><content type='html'>How come this doesn't work:&lt;br /&gt;&amp;lt;button action='&amp;lt;?php mysqli_query($connect,$query)?&amp;gt;'&amp;gt;Click&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;br /&gt;[sportscaster voice-over]&lt;br /&gt;&lt;br /&gt;Joe: Hey Bob, let's look at a slow-motion instant-replay of this common PHP newbie fallacy scenario.&lt;br /&gt;Bob: Sure Joe!&lt;br /&gt;Joe: Okay, so here goes:&lt;br /&gt;&amp;nbsp;&amp;nbsp;The user requests a HTTP URL document.&lt;br /&gt;&amp;nbsp;&amp;nbsp;The webserver fires up.&lt;br /&gt;&amp;nbsp;&amp;nbsp;The webserver finds that it needs PHP to generate the document.&lt;br /&gt;&amp;nbsp;&amp;nbsp;PHP fires up.&lt;br /&gt;Bob: Wow, look at PHP go!  That's fast!&lt;br /&gt;Joe: Yeah, it is fast.&lt;br /&gt;&amp;nbsp;&amp;nbsp;PHP has generated the document, and spits it out.&lt;br /&gt;Bob: Boy, it's already finished.  Hey, it's quit!&lt;br /&gt;Joe: That's right, Bob.&lt;br /&gt;&amp;nbsp;&amp;nbsp;PHP has FINISHED EXECUTION, and has exited.&lt;br /&gt;&amp;nbsp;&amp;nbsp;Now watch this!&lt;br /&gt;Bob: Oh boy, I see it coming now...&lt;br /&gt;Joe: Yep, there it is.&lt;br /&gt;&amp;nbsp;&amp;nbsp;There's some HTML in the browser, trying to execute some PHP code...&lt;br /&gt;Bob: But you can see, PHP has LONG FINISHED and is OUTTA HERE!!!&lt;br /&gt;Joe: That's right, Bob, PHP is simply not around to execute that code.&lt;br /&gt;Bob: So what can you do, Joe?&lt;br /&gt;Joe: Well, if you can live with the browser going back-n-forth to the web-server, with a significant "lag" time...&lt;br /&gt;Bob: Oooh, well, I can see how that might be useful sometimes...&lt;br /&gt;Joe: In those cases, you can use Ajax.&lt;br /&gt;Bob: Anything else?&lt;br /&gt;Joe: Not really.  Until you get back to the webserver and PHP, there's just no PHP available.  Unless your user is in the extreme minority of uber-PHP-geeks that has installed this EXPERIMENTAL PHP browser plug-in thingie: http://pecl.php.net/package/PHPScript&lt;br /&gt;Bob: Whoa, Joe, I don't think I've ever even heard of anybody who's ever installed that.&lt;br /&gt;Joe: Me neither, though I met Wez Furlong who wrote it, so I have to assume HE has installed it at least once...&lt;br /&gt;&lt;br /&gt;[cue to cool Guinness commercial]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-7455420510931327540?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/7455420510931327540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=7455420510931327540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7455420510931327540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/7455420510931327540'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/07/php-in-html.html' title='PHP in HTML'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-6424533960300193770</id><published>2007-07-07T00:14:00.000-05:00</published><updated>2007-07-07T00:40:05.435-05:00</updated><title type='text'>PHP Microsoft Excel Reader and Serial Killer Dates</title><content type='html'>So, my sister's ex-company of about 6 years that has shut down operations, but still has outstanding loan accounts to collect on...&lt;br /&gt;&lt;br /&gt;They have this arcane accounting system and it generates fixed-width field .TXT files, with the wrong dates (with 2-digit year, of course).&lt;br /&gt;&lt;br /&gt;The correct dates are in some Excel spreadsheets.&lt;br /&gt;&lt;br /&gt;So they wanted a quick hack script to change columns 254 through 259 in some .TXT files based on a simple lookup in some Excel files.&lt;br /&gt;&lt;br /&gt;Some developer told them it would take two weeks, and my sister didn't believe that, and they weren't real keen on spending that much $$$.&lt;br /&gt;&lt;br /&gt;I told her it was more like a 2 hour job, which might turn into 2 days, when all is said and done.&lt;br /&gt;&lt;br /&gt;It actually only took about 8 hours, all told, and most of that was spent in attempting to use various Excel reader PHP scripts that just plain didn't work.&lt;br /&gt;&lt;br /&gt;The one up on PHPClasses ends up using parse_url to try to figure out where a local file is, and bombs out.  It's a really nifty stream-filter OOP thingie, if it only actually worked...&lt;br /&gt;&lt;br /&gt;And what's with all the annoying ads?  Maybe less ads would get more traffic would get more revenue... [shrug]&lt;br /&gt;&lt;br /&gt;There were several Excel Reader commercial options in the $100 to $200 range, which didn't appeal at all.&lt;br /&gt;&lt;br /&gt;There's an Excel Writer in the &lt;a href="http://pear.php.net/"&gt;PEAR Repository&lt;/a&gt;, but I couldn't see how to make it read Excel files.&lt;br /&gt;&lt;br /&gt;There was some other Excel Reader script, but I forget now why I rejected it.  Oh well.&lt;br /&gt;&lt;br /&gt;Finally, I found &lt;a href="http://sourceforge.net/projects/phpexcelreader/"&gt;an Excel Reader PEAR package&lt;/a&gt;, only it's on Sourceforge instead of in PEAR.&lt;br /&gt;&lt;br /&gt;Go figure.&lt;br /&gt;&lt;br /&gt;It also had a bug, where it was doing an include of 'OLERead.php' but the file was actually named 'OLERead.inc'&lt;br /&gt;&lt;br /&gt;Not quite sure how that passed by a QA process, &lt;span style="font-weight:bold;"&gt;any QA process&lt;/span&gt; but it's trivial to fix.&lt;br /&gt;&lt;br /&gt;I did submit a bug report, so hopefully it will get fixed.  That is the nice thing about OpenSource.&lt;br /&gt;&lt;br /&gt;The example to read a whole sheet in as an array was pretty much all I needed after that quick '.php' -&gt; '.inc' hack.&lt;br /&gt;&lt;br /&gt;I didn't even try the reading as a stream thing, since there are only a few thousand accounts.&lt;br /&gt;&lt;br /&gt;So I had a nice Excel Reader to do the account number to date lookup.&lt;br /&gt;&lt;br /&gt;Yippee.&lt;br /&gt;&lt;br /&gt;Then came the joy of Microsoft Excel internal date format...&lt;br /&gt;&lt;br /&gt;It's basically a "count" of days from January 1 1900 for the integer part, and a count of seconds for the fractional/decimal part.&lt;br /&gt;&lt;br /&gt;Of course, Microsoft aped Lotus 123 and knowingly left in the bug of 1900 being a leap year (it's not)!&lt;br /&gt;&lt;br /&gt;So from 0 to 60, the date is "off" by one, and at 60, the bogus date of February 29, 1900 is output.  Everything is great from 61 up to a zillion or so where you get to December 31, 9999.&lt;br /&gt;&lt;br /&gt;Now, granted, none of these loans date back to the first couple months of 1900, but it's still pretty irksome...&lt;br /&gt;&lt;br /&gt;And you'd want a conversion function to be correct and re-usable, rather than something that only works for a limited input set. (Y2K anybody?)&lt;br /&gt;&lt;br /&gt;I found a conversion function in C, and ported it to PHP:&lt;br /&gt;&lt;a href="http://l-i-e.com/excel_date.phps"&gt;http://l-i-e.com/excel_date.phps&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm not claiming it's the best code ever, and I don't even know what it does, really, as I just changed the variables to have $ in front, and swapped int() function into floor() function.&lt;br /&gt;&lt;br /&gt;Slapped in an sprintf instead of returning the individual month/day/year as pass-by-access args, since it seemed easier.&lt;br /&gt;&lt;br /&gt;That pretty much sums up the past couple evenings for me.&lt;br /&gt;&lt;br /&gt;I occasionally run into a Microsoft devotee who wonders why I hate Microsoft so much.&lt;br /&gt;&lt;br /&gt;Really, if this rant doesn't make it clear why I hate Microsoft, I simply cannot hold a rational conversation with you...&lt;br /&gt;&lt;br /&gt;It &lt;span style="font-weight:bold;"&gt;would&lt;/span&gt; have been a 2-hour job if MS wasn't so stupid, but it was an 8-hour job because Microsoft is, well, stupid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-6424533960300193770?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://sourceforge.net/projects/phpexcelreader/' title='PHP Microsoft Excel Reader and Serial Killer Dates'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/6424533960300193770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=6424533960300193770' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6424533960300193770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6424533960300193770'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/07/php-microsoft-excel-reader-and-serial.html' title='PHP Microsoft Excel Reader and Serial Killer Dates'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-3477476803363181029</id><published>2007-07-05T22:00:00.000-05:00</published><updated>2007-07-05T22:06:58.386-05:00</updated><title type='text'>Windows PHP Free Development</title><content type='html'>Zoe Slattery of IBM has documented exactly how a Windows user would go about hacking PHP source with all &lt;span style="font-weight:bold;"&gt;free&lt;/span&gt; development tools.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www-03.ibm.com/developerworks/blogs/page/phpblog"&gt;http://www-03.ibm.com/developerworks/blogs/page/phpblog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure if I should leap with joy or cringe in fear, but now any PHP Windows user could manage to write their own custom extension.&lt;br /&gt;&lt;br /&gt;I managed to stumble through it once, thanks to Sara Goleman's fantastic articles up on Zend.com:&lt;br /&gt;&lt;a href="http://devzone.zend.com/node/view/id/1021"&gt;Extension Writing Part I: Introduction to PHP and Zend&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I wonder how long it will be before Microsoft accidentally on purpose breaks things so you can't do this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-3477476803363181029?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www-03.ibm.com/developerworks/blogs/page/phpblog' title='Windows PHP Free Development'/><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/3477476803363181029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=3477476803363181029' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3477476803363181029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/3477476803363181029'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/07/windows-php-free-development.html' title='Windows PHP Free Development'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-6187047360439709552</id><published>2007-06-14T15:57:00.000-05:00</published><updated>2007-06-14T16:19:46.975-05:00</updated><title type='text'>Refund Policy</title><content type='html'>So I was setting up a new domain today for a website, and for the first time noticed &lt;a href="http://hostbaby.com"&gt;Hostbaby's&lt;/a&gt; Refund Policy at the bottom of their contact page:&lt;br /&gt;&lt;br /&gt;REFUND POLICY: Anyone who wants a refund can get a refund for any reason.&lt;br /&gt;&lt;br /&gt;Made me laugh out loud.&lt;br /&gt;&lt;br /&gt;Now, the thing is, I'm sure some readers are saying "Yeah, right" sarcastically.&lt;br /&gt;&lt;br /&gt;But I've worked with these guys long enough to know, that if that's what they say their policy is, that's actually their policy.&lt;br /&gt;&lt;br /&gt;REFUND POLICY: Anyone who wants a refund can get a refund for any reason.&lt;br /&gt;&lt;br /&gt;You can tell them you want to shut down your site and get a refund because your dog ate your homework, and they'll do it.&lt;br /&gt;&lt;br /&gt;Plus they don't even charge you until a full month, so you get your site up before the billing starts.&lt;br /&gt;&lt;br /&gt;I love this webhost.&lt;br /&gt;&lt;br /&gt;PS They also run &lt;a href="http://cdbaby.com/"&gt;CDBaby.com&lt;/a&gt; where you can buy a zillion Indie CDs, but no major label junk. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-6187047360439709552?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/6187047360439709552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=6187047360439709552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6187047360439709552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6187047360439709552'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/06/refund-policy.html' title='Refund Policy'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-6583945640541800472</id><published>2007-06-13T11:38:00.000-05:00</published><updated>2007-06-13T14:39:02.723-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP header location redirect refresh 301 HTTP protocols'/><title type='text'>PHP header location redirect refresh</title><content type='html'>I haven't posted much, but at php|tek 2007, Chris Shiflett actually said he &lt;span style="font-weight:bold;"&gt;liked&lt;/span&gt; my rant, and that I should post more.&lt;br /&gt;&lt;br /&gt;Well, hey, if Chris Shiflett says I oughta do something, I listen.&lt;br /&gt;&lt;br /&gt;So, today's rant is about PHP header Location hacks.&lt;br /&gt;&lt;br /&gt;First, let's be sure everybody understands what it is:&lt;br /&gt;&lt;br /&gt;header("Location: http://example.com");&lt;br /&gt;&lt;br /&gt;will re-direct the browser to the URL example.com&lt;br /&gt;&lt;br /&gt;Specifically, the PHP tells Apache to issue to the browser a 301 Redirect header to that URL, and then the browser gets that 301 Rediret header and automatically tries to visit that URL.&lt;br /&gt;&lt;br /&gt;EDIT&lt;br /&gt;As pointed out on PHP-General, PHP actually sends a 302 Temporarily Moved rather than a 301 Permanently moved.  The rest of the rant still applies, as I simply mis-typed 301 for 302 anyway.&lt;br /&gt;/EDIT&lt;br /&gt;&lt;br /&gt;Now this seems really cool at first, perhaps because it &lt;span style="font-weight:bold;"&gt;is&lt;/span&gt; really cool, when used for an appropriate problem.&lt;br /&gt;&lt;br /&gt;Unfortunately, many PHP scripters are using this as an Idiom or as a Programming Construct with things like:&lt;br /&gt;&lt;br /&gt;if (!logged_in()){&lt;br /&gt;  header("Location: login.php");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Now, this does "work" but there are several problems with it.&lt;br /&gt;&lt;br /&gt;First and foremost, the HTTP Specs require a &lt;span style="font-weight:bold;"&gt;complete&lt;/span&gt; URI for the location.  And while this fragment of a URI might "work" on most browsers, it will, sooner or later, totally mess you up when the browser mis-interprets this.&lt;br /&gt;&lt;br /&gt;Specifically, some versions of IE will do the redirect, but won't POST the original data as a redirect should, with this URI fragment.  Use the full URL, and IE actually does the right thing, and redirects with all the POST data intact.&lt;br /&gt;&lt;br /&gt;You shouldn't use an incomplete URI just because "it works" any more than you should use non-compliant HTML just because it works.&lt;br /&gt;&lt;br /&gt;But let's look at this header("Location: ") in a slow-motion instant replay:&lt;br /&gt;User requests page X&lt;br /&gt;Browser uses dog-slow Internet to contact web server.&lt;br /&gt;Web server receives request, hands it off to PHP&lt;br /&gt;PHP responds over dog-slow Internet with 301 Redirect to login.php.&lt;br /&gt;Browser interprets 301 Redirect, hopefully correctly.&lt;br /&gt;Browser uses dog-slow Internet to contact web server.&lt;br /&gt;Web server receives request for login.php, hands it off to PHP&lt;br /&gt;PHP finally spits out the login form.&lt;br /&gt;&lt;br /&gt;Whew.&lt;br /&gt;&lt;br /&gt;Maybe you should consider just doing this instead:&lt;br /&gt;&lt;br /&gt;if (!logged_in()){&lt;br /&gt;  require 'login.php';&lt;br /&gt;  exit;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;And look, ma, no extra round trip through the dog-slow Internet.&lt;br /&gt;&lt;br /&gt;Plus, you're not &lt;span style="font-weight:bold;"&gt;wasting&lt;/span&gt; an HTTP connection, which, on a busy server, is a precious resource.  Presumably you'd like your website to be popular enough to be busy someday, right?&lt;br /&gt;&lt;br /&gt;You're going to end up reading the login.php file in the end anyway.  Why would you spend all that time going back and forth to the browser to do it?&lt;br /&gt;&lt;br /&gt;And include 'login.php' is no more difficult to read/understand/maintain than the header().&lt;br /&gt;&lt;br /&gt;Reserve a header("Location: xxx") for when you &lt;span style="font-weight:bold;"&gt;really&lt;/span&gt; need it:  When a document has actually moved and the URL is being retired.&lt;br /&gt;&lt;br /&gt;Don't use header("Location: xxx") as a Programming Construct in place of simple if/else and include logic.&lt;br /&gt;&lt;br /&gt;PS This same rant applies to the header("Refresh: ") usage as well.  Though why you'd want to use that instead of Location: is beyond me, and probably the subject of another rant...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-6583945640541800472?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/6583945640541800472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=6583945640541800472' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6583945640541800472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/6583945640541800472'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2007/06/php-header-location-redirect-refresh.html' title='PHP header location redirect refresh'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-115100604304998571</id><published>2006-06-22T14:08:00.001-05:00</published><updated>2009-07-07T10:01:43.782-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PDF'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='download'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Adobe'/><category scheme='http://www.blogger.com/atom/ns#' term='XSS'/><title type='text'>PHP Downloads, Content-Disposition, Content-type, and other arcana.</title><content type='html'>Every damn day, some other poor PHP newbie goes off and finds "advice" in Google about how to force browsers to download things, and how to get the filename they want in the "Save As..." prompt box.&lt;br /&gt;&lt;br /&gt;Invariably, these newbies are suckered in by Bad Advice&lt;sup&gt;&lt;font size="-2"&gt;tm&lt;/font&gt;&lt;/sup&gt; from people who &lt;span style="font-weight:bold;"&gt;clearly&lt;/span&gt; do not read the HTTP specs.&lt;br /&gt;&lt;br /&gt;Now I'm not claiming to have read &lt;span style="font-weight:bold;"&gt;all&lt;/span&gt; the HTTP specs, much less memorized them, but did fight through this battle in the days of version 3 and 4 browsers, and it &lt;span style="font-style:bold;"&gt;still&lt;/span&gt; seems to be tripping people up, while my solution has been working for me since nineteen-ninety-mumble.&lt;br /&gt;&lt;br /&gt;So I'm gonna let you in on a few little &lt;span style="font-style:italic;"&gt;secrets&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Okay, one of the secrets is widely published in the RFCs, and the other is hard-won experience about how the 1995 johnny-come-lately Microsoft made-up Content-disposition header isn't really widely-supported very well, and how to make 100% certain that your downloads always end up prompting the user for the right filename with a crude but effective hack that leaves the brower with no other reasonable choice.&lt;br /&gt;&lt;br /&gt;First, if you Google for this topic, you're going to find a lot of people suggesting a lot of different MIME-types to use for the "Content-type" header:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;application/octet-stream&lt;br /&gt;application/download&lt;br /&gt;application/force-download&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Note that this is to force a download -- If you actually want a browser to display (or attempt to display) some content, the Content-type: should always be the correct Content-type for that type of document.  E.g. text/html for HTML, image/gif for a GIF, image/jpeg for a JPEG (image/jpg will not work on some browsers), image/png for a PNG, application/pdf for a PDF, and so on.&lt;br /&gt;&lt;br /&gt;If you are ever in doubt about the correct MIME-type for browser display, find a static URL that works, preferably on the corporate site driving that technology, and find out what Content-type: is sent by their site for their sample content.&lt;br /&gt;&lt;br /&gt;For a download, &lt;span style="font-style:italic;"&gt;application/octet-stream&lt;/span&gt; works because it's a part of the HTTP specification, and has been part of the HTTP spec, from the very beginning of HTTP specifications.&lt;br /&gt;&lt;br /&gt;The others "work" only because they are &lt;span style="font-weight:bold;"&gt;made-up&lt;/span&gt; content-types, and the browser currently has  &lt;span style="font-weight:bold;"&gt;no idea&lt;/span&gt; what to do with them.&lt;br /&gt;&lt;br /&gt;Some equally valid Content-type would be:&lt;code&gt;&lt;br /&gt;asdf/asdf&lt;br /&gt;abc/abc&lt;br /&gt;you-can-put/anything-you-want-here&lt;br /&gt;microsoft/sucks&lt;br /&gt;asdfswetrkhkhkvnknsdbknilghwerthiehl/wilerywnfaksvnklgndiglkghadlgha&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Only problem is, &lt;span style="font-weight:bold;"&gt;tomorrow&lt;/span&gt; Microsoft can choose, at their discretion, that "application/download", or any of the other made-up MIME-types means "Put it in the &lt;span style="font-style:italic;"&gt;My documents&lt;/span&gt; directory", because MS knows much better than you that that is what all their users really want, and your download doesn't do what you want any more.&lt;br /&gt;&lt;br /&gt;But they &lt;span style="font-weight:bold;"&gt;cannot&lt;/span&gt; change the meaning of &lt;span style="font-style:italic;"&gt;application/octet-stream&lt;/span&gt;, because that is specifically reserved, in the HTTP specification, for &lt;span style="font-style:italic;"&gt;force a download&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, all of the above boils down to the following question:&lt;br /&gt;&lt;br /&gt;Do you want to use a MIME type that happens, by sheer coincidence, to not be "taken" yet and will work today, but tomorrow might be re-defined?&lt;br /&gt;&lt;br /&gt;Or would you rather use the &lt;span style="font-weight:bold;"&gt;documented feature&lt;/span&gt;  that &lt;span style="font-style:italic;"&gt;appliction/octet-stream&lt;/span&gt; will always work?&lt;br /&gt;&lt;br /&gt;For anybody not well-versed in &lt;span style="font-style:italic;"&gt;Tech-Talk&lt;/span&gt; the correct answer is the latter, and definitely not the former.&lt;br /&gt;&lt;br /&gt;So to force the browser to download a document, the only correct solution is:&lt;code&gt;&lt;br /&gt;Content-type: application/octet-stream&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Anything else is a game of Russian Roulette.&lt;br /&gt;&lt;br /&gt;With Microsoft pulling the trigger.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now we come to the somewhat more complicated issue of getting the "Save As..." window to provide the filename you like as a default.&lt;br /&gt;&lt;br /&gt;Let's assume, for our purposes, that you want this filename:&lt;code&gt;&lt;br /&gt;iwant.xyz&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In an ideal world, the "Content-disposition: ... ;filename=iwant.xyz" would work perfectly for this.&lt;br /&gt;&lt;br /&gt;... represents some sort of MIME-type, which is largely irrelevant, for the purposes of this article about forced downloads.&lt;br /&gt;&lt;br /&gt;Unfortunately, with some versions of some browsers, this Content-disposition: simply will not work.&lt;br /&gt;&lt;br /&gt;In fact, no matter what combinations of headers you try to use, there is &lt;span style="font-weight:bold;"&gt;some&lt;/span&gt; minute version, such as x.y.z.37, that &lt;span style="font-style:italic;"&gt;doesn't work&lt;/span&gt; even though x.y.z.36 and x.y.z.38 &lt;span style="font-style:italic;"&gt;do work&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is complicated by the presence or absence, and/or changes to the Content-type: and the "..." part of Content-disposition: that we're ignoring.&lt;br /&gt;&lt;br /&gt;To document exactly which versions of which browsers do/don't work for which combination of headers, mime-types and URLs is well beyond the scope of a blog post.  Perhaps a Ph.D. Thesis would be more appropriate, if somebody is desparate for a Thesis Topic and has a lot of time to spare.&lt;br /&gt;&lt;br /&gt;And for the love of &lt;span style="font-style:italic;"&gt;insert diety of choice here&lt;/span&gt; do not ask me to tell you which browser/version won't work with your particular &lt;span style="font-style:italic;"&gt;solution&lt;/span&gt;.  I have neither the time nor the inclination to do your browser-testing QA for you.  I don't even like doing my own QA, much less yours.&lt;br /&gt;&lt;br /&gt;I can only guarantee you that if you test on &lt;span style="font-weight:bold;"&gt;every&lt;/span&gt; minor version of &lt;span style="font-weight:bold;"&gt;every&lt;/span&gt; browser ever released, you &lt;span style="font-weight:bold;"&gt;will&lt;/span&gt; find one that does not work.&lt;br /&gt;&lt;br /&gt;But I &lt;span style="font-weight:bold;"&gt;do&lt;/span&gt; have a solution for you:&lt;br /&gt;Provide a URL which the browser cannot &lt;span style="font-weight:bold;"&gt;possibly&lt;/span&gt; mess up.&lt;br /&gt;&lt;br /&gt;For example, this URL &lt;span style="font-weight:bold;"&gt;will&lt;/span&gt; mess up some browsers:&lt;br /&gt;http://example.com/download.php?filename=iwant.xyz&lt;br /&gt;&lt;br /&gt;This URL, however, the browser, cannot possibly mess up:&lt;br /&gt;http://example.com/download/iwant.xyz&lt;br /&gt;because it's too damn simple to mess up.&lt;br /&gt;K.I.S.S. priniciple is the watchword here.&lt;br /&gt;&lt;br /&gt;Don't give the browser any opportunity to screw up.  Because if you do, some browser somewhere &lt;span style="font-weight:bold;"&gt;will&lt;/span&gt; screw up.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"But wait!"&lt;/span&gt;, you say, "&lt;span style="font-style:italic;"&gt;I can't do that! I need my PHP script to do the download work&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Yes, you can.&lt;br /&gt;&lt;br /&gt;Follow the bouncing ball:&lt;br /&gt;&lt;br /&gt;First, 'download' above may &lt;span style="font-weight:bold;"&gt;look&lt;/span&gt; like a directory, but it's not.  It's a PHP script.  It just doesn't happen to have &lt;span style="font-style:italic;"&gt;.php&lt;/span&gt; on the end of it.&lt;br /&gt;&lt;br /&gt;And &lt;span style="font-style:italic;"&gt;iwant.xyz&lt;/span&gt; doesn't have to be in any particular location just because it looks like a boring static URL component.&lt;br /&gt;&lt;br /&gt;There are a variety of ways to make this work.  Apache's &lt;a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html"&gt;mod_rewrite&lt;/a&gt; springs to mind for Apache experts, and there are many articles online telling you how to do PHP mod_rewrite.&lt;br /&gt;&lt;br /&gt;But, truth to tell, mod_rewrite is a real PITA to mess with.  And Apache/PHP has a &lt;span style="font-weight:bold;"&gt;much easier&lt;/span&gt; technique available which I'll detail below.&lt;br /&gt;&lt;br /&gt;So, there are two tasks here for this URL:&lt;br /&gt;http://example.com/download/iwant.xyz&lt;br /&gt;&lt;br /&gt;The first is to somehow get 'download' to be a PHP script, even without '.php' on the end.&lt;br /&gt;And the second is to somehow make 'iwant.xyz' from the URL available to PHP.&lt;br /&gt;&lt;br /&gt;Fortunately, the mechanics of these are very easy tasks.&lt;br /&gt;&lt;br /&gt;It seems to be difficult for newbies to wrap their brains around the concepts, but the actual mechanics are trivial, and I'm hoping this How-To will ameliorate the difficulty of the concepts.&lt;br /&gt;&lt;br /&gt;Let us begin by assuming your not quite working download.php PHP script looks something like this:&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?php&lt;br /&gt;  //register_globals is off, of course&lt;br /&gt;  $filename = $_GET['filename'];&lt;br /&gt;  &lt;br /&gt;  //Crude cleansing to avoid ../../etc/passwd hacks&lt;br /&gt;  $filename = basename($filename);&lt;br /&gt;  &lt;br /&gt;  //In an ideal world, you would have a specific range of legal values for $filename&lt;br /&gt;  //And your cleansing would test positive only for valid input&lt;br /&gt;  //The following line is far too restrictive in anything but this sample application&lt;br /&gt;  //But it's definitely the Right Way (tm) for THIS sample application&lt;br /&gt;  //Security can't be bought off-the-rack.  It's a custom job like this&lt;br /&gt;  if ($filename != 'iwant.xyz') die("Did you really think I wouldn't add filename validation here?");&lt;br /&gt;  &lt;br /&gt;  //I can virtually guarantee that the next line is not correct.  Fix it.&lt;br /&gt;  //I personally would recommend that it NOT be in your webtree,&lt;br /&gt;  //so Bad Guys (tm) cannot bypass your application and just get it direct.&lt;br /&gt;  //If your webhost does not provide a non-web-tree directory, find a new host.&lt;br /&gt;  //This should be the complete full path to the "real" iwant.xyz file.&lt;br /&gt;  $basename = '/some/path/to/the/real/files/';&lt;br /&gt;  &lt;br /&gt;  //Compose the actual full file path:&lt;br /&gt;  //If you didn't put / at the end of $basename, add it here&lt;br /&gt;  //Or do some fancy footwork to be sure you have the proper number of '/'s you need&lt;br /&gt;  //Or not, as Un*x systems ignore bogus extra '/' in a pathname anyway.&lt;br /&gt;  $fullname = "$basename$filename";&lt;br /&gt;  &lt;br /&gt;  //For larger files, a decent browser will provide a progress meter, if you do this:&lt;br /&gt;  $filesize = filesize($fullname);&lt;br /&gt;  header("Content-length: $filesize");&lt;br /&gt;  &lt;br /&gt;  //As discussed above, the only Documented Feature,&lt;br /&gt;  //sure-fire guaranteed way to force a download every time is:&lt;br /&gt;  header("Content-type: application/octet-stream");&lt;br /&gt;  &lt;br /&gt;  //Now just read the file and spit it out:&lt;br /&gt;  readfile($fullname);&lt;br /&gt;  //For large files, an fopen/fread loop using feof may be more appropriate&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now, instead of the usual 'download.php' you might expect, name this script 'download' without the '.php'&lt;br /&gt;&lt;br /&gt;In order to convince Apache that this script really &lt;span style="font-weight:bold;"&gt;is&lt;/span&gt; a PHP script, even without the .php on it, create a file named '.htaccess' in the same directory as 'download' (or a 'higher' directory) and put this in it:&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;Files download&amp;gt;&lt;br /&gt;  ForceType application/x-httpd-php&lt;br /&gt;&amp;lt;/Files&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The above three lines of magic force Apache to think of 'download' as a PHP script, even though .php is not part of the script name.&lt;br /&gt;&lt;br /&gt;This assumes that your webserver has been configured with .htaccess "on" in httpd.conf.  If that's not the case, then you would probably want to put those three lines directly in httpd.conf, or in a file that httpd.conf Includes.&lt;br /&gt;&lt;br /&gt;If your Apache webserver host provides neither httpd.conf nor .htaccess to you, the I feel truly sorry for you, but cannot help you, other than to suggest finding a better host.&lt;br /&gt;&lt;br /&gt;Your URL would then look something like:&lt;br /&gt;http://example.com/download?filename=iwant.xyz&lt;br /&gt;&lt;br /&gt;You should go ahead and build this example application now, and then we can move on to our second task of getting rid of the ?filename= part.&lt;br /&gt;&lt;br /&gt;Here is a sample application using the above code:&lt;br /&gt;&lt;a href="http://l-i-e.com/blogger/download.php?filename=iwant.xyz"&gt;http://l-i-e.com/blogger/download.php?filename=iwant.xyz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that you will, depending on your browser make and model, probably be prompted to "Save As..." with the filename 'download.php'&lt;br /&gt;&lt;br /&gt;We'll be fixing that in our next task, so just change the name to 'iwant.xyz' by hand when prompted to download.&lt;br /&gt;&lt;br /&gt;But if you can find a browser that does &lt;span style="font-weight:bold;"&gt;not&lt;/span&gt; treat that file as a download, I'll send you a Cookie.&lt;br /&gt;&lt;br /&gt;Note that you can configure some browsers to just auto-save all downloads in some directory or, blech, on your desktop.  That's a user-configuration choice which nothing in the world is going to "fix".  Sorry.  Educate the user, or live with their freedom of choice, whichever way you want to look at it.&lt;br /&gt;&lt;br /&gt;But the browser itself is still treating the output as a 'download' even if it has been [mis-]configured to just dump the file in some random directory.&lt;br /&gt;&lt;br /&gt;Now, on to the task of getting the URL to end in /iwant.xyz so that the browser is "fooled" into thinking it's a static URL and it &lt;span style="font-weight:bold;"&gt;will&lt;/span&gt; use 'iwant.xyz' as the default filename for the download window.&lt;br /&gt;&lt;br /&gt;As you can see, your script 'download' is going to have some &lt;span style="font-style:italic;"&gt;extra&lt;/span&gt; stuff at the end of it.&lt;br /&gt;&lt;br /&gt;Apache and PHP collaborate to mostly ignore anything &lt;span style="font-style:italic;"&gt;extra&lt;/span&gt; tacked onto the end of a URL, except for one crucial input they provide:&lt;code&gt;&lt;br /&gt;$_SERVER['PATH_INFO']&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This variable is set by Apache/PHP to contain everything after your script name that is in the URL, no matter what is there.&lt;br /&gt;&lt;br /&gt;Now, because your real application might need more input than just 'iwant.xyz' I'm going to go above and beyond here, and provide an include file that will give a lot of flexibility.&lt;br /&gt;&lt;br /&gt;Here are some URLs the &lt;span style="font-style:italic;"&gt;normal&lt;/span&gt; way, and some done my &lt;span style="font-style:italic;"&gt;recommended&lt;/span&gt; way compared side-by-side:&lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;  &lt;tr&gt;&lt;th&gt;Normal&lt;/th&gt;&lt;th&gt;Recommended&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download.php?filename=iwant.xyz&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download/iwant.xyz&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download?filename=subdirectory/iwant.xyz&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download/subdirectory/iwant.xyz&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download?page=42&amp;amp;line=20&amp;amp;filename=iwant.xyz&lt;/td&gt;&lt;br /&gt;    &lt;td&gt;http://example.com/download/page=42/line=20/iwant.xyz&lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Keep in mind on that last one, that the browser &lt;span style="font-weight:bold;"&gt;cannot&lt;/span&gt; know that you don't have directories named 'page=42' and 'line=20' no matter how odd that may seem for directory names.&lt;br /&gt;&lt;br /&gt;Those are perfectly valid directory names, and the browser has to assume that's what you have.&lt;br /&gt;&lt;br /&gt;Only you and I will know that 'download' isn't a directory but a PHP script, and those 'extra' bits are really just inputs to this PHP include:&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?php&lt;br /&gt;  //Consider a URL such as:&lt;br /&gt;  //  http://example.com/scriptname/var1=val1/var2=val2/path/to/filename.xyz&lt;br /&gt;  //Transform it into:&lt;br /&gt;  //  $PATH = '/path/to/filename.xyz'&lt;br /&gt;  //  $PATH_VARS['var1'] = 'val1';&lt;br /&gt;  //  $PATH_VARS['var2'] = 'val2';&lt;br /&gt;  $PATH = '';&lt;br /&gt;  $parts = explode('/', $_SERVER['PATH_INFO']);&lt;br /&gt;  foreach ($parts as $part){&lt;br /&gt;    $pieces = explode('=', $part);&lt;br /&gt;    switch(count($pieces)){&lt;br /&gt;      case 1: /* tack it on as part of a pathname */&lt;br /&gt;        //Also ignore the leading '/' of PATH_INFO which turns into an empty '' from explode()&lt;br /&gt;        if ($pieces[0] !== '') $PATH .= "/" . $pieces[0];&lt;br /&gt;      break;&lt;br /&gt;      default: /* Set up something like $_GET only with $PATH_VARS */&lt;br /&gt;        $var = $pieces[0];&lt;br /&gt;        // value might have = within it...&lt;br /&gt;        unset($pieces[0]);&lt;br /&gt;        $val = implode('=', $pieces);&lt;br /&gt;        $PATH_VARS[$var] = $val;&lt;br /&gt;      break;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I've commented the above script heavily, and all it does is transform the PATH_INFO that Apache and PHP provide into a couple convenient variables:&lt;br /&gt;$PATH_VARS will contain any /var=val/ in the URL as $PATH_VARS['var'] = 'val';&lt;br /&gt;$PATH will contain anything else in the path as '/subdir1/subdir2/filename.xyz';&lt;br /&gt;&lt;br /&gt;Save that script above as 'pathinfo.inc' and change the top of your 'download' script from $filename = $_GET['filename'] into this:&lt;code&gt;&lt;br /&gt;require 'pathinfo.inc';&lt;br /&gt;$filename = $PATH_VARS['filename'];&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now, you can surf to a URL like this:&lt;br /&gt;&lt;a href="http://l-i-e.com/blogger/download/iwant.xyz"&gt;http://l-i-e.com/blogger/download/iwant.xyz&lt;/a&gt;&lt;br /&gt;and get a download windows with the only reasonable choice for a default filename to "Save As..." that a browser could possibly infer from that static-looking URL:  'iwant.xyz'&lt;br /&gt;&lt;br /&gt;It would be nice if this was a &lt;span style="font-weight:bold;"&gt;Documented Feature&lt;/span&gt; or if something like Content-disposition actually worked in all the minor versions of all the browsers ever released.&lt;br /&gt;&lt;br /&gt;But, in this case, consider what else a browser could possibly &lt;span style="font-weight:bold;"&gt;do&lt;/span&gt; with the download window it &lt;span style="font-weight:bold;"&gt;must&lt;/span&gt; provide.&lt;br /&gt;&lt;br /&gt;If you really think about this, I believe you'll come to the same conclusion I did, many years ago:  This is a hack, but a reasonably safe hack, because what else can a browser do with such a simple URL, given that it must prompt the user for a file download (or auto-save the download by user choice) to remain compliant with the HTTP Spec.&lt;br /&gt;&lt;br /&gt;Here is the final source for our download script:&lt;br /&gt;&lt;a href="http://l-i-e.com/blogger/download.phps"&gt;http://l-i-e.com/blogger/download.phps&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And the pathinfo.inc file:&lt;br /&gt;&lt;a href="http://l-i-e.com/blogger/pathinfo.phps"&gt;http://l-i-e.com/blogger/pathinfo.phps&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are a few caveats worth mentioning here:&lt;br /&gt;&lt;br /&gt;Unlike $_GET, $PATH_VARS cannot be made into a "super-global" so you'll have to declare it global within your functions/methods.&lt;br /&gt;&lt;br /&gt;Actually, technically, you could use PHP's RunKit extension to force $PATH_VARS to be a "super-global" but if you've got RunKit installed on your server, you probably already know everything in this article anyway.&lt;br /&gt;&lt;br /&gt;If you don't know what RunKit is, you should just take my word for it that you don't want it installed, but if you need convincing, let me just point out that the purpose of RunKit is to be able to re-define something like:&lt;blockquote&gt;&lt;code&gt;&lt;br /&gt;if ($whatever) echo $something;&lt;br /&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;so that the 'if' and the 'echo' don't do what you expect them to do anymore.&lt;br /&gt;&lt;br /&gt;I.e., RunKit lets you re-define the actual PHP language on-the-fly, for developing a new version of the PHP language.&lt;br /&gt;&lt;br /&gt;Let me also point out, in case it's not blatantly obvious, that savvy users can &lt;span style="font-weight:bold;"&gt;still&lt;/span&gt; put any damn thing they want into the URL in attempts to break your script, take over your server, and otherwise cause you much grief.&lt;br /&gt;&lt;br /&gt;This URL munging should not be considered primarily as a "Security Measure" though there may, or may not, be some relative increased security in that finding a ? in a URL and then trying variants is probably a very common Bad Guy technique, but cramming more things onto the end of a static URL generally doesn't do anything at all, so most Bad Guys probably don't do a lot of that.&lt;br /&gt;&lt;br /&gt;This falls into "Security through Obscurity" though, which are generally very weak security measures, and only useful, if at all, when layered in with other, more robust, Security Measures.&lt;br /&gt;&lt;br /&gt;Or, to make a long story short, you &lt;span style="font-weight:bold;"&gt;must&lt;/span&gt; still validate and cleanse any data coming from $PATH and $PATH_VARS, exactly as you would for $_GET.&lt;br /&gt;&lt;br /&gt;Required Reading:&lt;br /&gt;&lt;a href="http://phpsec.org/"&gt;http://phpsec.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I aleady know that at least one other PHP Developer thinks I'm daft to put /var=val/ into the URL, and that I should just use 'positional' elements.&lt;br /&gt;&lt;br /&gt;Unfortunately, I do not find that very convenient, as some of the elements in my scripts are optional, so the URL would end up needing too many '/////' in it and my eyes are too old and worn-out to attempt to count those correctly.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can also safely predict some bloggers will insist that "Content-disposition:" works just fine in all browsers, or maybe they'll be smart and qualify it as "all modern browsers"&lt;br /&gt;&lt;br /&gt;My only possible responses to that are:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;You haven't tested enough minor release versions&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I believe backwards-compatible legacy support for ancient browsers is important&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;If you do not like this particular solution, just don't use it.&lt;br /&gt;&lt;br /&gt;I happen to believe, based on my experience fixing far too many bug reports from iconoclastic users of niche browsers you may have never even heard of, that it's the only correct solution to browser insanity, paricularly if you use PHP to output dynamic rich media such as Images (GIF, JPEG, PNG), PDF, FDF, Flash/Ming, and so on, as I have done.&lt;br /&gt;&lt;br /&gt;The pathinfo.inc file above works wonderfully for a URL such as:&lt;br /&gt;http://example.com/thumbnail/max_width=100/photographer_id=7/artist_id=15/rockstar.jpg&lt;br /&gt;&lt;br /&gt;It also works for the PDF URL embedded in an FDF which tend to drive Netscape/IE crazy if you start adding dynamic elements.&lt;br /&gt;&lt;br /&gt;This rant was actually referenced by none other than PHP Security Expert Chris Shiflett in &lt;a href="http://swik.net/PHP/Planet+PHP/The+Adobe+PDF+XSS+Vulnerability/tsjr"&gt; The Adobe PDF XSS Vulnerability&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-115100604304998571?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/115100604304998571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=115100604304998571' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/115100604304998571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/115100604304998571'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2006/06/php-downloads-content-disposition.html' title='PHP Downloads, Content-Disposition, Content-type, and other arcana.'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28350022.post-114798528279377863</id><published>2006-05-18T15:47:00.000-05:00</published><updated>2006-06-22T23:57:12.593-05:00</updated><title type='text'>Bogus Blog?</title><content type='html'>Truthfully, this blog originally got created just so I could add a comment to:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://phpgirl.blogspot.com/2006/05/chicago-php-user-group-report.html"&gt;http://phpgirl.blogspot.com/2006/05/chicago-php-user-group-report.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28350022-114798528279377863?l=richardlynch.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://richardlynch.blogspot.com/feeds/114798528279377863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28350022&amp;postID=114798528279377863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/114798528279377863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28350022/posts/default/114798528279377863'/><link rel='alternate' type='text/html' href='http://richardlynch.blogspot.com/2006/05/bogus-blog.html' title='Bogus Blog?'/><author><name>Richard Lynch</name><uri>http://www.blogger.com/profile/03615701995633150243</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_BmA524o-X8w/SlNktOJrEgI/AAAAAAAAAAc/KVJyVeMRPbc/S220/RichardLynch.jpg'/></author><thr:total>0</thr:total></entry></feed>
