So, there I was debugging what looked like a memory leak in APC - a perfectly straightforward bug at first glance. APC's internal allocator was leaving around a bunch of 40 byte fragments all over the place. The fragments were literally killing APC allocate and deallocate performance - with nearly 85k fragments lying around in the 128Mb cache that www.php.net uses. Even though the allocator is a first-fit based system, it still has to traverse a large number of blocks to locate the previous free block to free any particular allocated block.
Basically, it was having serious issues with memory performance. This had something to do with one of the changes I'd put into APC-3.0.13 - canary checks. The canary essentially increased the memory header size by one size_t exactly. This broke the default word alignment on x86, but I thought I had all bases covered when I put in the approriate word aligns.
24 Bytes: Now, the default allocation size in APC is 24 bytes on x86. That is 12 bytes (3 x sizeof(size_t)) plus padding to make it a multiple of 8 coming to a total of 16 bytes. Then put in the data area (say, 1 byte), which is padded up to 8 bytes. Add all of it together and the smallest block APC can allocate is 24 bytes.
Due to some strange quirk of code, 40 bytes seems to be a very unpopular size to allocate. The allocations for 17-24 bytes of data goes into the 40 byte block and for some strange reason that seems really rare. I ran through a bunch of the standard tests I run with APC to get some sane statistics out of it. After running through hundred odd random tests from the standard phpt files, I got a pile of data. Twenty minutes later I had pulled that data together into a rough histogram (which is nearly the same thing as a bar chart for discrete data, I suppose) by printing out SVG and applying styling in inkscape.
Maybe I'm just hooked into drawing pretty graphs. But it clearly indicates what is going wrong. There are not enough 40 byte allocations to consume all the spare chunks being created. But, is this not true for the 80 or 96 blocks, you might ask. Unlike the 40 byte block both 80 (32 + 48) and 96 (48 + 48) byte blocks are easily consumed by requirements for smaller blocks. The 40 byte block on the other hand cannot be split into any smaller block because it is smaller than 24x2.
Thus due to the lack of demand and the inabilty to compromise (*heh*), the 40 byte blocks remain unwilling to accept any commitments. Until a memory block nearby is free'd the block will sit around waiting for someone to allocate 40 bytes - which as the pretty graph shows, is not a popular choice.
Now to sleep on this problem and hope I wake up with a solution - clear and perfect.
--If it breaks then you get to keep both pieces.
-- Warranty disclaimer for the chat program.
Immediately after announcing the Y! mail unlimited storage, the webservices api for Y! mail has also been announced. The API is loosely modelled over NNTP and IMAP (and when I say loosely, I mean the designers read both specs *heh*) and has some really interesting features. But more importantly, now you can do cool things with it.
About 4 months back, one of the mail backend developers, Ryan Kennedy, visited Bangalore to talk about the internal workings of this awesome API. I'd gotten slightly interested because there was talk about a JSON based API which looked a lot easier to use from Javascript land. And when the hack day came around, I had managed to hack up a pretty decent Y! mail reader interface using XUL, which I named Tapestry.
Most of the XUL code is pulled out of Thunderbird code and a large amout of the UI is controlled by CSS. The XUL css selectors are really funky - take a closer look at my css for how the different styles for messages (read, unread, replied) is css based rather than with code in Javascript. Also I played around with image slicing with CSS to put all my toolbar images into a single image and using rectangle clips to use them in appropriate buttons. In short, I had a lot of fun learning stuff to write it. But the problem was that having done it, I couldn't really show it to anyone outside the company - but now I can.
But before the demo, let me quote my bloody stupid threading code which I wrote in under twenty minutes, which unlike jwz's threading algorithm, mine handles only In-Reply-To based mail threads. But the cool part is that this function is sort of "re-entrant", so calling it multiple times from async response code manages to simulate threading as an when a message is fetched - not having to wait for all the messages to load up.
Folder.prototype.sort = function() { for (var i=0; i<this.msglist.length; i++) { var msg = this.msglist[i]; var parent = null; if(!msg.parent) { if(msg.parentid && (parent = this.msgidmap[msg.parentid])) { msg.parent = parent; parent.children.push(msg); } } } }
I don't want to attract too much attention to the hack, because of some hosting issues. So if you'd really like to see it in action and have a Y! mail beta account & run firefox 1.5/2.0, keep reading.
Ryan had hosted an in-colo mirror of my hack - it might be slow to load the images because those are on-demand and not JS pre-fetched. It is my initial release and a lot of buttons and menus don't work there. Not much has been done on top of this, but the minimum functionality works and you should probably scroll through with the keyboard which is something I *really* need. I'm sure the layout code could do with a bit of work, especially on widescreen monitors - but it was something I did for fun. The code should prove interesting to anybody who wants to read it, because I've tried a few new things with javascript and generally that has come out really well.
--Always do it right. This will gratify some people and astonish the rest.
-- Mark Twain
Really, I need a word for this concept. ESR might have gotten his just desserts with such efforts as Everybody loves Eric Raymond, but I still need a word to describe ex-programmers who have looped into their own brain-stem for feedback.
The urge to find a suitable word (in the spirit of The Meaning of Liff) came from reading Miguel De Icaza talking about Mono. I've been watching that project from its very beginnings and I've not been impressed by the way Miguel deals with anyone who doesn't toe the party line. Slashdot comments put it a bit more bluntly than I'll care to be.
A Sharp# Divide: I was quite saddened when I read jdub's blog post today about the gtk# ribbon SoC submission. Building new composite controls in C# basically makes the widget useless for other languages as it cannot be wrapped easily into C, python, java or $insert_language. But it does make sense for Miguel to suggest it as because it makes people want to use Gtk# over something like java-gnome or php-gtk (*cough*).
Wrapper Hell: Now, if you look back at the history of mono, you'll see that avoiding the multitude of hand-coded wrappers was the so called rationale behind mono in the first place. Read his 2001 interview and the part about "Making Programming Interfaces Language-Independent". Now pull yourself back to today and look at Jdub's blog post. I can see why Miguel is losing traction with the rest of the community, albeit after 5 years or so of work on Mono.
A GPL'd Java: With the emergence of Java as a proper f/oss VM subsystem, I don't think there is any need to introduce an unacceptable risk in the form of mono. When you combine a decent fork-mode java VM implementation (i.e start VM, JIT compile classpath, listen on domain socket, fork for each application to reduce memory footprint with multiple VMs), with a bunch of decent wrappers for C-based GTK widgets - you can create a non-sucky Java user experience. I don't see the point in pulling along mono in a world with Java, python and whatnot to develop gnome applications (read last three words again till the point is taken).
Honestly, I do have a huge axe to grind about Mono in general (because of my brushes with lupus and miguel while working on dotgnu) - but the project is doing some decent work in re-implementing .NET system libraries, which is in fact a good thing. My only beef is with pushing mono into gnome and peddling it as a target platform for F/OSS applications ( tomboy, f-spot, muine etc...).
So, like I said ... I need a new word.
--You'd better smile when they watch you, smile like you're in control.
-- Smile, "Was (Not Was)"
This had to be documented, like the other offtopic masterpeices. It all starts from a mail which had a typo - "Vacancy for 1/2 girls" which evolved into a discussion about dinosaurs (don't ask). But it eventually ended up with Dinoman and spo0nman in discussion.
I know Kung-Fu: Now throw yourself back to the Matrix, the first ever episode [1] - spo0nman as Neo. dinoman as Tank and me as Morpheus.
spo0nman : Reg-ex? I'm going to learn Reg-ex?... Holy shit. dinoman : Hey Mikey, I think he likes it. How about some more? spo0nman : Hell yes. Hell yeah. t3rmin4t0r: How is he? dinoman : Ten hours straight. He's a machine. spo0nman : I know Regular expressions. t3rmin4t0r: Show me.
Volley #2: Now, that alone wouldn't classify as an offtopic masterpeice. So here's the second wave with even more - in the matrix gym.
Sometime later, after t3 beats the cwap out of spo0nman, dinoman : There is no spoon, really. t3rmin4t0r: How did I beat you? spo0nman : You were too fast. t3rmin4t0r: Do you think my beating you has anything to do with perl in this place? spo0nman : .... t3rmin4t0r: Again...
And I for one, welcome our matrix spoofing overlords ... *bows*
--I suppose if we couldn't laugh at things that don't make sense, we couldn't react to a lot of life.
-- Hobbes
Every company has its own unique attitude. Now, I lament a bit about some stuff in Yahoo! I never got to experience - its fun side. I did catch the tail end of this phenomenon, but here's a blast from the past about how different the times were in the last millenium.
This is one of the cards from the Yahoo!-o-poly which was given out as the year end gifts in '99. There is a fair bit of company history hidden inside those images like the Say 'No' to AOL card or the reply to all card.
Somewhere along the way, that sense of humour seems to have been replaced with suit & coat seriousness. Maybe not with the old folks, but every hire you make you dilutes the culture if you fail to inculcate the same in him - which requires slow growth and mainly of fresh talent. A crowd of new joinees in their thirties is impossible to subvert to local cultural standards.
But let me say this - mourn not for what some never had.
--Some changes are so slow, you don't notice them;
Others are so fast, they don't notice you.
So it has finally happened - a stable release of dotgnu's Portable.NET and Libjit, after nearly a year and a bit more. The critical thing about this release is that Rhys doesn't yet know about this yet. This is the first release we've done without rhysw's involvement - he's been last sighted in Greephone land. So rather than the usual place, you can get the packages from the savannah download area.
This is by far the most revolutionary release dotgnu has had. The entire x86 engine is now fully native JITted. The windows.forms has taken quite a lot of work. My special congratulations to Aleksey Demakov and Klaus Triechel - who have worked especially hard of late to get libJIT into the shape it is today.
And in other news, we've put up a couple of Google SoC ideas at gnu.org. I'm very much interested in people picking up the AMD64/ARMv4 libjit core, either individually or as a team (does GOOG allow that ?). Also great strides being made in WinForms land, Radek has just managed to get the SharpDevelop editor to run.
The SD code uses a fair bit of PInvoke code bits to draw the caret and such, which is totally disabled in this rebuild. But it is quite an achievement at this point to be able to run a GUI component of this complexity.
Awesome work all around folks !
--Time is the most valuable thing a man can spend.
-- Theophrastus
One of the first thoughts which crossed my mind when I was writing Migration Patterns of Codemonkeys was how ill-prepared I was for such a migration, at that point. I had decided that I would fix that deficiency as soon as things settled down. But during the tumultous times that followed, that TODO item has lain un-noticed in the pile of higher priorities. But no more.
So yesterday, my resume has risen on stepping-stones of its dead self to higher things. In keeping with the whole semantic markup fad, I've tried to keep to the hResume microformat while peicing together this. The presentation - both print and screen - is all done in css.
The content has been slightly trimmed to fit into a single A4 page - but it does indeed provide a big picture view of my non-achievements over the last 6 years or so.
--The closest to perfection a person ever comes is when he fills out a job application form.
-- Stanley J. Randall
For every other php programmer who reads Rasmus's no framework mvc, these following lines are what they often finally remember.
3. Fast * Avoid include_once and require_once * Use APC and apc_store/apc_fetch for caching data that rarely changes
Eventhough include_once has its performance hit, some people avoid it by some rather simple code borrowed from their C experience. Here is how the code looks in general.
<?php if(defined(__FILE__)) return; define(__FILE__, true);
This is nearly identical to what you would use in a C header to prevent inclusion checks. But as the emergence of precompiled headers shows, even those folks are trying to reduce the expenditure of including & pre-processing the same file multiple times.
I do not deny that the include check above works. But it checks for double inclusion during execution, which is exactly what was wrong with include_once as well. Even worse, it hits APC really badly. But the situation takes a bit of context to understand - let us pick a 'real' library fubar (name changed to keep my job) which has been avoiding include_once. Here is how the logical dependency graph looks like :
In a moment of madness, you decide to make all includes properly for design coherence, especially for that doxygen output to look purty. But instead of using include_once as a sane man should, you remember the wisdom of elders and proceed to do includes. And then kick it up a notch with inclusion checks as illustrated above. But this what Zend (and by design APC, too) actually compiles up.
The nodes marked in red are actually never used because of the inclusion checks, but they are compiled and installed. Zend pollutes the function table and class table for such with a bunch of mangled names for each function - APC serves up a local copy of the same cached file for multiple inclusions, which all have the same mangled name - by ignoring redeclaration errors.
If you were using include_once, these files would have never been compiled. But the above solution *seems* to work in APC land, but in reality does not play very nice at high cache loads. And while debugging *cough* fubar, I ran into a very corner case mismatch issue.
During a cache slam or expunge - when the cache is being written to by one process, other processes do not hit the cache and fall back to zend compile calls. Now imagine such a cache fail happening mid-way in one request.
Now the executor has two types of opcode streams to deal with, one which is Zend fresh ! and one which is from the APC (Opcodes in a Can) freezer. Even though only a couple of opcodes in the normal opcodes stream is executed, the pre-execution phase of installing classes and functions in their respective tables runs into issues unknown thanks to early binding and late binding combinations, which was behind that bug from hell in class inhertiance. But more annoyingly, I cannot reproduce them in ideal testing conditions - wasting about two nights of my sleep in the process.
So I implore, beg and plead - please do not write code like this to avoid include_once, it just makes it slower, heavier on your memory footprint and increases cache lock contention. At least don't do it in the name of performance - I wrote this blog entry just because the guy who wrote fubar said "I didn't know it worked this way". There are a bunch of other such gotchas, which is currently my talk proposal for OSCON '07.
And just out of curiousity, I'm wondering whether an apc.always_include_once might help such code. But on the other hand I hate optimising for bad code, much cleaner to drop such files from cache - after all "they don't the deserve the performance".
So, trust me when I say this ... leave include checks to the experts !
--Too much is more than enough by definition.
In the dim dark past of October 2005, spo0nman and teemus did a hack in office. It was a tiny bit of javascript magic combined with a lot of heavy PNG maps and individually marking each cube's position on the map. It was the beginning of so many other nights when we did hacks - even weekends. But that's irrelevant. What is relevant is that to avoid slashdotting my puny little desktop, we had to distribute our load across all the machines - someone asked me to explain how we did that, quite recently and it needs a quick mention outside at least.
RewriteMap: Introducing to you, a small bit of hidden magic inside the apache mod_rewrite module - something which gets just a passing mention in the manual. You can define a RewriteMap which is a program - a full fledged script in any language you please.
RewriteMap lb prg:/usr/local/bin/lb.pl RewriteRule ^/floors/(\?.*)?$ ${lb:$1} [R]
The script is not invoked for every request, but an instance of the script is kept alive and feed one line at a time. And because spo0nman wrote it, it ended up being a perl script. Here's the entire perl code.
#!/usr/bin/perl -w $| = 1; my @urls = qw (http://m1 http://m2 ...) $cnt = 0; while () { $cnt = (($cnt+1) % 3); my $mirror = $urls[$cnt]; print "$mirror\n"; }
Now, the beauty of this is not in this code. The perl real beauty that
came out of this was something which generates and rewrites dynamically
without restarting apache - with a db or just about any data source
you can code up.
Imagine a script which watches your access log to accumulate statistics. Now combine that with a script which wget's frequently hit URLs into a local file. And then imagine a perl script which does a stat() on that file and does an internal redirect to static pages if the file is recent enough (blog archives *cough*).
Implementing something like this into S9Y would make a lot of sense - the gain of hitting a static file would be a LOT better than using something like APC. Would make sense for someone like lunatech who still gets heavy hits on his comment disallowed archives but still uses php to serve out the pages (at least, they seem static, yet send out a X-Blog: Serendipity header). And rather than statically rendering all the pages (like I do), a hack like this could let you do only pages which get n+ requests per day or something and clean up on a cron with stat.atime values.
Hope someone reads this blog and saves me all that work ;)
--Nothing is impossible for the man who doesn't have to do it himself.
-- A.H. Weiler
Being a psuedo-security guy of sorts, I'd decided to jump back into insecurity land a couple of weeks back. I haven't really been into security-tech for quite a long time, having hung up my script kiddie slingshot a long time back. But of late, it has again started to look attractive - but more than mere implementation issues, I've been looking for true blue design issues.
Recently on IRC, dumbhead was defending his default password on his router, which is conveniently firewalled off from the WAN. In my attempts to prove that setup insecure, I discovered DNS Pinning. It has been truly enlightening to perform a cursory attack on a home router with a faked up nameserver (re-used my twisted.names code).
The first request immediately does an iframe with a made-up hostname to ensure that no dns caches interfere. The resolution of that host (say "mordor") looks somewhat like this.
;; QUESTION SECTION: ;mordor. IN A ;; ANSWER SECTION: mordor. 284 IN A xxx.xxx.xx.xx mordor. 284 IN A 192.168.1.1
Now there is a good probability that the first IP will be hit nearly immediately by the browser. The server is running a script which tails the access log as soon as that vhost is hit (for dynamic vhosts, install lighttpd-mod-mysql-vhost), marking the vhost in the table as "hit". A sudo'd python script hooks into the mysql table, flips that flag to "block" after running an iptables packet drop on dst port 80, src ip of the victim.
Thirty seconds after loading the first iframe, the code in there creates another iframe with src=document.location+"?xyz". Very soon, that frame loads up 192.168.1.1 in the same domain as the attacking website. I've got a default exploit sequence, which opens up port 22 for the Huawei WA1003A router which BSNL is distributing these days - but this requires the default password to be unchanged.
But the default password might not be required with the more expensive routers. If I could run my first evil iframe on port 2869 to commit the b0rkage, I would essentially be able to access the UPnP which takes a bit of SOAP to reduce the NAT into swiss cheese. But I'm a bit too lazy to actually write out those SOAP calls using XmlHttp (hah, same domain). And all that *without* a single password.
Most people have dismissed the DNS feature as unusable for hacking most websites because it sends invalid Host: headers and without cookies. But none of the routers I've looked at so far care about that or even have javascript checks for iframes (not that it will affect XHR much).
Amazingly simple, elegant. And DNS has been around for only 20 years ...
PS: thanks for providing the domain - you know who you are :)
--The Domain Name Server (DNS) is the Achilles heel of the Web.
-- Sir Tim Berners-Lee
posted at: 04:23 | path: /insecurity | permalink |
The time I've been at Yahoo! has been the best couple of years of my life so far. Sure, I've had my share of problems - some with work and some otherwise - but who hasn't ? The thing I truly treasure about these years are the sweet sweet memories. There's a lot that happened which I'll remember for a long long time to come - because I've changed from that other guy who joined-up two years ago and that's no accident.
It wasn't the smooth ride it looks like in hindsight. I admit it, there were all sorts of days in there - good and bad. But most of what I remember is time spent with friends - premshree, spo0nman, teemus, sabiokap, hitesh, sid and aathitude. Hanging out in the cafeteria, playing pool, the 4th floor balcony at 3 AM`.
In fact, you could totally blame my current sanity on pool. That pool table has been a place where I could go to just to get away from the computer. More than just playing the game, there was a point when I got more than usually good at it. The friday evening pool sessions were my time to shine and I generally came back upto level for every game I lost over the week. There is something about sending in your status report that makes you really kick ass in pool.
And then there were the crazy hours. Coming in to office just in time to complain about the buffet lunch and leaving just in time to complain about the early morning traffic. But these days, when I feel like working, I just stay at home and concentrate on working rather than head out somewhere where there's an near infinite supply of friends and coffee.
But after two years, it doesn't quite have the same small company feel it had. I had decided that I'd stick around for at least two years - no matter what. That is done.
As the walrus said, "The time has come to talk of many things" ...
PS: Happy 12th birthday Yahoo! ...
--How do you expect me to remember your birthday when you never look any older?
-- The Diplomatic Husband
Kerala's IT Mission is sponsoring FOSS Meet @ NITC, which is going to be kicked off tomorrow by the honourable Chief Minister of Kerala. I'd talked there last year and was planning to just drop by there on my way back to Bangalore.
Had to cancel that trip, mainly out of laziness - travelling 10 hours in a train to reach a strange town with nobody to pick me up and no accomodation confirmed isn't my idea of a fun weekend. Was planning to catch up with some folks from around India, who have talks at this event - doing that once a year at FOSS.IN isn't quite enough. But as Mr Pradeepto said, this isn't the only conference - and it isn't as if I've got something useful to add to this conference.
There were a couple of talks I wanted to attend - especially lawgon's "What went wrong with FOSS movement in INDIA ?". I suspect that this has something to do with the what is stopping indian contributors thread which hit nearly all LUG lists in India.
I think the real question asked in the mail is Why are there are no FOSS *Rockstars* from India - people who are larger than life (taj might qualify). And there are FOSS contributors to be found India, but as shres put it bluntly - "contributors are hard to find" - the whiteboard at foss.in is proof that there are enough.
If there is indeed a drought of new comers to the FOSS world, the general argument is that "You're not looking at the right place" to invest time and resources. For example, second tier colleges, with lack-lusture cookie cutter graduate programmes, produce more FOSS contributors than premier institutions (like the IITs). But I've had my own theories about why that happens and why it happened a lot during the post-Y2K bust. So I think that investing into these colleges in a big way might in fact upset the process that is producing hackers today.
So, I've got a feeling that this talk would be well worth attending - to throw more light on what's going wrong and to look at the solutions suggested. I'd be really interested in helping with any practical solution to the contribute-or-mentor problem that I've been fighting for a while (do you mentor or do you contribute directly ?). So if anybody attends it, please blog about it.
I've got fond memories of last year - preparing the slides at the last minute, walking about in that big campus, spending time at Calicut beach. We had a lot of fun and I mean, A LOT. And the conference is really good, the kids do use Fedora on the desktop in their labs. The XGL demos were a particular attraction last year.
Maybe next year.
--The best way to avoid responsibility is to say, "I've got responsibilities."
posted at: 02:44 | path: /conferences | permalink |
Some people are born managers, some others acquire that talent over the years and then there are those who have it thrust upon them. But everybody's still gotta manage, play the game with the hand they've been dealt with and not all of them will make good poker players. From my shuffled set of manager cards, let me therefore deal out a card which has been played so often that, it is pointless to attempt a bluff. But first, some setting and scenario - from the receiving end of the card.
Case of the Mondays: Imagine working in a team of ten odd people. For some strange reason your manager seems to insist on the entire team showing up at 9 'O clock sharp, just like factory workers everywhere - except without the benefit of a siren to warn them. Except there are two free-thinking hippies who still show up at work at 11, with bleary eyes as if they've been working all night long - and maybe they have. The first clue that the management (no, it is no longer in singular) is displeased comes from an email, similar to the following with appropriate padding.
From: manager@company To: team-world-wide@ Subject: Punctuality and Official Timings We as a company ... blah ... blah ... customer ... blah time is money ... waste no time ... read this long mail ... with care and precision ... key aspects ... morale and motivation ... blah blah Of late, it has been noticed that people ... you know who you are ... yada yada ... engineers show up late ... as late as lunch ... must encourage team work ... on mondays 99 bugs on the product ... Take one for the team ... pass it all around ... make sacrifices for the team ... ask not what the team can do for you but, ... So, please ensure sync ... and conf-calls with onsite ... by coming in time every day. Thanking you, Your Neighbourhood PHB
No Names: A politely worded mail, which in the manager's opinion conveys the essence of his complaint in clarity. But such mails accomplish two things. First it fails to totally point out who's wrong and who's not. This indicates to those in the wrong that the manager is non-confrontational and is more likely to snipe from afar than come out in a melee. And by not naming any names, the manager assumes that the people responsible will know and take action. But by denying personal criticism, they are blocking off the employee's response in advance. There is no way for the employees who have incurred the displeasure to broach this topic and explain in person - without appearing petty. They might have a very good reason for coming in late every day - a conf call at 10 PM every night for instance.
Authority Erosion: Secondly and more importantly, such a public announcement erodes into your authority and trust from the other employees. When they see your orders disobeyed with impunity (yes, when ... not if), you are literally letting your targets eat into your authority, while building their own pseudo-authority as a rebel - especially if they are still good at their job. To give an appropriate analogy, it is indeed hard to keep faith in this world, when certain people aren't instantaneously hit by lightning, even out of stormy skies. In short, it pisses off more people who keep to the lines, when you send such a mail which gets an unconscious "Yeah, but what can you do ?" response.
I call this manoeuvre the Group Therapist, where someone having run out of his power and authority, tries to turn the peer pressure screws and essentially try to shame people into obeying. And sometimes it works, mainly because people are sheep. Nothing bad happens if it works, but as mentioned above, problems get worse if it doesn't work - especially over a prolonged period.
Grapevine: But private direct criticism can still work as a deterrant for others. The office grapevine is strong and long enough to actually leak what was said in that sound proof conference room - and the weird thing about people is that they believe hearsay more than an official memo. Gossip in general giving no advantage to the producer other than the thrill of being "in the know", while official communiques aren't viewed with such pink-tinted glasses - Making the water cooler conversations more effective at communication than any office memo ever sent. Strange, but logical.
If you've read Migration Patterns of Codemonkeys or Performance Inversion, you'd already know that my my bitter well of cynicism holds no answers. But they present some facts, pose a couple of questions and the rest has been left as an exercise to the reader :)
--Long gone are the days when personal shame caused you to take personal responsibility.
-- Linus Torvalds
posted at: 06:46 | path: /observations | permalink |