| Feed View | The Daily WTF |
| Curious Perversions in Information Technology |
Subscribe | Retrun to feeds | Users subscribed: 0 | Last Updated: Dec 02 2008, 17:20:54
Fresh out of school, Maxim was able to score himself a pretty sweet entry level position in a small private bank. Rather than being responsible for maintaining the company's static phone book on the corporate intranet or some other stereotypical entry level thing, he was placed in the understaffed Publications department to do some surprisingly heavy impacting IT work. The department's job was to produce and distribute various financial reports including the most important one of all - the Recommendation List. This list was considered mission critical for the bank as it contained the official recommendations of what stocks and bonds to buy or sell and was sent out to managers and customers alike. A bad recommendation could make or break the financial managers, not to mention the customers whom invested their money with the bank, who made decisions based on this information. At the core of the Recommendation List was the Great Excel Spreadsheet (or "G.E.S." as it was known internally). Its existence was so crucial that it even had its own dedicated employee, Helen, the Report Editor. Each week, the Helen's dance would go like this: - First she would send the spreadsheet to a team of Analysts who would make adjustments based on their "insight" of the market.
- Once returned to the Editor, she would then run a macro that would update stock and bond values from a data provider.
- This spreadsheet would then be returned to the Analysts for re-verification.
- If everything was in order, it would be sent to the print shop and then snail mailed to managers every week and to their private customers monthly.
With all of this back and forth, Management felt that this process was ripe for improvement. So, armed with a copy of Access for the front end and a SQL Server account to handle everything on the back end, Maxim went to work. Never Underestimate the Power of Yield The original developer of the G.E.S. was long gone by the time Maxim showed up, but this wasn't much of a problem. Amid the ocean of financial mumbo-jumbo, he found good comments and descriptively named data fields. From a technical perspective, everything was clear except for one field - Yield. The information surrounding Yield was more cautionary than helpful. The formula's description, for example, simply read "DO NOT EVER ATTEMPT TO CHANGE THIS CALCULATION! EVER!" Looking for some useful information, Maxim turned to the analysts for some help. "Oh, God!" the lead analyst cringed, "you're not touching the Yield!?! Oh no no no, don't touch that! That's the most important part of the whole spreadsheet!!" After a bit more prodding, he learned that the Yield was the magic number that influenced the Analysts' decision to recommend a stock or bond. Thankfully, Maxim was able to port over the function that calculated the yield value alone and very soon, he was on his way to making his new application live. Heisenberg Uncertainty Principle...of Copy-and-Pasting into Spreadsheets? With a month's worth of experience under his belt, Maxim's project was coming along quite well. Everybody loved using the pretty Access front end with its drop-downs and he had created instead of the ominous facade of the Great Excel Spreadsheet. Even Helen was satisfied since she now had more of purpose than pushing paper out week after week! However, the joy was short-lived, as was revealed during an emergency department meeting. The lead analyst started, "Maxim, we're finding some discrepancies in the report. Several values in what we're finding to be random stocks and bonds are being grossly misrepresented." "How do you mean?" asked Maxim. "Point blank - we believe that YOU broke the Yield calculation and we're two days away from sending out bad figures that could ruin the bank and its investors." After having to awkwardly sit through the rest of the meeting where "Plan B" (resurrect Helen) was discussed, Maxim got to work looking for a root cause. Skeptical that the database would calculate some fields incorrectly, Maxim manually worked out the values by hand and found the problem and found the biggest shocker of all - some of the formulas in the original spreadsheet were wrong to begin with. In going back previous editions of the spreadsheet, somehow, they managed to send completely idiotic numbers to their customers for three full years (at least). Not a single customer, not a single manager ever noticed the inconsistency for what were supposed to be trivial multiplications; not a single one of them noticed that "The-most-important-figure-on-this-chart-we-base-all-our-decisions-on" was random garbage. In the end, he found out that whenever Helen needed to create a new row, she would simply copy and paste some random row and then adjust the values. At some point, however, she must have messed up and the spreadsheet ended up in a weird state, with formulas referring to cells in other rows, or sometimes even referring to nothing, creating a whole bunch of inconsistent values. Excited at the chance to clear his name, Maxim revealed his findings to the lead analyst. However, instead of relief, he only shrugged and responded “Hmph... well, we usually just use our gut for recommendations, anyway."
Brought to you by the Non-WTF Job Board:  
 "Hmmm," Michael pondered, "the 4-minute Shrimp takes 10 minutes to prep and 7 minutes to cook... maybe it only takes 4 minutes to eat?"  "After waiting fifteen minutes for a bus at my local station," Johnno writes, "I figured that there was something wrong. I checked the sign for delays and, as I thought, the bus timedout."  "Every time I refreshed the page," Arlen Phillips wrote, "the number of seconds I was told to wait grew by exactly 6000000000000000000. I gave up after at 156000000000000000000 seconds, which, according Google, is slightly under 5 trillion years. I can wait, I guess..."  Dotan Cohen (דותן כהן) received this great tip. "Had I known this," he added, "I might have tried something different."  YK appreciated that the Hong Kong airport puts a serious effort in testing cleaniness. 
Brought to you by the Non-WTF Job Board:  
 Have you ever found yourself writing a function to do something that seems pretty simple, then months or years later you find out there's a built-in function to accomplish exactly what you were doing? Maybe you didn't know where to look or the built-in function's name was confusing. I'd argue that Java's toUpperCase() does not fall in this category. Somehow I imagine that if you were to reverse engineer the built-in method, it wouldn't look like this implementation (submitted anonymously): private static String upperCaseIt(String Account) { String result = ""; int i = 0; while (Account.length() > i) { if (Account.substring(i,i+1).equals("a")) { result = result + "A";} else { if (Account.substring(i,i+1).equals("b")) { result = result + "B";} else { if (Account.substring(i,i+1).equals("c")) { result = result + "C";} else { if (Account.substring(i,i+1).equals("d")) { result = result + "D";} else { if (Account.substring(i,i+1).equals("e")) { result = result + "E";} else { if (Account.substring(i,i+1).equals("f")) { result = result + "F";} else { /* I'm sure you get the idea. */ } } } } } } i++; } return result; }
Brought to you by the Non-WTF Job Board:  
 When Timothy B. stumbled across a function that had a vague name, no comments, and variables, he took a few minutes to try to break it down in his head. static char *nice_num(long n) { int neg = 0, d = 3; char *buffer = prtbuf; int bufsize = 20; if (n < 0) { neg = 1; n = -n; } buffer += bufsize; *--buffer = '\0'; do { *--buffer = '0' + (n % 10); n /= 10; if (--d == 0) { d = 3; *--buffer = ','; } } while (n); if (*buffer == ',') ++buffer; if (neg) *--buffer = '-'; return buffer; } Got that? Yeah, it takes a few minutes to figure out. The function that this, er, function is trying to accomplish is to add commas at the thousands, millions, etc. places. It works backwards, starting with the string terminator, then setting the one, ten, hundred, etc. digits using goofy modulus math. The function divides by ten with each iteration (rather than 1,000 for some reason), stopping at every third to stick a comma in. And if it was negative to begin with, it mashes a minus sign back on to the string before returning it. Personally, I would've called the function "nice_num,horrible_implementation", but I'm pretty sure commas aren't legal in C++ function names.
Brought to you by the Non-WTF Job Board:  
 "Why won't this stupid thing just... just... graagh!" The salesman clutched the edges of his massive keyboard tightly, his knucles white. While he looked angry, he wasn't actually angry; rather he was frustrated approaching angry. The year was 1984, and the PC was finally moving out of the "early adopter" range and companies started sending them out into the field. Ricky happened to be working at a help desk during this exciting time, aiding in the rollout of the shiny new PCs to various teams in the company. Unfortunately for him, one of the first teams that needed the PCs most desperately was also one of the departments least able to understand and use them – sales. It's not that the sales team was stupid; it was just that they were now having to deal with a major change to the way they'd measure performance, record sales, and run reports. One salesman in particular, Jeff, struggled with it more than his other colleagues in the department. He became well known by much of the helpdesk staff – Ricky, in particular. Jeff didn't really have much of a temper, but it didn't take much to frustrate him. When he encountered a problem, it was as though he'd encountered quicksand. He could save himself if he took a moment to assess the situation when he was just ankle deep, but instead would struggle and thrash around, burying himself deeper and deeper. By the time that just a single nostril (metaphorically) was sticking out above the muck, he'd call the helpdesk to rescue him. "I'm trying to get this report to not look stupid, but the stupid thing just... just..." "OK, Jeff," Ricky began, trying to talk him down. "Can you describe how you want it to look?" "I want it condensed; like, smaller, you know?" Since it was printed on a dot-matrix printer with fixed sizes, there wasn't much Ricky could do there. He sighed, knowing that this would be another time that getting a more detailed description from Jeff would be like pulling teeth. "So is it too many pages horizontally, or vertically, or..." "Yeah, it's too many pages. Also I don't need this date that shows up." "Which date?" "03/20/84." Ricky kept probing Jeff for more information, and Jeff's answers remained vague. Jeff kept changing his description of what he wanted, and both just became more and more frustrated with the other. Hoping to ease the tension and get the conversation back on track, Ricky decided a little joke was in order. "OK, I'm sorry, I'm really not understanding what you're telling me. Could you just hold the phone up to the screen so I can take a look at it?" Ricky heard a faint click of plastic hitting glass, then silence for about 30 seconds. Finally, Jeff came back on the line. "Well?" Maintaining his composure, he asked Jeff to send in a hard copy. Ricky could only imagine Jeff waking up at 3:00 AM that night to wonder "WTF did I do?"
Brought to you by the Non-WTF Job Board:  
 Having just inherited a mammoth, ASP-based ecommerce application created in a developmestuction by a handful of different consultants over several years, Ryan Davis found himself asking one question, over and over: why? Why didn't they use some off-the-shelf ecommerce site? Why aren't there any comments, anywhere?? Why did anyone let the original developer near a keyboard, let alone allow him to program!? Why did I even bother coming in today!?!? After nearly reaching his very last nerve, Ryan noticed a file that came up in his search for "contact_id". It was simply named why.txt and, although it was a mere 114 bytes, he hoped it would contain the answer to all the questions he had asking. Upon opening the file, however, it left him with one more question... /cart/checkout.asp:15 if not contact_id <> 0 then Why indeed.
Brought to you by the Non-WTF Job Board:  
 The Mandatory Three (from Jim) After the dot com bust, I spent a lot of time interviewing. It was mostly dead ends or companies that were only willing to hire one person to do the job of four (specifically, the four that they had just laid off). A friend of mine who worked at a school, told me about an IT position there. Being out of work for so long, I was very eager to get in for an interview, and figured I might have an "in" since he was working there already. When I arrived at the interview, there were two other candidates waiting. I was to go in first, and I was informed that all three of the interviews would be done in "rapid fire" succession, and each would take just 30 minutes. I went into their conference room, and was a bit startled by the fifteen people sitting around the table. This was known as "The Gauntlet." This group of people only asked a few, fairly non-technical questions. Most seemed bored, and some occasionally looked at their watches and yawned! Now, I am not the most exciting person in the world, but I am certainly not that boring. I finished the interview and left feeling quite confused. What the hell just happened? I got a call from my mom later in the day, and I told her about the interview. Being a teacher, she was familiar with what I had gone through and she explained it to me. It turns out that in education, every job offered requires at least three interviews to be done, even if the job has already been filled (most are filled internally). Basically, I was just "filler." It now made sense why everybody was bored and just waiting for the interview to be over. It also made sense why there were two other candidates, and why the interviews were done so quickly and carelessly. My friend checked it all out for me and confirmed that I was indeed filler. When I asked why so many people for a "filler" interview, I was told that it was the law. What a complete waste of everybody's time! The lesson here is: If you go on an interview for an educational institution, and your interview is way too quick and simple, chances are you are just "filler". Do yourself a favor and run from the interview if you see yawning! Ironically, I now work for a university, where I see many "fillers" come in for interviews. The poor bastards! The Easy Road to Success (from Paul H.) I was working for a large Swiss bank in a risk analysis department. We were dealing with pretty complex deals which required lots of processing time and had very little time to work, so we had built a grid to handle it. Our systems kept very close watch on the grid, opting for our own job queue instead of what the grid offered. As such, we needed people who knew a few things about programming. I have no idea where the candidates came from, but we had put the word out that we were looking for senior developers. The candidates would come to us, be interviewed by our dev manager (who had been promoted because his code wasn't worth the disk space it was stored on), then get passed to us. We'd start the talk with background, basic one-liner questions, then jump to one of our open-ended questions. Our favorite was "how would you build a priority queue?" We'd explain what a priority queue is, what someone would use it for, tell them it didn't need to be persistable, and let them know it was a real-world exercise, since we had to build one for our project. Nine times out of ten the answer involved XML. And people would try to convince us that XML was the best, fastest, and easiest way to go. My favorite candidate stammered for a few seconds then pulled out a SecurID key fob, acted like it was a Blackberry, and claimed there was a production issue at his job and he had to go. So after a month of horrible candidates we had a day with three interviews in a row. Each candidate gave a perfect, clear, correct answer. So we followed up with a similar, but easier question and all three bombed miserably. We sat around discussing it at the end of the day and it didn't take long for the dev manager to admit he had given all of them the answer because he was tired of us rejecting candidates. Relevant Inexperience (from Adam) The company I am contracting at are having a recruitment drive ahead of a big government contract. Since I know a bit about coding I have been asked to scan through the résumés and select the ones that have the relevant experience. Why the agencies don't do this is beyond me. Anyway, I received a résumé recently, and I started to skim through it. The header of "relevant experience" looked fine until the last entry: | Technology | Experience | Competency | | The Italian language | 10 years | Awful | OK, quite amusing, and on I went to work experience, which had some fairly standard bullet points about AJAX, C#, SQL and so forth. So far so good. Then I got to the last bullet point: - I do not understand .NET interfaces as I have never used them. I've survived just fine without them so far thank you very much, so if this is a big problem, let's not waste eachothers' time, please. Oh, and you may as well stop reading.
At that point, I stopped reading (since we use interfaces all over our n-tier apps) and fired a quick email off to the agent to suggest he reads through the résumés before he passes them along. Out of curiosity, however, I skimmed through the rest of the résumé. Here are a few more gems: - Overhauled a dynamic intranet site, using "classic" ASP, for use by a distributed team, to teach myself "web stuff"
- (beneath a previous job) It was here that I taught myself how to program, whilst recuperating from a nasty accident involving a taxi.
- The system ran like a dog, but it was good for a first attempt.
Needless to say, we all had a good laugh, but he didn't get as far as a technical interview over the phone.
Brought to you by the Non-WTF Job Board:  
 "I've heard of Gisborne, Ashburton, Darfield, and Kaikoura", writes Steve Chadbourne, "but that last town is a new one to me."  Andy C spotted this on Fox 5...  TODO: put some text in here about the next picture  (from Caleb)
Brought to you by the Non-WTF Job Board:  
 It seemed like a simple request. "Please add 'MAINT-CNTRL-ADMIN' to the cost center dropdown for client #876." It was also Scott A's very first assignment, having recently started as a web developer for the B2B merchandise reseller. The ecommerce application he was hired to maintain was ASP-based and had been developed over the course of several years by an outside consultant. During the job interview, the system looked pretty decent: it tracked orders, inventory, products, etc. The UI wasn't wonderful, but it worked. As for the request, Scott figured it'd be a matter of finding the cost center table and add a new row for that particular client. If only it were that simple. Since there was no "Cost Center" table — nor anything named anything similar — he decided to just trace the code to find where the dropdown got its data from. That's when the fun began. The first thing Scott noticed was that there seemed to be a lot of include files. And the include files included a lot of other include files. And those files included even more files. Functions were being called and objects being created that he couldn't find the source for. After a short while, the entire site began to seem like one giant "choose your own adventure" novel, and it quickly became clear that simply opening up the target page and looking for the drop down wasn't going to be enough. In desperation, Scott wrote a simple script that would trace all of the include files and display them in a nice pretty tree. Surely, he'd be able to find the files he needed to look at after that. Following is the output of what he got for one — yes, one — the pages within the website. catalog.asp catalog.code.inc.asp catalog.display.inc.asp catalog.display.product.inc.asp catalog.display1.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display19.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display2.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display3.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display4.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display5.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display6.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display.productlist.inc.asp catalog.display.productlist2.inc.asp catalog.display.productlistProduct.inc.asp catalog.display.quickorder13.inc.asp catalog.display.quickorder23.inc.asp CatalogRedirect.code.inc.asp category.code.inc.asp iUser2.0a.code.login.inc.asp iUser2.0.code.login.inc.asp iUser3.0.code.login.inc.asp Category2.0.obj.inc.asp iUser2.0a.code.login.inc.asp iUser2.0.code.login.inc.asp iUser3.0.code.login.inc.asp layout.display.catalogs.inc.asp content.display.catalogs.inc.asp cart.display.inc.asp cart.display.table.inc.asp CartImage.display.inc.asp catalog.display.feature.inc.asp catalog.display.productlist2.inc.asp catalog.display.productlistProduct.inc.asp catalog.display.inc.asp catalog.display.product.inc.asp catalog.display1.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display19.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display2.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display3.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display4.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display5.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display6.product.inc.asp catalog.display.product.files.inc.asp catalog.display.productADD.inc.asp catalog.display.productlist.inc.asp catalog.display.productlist2.inc.asp catalog.display.productlistProduct.inc.asp catalog.display.quickorder13.inc.asp catalog.display.quickorder23.inc.asp catalogform.display.inc.asp cataloglink.display.inc.asp CatalogPass.display.inc.asp catalogpointscash.display.inc.asp catalogpointshistory.display.inc.asp CatalogPointsReport.display.inc.asp catalogpointstransfer.display.inc.asp catalogpointsupload.display.inc.asp CatalogProfile.display.inc.asp CatalogSearch.display.inc.asp catalog.display.productlistProduct.inc.asp CatalogUser.display.inc.asp changepassword.display.inc.asp inventory.display.inc.asp inventoryvalue.display.inc.asp login.display.inc.asp login.error.display.inc.asp login.permanent.display.inc.asp lsmanage.display.inc.asp order.display.inc.asp order.display.1.inc.asp cart.display.table.inc.asp order.display.2.inc.asp cart.display.table.inc.asp order.display.2.BillBranch.inc.asp order.display.2.BillCorporate.inc.asp order.display.2.BillMe.inc.asp order.display.2.BillMeWithPO.inc.asp order.display.2.CostCenter.inc.asp order.display.2.CreditCard.inc.asp order.display.2.PaidInFull.inc.asp order.display.2.PaymentTypeRequest.inc.asp order.display.2.PayrollDeduct.inc.asp order.display.2.Points.inc.asp order.display.2.Prepay.inc.asp order.display.3.inc.asp cart.display.table.inc.asp order.display.4.inc.asp order.display.3.inc.asp cart.display.table.inc.asp order23.display.inc.asp cart.display.table.inc.asp cartfile.code.inc.asp order23.display.1.inc.asp order23.display.2.inc.asp order.display.2.BillBranch.inc.asp order.display.2.BillCorporate.inc.asp order.display.2.BillMe.inc.asp order.display.2.BillMeWithPO.inc.asp order.display.2.CostCenter.inc.asp order.display.2.CreditCard.inc.asp order.display.2.PaidInFull.inc.asp order.display.2.PaymentTypeRequest.inc.asp order.display.2.PayrollDeduct.inc.asp order.display.2.Points.inc.asp order.display.2.Prepay.inc.asp order23.display.3.inc.asp orderhistory.display.inc.asp orderreport.display.inc.asp orderreportRJR.display.inc.asp rmicusage.display.inc.asp usage.display.inc.asp userreport.display.inc.asp userreport2.display.inc.asp layout.display0-1.inc.asp layout.display0-2.inc.asp layout.display1-1.inc.asp layout.display1-2.inc.asp layout.display10-1.inc.asp layout.display10-2.inc.asp layout.display11-1.inc.asp layout.display11-2.inc.asp layout.display12-1.inc.asp layout.display12-2.inc.asp layout.display13-1.inc.asp layout.display13-2.inc.asp layout.display14-1.inc.asp layout.display14-2.inc.asp layout.display15-1.inc.asp layout.display15-2.inc.asp layout.display16-1.inc.asp layout.display16-2.inc.asp layout.display17-1.inc.asp menus-17.code.inc.asp cms.code.sub.inc.asp menus-17.display.css.inc.asp menus-17.display.js.inc.asp layout.display17-2.inc.asp layout.display18-1.inc.asp menus-17.code.inc.asp cms.code.sub.inc.asp layout.display18-2.inc.asp layout.display19-1.inc.asp layout.display19-2.inc.asp layout.display2-1.inc.asp layout.display2-2.inc.asp layout.display20-1.inc.asp layout.display20-2.inc.asp layout.display21-1.inc.asp layout.display21-2.inc.asp layout.display22-1.inc.asp layout.display22-2.inc.asp layout.display23-1.inc.asp layout.display23-2.inc.asp layout.display24-1.inc.asp layout.display24-2.inc.asp layout.display25-1.inc.asp layout.display25-2.inc.asp layout.display26-1.inc.asp layout.display26-2.inc.asp catalog.display.productlist2.inc.asp catalog.display.productlistProduct.inc.asp layout.display27-1.inc.asp layout.display27-2.inc.asp layout.display28-1.inc.asp layout.display28-2.inc.asp layout.display29-1.inc.asp layout.display29-2.inc.asp layout.display3-1.inc.asp layout.display3-2.inc.asp layout.display30-1.inc.asp layout.display30-2.inc.asp layout.display31-1.inc.asp layout.display31-1.code.functions.inc.asp layout.display31-1.code.inc.asp layout.display31-2.inc.asp layout.display32-1.inc.asp layout.display32-2.inc.asp layout.display4-1.inc.asp layout.display4-2.inc.asp layout.display5-1.inc.asp layout.display5-2.inc.asp layout.display6-1.inc.asp layout.display6-2.inc.asp layout.display7-1.inc.asp layout.display7-2.inc.asp layout.display8-1.inc.asp layout.display8-2.inc.asp layout.display9-1.inc.asp layout.display9-2.inc.asp ProductOption2.0.obj.inc.asp ProductTMG2.0.obj.inc.asp variables.inc.asp CartTMG2.0.obj.inc.asp Category2.0.obj.inc.asp CCCharge2.0a.obj.inc.asp cmsForm2.1.obj.inc.asp cmsFormData2.1.obj.inc.asp cmsFormDataElement2.1.obj.inc.asp cmsFormElement2.1.obj.inc.asp cmsFormElementType2.1.obj.inc.asp cmsFormProcessor2.1.obj.inc.asp cmsFormProcessorRole2.1.obj.inc.asp cmsPage2.1.obj.inc.asp cmsParagraph2.1.obj.inc.asp cmsSection2.1.obj.inc.asp Coupon2.1.obj.inc.asp Customer2.0.obj.inc.asp Feature2.0.obj.inc.asp Item2.1.obj.inc.asp ItemLong2.1.obj.inc.asp LSList2.0.obj.inc.asp Object2.0a.obj.inc.asp ObjectRelation2.0.obj.inc.asp StorageBinary2.0.obj.inc.asp StorageDatabase2.0.obj.inc.asp StorageImage2.0.obj.inc.asp StorageIndex2.0.obj.inc.asp StorageString2.0.obj.inc.asp Object2.1.obj.inc.asp Clientscript2.1.obj.inc.asp Color2.1.obj.inc.asp Extension2.1.obj.inc.asp SPD2.1.obj.inc.asp StorageBinary2.0.obj.inc.asp StorageDatabase2.0.obj.inc.asp StorageImage2.0.obj.inc.asp StorageIndex2.0.obj.inc.asp StorageString2.0.obj.inc.asp OrderTMG2.0.obj.inc.asp Price2.1.obj.inc.asp ProductOption2.0.obj.inc.asp ProductTMG2.0.obj.inc.asp Receipt2.0.obj.inc.asp email2.1.obj.inc.asp Shipping2.1.obj.inc.asp Browser2.1.obj.inc.asp Email2.1.obj.inc.asp User2.0.obj.inc.asp Crypt2.1.obj.inc.asp Object2.1.obj.inc.asp Clientscript2.1.obj.inc.asp Color2.1.obj.inc.asp Extension2.1.obj.inc.asp SPD2.1.obj.inc.asp StorageBinary2.0.obj.inc.asp StorageDatabase2.0.obj.inc.asp StorageImage2.0.obj.inc.asp StorageIndex2.0.obj.inc.asp StorageString2.0.obj.inc.asp User2.1.obj.inc.asp Crypt2.1.obj.inc.asp variables.code.constants.inc.asp variables.code.functions.inc.asp variables.code.server.inc.asp variables.code.timecheck.inc.asp
Brought to you by the Non-WTF Job Board:  
 It's that time again! Sponsors: we greatly appreciate your help in paying the bills here at The Daily WTF. And, dear readers, thank for support TDWTF by visiting these fine companies and checking out their products & services.  |  | 5pm - the next generation, web-based project management tool designed to be your central location for project and task management, team collaboration, time tracking, reporting and more. With their no-hassle free trial, it's certainly worth checking out. |  |  | A Sane Approach to Database Design - the book that tells you how to build a smart database, with lots of examples of people who did it wrong. And although the irish girl has nothing to do with database design, I certainly appreciate keeping up the tradition. |  |  | MindFusion - a great source for floatcharting and diagramming components for a variety of platforms including .NET, WPF, ActiveX and Swing |  |  | Mosso - massively scalable hosting for .NET (2,3,3.5) PHP, Ruby, etc., with unlimited sites & mailboxes, simple online provisioning, and an enterprise clustered platform that's supported by real people. |  | | Rails Kit - developers of the Software as a Service Rails Kit, which includes well-tested modules, controllers, and utilities to handle all the billing/account/merchant legwork for your RoR application. |  |  | SlickEdit - makers of that very-impressive code editor and some pretty neat Eclipse and VisualStudio.NET tools and add-ins, some of which (Gadgets) are free. Check out this short video highlighting just one of SlickEdit's Visual Studio integration features. |  |  | SmartBear - there's no good reason not to do code review, especially with tools like CodeCollaborator; if nothing else, consider getting SmartBear's completely free book (book as in... paper, not some PDF), The Best Kept Secrets of Peer Code Review. |  |  | Splunk - Search, navigate, alert and report on all your IT data in real time. Logs, configurations, messages, traps and alerts, script, code, metrics and more. If a machine can generate it -- Splunk can eat it. |  |  | SoftLayer - serious hosting provider with datacenters in three cities (Dallas, Seattle, DC) that has plans designed to scale from a single, dedicated server to your own virtual data center (complete with racks and all) |  |  | WebFaction - very reasonable priced linux hosting that offers all sorts of features (from Rails to MySQL to SVN repositories) with unlimited domains, unlimited Websites, and unlimited Databases. |  | | The Non-WTF Job Board - Powered by HiddenNetwork, it features some great job opportunities like: | I'm by no means an expert on fire safety code... but I'm pretty sure this doesn't quite qualify as a fire exit.  (from Matt Courtney) "As you may be aware," Antony B," "Google Streetview in Australia blurrs the faces of people in the street who are photographed, for privacy reasons, etc. The software also does the same thing for the face of Colonel Sanders on the KFC signs. "  Jon writes, "I couldn't help but laugh when I saw this juxtaposition. The really sad part is that, the night I first saw it, there were people standing outside. I felt bad for laughing, but that didn't stop me from stopping for a quick photo!"  Virgil wondered how often these issues presented themselves...  "My company recently purchased a Cisco router," Jeff Mitchell wrote, "and a few days later, I received the two-page End User License Agreement for some of the software. Inside a cardboard envelope. Inside a FedEx bubble mailer. Inside a large UPS 2nd Day Air box. I suppose they really wanted to make sure all that fine print was legible." 
Brought to you by the Non-WTF Job Board:  
 The billing application was slow. And not slow in the taking-30-seconds-to-start-up sense, but slow in the ridiculously-freaking-slow sense. Loading an invoice took between ten and fifteen minutes. Updating a line item on an invoice took up to a minute. And saving the invoice back to the database took even longer than loading it in the first place. Clearly, things couldn't stay this way – a minimum of 25 minutes to update a single invoice was completely unacceptable. They needed an expert. They needed... The Optimizer. Kent had earned his reputation by making a simple but dramatic improvement in another application's performance. A database server had been set up with the default cache size, 64KB. Seeing that it could have been using a full 16MB, he changed the setting and performance improved considerably. Simple as it was, he was immediately hailed as a hero, and because of that, the powers that be wanted to put him on the billing application. For Kent, this was going to be a much bigger challenge. The billing system was not only known for its slowness, but for its bugginess. Throwing more hardware at the problem would only take them so far, and some invoices loaded quicker than others. Furthermore, and even more troubling, some of the prices just didn't work. Most of the prices were "marketing rounded" ($599.99 as opposed to $600.00), but for certain numbers that didn't work, they had workarounds. For $700, for example, they used $699.95 because $699.99 didn't work right. The highest price they could have was $999.99, because as the previous developer had told them, the hardware wasn't powerful enough for a thousands digit. Kent knew where to start – in the database. Searching by variable name in the application code was usually an exercise in how soon he'd be reaching for some aspirin; the database is where the answers are. It didn't take him long to find the columns DOLLARS and SENSE [sic]. OK, sure, using floating point numbers can occasionally have its pitfalls, so maybe this was an intentional choice. The data certainly looked ok. Nothing in DOLLARS was above 999, and nothing in SENSE was above 99. Now that he had his column names, Kent could start looking at the actual code. His search led him to some scary code comments. "Some prices are wrong, I don't know why," "Fix this" and "OH GOD WHAT HAVE I DONE." OK, the last one was an exagerration, but the comments were very troubling, and worse, Kent couldn't make heads or tails of the code that accompanied the comments. His descent took him further and further into the twisty passages of the codebase which, as it happened, was written in assembly. To make the whole system run fast, of course. Kent eventually stumbled upon a file that stored basically a giant two dimensional array. In pseudocode (as the original assembler would be too painful), the file would've looked like so: decimal[1000, 100] prices = {{ 0.00, 0.01, ..., 0.98, 0.99 }, { 1.00, 1.01, ..., 1.98, 1.99 }, { 2.00, 2.01, ..., 2.98, 2.99 }, { 3.00, 3.01, ..., 3.98, 3.99 }, { 4.00, 4.01, ..., 4.98, 4.99 }, ... {999.00, 999.01, ..., 999.98, 999.99}}; OK, Kent thought, scratching his head. Why would every valid price be in a giant array? The array took nearly 80KB of memory, which partly explained why the binary was so large, but still it seemed like it was much larger than it should be... Kent peeked at the last assembler log and learned that the array isn't declared once and used repeatedly – it's included everywhere it's used. Which was over 100 times. As for how this price lookup was used, following is some more pseudocode: pointer=&array; // Location of the start of the array offset=0; price_offset=price_in_dollars + price_in_cents; price_offset=(price_in_dollars * 100) + price_in_cents; for(x=0; x<price_offset; x++) { offset++; } return *(pointer + offset); As far as I'm concerned, the ability to write assembly code requires some kind of superhuman intelligence. Reading this code, however, leads me to believe otherwise. Kent's predecessor seemed to struggle with it, as he had apparently never heard of labels (which allow you to give a name to a memory address) and instead tracked memory locations of each line of code. This, in turn, lead to lots of dupilicate and nonsensical lines. For example, in the snippet above "offset" is set twice. The reason that "offset=price_in_dollars + price_in_cents" was left in was because Kent's predecessor couldn't always delete code. Removing an instruction would shift the memory addresses of all subsequent instructions, which would obviously have an impact on those hard-coded addresses. In some cases — specifically, when the length of the instruction(s) he wanted to remove was divisible by two — he was able to effectively perform no operation yet still take up two bytes: he could simply jump to the address of the next instruction. But for those pesky instructions that would leave a remainder of one byte, the programmer just couldn't figure out a no-operation instruction that took up a single byte. Apparently, he never bothered to look up NO-OP, a one byte instruction that does just that. As it turned out, it never occurred to the original programmer that the two-byte no-op he used (relative jump of one byte) could also be used to jump any number of bytes forward. And this is where the loop in the preceding code comes in. To convert two integers (one for dollars, one for *ahem* cents) into a single decimal — or, more specifically, a pointer to the decimal number stored in the aforementioned array — the programmer incremented once for each penny. So, the second-worst-case scenario of $999.99 would result in nearly 1,000,000 increment instructions. Plus all the other nearby instructions. Plus the overhead of incrementing a pointer not stored in a register. Even in assembler, this is damn slow. What's the worst case scenario, you may be wondering? A price that is "invalid." For instance, as mentioned earlier, $699.99 is invalid. Some prices didn't work because the array's values had been entered by hand and some had been missed. That's right, all 100,000 (0-999 dollars, 0-99 cents) entries in the array were entered manually by the previous developer. Saving prices back was done in a way similar to the lookups. It'd again loop over every cent trying to find a match in the huge array of prices, then split it into DOLLARS and SENSE. And if it was an invalid/missing number, it'd enter an infinite loop. Because of this, the employees guarded their "bad prices" list fiercely. With an understanding of how it worked, it took all of an afternoon to fix the slowdown. It now ran dramatically faster, supported prices up to $999,999,999.99 (which would be ideal if they started selling yachts), and didn't even have any "bad" prices that would cause infinite loops. Oh, and the binary dropped to less than 50KB in size as a result of the changes as well. Looking back, Kent is proud of the work he'd done. After over three months turning his predecessor's code into something sane, the only negative side effect is the occasional recurring nightmare in which Kent is hired at another place where his predecessor had built the application he'd be maintaining.
Brought to you by the Non-WTF Job Board:  
 "Thank goodness this bicycle I'm borrowing still works after Y2K," Robin Sheat notes, "I can't even imagine the programmer-hours required to bring it up to spec."  Google's CSS How-To didn't inspire a whole lot of confidence in Stephen Schwarz.  "This error pops up every now and then," Jeff Pitcrew writes, "and this one in particular happened on May 1st. I do respect that they programmed their licensing to be flexible enough for two millennia in, presumably, either direction."  "Hmmmm," Jeremy Vanderburg pondered, "I've never heard of this sequel before... but who can keep up with such things these days."  Tyler Menezes notes, "apparently null wasn't the answer."  "I normally wouldn't send in all-too-common 500-Error," Brian Reiter wrote, "but this error from the website of Chicago Public Radio's This American Life is a head-scratcher on several levels." 
Brought to you by the Non-WTF Job Board:  
 Back in 1998, at the Department of Informatics at the University of Umeå in Sweden, the professors had decided that instead of the final exam being solely a regurgitation of knowledge gleaned from text books and lectures, it would be a good idea for students to venture out into the real world to complete their bachelor's degrees. In teams of two, they would spend time with a local business, learn how Information Technology fit in with their daily work, and present it back to the professors. While most students received mundane case studies, the one that Niclas Olovsson and his teammate were assigned became the envy of the other students - the usage of IT tools for supporting flight mechanics at a local airport. Upon receiving their assignment, Niclaus figured that any modern airport would require a state-of-the-art system to keep their airplanes in the air. He imagined hand held smart terminals that received work orders over an intranet, sent data back over an extranet to a VB application over the internet! The synergistic combinations of buzzwords were endless! However, on the morning of their arrival, much to their chagrin, all they found was a greasy old PC...and Klaus. Klaus was the head of maintenance for the airline, but you wouldn't know it by looking at him. Smelling like a combination of jet fuel and Camels, he sure didn't look like management. Probably the only thing that made him different than a car garage "grease monkey" was the wings and airline logo on his grease-stained overalls. Scratching his week old stubble, Klaus began, "So, ya boys wanna learn about how we use computers in the high tech field of modern avionics? C'mon - step into my office - pull yerselves up a chair!" by office he meant the corner of the hanger with the porta potties and by chair, Klaus meant "oil canisters". Niclas, carefully perched on a canister, started "So, do you have an intranet that you use to..." "Whoa, slow down...Save your questions for the end - got a lot to cover." And in their sessions in the following two weeks, cover he did. Apparently, aviation mechanics are very much into exposing the granular details of everything, from the Airline's Employee Time Entry System to the web page that showed what was for lunch in the cafeteria. "Did I show you guys our state-of-the-art, custom CMS yet?" Niclas perked up - "Er, um, no, not yet - go on!" Content Management Systems are indeed buzzword-worthy - this would make for a fine bullet point in his presentation and just had to be more interesting than another hour covering the minute details of the airline's phonebook application. However, when Klaus said "CMS", what he really meant was "Folder on the hanger's computer labeled CMS". Some time ago, the airline had paid a one man company to convert the written manuals into PDFs. And so he did. One by one. As pictures. Luckily the Adobe files were roughly covering a chapter each, so the page numbering in the table of contents was somewhat aligned with the page numbers in the PDF for the first chapter, but for any other chapter, the mechanic had to calculate page numbering difference or scroll through the file to find the right section. "I know it seems strange to you guys, but we just sort of know where to go in the electronic manuals." grunted Klaus. "But, what about those binders?" asked Niclas' teammate. "They're the updates we get from the airplane manufacturers." Niclas and his teammate learned that airplane manufacturers regularily update their manuals, and each release supersedes any previous editions. Therefore, even if details of a procedure are on the computer, the mechanic still had to check the udpate binders before performing any maintenance. Once their two-week overview was completed, the information was compiled into a very clean presentation of what the mechanics used to do their daily jobs and was presented to a panel of professors. When asked what, if any, recommendations they would make in regards to the situation, Niclas simply responded "we advise taking the train."
Brought to you by the Non-WTF Job Board:  
 The bar for entry into CodeSOD is pretty straight forward: professionally-developed code that elicits that certain What The— reaction. Though there have been a few exceptions over the years, generally speaking, student code, hobbyist code, and amateur code need not apply. That said, I'd like to try something a little different today. Today's example is not technically professionally-developed, it's a Stupid Coding Trick. "So I was bored at work one day," Graeme Job explains, "and wondered, what's the most useless thing I could do with my time without actually doing anything. Then it hit me. I could use T-SQL to generate... Madelbrot." Graeme continued, "Following is a single T-SQL SELECT statement that generates a text-representation of a Mandelbrot Set. The results are best viewed in text-mode." -- AUTHOR: GRAEME JOB -- CREATED: 12-OCT-2008 -- BECAUSE: SINGLE SQL COMMAND < 50 LINES. JUST BECAUSE. WITH XGEN(X, IX) AS ( -- X DIM GENERATOR SELECT CAST(-2.2 AS FLOAT) AS X, 0 AS IX UNION ALL SELECT CAST(X + 0.031 AS FLOAT) AS X, IX + 1 AS IX FROM XGEN WHERE IX < 100 ), YGEN(Y, IY) AS ( -- Y DIM GENERATOR SELECT CAST(-1.5 AS FLOAT) AS Y, 0 AS IY UNION ALL SELECT CAST(Y + 0.031 AS FLOAT) AS Y, IY + 1 AS IY FROM YGEN WHERE IY < 100 ), Z(IX, IY, CX, CY, X, Y, I) AS ( -- Z POINT ITERATOR SELECT IX, IY, X, Y, X, Y, 0 FROM XGEN, YGEN UNION ALL SELECT IX, IY, CX, CY, X * X - Y * Y + CX AS X, Y * X * 2 + CY, I + 1 FROM Z WHERE X * X + Y * Y < 16 AND I < 100 ) SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( (X0+X1+X2+X3+X4+X5+X6+X7+X8+X9+X10+X11+X12+X13+X14+X15+X16+X17+X18+X19+ X20+X21+X22+X23+X24+X25+X26+X27+X28+X29+X30+X31+X32+X33+X34+X35+X36+X37+X38+X39+ X40+X41+X42+X43+X44+X45+X46+X47+X48+X49+X50+X51+X52+X53+X54+X55+X56+X57+X58+X59+ X60+X61+X62+X63+X64+X65+X66+X67+X68+X69+X70+X71+X72+X73+X74+X75+X76+X77+X78+X79+ X80+X81+X82+X83+X84+X85+X86+X87+X88+X89+X90+X91+X92+X93+X94+X95+X96+X97+X98+X99), 'A',' '), 'B','.'), 'C',','), 'D',','), 'E',','), 'F','-'), 'G','-'), 'H','-'), 'I','-'), 'J','-'), 'K','+'), 'L','+'), 'M','+'), 'N','+'), 'O','%'), 'P','%'), 'Q','%'), 'R','%'), 'S','@'), 'T','@'), 'U','@'), 'V','@'), 'W','#'), 'X','#'), 'Y','#'), 'Z',' ') FROM ( SELECT 'X' + CAST(IX AS VARCHAR) AS IX, IY, SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ', ISNULL(NULLIF(I, 0), 1), 1) AS I FROM Z) ZT PIVOT ( MAX(I) FOR IX IN ( X0,X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18,X19, X20,X21,X22,X23,X24,X25,X26,X27,X28,X29,X30,X31,X32,X33,X34,X35,X36,X37,X38,X39, X40,X41,X42,X43,X44,X45,X46,X47,X48,X49,X50,X51,X52,X53,X54,X55,X56,X57,X58,X59, X60,X61,X62,X63,X64,X65,X66,X67,X68,X69,X70,X71,X72,X73,X74,X75,X76,X77,X78,X79, X80,X81,X82,X83,X84,X85,X86,X87,X88,X89,X90,X91,X92,X93,X94,X95,X96,X97,X98,X99) ) AS PZT As for the aforementioned results, I've taken the liberty of pasting them into notepad and snapping a screenshot.  Have any of your own stupid coding tricks to share? Then send 'em on in. The goal of a stupid coding trick isn't obfuscation per se... just, well, stupid awesomeness. Kinda like a quine, except even more useless.
Brought to you by the Non-WTF Job Board:  
 It was fall of 1995 and everyone was gearing up for the 1996 tax season. After years of maintenance of a DOS-based tax application, TaxQuik -- as we'll call the company -- had to get with the times. New, spunky companies were building tax software for Windows with fancy GUIs, integrated help and even Internet-enabled features, while TaxQuik was still in the text-based stone age of DOS. The one thing that the new companies all lacked was the name recognition and brand loyalty of TaxQuik's customers. The company developed an aggressive plan to continue to support the DOS version, while simultaneously building a Windows version of the software. And by all accounts, the plan worked like a charm. Some of TaxQuik's larger clients were given a preview version of the new Windows version, and the feedback was almost universally positive. An interactive 1040 form that could be printed on any sheet of paper without needing blank copies of the form? It was the kind of thing that tax accountants' dreams were made of. Trouble in Paradise As testing continued, the initial appeal of the software started to wear off. One day, a user called to complain his network connection kept dropping whenever he was using the Windows version. The following day, two more reports of the same problem came in. Eventually TaxQuik received more issue reports than it could handle, so the network infrastructure group was called in to help. Bruce W. and the rest of the infrastructure team got to work right away, first setting up a test installation on a small network with a sniffer running on one of the machines. They entered 1040 information for Joe Employee at 123 Fake St. and took a deep breath as they hit ENTER. There was barely a blip in the network traffic. Returning to the machine, they loaded the tax form, tabbed through, changed a few fields and hit ENTER again. Again, hardly any traffic was generated. "Wait, let me try," Bruce said, grabbing the mouse. "Whoa, what just happened?" a teammate exclaimed. "What did you do? A ton of traffic just came through!" "Uh, nothing, I think." Bruce hadn't done anything but sit down at the table and put his hand on the mouse. "Let me see if I can reproduce whatever just happened," he said. Bruce dragged the cursor to the file menu and was about to reload the form. "You just did reproduce it! What the heck are you doing?" This gave Bruce an idea. "I have to ask the lead developer about something." The Source "Oh, I think I might know what the problem is," the lead developer said, when Bruce questioned him. "We wanted the operations to be quick so it would feel like a Windows app instead of a DOS app ported to Windows, so we spent a lot of time on optimization and hiding reads and writes." "So ..." "So, we decided to put a lot of the background logic in the application's MouseMove event." Bruce summoned all of his self control to keep from slapping himself on the forehead. "What kind of 'background logic'?" "You know -- database reads and writes, re-calculations." Windows Next Season After several meetings, it was decided that it wasn't the best idea to put critical code in an app's MouseMove event. Realizing that users of the DOS version were probably accustomed to keyboard navigation sealed the deal. TaxQuik quietly stopped describing the Windows version as a "preview" -- probably because "harbinger of doom" would've been more apt -- and instead called it a "limited beta." Large sections of code were reworked to perform smaller tasks in little bursts, rather than unleash a series of dozens of commands and queries while the mouse was moved around the screen, but it wasn't enough. TaxQuik didn't have a shippable Windows version of the software for the 1996 tax season. The following year, it managed to put out a Windows version that still had some performance issues, but by 1998 the company had hit its stride. At this rate, TaxQuik will hopefully have a Windows Vista version by 2012. Hidden Tax Moves was originally published in Alex's DevDisasters column in the Sep 15, 2008 issue of Redmond Developer News. RDN is a free magazine for influential readers and provides insight into Microsoft's plans, and news on the latest happenings and products in the Windows development marketplace.
Brought to you by the Non-WTF Job Board:  
 Go ahead Michael Fulker, make your move. I'll count to one.  "I was obeying my wife and doing some research into what would happen to our daughter who had swallowed a penny (because, you never know, she might not poop it out)" P. James wrote, "and I came across this interesting... Culinary Development?"  Jon was looking forward to punching some dudes in Oni, when suddenly...  Ben spotted this ad that was run on a web site that I won't name here. Whatever web site it was, it seems their QA or ad department was asleep at the wheel.  "I encountered this page while trying to use a web-based library catalog," Konrad Zielinski writes. "Having to not use the navigation buttons on your browser seems like a little bit of a WTF to me."  Based on these two ads spotted by Claudio in Milan, I'd say Playlife has a better ad than Microsoft.  
Brought to you by the Non-WTF Job Board:  
 Diego G. lives in Argentina and is working with a developer from the USA on a PHP project. Recently they were discussing the merits of handling the communication from the backend to the frontend via XML or JSON. The system used XML elsewhere already, but for the new work it looked like it'd be quicker and easier to work with JSON in the PHP pages. The contact in the US didn't like one solution more than the other, and in the interest of getting the project done quickly, sent an email with his solution. We choose to keep it simple. Hope this makes sense. Please feel free to add any additional info you feel is needed. thanks. Please let me know if you have any questions. Following is a sample of what we've been asked to do. <response> <content id="account-item-data"> <items> <item> <JSON> {"id":"5078","confidential":"false","sort-date":"20081027200000", "save-date-mmdd":"Oct 27","save-date-yyyy":"Oct 27","type":"N", "allow-remember":"true","keys":{},"vendor": {"first-name":"Johann Sebastiann","last-name":"Bach"}} </JSON> </item> <item> <!-- ... -->
Brought to you by the Non-WTF Job Board:  
 Ever since the first Free Sticker Week ended back in February '07, I've been sending out WTF Stickers to anyone that mailed me a SASE or a small souvenir. More recently, I've been sending out the coveted TDWTF Mugs for truly awesome souvenirs. Nothing specific; per the instructions page, "anything will do." Well, here goes anything, yet again! (previous: A Crapton of Candy). It's not every day that one is treated to a nice, steak dinner. Even rarer is when said dinner shows up at your front door, completely randomly and unexpected. Brandon "galgorah" Leach (Boston, MA) wrote, "here's at least one lunch you shouldn't be able to complain about. Well, unless you eat this all in one sitting."  What makes steaks by mail so exciting -- in addition to the fact that they're steaks by mail -- is the fact that they're shipped with dry ice. Nothing is more ominous than opening a package and watching smoke pour out. If you have yet to experience such a treat, this is exactly what it's like.  As for the contents... filet-fricken-mignon and some awesomely delectable sides. Brandon, you rock -- I'll definitely send a couple extra stickers your way and a TDWTF mug, too!  Not pictured: seasoning packet, cutting board, 4 steak knives, ensuing knife fight over the steaks, victorious me, bloodied coworkers, and steak dinner with lawyer to discuss subsequent lawsuit(s) A.B. Hollar (Harrisonburg, VA) sent this empty Cuban cigar box, happy birthday napkin, Rosetta Stone sticker, and evil lego dude.  "To help you with the dire food situation," wrote Daniel Quadros (Sao Paulo, Brazil) "here are some take-out menus. Some of them even offers free delivery!" How exciting! I called up Engenharia Do Hamburguer to place an order. Of course, they spoke some kind of Spanish, so I repeated myself a few times very loudly and slowly. I'm pretty sure those burgers will be on their way soon.  Jeremy D. Pavleck sent this massive set of Minnesota souvenirs and randomness, including: invitation to his wedding, which took place at the Science museum on 2^10; orange pencil favor from said wedding;combo pen/pencil from HP; and an itemized list of the contents.  This TFT-screen cleaning towel and a two-euro coin is from Matthias Leeb (Wien, Austria).  Not to many people can say that they've done the Quebec microbrewery tour. Thanks to Martin King (Quebec, Canada), now I can not only fake it, but prove that I was there, too.  Kirby Stirland sent over WTF?: How to Survive 101 of Life's Worst F*#!-ing Situations. Since I'm still entrenched in my insult book, I only had a | |